Trailing-Edge
-
PDP-10 Archives
-
decuslib20-10
-
decus/20-185/xmit.mac
There are no other files named xmit.mac in the archive.
;Edit number 32 by SST.D-BIGELOW on 7-Nov-84
; Add feature test LWrite so that vaxmit can be assembled without
; support for last writer string.
;
;Edit number 31 by SST.D-BIGELOW on 2-Nov-84
; Fix bug where second attempt to delete a file would jump off into
; literal space in DELFIL: routine.
;
;Edit number 30 by SST.D-BIGELOW on 25-Oct-84
; Remove ASND call to get I/O port, since it hinders debugging when
; a system fork is killed and port ownership is retained. Also change
; feature test switches.
;
;Edit number 27 by SST.D-BIGELOW on 24-Oct-84
; Remove GNJFN call in file sending routine. It seems to malfunction
; after a deletion of the file it refers to, causing many race
; conditions.
;
;Edit number 26 by SST.D-BIGELOW on 24-Oct-84
; Insert last writer string into filename packet, to preserve file
; author names across the network.
;
;Edit number 25 by SST.D-BIGELOW on 7-Sep-84
; Make XMIT handle eight bit files.
;
;Edit number 24 by SST.D-BIGELOW on 4-Sep-84
; Break program into header and main file, and explicitly specify which
; system each version is to talk to.
; * Begin minor version 3.
;
;Edit number 23 by SST.D-BIGELOW on 2-Aug-84
; Add code to detect DDT startup and not hang awaiting LF after
; rescan buffer is empty.
;
;Edit number 22 by SST.D-BIGELOW on 1-Aug-84
; Correct bug in nak counting caused by use of T4 in INPACK routine.
;
;Edit number 21 by SST.D-BIGELOW on 1-Aug-84
; Add routine to clear input and output buffer of transmit line after
; a nak or retransmit. Try to prevent nak cascading.
;
;Edit number 20 by SST.D-BIGELOW on 24-Jul-84
; Inprove error handling of NAK packets.
;
;Edit number 17 by SST.D-BIGELOW on 24-Jul-84
; Make the INPACK routine re-shuffle the packet so that it is always
; alligned with PACKET despite preceeding nulls. Handle the quoting
; internally to use SOUT rather than BOUT later on.
; * Begin minor version 2.
;
;Edit number 16 by SST.D-BIGELOW on 23-Jul-84
; Remove debugging conditional, and make debugging output always
; available by switch. Make logging settable by feature test but let
; it be set by switch too.
;
;Edit number 15 by SST.D-BIGELOW on 20-Jul-84
; Add /S switch to start with sending rather than receiving. Used
; during debugging.
;
;Edit number 14 by SST.D-BIGELOW on 20-Jul-84
; Add packet number or ack/nak codes to ack/nak packets. Avoid
; problems getting out of sync.
; * Begin minor version 1.
;
;Edit number 13 by SST.D-BIGELOW on 19-Jul-84
; Yet more error reporting in receiving routine -- report the difference
; between packet received and packet expected.
;
;Edit number 12 by SST.D-BIGELOW on 19-Jul-84
; Change available byte sizes from eight and six to seven and six.
; Exchanging bytes with the VAX is only profitable in seven-bit mode.
;
;Edit number 11 by SST.D-BIGELOW on 18-Jul-84
; Include complete error logging if log file is on. Report the cause
; of all error aborts.
;
;Edit number 10 by SST.D-BIGELOW on 16-Jul-84
; Include VAX Xmit support. If on KLA, decide whether we're talking to
; KLB or VAX and open appropriate port.
;
;Edit number 7 by SST.D-BIGELOW on 13-Jul-84
; Tidy up abort processing -- make low level routines always decide
; when to clear a jfn rather than leaving it to the main loop.
;
;Edit number 6 by SST.D-BIGELOW on 12-Jul-84
; Make sure F.Abrt is always cleared in main loop.
;
;Edit number 5 by SST.D-BIGELOW on 10-Jul-84
; Add ack and nak logging, with name of file, to SY:XMIT.LOG.
;
;Edit number 4 by SST.D-BIGELOW on 10-Jul-84
; Change again to make count and checksum and packet number use offsets
; rather than parity. Must avoid sending 0 or 200 characters, since
; they seem very prone do dropping at high speeds.
;
;Edit number 3 by SST.D-BIGELOW on 10-Jul-84
; Change checksum and count to use parity bit instead of offset.
;
;Edit number 2 by SST.D-BIGELOW on 6-Jul-84
; First complete version of program, ready for first stage
; debugging. No debugging aids yet, and poor error recovery.
;
Subttl Table of contents for Xmit
; -- Section -- -- Page --
;
; 1. Edit history.................................................. 1
; 2. Table of contents............................................. 2
; 3. Program Initialization........................................ 3
; 4. Priority Interrupt System routines............................ 8
; 5. Interrupt processing routines................................. 9
; 6. Open and close port for I/O................................... 10
; 7. Start of main program......................................... 11
; 8. Getpkt - Check for incoming packets........................... 14
; 9. Inpack - routine to check and valididate incoming packets..... 15
; 10. Ack, Nak and Can routines..................................... 18
; 11. Packet control routines....................................... 19
; 12. File receiving routine........................................ 20
; 13. Incoming data packet handling................................. 21
; 14. Chkfil - Send outgoing files.................................. 23
; 15. Sndpak - loop sending data packets............................ 25
;
; (End of table of contents)
Subttl Program Initialization
;Version information
Vmajor==1 ; Major version
Vminor==3 ; Minor version
Vedit==32 ; Edit number
Vcust==4 ; WCC edit code
Pgver. (VMajor,VMinor,VEdit,VCust)
;==========================================================================
;Program feature test switches
Omit Comman ;no comnd jsys routines
Omit Memory ;no need for memory management
Omit Sorter ;or sorting either
Omit String ;no string package
Include F..UUO ; Local uuo features
; If included, requires UUOCON.REL
;* === Abstract ===
;*
;*
;* Written by SST.D-BIGELOW on 02-Jul-84
;*
;* Files required: SYMBOL.UNV, MACSYM.UNV, MONSYM.UNV, MACREL.REL, UUOCON.REL
;*
;* Description: This program runs on a DEC-20 to automatically handle file
;* transfers between systems. It reads files from OUTBOX: and sends
;* them across the line, and puts incoming files into INBOX:.
;*
;*
;Protocol explanation
Comment %
There are six possible types of packets, as follows:
A Ack a packet (standard good response)
B Nak a packet (standard response to bad packet)
C Cancel transaction (no response appropriate)
D Data packet (requires A, B or C back)
E EOF packet (requires A, B or C back)
F File init packet (requires A, B or C back)
;Proper packet format is:
[SOP] [CODE] [COUNT] [D1] .. [Dn] [CHK] [EOP]
Where
SOP == start of packet, ascii code 1 (^A)
CODE == type of packet, A through F
COUNT == number of data packets, 0 through MAXPKT-n
D1..Dn == data packet, numbered in sequence
CHK == seven bit checksum
EOP == end of packet, ascii code 2 (^B)
The COUNT and the CHK values are constrained to be 7 bits, from 0 - 177.
To avoid problems with ascii codes 0-37, these values are translated to
the values 240-277. The count is added to the checksum before this
translation takes place, and the checksum includes all bytes after SOP.
In data packets, values in the range 0-2 or 200-202 are quoted, with a
quote byte ("\") before and octal 40 added to the character itself,
coming after. A sequence "\\" gives a single "\".
%
;Symbols and storage
;Abort macro
Define Abort(ax),<
jrst [skpoff f.log ;;logging?
print asc<%P ax %C> ;;yes, print message
jrst p.can] ;;and cancel packet
>
Define JAbort(ax),<
erjmp [skpoff f.log ;;logging?
print asc<%P ax -- %E%C> ;;yes, print message
jrst p.can] ;;and cancel packet
>
Define GAbort(ax),<
jrst [skpoff f.log ;;logging?
print asc<%P ax %C> ;;yes, print message
jrst clrfil] ;;clear file and return
>
;Switches and locations
Switch F.Ieof ;input end of file
Switch F.Abrt ;aborting (can)
Switch F.Dbug ;debugging
Switch F.Log ;information logging
Switch F.Send ;start with send (debugging)
;Feature tests
Ifndef Delay,<Delay==^D45000> ;Delay time
Ifndef Logit,<Logit==1> ;Logging on
Ifndef LWrite,<LWrite==1> ;last writer string written
Dsend==delay * 2 / 3 ;sending delay 2/3 of regular delay
Dwait==^D20000 ;20 seconds for data wait
Loging: exp logit ;state of default logging
Maxpkt==^D100 ;maximum packet size
Maxsnd==maxpkt/2-6 ;maximum send size, assuming quoting
Blksiz==maxpkt/4+1 ;storage for packets
Maxnak==^D12 ;maximum naks before aborting
Quote=="\" ;Quote character
;More symbols
sop==1 ;start of packet
eop==2 ;end of packet
nul==0
ack==1 ;begin "A" offset
nak==2 ;nak
can==3 ;cancel or abort transaction
dat==4 ;data packet
eof==5 ;end of file
sof==6 ;start of file
Code: block 1 ;ack code
Dat1: block 1 ;first data item
Intmsk: block 1 ;interrupt mask word
Intblk: block 3 ;interrupt levels
Numack: block 1 ;number of acks per file
Numnak: block 1 ;number of naks per file
Nakcnt: block 1 ;count of naks received
Pktnum: block 1 ;packet number
Chksum: block 1 ;checksum
Logjfn: block 1 ;logging file
Ccoc: block 2 ;ccoc words
Data: block blksiz ;incoming file characters
Outpkt: block blksiz ;outgoing data
Packet: block blksiz*2 ;incoming data
;**; Filename and writer strings are cleared together -- don't separate
Filnam: block 24 ;filename block
Writer: block 24 ;last writer block
strlen==.-filnam-1 ;size to clear
Stak..: block stksiz ;standard stack
;Strings
;Priority interrupt storage
Chntab: xwd 1,ctrlc ;channel 1 for control-C
xwd 2,timint ;channel 2 for timer interrupts
Levtab: exp intblk,intblk+1,intblk+2
Subttl Priority Interrupt System routines
;Routine to initialize the pi system
Inipi: movei a,.fhslf ;init levtab and chntab
move b,[levtab,,chntab]
sir%
movei a,.fhslf ;turn on desired channels
movx b,1B0!1B1 ;channels 0 and 1
aic%
movei a,.fhslf ;enable interrupt system
eir%
movei a,.fhjob ;job code
rtiw%
movem b,intmsk ;save mask
movx b,1B3 ;control-C
stiw%
erjmp .+1 ;ignore errors
move a,[3,,0] ;enable for control-c
ati% ;to channel zero
erjmp .+1 ;ignore errors
movei a,.cttrm ;this tty
rfcoc% ;read our coc words
dmovem b,ccoc ;save them
dmove b,[252525,,313125 ;all codes to ^ format except crlf
252525,,252525]
sfcoc% ;set coc words
ret ;done
;Routine to disable the pi system
Dispi: movei a,.fhslf ;disable the pi system
dir%
movei a,.fhjob ;this job
move b,intmsk ;interrupt mask
stiw% ;reset terminal interrupt mask
erjmp .+1
movei a,.fhslf ;disable all channels
movei b,0
aic%
movei a,.cttrm ;this terminal
dmove b,ccoc ;get old ccoc words
sfcoc% ;set them back
ret ;done
Subttl Interrupt processing routines
;Here to intercept a ^C
Ctrlc: push p,a ;save acs
push p,b
push p,c
call clsprt ;close the port
call dispi ;and clear pi system
haltf% ;and exit
;If continued..
call inipi ;set up pi
call opnprt ;open port again
pop p,c ;restore acs
pop p,b
pop p,a
debrk% ;dismiss the interrupt
;Here for a timer interrupt
Timint: push p,a ;save an ac
hrrz a,intblk+1 ;get interrupt pc from location two
caie a,intpc ;are we at interrupt pc?
ifskp. ;yes
movx a,1B5 ;user mode bit
iorm a,intblk+1 ;set user mode to return
endif.
pop p,a
debrk% ;and dismiss
Subttl Open and close port for I/O
Opnprt:
;(30) movei a,port ;get port to use
;(30) asnd% ;try to assign it
;(30) dblerr (<Can't assign system I/O port>,EXIT)
movx a,gj%sht ;now get jfn
hrroi b,aport ;ascii port name
gtjfn%
dblerr (<Can't get jfn on system I/O port>,EXIT)
movem a,p1 ;store jfn
movx b,fld(10,of%bsz)!of%rd!of%wr
openf% ;open the jfn
dblerr (<Can't open the I/O port>,EXIT)
rfmod% ;get jfn mode word
txz b,tt%pgm ;disable ^S/^Q mode
stpar% ;set mode
erjmp .+1
skipn loging ;are we logging?
ifskp. ;yes
movx a,gj%sht!gj%fou ;new generation
bpm b,syslog ;log file to use
gtjfn%
erjmp r ;can't
movx b,fld(7,of%bsz)!of%wr ;writing
openf% ;open it
erjmp r ;can't
movem a,logjfn ;save jfn
setjfn (a) ;set this print jfn
flgon f.log ;set flag
endif.
ret ;done
;Here to close the port and the I/O jfn
Clsprt: move a,p1 ;get tty jfn
rfmod% ;get jfn mode word
txo b,tt%pgm ;enable ^S/^Q mode
stpar% ;set mode
erjmp .+1
move a,p1 ;get jfn
txo a,cz%abt ;abort close
closf% ;do it
erjmp .+1 ;ignore errors
;(30) movei a,port ;default port
;(30) reld% ;deassign it
;(30) erjmp .+1 ;ignore errors
move a,logjfn ;get logging jfn
skpoff f.log ;open?
closf% ;yes, close it
jfcl ;ignore errors
ret ;done
;Here to clear the port I/O line after an error
Clrprt: move a,p1 ;get i/o port
cfibf% ;clear input buffer
erjmp .+1 ;ignore errors
move a,p1 ;just in case
cfobf% ;clear output buffer
erjmp .+1 ;just in case
movei a,^D1000 ;one second
disms% ;pause
ret ;and return
Subttl Start of main program
Xmit: reset%
setz f, ;flags
stack stak.. ;stack
movei a,.fhslf ;set this fork's capabilities
rpcap% ;read them first
txnn c,sc%whl!sc%opr ;must be able to set whoper
noerr (<? Insufficient capabilities to run program>,EXIT)
call inipi ;set interrupts
movei a,.rsini ;get our rescan buffer
rscan%
erjmp .+1
movei a,.rscnt ;now get count
rscan% ;do it
setz a, ;none to read
jumpe a,setprt ;nothing to rescan, proceed
Xmi.a: pbin% ;now look for switch
Xmi.b: cain a,12 ;end of line?
jrst setprt ;yes, proceed
caie a,"/" ;switch?
jrst xmi.a ;nope
pbin% ;get next
andi a,137 ;turn off upper case
cain a,"D" ;debug?
flgon f.dbug ;yes
cain a,"L" ;logging?
setom loging ;yes, set it
cain a,"S" ;start with send?
flgon f.send ;yes
jrst xmi.b ;keep looping
;Set up the port
Setprt: call opnprt ;open the port
seto p2, ;initialize to no files
;Main processing loop
clrsks f.send ;skip getpkt if /S specified
Main: call getpkt ;await incoming packets
clrskp f.abrt ;aborting?
jrst main ;yes, retry
call chkfil ;check for incoming files
jrst main ;do it forever
;Routine to clear open files
Clrfil: skipg a,p2 ;any open files?
ret ;nope
txo a,cz%abt ;abort close
closf% ;close the file
erjmp .+1 ;ignoring errors
ret
Subttl Getpkt - Check for incoming packets
;First level of processing -- wait for incoming characters for up to five
;minutes before returning.
Getpkt: movei b,delay ;first delay
call inpack ;input a packet
jrst @disp1(p3) ;dispatch to proper routine
;Dispatch table
Disp1: exp r ;invalid packet
exp r ;ack
exp r ;nak
exp r ;cancel
abort <Received Data packet without init>
abort <Received EOF packet without init>
exp p.sof ;start of file
Subttl Inpack - routine to check and valididate incoming packets
;We check type, contents and checksum before returning a valid packet code.
; Packets are returned in PACKET, code in P3, count in P4.
; Call this routine with timeout period in B.
Inpack: setzb p3,t2 ;assume bad packet code
move a,[.fhslf,,.timel] ;elapsed time
movei c,1 ;channel 1
timer% ;set interval timer
dblerr (<Can't set timer interrupt>,EXIT)
;Read in a line
move a,p1 ;input jfn
move b,[point 8,packet] ;pointer
movei c,maxpkt*2 ;maximum size
movei d,eop ;end of packet character
sin% ;read it
;INTPC is sacred... the timer interrupt trap looks for the PC set to
; this location and continues the JSYS if found there. This makes the
; SIN return even if not completed.
Intpc: jfcl ;wait here
move a,[.fhslf,,.timal] ;remove all requests
timer% ;cancel
erjmp .+1 ;ignore errors
;Analyze the line read in
cain c,maxpkt*2 ;anything happen?
ret ;nope
idpb d,b ;make sure packet ends with an eop
move t1,[point 8,packet] ;load packet pointer
move t4,t1 ;copy pointer
;Print data if appropriate
ifon. f.dbug ;debugging?
typncr <
Incoming: > ;type prompt
movei a,.priou ;output
movx c,no%lfl!fld(4,no%col)!10 ;how to type it
move t3,[point 8,packet] ;source
ildb b,t3 ;get a byte
nout% ;type it
erjmp .+1
caie b,eop ;end?
jrst .-4 ;nope, loop
endif.
;Find a sop character
Inpk.a: ildb b,t1 ;get char
cain b,eop ;end of packet?
jrst inpk.e ;error
caie b,sop ;start of packet?
jrst inpk.a ;nope, keep looking
idpb b,t4 ;redeposit
;Here if we have a packet start. Get code character
ildb b,t1 ;next
idpb b,t4 ;redeposit
move t2,b ;copy into checksum
subi b,100 ;make into an offset
jumple b,inpk.e ;return if too low
caile b,sof ;or if too high
jrst inpk.e ;error
;Get the count of remaining characters
ildb t3,t1 ;count of characters remaining
idpb t3,t4 ;redeposit
cail t3,240 ;value offset?
subi t3,240 ;yes, make true value
jumpl t3,inpk.e ;check for too small
caile t3,maxpkt ;check for too large
jrst inpk.e ;error
move p4,t3 ;copy the count for later use
add t2,t3 ;add into checksum
sojl t3,inpk.c ;count down
ildb a,t1 ;get first data character
idpb a,t4 ;deposit it
add t2,a ;add to checksum
movem a,dat1 ;and store it
;Loop checksuming the data
Inpk.b: sojl t3,inpk.c ;count down
ildb a,t1 ;get a character
add t2,a ;add it in
caie a,quote ;quoted?
ifskp. ;yes
ildb a,t1 ;get next character
add t2,a ;add to checksum
subi a,40 ;remove offset
soj t3, ;count down
soj p4, ;also change permanent count
endif.
idpb a,t4 ;replace in new position
jrst inpk.b ;and loop
;Now check the checksum
Inpk.c: andi t2,177 ;reduce to seven bits
caige t2,40 ;printable?
addi t2,240 ;no, make it so
ildb a,t1 ;get checksum
came a,t2 ;match?
jrst inpk.e ;error
;Finally, the EOP character should follow
ildb a,t1 ;get last char
caie a,eop
jrst inpk.e ;error
move p3,b ;copy the code
ifon. f.dbug ;debugging?
type < (good)>
endif.
ret ;return success
Inpk.e: ifon. f.dbug ;debugging?
type < (bad)>
endif.
ret ;return failure
Subttl Ack, Nak and Can routines
P.Ack: aos numack ;bump ack number
movei p3,"A" ;packet code
P.All: movei p4,1 ;one data
call pinit ;packet init
move a,code ;get packet code
idpb a,t1 ;store the packet code
add a,chksum ;add in
andi a,177 ;make seven bits
caige a,40 ;printable?
addi a,240 ;no, convert it
idpb a,t1 ;store it
movei a,eop ;end of packet
idpb a,t1 ;store it
call outsnd ;send it out
ret ;and return
;Nak routine -- called as a response to anything that you
; don't understand.
P.Nak: aos numnak ;bump nak count
movei p3,"B" ;packet code
setom code ;no special code for nak
jrst p.all ;send it
;Cancel routine -- Called to send an abort packet across the line.
P.Can: call clrfil ;close the file
P.Can2: movei p3,"C" ;packet code
setom code ;no special code for can
call p.all ;send it
skpoff f.log ;logging?
call endf.a ;yes, close the log file
time% ;get a random number
andi a,1777 ;10 bits
lsh a,4 ;shift to range of up to 16 seconds
disms% ;random wait
flgon f.abrt ;aborting...
ret ;done
Subttl Packet control routines
;Pinit routine -- prepare an outgoing packet
; Leaves T1 set up as a byte pointer
Pinit: move t1,[point 8,outpkt] ;point to packet area
movei a,sop ;packet start
idpb a,t1
idpb p3,t1 ;deposit packet code
movem p3,chksum ;start the checksum
move a,p4 ;count of data
addm a,chksum ;add to checksum
caige a,40 ;printable?
addi a,240 ;no, make it so
idpb a,t1 ;add it to packet
ret ;done
;Outsnd routine -- send the packet
Outsnd: move a,p1 ;I/O jfn
move b,[point 8,outpkt] ;pointer to data
movei c,maxpkt ;maximum size
movei d,eop ;end of packet
sout% ;send it
ifon. f.dbug ;debugging?
typncr <
Outgoing: > ;tell user
movei a,.priou ;output
movei a,.priou ;output
movx c,no%lfl!fld(4,no%col)!10 ;how to type it
move t3,[point 8,outpkt] ;source
ildb b,t3 ;get a byte
nout% ;type it
erjmp .+1
caie b,eop ;end?
jrst .-4 ;nope, loop
type ;crlf
endif.
ret ;done
Subttl File receiving routine
;This routine is called for a start of file packet. Open a file with the
; proper name and then await the arrival of data packets.
P.Sof: move a,[filnam,,filnam+1] ;set up to blt zeroes
setzm filnam ;clear first word
blt a,filnam+strlen ;through writer string
bpl a,<INBOX:> ;source
move b,[point 7,filnam] ;destination
movei c,6 ;count
ildb d,a ;get a byte
idpb d,b ;deposit it
sojg c,.-2 ;loop
move a,[point 8,packet+1] ;source
sosg c,p4 ;count (minus bytesize char)
abort <Received inadequately sized data packet>
Psof1: ildb d,a ;get a byte
cain d,"/" ;name/writer separator?
skipa b,[point 7,writer] ;yes, write to new location
idpb d,b ;deposit it
sojg c,psof1 ;loop
;Open a file
movx a,gj%sht!gj%fou ;new file
hrroi b,filnam ;name
gtjfn% ;get jfn
erjmp [skpoff f.log ;logging?
print asc<%C%P Unable to GTJFN incoming file -- %E%C>
jrst p.can2] ;cancel
movem a,p2 ;store jfn
skpoff f.log ;logging?
print a,asc<%CReceiving file %J at %D...%C> ;yes
move b,dat1 ;get the byte size
lsh b,^d30 ;shift into proper place
txo b,of%wr ;write the file
openf% ;open it
jabort <Can't open incoming file>
hrli a,.sflwr ;set name of last writer
hrroi b,writer ;string
skipe writer ;anything there?
sfust% ;yes, set string
setzm numack ;clear acks and naks
setzm numnak
;Ack the sof packet
movei a,"F" ;file init
movem a,code ;store it
call p.ack ;send a response
setzm pktnum ;initialize packet number
jrst datpak ;and get first packet
Subttl Incoming data packet handling
Datpak: movei t4,maxnak ;maximum number of naks
movem t4,nakcnt ;store them
jrst dtp.a1 ;skip countdown
Datp.a: sosg nakcnt ;count down
jrst nakout ;reached the limit
Dtp.a1: movei b,dwait ;data wait
call inpack ;get a packet
jrst @disp2(p3) ;dispatch on answer
;Good response, process incoming data
Datp.b: move a,dat1 ;get packet number
movem a,code ;store as ack/nak code
cail a,240 ;value offset?
subi a,240 ;yes, make true value
move b,pktnum ;get packet number
camge a,b ;compare packet numbers
jrst datpc1 ;obsolete, ack it
camg a,b ;too large this time?
jrst dtp.b1 ;nope, continue
jumpe b,datpc1 ;catch obsolete during 128-0 wrap
skpon f.log ;logging?
jrst p.can ;nope, just cancel
print b,asc<%P Expecting packet %N but received packet >
print a,asc<%N%C> ;show discrepancy
jrst p.can ;now cancel
;Right packet number, output contents
Dtp.b1: aos t3,pktnum ;bump packet count
andi t3,177 ;make 7-bit only
movem t3,pktnum ;restore
sosg t1,p4 ;get count
jrst datpc2 ;no data
movn c,t1 ;get negative count
move b,[point 8,packet+1] ;point to data
move a,p2 ;get file jfn
sout% ;output the data
jrst datpc2 ;done
;Here to ack and get next
Datpc1: call clrprt ;clear the line
call p.ack ;ack obsolete packet
jrst datp.a ;but count it with naks
Datpc2: call p.ack ;ack it
jrst datpak ;and get next
;End of file and error handling
Datp.d: move b,pktnum ;get number
move a,dat1 ;get packet number
movem a,code ;save code
cail a,240 ;value offset?
subi a,240 ;yes, remove offset added before
came a,b ;compare packet numbers
abort <Skipped an incoming packet before EOF received>
move a,p2 ;get file jfn
closf% ;close the file
jabort <Can't close incoming file>
skpoff f.log ;logging?
call endfil ;yes
setz p2, ;no file
call p.ack ;ack the packet
jrst getpkt ;try next incoming file
;Nak handling
Datp.e: call clrprt ;clear the line
call p.nak ;nak it
jrst datp.a ;and try again
;Too many naks
Nakout: abort <Sent or received too many naks>
;Dispatch table
Disp2: exp datp.e ;illegal, nak
exp datp.e ;ack
exp datp.e ;nak
gabort <Received CAN while expecting data packet>
exp datp.b ;data packet
exp datp.d ;end of file
abort <Received SOF while expecting data packet>
Subttl Chkfil - Send outgoing files
;Loop looking for files in OUTBOX: and sending them over the line.
; If the line is inactive, wait here forever, periodically sending SOF
; packets, until the other line activates.
Chkfil: movx a,gj%old!gj%sht!gj%ifg!.gjall ;find *.*.*
bpm b,sysbox ;outbox: or vaxbox:
gtjfn% ;get first in list
erjmp r ;none, return
;Here on each file
Opnfil: hrrzm a,p2 ;save the individual jfn
movei p3,"F" ;file init
setz p4, ;count filled in later
call pinit ;init a packet
move a,p2 ;get jfn
move b,[1,,.fbbyv] ;word containing byte size
movei c,t2 ;where to store size
gtfdb% ;get the word
ldb t1,[point 6,t2,11] ;get size
caie t1,7 ;if it isn't seven,
cain t1,10 ;or eight,
caia ;(one or the other)
movei t1,6 ;then we'll make it six
move a,p2 ;get jfn
movx b,of%rd ;read mode
dpb t1,[point 6,b,5] ;deposit byte size
openf% ;open it
erjmp delfil ;open error, delete and try again
skpoff f.log ;logging?
print a,asc<%CSending file %J at %D...%C>
setzm numack ;clear acks and naks
setzm numnak
;Calculate the size of the file name and writer string and write them out
hrroi a,filnam ;destination
move b,p2 ;jfn
movx c,js%nam!js%typ!js%paf ;name and type only
jfns% ;copy it
movei d,1 ;initialize counter
bpm a,filnam ;start
move b,[point 8,outpkt+1] ;destination
call copchk ;copy name with checksumming
;See if last writer string is required
IFN LWrite,<
push p,b ;save pointer
move a,p2 ;get jfn
hrli a,.gflwr ;last writer
hrroi b,filnam ;reuse string location
gfust% ;get the string
pop p,b ;restore destination
bpm a,filnam ;where it starts
movei c,"/" ;name/writer separator
addm c,chksum ;add to checksum
idpb c,b ;into string
aoj d, ;count it
call copchk ;now copy the writer string
>;End IFN LWrite
;Done with name
Chkf.b: move a,chksum ;get checksum
add a,d ;add in data count
add a,t1 ;also add size field
andi a,177 ;make seven bits
caige a,40 ;printable?
addi a,240 ;no, make it so
idpb a,b ;deposit it
movei a,eop ;end of packet
idpb a,b ;add that too
caige d,40 ;printable count?
addi d,240 ;no, make it so
dpb d,[point 8,outpkt,23] ;deposit in count field
dpb t1,[point 8,outpkt,31] ;follow with size field
setom pktnum ;start with packet -1
flgoff f.ieof ;no end of file
;Await response, keep trying forever
Filsnd: call outsnd ;send it off
movei b,dsend ;how long to wait
call inpack ;get a packet
jrst @disp3(p3) ;dispatch
;Check response to see if it's right
Rspchk: move a,dat1 ;get packet number
caie a,"F" ;file init?
jrst filsnd ;nope, try again
jrst sndpak ;yes, proceed
;Copchk -- copy string from (a) to (b) with checksumming
Copchk: ildb c,a ;get a character
jumpe c,r ;no more
addm c,chksum ;add to checksum
idpb c,b ;deposit it
aoja d,copchk ;loop until done
;Dispatch table
Disp3: exp filsnd ;garbage, try again
exp rspchk ;ack, success
exp filsnd ;nak, try again
gabort <Received CAN after sending SOF packet>
abort <Received data packet after sending SOF packet>
abort <Received EOF packet after sending SOF packet>
abort <Received SOF packet after sending SOF packet>
Subttl Sndpak - loop sending data packets
;The file init has been acknowledged, send the data
Sndpak: aos t3,pktnum ;next packet
andi t3,177 ;make it 7-bits
movem t3,pktnum ;restore
move a,p2 ;file jfn
move b,[point 8,data] ;data pointer
movni c,maxsnd ;data to read - overhead bytes
sin% ;read data in
erjmp sndp.b ;probably eof with data
;Send some data
Sndp.b: addi c,maxsnd ;find number read
skipg t2,c ;test and copy number
jrst sndp.g ;must be eof, nothing read
movei p3,"D" ;data packet
setz p4, ;initialize count to zero
call pinit ;initialize packet
move a,pktnum ;get packet number
caige a,40 ;printable?
addi a,240 ;no, make it so
movem a,code ;save to check ack code later
addm a,chksum ;add to checksum
idpb a,t1 ;put into outgoing packet
move b,[point 8,data] ;pointer to source
;Data loop
Sndp.c: ildb a,b ;get data byte
ldb d,[point 7,a,35] ;get only seven bits of it
caie a,quote ;a quote character?
caig d,eop ;or end of packet char?
caia
jrst sndpc1 ;nope, continue
movei d,quote ;get quote char
addm d,chksum ;add to checksum
idpb d,t1 ;deposit it
addi a,40 ;add offset
aoj t2, ;and bump the character count
Sndpc1: idpb a,t1 ;store the character
addm a,chksum ;and checksum it
sojg c,sndp.c ;loop for all characters
;Now do the checksum
aos a,t2 ;copy count and bump it
caige t2,40 ;printable?
addi t2,240 ;no, make it so
dpb t2,[point 8,outpkt,23] ;deposit it
add a,chksum ;now get checksum and add in count
andi a,177 ;make seven bits
caige a,40 ;printable?
addi a,240 ;no, make it so
idpb a,t1 ;store in the packet
movei a,eop ;end it
idpb a,t1
;Send the packet
Sndp.d: movei t4,maxnak ;get maximum naks
movem t4,nakcnt ;store them
jrst sdp.e1 ;and hop
Sndp.e: aos numnak ;got a nak
call clrprt ;clear the line
sosg nakcnt ;count down naks
jrst nakout ;too many
Sdp.e1: call outsnd ;send the packet
movei b,dwait ;data wait
call inpack ;get a packet
jrst @disp4(p3) ;dispatch on answer
;Here when deciding whether we're done or not
Sndp.f: move a,dat1 ;get packet number
came a,code ;match the code?
jrst sndp.e ;nope, try again
aos numack ;got an ack
skpon f.ieof ;input end of file?
jrst sndpak ;no, do next
;Now close, delete and expunge the file
move a,p2 ;get jfn
txo a,co%nrj ;don't release it
closf% ;close the file
erjmp .+1 ;ignore errors
skpoff f.log ;logging?
call endfil ;yes
;Alternate entry to delete file if we can't open it
Delfil: move a,p2 ;get jfn
txo a,df%exp ;expunge and keep jfn
delf% ;delete the file
erjmp [move a,p2 ;try again
delf% ;delete only
jfcl ;ignore errors
jrst .+1] ;and return in-line
jrst chkfil ;look for next file
;Here when file is done
Sndp.g: movei p3,"E" ;end file
movei p4,1 ;one data
call pinit ;set it up
move a,pktnum ;install packet number
andi a,177 ;make seven bits
caige a,40 ;printable?
addi a,240 ;no, make it so
movem a,code ;store code
addm a,chksum ;add to checksum
idpb a,t1 ;deposit it
move a,chksum ;get checksum
andi a,177 ;make seven bits
caige a,40 ;printable?
addi a,240 ;no, make it so
idpb a,t1 ;tack that on
movei a,eop ;end of packet
idpb a,t1 ;tack it on
flgon f.ieof ;set eof
jrst sndp.d ;and send it away
;Dispatch table
Disp4: exp sndp.e ;illegal, retry
exp sndp.f ;ack, do the next unless eof
exp sndp.e ;nak, try again
gabort <Received CAN after sending data packets>
abort <Received data packet after sending data packet>
abort <Received EOF packet after sending data packet>
abort <Received SOF packet after sending data packet>
;Endfil -- print ending information
Endfil: move a,numack ;number of acks
print a,asc<...Finished file at %D with %N acks and >
move a,numnak ;number of naks
print a,asc<%N naks%C>
Endf.a: move a,logjfn ;get logging file
txo a,co%nrj ;don't release jfn
closf% ;close it
ret ;on error
move a,logjfn ;get jfn again
movx b,fld(7,of%bsz)!of%app ;append mode
openf% ;open it
flgoff f.log ;can't, turn off logging
ret ;done
;End of program
end xmit