TITLE 'XMODEM/ASM' ; ; Modem/Xmodem protocol for interchange of programs ; with the CP/M operating system. Employs the ; "Christensen" protocol. ; ; Note entry into the routine is direct from the ; terminal mode. The program prompts for the ; filename to send/receive. ; ; This segment makes no attempt to translate or ; otherwise adjust the outgoing (or incoming) data ; for the target/source system format. The user is ; responsible for seeing to it that the data is ; in the correct format for the transfer. ; ; Comment (Copyright notice) COMM 'XMODEM 6.2.0 Authored by HAL N. FUQUAY.' COMM ' Released to the public domain 01/17/1985' ; SOH EQU 1 EOT EQU 4 ACK EQU 6 NAK EQU 21 CAN EQU 24 ; ; SECWT EQU 20 ; 20 SECONDS FOR TIMEOUT ; ; ; Called subroutines: ; Getchar - Called to check on input ; from the Rs-232 interface. ; Send - Called to send a character to ; to other end. ; ; Note that CP/M sends in 128-byte blocks, which ; means that it is 2-for-1 on the TRS-80. ; Due to this difference in record lengths, the ; system treats the file(s) to send/receive as ; a byte-stream of data. 1 record is buffered ; by the segment (128 bytes). The last block is ; padded with zeros if padding is needed. ; ; ; Entry points: ; SENDCPM - Send a file to another MODEM ; system. ; RECVCPM - Receives a file from a MODEM ; system. ; ORG 3000H ; THE STARTING POINT ; ; DUMMY DEFL DUMMY-$ IF NOT,DUMMY GET SVC/ASM ENDIF ; SENDXY ; ; ENTER HERE TO SEND A XMODEM FILE. (HL) MUST ; CONTAIN THE FILESPEC TO SEND. ; LD A,@FSPEC LD DE,CPMDCB RST 28H ; PARSE FILENAME JP NZ,CERROR ; FATAL ERROR IN FILENAME LD A,@FLAGS RST 28H SET 0,(IY+18) ; READ-ONLY LD A,@OPEN ; OPEN THE FILE LD DE,CPMDCB LD HL,CPMBUF LD B,0 ; DO IT IN ANY CASE RST 28H ; OK -- IT IS OPEN! JP NZ,CERROR ; OH OH -- SOMETHING IS ; WRONG! LD A,@GET LD DE,CPMDCB RST 28H ; ATTEMPT TO READ 1 CHAR JP NZ,CERROR ; SOMETHING IS WRONG LD A,@REW LD DE,CPMDCB RST 28H ; REWIND IF OK CALL WAIT5 ; WAIT 5 SECONDS CALL SETOFF LD HL,STSMES LD A,@DSPLY RST 28H CALL FLUSHBF ; FLUSH BUFFER WAIT10 CALL GETCHAR ; WAIT FOR A NAK CP NAK ; SAME? JR Z,OKSND CP CAN ; CANCEL? JP Z,CANCPM LD A,@KBD RST 28H CP 80H JP Z,CANCPM ; CANCEL IF JR WAIT10 OKSND LD A,1 LD (BLOCK),A XOR A LD (LASTB),A FILL1 LD HL,XMTBUF ; TRANSMIT BUFFER LD DE,XMTBUF+1 LD A,0 LD (HL),A LD BC,127 LDIR ; ZERO IT XOR A LD (CPMRET),A LD B,128 LD HL,XMTBUF FILDC LD DE,CPMDCB LD A,@GET RST 28H ; GET 1 CHARACTER JP NZ,DONXM LD (HL),A INC HL DJNZ FILDC SENDC CALL SENDBFR ; SEND A BUFFER UNTIL OK LD A,(LASTB) OR A JP NZ,ENDXMT JR FILL1 SENDBFR LD A,SOH ; SEND SOH CALL SEND ; SEND IT LD A,(BLOCK) CALL SEND ; SEND BLOCK NUMBER LD A,(BLOCK) ; RELOAD IT CPL ; COMPLEMENT ACCUM CALL SEND ; CHECK OF BLOCK NUMBER LD E,0 ; STORE CHECKSUM LD B,128 ; HOW MANY TO DO LD HL,XMTBUF ; PLACE TO GET FROM SDCPM1 LD A,(HL) ADD A,E LD E,A LD A,(HL) ; RELOAD PUSH DE PUSH BC CALL SEND ; SEND IT POP BC ; RESTORE REGS POP DE INC HL DJNZ SDCPM1 ; CONTINUE LD A,E CALL SEND ; SEND CHECKSUM LD B,SECWT ; USE THIS FOR SECONDS WTOK PUSH BC ; SAVE COUNT CALL GETFROM ; GET ONE CHARACTER WITH ; TIMOUT JR Z,NOERX ; CHECK THE ONE WE GOT POP BC ; RESTORE COUNT DJNZ WTOK JP PERMER ; WE HAVE A PROBLEM NOERX POP BC ; FIX STACK CP CAN ; DO WE CANCEL? JP Z,CCCPM ; CANCEL XMIT CP ACK ; IS IT OK? JR NZ,CHKRET ; RETRIES IF NOT LD A,(BLOCK) ; ELSE NEXT BLOCK INC A LD (BLOCK),A XOR A ; SET ZERO FLAG RET CHKRET LD A,(CPMRET) INC A ; INCREMENT IT CP 10 ; IS IT 10? JR Z,TOMRET ; PERMANENT ERROR LD (CPMRET),A JR SENDBFR TOMRET LD HL,TOMER LD A,@DSPLY RST 28H JP CANCPM TOMER DM '! Cannot send block -- abort !',13 CCCPM LD HL,CCPM LD A,@DSPLY RST 28H PERMER LD HL,PERM LD A,@DSPLY RST 28H JP CANCPM ; CANCEL FILESEND CCPM DM '! Transmission cancelled by receiving end !',13 PERM DM 10,'! Timeout waiting for ACK/NAK !',13 STSMES DM '! Waiting for initial NAK -- ^X to cancel !',13 GETFROM CALL GETCHAR ; CHECK FOR ONE NOW RET Z ; RETURN IF SO PUSH BC LD A,@PAUSE LD BC,32767 RST 28H ; WAIT 1/2 SEC. POP BC CALL GETCHAR RET Z PUSH BC LD A,@PAUSE LD BC,32767 RST 28H POP BC CALL GETCHAR RET ; RETURN ANYWAYS! FLUSHBF CALL GETFROM ; CALL IT RET NZ JR FLUSHBF ; CONTINUE TILL NOTHING CANCPM LD A,CAN CALL SEND ; CALL THE SEND TO CANCEL LD A,@DSPLY LD HL,CANCDX RST 28H LD HL,0FFFFH JP RETTER ; GO BACK TO TERMINAL CANCDX DM 10,'! Transmit cancelled !',13 CPMDCB DS 32 CPMBUF DS 256 XMTBUF DS 129 CPMFIL DS 25 DONXM LD A,0FFH LD (LASTB),A JP SENDC ENDXMT LD B,5 ; TRY 5 TIMES ENDXM1 LD A,EOT CALL SEND WTCRL CALL GETFROM JR NZ,XMW1 ; RESEND IF NOTHING CP ACK ; ACK? JR Z,OKXT XMW1 DJNZ ENDXM1 LD HL,WRD LD A,@DSPLY RST 28H OKXT LD A,@DSPLY LD HL,SDCCPM RST 28H LD A,@CLOSE LD DE,CPMDCB RST 28H LD HL,0 JP RETTER ; CERROR PUSH AF ; SAVE ERROR CODE LD A,@DSPLY LD HL,DSSS RST 28H LVN POP AF ; WE RESTORE LD C,A SET 6,C SET 7,C LD A,@ERROR RST 28H ; PRINT ERROR MESSAGE LD A,@DSPLY LD HL,FRXN RST 28H LD HL,0FFFFH ; ERROR! JP RETTER DSSS DM '? ',03 FRXN DM '! Fatal error in Xmodem mode -- exit !',13 SDCCPM DM '! Modem protocol filesend complete !',13 BLOCK DB 0 OLDBIT7 DB 0 LASTB DB 0 CPMRET DB 0 WRD DM '! Terminator not correct -- exiting anyway !',13 RECVXY ; ENTER HERE TO RECEIVE A XMODEM FILE. THE FILESPEC ; MUST BE IN (HL). ; LD (STORHLX),HL ; SAVE FOR LATER LD A,@FSPEC LD DE,CPMDCB RST 28H JP NZ,RXERROR ; RECIEVE ERROR LD A,@FLAGS RST 28H SET 0,(IY+18) ; SET READ ONLY LD A,@OPEN ; WE TRY AN OPEN FIRST LD DE,CPMDCB LD HL,CPMBUF LD B,0 ; 0 LRL. RST 28H ; OPEN IT. JP NZ,MAYROK ; MAY NOT EXIST. JP NOEXBAT MAYROK CP 24 ; FILE NOT HERE JP NZ,RXERROR ; RECEIVE ERROR MAYO3 LD A,@FSPEC LD HL,(STORHLX) LD DE,CPMDCB RST 28H JP NZ,RXERROR LD A,@INIT LD B,0 LD HL,CPMBUF LD DE,CPMDCB RST 28H ; ATTEMPT TO INIT JP NZ,RXERROR ; ERROR! CALL WAIT5 ; WAIT 5 SECONDS CALL SETOFF LD HL,RDYRCV LD A,@DSPLY ; READY TO RECEIVE RST 28H XOR A ; RETRY COUNTER LD (COUNTR),A ; COUNTER LOAD LD A,1 LD (BLOCK),A NAKIT CALL FLUSHBF ; FLUSH BUFFERS LD A,NAK CALL SEND ; SEND A LD B,10 ; WAIT 10 SECONDS WAITFOR CALL GETFROM JP Z,GOXIN ; WE GOT SOMETHING! LD A,@KBD RST 28H OR A ; CHECK KB JP NZ,RXCAN DJNZ WAITFOR LD A,(COUNTR) INC A CP 10 ; 10 RETRIES? JP Z,RXCAN ; CANCEL RECEIVE LD (COUNTR),A JR NAKIT ; NAK IT AGAIN! RXCAN CALL GETFROM ; GET ONE CHAR JR Z,RXCAN LD A,CAN CALL SEND LD HL,RXCCAN LD A,@DSPLY RST 28H LD A,@REMOV LD DE,CPMDCB RST 28H ; KILL THE FILE LD HL,CNC LD A,@DSPLY RST 28H CALL FLUSHBF LD HL,0FFFFH JP RETTER CNC DM '! Receive cancelled, incomplete file deleted. !',13 GOXIN PUSH AF XOR A LD (COUNTR),A POP AF GOXMOR CP EOT ; END OF TRANSMIT JP Z,ENDRCV CP SOH ; IS IT SOH? JP Z,SOHX ; GO GET BLOCK CP CAN ; CANCEL? JP Z,RXCAN JP RESEND SOHX LD HL,CPMI ; CLEAR INPUT BUFFER LD DE,CPMI+1 LD BC,127 ; WE ZERO 128 BYTES XOR A LD (HL),A LDIR ; ZERO IT CALL GETFROM ; GET THE NEXT ONE JP NZ,TIMOR ; TIMEOUT RECEIVE LD B,A LD A,(BLOCK) ; WE GET BLOCK NUMBER CP B JP Z,BLKOK ; THE BLOCK NUMBER IS OK DEC A ; CHECK THIS ONE TOO CP B JP Z,RECVIGN ; IT'S A REPEAT JP LOST RECVIGN CALL FLUSHBF ; WAIT FOR LINE TO CLEAR LD A,ACK CALL SEND JP CONTMX BLKOK CALL GETFROM JP NZ,TIMOR CPL LD B,A LD A,(BLOCK) CP B JP Z,CONV ; WE ARE OK! DEC A CP B ; CHECK LAST ONE JP Z,RECVIGN JP LOST CONV LD B,128 ; 128 BYTES/RECORD LD C,0 ; INITIALIZE CHECKSUM LD HL,CPMI RECV1 CALL GETFROM JP NZ,RESEND ; RE-SEND (NOT ENOUGH) LD (HL),A INC HL ADD A,C LD C,A LD A,@KBD RST 28H ; SCAN KEYBOARD CP 80H ; IS IT A ? JP Z,RXCAN DJNZ RECV1 GETCK CALL GETFROM JP NZ,RESEND ; SOMETHING GOT LOST CP C ; CHECK IT JP NZ,RESEND ; RE SEND BLOCK LD B,128 LD HL,CPMI WRITI LD A,@PUT LD DE,CPMDCB LD C,(HL) PUSH BC PUSH HL RST 28H POP HL POP BC JP NZ,RXERROR INC HL DJNZ WRITI LD A,ACK CALL SEND LD A,(BLOCK) INC A LD (BLOCK),A CONTMX CALL GETFRX JP NZ,TIMOR ; TIMOUT ON RECEIVE JP GOXMOR ; TIMOR LD A,@REMOV LD DE,CPMDCB RST 28H LD HL,TIMORX LD A,@DSPLY RST 28H LD HL,0FFFFH JP RETTER TIMORX DM '! Timeout during receive - incomplete file deleted. !',13 ; ; RDYRCV DM '! File open, ready to receive !',10 DM '! Type ^X to cancel before transmission begins !',13 ENDRCV LD A,@CLOSE LD DE,CPMDCB RST 28H LD A,@DSPLY LD HL,FILCOM RST 28H LD A,ACK CALL SEND JP RETTER FILCOM DM '! Modem protocol file received. !',13 RXERROR PUSH AF LD A,@DSPLY LD HL,RXERM RST 28H POP AF JP CERROR ; ERROR HANDLING RXERM DM '! ? Disk error during receive -- message follows !',13 CPMI DS 129 COUNTR DB 0 RXCCAN DM 10,'! Cancelling receive. !',13 ; ; LOST JR RESEND ; TRY AGAIN. RESEND LD A,(COUNTR) INC A LD (COUNTR),A CP 10 ; 10 RETRIES? JR Z,RESOUT CALL FLUSHBX ; CLEAR INPUT LD A,NAK CALL SEND CALL GETFRX JP NZ,TIMOR JP GOXMOR RESOUT LD HL,RESX LD A,@DSPLY RST 28H JP RXCAN GETFRX PUSH BC LD B,SECWT ; USE THIS FOR # SECONDS FFX CALL GETFROM JR Z,GOB ; RETURN IF THERE IS ONE DJNZ FFX ; CONTINUE TILL DONE XOR A CP 1 POP BC RET ; RETURN WITH NZ RESULT GOB POP BC RET ; RETURN WITH IT RESX DM '! ? Block cannot be received !',13 FLUSHBX CALL GETFROM ; GET ONE WITH TIMEOUT RET NZ ; RETURN IF NOTHING JR FLUSHBX ; CONTINUE NOEXBAT LD A,@DSPLY LD HL,BATMX RST 28H LD HL,0FFFFH JP RETTER BATMX DM '! ? Xmodem receive file exists - ABORT !',13 STORHLX DW 0 ; PLACE TO SAVE POINTER ; ; ; START LD DE,PLACE LD BC,50 LDIR ; MOVE IT TO A SAFE PLACE LD HL,XMODEM LD A,@DSPLY RST 28H LD HL,PLACE LD A,(HL) CP 13 ; CHECK IT OUT CALL Z,GETPARMS LD HL,PLACE ; CHECK IT OUT LD B,80 ; WE CHECK 80 CHARS CHKIT LD A,(HL) ; CHECK IT OUT CP 13 ; JR Z,CXX ; NOTHING CP 3 JR Z,CXX ; NOTHING CP '(' ; OPEN PAREN'S? JR Z,GETCCC INC HL DJNZ CHKIT JR CXX GETCCC LD DE,DEVNAME INC HL LD B,3 MOVIT LD A,(HL) LD (DE),A INC HL INC DE DJNZ MOVIT CXX LD A,@FSPEC LD DE,DCB LD HL,DEVNAME RST 28H ; MOVE THE DEVICE NAME LD A,@OPEN LD DE,DCB LD HL,BUFFER LD B,0 ; OPEN IT RST 28H ; DO IT! JP NZ,NODEV ; NO DEVICE OF THAT NAME LD HL,PLACE LD A,(HL) ; CHECK IT AGAIN! CP 13 ; ? JP Z,EXIT1 ; LEAVE IF SO AND 0DFH CP 'S' ; SEND? JP Z,SENDCPM ; SEND IF SO CP 'R' ; RECEIVE? JP Z,RECVCPM ; GO TO IT IF SO LD A,@DSPLY LD HL,NOTLEG RST 28H EXIT1 LD A,@EXIT LD HL,0 RST 28H NOTLEG DM '? Not a legal option. Options are:',10 DM ' S filename - send a file to your end',10 DM ' R filename - receive a file from your end',10 DM 10,' Please try again.',13 OKGO LD DE,DCB LD A,@CTL LD C,4 LD IY,INTHDL ; WE WANT TO ATTACH RST 28H ; DO IT! LD (OLDIY),IY ; SAVE THE OLD ONE RET SENDCPM INC HL ; SKIP NEXT INC HL CALL OKGO ; GO ATTACH THE RS-232 LD (OLDSTK),SP ; SAVE STACK JP SENDXY ; SEND THE FILE RECVCPM INC HL INC HL CALL OKGO LD (OLDSTK),SP ; SAVE STACK JP RECVXY DCB DS 32 BUFFER DS 256 PLACE DS 64 NODEV LD A,@DSPLY LD HL,NODVR RST 28H LD HL,0FFFFH RET ; NO DEVICE OF THAT NAME NODVR DM '? No RS-232 device available.',13 XMODEM DM 28,31 DM '** XMODEM TRS-80 Version 6.2.0',10 DM ' Written by Hal N. Fuquay',10 DM ' Released to public domain',10,13 DM ' TRSDOS 6.2.0 version only',13 DEVNAME DM '*RO',13 GETPARMS LD HL,PARIN LD A,@DSPLY RST 28H LD HL,PLACE LD B,50 LD A,@KEYIN RST 28H JP C,LXV LD A,B OR A JP Z,LXV RET ; RETURN TO THE PLACE. PARIN DM 'Enter direction, filename, and device as:',10,10 DM 'S filename (*XX)',10 DM ' or',10 DM 'R filename (*XX)',10 DM 10,'Instructions? ',14,03 LXV POP AF ; RESTORE OLD PLACE LD HL,0FFFFH RET ; RETURN TO CALLER RETTER PUSH HL LD A,@CTL LD DE,DCB LD C,4 LD IY,(OLDIY) RST 28H ; RESTORE OLD HANDLER CALL WAIT5 CALL SETON LD HL,DSPX LD A,@DSPLY RST 28H POP HL LD SP,(OLDSTK) RET ; RETURN TO CALLER DSPX DM 10,'% Exiting',13 OLDSTK DW 0 OLDIY DW 0 ; OLD IY LOCATION INTHDL DI ; NOT RE-ENTRANT! PUSH DE PUSH HL PUSH AF PUSH BC LD DE,(BUFPOS) INC DE LD HL,(POSOF) XOR A SBC HL,DE LD A,H OR L JR Z,NORES LD HL,(POSIT) LD DE,DCB LD A,@GET RST 28H ; GET THE CHARACTER JR NZ,NORES LD (HL),A INC HL LD (POSIT),HL LD HL,(BUFPOS) INC HL LD (BUFPOS),HL LD DE,(LASTW) ; LAST LEGAL WORD XOR A SBC HL,DE LD A,H OR L JR NZ,NORES LD HL,INTBUF LD (POSIT),HL LD DE,0 LD (BUFPOS),DE NORES POP BC POP AF POP HL POP DE RET POSIT DW INTBUF BUFPOS DW 0 POSOF DW 0 POSRED DW INTBUF GETCHAR PUSH HL PUSH DE PUSH BC PUSH AF DI LD HL,(BUFPOS) LD DE,(POSOF) XOR A SBC HL,DE LD A,H OR L ; CHECK TO SEE IF SAME JR Z,NOCHAR INC DE LD (POSOF),DE LD HL,(POSRED) LD C,(HL) INC HL LD (POSRED),HL LD HL,(POSOF) LD DE,(LASTW) XOR A SBC HL,DE LD A,H OR L JR NZ,NORESX LD HL,INTBUF LD (POSRED),HL LD DE,0 LD (POSOF),DE NORESX POP AF LD A,C POP BC POP DE POP HL CP A EI RET NOCHAR POP AF POP BC POP DE POP HL LD A,0 CP 1 EI RET BKMK DB 0 SEND PUSH AF PUSH BC PUSH DE LD C,A WTX LD A,@PUT LD DE,DCB RST 28H POP DE POP BC POP AF RET ; RETURN TO CALLER SETOFF PUSH HL ; SAVE COMMAND LINE LD A,@CMNDR LD HL,SETOF RST 28H ; SET IT OFF POP HL ; RESTORE COMMAND LINE XOR A RET ; RETURN SETON LD A,@CMNDR PUSH HL ; SAVE COMMAND LINE LD HL,SETO RST 28H POP HL ; RESTORE COMMAND LINE XOR A RET SETOF DM 'Setcom (break=0,word=8)',13 SETO DM 'Setcom (break=3)',13 LASTW DW 256 ; THE LAST PLACE (SUPPOSEDLY) INTBUF DB 0 DS 257 ; TTON DM 'TTY CRT',13 TTOF DM 'TTY OFF',13 WAIT5 PUSH BC PUSH AF PUSH DE LD B,4 WT1 PUSH BC LD BC,60000 LD A,@PAUSE RST 28H POP BC DJNZ WT1 POP DE POP AF POP BC RET END START Downloaded from 8/N/1 #1 at 904/377-1200 - G. Omer