; ;do a CLEAR 0,59392 before assembling ;SAVEM "MODEM",59392,xxxxx,59392 ; ;Where "xxxxx" is the highest address used ; ; ;Tandy 200 XMODEM/Terminal program ;Tom Jennings ;Fido Software ;Box 77731 ;San Francisco CA 94107 ; ORIGIN equ 59392 TIMEOUT equ 200 ;char-wait timeout value ; ;NOTE: For space purposes, the two functions 'prompt' and ;'create' upon error return to the next-level-up instead ;of the caller, to avoid the explicit blank-input and ;error checking done by: ; ; call prompt call create ; jz (blank line) jc (no create) ; ;The original, "normal" code is commented out with ";#", ;added code marked with #, as well as the 'popabort' routine. ; org ORIGIN ; ;ROM calls. Look 'em up. The "$" defines are from the Tandy 200 ;tech ref manual. The others are from the Covington ROM Maps. ;(One zillion thanks to Robert D. Covington!) ; $SETSER equ 191dh ;Set RS-232 (HL=string) $INZCOM equ 86deh ;Init RS-232 (H=baud, L=bits) $CLSCOM equ 87b5h ;Close RS-232 $RCVX equ 8508h ;Check for chars (Z=no chars) $RV232C equ 8519h ;Read character to A $SNDCOM equ 8629h ;Output C $SD232C equ 8643h ;Output A $DISHHC equ 61bah ;Disconnect line $CONHHC equ 61d0h ;Connect line $ATDIAL equ 622bh ;Dial ; ;LCD calls ; $CLS equ 4f4dh ;Clear screen $POSIT equ 4f9bh ;Position (H=col, L=line) $LCDPUT equ 503ch ;Display A $ERAEOL equ 4f7ch ;Erase to end of line $CURSON equ 4f68h ;Enable cursor $CURSOF equ 4f6dh ;Disable cursor $CRLF equ 4f3eh ;Do CR/LF $ENTREV equ 4f88h ;Reverse video on $EXTREV equ 4f8dh ;Reverse video off PUTSTR equ 6df6h ;Print string at HL PUTHL equ 470bh ;Display HL in decimal ; ;Function key calls ; $STDSPF equ 4fc4h ;Set/display keys (HL=table) $ERAFNK equ 4fa9h ;Undisplay keys $FNKSB equ 6e42h ;Display keys $STFNK equ 6e20h ;Set key defs (HL=table) ; ;Keyboard calls ; $CHGET equ 12f7h ;Wait for a key hit $KYREAD equ 8b03h ;Read keyboard (!Z, carry=Fkey) $KEYX equ 8b31h ;Check key or BREAK (!Z, carry) $BRKCHK equ 8b4dh ;Check BREAK key (carry) $INLIN equ 54f6h ;Input a line? $LINE equ f685h ;where line stored? ; ;File system calls ; ;CHKDC Doesnt work right! It will not work with 6 char ;filenames (eg. 123456.DO), as the ROM copies only the first 8 ;bytes ... ie "1234567.D"! ; ;The ROM code at $CHKDC is: ;6e4d: mvi a,8 ;6e4f: lxi h,f833 ;6e52: call 6e06 ; ... ;... so we do this instead: ; mvi a,9 ; call 6e4fh ; $CHKDC equ 6e4dh ;Find file DE=fname (!Z, HL=FCB) $GTXTTB equ 6e8ch ;Get top addr HL=FCB (HL=top) $KILASC equ 2ab5h ;Kill .DO file $MAKTXT equ 2d7ch ;Create .DO file $FILNAM equ f746h ;where filename stored $MAKHOL equ 82a8h ;Insert in file HL, BC $INSCHR equ 829ch ;Insert A into HL $MENU equ 67a4h ;Return to Menu ; ;Memory variables. ; MAXRAM equ eeb0h ;top of memory HIMEM equ eeb4h ;Where BASIC stores HIMEM UNUSED equ f669h ;ptr to unused memory MSPLAN equ 61102 ;put 'MP' here for MSPLAN ; ;Program start -- clear the screen, display our signon, then ;loop in terminal mode, execute function keys if pressed. ; main: ;use system stack... call init ;one-time startup ; ;Terminal mode: echo characters ... ; s1: call $KYREAD ;poll keyboard jz s2 ;if a key pressed sta lastc ;store it jnc s1a ;if a function key call $ENTREV ;reverse video on call functions ;process F-key, call dolabel ;update label line, call $EXTREV ;reverse video off jmp s1 ;repeat. s1a: call modout ;output to the modem s2: call $RCVX ;check line for a character jz s1 ;if there is one, call $RV232C ;read it, (ignore errors) ora a ;check for garbage jz s1 cpi f0h jnc s1 sta lastc ;store for capture call $LCDPUT ;output to LCD call captpc ;(write to a file) jmp s1 ; ;Process function keys. Function code is in 'lastc'. ; fnctbl dw disc ;F1 disconnect dw dial ;F2 call dw capture ;F3 capture dw baud ;F4 baud rate dw xrecv ;F5 XMODEM download dw xsend ;F6 XMODEM upload dw return ;F7 dw menu ;F8 menu dw label ;LABEL on/off ; ;... and here's the code. ; functions: lda lastc ;get the character cpi 9 ;only 0 - 8 supported rnc call dispat ;dispatch pchl ;jump there, return direct dispat: lxi h,fnctbl ;do a table dispatch add a ;(word offset) add l mov l,a mvi a,0 adc h mov h,a ;HL -> table entry mov a,m inx h mov h,m mov l,a return: ret ; ;Return to the main menu. Close any capture file. ; menu: call captfo ;if capt file open jz mu1 call captfl ;flush to disk call captcl ;close file mu1: lxi h,'MP' ;store 'M', 'P' here shld MSPLAN ;so MSPLAN can overwrite jmp $MENU ;done! ; ;Capture text into a file; create the file if it does ;not exist. ; capture: call captfo ;if file open already, jnz captcl ;go stop it lxi h,cptstr ;else ask for filename call prompt ;# jz aborted ;no input call create ;create one, ;# jc aborted ;(cant) cp3: shld captpos ;mark as open xra a sta captcnt ;mark as empty ret ; ;Mark the capture file closed, print a message. ; captcl: mvi a,255 ;mark as closed sta captcnt lxi h,cptostr call PUTSTR ;say we're done jmp $EXTREV ;reverse video off ; ;Write the last character to the capture file, if open. ; captpc: call captfo ;file open? rz ;nope. mov a,c ;A == byte count cpi 128 ;if no room in jc pc1 ;the buffer, call captfl ;flush to disk jc captcl ; no room! pc1: lxi h,buff ;else store this lda captcnt ;byte in the buffer add l mov l,a mvi a,0 adc h mov h,a lda lastc ;get the character mov m,a ;store it lxi h,captcnt inr m ;count it ret ; ;Write any capture data out to clear the buffer. (Only if ;the file is open and there is something in the buffer.) ; captfl: call captfo ;check if open rz ; nope ora a ;check byte count rz ; buffer empty mvi b,0 ;BC == byte count mov m,b ;mark as written lhld captpos ;HL where the data is call write ;write it, shld captpos ;new file position rnc ;if disk full, call $ENTREV ;turn on reverse video, lxi h,xs6str ;say "disk full" call PUTSTR jmp captcl ;go close it, ; ;Check capture file open -- return Z set if not open, ;else the buffer byte count in C. Return HL pointing ;to the byte count. ; captfo: lxi h,captcnt mov a,m mov c,a ;255 means inr a ;file not open ret ; ;Function key routine: enable the cursor and turn the ;LABEL line on and off. ; label: lda lblflg ;toggle xri 1 ;off and on sta lblflg dolabel: call $CURSON ;cursor on lxi h,funkey ;HL == table lda lblflg ora a jz $ERAFNK ;0 == turn it off jmp $STDSPF ;set/display func keys ; ;Function key routine: dial a number. If the first character is ;'P', use pulse dialing. ; dial: lxi h,dialstr call prompt ;input a phone number ;# jz aborted ; mvi a,'T' ;assume TouchTone ; sta mdmdial ; ldax d ;if first character ; cpi 'P' ;is P for Pulse ; jnz dl1 ; sta mdmdial ;set that in mdmstat ; inx d ;then skip it dl1: push d ;save phone number mvi a,'M' ;select modem port call setbaud pop h call $ATDIAL ;dial the phone, jmp $CONHHC ;re-connect phone line ; ;Disconnect. ; disc: call $DISHHC ;disconnect, lxi h,discstr ;say so call PUTSTR jmp dobaud ;restore settings ; ;Abort and return to the caller one-level-up. ; popabort: ;# pop h ; ;Blank command input: command aborted. ; aborted: lxi h,xs4str ;"aborted" call PUTSTR jmp $CRLF ; ;Function key routine: set baud rate. ; baud: lxi h,baudstr ;display the prompt, call prompt ;get input ;# jz aborted ;blank line ; mvi a,'T' ; sta mdmdial ;default to TouchTone ldax d ;see what we got cpi 'M' ;'M' means int. modem jz setbaud cpi '1' ;check for 0 - 9 jc baud cpi ':' ;'9' + 1 jnc baud ; ;Set baud rate as specified by the code in A: M for modem, ;0 - 9 for serial port. For the serial port we point to ;the 7 byte string; for the Modem, we point to a six ;byte string... (no, it's not in the docs...) ; setbaud: sta mdmstat ;set new rate dobaud: lxi h,mdmstat ;HL == modem string mov a,m ;get current setting cpi 'M' ;if serial (not M) stc ;set carry jnz sb1 ;go set it inx h ;else skip the baud/M ora a ;clear carry sb1: jmp $SETSER ;init the port ; ;XMODEM receive a file. ; xrecv: lxi h,xrstr ;file-to-get prompt call prompt ;input a filename ;# jz aborted call create ;create it, ;# jc aborted ;duh, exists?! shld filepos ;where data goes ; ;Set up to receive blocks until we get an EOT. Start off ;with the ACK/NAK character NAK, to serve as the initial ;NAK to start the protocol. ; lxi h,recv ;RECV label line call xminit ;start status display call xmnext ;display starts at 1 ; ;Issue the ACK/NAK character, receive the first byte. If SOH, ;a data block follows; if EOT, then the file ends. ; xr2: call xmstat ;display status jc xdone ;aborted lda ackchar call modout ;send the ACK/NAK call modin ;see what we get jc xdone ;(manual abort) jz xr2 ;nothing cpi 4 ;if EOT jnz xr2a ;output an ACK mvi a,6 ;to let sender call modout ;know we got it xra a ;A == complete jmp xdone ;done! xr2a: cpi 1 ;else if not SOH, jnz xr2 ;wait for one or the other ; ;SOH, block start. Next byte is the sector number, then the 1's ;complement of the sector number. Make sure these are correct. ; xr3: call modin ;get sector number, jc xdone ;(manual abort) jz badblk2 ;timeout! mov c,a lda sector cmp c ;correct? jnz badblk1 ;if not, flush, NAK it call modin ;get a byte, jc xdone ;manual abort jz badblk2 ;timeout! cma ;get 1's compl. sector, mov c,a ;complement it back, lda sector cmp c ;correct? jnz badblk1 ;flush, NAK it ; ;Data block follows. Load data into a local buffer. Stop ;storing data when we get a Control-Z, ie. end of file. (The ;rest of the block may be Control-Z fillers; or their may ;be garbage bytes following the Control-Z.) Keep a count in ;D of bytes actually in the buffer. We of course have to ;checksum all the bytes received. ; lxi h,buff ;where to put data mvi b,128 ;B is byte count mvi c,0 ;C is checksum mvi d,0 ;D is bytes in buff xr4: push b ;HL is file position push d push h call modin ;get a byte pop h pop d pop b jc xdone ;(manual abort) jz badblk2 ;timeout! mov e,a add c ;update checksum mov c,a lda lastc ;if we've had a Control-Z cpi 26 ;don't store any more jz xr4a ;incoming chars mov a,e ;get back the byte, mov m,a ;store it, sta lastc ;remember last char, cpi 26 ;if this isn't Control-Z jz xr4a inx h ;advance the pointer, inr d ;count another byte xr4a: dcr b ;next ... jnz xr4 ; ;Got all the data bytes. ; push b ;save C, checksum push d push h ;save HL, next data address call modin ;get the checksum byte pop h pop d pop b jc xdone ;manual abort jz badblk2 ;not received! cmp c ;OK? jnz badblk2 ;nope! ; ;Good block. Move the data into the file, ACK it. ; goodblk: mov a,d ;see if any data ora a ;to write! jz gb2 mov c,d mvi b,0 ;BC == bytes to put in file lhld filepos ;HL == file position call write ;write to file jc xdone ;disk full!! shld filepos ;HL == next file position gb2: mvi a,6 ;ACK character sta ackchar call xmnext ;advance display jmp xr2 ; ;Bad data block. NAK it. ; ;badblk1: flush line first ;badblk2: NAK it. ; badblk1: call flush ;read until line is jc xdone ;empty (or manual abort) jnz badblk1 badblk2: mvi a,21 ;NAK character sta ackchar lxi h,retries ;count another error, dcr m jnz xr2 ;try again ... mvi a,2 ;"error" code jmp xdone ; ;XMODEM send a file. ; xsend: lxi h,xsstr ;file-to-send prompt call prompt ;get filename ;# jz aborted ;quit if no name call open ;open file at DE jz aborted ; doesnt exist! call $GTXTTB ;get file start shld filepos ;save for later lxi h,send ;start status line call xminit ;start status display ; ;Wait for the initial NAK before starting. We detect CRC vs. ;checksum here; XMINIT sets 'crcflg', we clear it to 0 if ;we get a NAK start character. ; waitnak: call xmstat ;display status, jc xdone ;check abort call modin ;get initial character jc xdone ;manual abort jz waitnak ;nothing cpi 21 ;NAK? (checksum start) jz sdata ;go do it (crcflg == 0) cpi 'C' ;'C'? (CRC mode) jnz waitnak sta crcflg ;flag as CRC mode ; ;First time, or block sent and acknowledged. Check for EOF. ;HL is the initial file address, or the next address if ;the block was sent correctly; store it. ; sdata: call xmnext ;increment block number lda lastc ;if last char sent cpi 26 ;was a Control-Z jz sendeot ;end transfer now ; ;(Re)send the current block. ; sd1: call xmstat ;display status jc xdone lda retries dcr a sta retries mvi a,2 ;code for "error" jz xdone ;too many retries! mvi a,1 call modout ;send block start SOH, lda sector push psw call modout ;send sector, pop psw cma call modout ;1's compl. sector, mvi c,0 ;reset checksum, mvi b,128 ;B == byte count, lhld filepos ;HL == data ; ;Output 128 data bytes. HL is left pointing to the next unsent ;byte (or at the Control-Z if we reach EOF). ; sd2: mov a,m ;get data byte push b push h call modout ;send data bytes pop h pop b lda crcflg ;if CRC mode ora a jz sd2a mov a,m call updcrc ;update CRC sd2a: mov a,m ;update checksum add c mov c,a mov a,m sta lastc ;if we just sent cpi 26 ;a Control-Z jz sd3 ;don't go beyond EOF inx h ;(don't advance ptr) sd3: dcr b jnz sd2 shld nextpos ;save as next position ; ;Output either the checksum or the two CRC bytes. ; lda crcflg ora a jz sd4 ;if CRC mode call fincrc ;complete CRC, mov a,h ;output CRC push h call modout ;MSB first pop b ;then LSB sd4: mov a,c call modout ;send checksum ; ;This block is sent; get ACK or NAK or timeout. ; waitack: call modin ;get a character jc xdone ; manual abort jz waitack ; timeout, get something cpi 21 ;NAK? jz sd1 ; resend same cpi 6 ;ACK? jnz waitack lhld nextpos ; yup, advance file shld filepos ; pointer jmp sdata ; ;File is completely sent. Send the EOT and wait for an ACK. ; sendeot: mvi a,5 ;set retries sta retries eo1: mvi a,4 call modout ;send EOT jc xdone ;abort call modin ;get acknowledge jc xdone ;manual abort jz eo1 ;nothing cpi 6 ;ACK? mvi a,0 ;0 == complete jz xdone ;done! lxi h,retries dcr m jnz eo1 ;count another try... mvi a,2 ;2 == error jmp xdone ; ;Update CRC. Data byte in A. ; updcrc: push b push h mov c,a ;C == data byte mvi b,8 ;B == bits per byte lhld crc ;HL == CRC u1: mov a,c add a ;data MSB -> carry mov c,a mov a,l ral ;carry into CRC LSB mov l,a mov a,h ral ;(16 bit shift left) mov h,a jnc u2 ;if overflow mvi a,21h ; CRC= CRC xor 1021h xra l mov l,a mvi a,10h xra h mov h,a u2: dcr b ;continue jnz u1 shld crc ;update CRC pop h pop b ret ; ;Complete the CRC, return 0 if CRC is correct. ; fincrc: xra a call updcrc ;pass two zeros through xra a call updcrc ; ;Check CRC for zero (OK). ; chkcrc: lhld crc mov a,l ora h ;A == 0 or not ret ; ; ;XMODEM status initialization. HL == label line entry ;for this command. ; xminit: call $CURSOF ;turn cursor off call captfl ;flush/free the buffer mvi a,'D' sta mdmxon ;disable XON/XOFF call dobaud xra a sta abtflg ;no manual abort sta sector ;reset sector sta lastc ;clear 'last character' sta crcflg ;checksum mode mvi a,21 sta ackchar ;set initial NAK mvi a,10 sta retries ;set 10 retries lxi h,0 shld blockno ;starting block number mvi h,1 ;col 1, status line call putsl ;display text, lxi h,xs1str ;"Block: " call PUTSTR call $ERAEOL ;erase E.O.L. jmp flush ;flush garbage ; ;Display XMODEM status on the bottom line. Check for ;BREAK key pressed, and return carry set if so. ; xmstat: mvi h,8 ;col 8, status line call putsl ;position cursor lda crcflg ora a ;print 'C' (indicating jnz xm1 ;CRC mode) mvi a,' ' ;or ' ' xm1: call $LCDPUT ;display char in A lhld blockno ;block number in HL call PUTHL ;print it out mvi a,' ' call $LCDPUT ;trailing space jmp abort ;check BREAK key ; ;Get ready for the next block; advance sector number, ;displayed number, reset retries. ; xmnext: lxi h,0 shld crc ;reset the CRC lxi h,sector inr m ;advance sector mvi a,10 ;reset retry counter sta retries lhld blockno inx h ;increment block # shld blockno ret ; ;Xmodem complete; display status message indicated by A. ; xdone: mov c,a mvi b,0 ;BC == code lxi h,msgtbl ;HL == table dad b dad b ;HL == table(BC) mov a,m inx h mov h,m mov l,a ;HL= (table(BC)) call PUTSTR ;print it, call $ERAEOL ;clear the rest of the line call $CRLF ;then a CR/LF mvi a,'E' sta mdmxon ;enable XON/XOFF jmp dobaud ; ;Output a character to the modem. If BREAK pressed, ;return carry set and A = 1. ; modout: ; call $SNDCOM call $SD232C ;output a byte rnc jmp setabort ; ;Flush all pending input from the modem; abort and return carry ;set if BREAK is pressed. ; flush: mvi b,1 ;flush only call mi0 ;possible read rc ;(abort) jnz flush ;read again if more ret ;RS232 input queue empty ; ;Check for a character from the modem; if none available, return ;Z set. If BREAK is pressed, return carry set. ; modin: mvi b,TIMEOUT ;1 sec time value mi0: mvi c,0 ;inner-loop counter mi1: call $RCVX ;Tandy 200 ROM jnz mi3 ;if nothing ready push b call abort ;check BREAK explicitly pop b rc dcr c jnz mi1 ;keep waiting ... dcr b jnz mi1 ;keep trying ret ;(Z set) mi3: call $RV232C ;read the character jc setabort ;if BREAK key mov c,a ori 1 ;clear Z and carry mov a,c ret ; ;Check for manual abort. ; abort: lda abtflg ;see if aborted already ora a stc rnz ;return carry if so call $KEYX ;check BREAK/PAUSE rnc ; ;Set the manual-abort flag, set carry and abort return code. ; setabort: mvi a,1 sta abtflg ;set flag if so ret ; ;Position the cursor to column H on the status line. (Which ;may be 15 or 16 depending if the LABEL line is displayed.) ; putsl: lda lblflg ;1 == LABEL line on xri 1 ;toggle it, adi 15 ;line 15 or 16 mov l,a ;L= line, jmp $POSIT ;position cursor ; ;Display a prompt at HL, get a line of input. Convert to all ;upper case, null terminated. Returns HL pointing to the ;inputted text, Z set if blank line input. ; prompt: call PUTSTR ;print on status line call $ERAEOL ;erase the line mvi a,40 ;eh? mov c,a ;eh? mov b,a ;eh? call $INLIN ;get input inx h ;eh? push h pop d ;DE --> input line ; ;Convert to all upper case, stop at NULL. ; mvi c,0 ;character count ma2: mov a,m ora a ;stop at null jz ma4 ; process E.O.L. cpi 96 ;check for a - z jc ma3 sui 32 ;convert to A - Z mov m,a ma3: inr c ;count another character inx h jmp ma2 ;repeat... ma4: mov a,c ;if 0 characters input ora a jz popabort ;# pop/abort if blank line ret ;return Z set, DE == input. ; ;Format the filename at DE into a left justified, space filled ;8 char string. The extention, if any, is stripped off. (MAKTXT ;doesn't need it; if open() was called first, then .DO is appended; ;the user may have entered one.) ; fmtfname: ff1: lxi h,$FILNAM ;HL == ROM filename storage mvi c,6 ;copy filename there ff1a: ldax d ;6 chars max ora a ;space-fill after a NUL jz ff1b cpi '.' ;or at the extention jnz ff1c ff1b: mvi a,' ' ;space fill dcx d ;un-do the upcoming INX D ff1c: mov m,a inx h inx d dcr c jnz ff1a mvi m,' ' ;pad out to 8 chars inx h mvi m,' ' inx h mvi m,0 ;terminate it ret ; ;Given a filename at DE, open a file, return HL pointing ;to the directory entry, or Z set if file not found. ;Preserves DE. ; open: mov l,e ;DE == filename mov h,d ;HL == filename op0: mov a,m ;add .DO if its not there cpi 0 ;already jz op1 cpi '.' jz op1 inx h jmp op0 op1: mvi m,'.' ;add '.DO' inx h mvi m,'D' inx h mvi m,'O' ;and a null inx h mvi m,0 ;DE == filename push d mvi a,9 ;SEE COMMENT call $CHKDC + 2 ;SEE COMMENT pop d ret ; ;Create a RAM file. If the file exists, ask if we should delete ;it first (return carry if NO). Filename is at DE. Returns DE ;pointing to the directory entry, HL to the file start. ; create: call open ;if it exists, jz cr1 push d push h lxi h,killstr ;ask if we should overwrite call PUTSTR call $ERAEOL call $CHGET ;get an answer push psw call $LCDPUT ;echo it call $CRLF pop psw pop h pop d ani 5fh ;quick toupper() cpi 'Y' jnz popabort ;# abort if NO ;# stc ;# rnz ;return if NO push d ;save filename push h ;save ptr to dir. entry call $GTXTTB ;get file top address, xchg ;into DE pop h ;dir entry in HL call $KILASC ;kill the file pop d ;get back filename cr1: call fmtfname ;format it, jmp $MAKTXT ;ROM call creates it ; ;Write out BC characters from the buffer to a file, data ;position HL. Returns carry set and A = 3 if no room, else ;HL pointing to next file position. ; write: call $MAKHOL ;make a hole for it, mvi a,3 rc ;disk full!!! lxi d,buff ;now copy the data ; ;Copy C bytes from DE to HL. ; blkmov: ldax d ;byte by byte into mov m,a ;the hole we just made! inx d inx h dcr c jnz blkmov ret ; ;---------------------------------- ; ;Data area. The values here are the proper startup ;values. Note that the init code is deleted at runtime... ; lastc db 0 ;last char sent/recvd lblflg db 1 ;1 == label line on abtflg db 0 ;1 == BREAK pressed captcnt db 255 ;capture byte count (255 == closed) captpos dw 0 ;capture file position filepos dw 0 ;send/recv pos. within file nextpos dw 0 ;next filepos (send) sector db 0 ;send/recv sector number 0 - 255 blockno dw 0 ;send/recv block number 1 - N retries db 0 ;send/recv block retries crcflg db 0 ;send/recv 'C' == CRC mode ackchar db 0 ;send ACK/NAK char crc dw 0 ;send CRC calc ; ;Function keys. ; funkey db 'Dis',227 ;F1 DISCONNECT db 'Cal',236 ;F2 CALL capt db 'Cap',244 ;F3 CAPTURE db 'Bau',228 ;F4 BAUD RATE recv db 'Rec',246 ;F5 XMODEM DOWNLOAD send db 'Sen',228 ;F6 XMODEM UPLOAD db 128 ;F7 db 'Men',245 ;F8 MENU cptstr db 'Capture file: ',0 ;prompt for CAPTURE cptostr db 'Capture off',13,10,0 ; xrstr db 'Recieve file: ',0 ;prompt for RECV xsstr db 'Send file: ',0 ;prompt for SEND killstr db 'Overwrite? (Y,N): ',0 ;prompt for file exists discstr db 'Disconnect',13,10,0 ; baudstr db 'MDM 3=300 5=1200 6=2400 8=9600: ',0 ;prompt for BAUD dialstr db 'Dial: ',0 ;prompt for DIAL ; ;XMODEM status messages, displayed by xdone(), using a code ;to choose from this table: ; xs1str db 'Block: ',0 ;XMODEM status line xs3str db 'Done',0 ;good status xs4str db 'Aborted',0 ;manually aborted xs5str db 'Error!',0 ;bad status xs6str db 'Full! ',0 ;no more memory msgtbl dw xs3str ;code 0 dw xs4str ;code 1 dw xs5str ;... dw xs6str ; ;We use the modem string stored in Tandy 200 RAM. ; mdmstat db '88N1' mdmxon db 'ENN,O,T',0 ; ;-------------------------------- ; ;Things in this area get overwritten at runtime. 'init' is ;replaced with a single RET; 'buff' is the next 128 bytes, ;and the stack follows that. ; init: nop ;changed to RET later buff: ;data buffer here ; ;One-time initialization. ; call dolabel ;label line ON call dobaud ;set baud rate call $CLS ;clear the screen, lxi h,0101h ;line 1, col 1 call $POSIT lxi h,title ;display our title call PUTSTR lxi h,010fh ;line 15, col 1 call $POSIT ;cursor at last line mvi a,c9h ;"RET" sta init ;safely truncate ret ; ; db '---------------------------------------' title db ' Tandy 200 XMODEM & Terminal Program ',13,10 db 13,10 db ' (30 May, 1992)',13,10 db ' World Power Systems',13,10 db ' Tom Jennings, Box 77731',13,10 db ' San Francisco CA 94107 USA',13,10 db 0 end