page 64 title 'Simple terminal emulator - KERMIT part 1' maclib term ; -->> File : KERMIT.ASM ; ========== ; (Adapted from the Version 3.9A, (c) Columbia University) ; Copyright (c) Werner Cirsovius ; Hohe Weide 44 ; D-2000 Hamburg 20 ; Federal Republic of Germany ; Tel.: 040/4223247 ; Version 1.10, February 1988 ; ===== Externals ===== ; From LIB BASELIB extrn close,strbi0 ; To TERMINAL public sendK,recvK ; From module XMODEM extrn decout ; From module KERSUB extrn argblk,numtry,czseen,data,oldtry,bufpnt,chrcnt extrn state,temp4,spad,spadch,seol,squote,quot8 extrn qbchr,chktyp,inichk,pktnum,spsiz,rquote extrn reol,rpadch,rpad,rtime,rpsiz,numrtr,curchk extrn numpkt,size,datptr,cbfptr,filbuf,filflg extrn eoflag,fcbptr extrn ermes4,ermes5,ermes6,erms10,infms3 extrn infms4,inms13,inms22,inms23,inms24 extrn scrnrt,scrnp,outln2 extrn ptchr,spack,error3,tryagn,errchk,compp,countp extrn outbuf,ackp,rpack,error,finmes,errmsg extrn Zstate,gtchr,r,finish ; To module KERSUB public @abort,nak0,updrtr ; ***** PART 1 : the SENDER ***** sendK: call init ;Clear the line and ;initialize the buffers. xra a sta pktnum ;Set the packet number to zero. sta numtry ;Set the number of tries to zero. lxi h,0 shld numpkt ;Set the number of packets to zero. shld numrtr ;Set the number of retries to zero. lxi d,scrnrt;Position cursor call strbi0 lxi h,0 call decout ;Write the number of retries. mvi a,'1' ;Reset to use single character checksum sta curchk ;For startup mvi a,'S' sta state ;Set the state to receive initiate. ; send2: ;SEND state table switcher ; lxi d,scrnp ;Position cursor call strbi0 lhld numpkt call decout ;Write the packet number. lda state ;Get the state. cpi 'D' ;Are we in the data send state? jnz send3 call sdata jmp send2 send3: cpi 'F' ;Are we in the file send state? jnz send4 call sfile ;Call send file. jmp send2 send4: cpi 'Z' ;Are we in the EOF state? jnz send5 call seof jmp send2 send5: cpi 'S' ;Are we in the send initiate state? jnz send6 call sinit lda state ;Get state back cpi 'F' ;Into file send state yet? jnz send2 ;No lxi d,inms23;Yes, print sending... call finmes jmp send2 send6: cpi 'B' ;Are we in the eot state? jnz send7 call seot jmp send2 send7: cpi 'C' ;Are we in the send complete state? jnz send8 ;No... lxi d,infms3;Yes, write "Complete" message. lda czseen ;Or was it interrupted? ora a jz finish ;No. lxi d,inms13;Yes, then say "Interrupted" instead. jmp finish send8: lxi d,infms4;Anything else is equivalent to "abort" jmp finish ; sinit: ; Send initiate ; call bmxtry ;Set retry count jnc errmsg mvi a,'1' ;Reset to use single character checksum sta curchk ;For startup lda chktyp ;Get our desired block check type sta inichk ;Store so we tell other end lxi h, data ;Get a pointer to our data block. call rpar ;Set up the parameter information. sta argblk+1;Save the number of arguments. lda numpkt ;Get the packet number. sta argblk mvi a,'S' ;Send initiate packet. call spack ;Send the packet. jmp @abort ; Failed, abort. call rpack ;Get a packet. jmp r ; Trashed packet don't ;change state, retry. cpi 'Y' ;ACK? jnz sinit3 ;If not try next. call compp rnz ;If not try again. call countp lda argblk+1;Get the number of pieces of data. lxi h,data ;Pointer to the data. call spar ;Read in the data. lda numtry ;Get the number of tries. sta oldtry ;Save it. lda inichk ;Get the agreed upon block check type sta curchk ;Store as type to use for packets now mvi a,true sta filflg ;Nothing in the DMA. xra a sta eoflag ;Not the end of file. jmp Fset sinit3: cpi 'N' ;NAK? jnz errchk ;If not see if its an error. call updrtr ;Update the number of retries. lda pktnum ;Get the present packet number. inr a ;Increment. mov b,a lda argblk ;Get the packet's number. cmp b ;Is the packet's number one ;more than now? rnz ;If not assume its for this packet, ;go again. Fset: xra a sta numtry ;Reset number of tries. mvi a,'F' ;Set the state to file send. sta state ret ; sfile: ; Send file header ; call bmptry ;Bump error count jnc errmsg xra a ;Clear A sta czseen ;No control-Z or X seen lxi h, data ;Get a pointer to our data block. shld datptr ;Save it. lxi h,fcbnam;Pointer to the file name in the FCB. shld fcbptr ;Save position in FCB. mvi b,0 ;No chars yet. mvi c,0 sfil11: mov a,b cpi 8 ;Is this the ninth char? jnz sfil12 ;If not proceed. mvi a,'.' ;Get a dot. lhld datptr mov m,a ;Put the char in the data packet. inx h shld datptr ;Save position in data packet. inr c sfil12: inr b ;Increment the count. mov a,b cpi 12 ;Twelve? jp sfil13 lhld fcbptr mov a,m ani 7fh ;Turn off CP/M 2 or 3's high bits. inx h shld fcbptr ;Save position in FCB. cpi ' '+1 ;Is it a good character? jm sfil11 ;If not get the next. lhld datptr mov m,a ;Put the char in the data packet. inx h shld datptr ;Save position in data packet. inr c jmp sfil11 ;Get another. sfil13: mov a,c ;Number of char in file name. sta argblk+1 lhld datptr mvi m,0 ;Put in a zero for printing. lda pktnum ;Get the packet number. sta argblk mvi a,'F' ;File header packet. call spack ;Send the packet. jmp @abort ; Failed, abort. call rpack ;Get a packet. jmp r ; Trashed packet don't ;change state, retry. cpi 'Y' ;ACK? jnz sfile2 ;If not try next. call compp rnz ;If not hold out for the right one. sfil14: call countp lda numtry ;Get the number of tries. sta oldtry ;Save it. xra a sta numtry ;Reset the number of tries. sfil15: xra a ;Get a zero. sta fcbrc ;Set the record number to zero. sta eoflag ;Indicate not EOF. mvi a,true sta filflg ;Indicate file buffer empty. call gtchr jmp Zstate ;Error go see if its EOF. ;Got the chars, proceed. sta size ;Save the size of the data gotten. mvi a,'D' ;Set the state to data send. sta state ret sfile2: cpi 'N' ;NAK? jnz errchk ;Try if error packet. call updrtr ;Update the number of retries. lda pktnum ;Get the present packet number. inr a ;Increment. mov b,a lda argblk ;Get the packet's number. cmp b ;Is the packet's number one ;more than now? rnz ;If not go try again. jmp sfil14 ;Just as good as a ACK ;go to the ACK code. ; sdata: ; Send data ; call bmptry ;Bump retry count jnc errmsg lxi h, data ;Get a pointer to our data block. shld datptr ;Save it. lxi h,filbuf;Pointer to chars to be sent. shld cbfptr ;Save position in char buffer. mvi b,1 ;First char. sdat11: lhld cbfptr mov a,m inx h shld cbfptr ;Save position in char buffer. lhld datptr mov m,a ;Put the char in the data packet. inx h shld datptr ;Save position in data packet. inr b ;Increment the count. lda size ;Get the number of chars in char buffer cmp b ;Have we transfered that many? jp sdat11 ;If not get another. lda size ;Number of char in char buffer. sta argblk+1 lda pktnum ;Get the packet number. sta argblk mvi a,'D' ;Data packet. call spack ;Send the packet. jmp @abort ; Failed, abort. call rpack ;Get a packet. jmp r ; Trashed packet don't ;change state, retry. cpi 'Y' ;ACK? jnz sdata2 ;If not try next. call compp rnz ;If not hold out for the right one. lda argblk ;Get the packet number back call countp lda numtry ;Get the number of tries. sta oldtry ;Save it. xra a sta numtry ;Reset the number of tries. lda argblk+1;Get the data length cpi 1 ;Check if only 1 character? jnz sdat15 ;If not, just continue lda data ;Got one character, get it from data cpi 'Z' ;Want to abort entire stream? jnz sdat14 ;If not, check for just this file sta czseen ;Yes, remember it sdat14: cpi 'X' ;Desire abort of current file? jnz sdat15 ;If not, just continue sta czseen ;Yes, remember that sdat15: lda czseen ;Also get control-Z flag ora a ;Check if either given jz sdat12 ;If neither given, continue mvi a,'Z' ;Change state to EOF sta state ret ;And return sdat12: call gtchr jmp Zstate ;Error go see if its EOF. sta size ;Save the size of the data gotten. ret sdata2: cpi 'N' ;NAK? jnz errchk ;See if is an error packet. call updrtr ;Update the number of retries. lda pktnum ;Get the present packet number. inr a ;Increment. mov b,a lda argblk ;Get the packet's number. cmp b ;Is the packet's number one ;more than now? rnz ;If not go try again. jmp sdat12 ;Just as good as a ACK ;go to the ACK code. ; seof: ; Send EOF ; call bmptry ;Bump retry count jnc errmsg lda pktnum ;Get the packet number. sta argblk xra a sta argblk+1;No data. lda czseen ;Check if C-Z or C-X typed ora a jz seof14 ;If not aborted, just keep going mvi a,'D' ;Tell other end to discard packet sta data ;Store in data portion mvi a,1 ;One character sta argblk+1;Store the length seof14: mvi a,'Z' ;EOF packet. call spack ;Send the packet. jmp @abort ; Failed, abort. call rpack ;Get a packet. jmp r ; Trashed packet don't change ;state, retry. cpi 'Y' ;ACK? jnz seof2 ;If not try next. call compp rnz ;If not hold out for the right one. seof12: call countp lda numtry ;Get the number of tries. sta oldtry ;Save it. xra a sta numtry ;Reset the number of tries. mvi a,'B' ;Set the state to EOT. sta state clfile: lxi d,fcb call close ;Close the file ret seof2: cpi 'N' ;NAK? jnz errchk ;Try and see if its an error packet. call updrtr ;Update the number of retries. lda pktnum ;Get the present packet number. inr a ;Increment. mov b,a lda argblk ;Get the packet's number. cmp b ;Is the packet's number one ;more than now? rnz ;If not go try again. jmp seof12 ;Just as good as a ACK ;go to the ACK code. ; seot: ; Send EOT ; call bmptry ;Bump retry count jnc errmsg lda pktnum ;Get the packet number. sta argblk xra a sta argblk+1;No data. mvi a,'B' ;EOF packet. call spack ;Send the packet. jmp @abort ; Failed, abort. call rpack ;Get a packet. jmp r ; Trashed packet don't ;change state, retry. cpi 'Y' ;ACK? jnz seot2 ;If not try next. call compp rnz ;If not hold out for the right one. seot12: call countp lda numtry ;Get the number of tries. sta oldtry ;Save it. xra a sta numtry ;Reset the number of tries. mvi a,'C' ;Set the state to file send. sta state ret seot2: cpi 'N' ;NAK? jnz errchk ;Is it error. call updrtr ;Update the number of retries. lda pktnum ;Get the present packet number. inr a ;Increment. mov b,a lda argblk ;Get the packet's number. cmp b ;Is the packet's number one ;more than now? rnz ;If not go try again. jmp seot12 ;Just as good as a ACK ;go to the ACK code. bmxtry: mvi b,imxtry jmp combmp bmptry: mvi b,maxtry combmp: lda numtry ;Get the number of tries. cmp b ;Have we reached the maximum ;number of tries? inr a ;Increment it. sta numtry ;Save the updated number of tries. ret ; ***** PART 2 : the RECEIVER ***** recvK: call init ;Clear the line and ;initialize the buffers. mvi a,'1' ;Start with single character checksum sta curchk ;Save the type xra a ;Start a packet zero. sta argblk mvi a,'R' ;Receive init packet. call spack ;Send the packet. jmp finbad ; Die! xra a sta czseen ;Clear the ^X/^Z flag initially. lxi h,0 shld numpkt ;Set the number of packets to zero. shld numrtr ;Set the number of retries to zero. sta pktnum ;Set the packet number to zero. sta numtry ;Set the number of tries to zero. lxi d,scrnrt;Position cursor call strbi0 lxi h,0 call decout ;Write the number of retries. mvi a,'R' sta state ;Set the state to receive initiate. ; read2: ;RECEIVE state table switcher. ; lxi d,scrnp ;Position cursor call strbi0 lhld numpkt call decout ;Write the current packet number. lda state ;Get the state. cpi 'D' ;Are we in the DATA receive state? jnz read3 call rdata jmp read2 read3: cpi 'F' ;Are we in the FILE receive state? jnz read4 call rfile ;Call receive file. jmp read2 read4: cpi 'R' ;Are we in the Receive-Initiate state? jnz read5 call rinit lda state ;Get new state cpi 'F' ;Went into receive state? jnz read2 ;No lxi d,inms24;Yes, get receiving... message call finmes ;Go print it jmp read2 read5: cpi 'C' ;Are we in the Receive-Complete state? jnz read6 lxi d,infms3;Put in "Complete" message. lda czseen ;Or was it interrupted? ora a jz finrd ;No. xra a ;Yes, clear flag. sta czseen finbad: mvi a,1 ;Set bad end lxi d,inms13;Issue "interrupted" message. finrd: push psw push d call clfile ;Close file pop d pop psw jmp finish ;Print completion message ;in right place. read6: lxi d,infms4;Anything else is equivalent to "abort" jmp finish ; init: ;Initialize buffers and screen ; lxi d,outln2 call strbi0 lxi d,inms22 call finmes ;Tell we're waiting init1: mvi a,reclng;Buffer size. sta chrcnt ;Number of chars left. lxi h,dma ;Addr for beginning. shld bufpnt ;Store addr for beginning. ret ; ;Receive routines ; rinit: ;Receive init ; call rextry ;Bump retry counter dw ermes4 mvi a,'1' ;Reset block check type to ;single character sta curchk ;Store as current type for ;initialization call rpack ;Get a packet. jmp nak ; Trashed packet: nak, retry. cpi 'S' ;Is it a send initiate packet? jnz rinit3 ;If not see if its an error. lda numtry ;Get the number of tries. sta oldtry ;Save it. xra a sta numtry ;Reset the number of tries. lda argblk ;Returned packet number. ;(Synchronize them.) call countp lda argblk+1;Get the number of arguments received. lxi h,data ;Get a pointer to the data. call spar ;Get the data into the proper variables lxi h,data ;Get a pointer to our data block. call rpar ;Set up the receive parameters. sta argblk+1;Store the returned number of arguments mvi a,'Y' ;Acknowledge packet. call spack ;Send the packet. jmp @abort ; Failed, abort. lda inichk ;Now switch to agreed upon check-type sta curchk ;For all future packets mvi a,'F' ;Set the state to file send. sta state ret rinit3: cpi 'E' ;Is it an error packet. jnz nak0 ;If not NAK whatever it is. call error jmp @abort ; @abort: ;Abort ; mvi a,'A' ;Otherwise abort. sta state ret ; nak0: ;NAK ; call updrtr ;Update number of retries. nak: lda pktnum ;Get the packet number ;we're waiting for. sta argblk xra a ;No data. sta argblk+1 mvi a,'N' ;NAK that packet. call spack jmp @abort ; Give up. ret ;Go around again. updrtr: lxi d,scrnrt;Position cursor call strbi0 lhld numrtr inx h ;Increment the number of retries shld numrtr call decout ;Write the number of retries. ret ; rpar: ;This routine sets up the data for init packet ;(either the Send_init or ACK packet). ; lda rpsiz ;Get the receive packet size. adi ' ' ;Add a space to make it printable. mov m,a ;Put it in the packet. inx h ;Point to the next char. lda rtime ;Get the receive packet time out. adi ' ' ;Add a space. mov m,a ;Put it in the packet. inx h lda rpad ;Get the number of padding chars. adi ' ' mov m,a inx h lda rpadch ;Get the padding char. adi '@' ;Uncontrol it. ani 7fh mov m,a inx h lda reol ;Get the EOL char. adi ' ' mov m,a inx h lda rquote ;Get the quote char. mov m,a inx h mvi m,'Y' ;We know how to do 8-bit quoting inx h ;Advance to next lda inichk ;Get desired block check type mov m,a ;Store it inx h ;Advance pointer mvi a,8 ;Six pieces of data. ret ; spar: ;This routine reads in all the send_init packet ;information. ; sta temp4 ;Save the number of arguments. mov a,m ;Get the max packet size. sbi ' ' ;Subtract a space. sta spsiz ;Save it. lda temp4 cpi 3 ;Fewer than three pieces? rm ;If so we are done. inx h inx h ;Increment past the time out info. mov a,m ;Get the number of padding chars. sbi ' ' sta spad lda temp4 cpi 4 ;Fewer than four pieces? rm ;If so we are done. inx h mov a,m ;Get the padding char. adi '@' ;Re-controlify it. ani 7fh sta spadch lda temp4 cpi 5 ;Fewer than five pieces? rm ;If so we are done. inx h mov a,m ;Get the EOL char. sbi ' ' sta seol lda temp4 cpi 6 ;Fewer than six pieces? rm ;If so we are done. inx h mov a,m ;Get the quote char. sta squote lda temp4 ;Get the amount of data supplied cpi 7 ;Have an 8-bit quote? rm ;If not there, all done inx h ;Yes, get the character mvi a,false sta quot8 ;Assume not quoting mov a,m ;Get the supplied character cpi 'N' ;No? jz spar1 ;Then don't try to do it cpi ' ' ;Maybe they don't know about it... jz spar1 ;Then don't try to do it. cpi 'Y' ;Yes? jz spar1 sta qbchr ;Use their quote char ;(should validate) mvi a,true sta quot8 ;Turn quote flag and fall thru... spar1: lda temp4 ;Determine if block check type given cpi 8 ;Is the field there? rm ;If not, all done inx h ;Point to the character mov a,m ;Get the value mov b,a ;Copy value lda chktyp ;Get our type cmp b ;Is it our desired type? jz spar01 ;If so, use it mvi a,'1' ;No, use single character spar01: sta inichk ;Store the desired block check type ret ;And return ; rfile: ;Receive file ; call rectry ;Fix retry count dw ermes5 call rpack ;Get a packet. jmp nak ; Trashed packet: nak, retry. cpi 'S' ;Is it a send initiate packet? jnz rfile2 ; No, try next type. lda oldtry ;Get the number of tries. cpi imxtry ;Have we reached the maximum ;number of tries? jm rfil12 ;If not proceed. lxi d,ermes4 call error3 ;Move cursor and print an error message jmp @abort ;Change the state to abort. rfil12: inr a ;Increment it. sta oldtry ;Save the updated number of tries. lda pktnum ;Get the present packet number. dcr a ;Decrement. mov b,a lda argblk ;Get the packet's number cmp b ;Is the packet's number one ;less than now? jnz nak0 ;No, NAK and try again. call updrtr ;Update the retry count. xra a sta numtry ;Reset the number of tries. lxi h, data ;Get a pointer to our data block. call rpar ;Set up the parameter information. sta argblk+1;Save the number of arguments. mvi a,'Y' ;Acknowledge packet. call spack ;Send the packet. jmp @abort ; Failed, abort. ret rfile2: cpi 'Z' ;Is it an EOF packet? jnz rfile3 ; No, try next type. lda oldtry ;Get the number of tries. cpi maxtry ;Have we reached the maximum ;number of tries? jm tryagn ;If not proceed. lxi d,ermes6 call error3 ;Move cursor and print an error message jmp @abort ;Change the state to abort. rfile3: cpi 'F' ;Start of file? jnz rfile4 call compp jnz nak0 ;No, NAK it and try again. call countp call init1 ;Initialize all the buffers. lda numtry ;Get the number of tries. sta oldtry ;Save it. call ackp mvi a,'D' ;Set the state to data receive. sta state lda czseen ;Check if we punted a file cpi 'Z' ;and didn't want any more rz ;If that was the request, keep telling ;other end xra a ;Otherwise, clear flag ;(Control-X is only for one file) sta czseen ;And store the flag back ret rfile4: cpi 'B' ;End of transmission. jnz errchk call compp jnz nak0 ;No, NAK it and try again. xra a ;No data. ;(Packet number already in argblk). sta argblk+1 mvi a,'Y' ;Acknowledge packet. call spack ;Send the packet. jmp @abort mvi a,'C' ;Set the state to complete. sta state ret ; rdata: ;Receive data ; call rectry ;Fix retry count dw erms10 call rpack ;Get a packet. jmp nak ; Trashed packet: nak, retry. cpi 'D' ;Is it a data packet? jnz rdata2 ; No, try next type. rdat11: call compp jz rdat14 lda oldtry ;Get the number of tries. cpi maxtry ;Have we reached the maximum ;number of tries? jm tryagn ;If not proceed. lxi d,erms10 call error3 ;Display err msg. jmp @abort ;Change the state to abort. rdat14: call countp lda numtry ;Get the number of tries. sta oldtry ;Save it. lda argblk+1;Get the length of the data. call ptchr jmp @abort ; Unable to write out chars;abort. xra a sta numtry ;Reset the number of tries. sta argblk+1;No data. ;(Packet number still in argblk.) mov c,a ;Assume no data lda czseen ;Check if control-X typed ora a jz rdat15 ;Zero if not typed mov c,a ;Get the type of character typed mvi a,1 ;One data character sta argblk+1;Save the count mov a,c ;Get the possible data character sta data ;Store in data area rdat15: mvi a,'Y' ;Acknowledge packet. call spack ;Send the packet. jmp @abort ret rdata2: cpi 'F' ;Start of file? jnz rdata3 ; No, try next type. lda oldtry ;Get the number of tries. cpi maxtry ;Have we reached the maximum ;number of tries? jm tryagn ;If not proceed. lxi d,ermes5 call error3 ;Display err msg. jmp @abort ;Change the state to abort. rdata3: cpi 'Z' ;Is it a EOF packet? jnz errchk ;Try and see if its an error. call compp jnz nak0 ;No, NAK it and try again. call countp lda argblk+1;Get the data length cpi 1 ;Have one item? jnz rdat33 ;If not, ignore data lda data ;Yes, get the character cpi 'D' ;Is it a 'D' for discard? jz rdat36 ;If so, punt file rdat33: lhld bufpnt ;Get the dma pointer. lda chrcnt ;Get the number of chars left ;in the DMA. rdat34: dcr a ;Lower the count. ora a jm rdat35 ;If full then stop. mvi m,eof ;Put in a ^Z for EOF. inx h ;Point to the next space. jmp rdat34 rdat35: call outbuf ;Output the last buffer. jmp @abort ; Give up if the disk is full. call clfile ;Close up the file xra a ;Since we kept the file, sta czseen ;don't say it was discarded. rdat36: lda numtry ;Get the number of tries. sta oldtry ;Save it. call ackp mvi a,'F' sta state ret rextry: call bmxtry ;Fix retry count jmp comrec rectry: call bmptry comrec: xthl ;Get callers pointer mov e,m inx h mov d,m inx h xthl rc ;Ok, end pop psw ;Fix stack call error3 ;Move cursor and print an error message jmp @abort ;Change the state to abort. ; +++++ END OF KERMIT MAIN PACKAGE +++++ end ursor a