;PS:KERMIT.ASM[10,40], 13-Apr-83 17:19:03, Edit by Nick Bush, Stevens ; Add support for Telcon Zorba. Also add SET PORT command for Robins ; to allow use of general purpose port instead of communications port. ;PS:CPMKERMIT.ASM.4, 12-Apr-83 17:26:41, Frank ; Change current loc "." to "$" in Osborne code, so MAC80 can assemble it. ;PS:CPMKERMIT.ASM, 6-Apr-83 18:43:54, Frank ; Merge Charles Bacon's (NIH) Osborne 1 support. ;PS:CPMKERMIT.ASM, 6-Apr-83 18:43:54, Frank da Cruz, Columbia ; Merge Bruce Tanner's (Cerritos College) TRS-80 II support, including ; shortening all identifiers to 6 characters so MAC80 won't complain. ;PS:CPMKERMIT.ASM.11, 10-Feb-83 15:47:20, Bill C. ; Add in Apple ][ support (with Softcard and D.C. Hayes Micromodem) from ; someone at DEC. ;PS:KERMIT.ASM.6, 9-Feb-83 09:13:06, Bill C. ; Add SET PARITY command. ;PS:CPMKERMIT.ASM.9, 8-Feb-83 17:01:56, Bill C. ; Lower case EQU's to hopefully avoid some spurious ASM errors. ;PS:CPMKERMIT.ASM.8, 4-Feb-83 13:23:25, Bill C. ; Add Zenith Z-100 (under CP/M-85) support from Stevens (based on H-89 code.) ;PS:CPMKERMIT.ASM.7, 4-Feb-83 10:14:26, Bill C. ; Merge some cosmetic changes from U of Tenn. ;PS:CPMKERMIT.ASM.6, 4-Feb-83 10:10:19, Bill C. ;[UTK3] U of Tenn - Add some fixes to the LOG command. ;PS:CPMKERMIT.ASM.5, 4-Feb-83 09:01:39, Bill C. ;[UTK2] U of Tenn - Fix file renaming routine to properly index into file name. ;PS:CPMKERMIT.ASM.5, 4-Feb-83 08:58:38, Bill C. ;[UTK1] U of Tenn - Fix sending from non-connected drive. ;********************** Version 3.0 ***************************** ;PS:KERMIT.ASM.34, 3-Feb-83 15:05:31, Bill C. ; Clear line before printing file name. ;PS:KERMIT.ASM.32, 3-Feb-83 12:26:39, Bill C. ; Fix bug that incorrectly sent files of exactly 128*n characters. ;PS:KERMIT.ASM.29, 28-Jan-83 21:33:36, Bill C. ; Make conditional assembly under ASM and the new SYMBOL. ;PS:KERMIT.ASM.2, 25-Jan-83 17:01:30, Bill C. ; Add KERMIT Server master support -- RECEIVE, BYE, FINISH, LOGOUT ;********************** Version 2.5 ***************************** ;PS:CPM-KERMIT.ASM.3, 21-Jan-83 14:06:26, Bill C. ; Fix SEND to IBM; don't turn on parity in GTCHR. ;PS:CPM-KERMIT.ASM.2, 19-Jan-83 16:26:48, Bill C. ; Don't let empty lines mess us up. This is for the new CMS SP. ;PS:KERMIT-CPM.ASM.118, 1-Dec-82 14:34:01, Bill C. ; Fix bug that prevented files not on connected disk from being sent. ;PS:KERMIT-CPM.ASM.117, 1-Dec-82 12:40:34, Bill C. ; Finish CPM file creation switch. ;PS:KERMIT-CPM.ASM.116, 30-Nov-82 17:38:11, Bill C. ; Fix bug in edit 113 which caused only null files to be sent. ;PS:KERMIT-CPM.ASM.115, 30-Nov-82 16:32:09, Bill C. ; Add CPM created file switch. ;********************** Version 2.4 ***************************** ;PS:KERMIT.ASM.114, 22-Oct-82 16:10:23, Bill C. ; Fix parity problem in CONNECT code for the IBM. ;PS:KERMIT.ASM.113, 30-Sep-82 10:29:46, Bill C. ; Fix parity problem while sending files to the IBM. ;PS:KERMIT.ASM.111, 20-Jul-82 11:08:10, Bill C. ; Fix for spurious chars for the Robin. ;********************** Version 2.3 ***************************** ;PS:KERMIT.ASM.110, 22-Apr-82 12:29:05, Bill C. ; Turn off all VT52 emulation code for the Robin. ;PS:KERMIT.ASM.101, 16-Apr-82 17:05:16, Bill C. ; Put prompt after transfer on line 7 rather than 6 so as not to clobber ; error messages. ;PS:KERMIT.ASM.101, 16-Apr-82 17:05:15, Bill C. ; Make Robin screen stuff up to date, the same as the SuperBrain's. ;PS:KERMIT.ASM.98, 16-Apr-82 16:16:25, Bill C. ; Fix Robin to work as VT100 rather than VT52. ;********************** Version 2.2 ***************************** ;PS:KERMIT.ASM.97, 18-Mar-82 16:57:01, Bill C. ; Delete unused error messages. ;PS:KERMIT.ASM.96, 17-Mar-82 18:14:41, Bill C. ; Don't die on wrong packet number. Also, fix it so that NAKs are sent ; if problems occur receiving file. ;PS:KERMIT.ASM.95, 17-Mar-82 12:53:38, Bill C. ; On the first packet to the IBM (Send-Init) don't wait for XON. ;********************** Version 2.1 ***************************** ;PS:KERMIT.ASM.94, 17-Mar-82 12:28:22, Bill C. ; Put diagnostic messages under DEBUG switch. ;PS:KERMIT.ASM.93, 17-Mar-82 11:15:23, Bill C. ; Fix OSI, check MNPRST not MNPORT for status. ;PS:KERMIT.ASM.91, 3-Feb-82 12:28:25, Bill C. ; Fix Vector, change CONOUT to DCONIO. Also change turn-around char to XON. ;PS:KERMIT.ASM.84, 1-Feb-82 16:59:06, Bill C. ; Add in Heath and Robin support from Bernie Eiben & others at DEC. ;********************** Version 2.0 ***************************** ;PS:KERMIT.ASM.77, 28-Jan-82 16:11:27, Bill C. ; Fix long send packet size bug. ;PS:KERMIT.ASM.70, 27-Jan-82 10:08:25, Bill C. ; Fix data send retry problem. ;PS:KERMIT.ASM.62, 26-Jan-82 13:50:58, Bill C. ; Fix long file problem. Also spruce up set command. ;********************** Version 1.9 ***************************** ; KERMIT File Transfer program for point-to-point asynch connections. ; CP/M version ; ; Version 3.1 ; ; Based on the KERMIT Protocol. ; ; Bill Catchings ; Columbia University ; 612 W. 115th St. ; New York City, NY 10025 ; Special thanks to Frank da Cruz, Daphne Tzoar and Bernie Eiben for ; their help and contributions. ; Fixes by U Tenn are denoted by [UTK]. ORG 100H TRUE EQU -1 ; The whole, and nothing but... FALSE EQU NOT TRUE ; What can I say. ; KERMIT-80 Implementations. All can be assembled with SYMBOL or MAC80 ; on the DEC-10 or DEC-20 (unless otherwise noted), or ASM on the CP/M system. robin EQU TRUE ; For VT180 (Robin) condional assembly. brain EQU FALSE ; For SuperBrain assembly. vector EQU FALSE ; For Vector Graphics assembly. osi EQU FALSE ; For Ohio Scientific assembly. heath EQU FALSE ; For Heath assembly. z100 EQU FALSE ; For Z-100 under CP/M-85 assembly. apple EQU FALSE ; For APPLE ][ with D.C. Hayes Micromodem II. trs80 EQU FALSE ; For TRS-80 model II (Lifeboat CP/M 2.25C) osbrn1 EQU FALSE ; For Osborne 1 (Can't assemble with MAC80). telcon EQU FALSE ; For TELCON (portable) debug EQU FALSE ; For debugging (SuperBrain only). bell EQU 07O tab EQU 11O lf EQU 12O ff EQU 14O cr EQU 15O xon EQU 21O xoff EQU 23O esc EQU 33O del EQU 177O bdos EQU 0005H conin EQU 01H conout EQU 02H rdrin EQU 03H punout EQU 04H lstout EQU 05H dconio EQU 06H gtiob EQU 07H prstr EQU 09H consta EQU 0BH openf EQU 0FH closf EQU 10H sfirst EQU 11H snext EQU 12H delf EQU 13H readf EQU 14H ; Read from the file. writef EQU 15H makef EQU 16H cflsz EQU 23H IF brain baudst EQU 60H ; Port number for baud rate setting. baudrt EQU 0EF00H ; Memory location where baud rates are stored. mnport EQU 58H mnprts EQU 59H output EQU 01H input EQU 02H ENDIF IF osi mnport EQU 0CF01H mnprts EQU 0CF00H output EQU 02H input EQU 01H ENDIF IF vector mnport EQU 04H mnprts EQU 05H output EQU 01H input EQU 02H ENDIF IF heath mnport EQU 330O mnprts EQU 335O output EQU 20H input EQU 01H ENDIF IF z100 mnport EQU 0ECH mnprts EQU 0EDH output EQU 001H input EQU 002H ENDIF IF trs80 mnport EQU 0F4H ; 0F5H for port B mnprts EQU 0F6H ; 0F7H for port B output EQU 04H input EQU 01H ENDIF IF apple ; APPLE Slot 2 contains Micromodem II. MNPORT EQU 0E0A7H ; Communications Port. MNPRTS EQU 0E0A6H ; Communications Port Status. MNMODM EQU 0E0A5H ; Modem Control Port. ORGMOD EQU 8EH ; Modem Originate Mode. OUTPUT EQU 02H ; Output Buffer Empty. INPUT EQU 01H ; Input Register Full. APINC1 EQU 03H ; First Init Character for 6850 ACIA (Reset) APINC2 EQU 11H ; Second Init Character for ACIA (8-bits) APOFFH EQU 80H ; Set if OFFHOOK AP300 EQU 1 ; 300 Baud ENDIF IF osbrn1 ; Osborne 1 uses 6850 ACIA, but memory mapped. Derived from Apple. BAUDRT EQU 0EFC1H ; Memory location where baud rates are stored. OSTOP EQU 4000H ; Where we move OSMOVE to at startup OSPORT EQU 2A01H ; Communications Port. OSPRTS EQU 2A00H ; Communications Port Status. OUTPUT EQU 02H ; Output Buffer Empty. INPUT EQU 01H ; Input Register Full. OSBIN1 EQU 57H ; First Init Character for 6850 ACIA (Reset) ; (I would have thought 03, but prom code writes 57 there) OSBI12 EQU 55H ; Second Init Character for ACIA (8-bits, 1200) OSBI03 EQU 56H ; Second init char. for ACIA (8 bits, 300) ; (don't ask.. I don't know why SETUP writes 55 and 56 either) ENDIF IF telcon MNPORT EQU 20H ; Modem data port MNPRTS EQU 21H ; Modem status port OUTPUT EQU 01H ; Transmitter empty INPUT EQU 02H ; Input data available ENDIF IF robin pbausl EQU 90H ; The Baud-Rate register. ; ROBIN doesn't use this one , it uses the COMMunications port ; whose BAUD-rate is automatically set via SETUP B ;Beware ,we are have to steal the Interrupt chain from CPM ,since ;VT18X-CPM handles Input via interrupt @10H prntst EQU 49H prndat EQU 48H contst EQU 41H ; We'll handle Console input ourselves. condat EQU 40H ; The console register. gentst EQU 51H ; General port. gendat EQU 50H comtst EQU 59H ; This is our COMmunication port. comdat EQU 58H ; The same one used in startup mode T. output EQU 01H ; Output ready bit. input EQU 02H ; Input ready bit. ENDIF IF brain OR osi OR apple OR telcon defesc EQU ']'-100O ; The default escape character. ENDIF IF vector defesc EQU '~' ; Vector can't type ']'. ENDIF IF robin OR heath OR z100 OR osbrn1 defesc EQU '\'-100O ; The default is Control \ -- its easier B.E. ENDIF IF trs80 defesc EQU '_'-100O ; The default is Control _ (Control down arrow on the TRS-80 keyboard) ENDIF maxpkt EQU '~'-' '+2O ; Maximum size of a packet. maxtry EQU 05O ; Default number of retries on a packet. imxtry EQU 20O ; Default number of retries send initiate. drpsiz EQU 5EH ; Default receive packet size. dspsiz EQU 20H ; Default send packet size. dstime EQU 08H ; Default send time out interval. IF NOT apple AND NOT osbrn1 drtime EQU 05H ; Default receive time out interval. ENDIF IF apple OR osbrn1 DRTIME EQU 0AH ENDIF dspad EQU 00H ; Default send padding. drpad EQU 00H ; Default receive padding. dspadc EQU 00H ; Default send padding char. drpadc EQU 00H ; Default receive padding char. dseol EQU CR ; Default send EOL char. dreol EQU CR ; Default receive EOL char. dsquot EQU '#' ; Default send quote char. drquot EQU '#' ; Default receive quote char. parevn EQU 00H ; Even parity. parmrk EQU 03H ; Mark parity. parnon EQU 06H ; No parity. parodd EQU 09H ; Odd parity. parspc EQU 0CH ; Space parity. defpar EQU parnon ; Default parity. ibmpar EQU parmrk ; IBM COMTEN's parity. soh EQU 01H ; Start of header char. fcb EQU 5CH ; Location of File Control Block. buff EQU 80H ; Location of file output buffer (DMA). bufsiz EQU 80H ; Size of DMA. maxfil EQU 50H ; Maximum number of files allowed. diasw EQU 01H ; Default is diagnostics on. cmkey EQU 01H ; Parse a keyword. cmifi EQU 02H ; Parse an input file spec (can be wild). cmofi EQU 03H ; Parse an output file spec. cmcfm EQU 04H ; Parse a confirm. cmtxt EQU 05H ; Parse text. start: lxi h,0 ; Clear out hl pair dad sp ; and fetch the system stack pointer shld oldsp ; and save for later restoral lxi sp,stack ; and move in our own stack. mvi c,prstr ; Print the version header. lxi d,versio call bdos IF robin lhld 11H ;the CPM interrupt address shld cint ;save it for later call p8251 ;set default rate ENDIF IF osbrn1 lxi h,ostop ; where we're moving it to lxi d,osmove ; what we're moving mvi c,osmct ; How many bytes we're moving start1: ldax d inx d mov m,a inx h dcr c jnz start1 lda baudrt ani 1 sta osbaud ; Find out what speed is current ENDIF call kermit ; Start things going. call exit1 ; Finish up. ; This is the main KERMIT loop. It prompts for and gets the users commands. kermit: IF robin call resint ENDIF lxi d,kerm call prompt ; Prompt the user. lxi d,comtab lxi h,tophlp mvi a,cmkey call comnd jmp kermt2 lxi h,kermtb ; Get the address of the jump table. mov c,a mvi b,0 dad b pchl kermtb: jmp telnet jmp exit jmp help jmp log jmp read jmp send jmp setcom ; Set is an assembler keyword!! jmp show jmp status jmp finish jmp logout jmp bye kermt2: mvi c,prstr ; Print a string to the console. lxi d,ermes1 ; An error message. call bdos jmp kermit ; Do it again. kermt3: mvi c,prstr ; Print a string to the console. lxi d,ermes3 ; An error message. call bdos jmp kermit ; Do it again. ; RECEIVE command read: lxi d,data ; Where to put the text (if any.) mvi a,cmtxt call comnd ; Get either some text or a confirm. jmp kermt3 ; Didn't get anything. cpi 0 ; Get any chars? jz read1 ; Nope, just a regular send. sta argblk+1 ; Store the number of chars. xchg ; Get pointer into HL. mvi m,'$' ; Put in a dollar sign for printing. call init ; Clear the line and initialize the buffers. mvi c,prstr ; Position cursor. lxi d,scrfln call bdos mvi c,prstr ; Print the file name. lxi d,data call bdos IF robin call kerint ENDIF mvi a,0 ; Start a packet zero. sta argblk mvi a,'R' ; Receive init packet. call spack ; Send the packet. jmp kermt3 ; Die! jmp read12 read1: call init ; Clear the line and initialize the buffers. read12: mvi a,0 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. mvi c,prstr ; Position cursor. lxi d,scrnrt call bdos lxi h,0 call nout ; Write the number of retries. IF robin call kerint ENDIF mvi a,'R' sta state ; Set the state to receive initiate. read2: mvi c,prstr ; Be informative. lxi d,infms1 call bdos lhld numpkt call nout ; Write the number of packets. lda state ; Get the state. cpi 'D' ; Are we in the data send 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 jmp read2 read5: cpi 'C' ; Are we in the receive complete state? jnz read6 lxi d,infms3 ; Plus a little cuteness. mvi c,prstr call bdos jmp kermit read6: cpi 'A' ; Are we in the receive abort state? jnz read7 lxi d,infms4 ; Plus a little cuteness. mvi c,prstr call bdos jmp kermit read7: lxi d,infms4 ; Plus a little cuteness. mvi c,prstr call bdos jmp kermit ; Initialize buffers and clear line. init: mvi c,prstr ; Put statistics headers on the screen. lxi d,outlin call bdos init1: mvi a,bufsiz ; Buffer size. sta chrcnt ; Number of chars left. lxi h,buff ; Addr for beginning. shld bufpnt ; Store addr for beginning. ret ; Receive routines ; Receive init rinit: lda numtry ; Get the number of tries. cpi imxtry ; Have we reached the maximum number of tries? jm rinit2 lxi d,ermes4 mvi c,prstr call bdos ; Print an error message. jmp abort ; Change the state to abort. rinit2: inr a ; Increment it. sta numtry ; Save the updated number of tries. 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. mvi a,0 sta numtry ; Reset the number of tries. lda argblk ; Returned packet number. (Synchronize them.) inr a ; Increment it. ani 3FH ; Turn off the two high order bits. sta pktnum ; Save modulo 64 of the number. lhld numpkt inx h ; Increment the number of packets. shld numpkt 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. mvi a,'F' ; Set the state to file send. sta state ret rinit3: cpi 'E' ; Is it an error packet. jnz abort call error jmp abort ; These are some utility routines. ; Abort abort: mvi a,'A' ; Otherwise abort. sta state ret ; NAK nak: lda pktnum ; Get the packet number we're waiting for. sta argblk mvi a,0 ; No data. sta argblk+1 mvi a,'N' ; NAK that packet. call spack jmp abort ; Give up. ret ; Go around again. ; This routine sets up the data for init packet (either the ; Send_init or ACK packet). rpar: 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 100O ; 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 a,06H ; Six pieces of data. ret ; This routine reads in all the send_init packet information. spar: 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 100O ; 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 ret ; Receive file rfile: lda numtry ; Get the number of tries. cpi maxtry ; Have we reached the maximum number of tries? jm rfile1 lxi d,ermes5 mvi c,prstr call bdos ; Print an error message. jmp abort ; Change the state to abort. rfile1: inr a ; Increment it. sta numtry ; Save the updated number of tries. 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 mvi c,prstr call bdos ; 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 nak ; No, NAK and try again. mvi c,prstr ; Position cursor. lxi d,scrnrt call bdos lhld numrtr inx h ; Increment the number of retries shld numrtr call nout ; Write the number of retries. mvi a,0 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 rfil21 ; If not proceed. lxi d,ermes6 mvi c,prstr call bdos ; Print an error message. jmp abort ; Change the state to abort. rfil21: 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 nak ; No, NAK it and try again. mvi c,prstr ; Position cursor. lxi d,scrnrt call bdos lhld numrtr inx h ; Increment the number of retries shld numrtr call nout ; Write the number of retries. mvi a,0 sta numtry ; Reset number of tries. sta argblk+1 ; No data. (The packet number is in argblk.) mvi a,'Y' ; Acknowledge packet. call spack ; Send the packet. jmp abort ; Failed, abort. ret rfile3: cpi 'F' ; Start of file? jnz rfile4 lda pktnum ; Get the packet number. mov b,a lda argblk cmp b ; Is it the right packet number? jnz nak ; No, NAK it and try again. inr a ; Increment the packet number. ani 3FH ; Turn off the two high order bits. sta pktnum ; Save modulo 64 of the number. lhld numpkt inx h ; Increment the number of packets. shld numpkt call gofil ; Get a file to write to. jmp abort call init1 ; Initialize all the buffers. lda numtry ; Get the number of tries. sta oldtry ; Save it. mvi a,0 sta numtry ; Reset the number of tries. sta argblk+1 ; No data. (The packet number is in argblk.) mvi a,'Y' ; Acknowledge packet. call spack ; Send the packet. jmp abort mvi a,'D' ; Set the state to data receive. sta state ret rfile4: cpi 'B' ; End of transmission. jnz rfile5 lda pktnum ; Get the packet number. mov b,a lda argblk cmp b ; Is it the right packet number? jnz nak ; No, NAK it and try again. mvi a,0 ; 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 rfile5: cpi 'E' ; Is it an error packet. jnz abort call error jmp abort ; Receive data rdata: lda numtry ; Get the number of tries. cpi maxtry ; Have we reached the maximum number of tries? jm rdata1 lxi d,erms10 mvi c,prstr call bdos ; Print an error message. jmp abort ; Change the state to abort. rdata1: inr a ; Increment it. sta numtry ; Save the updated number of tries. 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: lda pktnum ; Get the present packet number. mov b,a lda argblk ; Get the packet's number. cmp b ; Is the packet's number correct? jz rdat14 lda oldtry ; Get the number of tries. cpi maxtry ; Have we reached the maximum number of tries? jm rdat12 ; If not proceed. lxi d,erms10 mvi c,prstr call bdos ; Print an error message. jmp abort ; Change the state to abort. rdat12: 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 nak ; No, NAK it and try again. mvi c,prstr ; Position cursor. lxi d,scrnrt call bdos lhld numrtr inx h ; Increment the number of retries shld numrtr call nout ; Write the number of retries. mvi a,0 sta numtry ; Reset number of tries. sta argblk+1 ; No data. (The packet number is in argblk.) mvi a,'Y' ; Acknowledge packet. call spack ; Send the packet. jmp abort ; Failed, abort. ret rdat14: inr a ; Increment the packet number. ani 3FH ; Turn off the two high order bits. sta pktnum ; Save modulo 64 of the number. lhld numpkt inx h ; Increment the number of packets. shld numpkt 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. mvi a,0 sta numtry ; Reset the number of tries. sta argblk+1 ; No data. (Packet number still in argblk.) 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 rdat21 ; If not proceed. lxi d,ermes5 mvi c,prstr call bdos ; Print an error message. jmp abort ; Change the state to abort. rdat21: 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 nak ; No, NAK it and try again. mvi c,prstr ; Position cursor. lxi d,scrnrt call bdos lhld numrtr inx h ; Increment the number of retries shld numrtr call nout ; Write the number of retries. mvi a,0 sta numtry ; Reset number of tries. sta argblk+1 ; No data. (The packet number is in argblk.) mvi a,'Y' ; Acknowledge packet. call spack ; Send the packet. jmp abort ; Failed, abort. ret rdata3: cpi 'Z' ; Is it a EOF packet? jnz rdata4 ; Try and see if its an error. lda pktnum ; Get the present packet number. mov b,a lda argblk ; Get the packet's number cmp b ; Is the packet's number correct? jnz nak ; No, NAK it and try again. inr a ; Increment the packet number. ani 3FH ; Turn off the two high order bits. sta pktnum ; Save modulo 64 of the number. lhld numpkt inx h ; Increment the number of packets. shld numpkt rdat33: lhld bufpnt ; Get the dma pointer. lda chrcnt ; Get the number of chars left in the DMA. rdat34: dcr a ; Lower the count. cpi 0 jm rdat35 ; If full then stop. mvi m,'Z'-100O ; 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. mvi c,closf ; Close up the file. lxi d,fcb call bdos lda numtry ; Get the number of tries. sta oldtry ; Save it. mvi a,0 sta numtry ; Reset the number of tries. sta argblk+1 ; No data. (The packet number is in argblk.) mvi a,'Y' ; Acknowledge packet. call spack ; Send the packet. jmp abort mvi a,'F' sta state ret rdata4: cpi 'E' ; Is it an error packet. jnz abort call error jmp abort ; Send command send: mvi a,cmifi ; Parse an input file spec. lxi d,fcb ; Give the address for the FCB. call comnd jmp kermit ; Give up on bad parse. send1: mvi a,cmcfm call comnd ; Get a confirm. jmp kermit ; Didn't get a confirm. send11: mvi a,0 ; Zero the fcb list number. sta fcbnum mvi c,sfirst ; Get the first file. lxi d,fcb call bdos cpi 0FFH ; Any found? jnz send12 mvi c,prstr lxi d,erms15 call bdos jmp kermit send12: lxi h,buff ; Get the right offset in the buffer. rlc rlc rlc rlc rlc add l mov l,a shld bufpnt lda fcb ;[UTK1] Get our drive spec. mov m,a ;[UTK1] Put it in fcb in buffer too. lxi h,fcbblk ; Get the base address of the list. lda fcbnum ; Get the FCB number. rlc ; Compute the offset. rlc rlc rlc mov c,a ; Add it to the base of the list. mvi b,0 dad b shld fcbptr lda fcbnum adi 1 sta fcbnum mvi b,0 send13: lhld bufpnt ; Get next char. mov a,m inx h shld bufpnt lhld fcbptr ; Put the char in the FCB. mov m,a inx h shld fcbptr inr b mov a,b cpi 10H ; Done? jm send13 mvi c,snext ; Get the next file. lxi d,fcb call bdos cpi 0FFH ; Any found, go move the fcb into the list. jnz send12 lda fcbnum sui 1 sta fcbnum lxi h,fcbblk ; Get the base address of the list. rlc ; Compute the offset. rlc rlc rlc mov c,a ; Add it to the base of the list. mvi b,0 dad b shld bufpnt lxi h,fcb shld fcbptr mvi b,0 send14: lhld bufpnt ; Get next char. mov a,m inx h shld bufpnt lhld fcbptr ; Put the char in the FCB. mov m,a inx h shld fcbptr inr b mov a,b cpi 10H ; Done? jm send14 call init ; Clear the line and initialize the buffers. mvi a,0 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. mvi c,prstr ; Position cursor. lxi d,scrnrt call bdos lxi h,0 call nout ; Write the number of retries. IF robin call kerint ENDIF mvi a,'S' sta state ; Set the state to receive initiate. send2: mvi c,prstr ; Be informative. lxi d,infms2 call bdos lhld numpkt call nout ; 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 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 lxi d,infms3 ; Plus a little cuteness. mvi c,prstr call bdos jmp kermit send8: cpi 'A' ; Are we in the send abort state? jnz send9 lxi d,infms4 ; Plus a little cuteness. mvi c,prstr call bdos jmp kermit send9: lxi d,infms4 ; Plus a little cuteness. mvi c,prstr call bdos jmp kermit ; Send routines ; Send initiate sinit: lda numtry ; Get the number of tries. cpi imxtry ; Have we reached the maximum number of tries? jm sinit2 lxi d,erms14 mvi c,prstr call bdos ; Print an error message. jmp abort ; Change the state to abort. sinit2: inr a ; Increment it. sta numtry ; Save the updated 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. 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. lda pktnum ; Get the packet number. mov b,a lda argblk cmp b ; Is it the right packet number? rnz ; If not try again. inr a ; Increment the packet number. ani 3FH ; Turn off the two high order bits. sta pktnum ; Save modulo 64 of the number. lhld numpkt inx h ; Increment the number of packets. shld numpkt 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. mvi a,0 sta numtry ; Reset the number of tries. mvi a,'F' ; Set the state to file send. sta state call getfil ; Open the file. jmp abort ; Something is wrong, die. ret sinit3: cpi 'N' ; NAK? jnz sinit4 ; If not see if its an error. mvi c,prstr ; Position cursor. lxi d,scrnrt call bdos lhld numrtr inx h ; Increment the number of retries shld numrtr call nout ; Write 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. mvi a,0 sta numtry ; Reset number of tries. mvi a,'F' ; Set the state to file send. sta state ret sinit4: cpi 'E' ; Is it an error packet. jnz abort call error jmp abort ; Send file header sfile: lda numtry ; Get the number of tries. cpi maxtry ; Have we reached the maximum number of tries? jm sfile1 lxi d,erms14 mvi c,prstr call bdos ; Print an error message. jmp abort ; Change the state to abort. sfile1: inr a ; Increment it. sta numtry ; Save the updated number of tries. lxi h, data ; Get a pointer to our data block. shld datptr ; Save it. lxi h,fcb+1 ; 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 8H ; 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 0CH ; Twelve? jp sfil13 lhld fcbptr mov a,m inx h shld fcbptr ; Save position in FCB. cpi '!' ; 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 a,'$' mov m,a ; Put in a dollar sign for printing. mvi c,prstr ; Position cursor. lxi d,scrfln call bdos mvi c,prstr ; Print the file name. lxi d,data call bdos 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. lda pktnum ; Get the packet number. mov b,a lda argblk cmp b ; Is it the right packet number? rnz ; If not hold out for the right one. sfil14: inr a ; Increment the packet number. ani 3FH ; Turn off the two high order bits. sta pktnum ; Save modulo 64 of the number. lhld numpkt inx h ; Increment the number of packets. shld numpkt lda numtry ; Get the number of tries. sta oldtry ; Save it. mvi a,0 sta numtry ; Reset the number of tries. sfil15: mvi a,0 ; Get a zero. sta fcb+20H ; Set the record number to zero. sta eoflag ; Indicate not EOF. mvi a,0FFH sta filflg ; Indicate file buffer empty. call gtchr jmp sfil16 ; Error go see if its EOF. jmp sfil17 ; Got the chars, proceed. sfil16: cpi 0FFH ; Is it EOF? jnz abort ; If not give up. mvi a,'Z' ; Set the state to EOF. sta state ret sfil17: 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 sfile3 ; Try if error packet. mvi c,prstr ; Position cursor. lxi d,scrnrt call bdos lhld numrtr inx h ; Increment the number of retries shld numrtr call nout ; Write 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. sfile3: cpi 'E' ; Is it an error packet. jnz abort call error jmp abort ; Send data sdata: lda numtry ; Get the number of tries. cpi maxtry ; Have we reached the maximum number of tries? jm sdata1 lxi d,erms14 mvi c,prstr call bdos ; Print an error message. jmp abort ; Change the state to abort. sdata1: inr a ; Increment it. sta numtry ; Save the updated number of tries. 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. lda pktnum ; Get the packet number. mov b,a lda argblk cmp b ; Is it the right packet number? rnz ; If not hold out for the right one. sdat12: inr a ; Increment the packet number. ani 3FH ; Turn off the two high order bits. sta pktnum ; Save modulo 64 of the number. lhld numpkt inx h ; Increment the number of packets. shld numpkt lda numtry ; Get the number of tries. sta oldtry ; Save it. mvi a,0 sta numtry ; Reset the number of tries. call gtchr jmp sdat13 ; Error go see if its EOF. sta size ; Save the size of the data gotten. ret sdat13: cpi 0FFH ; Is it EOF? jnz abort ; If not give up. mvi a,'Z' ; Set the state to EOF. sta state ret sdata2: cpi 'N' ; NAK? jnz sdata3 ; See if is an error packet. mvi c,prstr ; Position cursor. lxi d,scrnrt call bdos lhld numrtr inx h ; Increment the number of retries shld numrtr call nout ; Write 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. sdata3: cpi 'E' ; Is it an error packet. jnz abort call error jmp abort ; Send EOF seof: lda numtry ; Get the number of tries. cpi maxtry ; Have we reached the maximum number of tries? jm seof1 lxi d,erms14 mvi c,prstr call bdos ; Print an error message. jmp abort ; Change the state to abort. seof1: inr a ; Increment it. sta numtry ; Save the updated number of tries. lda pktnum ; Get the packet number. sta argblk mvi a,0 sta argblk+1 ; No data. 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. lda pktnum ; Get the packet number. mov b,a lda argblk cmp b ; Is it the right packet number? rnz ; If not hold out for the right one. seof12: inr a ; Increment the packet number. ani 3FH ; Turn off the two high order bits. sta pktnum ; Save modulo 64 of the number. lhld numpkt inx h ; Increment the number of packets. shld numpkt lda numtry ; Get the number of tries. sta oldtry ; Save it. mvi a,0 sta numtry ; Reset the number of tries. mvi c,closf ; Close the file. lxi d,fcb call bdos ;* Check if successful call gtnfil ; Get the next file. jmp seof13 ; No more. mvi a,'F' ; Set the state to file send. sta state ret seof13: mvi a,'B' ; Set the state to EOT. sta state ret seof2: cpi 'N' ; NAK? jnz seof3 ; Try and see if its an error packet. mvi c,prstr ; Position cursor. lxi d,scrnrt call bdos lhld numrtr inx h ; Increment the number of retries shld numrtr call nout ; Write 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. seof3: cpi 'E' ; Is it an error packet. jnz abort call error jmp abort ; Send EOT seot: lda numtry ; Get the number of tries. cpi maxtry ; Have we reached the maximum number of tries? jm seot1 lxi d,erms14 mvi c,prstr call bdos ; Print an error message. jmp abort ; Change the state to abort. seot1: inr a ; Increment it. sta numtry ; Save the updated number of tries. lda pktnum ; Get the packet number. sta argblk mvi a,0 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. lda pktnum ; Get the packet number. mov b,a lda argblk cmp b ; Is it the right packet number? rnz ; If not hold out for the right one. seot12: inr a ; Increment the packet number. ani 3FH ; Turn off the two high order bits. sta pktnum ; Save modulo 64 of the number. lhld numpkt inx h ; Increment the number of packets. shld numpkt lda numtry ; Get the number of tries. sta oldtry ; Save it. mvi a,0 sta numtry ; Reset the number of tries. mvi a,'C' ; Set the state to file send. sta state ret seot2: cpi 'N' ; NAK? jnz seot3 ; Is it error. mvi c,prstr ; Position cursor. lxi d,scrnrt call bdos lhld numrtr inx h ; Increment the number of retries shld numrtr call nout ; Write 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. seot3: cpi 'E' ; Is it an error packet. jnz abort call error jmp abort ; File routines ; Output the chars in a packet. ptchr: sta temp1 ; Save the size. lxi h,data ; Beginning of received packet data. shld outpnt ; Remember where we are. lda rquote mov b,a ; Keep the quote char in b. ptchr1: lxi h,temp1 dcr m ; Decrement # of chars in packet. jm rskp ; Return successfully if done. lxi h,chrcnt ; Number of chars remaining in dma. dcr m ; Decrement. jp ptchr2 ; Continue if space left. call outbuf ; Output it if full. jmp r ; Error return if disk is full. ptchr2: lhld outpnt ; Get position in output buffer. mov a,m ; Grab a char. inx h shld outpnt ; and bump pointer. cmp b ; Is it the quote char? jnz ptchr4 ; If not proceed. mov a,m ; Get the quoted character inx h shld outpnt ; and bump pointer. lxi h,temp1 dcr m ; Decrement # of chars in packet. mov d,a ; Save the char. ani 80H ; Turn off all but the parity bit. mov e,a ; Save the parity bit. mov a,d ; Get the char. ani 7FH ; Turn off the parity bit. cmp b ; Is it the quote char? jz ptchr3 ; If so just go write it out. mov a,d ; Get the char. adi 40H ; Make the character a control char again. ani 7FH ; Modulo 128. ptchr3: ora e ; Or in the parity bit. ptchr4: lhld bufpnt ; Destination buffer. mov m,a ; Store it. inx h shld bufpnt ; Update the pointer jmp ptchr1 ; and loop to next char. ; output the buffer, reset bufpnt and chrcnt outbuf: push b mvi c,writef ; The write code. lxi d,fcb call bdos ; Write the record. pop b cpi 0 ; Successful. jz outbf1 mvi c,prstr ; Tell about it. lxi d,erms11 call bdos ret outbf1: lxi h,buff ; Addr for beginning. shld bufpnt ; Store addr for beginning. mvi a,bufsiz-1 ; Buffer size. sta chrcnt ; Number of chars left. jmp rskp ; Get the chars from the file. gtchr: lda squote ; Get the quote char. mov c,a ; Keep quote char in c. lda filflg ; Get the file flag. cpi 0 ; Is there anything in the DMA? jz gtchr0 ; Yup, proceed. mvi b,0 ; No chars yet. call inbuf jmp gtceof ; No more chars, go return EOF. gtchr0: lda spsiz ; Get the maximum packet size. sui 5 ; Subtract the overhead. sta temp1 ; This is the number of chars we are to get. lxi h,filbuf ; Where to put the data. shld cbfptr ; Remember where we are. mvi b,0 ; No chars. gtchr1: lda temp1 dcr a ; Decrement the number of chars left. jp gtchr2 ; Go on if there is more than one left. mov a,b ; Return the count in A. jmp rskp gtchr2: sta temp1 lda chrcnt ; Space left in the DMA. dcr a ;* Can improve order here. jm gtchr3 sta chrcnt jmp gtchr4 gtchr3: call inbuf ; Get another buffer full. jmp gtch30 ; If no more return what we got. jmp gtchr4 ; If we got some, proceed. gtch30: mov a,b ; Return the count in A. cpi 0 ; Get any chars? jnz rskp ; If so return them. jmp gtceof ; If not, say we found the end of the file. gtchr4: lhld bufpnt ; Position in DMA. mov a,m ; Get a char from the file. inx h shld bufpnt mov d,a ; Save the char. ani 80H ; Turn off all but parity. mov e,a ; Save the parity bit. mov a,d ; Restore the char. ani 7FH ; Turn off the parity. cpi ' ' ; Compare to a space. jm gtchr5 ; If less then its a control char, handle it. cpi del ; Is the char a delete? jz gtchr5 ; Go quote it. cmp c ; Is it the quote char? jnz gtchr8 ; If not proceed. lxi h,temp1 ; Point to the char total remaining. dcr m ; Decrement it. lhld cbfptr ; Position in character buffer. mov m,a ; Put the char in the buffer. inx h shld cbfptr inr b ; Increment the char count. jmp gtchr8 gtchr5: ora e ; Turn on the parity bit. cpi ('Z'-100O) ; Is it a ^Z? jnz gtchr7 ; If not just proceed. lda eoflag ; EOF flag set? cpi 0 jz gtchr6 ; If not just go on. lda cpmflg ; Was the file created by CPM? cpi 0 jnz gtch52 ; If so, don't check for multiple ^Z's. lhld bufpnt lda chrcnt mov d,a ; Get the number of chars left in the DMA. gtch51: dcr d mov a,d jp gtch53 ; Any chars left? gtch52: mvi a,0 ; If not, get a zero. sta chrcnt ; Say no more chars in buffer. mov a,b ; Return the count in A. jmp rskp gtch53: mov a,m ; Get the next char. inx h ; Move the pointer. cpi ('Z'-100O) ; Is it a ^Z? jz gtch51 ; If so see if they rest are. gtchr6: mvi a,('Z'-100O) ; Restore the ^Z. gtchr7: sta temp2 ; Save the char. lxi h,temp1 ; Point to the char total remaining. dcr m ; Decrement it. lhld cbfptr ; Position in character buffer. mov m,c ; Put the quote in the buffer. inx h shld cbfptr inr b ; Increment the char count. lda temp2 ; Get the control char back. adi 40H ; Make the non-control. ani 7fH ; Modulo 200 octal. gtchr8: lhld cbfptr ; Position in character buffer. ora e ; Or in the parity bit. mov m,a ; Put the char in the buffer. inx h shld cbfptr inr b ; Increment the char count. jmp gtchr1 ; Go around again. gtceof: mvi a,0FFH ; Get a minus one. ret inbuf: lda eoflag ; Have we reached the end? cpi 0 rnz ; Return if set. push b ; Save the ACs. push d push h lxi h,chrcnt ; Reset character count. lda filflg ; Get the file flag. cpi 0 ; Has there ever been anything in the DMA? jz inbuf1 ; If so just set it. mvi m,bufsiz ; If not set it the buffer size. mvi a,0 ; Zero the flag. sta filflg jmp inbuf2 inbuf1: mvi m,bufsiz-1 ; ELse set it to one less than the buffer size. inbuf2: lxi h,buff ; Set the buffer pointer. shld bufpnt mvi c,readf ; Read a record. lxi d,fcb call bdos pop h ; Restore ACs. pop d pop b lda filerc ; Get the file record count. sui 1 ; Decrement it. sta filerc jnz rskp ; If not the last packet then retskp. lda fileex ; Any more left? cpi 0 jz inbuf3 sui 1 sta fileex mvi a,80H ; Get a 128. sta filerc ; Start the record count over. jmp rskp inbuf3: mvi a,0FFH sta eoflag ; Set the EOF flag. jmp rskp ; Get the next file spec. gtnfil: lda fcbnum ; Get the fcb number. sui 1 rm sta fcbnum lxi h,fcbblk ; Get the base address of the list. rlc ; Compute the offset. rlc rlc rlc mov c,a ; Add it to the base of the list. mvi b,0 dad b shld bufpnt lxi h,fcb shld fcbptr mvi b,0 gtnfl1: lhld bufpnt ; Get next char. mov a,m inx h shld bufpnt lhld fcbptr ; Put the char in the FCB. mov m,a inx h shld fcbptr inr b mov a,b cpi 10H ; Done? jm gtnfl1 getfil: mvi c,cflsz ; Get the file size. lxi d,fcb call bdos lda fcb+21H ; Get R0. cpi 0 jm gtnfl2 ; Is the last bit set? mvi b,0 ; If not, we'll or in zero. jmp gtnfl3 gtnfl2: mvi b,1 ; If so, we'll or in one. gtnfl3: ani 7FH sta filerc ; Save as the file record count. lda fcb+22H ; Get R1. rlc ; Shift over one bit. ora b ; Or in the high order from R0. sta fileex ; Save it as the file extent. mvi a,0FFH sta filflg ; Nothing in the DMA. mvi a,0 sta eoflag ; Not the end of file. sta fcb+0CH ; Zero the extent. sta fcb+0EH ; Must be zero for MAKEF or OPENF. sta fcb+20H ; Zero the current record. mvi c,openf ; Open the file. lxi d,fcb call bdos jmp rskp ; Get the file name (including host to micro translation) gofil: lxi h,data ; Get the address of the file name. shld datptr ; Store the address. lxi h,fcb+1 ; Address of the FCB. shld fcbptr ; Save it. mvi a,0 sta temp1 ; Initialize the char count. sta temp2 sta fcb ; Set the drive to default to current. mvi b,' ' gofil1: mov m,b ; Blank the FCB. inx h inr a cpi 0CH ; Twelve? jm gofil1 gofil2: lhld datptr ; Get the NAME field. mov a,m inx h shld datptr cpi '.' ; Seperator? jnz gofil3 lxi h,fcb+9H shld fcbptr lda temp1 sta temp2 mvi a,9H sta temp1 jmp gofil6 gofil3: cpi 0 ; Trailing null? jz gofil7 ; Then we're done. lhld fcbptr mov m,a inx h shld fcbptr lda temp1 ; Get the char count. inr a sta temp1 cpi 8H ; Are we finished with this field? jm gofil2 gofil4: sta temp2 lhld datptr mov a,m inx h shld datptr cpi 0 jz gofil7 cpi '.' ; Is this the terminator? jnz gofil4 ; Go until we find it. gofil6: lhld datptr ; Get the TYPE field. mov a,m inx h shld datptr cpi 0 ; Trailing null? jz gofil7 ; Then we're done. lhld fcbptr mov m,a inx h shld fcbptr lda temp1 ; Get the char count. inr a sta temp1 cpi 0CH ; Are we finished with this field? jm gofil6 gofil7: lhld datptr mvi m,'$' ; Put in a dollar sign for printing. mvi c,prstr ; Position cursor. lxi d,scrfln call bdos mvi c,prstr ; Print the file name. lxi d,data call bdos lda flwflg ; Is file warning on? cpi 0 jz gofil9 ; If not, just proceed. mvi c,openf ; See if the file exists. lxi d,fcb call bdos cpi 0FFH ; Does it exist? jz gofil9 ; If not create it. mvi c,prstr ; Inform the user we are renaming the file. lxi d,infms5 call bdos lda temp2 ; Get the number of chars in the file name. cpi 0 jnz gofil8 lda temp1 sta temp2 gofil8: mvi b,0 mov d,b ;[UTK2] Zero d for dad index into filename inr e mov e,a cpi 9H ; Is the first field full? jnz gofl81 mvi b,0FFH ; Set a flag saying so. dcr e gofl81: lxi h,fcb ; Get the FCB. dad d ; Add in the character number. mvi m,'&' ; Replace the char with an ampersand. push b push d mvi c,openf ; See if the file exists. lxi d,fcb call bdos pop d pop b cpi 0FFH ; Does it exist? jz gofl89 ; If not create it. mov a,b ; Get the flag. cpi 0 jz gofl83 dcr e ; Decrement the number of chars. mov a,e cpi 0 jz gofl88 ; If no more, die. jmp gofl81 gofl83: inr e ; Increment the number of chars. mov a,e cpi 9H ; Are we to the end? jm gofl81 ; If not try again. jz gofl88 ;[UTK2] If yes, quit trying. lda temp2 ; Get the original size. mov e,a jmp gofl81 gofl88: mvi c,prstr ; Tell the user that we can't rename it. lxi d,erms16 call bdos ret gofl89: lxi h,fcb+0CH ; Point past the end of the file name. mov b,m ; Save the present contents. mvi m,'$' ; Put in a dollar sign. push b mvi c,prstr ; Print the file name. lxi d,fcb+1 call bdos pop b lxi h,fcb+0CH ; Restore over the dollar sign. mov m,b gofil9: mvi c,delf ; Delete the file if it exists. lxi d,fcb call bdos mvi a,0 sta fcb+0CH ; Zero the extent. sta fcb+0EH ; Must be zero for MAKEF or OPENF. sta fcb+20H ; Zero the current record. mvi c,makef ; Now create it. lxi d,fcb call bdos cpi 0FFH ; Is the disk full? jnz rskp mvi c,prstr ; If so tell the user. lxi d,erms11 call bdos ret ; Packet routines ; Send_Packet ; This routine assembles a packet from the arguments given and sends it ; to the host. ; ; Expects the following: ; A - Type of packet (D,Y,N,S,R,E,F,Z,T) ; ARGBLK - Packet sequence number ; ARGBLK+1 - Number of data characters ; Returns: +1 on failure ; +2 on success spack: sta argblk+2 mvi b,0 ; Zero the checksum AC. lxi h,packet ; Get address of the send packet. mvi a,soh ; Get the start of header char. mov m,a ; Put in the packet. inx h ; Point to next char. lda argblk+1 ; Get the number of data chars. adi ' '+3 ; Real packet character count made printable. mov m,a ; Put in the packet. inx h ; Point to next char. mov b,a ; Start the checksum. lda argblk ; Get the packet number. adi ' ' ; Add a space so the number is printable. mov m,a ; Put in the packet. inx h ; Point to next char. add b mov b,a ; Add the packet number to the checksum. lda argblk+2 ; Get the packet type. mov m,a ; Put in the packet. inx h ; Point to next char. add b mov b,a ; Add the type to the checksum. spack2: lda argblk+1 ; Get the packet size. cpi 0 ; Are there any chars of data? jz spack3 ; No, finish up. dcr a ; Decrement the char count. sta argblk+1 ; Put it back. mov a,m ; Get the next char. inx h ; Point to next char. add b mov b,a ; Add the char to the checksum. jmp spack2 ; Go try again. spack3: mov a,b ; Get the character total. ani 0C0H ; Turn off all but the two high order bits. rrc rrc rrc rrc rrc rrc ; Shift them into the low order position. add b ; Add it to the old bits. ani 3FH ; Turn off the two high order bits. (MOD 64) adi ' ' ; Add a space so the number is printable. mov m,a ; Put in the packet. inx h ; Point to next char. lda seol ; Get the EOL the other host wants. mov m,a ; Put in the packet. inx h ; Point to next char. mvi a,0 ; Get a null. mov m,a ; Put in the packet. IF debug inx h ; Point to next char. mvi a,'$' ; Get a dollar sign. mov m,a ; Put in the packet. ENDIF call outpkt ; Call the system dependent routine. jmp r jmp rskp ; Write out a packet. outpkt: lda spad ; Get the number of padding chars. sta temp1 outpk2: lda temp1 ; Get the count. dcr a cpi 0 jm outpk6 ; If none left proceed. sta temp1 lda spadch ; Get the padding char. mov e,a ; Put the char in right AC. call outchr ; Output it. jmp outpk2 outpk6: lda ibmflg ; Is this the (dumb) IBM. cpi 0 jz outpk8 ; If not then proceed. lda state ; Check if this is the Send-Init packet. cpi 'S' jz outpk8 ; If so don't wait for the XON. outpk7: call inchr ; Wait for the turn around char. jmp outpk8 cpi xon ; Is it the IBM turn around character? jnz outpk7 ; If not, go until it is. outpk8: IF debug mvi c,prstr ; Print the packet lxi d,sppos call bdos lxi d,packet+1 mvi c,prstr call bdos ENDIF lxi h,packet ; Point to the packet. outlup: mov a,m ; Get the next character. cpi 0 ; Is it a null? jz rskp ; If so return success. mov e,a ; Put the char in right AC. call outchr ; Output the character. inx h ; Increment the char pointer. jmp outlup ; Set the parity for a character in A. setpar: push h ; Save HL. push b lxi h,parity mov c,m ; Get the parity routine. mvi b,0 lxi h,parjmp ; Get the first address. dad b pchl parjmp: jmp even jmp mark jmp none jmp odd jmp space none: jmp parret ; Don't touch the parity bit. even: ani 7FH ; Strip parity. jpe parret ; Already even, leave it. ori 80H ; Make it even parity. jmp parret mark: ori 80H ; Turn on the parity bit. jmp parret odd: ani 7FH ; Strip parity. jpo parret ; Already odd, leave it. ori 80H ; Make it odd parity. jmp parret space: ani 7FH ; Turn off the parity bit. jmp parret parret: pop b pop h ; Restore HL. ret ;************************System Dependent**************************** ; Put a char in E to the port. IF osi OR apple outchr: lda mnprts ; Get the port status into A. ani output ; Loop till ready. jz outchr mov a,e call setpar sta mnport ; Write the character. ret ENDIF IF osbrn1 outchr: call osldst ; Read the status port ani output ; Loop till ready. jz outchr mov a,e call setpar ; What about Bit 7? jmp osstda ; Write to the data port ENDIF IF brain OR vector OR heath OR z100 OR trs80 OR telcon outchr: in mnprts ; Get the output ready flag. ani output ; Is it set? jz outchr ; If so, loop until it isn't. mov a,e call setpar out mnport ; Output it. ret ENDIF IF robin outchr: lda gppflg ; Want to use the other port? cpi 0 ; . . . jz outchc ; No, use comm port outchg: in gentst ; Get the status of the general purpose port ani output ; Is it ready for output? jz outchg ; if not, wait until ready mov a,e ; Get the character call setpar ; Set the parity properly out gendat ; Output the character ret ; And return outchc: in comtst ; Get the output ready flag. ani output ; Is it set? jz outchc ; If so, loop until it isn't. mov a,e call setpar out comdat ; Output it. ret resint: push h ; Restore Interrupt to CPM. lhld cint ; CPM interrupt address. shld 11H ; Back to original. pop h ret kerint: push h ; Grab Interrupt from CPM. lxi h, prtint ; Our interrupt. shld 11H pop h ret ENDIF ;************************System Dependent**************************** ; ; Get a char from the port and return in A. IF osi OR apple inchr: lda mnprts ; Get the port status into A. ENDIF IF osbrn1 inchr: CALL OSLDST ; Read the status port ENDIF IF osi OR apple OR osbrn1 ani input ; See if the input ready bit is on. jnz inchr2 ; If so go read the input. mvi c,consta ; Is a char on the console? call bdos cpi 0 jz inchr ; If not go look for another char. mvi c,conin ; Get the char. call bdos cpi cr ; Is it a carriage return? jnz inchr ; If not go look for another char. ret ENDIF IF osi OR apple inchr2: lxi h,mnport ; If so, get the char. mov b,m ENDIF IF osbrn1 inchr2: CALL OSLDDA ; Read the data port mov b,a ENDIF IF osi OR apple OR osbrn1 lda parity ; Is the parity none? cpi parnon mov a,b jz rskp ; If so just return. ani 7FH ; Turn off the parity bit. jmp rskp ENDIF IF brain OR vector OR heath OR z100 OR trs80 OR telcon inchr: in mnprts ; Get the port status into A. ani input ; See if the input ready bit is on. jnz inchr2 ; If so go read the input. mvi c,consta ; Is a char on the console? call bdos cpi 0 jz inchr ; If not go look for another char. mvi c,conin ; Get the char. call bdos cpi cr ; Is it a carriage return? jnz inchr ; If not go look for another char. ret inchr2: in mnport ; If so, get the char. mov b,a lda parity ; Is the parity none? cpi parnon mov a,b jz rskp ; If so just return. ani 7FH ; Turn off the parity bit. jmp rskp ENDIF IF robin inchr: lda pchar cpi 0 jz inchr6 ; Look for console. mov b,a mvi a,0 sta pchar ; Zero it. lda parity ; Is the parity none? cpi parnon mov a,b jz rskp ; If so, just return. ani 7FH ; Turn parity-bit off. jmp rskp inchr6: lda cchar cpi 0 jz inchr mov b,a mvi a,0 sta cchar ; Zero it. mov a,b cpi cr jnz inchr ; Look for another one. ret ENDIF ; Receive_Packet ; This routine waits for a packet to arrive from the host. It reads ; characters until it finds a SOH. It then reads the packet into packet. ; ; Returns: +1 failure (if the checksum is wrong or the packet trashed) ; +2 success with A - message type ; ARGBLK - message number ; ARGBLK+1 - length of data rpack: mvi c,prstr ; Be informative. lxi d,infms0 call bdos rpack9: call inpkt ; Read up to a carriage return. jmp r ; Return bad. rpack0: call getchr ; Get a character. jmp rpack ; Hit a CR; null line; just start over. cpi soh ; Is the char the start of header char? jnz rpack0 ; No, go until it is. rpack1: call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cpi soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. mov b,a ; Start the checksum. sui ' '+3 ; Get the real data count. sta argblk+1 call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cpi soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. sta argblk add b ; Add it to the checksum. mov b,a lda argblk sui ' ' ; Get the real packet number. sta argblk call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cpi soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. sta temp1 ; Save the message type. add b ; Add it to the checksum. mov b,a lda argblk+1 ; Get the number of data characters. sta temp2 lxi h,data ; Point to the data buffer. shld datptr rpack2: lda temp2 sui 1 ; Any data characters? jm rpack3 ; If not go get the checksum. sta temp2 call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cpi soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. lhld datptr mov m,a ; Put the char into the packet. inx h ; Point to the next character. shld datptr add b ; Add it to the checksum. mov b,a jmp rpack2 ; Go get another. rpack3: call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cpi soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. sui ' ' ; Turn the char back into a number. sta temp3 mov a,b ; Get the character total. ani 0C0H ; Turn off all but the two high order bits. rrc rrc rrc rrc rrc rrc ; Shift them into the low order position. add b ; Add it to the old bits. ani 3FH ; Turn off the two high order bits. (MOD 64) mov b,a lda temp3 ; Get the real received checksum. cmp b ; Are they equal? jz rpack4 ; If so finish up. lxi d,dimsg1 mvi c,prstr call bdos ; Print a diagnostic message. ret rpack4: lhld datptr mvi m,0 ; Put a null at the end of the data. lda temp1 ; Get the type. jmp rskp inpkt: lxi h,recpkt ; Point to the beginning of the packet. shld pktptr inpkt2: call inchr ; Get a character. jmp r ; Return failure. lhld pktptr mov m,a ; Put the char in the packet. inx h shld pktptr mov b,a lda reol ; Get the EOL char. cmp b jnz inpkt2 ; If not loop for another. IF debug mvi a,'$' ; Get a dollar sign. mov m,a ; Put in the packet. inx h ; Point to next char. lxi d,rppos ; Print the packet mvi c,prstr call bdos lxi d,recpkt+1 mvi c,prstr call bdos ENDIF lxi h,recpkt shld pktptr ; Save the packet pointer. jmp rskp ; If so we are done. getchr: lhld pktptr ; Get the packet pointer. mov a,m ; Get the char. inx h shld pktptr cpi cr ; Is it the carriage return? jnz rskp ; If not return retskp. ret ; If so return failure. ; This is where we go if we get an error packet. ; Call error prints the error message on line 6 or so. ; Call error1 print CRLF followed by the message. ; Call error2 just prints the message. error: mvi a,'A' ; Set the state to abort. sta state mvi c,prstr ; Position the cursor. lxi d,screrr call bdos jmp error2 error1: mvi c,prstr lxi d,crlf ; Print a CRLF. call bdos error2: lda argblk+1 ; Get the length of the data. mov c,a mvi b,0 ; Put it into BC lxi h,data ; Get the address of the data. dad b ; Get to the end of the string. mvi a,'$' ; Put a dollar sign at the end. mov m,a mvi c,prstr ; Print the error message. lxi d,data call bdos ret ; This is the FINISH command. It tells the remote KERSRV to exit. finish: mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. IF robin call kerint ENDIF mvi a,0 sta numtry ; Inititialize count. finsh1: lda numtry ; How many times have we tried? cpi maxtry ; Too many times? jm finsh3 ; No, try it. finsh2: lxi d,erms18 ; Say we couldn't do it. mvi c,prstr call bdos jmp kermit ; Go home. finsh3: inr a ; Increment the number of tries. sta numtry mvi a,0 sta argblk ; Make it packet number zero. mvi a,1 sta argblk+1 ; One piece of data. lxi h,data mvi m,'F' ; Finish running Kermit. mvi a,'G' ; Generic command packet. call spack jmp finsh2 ; Tell the user and die. call rpack9 ; Get an acknowledgement (don't touch screen.) jmp finsh1 ; Go try again. cpi 'Y' ; ACK? jz kermit ; Yes, we are done. cpi 'E' ; Is it an error packet? jnz finsh1 ; Try sending the packet again. call error1 ; Print the error message. jmp kermit ; This is the LOGOUT command. It tells the remote KERSRV to logout. logout: mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. call logo ; Send the logout packet. jmp kermit ; Go get another command jmp kermit ; whether we succeed or not. logo: IF robin call kerint ENDIF mvi a,0 sta numtry ; Inititialize count. logo1: lda numtry ; How many times have we tried? cpi maxtry ; Too many times? jm logo3 ; No, try it. logo2: lxi d,erms19 ; Say we couldn't do it. mvi c,prstr call bdos ret ; Finished. logo3: inr a ; Increment the number of tries. sta numtry mvi a,0 sta argblk ; Make it packet number zero. mvi a,1 sta argblk+1 ; One piece of data. lxi h,data mvi m,'L' ; Logout the remote host. mvi a,'G' ; Generic command packet. call spack jmp logo2 ; Tell the user and die. call rpack9 ; Get an acknowledgement (don't play screen.) jmp logo1 ; Go try again. cpi 'Y' ; ACK? jz rskp ; Yes, we are done. cpi 'E' ; Is it an error packet? jnz logo1 ; Try sending the packet again. call error1 ; Print the error message. ret ; All done. ; This is the BYE command. It tells the remote KERSRV to logout and exits. bye: mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. call logo ; Tell the main frame to logout. jmp kermit ; If it fails, don't exit. IF apple mvi a,0 ; Hangup our end too! sta mnmodm ENDIF jmp exit1 ; Exit Kermit. ; This is the 'exit' command. It leaves KERMIT and returns to CP/M. exit: mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. exit1: IF robin call resint ENDIF lhld oldsp ; Get back the system stack sphl ; and restore it. ret ; Then return to system. ; This is the log command. It logs a session to a file. log: mvi a,cmofi ; Parse an input file spec. lxi d,fcb call comnd jmp kermt3 mvi a,cmcfm ; Parse a confirm. call comnd jmp kermt3 lxi h,logflg mvi m,0FFH ; Set the log flag. lxi h,buff shld bufpnt mvi c,delf ; Delete the file if it exists. lxi d,fcb call bdos mvi a,0 sta fcb+0CH ; Zero the extent. sta fcb+0EH ; Must be zero for MAKEF or OPENF. sta fcb+20H ; Zero the current record. mvi c,makef ; Now create it. lxi d,fcb call bdos cpi 0FFH ; Is the disk full? jnz kermit ;[UTK3] mvi c,prstr ; If so tell the user. lxi d,erms17 call bdos jmp kermit ; This is the 'help' command. It gives a list of the commands. help: mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. help2: mvi c,prstr ; Print a string to the console. lxi d,tophlp ; The address of the help message. call bdos jmp kermit ; This is the CONNECT command. telnet: mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. IF apple call ckdial ; See if dialing is required. jmp kermit ; Go to command loop if aborted. ENDIF mvi c,prstr ; Output start of message. lxi d,infms7 call bdos call escpr ; Print the escape char. mvi c,prstr ; Output the rest of the message. lxi d,infms8 call bdos IF robin call kerint ENDIF IF apple call ckdial ; See if dialing is required. jmp kermit ; Go to command loop if aborted. ENDIF chrlup: call prtchr ; See if char at port (type to cons). call conchr ; See if char at cons (type to port). jmp kermit ; Go to command loop. jmp chrlup ; Go do it again. ;************************System Dependent**************************** IF osi OR apple prtchr: lda mnprtst ; Get the port status into A. ani input ; See if the input ready bit is on. rz ; If not then return. prtch2: lda mnport ; If so, get the char. ENDIF IF osbrn1 prtchr: CALL OSLDST ; Read the status port ani input rz prtch2: CALL OSLDDA ; read the data port ENDIF IF brain OR vector OR heath OR z100 OR trs80 OR telcon prtchr: in mnprts ; Get the port status into A. ani input ; See if the input ready bit is on. rz ; If not then return. prtch2: in mnport ; If so, get the char. ENDIF IF robin prtint: push psw ; Save. in comtst ; Check communication-port. ani input ; See if the input ready bit is on. jnz prtch2 ; If so read it. in gentst ; Check general port ani input ; Input ready? jnz prtchg ; Might have character there in contst ; Check console ani input jnz prtch7 ; Read it. in prntst ani input jz prtret ; Check next one. in prndat ; Read and forget. prtret: pop psw ei ret ; Back from interrupt. prtch2: lda gppflg ; Using general port? cpi 0 ; . . . jz prtchc ; No, get this character in comdat ; Yes, get the character jmp prtret ; and return prtchc: in comdat ; If so, get the char. sta pchar ; Store it jmp prtret ; and return. prtch7: in condat ; Get char from console. sta cchar ; Store it jmp prtret ; and return. prtchg: lda gppflg ; Using general purpose port? cpi 0 ; . . . jz prtch9 ; No, just ingore character in gendat ; Yes, get the character sta pchar ; Store it jmp prtret ; And return prtch9: in gendat ; Get the character jmp prtret ; And return prtchr: lda pchar cpi 0 rz mov e,a mvi a,0 sta pchar mov a,e ENDIF ani 7FH ; Make seven bit. mov e,a ; Set the char aside. IF NOT robin lda vtflg ; Get the VT52 emulation flag. cpi 0 ; Is the flag set? jz prtch1 ; If not, don't do this stuff. ENDIF IF vector lda vtvflg ; Get the vector cursor control flag. cpi 0 jnz vtvect ; If its not zero go process the char. ENDIF IF NOT robin lda escflg ; Get the escape flag. cpi 0 ; Is the flag set? jnz vt52 ; If so go translate the sequence. mov a,e ; Get the char for testing. cpi del ; Is the char a delete. rz ; If so then forget this foolishness. cpi esc ; Is the char an escape? jnz prtch1 ; If not skip on. mvi a,1 ; Get a one. sta escflg ; Set the escape flag. jmp prtchr ; Get another char... ENDIF prtch1: lda logflg ; Get the log flag. cpi 0 cnz logit ; Log the char if it is set. mvi c,dconio ; Console output bdos call. call bdos ; Output the char to the console. jmp prtchr ; Go see if there is another character. IF robin conchr: lda cchar cpi 0 jz rskp push b mov b,a mvi a,0 sta cchar mov a,b pop b ENDIF IF NOT robin conchr: mvi c,dconio ; Direct console I/O BDOS call. mvi e,0FFH ; Input. call BDOS cpi 0 ; Is it a null? jz rskp ; If so, don't bother to write it. ENDIF mov e,a ; Move the char for comparison. lda escchr ; Get the escape char. cmp e ; Is it an escape char? jz intchr ; If so go process it. mov a,e ; Get the char. call setpar ; Set parity (if any). mov e,a ; Restore it. call prtout ; Output the char to the port. lda ecoflg ; Get the echo flag. cpi 0 ; Is it turned on? jz rskp ; If not we're done here. mvi c,dconio ; Direct console output. mov a,e ; Get the char. ani 7FH ; Turn off the parity bit. mov e,a ; Return it. call bdos ; Echo the char. jmp rskp IF robin intchr: lda cchar cpi 0 jz intchr mov b,a mvi a,0 sta cchar mov a,b ENDIF IF NOT robin intchr: mvi c,dconio ; Direct console I/O. mvi e,0FFH ; Input. call bdos ; Get a char. cpi 0 ; Is the char a null? jz intchr ; If so, go until we get a char. ENDIF mov b,a ; Save the actual char. ani 137O ; Convert to upper case. cpi 'C' ; Is it close? jnz intch0 ; If not proceed. mvi c,prstr ; Say we are back. lxi d,infms9 call bdos lda logflg ; Get the log flag. cpi 0 ; Is it set? rz ; Return if it is zero. mvi a,0 sta logflg ; Turn off the log flag. mvi c,prstr ; Tell the user we are closing the file. lxi d,infms6 call bdos lhld bufpnt mvi m,('Z'-100O) ; Put in a ^Z. mvi c,writef ; Write the last buffer. lxi d,fcb call bdos mvi c,closf ; Close the file. lxi d,fcb call bdos ret IF apple intch0: cpi 'D' ;Disconnect Modem? jnz apintc mvi a,0 ;Hangup the modem sta mnmodm ret apintc: cpi 'S' ; Is it status? ENDIF IF NOT apple intch0: cpi 'S' ; Is it status? ENDIF jnz inch01 ; If not, proceed. IF robin call resint ENDIF call stat01 ; Print out the status stuff. IF robin call kerint ENDIF jmp rskp inch01: mov a,b ; Get the char. cpi '?' ; Is it help? jnz intch1 ; If not, go to the next check. IF robin call resint ENDIF lxi d,inthlp ; If so, get the address of the help message. mvi c,prstr ; Print it. call bdos IF robin call kerint ENDIF jmp intchr ; Get another char. intch1: mov e,a ; Put the char into another reg. lda escchr ; Get the escape char. cmp e ; Is it the escape char? jnz intch2 ; If not, go send a beep to the user. mov a,e ; Get the char. call setpar mov e,a ; Restore it. call prtout ; Output it. jmp rskp ; Return, we are done here. intch2: mvi e,'G'-100O ; Otherwise send a beep. mvi c,dconio call bdos jmp rskp IF apple ; This code was mostly taken from ; APMODEM.ASM V2.1 ; Based on MODEM.ASM by Ward Christensen ; Modified for the Apple ][ by Gordon Banks 1-Jan-81 ; Micromodem ][ dialer option by Dav Holle 2-Feb-81 ; Code modified for KERMIT by Scott Robinson 14-Oct-82 ; ; Come here to see if we need to dial a number. ; ckdial: lda mnport ;access the data port lda mnprts ;check status ani 4 ;do we already have carrier? jz rskp ; Yes, just continue mvi a,0 ;Hangup Phone for starters sta mnmodm lxi b,1000 ;Delay for a second call delay mvi a,8FH ;orgmod+ap300+apoffh sta holdd ; storing mode for after dialing mvi A,8DH ;Go Offhook to start dialing sequence sta mnmodm mvi a,APINC1 ;Init ACIA sta mnport mvi a,APINC2 ;Set ACIA bits per character sta mnport lxi b,2500 ;wait 2.5 seconds for dial tone call delay lxi d,dialms ;Ask the user for the number mvi c,prstr call bdos ; gtdial: mvi c,conin ;Get a character call bdos push psw ;save it cpi 30H ;is it big enough to dial? jc dialed ; no cpi 3AH ;is it too big to dial? jnc dialed ; yes ani 0FH ;ok, it's a digit, get its value jnz dialnz ;dial nonzero digits as-is mvi A,10 ;dial zero as ten ; dialnz: mov e,a ;count pulses in E-reg dopuls: mvi a,0DH ;put it on-hook sta mnmodm LXI B,61 ;61-millisec pulse CALL DELAY MVI A,8DH ;take it off-hook again... STA mnmodm LXI B,39 ;39-millisec delay between pulses CALL DELAY DCR E ;any more pulses to do? JNZ DOPULS ; yep, do 'em LXI B,600 ;delay 600 msecs between digits CALL DELAY ; DIALED: POP PSW ;get back the char CPI CR ;do we have a CR (done dialing)? JNZ GTDIAL ; no, keep on dialin' lxi d,dialm2 mvi c,prstr call bdos TICTOC: mvi c,dconio ;Direct console input. mvi e,0FFH call BDOS cpi 0 ; Have a charcter? jnz nodial ; If so we abort LDA mnport ;access the data port LDA mnprts ;get modem status ANI 4 ;carrier? JNZ TICTOC ;No ; LDA HOLDD ;get the old modem control byte STA mnmodm ;turn our carrier on lxi d,dialm3 mvi c,prstr call bdos jmp rskp nodial: mvi a,0 ;Hangup the modem. sta mnmodm ret ;Return to abort the command. ; holdd: db 0 ;Modem setup code dialms: DB 'Number to Dial: $' dialm2: DB CR,LF,'Awaiting Carrier....(any key aborts)$' dialm3: DB cr,lf,'Connected.',CR,LF,'$' ; ; DELAY wait for the number of millisecs in B,C ; DELAY: PUSH B ;save B,C PUSH D ;save D,E INR B ;bump B for later DCR ; DELAY1: MVI E,126 ;delay count for 1 millisec (Apple Z80 clock=2.041MHz) ; DELAY2: DCR E ;count JNZ DELAY2 ; down ; DCR C ;more millisecs? JNZ DELAY1 ; yes DCR B ;no - more in hi byte? JNZ DELAY1 ; yes POP D ; no, restore D,E POP B ; restore B,C RET ENDIF IF NOT robin vt52: mvi a,00H ; Reset the ol' escape flag. sta escflg mov a,e ; Get the char. ENDIF IF vector cpi 'Y' ; Is it cursor position? jnz vt52a ; If so handle it special. mvi a,2 sta vtvflg ; Save the flag saying so. mvi c,conout ; Output the escape. mvi e,esc call bdos ret vt52a: ENDIF IF NOT robin cpi 'A' ; Less than an 'A'? jm vtig ; Yes - ignore. cpi 'K'+1 ; Greater than 'K'? jp vtig ; Yes - ignore. sui 'A' ; Else make into index. rlc ; Multiply by four. rlc ; (Shift left twice.) lxi h,ttab ; Load base addr of table. mov e,a ; Move a into de pair. mvi d,00H ; Zero out high byte. dad d ; Double add index+offset. xchg ; Exchange de with hl. mvi c,prstr ; Function code call bdos ; and syscall. ret ; Return. ENDIF IF vector vtvect: ; Treat cursor control special. lda vtvflg ; Get the flag. cpi 02H ; Is this the first char? jnz vtvct2 ; If not go write it. dcr a sta vtvflg ; Save the updated flag. mov a,e ; Get the char. sbi ' '-1 ; Subtract a space to get a number. sta vctccc ; Save the vector cursor control char. ret vtvct2: dcr a sta vtvflg ; Save the updated flag. mov a,e ; Get the char. sbi ' '-1 ; Subtract a space. mov e,a ; Move to output register. mvi c,dconio ; The function call bdos ; and the syscall. lda vctccc ; Get the first char. mov e,a mvi c,dconio ; Output it. call bdos ret ; Return home. ENDIF IF NOT robin vtig: ; Ignore escape sequence. push psw ; Push the char to be output. mvi e,esc ; Load an escape. mvi c,conout ; The function code call bdos ; and the syscal. pop psw ; Restore the character mov e,a ; and move to output register. mvi c,conout ; The function call bdos ; and the syscall. ret ; Return home. ENDIF logit: lhld bufpnt mov m,e ; Store the char. inx h shld bufpnt mov a,l cpi 0 ; Buffer full? rnz push d mvi e,xoff ;[UTK3] ^S to stop the call prtout ;[UTK3] host until we mvi c,writef ; write out the buffer. lxi d,fcb call bdos cpi 0 ; Successful. jz logit2 mvi c,prstr ; Tell about it. lxi d,erms11 call bdos logit2: mvi e,xon ;[UTK3] ^Q to restart call prtout ;[UTK3] the host. lxi h,buff shld bufpnt ; Reset the buffer pointer. pop d ret ; This is the SET command. setcom: lxi d,settab ; Parse a keyword from the set table. lxi h,sethlp mvi a,cmkey call comnd jmp kermt2 lxi h,setjtb ; Get the address of the jump table. mov c,a mvi b,0 dad b pchl setjtb: jmp escape jmp ibmset jmp local jmp kermt3 jmp setsnd jmp filwar jmp setcpm jmp parset IF NOT robin jmp vt52em ENDIF IF brain OR robin OR osbrn1 jmp baud ENDIF IF robin jmp gppset ENDIF ; SET SEND command. setsnd: lxi d,stsntb ; Parse a keyword from the set send table. lxi h,stshlp mvi a,cmkey call comnd jmp kermt2 lxi h,stsjtb ; Get the address of the jump table. mov c,a mvi b,0 dad b pchl stsjtb: jmp stpdch jmp stpad stpad: mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. jmp kermit stpdch: mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. jmp kermit IF brain ; This is the BAUD change SET subcommand. baud: mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. lxi d,baudtb ; Get the address of the baud rate table. mvi c,prstr ; Output to the user. call bdos mvi c,conin ; Console input (with echo). call bdos ani 137O ; Capitalize the char. sui 'A' ; Normalize to zero. jm bderr ; Go tell the user he flubbed. cpi 10H ; Is the number greater than 15? jp bderr ; Go tell the user he flubbed. mov b,a ; Save the number. lda baudrt ; Get the present baud rates. mov d,a ; Set it aside. mov a,b ; Get the new baud rate. rlc ; Shift left 4 places. rlc rlc rlc mov b,a ; Set it aside. mov a,d ; Get the old baud rates. ani 0FH ; Turn off the left. baud2: add b ; Combine the two rates. sta baudrt ; Store the new baud rates. out baudst ; Set the baud rates. jmp kermit bderr: lxi d,ermes2 ; Get the error message. mvi c,prstr ; Print it. call bdos jmp kermit ENDIF IF robin baud: mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. call p8251 ; Set up COMM port jmp kermit ; and come back. P8251: mvi a,0 ; Push 8251 into stable state. out comtst ; By sending three nulls. mvi a,0 out comtst mvi a,0 out comtst mvi a,100O ; Reset 8251. out comtst mvi a,116O ; 1 Stop,no par,8 bits,16*clock sampling. out comtst mvi a,27O ; Error reset,rec ena,data term rdy,xmit ena. out comtst in comtst ; Dummy read. ret ; It's a subroutine. ENDIF IF osbrn1 ; The same command, this time for the Osborne 1 baud: mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. lxi d,baudtb ; Get the address of the baud rate table. mvi c,prstr ; Output to the user. call bdos mvi c,conin ; Console input (with echo). call bdos ani 137O ; Capitalize the char. cpi 'A' ; A means 300 mvi c,0 ; and 0 means 300 in the baud byte jz baud1 cpi 'B' ; B means 1200 jnz bderr ; and anything else is wrong inr c ; non-zero means 1200 baud1: mov a,c sta osbaud ; Remember it. call osbset ; Osborne setup routine jmp kermit bderr: lxi d,ermes2 ; Get the error message. mvi c,prstr ; Print it. call bdos jmp kermit osbset: mvi a,OSBIN1 ; Reset the ACIA CALL OSSTST ; Write the control port osbs1: inr c ; Waiting loop jnz osbs1 lda osbaud ; Go for 300 or 1200? ora a mvi a,osbi03 ; Guess 300 jz osbs2 mvi a,osbi12 ; wrong: 1200 osbs2: sta baudrt ; (seems this is what one does on an Osborne) JMP OSSTST ; Write the control reg. ENDIF ; This is the ESCAPE character SET subcommand. escape: mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. lxi d,escmes ; Get the address of the escape message. mvi c,prstr ; Print it. call bdos mvi c,conin ; Get the char. call bdos sta escchr ; Store the new escape character. jmp kermit ; This is the LOCAL echo SET subcommand. local: lxi d,ontab lxi h,onhlp mvi a,cmkey call comnd jmp kermt2 sta temp1 ; Save the parsed value. mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. lda temp1 ; Get the parsed value. sta ecoflg ; Set the local echo flag. jmp kermit IF NOT robin ; This is the VT52 emulation SET subcommand. vt52em: lxi d,ontab lxi h,onhlp mvi a,cmkey call comnd jmp kermt2 sta temp1 ; Save the parsed value. mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. lda temp1 ; Get the parsed value. sta vtflg ; Set the VT52 emulation flag. jmp kermit ENDIF ; This is the FILE-WARNING SET subcommand filwar: lxi d,ontab lxi h,onhlp mvi a,cmkey call comnd jmp kermt2 sta temp1 ; Save the parsed value. mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. lda temp1 ; Get the parsed value. sta flwflg ; Set the file-warning flag. jmp kermit ; This is the SET IBM command. ibmset: lxi d,ontab lxi h,onhlp mvi a,cmkey call comnd jmp kermt2 sta temp1 ; Save the parsed value. mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. lda temp1 ; Get the parsed value. sta ibmflg ; Set the IBM flag. cpi 0 ; Is it turned on? jz ibmst1 ; If not, set parity to the default. mvi a,ibmpar ; Get the IBM parity. mvi b,1 ; Set local echo on. jmp ibmst2 ibmst1: mvi a,defpar mvi b,0 ; Set local echo off. ibmst2: sta parity ; Save them. mov a,b sta ecoflg jmp kermit ; This is the SET PORT command. IF robin gppset: lxi d,gpptab lxi h,gpphlp mvi a,cmkey call comnd jmp kermt2 sta temp1 ; Save the parsed value. mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. lda temp1 ; Get the parsed value. sta gppflg ; Set the port flag. jmp kermit ENDIF ; SET CPM-CREATED-FILE command. setcpm: lxi d,ontab lxi h,onhlp mvi a,cmkey call comnd jmp kermt3 sta temp1 ; Save the parsed value. mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. lda temp1 ; Get the parsed value. sta cpmflg ; Set the CPM flag. jmp kermit parset: lxi d,partab lxi h,parhlp mvi a,cmkey call comnd jmp kermt3 sta temp1 ; Save the parsed value. mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. lda temp1 ; Get the parsed value. sta parity ; Set the CPM flag. jmp kermit ; This is the SHOW command. show: mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. ;* Reconcile this and status. call stat01 ; For now just cop out. jmp kermit ; This is the STATUS command. status: call stat0 jmp kermit stat0: mvi a,cmcfm call comnd ; Get a confirm. jmp kermt3 ; Didn't get a confirm. stat01: lxi d,locst ; Get the address of the local echo string. mvi c,prstr ; Print it. call bdos lda ecoflg ; Get the local echo flag. cpi 0 ; Is it on? jz stat02 ; If not say so. lxi d,onstr ; Say on. jmp stat03 stat02: lxi d,offstr ; Say off. stat03: mvi c,prstr ; Print it. call bdos IF NOT robin lxi d,vtemst ; Get the address of the VT52 emulation string. mvi c,prstr ; Print it. call bdos lda vtflg ; Get the VT52 emulation flag. cpi 0 ; Is it on? jz stat1 ; If not say so. lxi d,onstr ; Say on. jmp stat11 stat1: lxi d,offstr ; Say off. stat11: mvi c,prstr ; Print it. call bdos ENDIF lxi d,cpmst ; Get the address of the CPM created file. mvi c,prstr ; Print it. call bdos lda cpmflg ; Get the CPM flag. cpi 0 ; Is it on? jz stat2 ; If not say so. lxi d,onstr ; Say on. jmp stat21 stat2: lxi d,offstr ; Say off. stat21: mvi c,prstr ; Print it. call bdos lxi d,ibmst ; IBM string. mvi c,prstr ; Print it. call bdos lda ibmflg ; IBM flag. cpi 0 ; Is it on? jz stat3 ; If not say so. lxi d,onstr ; Say on. jmp stat31 stat3: lxi d,offstr ; Say off. stat31: mvi c,prstr ; Print it. call bdos lxi d,filst ; File warning string. mvi c,prstr ; Print it. call bdos lda flwflg ; File warning flag. cpi 0 ; Is it on? jz stat4 ; If not say so. lxi d,onstr ; Say on. jmp stat41 stat4: lxi d,offstr ; Say off. stat41: mvi c,prstr ; Print it. call bdos lxi d,parst ; Parity string. mvi c,prstr ; Print it. call bdos lda parity ; Get the parity setting. lxi d,pnonst ; None by default. cpi parmrk ; Is it mark? jnz stat5 ; If not say so. lxi d,pmrkst ; Say mark. jmp stat55 stat5: cpi parspc ; Is it space? jnz stat51 ; If not say so. lxi d,pspcst ; Say space. jmp stat55 stat51: cpi parodd ; Is it odd? jnz stat52 ; If not say so. lxi d,poddst ; Say odd. jmp stat55 stat52: cpi parevn ; Is it even? jnz stat55 ; If not say so. lxi d,pevnst ; Say even. stat55: mvi c,prstr ; Print it. call bdos lxi d,escst ; Escape string. mvi c,prstr ; Print it. call bdos call escpr ; Print the escape char. lxi d,crlf ; Get the address of a crlf. mvi c,prstr ; Print it. call bdos IF osbrn1 lxi h,300H ; Assume 300 baud lda osbaud ora a jz stat61 mvi h,12H ; No, it's 1200 stat61: call nout ; Print either "300" or "1200" lxi d,osbmsg ; Print " baud",cr,lf mvi c,prstr call bdos ENDIF ret ; Print the escape char. escpr: lda escchr ; Get the escape char. cpi ' ' ; Is it a control char? jp escpr2 mvi c,prstr ; Output Control-. lxi d,inms10 call bdos lda escchr ori 100O ; De-controlify. escpr2: mvi c,conout ; Output the char mov e,a call bdos ret ;************************System Dependent**************************** IF osi OR apple prtout: lxi h,mnport ; Output it. mov m,e ret ENDIF IF osbrn1 prtout: mov a,e jmp OSSTDA ENDIF IF brain OR heath OR z100 OR trs80 OR telcon prtout: in mnprts ; Get the output ready flag. ani output ; Is it set? jz prtout ; If so, loop until it isn't. mov a,e ; Get the char to output. prtou2: out mnport ; Output it. ret ENDIF IF vector prtout: mov a,e ; Get the char to output. out mnport ; Output it. ret ENDIF IF robin prtout: lda gppflg ; Check if using general port cpi 0 ; . . . jz prtouc ; No, using comm port prtoug: in gentst ; Get general port flags ani output ; Ready for output? jz prtoug ; If not, wait until it is mov a,e ; Get the character to print out gendat ; and send it ret ; All done prtouc: in comtst ; Get the output ready flag. ani output ; Is it set? jz prtout ; If so, loop until it isn't. mov a,e ; Get the char to output. out comdat ; Output it. ret ENDIF ; Utility routines ; Jumping to this location is like retskp. It assumes the instruction ; after the call is a jmp addr. rskp: pop h ; Get the return address. inx h ; Increment by three. inx h inx h pchl ; Jumping here is the same as a ret. r: ret ; This routine prints the number in HL on the screen. ; (Thanks to Jeff Damens) nout: mvi a,0 sta temp4 mov a,h push psw ; Save argument. ani 0F0H ; Only want high order nibble. rrc rrc rrc rrc call pdig ; Print the digit. pop psw ; Restore argument. ani 0FH ; Just the low order nibble. call pdig mov a,l push psw ; Save argument. ani 0F0H ; Only want high order nibble. rrc rrc rrc rrc call pdig ; Print the digit. mvi a,0FFH sta temp4 ; Make sure at least one zero is printed. pop psw ; Restore argument. ani 0FH ; Just the low order nibble. ; print the digit in register a pdig: push psw ; Save the digit. cpi 0 jnz pdig2 lda temp4 ; Is the print zero flag set? cpi 0 jnz pdig2 pop psw ret pdig2: mvi a,0FFH ; Set the print zero flag. sta temp4 pop psw ; Restore the digit. cpi 10 ; Do we use digits or a-f? jm usedig ; Digit. adi 'A'-10 ; Compute digit jmp havdig ; and proceed. usedig: adi '0' ; Convert to digit havdig: mov e,a mvi c,conout push h call bdos pop h ; Save h & l from bdos ret ; and return. ; This set of routines provides a user oriented way of parsing ; commands. It is similar to that of the COMND JSYS in TOPS-20. ; This routine prints the prompt in DE and specifies the reparse ; address. prompt: pop h ; Get the return address. push h ; Put it on the stack again. shld cmrprs ; Save it as the address to go to on reparse. lxi h,0 ; Clear out hl pair. dad sp ; Get the present stack pointer. shld cmostp ; Save for later restoral. xchg ; Save the pointer to the prompt. shld cmprmp xchg lxi h,cmdbuf shld cmcptr ; Initialize the command pointer. shld cmdptr mvi a,0 sta cmaflg ; Zero the flags. sta cmccnt mvi a,0FFH ; Try it this way (Daphne.) sta cmsflg mvi c,prstr lxi d,cmcrlf call bdos mvi c,prstr ; Print the prompt. lhld cmprmp xchg call bdos ret ; This address is jumped to on reparse. repars: lhld cmostp ; Get the old stack pointer. sphl ; Make it the present one. lxi h,cmdbuf shld cmdptr mvi a,0FFH ; Try it this way (Daphne.) sta cmsflg lhld cmrprs ; Get the reparse address. pchl ; Go there. ; This address can be jumped to on a parsing error. prserr: lhld cmostp ; Get the old stack pointer. sphl ; Make it the present one. lxi h,cmdbuf shld cmcptr ; Initialize the command pointer. shld cmdptr mvi a,0 sta cmaflg ; Zero the flags. sta cmccnt mvi a,0FFH ; Try it this way (Daphne.) sta cmsflg mvi c,prstr lxi d,cmcrlf call bdos mvi c,prstr ; Print the prompt. lhld cmprmp ; Get the prompt. xchg call bdos ;* Instead return to before the prompt call. lhld cmrprs pchl ; This routine parses the specified function in A. Any additional ; information is in DE and HL. ; Returns +1 on success ; +4 on failure (assumes a JMP follows the call) comnd: sta cmstat ; Save what we are presently parsing. call cminbf ; Get chars until an action or a erase char. cpi cmcfm ; Parse a confirm? jz cmcfrm ; Go get one. cpi cmkey ; Parse a keyword? jz cmkeyw ; Try and get one. cpi cmifi ; Parse an input file spec? jz cmifil ; Go get one. cpi cmofi ; Output file spec? jz cmofil ; Go get one. cpi cmtxt ; Parse arbitrary text? jz cmtext ; Go do it. mvi c,prstr ; Else give an error. lxi d,cmer00 ; "?Unrecognized COMND call" call bdos ret ; This routine parses arbitrary text up to a CR. ; Accepts DE: address to put text ; Returns in A: number of chars in text (may be 0) ; DE: updated pointer cmtext: xchg ; Put the pointer to the dest in HL. shld cmptab ; Save the pointer. mvi b,0 ; Init the char count cmtxt1: call cmgtch ; Get a char. cpi 0 ; Terminator? jp cmtxt5 ; No, put in user space. ani 7FH ; Turn off minus bit. cpi esc ; An escape? jnz cmtxt2 ; No. mvi c,conout mvi e,bell ; Get a bell. call bdos mvi a,0 sta cmaflg ; Turn off the action flag. lhld cmcptr ; Move the pointer to before the escape. dcx h shld cmcptr shld cmdptr lxi h,cmccnt ; Get the char count. dcr m ; Decrement it by one. jmp cmtxt1 ; Try again. cmtxt2: cpi '?' ; Is it a question mark? jz cmtxt3 ; If so put it in the text. cpi ff ; Is it a formfeed? cz cmblnk ; If so blank the screen. mov a,b ; Return the count. lhld cmptab ; Return updated pointer in HL. xchg jmp rskp ; Return success. cmtxt3: lxi h,cmaflg ; Point to the action flag. mvi m,0 ; Set it to zero. cmtxt5: inr b ; Increment the count. lhld cmptab ; Get the pointer. mov m,a ; Put the char in the array. inx h shld cmptab ; Save the updated pointer. jmp cmtxt1 ; Get another char. ; This routine gets a confirm. cmcfrm: call cmgtch ; Get a char. cpi 0 ; Is it negative (a terminator; a space or ; a tab will not be returned here as they ; will be seen as leading white space.) rp ; If not, return failure. ani 7FH ; Turn off the minus bit. cpi esc ; Is it an escape? jnz cmcfr2 mvi c,conout mvi e,bell ; Get a bell. call bdos mvi a,0 sta cmaflg ; Turn off the action flag. lhld cmcptr ; Move the pointer to before the escape. dcx h shld cmcptr shld cmdptr lxi h,cmccnt ; Get the char count. dcr m ; Decrement it by one. jmp cmcfrm ; Try again. cmcfr2: cpi '?' ; Curious? jnz cmcfr3 mvi c,prstr ; Print something useful. lxi d,cmin00 call bdos mvi c,prstr lxi d,cmcrlf ; Print a crlf. call bdos mvi c,prstr lhld cmprmp ; Reprint the prompt. xchg call bdos lhld cmdptr ; Get the pointer into the buffer. mvi a,'$' ; Put a $ there for printing. mov m,a lhld cmcptr dcx h ; Decrement and save the buffer pointer. shld cmcptr mvi c,prstr lxi d,cmdbuf call bdos mvi a,0 ; Turn off the action flag. sta cmaflg jmp repars ; Reparse everything. cmcfr3: cpi ff ; Is it a form feed? cz cmblnk ; If so blank the screen. jmp rskp ; This routine parses a keyword from the table pointed ; to in DE. The format of the table is as follows: ; ; addr: db n ; Where n is the # of entries in the table. ; db m ; M is the size of the keyword. ; db 'string$' ; Where string is the keyword. ; db a,b ; Where a & b are pieces of data ; ; to be returned. (Must be two of them.) ; ; The keywords must be in alphabetical order. cmkeyw: shld cmhlp ; Save the help. xchg ; Get the address of the table. shld cmptab ; Save the beginning of keyword tab for '?'. mov b,m ; Get the number of entries in the table. inx h shld cmkptr lhld cmdptr ; Save the command pointer. shld cmsptr cmkey2: mov a,b ; Get the number of entries left. cpi 0 ; Any left? rz ; If not we failed. lhld cmkptr mov e,m ; Get the length of the keyword. inx h cmkey3: dcr e ; Decrement the number of chars left. mov a,e cpi 0FFH ; Have we passed the end? jm cmkey5 ; If so go to the next. call cmgtch ; Get a char. cpi 0 ; Is it a terminater? jp cmkey4 ; If positive, it is not. ani 7FH ; Turn off the minus bit. cpi '?' jnz cmky31 mvi a,0 sta cmaflg ; Turn off the action flag. lxi h,cmccnt ; Decrement the char count. dcr m ;* Must go through the keyword table and print them. mvi c,prstr lhld cmhlp ; For now print the help text. xchg call bdos mvi c,prstr lxi d,cmcrlf ; Print a crlf. call bdos mvi c,prstr lhld cmprmp ; Reprint the prompt. xchg call bdos lhld cmdptr ; Get the pointer into the buffer. mvi a,'$' ; Put a $ there for printing. mov m,a lhld cmcptr dcx h ; Decrement and save the buffer pointer. shld cmcptr mvi c,prstr lxi d,cmdbuf call bdos jmp repars ; Reparse everything. cmky31: cpi esc ; Is it an escape? jnz cmky35 mvi a,0 sta cmaflg ; Turn off the action flag. push d push b push h call cmambg jmp cmky32 ; Not ambiguous. mvi c,conout mvi e,bell call bdos ; Ring the bell. lhld cmcptr ; Move the pointer to before the escape. dcx h shld cmcptr shld cmdptr lxi h,cmccnt ; Get the char count. dcr m ; Decrement it by one. pop h pop b pop d inr e ; Increment the left to parse char count. jmp cmkey3 cmky32: lhld cmcptr ; Pointer into buffer. dcx h ; Backup to the escape. xchg pop h push h cmky33: mov a,m ; Get the next char. cpi '$' ; Finished? jz cmky34 inx h xchg mov m,a ; Move it into the buffer. inx h xchg lda cmccnt ; Increment the char count. inr a sta cmccnt jmp cmky33 cmky34: lda cmccnt ; Get the character count. inr a ; Increment and save it. sta cmccnt xchg ; Put the command buffer pointer in HL. mvi a,' ' ; Get a blank. mov m,a ; Put it in the command buffer. inx h ; Increment the pointer shld cmcptr ; Save the updated pointer. shld cmdptr pop h push h xchg mvi c,prstr ; Print the rest of the keyword. call bdos mvi c,conout mvi e,' ' call bdos ; Print a blank. pop h pop b pop d jmp cmky37 cmky35: push h push d call cmambg jmp cmky36 mvi c,prstr lxi d,cmer01 call bdos ; Say its ambiguous. jmp prserr ; Give up. cmky36: pop d pop h cmky37: inr e ; Add one incase it is negative. mvi d,0 dad d ; Increment past the keyword. inx h ; Past the $. mov d,m ; Get the data. inx h mov e,m mov a,e jmp rskp cmkey4: cpi 'a' ; Is it less than a? jm cmky41 ; If so don't capitalize it. cpi 'z'+1 ; Is it more than z? jp cmky41 ; If so don't capitalize it. ani 137O ; Capitalize it. cmky41: mov d,m ; Get the next char of the keyword. inx h cmp d ; Match? jz cmkey3 ; If so get the next letter. cmkey5: mvi d,0 mov a,e ; Get the number of chars left. cpi 0 ; Is it negative? jp cmky51 mvi d,0FFH ; If so, sign extend. cmky51: dad d ; Increment past the keyword. lxi d,0003H ; Plus the $ and data. dad d shld cmkptr dcr b ; Decrement the number of entries left. lhld cmsptr ; Get the old cmdptr. shld cmdptr ; Restore it. ;* check so we don't pass it. jmp cmkey2 ; Go check the next keyword. cmambg: dcr b ; Decrement the number of entries left. rm ; If none left then it is not ambiguous. inr e ; This is off by one; adjust. mov c,e ; Save the char count. mov a,e cpi 0 ; Any chars left? rz ; No, it can't be ambiguous. mvi d,0 dad d ; Increment past the keyword. mvi e,3 ; Plus the $ and data. dad d mov b,m ; Get the length of the keyword. inx h xchg lhld cmkptr ; Get pointer to keyword entry. mov a,m ; Get the length of the keyword. sub c ; Subtract how many left. mov c,a ; Save the count. cmp b jz cmamb0 rp ; If larger than the new word then not amb. cmamb0: lhld cmsptr ; Get the pointer to what parsed. cmamb1: dcr c ; Decrement the count. jm rskp ; If we are done then it is ambiguous. xchg ; Exchange the pointers. mov b,m ; Get the next char of the keyword inx h xchg ; Exchange the pointers. mov a,m ; Get the next parsed char. inx h cpi 'a' ; Is it less than a? jm cmamb2 ; If so don't capitalize it. cpi 'z'+1 ; Is it more than z? jp cmamb2 ; If so don't capitalize it. ani 137O cmamb2: cmp b ; Are they equal? rnz ; If not then its not ambiguous. jmp cmamb1 ; Check the next char. cmifil: xchg ; Get the fcb address. shld cmfcb ; Save it. mvi e,0 ; Initialize char count. mvi m,0 ; Set the drive to default to current. inx h shld cmfcb2 mvi a,0 ; Initialize counter. mvi b,' ' cmifi0: mov m,b ; Blank the FCB. inx h inr a cpi 0CH ; Twelve? jm cmifi0 cmifi1: call cmgtch ; Get another char. cpi 0 ; Is it an action character. jp cmifi2 ani 7FH ; Turn off the action bit. cpi '?' ; A question mark? jnz cmif12 lxi h,cmaflg ; Blank the action flag. mvi m,0 lhld cmcptr ; Decrement the buffer pointer. dcx h shld cmcptr jmp cmifi8 ; Treat like any other character. cmif12: cpi esc ; An escape? jnz cmif13 mvi a,0 sta cmaflg ; Turn off the action flag. mvi c,conout mvi e,bell call bdos ; Ring the bell. lhld cmcptr ; Move the pointer to before the escape. dcx h shld cmcptr shld cmdptr lxi h,cmccnt ; Get the char count. dcr m ; Decrement it by one. jmp repars cmif13: mov a,e ; It must be a terminator. cpi 0 ; Test the length of the file name. jz cmifi9 ; If zero complain. cpi 0DH jp cmifi9 ; If too long complain. jmp rskp ; Otherwise we have succeeded. cmifi2: cpi '.' jnz cmifi3 inr e mov a,e cpi 1H ; Any chars yet? jz cmifi9 ; No, give error. cpi 0AH ; Tenth char? jp cmifi9 ; Past it, give an error. mvi c,9H mvi b,0 lhld cmfcb dad b ; Point to file type field. shld cmfcb2 mvi e,9H ; Say we've gotten nine. jmp cmifi1 ; Get the next char. cmifi3: cpi ':' jnz cmifi4 inr e mov a,e cpi 2H ; Is it in the right place for a drive? jnz cmifi9 ; If not, complain. lhld cmfcb2 dcx h ; Point to previous character. mov a,m ; Get the drive name. sui '@' ; Get the drive number. shld cmfcb2 ; Save pointer to beginning of name field. dcx h ; Point to drive number. mov m,a ; Put it in the fcb. mvi e,0 ; Start character count over. jmp cmifi1 cmifi4: cpi '*' jnz cmifi7 mov a,e cpi 8H ; Is this in the name or type field? jz cmifi9 ; If its where the dot should be give up. jp cmifi5 ; Type. mvi b,8H ; Eight chars. jmp cmifi6 cmifi5: mvi b,0CH ; Three chars. cmifi6: lhld cmfcb2 ; Get a pointer into the FCB. mvi a,'?' mov m,a ; Put a question mark in. inx h shld cmfcb2 inr e mov a,e cmp b jm cmifi6 ; Go fill in another. jmp cmifi1 ; Get the next char. cmifi7: cpi '0' jm cmifi9 cpi 'z'+1 jp cmifi9 cpi 'A' ; Don't capitalize non-alphabetics. jm cmifi8 ani 137O ; Capitalize. cmifi8: lhld cmfcb2 ; Get the pointer into the FCB. mov m,a ; Put the char there. inx h shld cmfcb2 inr e jmp cmifi1 cmifi9: mvi c,prstr lxi d,cmer02 call bdos ret cmofil: jmp cmifil ; For now, the same as CMIFI. cminbf: push psw push d push h lda cmaflg ; Is the action char flag set? cpi 0 jnz cminb9 ; If so get no more chars. cminb1: lxi h,cmccnt ; Increment the char count. inr m mvi c,conin ; Get a char. call bdos lhld cmcptr ; Get the pointer into the buffer. mov m,a ; Put it in the buffer. inx h shld cmcptr cpi 25O ; Is it a ^U? jnz cminb2 cmnb12: mvi c,prstr lxi d,clrlin ; Clear the line. call bdos mvi c,prstr lhld cmprmp ; Print the prompt. xchg call bdos lxi h,cmdbuf shld cmcptr ; Reset the point to the start. lxi h,cmccnt ; Zero the count. mvi m,0 jmp repars ; Go start over. cminb2: cpi 10O ; Or backspace? jz cminb3 cpi del ; Delete? jnz cminb4 mvi c,prstr ; Print the delete string. lxi d,delstr call bdos cminb3: lda cmccnt ; Decrement the char count by two. dcr a dcr a cpi 0 ; Have we gone too far? jp cmnb32 ; If not proceed. mvi c,conout ; Ring the bell. mvi e,bell call bdos jmp cmnb12 ; Go reprint prompt and reparse. cmnb32: sta cmccnt ; Save the new char count. mvi c,prstr ; Erase the character. lxi d,clrspc call bdos lhld cmcptr ; Get the pointer into the buffer. dcx h ; Back up in the buffer. dcx h shld cmcptr jmp repars ; Go reparse everything. cminb4: cpi '?' ; Is it a question mark. jz cminb6 cpi esc ; Is it an escape? jz cminb6 cpi cr ; Is it a carriage return? jz cminb5 cpi lf ; Is it a line feed? jz cminb5 cpi ff ; Is it a formfeed? jnz cminb7 call cmblnk cminb5: lda cmccnt ; Have we parsed any chars yet? cpi 1 jz prserr ; If not, just start over. cminb6: mvi a,0FFH ; Set the action flag. sta cmaflg jmp cminb9 cminb7: cpi ' ' jz cminb1 ; Get another char. cpi tab jz cminb1 ; Get another char. jmp cminb1 ; Get another. cminb9: pop h pop d pop psw ret cmgtch: push h push b cmgtc1: lda cmaflg cpi 0 ; Is it set. cz cminbf ; If the action char flag is not set get more. lhld cmdptr ; Get a pointer into the buffer. mov a,m ; Get the next char. inx h shld cmdptr cpi ' ' ; Is it a space? jz cmgtc2 cpi tab ; Or a tab? jnz cmgtc3 cmgtc2: lda cmsflg ; Get the space flag. cpi 0 ; Was the last char a space? jnz cmgtc1 ; Yes, get another char. mvi a,0FFH ; Set the space flag. sta cmsflg mvi a,' ' pop b pop h jmp cmgtc5 cmgtc3: push psw mvi a,0 sta cmsflg ; Zero the space flag. pop psw pop b pop h cpi esc jz cmgtc5 cpi '?' ; Is the user curious? jz cmgtc4 cpi cr jz cmgtc4 cpi lf jz cmgtc4 cpi ff rnz ; Not an action char, just return. cmgtc4: push h lhld cmdptr dcx h shld cmdptr pop h cmgtc5: ori 80H ; Make the char negative to indicate it is ret ; a terminator. ; This routine blanks the screen. cmblnk: mvi c,prstr ; Print the string to blank the screen. lxi d,clrtop call bdos ret ; Pure storage. IF brain versio: db 'CUCCA SuperBrain Kermit-80 - V3.1',cr,lf,'$' ENDIF IF osi versio: db 'CUCCA OSI Kermit-80 - V3.1',cr,lf,'$' ENDIF IF apple versio: db 'CUCCA/DEC APPLE ][ Kermit-80 - V3.1',cr,lf,'$' ENDIF IF vector versio: db 'CUCCA Vector Graphics Kermit-80 - V3.1',cr,lf,'$' ENDIF IF heath versio: db 'CUCCA/DEC Heath/Zenith-89 Kermit-80 - V3.1',cr,lf,'$' ENDIF IF z100 versio: db 'CUCCA/Stevens Heath/Zenith Z-100 Kermit-80 - V3.1',cr,lf,'$' ENDIF IF robin versio: db esc,3CH,'CUCCA/DEC VT18X Kermit-80 - V3.1',cr,lf,'$' ENDIF IF trs80 versio: db 'CUCCA/Cerritos TRS-80 II Kermit-80 - V3.1',cr,lf,'$' ENDIF IF osbrn1 versio: db lf,lf,'CUCCA/NIH Osborne 1 Kermit-80 - V3.1',cr,lf,'$' ENDIF IF telcon versio: db 'CUCCA/Stevens Telcon Kermit-80 - V3.1',cr,lf,'$' ENDIF kerm: db 'Kermit-80>$' delpr: db 'Delete it? $' crlf: db cr,lf,'$' ermes1: db cr,lf,'?Unrecognized command$' ermes2: db cr,lf,'?Illegal character$' ermes3: db cr,lf,'?Not confirmed$' ;***************************System Dependent************************ IF brain ermes4: db esc,'Y& ',esc,'~K?Unable to receive initiate$' ermes5: db esc,'Y& ',esc,'~K?Unable to receive file name$' ermes6: db esc,'Y& ',esc,'~K?Unable to receive end of file$' erms10: db esc,'Y& ',esc,'~K?Unable to receive data$' erms11: db esc,'Y& ',esc,'~K?Disk full$' erms14: db esc,'Y& ',esc,'~K?Unable to receive an acknowledgement from the host$' erms15: db esc,'Y& ',esc,'~K?Unable to find file$' dimsg1: db esc,'Y& ',esc,'~K%Bad checksum$' infms0: db esc,'Y#TWaiting .....$' infms1: db esc,'Y#TReceiving ...',esc,'Y#4$' infms2: db esc,'Y#TSending .....',esc,'Y#4$' infms3: db bell,esc,'Y#TCompleted ',esc,'Y',27H,' $' infms4: db bell,esc,'Y#TFailed ',esc,'Y',27H,' $' infms5: db esc,'Y& ',esc,'~K%Renaming file to $' ENDIF IF osi ermes4: db esc,'=',06H,00H,esc,'T?Unable to receive initiate$' ermes5: db esc,'=',06H,00H,esc,'T?Unable to receive file name$' ermes6: db esc,'=',06H,00H,esc,'T?Unable to receive end of file$' erms10: db esc,'=',06H,00H,esc,'T?Unable to receive data$' erms11: db esc,'=',06H,00H,esc,'T?Disk full$' erms14: db esc,'=',06H,00H,esc,'T?Unable to receive an acknowledgement from the host$' erms15: db esc,'=',06H,00H,esc,'T?Unable to find file$' dimsg1: db esc,'=',06H,00H,esc,'T%Bad checksum$' infms0: db esc,'=',03H,34H,'Waiting .....$' infms1: db esc,'=',03H,34H,'Receiving ...',esc,'Y#4$' infms2: db esc,'=',03H,34H,'Sending .....',esc,'Y#4$' infms3: db bell,esc,'=',03H,34H,'Completed ',esc,'Y& $' infms4: db bell,esc,'=',03H,34H,'Failed ',esc,'Y& $' infms5: db esc,'=',06H,00H,esc,'T%Renaming file to $' ENDIF IF apple OR trs80 ; (Lifeboat 2.25 and later use ADM-31; 2.24 and earlier must use ADM-3A) ermes4: db esc,'=',20H+06H,20H+00H,esc,'T?Unable to receive initiate$' ermes5: db esc,'=',20H+06H,20H+00H,esc,'T?Unable to receive file name$' ermes6: db esc,'=',20H+06H,20H+00H,esc,'T?Unable to receive end of file$' erms10: db esc,'=',20H+06H,20H+00H,esc,'T?Unable to receive data$' erms11: db esc,'=',20H+06H,20H+00H,esc,'T?Disk full$' erms14: db esc,'=',20H+06H,20H+00H,esc,'T?Unable to receive an acknowledgement from the host$' erms15: db esc,'=',20H+06H,20H+00H,esc,'T?Unable to find file$' ENDIF IF apple OR osbrn1 OR trs80 dimsg1: db esc,'=',20H+06H,20H+00H,esc,'T%Bad checksum$' infms0: db esc,'=',20H+07H,20H+0FH,'Waiting .....$' infms1: db esc,'=',20H+07H,20H+0FH,'Receiving ...' db esc,'=',20H+03H,20H+15H,'$' infms2: db esc,'=',20H+07H,20H+0FH,'Sending .....' db esc,'=',20H+03H,20H+15H,'$' infms3: db esc,'=',20H+07H,20H+0FH,'Completed ',cr,lf,'$' infms4: db esc,'=',20H+07H,20H+0FH,'Failed ',cr,lf,'$' infms5: db esc,'=',20H+06H,20H+00H,esc,'T%Renaming file to $' ENDIF IF osbrn1 ermes4: db cr,lf,'?Unable to receive initiate$' ermes5: db cr,lf,'?Unable to receive file name$' ermes6: db cr,lf,'?Unable to receive end of file$' erms10: db cr,lf,'?Unable to receive data$' erms11: db cr,lf,'?Disk full$' erms14: db cr,lf,'?Unable to receive an acknowledgement from the host$' erms15: db cr,lf,'?Unable to find file$' ENDIF IF vector ermes4: db esc,00H,06H,('Q'-100O),'?Unable to receive initiate$' ermes5: db esc,00H,06H,('Q'-100O),'?Unable to receive file name$' ermes6: db esc,00H,06H,('Q'-100O),'?Unable to receive end of file$' erms10: db esc,00H,06H,('Q'-100O),'?Unable to receive data$' erms11: db esc,00H,06H,('Q'-100O),'?Disk full$' erms14: db esc,00H,06H,('Q'-100O),'?Unable to receive an acknowledgement from the host$' erms15: db esc,00H,06H,('Q'-100O),'?Unable to find file$' dimsg1: db esc,00H,06H,('Q'-100O),'%Bad checksum$' infms0: db esc,34H,03H,'Waiting .....$' infms1: db esc,34H,03H,'Receiving ...',esc,15H,03H,'$' infms2: db esc,34H,03H,'Sending .....',esc,15H,03H,'$' infms3: db bell,esc,34H,03H,'Completed ',esc,00H,07H,'$' infms4: db bell,esc,34H,03H,'Failed ',esc,00H,07H,'$' infms5: db esc,00H,06H,('Q'-100O),'Renaming file to $' ENDIF IF heath OR z100 OR telcon ermes4: db esc,'Y ?Unable to receive initiate$' ermes5: db esc,'Y ?Unable to receive file name$' ermes6: db esc,'Y ?Unable to receive end of file$' erms10: db esc,'Y ?Unable to receive data$' erms11: db esc,'Y ?Disk full$' erms14: db esc,'Y ?Unable to receive an acknowledgement from the host$' erms15: db esc,'Y ?Unable to find file$' dimsg1: db esc,'Y %Bad checksum$' infms0: db esc,'Y& Waiting .....$' infms1: db esc,'Y& Receiving ...',esc,'Y#3$' infms2: db esc,'Y& Sending .....',esc,'Y#3$' infms3: db bell,esc,'Y& Completed ',esc,'Y $' infms4: db bell,esc,'Y& Failed ',esc,'Y $' infms5: db esc,'Y %Renaming file to $' ENDIF IF robin ermes4: db esc,'[7;1H',esc,'[K?Unable to receive initiate$' ermes5: db esc,'[7;1H',esc,'[K?Unable to receive file name$' ermes6: db esc,'[7;1H',esc,'[K?Unable to receive end of file$' erms10: db esc,'[7;1H',esc,'[K?Unable to receive data$' erms11: db esc,'[7;1H',esc,'[K?Disk full$' erms14: db esc,'[7;1H',esc,'[K?Unable to receive an acknowledgement from the host$' erms15: db esc,'[7;1H',esc,'[K?Unable to find file$' dimsg1: db esc,'[7;1H',esc,'[K%Bad checksum$' infms0: db esc,'[4;53HWaiting .....$' infms1: db esc,'[4;53HReceiving ...',esc,'[4;22H$' infms2: db esc,'[4;53HSending .....',esc,'[4;22H$' infms3: db bell,esc,'[4;53HCompleted ',esc,'[8;1H$' infms4: db bell,esc,'[4;53HFailed ',esc,'[8;1H$' infms5: db esc,'[7;1H',esc,'[K%Renaming file to $' ENDIF erms16: db 'Unable to rename file$' erms17: db cr,lf,'?Disk full$' erms18: db cr,lf,'?Unable to tell host that the session is finished$' erms19: db cr,lf,'?Unable to tell host to logout$' infms6: db cr,lf,'[Closing the log file]$' infms7: db cr,lf,'[Connected to remote host, type $' infms8: db 'C to return]',cr,lf IF NOT trs80 db '$' ENDIF IF trs80 db '(Control-_ is the Down-Arrow key on the TRS-80 keyboard)',cr,lf,'$' ENDIF infms9: db cr,lf,'[Connection closed, back at micro]$' inms10: db 'Control-$' cfrmes: db ' Confirm with carriage return $' filhlp: db ' Input file spec (possibly wild) $' escmes: db cr,lf,'Type the new escape character: $' tophlp: db cr,lf,'BYE to host (LOGOUT) and exit to CP/M' db cr,lf,'CONNECT to host on selected port' db cr,lf,'EXIT to CP/M' db cr,lf,'FINISH running Kermit on the host' db cr,lf,'HELP by giving this message' db cr,lf,'LOG the terminal session to a file' db cr,lf,'LOGOUT the host' db cr,lf,'RECEIVE file from host' db cr,lf,'SEND file to host' db cr,lf,'SET a parameter' db cr,lf,'SHOW the parameters' db cr,lf,'STATUS of Kermit$' sethlp: IF brain OR robin OR osbrn1 db cr,lf,'BAUD rate change' ENDIF db cr,lf,'CPM-CREATED-FILE will be sent' db cr,lf,'ESCAPE character change' IF brain db cr,lf,'FILE-WARNING' ENDIF db cr,lf,'IBM (parity and turn around handling)' db cr,lf,'LOCAL-ECHO echoing (half-duplex)' IF robin db cr,lf,'PORT (to communicate on)' ENDIF db cr,lf,'PARITY (to use on communication line)' IF NOT robin db cr,lf,'VT52-EMULATION' ENDIF db '$' stshlp: db cr,lf,'PAD-CHAR' db cr,lf,'PADDING$' IF robin gpphlp: db cr,lf,'COMMUNICATIONS - Communications port' db cr,lf,'GENERAL - General purpose port$' ENDIF parhlp: db cr,lf,'EVEN MARK NONE ODD SPACE$' onhlp: db cr,lf,'OFF ON$' yeshlp: db cr,lf,'NO YES$' inthlp: db cr,lf,'? This message' db cr,lf,'C Close the connection' IF apple db cr,lf,'D Close and disconnect the connection' ENDIF db cr,lf,'S Status of the connection' db cr,lf,'Typing the escape character will send it to the host' db cr,lf,cr,lf,'Command>$' onstr: db ' on$' offstr: db ' off$' locst: db cr,lf,'Local echo$' IF NOT robin vtemst: db cr,lf,'VT52 emulation$' ENDIF cpmst: db cr,lf,'CPM created file$' ibmst: db cr,lf,'IBM flag$' filst: db cr,lf,'File warning$' escst: db cr,lf,'Escape char: $' parst: db cr,lf,'Parity: $' pnonst: db 'none$' pmrkst: db 'mark$' pspcst: db 'space$' poddst: db 'odd$' pevnst: db 'even$' IF osbrn1 osbmsg: db ' baud',cr,lf,'$' ENDIF IF brain baudtb: db ('A'-100O),esc,'~kType the letter corresponding with the baud rate desired.' db cr,lf,'(A) 50' db cr,lf,'(B) 75' db cr,lf,'(C) 110' db cr,lf,'(D) 134.5' db cr,lf,'(E) 150' db cr,lf,'(F) 300' db cr,lf,'(G) 600' db cr,lf,'(H) 1200' db cr,lf,'(I) 1800' db cr,lf,'(J) 2000' db cr,lf,'(K) 2400' db cr,lf,'(L) 3600' db cr,lf,'(M) 4800' db cr,lf,'(N) 7200' db cr,lf,'(O) 9600' db cr,lf,cr,lf,'Letter: $' ENDIF IF osbrn1 baudtb: db cr,lf,'Type a letter corresponding to the baud rate desired.' db cr,lf,'(A) 300' db cr,lf,'(B) 1200' db cr,lf,cr,lf,'Letter: $' ENDIF ;***************************System Dependent************************** IF brain outlin: db ('A'-100O),esc,'~k' db cr,lf,tab,tab,'CUCCA SuperBrain Kermit-80 V3.1',cr,lf db cr,lf,'Number of packets: (hex)' db cr,lf,'Number of retries: (hex)' db cr,lf,'File name:$' delstr: db 10O,' ',10O,10O,'$' ; Delete string. clrspc: db ' ',10O,'$' ; Clear space. clrlin: db cr,esc,'~K$' ; Clear line. clrtop: db ('A'-100O),esc,'~k$' ; Clear screen and go home. scrnp: db esc,'Y#4$' ; Place for number of packets. scrnrt: db esc,'Y#4',lf,'$' ; Place for number of retries. scrfln: db esc,'Y%,',esc,'~K$' ; Place for file name. scrst: db esc,'Y#T$' ; Place for status. screrr: db esc,'Y& $' ; Place for error messages. ttab: ; Table start location. ta: db ('K'-100O),'$',0,0 ; Cursor up. tb: db 12O,'$',0,0 ; Cursor down. tc: db ('F'-100O),'$',0,0 ; Cursor right. td: db esc,'D$',0 ; No translation. te: db esc,'E$',0 tf: db esc,'F$',0 tg: db esc,'G$',0 th: db ('A'-100O),'$',0,0 ; Cursor home. ti: db ('K'-100O),'$',0,0 ; Reverse linefeed. tj: db esc,'~k$' ; Clear to end of screen. tk: db esc,'~K$' ; Clear to end of line. ENDIF IF debug rppos: db esc,'Y* RPack:',esc,'~K$' sppos: db esc,'Y( SPack:',esc,'~K$' ENDIF IF osi outlin: db ('^'-100O),esc,'Y' db cr,lf,tab,tab,tab,'CUCCA OSI Kermit-80 V3.1',cr,lf db cr,lf,'Number of packets: (hex)' db cr,lf,'Number of retries: (hex)' db cr,lf,'File name:$' delstr: db 10O,10O,'$' ; Delete string. clrspc: db ' ',10O,'$' ; Clear space. clrlin: db cr,esc,'T$' ; Clear line. clrtop: db ('^'-100O),esc,'Y$' ; Clear screen and go home. scrnp: db esc,'=',03H,15H,'$' ; Place for number of packets. scrnrt: db esc,'=',04H,15H,'$' ; Place for number of retries. scrfln: db esc,'=',05H,0CH,esc,'T$' ; Place for file name. scrst: db esc,'=',03H,34H,'$' ; Place for status. screrr: db esc,'=',06H,00H,'$' ; Place for error messages. ttab: ; Table start location. ta: db ('K'-100O),'$',0,0 ; Cursor up. tb: db 12O,'$',0,0 ; Cursor down. tc: db ('F'-100O),'$',0,0 ; Cursor right. td: db esc,'D$',0 ; No translation. te: db esc,'E$',0 tf: db esc,'F$',0 tg: db esc,'G$',0 th: db ('^'-100O),'$',0,0 ; Cursor home. ti: db ('K'-100O),'$',0,0 ; Reverse linefeed. tj: db esc,'Y$',0 ; Clear to end of screen. tk: db esc,'T$' ; Clear to end of line. ENDIF IF apple outlin: db ('^'-100O),esc,'Y' db cr,lf,tab,'CUCCA APPLE ][ Kermit-80 V2.3',cr,lf db cr,lf,'Number of packets: (hex)' db cr,lf,'Number of retries: (hex)' db cr,lf,'File name:$' delstr: db 10O,10O,'$' ; Delete string. clrspc: db ' ',10O,'$' ; Clear space. clrlin: db cr,esc,'T$' ; Clear line. clrtop: db ('^'-100O),esc,'Y$' ; Clear screen and go home. ;scrnp: db esc,'=',20H+03H,20H+15H,'$' ; Place for number of packets. scrnrt: db esc,'=',20H+03H,20H+15H,lf,'$' ; Place for number of retries. scrfln: db esc,'=',20H+05H,20H+0CH,'$' ; Place for file name. scrst: db esc,'=',20H+07H,20H+0FH,'$' ; Place for status. screrr: db esc,'=',20H+06H,20H+00H,'$' ; Place for error messages. ttab: ; Table start location. ta: db ('K'-100O),'$',0,0 ; Cursor up. tb: db 12O,'$',0,0 ; Cursor down. tc: db ('F'-100O),'$',0,0 ; Cursor right. td: db esc,'D$',0 ; No translation. te: db esc,'E$',0 tf: db esc,'F$',0 tg: db esc,'G$',0 th: db ('^'-100O),'$',0,0 ; Cursor home. ti: db ('K'-100O),'$',0,0 ; Reverse linefeed. tj: db esc,'Y$',0 ; Clear to end of screen. tk: db esc,'T$' ; Clear to end of line. ENDIF IF osbrn1 outlin: db 1AH ; (Clear screen, home cursor) db cr,lf,tab,'CUCCA/NIH Osborne 1 Kermit-80 V3.1',cr,lf db cr,lf,'Number of packets: (hex)' db cr,lf,'Number of retries: (hex)' db cr,lf,'File name:$' delstr: db 10O,10O,'$' ; Delete string. clrspc: db ' ',10O,'$' ; Clear space. clrlin: db cr,esc,'T$' ; Clear line. clrtop: db 1AH,'$' ; Clear screen and go home. ;scrnp: db esc,'=',20H+03H,20H+15H,'$' ; Place for number of packets. scrnrt: db esc,'=',20H+03H,20H+15H,lf,'$' ; Place for number of retries. scrfln: db esc,'=',20H+05H,20H+0CH,'$' ; Place for file name. scrst: db esc,'=',20H+07H,20H+0FH,'$' ; Place for status. screrr: db esc,'=',20H+06H,20H+00H,'$' ; Place for error messages. ttab: ; Table start location. ta: db ('K'-100O),'$',0,0 ; Cursor up. tb: db 12O,'$',0,0 ; Cursor down. tc: db ('L'-100O),'$',0,0 ; Cursor right. td: db esc,'D$',0 ; No translation. te: db esc,'E$',0 tf: db esc,'F$',0 tg: db esc,'G$',0 th: db ('^'-100O),'$',0,0 ; Cursor home. ti: db ('K'-100O),'$',0,0 ; Reverse linefeed. tj: db esc,'T$',0 ; (can't) Clear to end of screen. tk: db esc,'T$' ; Clear to end of line. ENDIF IF vector outlin: db ('D'-100O) db cr,lf,tab,tab,'CUCCA Vector Graphics Kermit-80 V3.1',cr,lf db cr,lf,'Number of packets: (hex)' db cr,lf,'Number of retries: (hex)' db cr,lf,'File name:$' delstr: db 10O,' ',10O,10O,'$' ; Delete string. clrspc: db ' ',10O,'$' ; Clear space. clrlin: db cr,('Q'-100O),'$' ; Clear line. clrtop: db ('D'-100O),'$' ; Clear screen and go home. scrnp: db esc,15H,03H,'$' ; Place for number of packets. scrnrt: db esc,15H,04H,'$' ; Place for number of retries. scrfln: db esc,0CH,05H,('Q'-100O),'$' ; Place for file name. scrst: db esc,34H,03H,'$' ; Place for status. screrr: db esc,00H,06H,'$' ; Place for error messages. ttab: ; Table start location. ta: db ('U'-100O),'$',0,0 ; Cursor up. tb: db 12O,'$',0,0 ; Cursor down. tc: db ('Z'-100O),'$',0,0 ; Cursor right. td: db esc,'D$',0 ; No translation. te: db esc,'E$',0 tf: db esc,'F$',0 tg: db esc,'G$',0 th: db ('B'-100O),'$',0,0 ; Cursor home. ti: db ('U'-100O),'$',0,0 ; Reverse linefeed. tj: db ('P'-100O),'$',0,0 ; Clear to end of screen. tk: db ('Q'-100O),'$' ; Clear to end of line. ENDIF IF heath outlin: db esc,'E',esc,'H' db cr,lf,tab,tab,'CUCCA/DEC Heath/Zenith 89 Kermit-80 V3.1',cr,lf ENDIF IF z100 outlin: db esc,'E',esc,'H' db cr,lf,tab,tab,'CUCCA/Stevens Heath/Zenith Z-100 Kermit-80 V3.1',cr,lf ENDIF IF telcon outlin: db esc,'H',esc,'J' db cr,lf,tab,tab,'CUCCA/Stevens Telcon Kermit-80 V3.1',cr,lf ENDIF IF heath OR z100 OR telcon db cr,lf,'Number of packets: (hex)' db cr,lf,'Number of retries: (hex)' db cr,lf,'File name:$' delstr: db 10O,' ',10O,'$' ;delete string clrspc: db ' ',10O,'$' ; Clear space. clrlin: db cr,esc,'l$' ; Clear line. clrtop: db esc,'H',esc,'J$' ; Clear screen and go home. scrnp: db esc,'Y#3$' ; Place for number of packets. scrnrt: db esc,'Y#3',lf,'$' ; Place for number of retries. scrfln: db esc,'Y%+',esc,'K$' ; Place for file name. scrst: db esc,'Y& $' ; Place for status. screrr: db esc,'Y $' ; Place for error messages. ttab: ; Table start location. ta: db esc,'A$',0 ; Cursor up. tb: db esc,'B$',0 ; Cursor down. tc: db esc,'C$',0 ; Cursor right. td: db esc,'D$',0 ; Cursor left te: db esc,'E$',0 ; Clear display tf: db esc,'F$',0 ; Enter Graphics Mode tg: db esc,'G$',0 ; Exit Graphics mode th: db esc,'H$',0 ; Cursor home. ti: db esc,'I$',0 ; Reverse linefeed. tj: db esc,'J$',0 ; Clear to end of screen. tk: db esc,'K$',0 ; Clear to end of line. ENDIF IF trs80 outlin: db esc,':' db cr,lf,tab,tab,'CUCCA/Cerritos TRS-80 II Kermit-80 V3.1',cr,lf db cr,lf,'Number of packets: (hex)' db cr,lf,'Number of retries: (hex)' db cr,lf,'File name:$' delstr: db 10O,' ',10O,'$' ;delete string clrspc: db ' ',10O,'$' ; Clear space. clrlin: db cr,esc,'T$' ; Clear line. clrtop: db esc,':$' ; Clear screen and go home. scrnp: db esc,'=#5$' ; Place for number of packets. scrnrt: db esc,'=#5',lf,'$' ; Place for number of retries. scrfln: db esc,'=%+',esc,'T$' ; Place for file name. scrst: db esc,'=#T$' ; Place for status. screrr: db esc,'=& $' ; Place for error messages. ttab: ; Table start location. ta: db 0BH,'$',0 ; Cursor up. tb: db 0AH,'$',0 ; Cursor down. tc: db 0CH,'$',0 ; Cursor right. td: db 08H,'$',0 ; Cursor left te: db esc,':$',0 ; Clear display tf: db esc,'F$',0 ; Enter Graphics Mode tg: db esc,'G$',0 ; Exit Graphics mode th: db 1EH,'$',0 ; Cursor home. ti: db 0BH,'$',0 ; Reverse linefeed. tj: db esc,'Y$',0 ; Clear to end of screen. tk: db esc,'T$',0 ; Clear to end of line. ENDIF IF robin outlin: db esc,3CH,esc,'[H',esc,'[J' db cr,lf,tab,tab,'CUCCA/DEC VT18X Kermit-80 V3.1',cr,lf db cr,lf,'Number of packets: (hex)' db cr,lf,'Number of retries: (hex)' db cr,lf,'File name:$' delstr: db 10O,' ',10O,'$' ;delete string clrspc: db ' ',10O,'$' ; Clear space. clrlin: db cr,esc,'[K$' ; Clear line. clrtop: db esc,'[H',esc,'[J$' ; Clear screen and go home. scrnp: db esc,'[4;22H$' ; Place for number of packets. scrnrt: db esc,'[5;22H$' ; Place for number of retries. scrfln: db esc,'[6;12H',esc,'[K$' ; Place for file name. scrst: db esc,'[4;53H$' ; Place for status. screrr: db esc,'[7;1H$' ; Place for error messages. ENDIF ; COMND tables comtab: db 0CH ; Twelve entries. db 03H,'BYE$',21H,21H db 07H,'CONNECT$',00H,00H db 04H,'EXIT$',03H,03H db 06H,'FINISH$',1BH,1BH db 04H,'HELP$',06H,06H db 03H,'LOG$',09H,09H db 06H,'LOGOUT$',1EH,1EH db 07H,'RECEIVE$',0CH,0CH db 04H,'SEND$',0FH,0FH db 03H,'SET$',12H,12H db 04H,'SHOW$',15H,15H db 06H,'STATUS$',18H,18H settab: IF brain OR osbrn1 db 0AH ; Ten entries. db 04H,'BAUD$',1BH,1BH ENDIF IF osi OR vector OR heath OR z100 OR apple OR trs80 OR telcon db 09H ; Nine entries. ENDIF IF robin db 0AH ; Ten entries db 04H,'BAUD$',18H,18H ENDIF db 10H,'CPM-CREATED-FILE$',12H,12H db 06H,'ESCAPE$',00H,00H db 0CH,'FILE-WARNING$',0FH,0FH db 03H,'IBM$',03H,03H db 0AH,'LOCAL-ECHO$',06H,06H db 06H,'PARITY$',15H,15H IF robin db 04H,'PORT$',1BH,1BH ENDIF db 07H,'RECEIVE$',09H,09H db 04H,'SEND$',0CH,0CH IF NOT robin db 0EH,'VT52-EMULATION$',18H,18H ENDIF stsntb: db 02H db 08H,'PAD-CHAR$',00H,00H db 07H,'PADDING$',03H,03H partab: db 05H ; Five entries. db 04H,'EVEN$',parevn,parevn db 04H,'MARK$',parmrk,parmrk db 04H,'NONE$',parnon,parnon db 03H,'ODD$',parodd,parodd db 05H,'SPACE$',parspc,parspc ontab: db 02H ; Two entries. db 02H,'ON$',01H,01H db 03H,'OFF$',00H,00H IF robin gpptab: db 02H ; Two entries db 0EH,'COMMUNICATIONS$',00H,00H db 07H,'GENERAL$',01H,01H ENDIF yestab: db 02H ; Two entries. db 02H,'NO$',00H,00H db 03H,'YES$',01H,01H cmer00: db cr,lf,'?Program error: Invalid COMND call$' cmer01: db cr,lf,'?Ambiguous$' cmer02: db cr,lf,'?Illegal input file spec$' cmin00: db ' Confirm with carriage return$' cmcrlf: db cr,lf,'$' ; Impure data ; COMND storage cmstat: ds 1 ; What is presently being parsed. cmaflg: ds 1 ; Non-zero when an action char has been found. cmccnt: ds 1 ; Non-zero if a significant char is found. cmsflg: ds 1 ; Non-zero when the last char was a space. cmostp: ds 2 ; Old stack pointer for reparse. cmrprs: ds 2 ; Address to go to on reparse. cmprmp: ds 2 ; Address of prompt. cmptab: ds 2 ; Address of present keyword table. cmhlp: ds 2 ; Address of present help. cmdbuf: ds 80H ; Buffer for command parsing. cmfcb: ds 2 ; Pointer to FCB. cmfcb2: ds 2 ; Pointer to position in FCB. cmcptr: ds 2 ; Pointer for next char input. cmdptr: ds 2 ; Pointer into the command buffer. cmkptr: ds 2 ; Pointer to keyword. cmsptr: ds 2 ; Place to save a pointer. oldsp: ds 2 ; Room for old system stack. ds 40H ; Room for 32 levels of calls. stack: ds 2 eoflag: ds 1 ; EOF flag; non-zero on EOF. filflg: ds 1 ; Non-zero when nothing in DMA buffer. logflg: db 0 ; Flag for a log file. ecoflg: db 0 ; Local echo flag (default off). escflg: db 0 ; Escape flag (start off). IF vector vtvflg: db 1 ; Flag for VECTOR VT52 emulation. vctccc: ds 1 ; Storage for reversing row and column. ENDIF IF NOT robin vtflg: db 1 ; VT52 emulation flag (default on). ENDIF IF robin pchar: db 0 ; The character from COMmunications-port. cchar: db 0 ; The console input-char. gppflg: db 0 ; Flag whether using comm port (0) or ; general port (1) cint: ds 2 ; CPM's Interrupt address. ENDIF IF brain flwflg: db 1 ; File warning flag (default on). ENDIF IF vector OR osi OR heath OR z100 OR robin OR apple OR trs80 OR osbrn1 OR telcon flwflg: db 0 ; File warning flag (default off). ENDIF ibmflg: db 0 ; IBM flag (default off). cpmflg: db 0 ; File was created by CPM. parity: db defpar ; Parity. escchr: db defesc ; Storage for the escape character. chrcnt: ds 1 ; Number of chars in the file buffer. filcnt: ds 1 ; Number of chars left to fill. outpnt: ds 2 ; Position in packet. bufpnt: ds 2 ; Position in file buffer. filerc: ds 1 ; File record count. fileex: ds 1 ; File extent. fcbptr: ds 2 ; Position in FCB. datptr: ds 2 ; Position in packet data buffer. cbfptr: ds 2 ; Position in character buffer. pktptr: ds 2 ; Poistion in receive packet. size: ds 1 ; Size of data from gtchr. spsiz: db dspsiz ; Send packet size. rpsiz: db drpsiz ; Receive packet size. stime: db dstime ; Send time out. rtime: db drtime ; Receive time out. spad: db dspad ; Send padding. rpad: db drpad ; Receive padding. spadch: db dspadc ; Send padding char. rpadch: db drpadc ; Receive padding char. seol: db dseol ; Send EOL char. reol: db dreol ; Receive EOL char. squote: db dsquot ; Send quote char. rquote: db drquot ; Receive quote char. pktnum: ds 1 ; Packet number. numpkt: ds 2 ; Total number of packets sent. numrtr: ds 2 ; Total number of retries. numtry: ds 1 ; Number of tries on this packet. oldtry: ds 1 ; Number of tries on previous packet. state: ds 1 ; Present state of the automaton. packet: ds 4 ; Packet (data is part of it). data: ds 5AH ; Data and checksum field of packet. recpkt: ds 60H ; Receive packet storage (use the following). filbuf: ds 60H ; Character buffer. temp1: ds 1 ; Temporary storage. temp2: ds 1 temp3: ds 1 temp4: ds 1 argblk: ds 20H ; Used for subroutine arguments. fcbnum: ds 1 ; Number of FCB's left in the list. fcbblk: ds maxfil*10H ; Used for a list of FCB's. IF osbrn1 osbaud: db 1 ; Baud rate: 0=300, non-0=1200 osmove: osflag equ 0EF08H ; Osborne 1 Bank-2 flag OSLDST EQU ostop-osmove+$ DI OUT 0 LDA osprts ; Read the status port OUT 1 EI ret OSSTST equ ostop-osmove+$ DI OUT 0 STA osprts ; Write the control port jmp osstex OSLDDA equ ostop-osmove+$ DI OUT 0 LDA osport OUT 1 EI ret OSSTDA equ ostop-osmove+$ DI OUT 0 STA osport osstex equ ostop-osmove+$ OUT 1 mvi a,1 sta osflag EI ret osmct equ $-osmove ENDIF END