home *** CD-ROM | disk | FTP | other *** search
- ;****************************************************************************
- ; FILE UPLOAD UTILITY FOR CIS A PROTOCOL.
- ; WRITTEN 3/17/82 BY BOB RICHARDSON
- ; COPYRIGHT (C) 1982 PERFORMANCE BUSINESS MACHINES
- ; program distributed by permission- further distribution must contain this
- ; notice, the copyright notice and the authors name
- ;
- ; INVOKED BY "UPLOAD FNAME.FTP" AND USES DEFAULT FCB AND COMMAND LINE
- ; *************************************************************************
- .z80
- ; equates
- soh equ 01h ; start of header
- etx equ 03h ; end of text
- eot equ 04h ; end of transmission
- enq equ 05h ; enq char - not used
- si equ 0fh ; shift in - starts protocol on terminal
- so equ 0eh ; shift out - ends protocol
- ;
- knak equ 15h ; nak
- dle equ 10h ; data link escape - used to mask chars for transparency
- esc equ 1bh ; escape
- eof equ 1ah ; ctl-z
- ctlz equ 1ah ; also
- cr equ 0dh ; carriage return
- lf equ 0ah ; line feed
- tof equ 0ch ; top of form
- ;
- cldboot equ 00h ; bios coldboot vector
- iobyte equ 0003h ; addr of iobyte
- deffcb equ 05ch ; addr of default fcb
- command equ 080h ; addr of command line
- bdos equ 05h ; addr of bdos jmp
- ; BDOS FUNCTIONS
- prnstg equ 09h ; print string delimited by $
- rdcbuf equ 0ah ; read console buffer function
- fn$opn equ 0fh ; open disk file
- fn$cls equ 010h ; close disk file
- fn$del equ 013h ; delete disk file
- fn$rds equ 014h ; read sequential
- fn$wts equ 015h ; write sequential
- fn$mak equ 016h ; make file
- fn$ren equ 017h ; rename file
- fn$std equ 01ah ; set dma function
-
- ;
- ; BIOS OFFSETS FOR VARIOUS CALLS
- const equ 03h ; constat call
- conin equ 06h ; conin
- conout equ 09h ; character out to console
- list equ 0ch ; character to line printer
- punch equ 0fh ; char to punch device
- rdr equ 12h ; get char from reader device
- reader equ 12h ; alternate spelling
- ; FCB OFFSETS
- current equ 32 ; offset to current record number
- ftype equ 09 ; and offset to type
- ; Version info
- vers equ '1' ; ascii version
- rev equ '2' ; and rev level
- ; History info
- ; 3/20/1982 FIRST COMPLETE VERSION RELEASED
- ; BY THE AUTHOR BOB RICHARDSON OF MICROPRO INTL
- ; CORPORATION - FURTHER DISTRIBUTION MUST CONTAIN
- ; THIS COMMENT - this file made available courtesy
- ; of MicroPro International Corp. and the author
- ;
- ;**************************************************************************
- ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- ; code begins:
- ; MAIN DRIVER LOOP FOR THE UPLOAD PROTOCOL
- ;
- upld:
- ld sp,upld ; the Charlie Strom memorial local stack
- call announce ; copyrite and vers, rev level
- call dskinit ; initialize disk buffer
- call procol ; turn on protocol, open file, and start
- upldrt:
- call sndhdr ; then send the header for file xfer
- call waitack ; and wait for ack response
- jp c,upldrt ; retry if nak response
- jp nz,comfail ; error so dump job
- call sendack ; else prompt for first record
- uplp:
- call getrec ; get terminals record
- jp c,uplp ; wait for resend if nak
- ld a,(seeneot) ; get eotflag
- cp 00h ; and test for completion
- jp nz,fin ; eof - recd eot record
- upl1:
- call putrec ; write rec(s) to disk
- jp c,dspacen ; no space on host disk - send fail message
- call z,sendack
- jp uplp ; loop till eof
- ;
- fin:
- call sendack ; ack eot message
- call complete ; turn off protocol and send all done message
- call fclose ; dump buffer tailings if any
- jp cldboot ; terminate
- ;************************************************************************
- ; end of driver beginning of subroutines
- biosvct:
- ld hl,(cldboot+1) ;get start of bios table
- add hl,de ; get addr for branch
- jp (hl) ; return handled to inline location
- ;************************************************************************
- ; Get rev and version and copyright notice to operator
- announce:
- ld de,cpyrite ; copyright notice
- call prnmes ; to console
- ret ; to caller
- ;
- cpyrite:
- defb cr,lf,'Upload Vers. ',vers,'.',rev,cr,lf
- defb ' Copyright (C) 1982 PBM Division MicroPro International Corporation ','$'
- ;
- ; **************************************************************************
- ; Kudos to Russ Renshaw for inventing this protocol
- ; and special thanks to charlie, tom, and dave - sysops of the CIS CP-MIG
- ; without whose help none of this code would be here
- ; ***************************************************************************
- ; INITIALIZE THE PROTOCOL AND OPEN FILES
- procol:
- ld de,deffcb ; get default fcb
- ld c,fn$opn ; open file function
- call bdos ; see if we can open file
- cp 04h ; test for successful open
- jp c,isfil ; send file exists message if file there
- ld a,(command) ; get count of oper supplied chars
- or a ; and insure non zero value
- jp z,nospec ; complain if not right
- ld hl,deffcb+ftype ; addr of file type
- push hl ; and save for next use
- ld de,typsav ; save area
- ld bc,03h ; length of file type
- ldir ; move to save area - operator supplied file type
- pop de ; here is the next use of filetype addr in fcb
- ld hl,dollar ; $$$ for temporary file type
- ld bc,03h ; length of file type
- ldir ; move it in
- ; the above added for pip compatibility
- ld a,0 ; get zero
- ld (masking),a ; and start masking ctl chars in msg text
- call rmtnm ; prompt operator for name at his end
- ld a,(conbuff+1) ; start of data - contains byte count
- ld c,a ; is count for move
- ld b,0 ; with high order=0
- ld hl,conbuff+2 ; start of actual name
- call noblnk ; bypass all blanks
- jp z,comfail ; if this passes machine is broken - get a new
- ; one.
- ld de,filespec ; addr in esc a message
- push bc ; save the number of non blanks
- ldir ; move filespec to message
- pop hl ; restore count
- ld a,cr ; get cr to terminate the esc a string
- ld (de),a ; and move it to the esc a message buffer end
- inc hl ; update count to reflect this fact
- ld (tmpsav),hl ; and save for next routine
- ; here we create the temporary $$$ file on the disk
- ld de,deffcb ; so make the file - all is well
- ld c,fn$del ; first delete it just in case
- push de ; save for next call
- call bdos ; to pyramid building routine
- pop de ; restore fcb pointer
- ld c,fn$mak ; make function
- call bdos ; mush
- cp 04h ; test sucessful completion
- jp nc,nodirsp ; else give error for no directory space
- ld a,0 ; get zero
- ld (deffcb+current),a ; to current record
- ret ; to caller
- ;
- tmpsav:
- defw 00h ; save area for operator count from
- ; remote file name
- ; **********************************************************************
- ; send the esc a header to the terminal - refer to the protocol document
- ; for the format of this record - is essentially the same as normal
- ; but fields have special meanings.
- sndhdr:
- ; and then turn on protocol in terminal
- ld a,si ; get shift in char
- call punout ; send it
- ld a,esc ; send esc
- call punout ; charge
- ld a,'A' ; esc a for message
- call punout ; mush ye huskies mush
- ld hl,(tmpsav) ; get count from operator answer for name
- push hl ; move to bc
- ld hl,escames ; get message balance addr
- pop bc ; restore count from command line
- ld a,c ; get count in accumulator
- add a,escalen ; and add in normal length
- ld b,a ; get in byte counter
- call prmesout ; send message as normal
- xor a ; set z flag
- ret ; and return
- ; bypass leading blanks in command line
- noblnk:
- ld a,(hl) ; get char
- cp 20h ; test blank
- ret nz ; non blank
- dec c ; reduce count
- ret z ; return error if exhausted
- inc hl ; increment buffer pointer
- jp noblnk
-
- ; file exists on host- blow off terminal as security measure
- ;
- isfil:
- ld de,isflmes ; file found message
- call prnmes ; to console
- jp cldboot ; and terminate abnormally
- ;
- isflmes:
- defb cr,lf,'FILE ALREADY EXISTS ON HOST- CHECK DIRECTORY$'
- ; nospec is issued when user omits the
- ; filespec in the command line
- nospec:
- ld de,nospecm ; file found message
- call prnmes ; to console
- jp cldboot ; and terminate abnormally
- ;
- nospecm:
- defb cr,lf,'I am sorry- you must specify a name for upload$'
-
- ; error - the host has no directory space
- nodirsp:
- ld de,nodirmes ; no directory space
- call prnmes ; to console
- jp cldboot ; and terminate
- ;
- nodirmes:
- defb cr,lf,'NO DIRECTORY SPACE ON HOST !!!','$'
- ;
- ; message for ESC A header - sent if all is well to start upload
- escames:
- defb 'U' ; upload
- defb 'B' ; Binary transfer
- escalen equ $-escames ; length for send routine
- filespec:
- defs 16h ; name of file to upload
- typsav:
- defs 03h ; save area for file type until sucessfull
- dollar:
- defb '$$$' ; temporary file type in case of io error
- ;
- ;**************************************************************************
- ;get name for remote computer
- ; a <cr> response will cause the same name to be used as on host
- rmtnm:
- ld de,remquery ; ask the terminal what it wants to call it
- call prnmes ; to the operating system such as it is
- ld de,conbuff ; get a response
- call rdcon ; and then
- ld hl,conbuff+2 ; convert to insure upper case
- ld a,(conbuff+1) ; get char count xferred
- cp 0 ; insure some characters
- jp z,naminv ; else take default value
- ld c,a ; get counter for blank test to
- call noblnk ; further insure no error
- jp z,naminv ; else use same name as on host
- ld b,a ; in byte counter
- ; roll lower to upper case if necessary
- rmtnm1:
- ld a,(hl) ; pick up char
- cp 061h ; test for lower case
- jr c,rmtntl ; not lower if carry
- cp 07bh ; still looking if less than z
- jr nc,rmtntl ; so go on about business
- and 05fh ; else roll
- ld (hl),a ; and save
- rmtntl:
- inc hl ; bump character pointer
- djnz rmtnm1 ; and get next character
- ret ; and return to caller
- ; use same name as host for remote file
- ;
- naminv:
- ld hl,command+1 ; use the command line input
- ld de,conbuff+2 ; for the remote name
- ld a,(command) ; length
- ld c,a ; to counter with
- ld (conbuff+1),a ; count in command line
- ld b,0 ; zero high order
- ldir ; move characters
- ret ; to caller
- ;
- ; buffer for response to filename question
- conbuff:
- defb 010h ; sixteen bytes max I'll allow
- defb 00h ; initial count
- defs 16 ; and blank buffer
- ;
- remquery:
- defb cr,lf,' I need the file name on your computer',cr,lf,'->','$'
- ;
- ;
- ;***************************************************************************
- ; TRANSMIT ACK OR NAK TO TERMINAL
- sendack:
- ld a,'.' ; get ack character
- jp acknak ; branch to common code
- ;
- sendnak:
- ld a,'/' ; nak char
- acknak:
- call punout ; send it
- scf ; insure carry reset for logic flow in mn loop
- ccf ; could have used or a , i know - good document
- ret ; but thats a subject for another time
- ;*****************************************************************************
- ; send a record using the CIS-A protocol
- ; used primarily for the esc a header in this program
- ;
- prmesout:
- push bc ; save byte count
- push hl ; save buffer pointer
- xor a ; get zero
- ld (chksum),a ; and init checksum
- ld a,soh ; get start of header char
- call punout ; and send it
- ld a,(currec) ; get current record
- call sumupd ; and update checksum
- call punout ; and send it
- pop hl ; restore buffer addr
- pop bc ; restore count to b
- ;
- pmeslp:
- push hl ; save pointer
- push bc ; and char count
- ld a,(hl) ; get char
- call sumupd ; update checksum
- call tstmsk ; test if masking necessary
- call punout ; send char
- pop bc ; restore count
- pop hl ; get buffer pointer
- inc hl ; increment it
- djnz pmeslp ; and loop until all done
- ;
- ld a,etx ; get etx char
- call punout ; send it
- ld a,(chksum) ; get check sum
- cp 020h ; test for < ascii space
- jp nc,pmesl1 ; if = or greater, do not mask
- or 040h ; else add to supply transparency
- push af ; save checksum
- ld a,dle ; send dle
- call punout ; to remote
- pop af ; restore char
- pmesl1:
- call punout ; send it
- ret ; and return
- ;*************************************************************************
- ; Test here for masking of control chars, handle if necessary
- ; control chars are masked to prevent confusion between innocent bit combos
- ; and protocol control chars
- tstmsk:
- push af ; save char
- ld a,(masking) ; get switch value
- cp 00h ; test for on status
- jp nz,tstmsr ; if off return immediate
- pop af ; restore original char
- push af
- cp 05h ; test if one of the offending chars
- jp c,tstms1 ; mask if so
- cp dle ; or if equal the dle
- jp z,tstms1 ; go masked
- cp knak ; or if = to
- jp z,tstms1 ; the fatal nak mask it
- ; common return
- tstmsr:
- pop af
- ret ; common return if no masking necessary
- ; masking needed - so mask it
- tstms1:
- ld a,dle ; send dle char first
- call punout ; and send it
- pop af ; followed by char+40
- or 040h ; to insure transparecy
- ret
- ;
- masking:
- defb 00h ; flag for control char masking
- ;
- ;****************************************************************************
- ; update the checksum
- ; called whenever we need checksumming - uses simple checksum algorithm
- sumupd:
- push af ; save char
- ld e,a ; and leave it in reg
- ld a,(chksum) ; get old checksum
- rlca ; and rotate it
- add a,e ; add new byte
- adc a,0 ; and possible carry
- ld (chksum),a ; and save it
- pop af ; restore character
- ret ; and return
- ;****************************************************************************
- ; Read a record from the serial port
- ; using the Compuserve A protocol
- getrec:
- xor a ; init checksum
- ld (chksum),a ; for use soon
- call rdrin ; get a char from the rdr device
- cp etx ; maybe he is just nervous
- jp z,getrec ; so wait - questionable situation
- cp soh ; better be an soh
- jp nz,comfail ; else abort the protocol
- ; get the terminals record number
- call rdrin ; get record number
- ld (trmrno),a ; and save it for later ack/nak branch
- call sumupd ; and start checksumming
- ; set up to fill a buffer
- ld a,00h ; zero to char count
- ld (charcnt),a ; for index pointer
- ld (charcnt+1),a ; both halves must get cleared
- ld (seeneot),a ; and reset the eot status byte
- ld hl,buffer ; get address of comm buffer
- ; then read data until etx
- getr1: ; mainloop
- push hl ; save the buffer pointer
- call rdrin ; and get a char
- pop hl ; restore buffer pointer
- cp etx ; see if its the end of record
- jp z,getetx ; so go get checksum if so
- cp eot ; test for eot
- jp z,geteot ; and handle if recieved
- getr2:
- cp dle ; was it a masking char?
- jr nz,getr3 ; regular unmasked character
- push hl ; else get next char
- call rdrin ; from terminal
- pop hl ; restore buffer pointer
- and 03fh ; and correct for masking
- getr3:
- ld (hl),a ; save in buffer
- inc hl ; update pointer
- call sumupd ; update checksum
- ld bc,(charcnt) ; update count
- inc bc ; to reflect chars in buffer
- ld (charcnt),bc ; merrily counting
- jp getr1 ; and go back for more
- ;
- ; here when eot is spotted
- geteot:
- ld (seeneot),a ; set eot recieved flag
- call sumupd ; update the checksum for eot
- jp getr1 ; and return to loop for etx, chksum
- ; recvd an etx
- getetx:
- call rdrin ; get term's checksum
- cp dle ; see if its masked
- jr nz,getet1 ; and bypass this if not
- call rdrin ; get real checksum
- and 01fh ; and make it a control char
- ; validate the transmission
- getet1:
- ld c,a ; and test to see
- ld a,(chksum) ; that all is ok
- cp c ; zero if equal
- jp nz,getnak ; reject if not
- ld a,(trmrno) ; get term record number
- ld c,a ; and save for compare
- ld a,(currec) ; get what host thinks is current
- sub c ; and test for terminal high
- jp c,comfail ; signal communications failure if so
- ld (trmrno),a ; else save a flag for disk write routine
- call updrnum ; everything looks ok - we are acking
- xor a ; so clear carry flag to show all went well
- ret ; and return
- ; error has occured in xmission
- getnak:
- call sendnak ; something is very wrong- send a nak
- scf ; set the carry flag
- ret ; and retry
- ; transmission control variables
- trmrno:
- defb 00h ; area for term. record number
- seeneot:
- defb 00h ; flag to indicate eot detected
- charcnt:
- defw 00h ; counter for chars received
- ;
- ;
- ;
- ;**************************************************************************
- ; Routine to write the approved characters to disk. only error is no space
- ; write a record to the disk a character at a time..
- putrec:
- ld a,(trmrno) ; get flag for record number
- or a
- jp nz,dputfin ; bypass put unless correct record
- ld hl,buffer ; get start of comm record
- ld bc,(charcnt) ; and get count of chars
- ld a,b ; and test for zero error
- or c ;
- jp z,dputfin ; bypass putloop if so
- ;
- dputlp:
- ld a,(hl) ; get the char
- push hl ; save the buffer pointer
- push bc ; save the count
- call ptchar ; put 1 char to disk stream
- pop bc ; restore count
- pop hl ; restore buffer pointer
- inc hl ; update ptr
- dec bc ; and update count
- ld a,b ; test for zero
- or c ; value in byte counter
- jp nz,dputlp ; and spin till done
- ;
- dputfin:
- ld a,(dskerr) ; test for possible disk error
- or a ; should be zero
- ret z ; ret good if so
- scf ; else set error for disk space
- ret ; and return
- ;
- ; initialize the disk buffer on startup or after a write
- dskinit:
- ld hl,dbuff ; start addr
- ld de,dbuff+1 ; for overlapping move
- ld bc,buffend-dbuff-1 ; buffer length-1
- ld a,ctlz ; ctlz to clear with
- ld (hl),a ; save the seed
- ldir ; and clear
- ret ; to caller
- ;
- ; routine to put a character in the disk buffer and write if buffer is full
- ; writes will ONLY occur on eot or full buffer
- ptchar:
- ld hl,(dpointr) ; get current pointer
- ld (hl),a ; and save character
- inc hl ; point to next
- ld (dpointr),hl ; and save it
- ld de,buffend ; get limit
- xor a ; clear carry
- sbc hl,de ; test for end
- ret nz ; return if not boundry
- call ptitout ; write the record
- ld hl,dbuff ; re-init pointers
- ld (dpointr),hl ; for next pass
- call dskinit ; re-init buffer
- ret ; and return
-
- ptitout:
- ld de,dbuff ; get dma addr
- ld c,fn$std ; set dmaadr function
- call bdos ; to os
- ld de,deffcb ; fcbaddr
- ld c,fn$wts ; write sequential function
- call bdos ; and its done
- ld (dskerr),a ; save possible error status
- ret ; and return to caller
- ;
- ; close the file and write record if non-empty
- fclose:
- ld hl,(dpointr) ; get pointer value
- ld de,dbuff ; and init value
- xor a ; clear carry
- sbc hl,de ; is pointer at start of buffer??
- jr z,fclos1 ; yes, bypass flush
- call ptitout
- ; close the file and rename it to the originally specified name
- fclos1:
- ld de,deffcb ; for file close function
- ld c,fn$cls ; the aforementioned function
- call bdos ; close and go
- ld de,deffcb+16 ; get next 16 for rename setup
- xor a ; clear drive byte
- inc de
- ld (de),a ; for later
- ld hl,deffcb+1 ; and point to old name
- ld bc,08h ; length for move
- ldir ; move in file name
- ld hl,typsav ; get original file type
- ld bc,03h ; and length
- ldir ; and move it in too
- ld c,fn$ren ; rename function change fil.$$$ to fil.ext
- ld de,deffcb ; addr of fcb for renamed file
- call bdos ; rename it
- ret ; to caller
- ;
- dskerr:
- defb 00h
- ;
- ;*************************************************************************
- ; Communications have failed - reset everything and split
- ;
- comfail:
- ld a,knak ; send physical abort character
- call punout ; and abort
- ld de,failmes ; get comm failure message
- call prnmes ; send message
- ld de,deffcb ; and delete any file by that name
- ld c,fn$del ; delete function
- call bdos ; go out in the best way
- jp cldboot ; and abort
- ;
- failmes:
- defb CR,LF,' Communications Failure - Upload aborted','$'
- ;**********************************************8
- ; Host is out of disk space
- dspacen:
- ld a,knak ; send physical abort character
- call punout ; and abort
- ld de,dspcmes ; get comm failure message
- call prnmes ; send message
- jp cldboot ; and abort
- ;
- dspcmes:
- defb cr,lf,' Host out of disk space - Upload aborted','$'
- ;
- ;**************************************************************************
- ; EOF - send a good eot message to let host know we are done
- puteot:
- ld a,0ffh ; turn of the switch to insure
- ld (masking),a ; that eot is sent unmasked
- ;
- ld hl,eotmes ; get addr of eot char
- ld b,1 ; setup
- call prmesout ; and send it
- ret
- complete:
- ld a,so ; turn off protocol mode at terminal
- call punout ; now
- ld de,ucommes ; get upload complete
- call prnmes ; send it
- ;
- ret
- ucommes:
- defb cr,lf,' UPLOAD COMPLETE ','$'
- eotmes:
- defb eot
- ;**********************************************************************
- ; Wait for an ack from the terminal
- waitack:
- call pcharin ; get protocol char
- cp '.' ; is it ack
- jp z,gotack ; then handle
- cp '/' ; is it nak?
- jp z,rexmit ; then retransmit
- cp knak ; check for abort
- jp nz,waitack ; else loop
- ;
- ld a,01 ; set nz, clear carry
- or a ; and return
- ret
- ;
- rexmit:
- scf ; return carry set
- ret
- ;
- gotack:
- call updrnum ; update current record number
- xor a ; set zero flag and clear carry
- ret
- ;**************************************************************************
- ; update current record number
- updrnum:
- ld a,(currec) ; get current record number
- inc a ; and increment
- cp '9'+1 ; test for overflow
- jr c,updrok ; still valid if carry
- ld a,'0' ; else change it
- updrok:
- ld (currec),a ; and save result
- ret ; then return
- ;****************************************************************************
- ; START OF IO ROUTINES - THESE ROUTINES MAY BE MODIFIED AS REQUIRED TO SUPPORT
- ; THE USERS HARDWARE ENVIRONMENT
- ;****************************************************************************
- ; send a message to terminal using print string convention - this routine
- ; assumes terminal is accessible as console and uses bdos
- prnmes:
- ld c,prnstg ; settup function number
- call bdos ; call the operating system
- ret ; and return
- ;***************************************************************************
- ; this routine reads a standard console buffer from the operator- again, using
- ; bdos
- rdcon:
- ld c,rdcbuf ; read console buffer function
- call bdos ; to os
- ret ; to caller
-
- ;***********************************************************************
- ; This routine uses the bios punch call to access the console port
- ; the routine must send the char in a to the modem without stripping parity
- ;
- punout:
- push af ; save char
- ld c,a ; get char in proper register
- ld de,punch ; get offset
- call biosvct ; go doit
- pop af ; restore char
- ret
- ;**************************************************************************
- ; This routine calls the bios reader input to get an 8 bit character
- ; character is returned in a with parity bit INTACT!
- rdrin:
- ld de,reader ; get proper offset
- call biosvct ; go get the char
- cp knak ; see it its knak
- jp z,comfail ; comm failure if so
- ret
- ;
- ; *************************************************************************
- ; read one char from modem - parity may be stripped
- pcharin:
- ld de,conin ; get 1 char via bios
- call biosvct ; and return
- ret ; to caller
-
- ;
- currec:
- defb '1' ; initial record number
- chksum:
- defb 00h ; initial check sum
- dpointr:
- defw dbuff ; initial pointer value
-
- ;
- ;
- dbuff:
- ds 128 ; dma address
- buffend equ $
- buffer equ $
- end