; Program to receive a CP/M file through a serial port ; Accesses port directly, bypassing the BDOS ; Assumes an 8-bit word length and no parity ; ; Version of 9/17/83 ; ; BOOT EQU 0000H ;CP/M reboot address BDOS EQU 0005H ;CP/M BDOS entry point TFCB EQU 005CH ;FCB for file to be transmitted SIOSTA EQU 07H ;SIO status port SIODAT EQU 06H ;SIO data port IFLAG EQU 02H ;Input flag for serial port OFLAG EQU 01H ;Output flag for serial port BUFREC EQU 128 ;Buffer size (CP/M records) RETRY EQU 4 ;Number of retries before quitting ; ; ORG 100H ; ; If required, place serial port initialisaion code here ; RX: LDA TFCB+1 CPI ' ' ;Check for filename JNZ OPEN LXI D,FNMER ;Print erro message and reboot ABORT: MVI C,9 CALL BDOS MVI E,04H CALL XMTBYT ;Send EOT character JMP BOOT ;Return to CP/M OPEN: LXI D,TFCB MVI C,19 CALL BDOS ;Delete old file if present LXI D,TFCB MVI C,22 CALL BDOS ;Make new file INR A LXI D,DDFER ;Point at error message JZ ABORT ;Print and reboot START: MVI C,30 ;Send some NULs first MVI E,00H NULS: CALL XMTBYT DCR C JNZ NULS IN SIODAT ;Clear serial data port READY: LDA RPTCTR CPI RETRY MVI E,01H JZ READY1 ;First time for this record INR E ;Change request character to 02H ORA A ;Test repeat counter JNZ READY1 ;Try again if not zero ENDXMT: LXI D,EOTMSG ;Print EOT message and exit JMP ABORT READY1: CALL XMTBYT ;Send prompting byte READY2: MVI C,11 CALL BDOS ;Cet console status ORA A JZ READY3 ;No key presaed MVI C,1 CALL BDOS CPI 03H JZ ENDXMT ;Terminate if control-C pressed READY3: IN SIOSTA ;Read serial status port ANI IFLAG JZ READY2 ;Wait for character to be received IN SIODAT ;Get received character ANI 7FH ;Mask off bit 7 for ASCII codes CPI 03H JZ CLOSE ;Flush buffer and close file CPI 04H JZ ENDXMT ;End transmission CPI 01H JZ RCVREC ;Receive next record CPI 02H JNZ READY2 ;Ignore other characters RCVREC: MVI B,80H ;Byte count for record MVI D,0 ;Initialize checksum LHLD DATPTR ;Prepare to store data RCVRC1: CALL RCVBYT ;Get a byte MOV M,A ;Store in data buffer INX H ADD D MOV D,A ;Update checksum DCR B JNZ RCVRC1 ;Continue for 128 bytes CALL RCVBYT ;Get checksum CMP D PUSH PSW ;Save status JNZ RCVRC2 ;Bad read SHLD DATPTR ;Save new record pointer RCVRC2: LXI D,RECMSG MVI C,9 CALL BDOS ;Print received record message LDA RPTCTR CPI RETRY JZ RCVRC3 ;First try LXI D,AGAIN MVI C,9 CALL BDOS ;Print 'again' RCVRC3: LXI D,CRLF MVI C,9 CALL BDOS ;Print CRLF LXI H,RPTCTR DCR M ;Decrement repeat counter POP PSW JNZ START ;Unsuccessful read MVI A,RETRY STA RPTCTR ;Reset counter for next record LXI H,RECCNT+4 COUNT: INR M MVI A,'9' CMP M ;Over 9? JNC BUFCHN MVI M,'0' DCX H MOV A,M CPI ' ' JNZ COUNT MVI M,'0' JMP COUNT ;Put '0' in message BUFCHN: LHLD DATPTR LXI D,-(DATBUF+BUFREC*128) DAD D CC FLUSH ;Flush buffer if full JMP READY ;Go look for next record FLUSH: LXI D,DATBUF ;Start at beginning of buffer FLUSH1: LHLD DATPTR MOV A,D ;Compare to see if empty CMP H JNZ FLUSH2 ;More to go MOV A,E CMP L JNZ FLUSH2 LXI H,DATBUF SHLD DATPTR ;Reset data pointer RET FLUSH2: PUSH D MVI C,26 CALL BDOS ;Set DMA address LXI D,TFCB MVI C,21 CALL BDOS ;Write record POP D ORA A JZ FLUSH3 ;Good write LXI D,DDFER ;Disk error JMP ABORT FLUSH3: LXI H,0080H DAD D ;Point to next record XCHG JMP FLUSH1 ;Go write it if present CLOSE: CALL FLUSH ;Flush buffer of data LXI D,TFCB MVI C,16 CALL BDOS ;Close file LXI D,EOFMSG MVI C,9 CALL BDOS ;Print EOF message JMP BOOT ;Reboot RCVBYT: IN SIOSTA ;Receive byte from serial port ANI IFLAG JZ RCVBYT IN SIODAT RET XMTBYT: IN SIOSTA ;Transmit byte to serial port ANI OFLAG JZ XMTBYT MOV A,E OUT SIODAT RET ; FNMER: DB 'File name missing',0DH,0AH,'$' DDFER: DB 'Disk or directory full',0DH,0AH,'$' EOFMSG: DB 'Transfer complete',0DH,0AH,07H,'$' EOTMSG: DB 'Transfer terminated',0DH,0AH,07H,'$' RECMSG: DB 'Record #' RECCNT: DB ' 1' ;Record # received DB ' received$' AGAIN: DB ' again$' ;Repeated record CRLF: DB 0DH,0AH,'$' ;CRLF sequence DATPTR: DW DATBUF ;Pointer to next storage location in buffer RPTCTR: DB RETRY ;Counter for repeated record DATBUF EQU $ ;Data buffer ; END