.TITLE MOV - binary transfer companion to TALK .ENABL LC ; ; PROGRAM MOV ; ; ; Written By: Mark Ransom, Datamap, Inc. ; ; Date Written: August 1, 1984 ; ; MOV is a companion program to the TALK program for binary file ; transfers. It runs on the remote PDP-11, handling all handshaking ; and file conversion. It is automatically invoked by the TALK ; program during a binary file transfer, and must be installed in ; the remote system as the MOV command. ; ; Binary transfers occur by sending out ASCII records and receiving ; back a handshake character from the destination. An ASCII record ; is generated by taking each data word and converting it to three ; characters, and adding a checksum to the end of the record. A ; file is transferred by first sending out a record with the file ; attributes, then sending each virtual block of the file in ; multiple records. As each record is received, a handshake character ; of "+" is sent if the checksum was good, or "-" if the checksum ; was bad. If a bad checksum is indicated, the record will be ; resent. The handshake characters are displayed on the screen to ; indicate the transfer progress, while the data words are suppressed. .PAGE .MCALL FCSMC$ FCSMC$ .MCALL GCMLB$,GCML$,CSI$,CSI$SW,CSI$ND,CSI$1,CSI$2 .MCALL ALUN$S,QIOW$S,EXIT$S CML: GCMLB$ 0,MOV,,5 CSI$ .EVEN CSI: .BLKB C.SIZE .EVEN IN = 1 ;mask for /IN switch OUT = 2 ;mask for /OUT switch SW: CSI$SW IN,IN,MASK CSI$SW OUT,OUT,MASK CSI$ND MASK: .WORD 0 FDB: FDBDF$ FDRC$A FD.RWM FDBK$A BLKBUF,512.,,1,IOSTAT FDOP$A 1,CSI+C.DSDS,DFNB DFNB: NMBLK$ DAT,DAT,,SY,0 FSRSZ$ 0 IOSTAT: .BLKW 2 ;QIO I/O status BLKBUF: .BLKB 512.+2 ;disk block buffer BUF: .BLKB 80. ;terminal I/O buffer BLKPTR: .WORD 0 ;pointer to current word in block buffer BUFLEN: .WORD 0 ;number of bytes currently in BUF CHAR: .BLKW 1 ;Input/Output handshake character CKSUM: .WORD 0 ;record checksum SIZE: .BLKW 2 ;final size of file FFBY: .WORD 0 ;F.FFBY - last good byte of file EFBK: .WORD 0,0 ;F.EFBK - last good block of file .PAGE MOVE:: FINIT$ ALUN$S #5,#"TI,#0 ;assign LUN 5 to terminal GCML$ #CML ;get command line BCS QUIT ;if error CSI$1 #CSI,CML+G.CMLD+2,CML+G.CMLD ;parse BCS QUIT ;if error CSI$2 #CSI,OUTPUT,#SW ;parse some more BCS QUIT ;if error BIT #IN,MASK ;check for /IN BNE MOVIN ;if /IN, move file into remote PDP BIT #OUT,MASK ;check for /OUT BEQ QUIT ;if not /OUT, no switch, so error JMP MOVOUT ;otherwise, move file out to TALK QUIT: EXIT$S .PAGE ; MOVIN - MOVE FILE IN FROM TALK. MOVIN: CLR BLKPTR ;clear disk block pointer MOVB #' ,CHAR QIOW$S #IO.WVB,#5,#5,,,,<#CHAR,#1,#40> ;write blank line to term MOVB #'+,CHAR ;send handshake to get ball rolling 10$: QIOW$S #IO.RPR!TF.RNE,#5,#5,,#IOSTAT,,<#BUF,#BUFLEN,,#CHAR,#1,#0> BCS 15$ ;if QIO error CMPB #IS.SUC,IOSTAT BEQ 20$ ;if no QIO error, process record 15$: MOV FFBY,FDB+F.FFBY ;assume EOF, set F.FFBY to proper value MOV EFBK,FDB+F.EFBK ;set F.EFBK MOV EFBK+2,FDB+F.EFBK+2 CLOSE$ #FDB ;close the output file JMP QUIT ;exit 20$: CALL CNVBIN ;convert input record from ASCII MOVB #'-,CHAR ;assume checksum is bad TST CKSUM ;test checksum BNE 10$ ;non-zero checksum is bad MOVB #'+,CHAR ;checksum was good, change handshake char MOV BLKPTR,R0 ;get disk block pointer BNE 60$ ;if non-zero, file has been initialized MOV #BLKBUF,BLKPTR ;otherwise, initialize pointer CALL OPNWRT ;... and open output file BCC 10$ ;if no error, read next record JMP QUIT ;otherwise, exit 60$: CMP R0,#BLKBUF+512. ;check to see if disk block buffer is full BLO 10$ ;if not full, read next record MOV #BLKBUF,BLKPTR ;otherwise, initialize block pointer WRITE$ #FDB ;and write virtual block to output file BCS 70$ ;if error, exit WAIT$ R0 ;wait for write complete BCC 10$ ;go back for next record 70$: JMP QUIT ;exit .PAGE ; MOVOUT - MOVE FILE OUT TO TALK. MOVOUT: OPEN$R #FDB ;open input file BCC 10$ ;if no error JMP QUIT ;exit 10$: MOV #BLKBUF+512.-16.,R1 ;put file attributes at end MOV R1,BLKPTR ;... of block buffer MOVB F.RTYP(R0),(R1)+ MOVB F.RATT(R0),(R1)+ MOV F.RSIZ(R0),(R1)+ MOV F.FFBY(R0),(R1)+ MOV F.HIBK(R0),SIZE ;get size of input file MOV F.HIBK+2(R0),SIZE+2 CMP F.EFBK(R0),SIZE ;compare to last good block of file BHI 16$ ;if last block higher, ok BLO 15$ ;if last block lower, use it for size CMP F.EFBK+2(R0),SIZE+2 ;check lower word BHIS 16$ ;if last block higher or same, ok 15$: MOV F.EFBK(R0),SIZE ;otherwise, use last block number MOV F.EFBK+2(R0),SIZE+2 ;... for file size 16$: MOV SIZE,(R1)+ ;save size as attribute MOV SIZE+2,(R1)+ MOV F.EFBK(R0),(R1)+ ;save ending block attribute MOV F.EFBK+2(R0),(R1)+ CLR (R1)+ ;reserved for contiguous file flag 20$: CALL TOBIN ;convert a record to ASCII 30$: CLRB CHAR ;clear handshake character ;write record, wait for handshake char QIOW$S #IO.RPR!TF.RNE,#5,#5,,,,<#CHAR,#1,,#BUF,BUFLEN,#40> BCC 40$ ;if no QIO error JMP QUIT ;exit 40$: CMPB #'-,CHAR ;check for bad handshake BEQ 30$ ;bad checksum, resend record CMPB #'+,CHAR ;check for good handshake BEQ 50$ ;good handshake, send next record BR 30$ ;unrecognizable handshake, assume bad 50$: CMP BLKPTR,#BLKBUF+512. ;see if anything is left in buffer BLO 20$ ;if buffer isn't empty, send some TST SIZE ;check block output count BNE 55$ ;if not zero, file isn't sent yet TST SIZE+2 ;check block output count BNE 55$ ;if not zero, file isn't sent yet JMP QUIT ;block count zero, file sent, exit 55$: READ$ #FDB ;read next virtual block BCS 60$ ;if error WAIT$ #FDB BCC 70$ ;if no error 60$: JMP QUIT ;exit 70$: MOV #BLKBUF,BLKPTR ;initialize block buffer pointer ADD #-1,SIZE+2 ;decrement block count ADC SIZE BR 20$ ;output a record .PAGE ; TOBIN - CONVERT INPUT RECORD TO BINARY FOR SENDING. TOBIN: MOV BLKPTR,R0 ;get disk block pointer MOV #BUF,R1 ;start record pointer MOV #-1,CKSUM ;initialize checksum 10$: MOV (R0)+,R2 ;get next word from buffer SUB R2,CKSUM ;add to checksum CALL BINWRD ;convert word to ASCII CMP R0,#BLKBUF+512. ;check pointer for end of buffer BHIS 20$ ;if end of buffer CMP R1,#BUF+70. ;check record pointer for end of record BLO 10$ ;if not end of record, loop 20$: MOV R0,BLKPTR ;update disk block pointer MOV CKSUM,R2 ;add checksum to end of record CALL BINWRD ;... in ASCII, of course SUB #BUF,R1 ;get output record length MOV R1,BUFLEN ;save it RETURN ; BINWRD - CONVERT SINGLE WORD TO BINARY FOR SENDING BINWRD: MOV R2,R3 ;get top 5 bits of word SWAB R3 ASR R3 ASR R3 ASR R3 BIC #177740,R3 ADD #77,R3 ;add offset of '?' MOVB R3,(R1)+ ;move to record buffer MOV R2,R3 ;get middle 6 bits of word ASR R3 ASR R3 ASR R3 ASR R3 ASR R3 BIC #177700,R3 ADD #77,R3 ;add offset of '?' MOVB R3,(R1)+ ;move to record buffer BIC #177740,R2 ;get bottom 5 bits of word ADD #77,R2 ;add offset of '?' MOVB R2,(R1)+ ;move to record buffer RETURN .PAGE ; OPNWRT - OPEN FILE FOR WRITING. OPNWRT: MOV #FDB,R0 ;get FDB address of file to open for write MOV #BLKBUF,R3 ;get address of file attributes MOVB (R3)+,F.RTYP(R0) ;move attributes to FDB MOVB (R3)+,F.RATT(R0) MOV (R3)+,F.RSIZ(R0) MOV (R3)+,FFBY ;save F.FFBY for after writing is complete MOV (R3)+,R2 ;get file size (upper word) SWAB R2 ;put in upper part of byte BIC #377,R2 ;... for call to .EXTND MOV (R3)+,R1 ;get file size (lower word) MOV (R3)+,EFBK ;save F.EFBK for after writing is complete MOV (R3)+,EFBK+2 TSTB (R3) ;check for contiguous file BEQ 30$ ;if not contiguous BIS #205,R2 ;set contiguous attribute for .EXTND 30$: OPEN$W R0 ;open output file BCS 50$ ;if error CALL .EXTND ;extend file to final size BCC 50$ ;if no error CALL .DLFNB ;error extending file, delete it SEC ;set carry to indicate error 50$: RETURN .PAGE ; CNVBIN - CONVERT OUTPUT RECORD FROM HEX. CNVBIN: MOV #BUF,R0 ;start record pointer MOV BLKPTR,R1 ;get disk buffer pointer BNE 5$ ;if non-zero, file is open MOV #BLKBUF,R1 ;otherwise, copy attributes ;... to beginning of buffer 5$: MOV IOSTAT+2,R2 ;get length of input record MOV #1,CKSUM ;initialize checksum 10$: MOVB (R0)+,R3 ;get input character SUB #77,R3 ;subtract '?' offset SWAB R3 ;move to upper 5 bits of word ASL R3 ASL R3 ASL R3 BIC #003777,R3 MOVB (R0)+,R4 ;get next character SUB #77,R4 ;subtract '?' offset ASL R4 ;move to middle 6 bits of word ASL R4 ASL R4 ASL R4 ASL R4 BIC #174037,R4 BIS R4,R3 ;add to first 5 bits MOVB (R0)+,R4 ;get next character SUB #77,R4 ;subtract '?' offset BIC #177740,R4 ;get lower 5 bits BIS R4,R3 ;add to other 11 bits MOV R3,(R1)+ ;move final word to disk buffer ADD R3,CKSUM ;add word to checksum SUB #3,R2 ;subtract 3 characters from input rec length BGT 10$ ;if more characters left, loop TST -(R1) ;adjust pointer to take off input checksum TST BLKPTR ;check initial disk buffer pointer BEQ 20$ ;if zero, don't update pointer MOV R1,BLKPTR ;update disk buffer pointer 20$: RETURN .END MOVE