home *** CD-ROM | disk | FTP | other *** search
- ; PLINK.ASM ver 6.4
- ; (revised 6/14/81)
- ;
- ;PLINK is a CP/M transient command which allows the user to
- ;PLINK currently supports two way transfer of text files between
- ;the CP/M disk and the remote computer. The following control
- ;codes may be initiated from the console keyboard:
- ;
- ;Control-E Exit PLINK to CP/M "warm-boot".
- ;
- ;Control-T Transmit ASCII file to remote system, asks for
- ; drive (A, B, etc.) and filename.typ.
- ;
- ;Control-C Aborts transmission of file to remote system.
- ;
- ;Control-Y Switches between saving and ignoring
- ; incoming ASCII data in RAM buffer,
- ; for later transfer to disk.
- ;
- ;Control-W Writes RAM buffer to disk, and asks for drive
- ; and filename.typ.
- ;
- ;Del (delete) Backspace when in command mode (e.g. ^T or ^W).
- ;
- ;Control-U Aborts current line when in command mode.
- ;
- ;(Note: all other control codes are passed to modem output, and
- ;may be interpreted by the remote system as various control
- ;functions.)
- ;
- ;
- ;bdos entry point and function codes
- ;
- base equ 0 ;<<-- set to offset of CP/M for your
- ;system, standard systems are 0, some
- ;'alternate' systems are 4200H
- ;
- bdos equ base+5
- resdsk equ 13 ;reset disk system
- offc equ 15 ;open file
- cffc equ 16 ;close file
- dffc equ 19 ;delete file
- rrfc equ 20 ;read record
- wrfc equ 21 ;write record
- mffc equ 22 ;make file
- ;
- ;TRS80 pickles and trout sio calls
- ;offset by -3 that is add 3 to all calls
- ;
- setsio equ 30h ;set up z80 sio
- siotst equ 33h ;read sio status
- sioinp equ 36h ;input a char
- sioout equ 39h ;output a char
- ;
- ;
- ;default fcb and field definitions
- ;
- fcb equ base+5ch
- fn equ 1 ;file name field (rel)
- ft equ 9 ;file type field (rel)
- ex equ 12 ;file extent field (rel)
- nr equ 32 ;next record field (rel)
- dbuf equ base+80h ;default disk buffer address
- ;
- ;ascii control characters
- ;
- cr equ 0dh ;carriage return
- lf equ 0ah ;line feed
- del equ 7fh ;delete (rubout)
- bell equ 07h ;bell signal
- tab equ 09h ;horizontal tab
- xon equ 11h ;x-on character
- null equ 00h ;null char
- ;
- ;the following "trigger" equate is set to "lf" (linefeed)
- ;by default. an optional trigger char may be passed via fcb1
- ;
- ; ie: PLINK B will set trigger to "bell"
- ;
- ;the following options are allowed
- ;
- ; 1. B = bell 07h
- ; 2. X = xon 11h
- ; 3. U = upload no trigger check at all
- ;
- ;any other ascii character may be passed through fcb1
- ;
- ;
- trigger equ LF ;default value
- ;
- ;
- ;warning character for low memory
- ;
- wrnsig equ BELL ;if you have one, put 'BELL' here
- ;...else put '*' here.
- ;
- ;
- ; **main program**
- ;
- org base+100h
- ;
- jmp 4000h
- org base+4000h
- lnki: lxi sp,stack+64 ;create local stack
- lhld base+1 ;point to CP/M jmp table
- lxi d,3 ;get ready to add 3
- dad d ;point to con status jmp
- shld citcal+1 ;modify call adrs
- dad d ;point to con in jmp
- shld rccal+1 ;modify call adrs
- dad d ;point to con out jmp
- shld wccal+1 ;modify call adrs
- lda fcb+1 ;see if optional trigger char
- cpi 20h ;blank.. ?
- jz skp ;..blank so use default "lf"
- cpi 'B' ;bell wanted
- jz trgbel
- cpi 'X' ;xon wanted
- jz trgxon
- cpi 'U' ;uploading no checking for trigger
- jz trgupl
- ;
- settrg sta overly+1 ;store the character as is then
- jmp skp
- ;
- trgbel mvi a,bell
- jmp settrg
- ;
- trgxon mvi a,xon
- jmp settrg
- ;
- trgupl xra a ;zero out jump
- sta overl1+1 ;change check for c/r to null
- sta overl2+1 ;and send linefeeds as well
- jmp skp
- ;
- skp: equ $
- ;
- ;
- cont:
- xra a ;clear char buffers
- sta inch
- sta outch
- sta flag ;clear text save flag
- lxi h,tbuf ;set ptr to tbuf
- shld ptr
- lxi h,0 ;size = 0
- shld size
- lxi h,lnkims ;print sign-on message
- call wcs
- ;
- ;main loop
- ;
- lnki3: call citest ;jump if no data from console
- jz lnki4
- call rcc ;else read console data
- cpi 20h
- cc pcc ;call pcc if control char
- jc lnki4 ;jump if pcc handled char
- ori 80h ;else set valid data bit
- sta inch ;and store in input char buffer
- ;
- lnki4: lda outch ;jump if no data for console
- ora a
- jp lnki5
- ani 7fh ;else discard valid data bit
- call wcc ;send char to console
- xra a ;then clear output char buffer
- sta outch
- ;
- lnki5: call mitest ;jump if no data from modem
- jz lnki6
- call rmc2 ;else read modem data
- call save ;save char in text buffer if flag on
- ori 80h ;set data valid bit
- sta outch ;store in output char buffer
- ;
- lnki6: call motest ;jump if modem xmit buffer busy
- jnz lnki7
- lda inch ;jump if no data for modem
- ora a
- jp lnki7
- ani 7fh ;discard valid data bit
- call wmc
- ;
- xra a ;...then clear input char buffer
- sta inch
- ;
- lnki7: jmp lnki3 ;end of main loop
- ;
- lnkims: db cr,lf,'PLINK ver 6.4'
- db cr,lf,cr,lf
- db '[^T]ransmit, [^Y]ank, [^W]rite, [^E]xit, [^C]ancel'
- db cr,lf,'Ready',cr,lf,lf,0
- ;
- ;pcc - process control character
- ;
- pcc: cpi 'E'-40h ;jump out if ctrl e
- jnz pcc1
- push h
- lxi h,ays ;print 'are you sure'
- call wcs
- pop h
- call rcc ;get answer
- call wcc ;echo it
- ani 5fh ;make upper case
- cpi 'Y' ;yes?
- jz pccex ;exit
- call wccr ;crlf
- stc ;tell plink to ignore this character
- ;
- ;
- pcc1: cpi 'T'-40h ;jump if not control-t
- jnz pcc2
- call stf ;transmit text file to modem
- stc ;tell plink to ignore this character
- ret
- ;
- pcc2: cpi 'Y'-40h ;jump if not control-y
- jnz pcc3
- lda flag
- dcr a ;was it zero?
- jnz pcc2a ;yes
- sta flag ;no, was 1, now 0
- lxi h,pcmnix ;print ignore incoming stuff
- jmp pcc2b
- ;
- pcc2a: mvi a,1 ;turn on text save flag
- sta flag
- lxi h,pccmr ;print 'saving incoming text in memory'
- ;
- pcc2b: call wcs
- stc ;tell plink to ignore this character
- ret
- ;
- pcc3: cpi 'W'-40h ;jump if not control-W
- jnz pcc4
- xra a ;turn off text save flag
- sta flag
- call wtb ;write text buffer to disk
- stc
- ret
- ;
- pcc4: stc ;let plink handle all other cont. codes
- cmc
- ret
- ;
- pccex: lxi h,disms ;print 'modem not disconnected'
- call wcs
- jmp base ;exit to warm boot
- ;
- ays: db cr,lf,'Exit to CP/M - are you sure (Y or N)? ',0
- ;
- disms: db cr,lf,'+++ Exit to CP/M +++',cr,lf,0
- ;
- pccmr: db cr,lf,'Saving incoming text in memory',cr,lf,0
- pcmnix: db cr,lf,'Ignoring incoming text',cr,lf,0
- ;
- ;stf - send text file (to modem)
- ;
- stf: call gfn ;get name of disk file to send
- jc stf6 ;jump if file name error
- call open ;try to open specified file
- cpi 255 ;jump if file not found
- jz stf7
- ;
- stf1: call read ;read next record into dbuf
- cpi 1 ;jump if end-of-file
- jz stf5
- lxi h,dbuf ;point to disk buffer
- mvi c,128
- ;
- stf2: mov a,m ;fetch next char from dbuf
- inx h
- cpi 'Z'-40h ;jump if end-of-file character
- jz stf5
- ;
- overl2 cpi lf ;ignore line feeds
- jz stf4
- call wmc ;write character to modem
- call wcc ;write character to console
- ;
- overl1 cpi cr ;jump if not carriage return
- jnz stf4
- ;
- stf3: call citest ;check console data ready
- jz stf3a ;no data there
- call rcc ;get console character
- cpi 'C'-40h ;control c aborts it
- jz stf8
- ;
- stf3a: call mitest ;wait for next modem character
- jz stf3
- call rmc2 ;check modem for trigger char.
- ;
- overly cpi trigger
- jnz stf3
- call wccr ;send crlf to console
- ;
- stf4: dcr c ;loop thru rest of dbuf
- jnz stf2
- jmp stf1 ;go get next record from disk
- ;
- stf5: lxi h,stfsm ;print 'file send complete'
- call wcs
- ret
- ;
- stf6: lxi h,stfs1 ;print 'file name error'
- call wcs
- ret
- ;
- stf7: lxi h,stfs2 ;print 'file not found'
- call wcs
- ret
- ;
- stf8: lxi h,stfsa ;print 'file send aborted'
- call wcs
- ret
- ;
- stfsm: db 'File send complete',cr,lf,0
- stfs1: db 'File name error or abort',cr,lf,0
- stfs2: db 'File not found',cr,lf,0
- stfsa: db cr,lf,'File send aborted',cr,lf,0
- ;
- ;save - save char in text buffer if flag on
- ;
- ; entry conditions
- ; a - character to save
- ;
- save: push psw
- lda flag
- ora a
- jnz save1
- pop psw
- ret
- ;
- save1: pop psw
- cpi del ;rubout (del) ?
- rz ;yes, ignore it
- cpi 20h ;test for control characters
- jnc save2 ;jump if not control char.
- cpi cr ;allow cr to be saved
- jz save2
- cpi lf ;allow lf to be saved
- jz save2
- cpi tab ;allow tab to be saved
- jz save2
- ret ;ignore all other control chars.
- ;
- save2: push h
- lhld size ;size = size + 1
- inx h
- shld size
- lhld ptr
- mov m,a
- inx h
- shld ptr
- push psw
- lda base+7 ;get system size
- sui 1 ;so we dont crash CP/M
- cmp h ;are we out of room?
- jz saveab ;yes, abort
- sui 4 ;leave some room (1k)
- cmp h
- mvi a,wrnsig ;signal console running out of space
- cc wcc
- pop psw
- pop h
- ret
- ;
- ;saveab - ran out of room, issue message and flow
- ; through to disk save routine
- ;
- savend: db bell,cr,lf,'Aborting - no room left',0
- ;
- saveab: lxi sp,stack+64 ;reinitialize stack
- lxi h,savend ;print 'aborting - no room left'
- call wcs
- lxi h,lnki ;set up return address
- push h ;leave it on the stack
- ;
- ;wtb - write text buffer to disk
- ;
- wtb: lhld size ;jump if text buffer empty
- mov a,l
- ora h
- jz wtb5
- mvi c,resdsk ;reset in case read-only
- call bdos
- call gfn ;get file name
- jc wtb6 ;jump if file name error
- call delt ;delete old file, if any
- call make ;make new file
- lhld size ;de = tbuf size
- xchg
- lxi h,dbuf ;top of stack points to dbuf
- push h
- lxi h,tbuf ;hl points to tbuf
- ;
- wtb1: mvi c,128 ;disk buffer size
- ;
- wtb2: mov a,m ;fetch next byte of tbuf
- inx h
- xthl
- mov m,a ;store in dbuf
- inx h
- xthl
- dcx d ;size = size - 1
- mov a,d ;exit loop if size = 0
- ora e
- jz wtb3
- dcr c ;loop until dbuf full
- jnz wtb2
- call write ;write full dbuf to disk
- xthl ;top of stack points to dbuf
- lxi h,dbuf
- xthl
- jmp wtb1 ;loop until end of tbuf
- ;
- wtb3: pop h ;hl points to current place in dbuf
- ;
- wtb4: mvi m,'Z'-40h ;store eof code
- inx h
- dcr c ;loop thru rest of dbuf
- jnz wtb4
- call write ;write last sector to disk
- call close ;clean up act and go home
- lxi h,tbuf ;clear text buffer
- shld ptr
- lxi h,0
- shld size
- lxi h,wtbsm ;print 'buffer saved on disk'
- call wcs
- ret
- ;
- wtb5: lxi h,wtbs1 ;print 'text buffer empty'
- call wcs
- ret
- ;
- wtb6: lxi h,wtbs2 ;print 'file name error'
- call wcs
- ret
- ;
- wtbsm: db cr,lf,'Buffer saved on disk',cr,lf
- db 'Memory save cancelled',cr,lf,0
- wtbs1: db 'Text buffer empty',cr,lf,0
- wtbs2: db 'File name error or abort',cr,lf,0
- ;
- ;wcs - write console string
- ;
- ; entry conditions
- ; hl - points to string (term by zero byte)
- ;
- wcs: mov a,m
- inx h
- ora a
- rz
- call wcc
- jmp wcs
- ;
- ;wccr - write console carriage return (and line feed)
- ;
- wccr: mvi a,cr
- call wcc
- mvi a,lf
- ;
- ;wcc - write console character
- ;
- ; entry conditions:
- ; a - character to write
- ;
- wcc: push psw
- push b
- push d
- push h
- mov c,a ;get character for cbios
- wccal: call $-$ ;modified by init.
- pop h
- pop d
- pop b
- pop psw
- ret
- ;
- ;rcs - read console string (with echo)
- ;
- ; exit conditions
- ; b - number of characters read (<255)
- ; hl - points to last char stored (cr)
- ;
- rcs: lxi h,ibuf
- mvi b,0
- ;
- rcs1: call rcc ;read next char from console
- cpi del ;jump if not del
- jnz rcs2
- inr b ;ignore del if ibuf already empty
- dcr b
- jz rcs1
- dcx h ;else discard last char
- mov a,m ;echo discarded char to console
- call wcc
- dcr b ;decrement count
- jmp rcs1 ; and loop
- ;
- rcs2: cpi 'U'-40h ;jump if not control u
- jnz rcs3
- call wccr ;else abort current line
- jmp rcs ; and start over
- ;
- rcs3: call wcc ;echo char to console
- mov m,a ;store char in ibuf
- inr b ;increment count
- cpi cr ;jump if carriage return
- jz rcs4
- inx h ;else advance pointer
- jmp rcs1 ; and loop
- ;
- rcs4: mvi a,lf ;issue line feed and return
- call wcc
- ret
- ;
- ;rcc - read console character
- ;
- ; exit conditions
- ; a - character read
- ;
- rcc: push b
- push d
- push h
- rccal: call $-$ ;modified by init.
- pop h
- pop d
- pop b
- ret
- ;
- ;wmc - write modem character
- ;
- ; entry conditions
- ; a - character to write
- ;
- ;
- wmc:
- ani 7fh
- sta xyz
- di
- out 0
- mvi a,0
- sta 0ef08h
- lda xyz
- sta 2a01h
- out 1
- mvi a,1
- sta 0ef08h
- ei
- ret
- ;
- ;rmc - read modem character
- ;
- ; exit conditions:
- ; a - character read
- di
- out 0
- mvi a,0
- sta 0ef08h
- rmc:
- lda 2a00h
- ani 01h
- cpi 00h
- jz rmc
- out 1
- mvi a,1
- sta 0ef08h
- ei
- rmc2: di
- out 0
- mvi a,0
- sta 0ef08h
- lda 2a01h
- sta xyz
- out 1
- mvi a,1
- sta 0ef08h
- ei
- lda xyz
- ani 7fh
- ret
- ;
- ;
- ;
- ;gfn - get file name
- ;
- gfn: lxi h,gfnsd ;print 'which drive?'
- call wcs
- call rcc ;get answer from console
- call wcc ;echo it to console
- ani 5fh ;make upper case
- cpi 'C'-40h ;^C means abort
- jz gfn6
- sui 'A'-1
- jc gfn ;require alphabetic
- jz gfn
- cpi 17 ;allow 16 drives (as in CP/M 2.x)
- jnc gfn
- sta fcb
- ;
- gfnb: lxi h,gfns1 ;print 'filename? '
- call wcs
- call rcs ;read response into ibuf
- lxi h,fcb+fn ;blank fill fn and ft fields
- mvi c,11
- ;
- gfn1: mvi m,' '
- inx h
- dcr c
- jnz gfn1
- lxi h,ibuf ;point to input buffer
- lxi d,fcb+fn ;scan off fn field
- mvi c,9
- ;
- gfn2: mov a,m ;fetch next char from ibuf
- inx h
- cpi 61h ;if lc, convert to uc
- jc gfn2a
- sui 20h
- ;
- gfn2a: cpi cr ;jump if end of line
- jz gfn5
- cpi '.' ;jump if end of name
- jz gfn3
- stax d ;else store char in fn field
- inx d
- dcr c ;loop if 8 or less chars so far
- jnz gfn2
- jmp gfn6 ;else take error exit
- ;
- gfn3: lxi d,fcb+ft ;scan off ft field
- mvi c,4
- ;
- gfn4: mov a,m ;fetch next char from ibuf
- inx h
- cpi 61h ;if lc, convert to uc
- jc gfn4a
- sui 20h
- ;
- gfn4a: cpi cr ;jump if end of line
- jz gfn5
- stax d ;else store char in ft field
- inx d
- dcr c ;loop if 3 or less chars so far
- jnz gfn4
- jmp gfn6 ;else take error exit
- ;
- gfn5: xra a
- sta fcb+ex ;set extent number to zero
- sta fcb+nr ;set record number to zero
- stc ;clear error flag and return
- cmc
- ret
- ;
- gfn6: stc ;set error flag and return
- ret
- ;
- gfnsd: db cr,lf,'Which drive? ',0
- gfns1: db cr,lf,'Filename? ',0
- ;
- ;open - open disk file
- ;
- open: push h
- push d
- push b
- lxi d,fcb
- mvi c,offc
- call bdos
- pop b
- pop d
- pop h
- ret
- ;
- ;read - read record from disk file
- ;
- read: push h
- push d
- push b
- lxi d,fcb
- mvi c,rrfc
- call bdos
- pop b
- pop d
- pop h
- ret
- ;
- ;close - close disk file
- ;
- close: push h
- push d
- push b
- lxi d,fcb
- mvi c,cffc
- call bdos
- pop b
- pop d
- pop h
- ret
- ;
- ;delt - delete disk file
- ;
- delt: push h
- push d
- push b
- lxi d,fcb
- mvi c,dffc
- call bdos
- pop b
- pop d
- pop h
- ret
- ;
- ;write - write record to disk
- ;
- write: push h
- push d
- push b
- lxi d,fcb
- mvi c,wrfc
- call bdos
- pop b
- pop d
- pop h
- ret
- ;
- ;make - make new disk file
- ;
- make: push h
- push d
- push b
- lxi d,fcb
- mvi c,mffc
- call bdos
- pop b
- pop d
- pop h
- ret
- ;
- ;citest - check console input status
- ;
- citest: push b
- push d
- push h
- citcal: call $-$ ;modified by init.
- ora a ;set zero flag
- pop h
- pop d
- pop b
- ret ;zero flag carries answer
- ;
- ;mitest - check modem input status
- mitest: di
- out 0
- mvi a,0
- sta 0ef08h
- lda 2a00h
- sta xyz
- out 1
- mvi a,1
- sta 0ef08h
- ei
- lda xyz
- ani 01h
- cpi 00h
- jnz mitst1
- ora a
- jmp mitst2
- mitst1 cma
- ora a
- mitst2 ret
- ;
- ;
- ;motest - check modem output status
- ;
- motest:
- di
- out 0
- mvi a,0
- sta 0ef08h
- lda 2a00h
- sta xyz
- out 1
- mvi a,1
- sta 0ef08h
- ei
- lda xyz
- xri 02h
- ani 02h
- mvi a,0
- jz motst1 ;zero flag carries answer
- cma
- ;
- motst1: ora a ;set zero flag if ready
- ret
- ;
- ;data area
- ;
- xyz: db 00
- inch: ds 1 ;input char buffer (to cyber)
- outch: ds 1 ;output char buffer (from ciber)
- stack: ds 80 ;local stack
- ibuf: ds 256 ;input buffer
- ;
- ;text buffer
- ;
- flag: ds 1 ;text save flag
- ptr: ds 2 ;text buffer pointer
- size: ds 2 ;text buffer size
- tbuf: equ $ ;start of text buffer
- ;
- end