.TITLE UTILTY - RSXNET UTILITY ROUTINES .IDENT /02.7/ .ENABL LC ;+ ; ; Free software BY ; Project Software & Development, Inc. ; ; This software is furnished for free and may be used and copied as ; desired. This software or any other copies thereof may be provided ; or otherwise made available to any other person. No title to and ; ownership of the software is hereby transferred or allowed. ; ; The information in this software is subject to change without notice ; and should not be construed as a commitment by PROJECT SOFTWARE ; AND DEVELOPMENT, INC. ; ; PROJECT SOFTWARE assumes no responsibility for the use or reliability ; of this software on any equipment whatsoever. ; ; Project Software & Development, Inc. ; 14 Story St. ; Cambridge, Ma. 02138 ; 617-661-1444 ; ; ; Title: UTILTY ; Author: Robin Miller ; Date: April 16, 1982 ; ; Description: ; ; This module contains the routines to do the initial handshaking ; with the SNDRCV program, the routines to send and receive, and the ; routines to perform error checking and retransmission. ; ; The protocal being used is very primative and will be changed ; at at later time. The current goal is to be compatible with VAXNET. ; ; Modification History: ; ;- .ENABL AMA .NLIST BEX .MCALL QIO$S, WTSE$S, QIOW$S ; Local equates: BELL = 7 ; BELL TAB = 9. ; HORIZONTAL TAB LF = 10. ; LINE FEED CR = 13. ; CARRIAGE RETURN SPACE = 32. ; ASCII SPACE EOT == 4 ; END OF TRANSMISSION ENQ == 5 ; ENQUIRE ACK == 6 ; ACKNOWLEGMENT NAK == 21. ; NEGATIVE ACKNOWLEGMENT SYN == 22. ; SYNCHRONIZE BYTE CAN == 24. ; CANCEL TRANSMISSION EOF == 26. ; END OF FILE RLIMIT == 8. ; THE RETRY LIMIT ; Local storage: EXACT:: .WORD 0 ; EXACT MATCH FLAG <>0 = TRUE RETRY: .WORD 0 ; CURRENT RETRY LIMIT NRETRY::.WORD 0 ; DISABLE RETRYS FLAG <> 0 = TRUE TBUFF: .BLKB 16. ; TEMPORARY STORAGE ; ASCII messages: TOREM: .ASCII "TOREM" ; SEND FILE TO REMOTE TORSX: .ASCII "TOVAX" ; GET FILE FROM REMOTE INITER: .ASCII "*** Error initializing SNDRCV program on the remote. ***" .ASCII .ASCII "*** Did you remember to start the SNDRCV program ? ***" .ASCIZ EXCMSG: .ASCII "*** Retry limit exceeded, aborting transmission. ***" .ASCIZ .EVEN .SBTTL INIT - DO INITIAL HANDSHAKING WITH SNDRCV ;+ ; ; INIT - Do initial handshaking with the SNDRCV program. ; ; The routine checks the direction (GET or SEND), and sends the direction ; to the SNDRCV program. ; ; Inputs: ; None. ; ; Outputs: ; C bit clear/set = success/failure, ; ;- INIT:: CALL $SAVAL ; SAVE ALL REGISTERS CLR RETRY ; INIT RETRY COUNTER MOV #-1,NRETRY ; DISABLE NORMAL RETRYS MOV #TOREM,R2 ; PRESUME SEND MODE CMP MODE,#SEND ; ARE WE IN SEND MODE ? BEQ 10$ ; IF EQ, YES MOV #TORSX,R2 ; NO, MUST BE GET MODE ; Transmit the direction, and get / check response. 10$: MOV #5,R3 ; SET THE BYTE COUNT TST ABOFLG ; USER TYPE CTRL/C TO ABORT ? BNE 30$ ; IF NE, YES (FAILURE) CALL GETRES ; SEND AND GET RESPONSE CMPB CODE,#ENQ ; IS SNDRCV ENQUIRING US ? BEQ 10$ ; IF EQ, YES (RETRANSMIT) CMPB CODE,#NAK ; DID WE GET A NAK ? BNE 20$ ; IF NE, NO INC RETRY ; BUMP THE RETRY COUNTER CMP RETRY,#RLIMIT ; OVER THE LIMIT ? BLT 10$ ; IF LT, NO CALL WRTEXC ; WRITE EXCEEDED LIMIT BR 30$ ; AND SHOW FAILURE 20$: CMPB CODE,#ACK ; DID WE GET AN ACK ? BNE 30$ ; IF NE, NO CLC ; YES, SHOW SUCCESS RETURN ; We received an invalid response or retry limit exceeded. 30$: MOV #INITER,R4 ; INIT ERROR MESSAGE CALL WRITE ; WRITE IT SEC ; SHOW FAILURE RETURN .SBTTL GETRES - WRITE MESSAGE AND GET RESPONSE ;+ ; ; GETRES - Write message to remote and wait for a response. ; ; This routine is used when sending the remote the file name to ; GET/SEND and also when sending a file. Although checking could ; be done for the transmission mode, GETFIL does its own reading ; and writing to the remote instead of using this routine. ; ; Inputs: ; R2 = the message to write. ; R3 = the message byte count. ; ; Outputs: ; C bit clear / set = valid code / invalid code. ; CODE = the first byte received from the remote. ; ;- GETRES:: CALL $SAVAL ; SAVE ALL REGISTERS CLRB RBUFF ; ENSURE FIRST BYTE NULL TST NRETRY ; RETRYS DISABLED ? BNE 10$ ; IF NE, YES CLR RETRY ; INITIALIZE RETRY COUNTER 10$: CALL READIT ; POST A READ REQUEST BCS 45$ ; IF CS, READ FAILED CALL WRITIT ; NOW DO THE WRITE BCS 45$ ; IF CS, WRITE FAILED 15$: WTSE$S #REMOTE ; WAIT FOR THE READ TSTB RIOSB ; DID WE SUCCEED ? BPL 60$ ; IF PL, YES CMPB #IE.BCC,RIOSB ; FRAMING ERROR ? BNE 20$ ; IF NE, NO INC BCCERR ; YES, BUMP THE COUNT BR 50$ ; AND CHECK FOR RETRY 20$: CMPB #IE.DAO,RIOSB ; OVERRUN ERROR ? BNE 30$ ; IF NE, NO INC DAOERR ; YES, BUMP THE COUNT BR 50$ ; AND CHECK FOR RETRY 30$: CMPB #IE.VER,RIOSB ; VERTICAL PARITY ERROR ? BNE 40$ ; IF NE, NO INC VERERR ; YES, BUMP THE COUNT BR 50$ ; AND CHECK FOR RETRY 40$: CALL CHKRIO ; REPORT THE ERROR 45$: JMP 100$ ; AND RETURN FAILURE ; Retransmit the last buffer. 50$: TST NRETRY ; RETRYS DISABLED ? BNE 55$ ; IF NE, YES (RETURN) CALL REPERR ; REPORT THE ERROR INC RETRY ; BUMP THE RETRY COUNT CMP RETRY,#RLIMIT ; ARE WE AT THE LIMIT ? BLT 10$ ; IF LT, NO (TRY AGAIN) CALL WRTEXC ; EXCEEDED RETRY COUNT 55$: BR 100$ ; AND RETURN FAILURE ; We have a successful return. 60$: CMPB #IS.TMO,RIOSB ; DID THE READ TIMEOUT ? BNE 70$ ; IF NE, NO INC TMOCNT ; YES, BUMP THE COUNT BR 50$ ; RETRY ON TIMEOUT ; Check for valid responses. 70$: MOV #RBUFF,R0 ; POINT TO RECEIVE BUFFER CMPB #ACK,(R0) ; DID WE GET AN ACK ? BEQ 80$ ; IF EQ, YES CMPB #NAK,(R0) ; DID WE GET A NAK ? BEQ 80$ ; IF EQ, YES CMPB #ENQ,(R0) ; DID WE GET AN ENQ ? BEQ 80$ ; IF EQ, YES CMPB #CAN,(R0) ; DID WE GET A CAN ? BEQ 80$ ; IF EQ, YES CMPB #EOF,(R0) ; DID WE GET AN EOF ? BEQ 80$ ; IF EQ, YES CMPB #EOT,(R0) ; DID WE GET AN EOT ? BEQ 80$ ; IF EQ, YES ; Received an invalid control code. TST DEBFLG ; IS DEBUG FLAG ENABLED ? BEQ 75$ ; IF EQ, NO MOV R0,R4 ; COPY THE RECEIVE BUFFER MOV R4,R5 ; COPY IT ADD RIOSB+2,R5 ; POINT TO END OF RESPONSE CLRB (R5) ; SHOW END OF MESSAGE CALL WRITE ; WRITE IT TO THE TERMINAL CALL BLANK ; WRITE A BLANK LINE 75$: TST NRETRY ; RETRYS DISABLED ? BNE 100$ ; IF NE, YES CALL READIT ; POST A READ REQUEST CALL SENQ ; AND SEND AN ENQ BR 15$ ; WAIT FOR A RESPONSE ; Received a valid response, check for a message with it. 80$: CMP RIOSB+2,#1 ; DID WE GET A MESSAGE ? BEQ 85$ ; IF EQ, NO INC R0 ; POINT PAST CONTROL BYTE DEC RIOSB+2 ; NOW ADJUST THE BYTE COUNT CALL WRBUFF ; OUTPUT THE RECEIVE BUFFER 85$: CMPB #NAK,(R0) ; DID WE GET A NAK ? BNE 90$ ; IF NE, NO TST NRETRY ; ARE RETRYS DISABLED ? BNE 50$ ; IF NE, YES (DON'T COUNT) INC NAKCNT ; COUNT THE NAKS BR 50$ ; AND DO A RETRY 90$: MOVB (R0),CODE ; SAVE THE CODE RECEIVED CLC ; SHOW SUCCESS RETURN ; We get here if an invalid control code was received ; or retrys are disabled. 100$: MOV #RBUFF,R0 ; RECEIVED BUFFER ADDRESS MOVB (R0),CODE ; COPY THE CODE RECEIVED TST DEBFLG ; DEBUG OUTPUT TURNED ON ? BEQ 110$ ; IF EQ, NO CALL WRBUFF ; OUTPUT THE RECEIVE BUFFER 110$: SEC ; SHOW FAILURE RETURN .SBTTL WRBUFF - WRITE THE RECEIVED BUFFER ;+ ; ; WRBUFF - Write the received buffer to the terminal/logfile. ; ; Inputs: ; R0 = the received buffer address. ; ; Outputs: ; All registers are preserved. ; ;- WRBUFF:: CALL $SAVAL ; SAVE ALL REGISTERS MOV R0,R4 ; COPY THE RECEIVE BUFFER ADD RIOSB+2,R0 ; POINT TO END OF MESSAGE CLRB (R0) ; SHOW END OF MESSAGE CALL WRITE ; AND WRITE THE MESSAGE CALL BLANK ; WRITE A BLANK LINE RETURN .SBTTL READIT - READ A RESPONSE FROM THE REMOTE ;+ ; ; READIT - Read a response from the remote. ; ; This routine is used to issue a read QIO before a write is done to ; the SNDRCV. It is the responsiblity ot the calling routine to wait ; on the remote event flag to determine when the read completes. The ; read will timeout after 30 seconds which normally is an indication of ; a transmission error. The timeout on the read on the remote end is ; set to 3 minutes so we will timeout first and initiate recovery. ; ; Inputs: ; None ; ; Outputs: ; RBUFF = the response from the remote. ; RIOSB = the byte count of the response. ; ;- READIT:: QIO$S #IO.RTT!TF.TMO,#REMOTE,#REMOTE,,#RIOSB,,<#RBUFF,#FILSIZ,#3.,#TTABLE> BCC 10$ ; IF CC, SUCCESS CALL CHKDIR ; REPORT THE DIRECTIVE ERROR SEC ; SHOW FAILURE 10$: RETURN .SBTTL WRITIT - WRITE A MESSAGE TO THE REMOTE ;+ ; ; WRITIT - Write a message to the remote. ; ; This routine is called to write a message (or response) to SNDRCV. ; The write is not waited for since it is presumed a read will be ; done next to get the response. A carriage return is automatically ; appended to the buffer when it is written. ; ; Inputs: ; R2 = the buffer address. ; R3 = the byte count. ; ; Outputs: ; None. ; ;- WRITIT:: TST R3 ; IS THERE A BYTE COUNT BEQ 10$ ; IF EQ, NO (SEND ) QIO$S #IO.WAL!TF.CCO,#REMOTE,,,,, BR 20$ ; AND RETURN ... 10$: QIO$S #IO.WAL!TF.CCO,#REMOTE,,,,,<#CRLF,#1,#0> 20$: BCC 30$ ; IF CC, SUCCESS CALL CHKDIR ; REPORT THE DIRECTIVE ERROR SEC ; SHOW FAILURE 30$: RETURN .SBTTL CHKSUM - CALCULATE THE CHECKSUM ;+ ; ; CHKSUM - Calculate the checksum. ; ; Inputs: ; R4 = the buffer address. ; R5 = the buffer byte count. ; ; Outputs: ; R1 = the checksum. ; ; Registers R3 - R5 are preserved. ; ;- CHKSUM:: JSR R5,$SAVRG ; SAVE REGISTERS R3 - R5 CLR R1 ; INITIALIZE THE CHECKSUM 10$: DEC R5 ; DECREMENT THE BYTE COUNT BMI 20$ ; IF MI, ALL DONE MOVB (R4)+,R3 ; COPY THE NEXT BYTE BIC #^C377,R3 ; CLEAR POSSIBLE SIGN EXTEND ADD R3,R1 ; ACCUMULATE THE CHECKSUM BR 10$ ; AND DO THE NEXT BYTE 20$: BIC #^C777,R1 ; CLEAR THE HIGH BITS RETURN .SBTTL WRTEXC - WRITE EXCEEDED RETRY MESSAGE ;+ ; ; WRTEXC - Write exceeded retry limit message. ; ;- WRTEXC:: MOV #EXCMSG,R4 ; SET THE MESSAGE ADDRESS CALL WRITE ; AND WRITE IT RETURN .SBTTL ROUTINES TO SEND VARIOUS CODES TO THE REMOTE ;+ ; ; These routines are called to send a control code to SNDRCV. The ; control code is moved into location CODE and then WRITIT is called ; to send it to SNDRCV on the remote. ; ;- SACK:: MOV #ACK,CODE ; ACKNOWLEGMENT BR RSEND ; AND SEND IT SNAK:: MOV #NAK,CODE ; NEGATIVE ACKNOWLEGMENT INC NAKCNT ; COUNT THE NAK CALL REPERR ; REPORT THE ERROR BR RSEND ; AND SEND IT SSYN:: MOV #SYN,CODE ; SYNCHRONIZE BR WSEND ; AND SEND IT SENQ:: MOV #ENQ,CODE ; ENQUIRE BR RSEND ; AND SEND IT SEOF:: MOV #EOF,CODE ; END OF FILE BR WSEND ; AND SEND IT SEOT:: MOV #EOT,CODE ; END OF TRANSMISSION BR WSEND ; AND SEND IT SCAN:: MOV #CAN,CODE ; CANCEL THE TRANSMISSION RSEND:: ; SEND / RESEND CONTROL CODE JSR R2,$SAVVR ; SAVE REGISTERS R0 - R2 MOV #CODE,R2 ; SETUP THE BUFFER ADDRESS MOV #1,R3 ; AND THE BYTE COUNT CALL WRITIT ; NOW SEND THE CODE RETURN WSEND: ; WAIT FOR THE CODE SENT JSR R2,$SAVVR ; SAVE REGISTERS R0 - R2 MOV #CODE,R2 ; SETUP THE BUFFER ADDRESS MOV #1,R3 ; AND THE BYTE COUNT CALL GETRES ; SEND IT AND GET RESPONSE RETURN .SBTTL COMPAR - COMPARE STRING FOR ENTRY IN TABLE ;+ ; ; COMPAR - Compare string for entry in table. ; ; This routine searches for a string within a table and if found, ; passes back the address of the entry within the table. ; ; Inputs: ; R0 - Input string. ; R1 - Table address. ; R2 - Size of each entry in the table. ; ; Outputs: ; R5 - Offset into the table. ; ;- COMPAR:: CALL $SAVAL ; SAVE EM MOV R0,R3 ; ADDRESS OF THE INPUT STRING MOV R1,R4 ; ADDRESS OF THE TABLE 10$: TSTB (R3) ; AT END OF INPUT STRING ? BEQ 100$ ; IF EQ, YES (SUCCESS) CMPB (R3),#SPACE ; DETECT A SPACE DELIMITER ? BEQ 100$ ; IF EQ, YES (PRESUME END) CMPB (R3),#TAB ; DETECT A TAB DELIMITER ? BEQ 100$ ; IF EQ, YES (PRESUME END) TSTB (R4) ; END OF THIS ENTRY ? BEQ 20$ ; IF EQ, YES CMPB (R3)+,(R4)+ ; DO THEY MATCH BNE 20$ ; IF NE, NO (NEXT ENTRY) BR 10$ ; ELSE CHECK NEXT BYTE 20$: ADD R2,R1 ; POINT TO NEXT ENTRY MOV R1,R4 ; COPY FOR NEXT COMPARE MOV R0,R3 ; RESET INPUT BUFFER ADDRESS TSTB (R4) ; END OF TABLE? BPL 10$ ; IF PL, NO SEC ; ELSE THE ENTRY WASN'T IN THE TABLE RETURN 100$: TSTB EXACT ; EXACT MATCH DESIRED ? BEQ 110$ ; IF EQ, NO (RETURN) TSTB (R4) ; END OF TABLE STRING BNE 20$ ; IF NE, NO (NEXT ENTRY) 110$: MOV R1,14(SP) ; RETURN OFFSET IN R5 RETURN .SBTTL MOVE - MOVE AN ASCIZ STRING ;+ ; ; MOVE - Move an ASCIZ string. ; ; Inputs: ; R0 = the output buffer address ; R1 = the ASCIZ string to move. ; ; Outputs: ; R0 = points to next available byte. ; ;- MOVE:: MOVB (R1)+,(R0)+ ; MOVE A BYTE BNE MOVE ; IF NE, MORE TO GO DEC R0 ; POINT AT THE NULL RETURN .SBTTL CDDMG - CONVERT DOUBLE PRECISION BINARY TO DECIMAL ;+ ; ; CDDMG - Convert double precision binary to decimal. ; ; This routine is used instead of the normal call to $CDDMG to blank ; fill the converted number like $CBTA allows. ; ; Inputs: ; R0 = address of output buffer. ; R1 = address of binary number. ; R2 = the field width. ; ; Outputs: ; R0 points to next storage location. ; Registers R1 and R2 are destroyed. ; ;- CDDMG:: MOV R2,-(SP) ; SAVE THE FIELD WIDTH MOV R0,-(SP) ; SAVE THE OUTPUT ADDRESS MOV #TBUFF,R0 ; STORE CONVERTED # HERE CLR R2 ; SET FOR ZERO SUPPRESSION CALL $CDDMG ; CONVERT TO DECIMAL ASCII CLRB (R0) ; SHOW END OF THE NUMBER MOV R0,R1 ; COPY LAST OUTPUT ADDRESS SUB #TBUFF,R1 ; CALCULATE THE BYTE COUNT MOV (SP)+,R0 ; RESTORE OUTPUT ADDRESS MOV (SP)+,R2 ; RESTORE FIELD WIDTH SUB R1,R2 ; NUMBER OF BLANKS TO FILL BLE 20$ ; IF LE, NO FILL NEEDED 10$: MOVB #SPACE,(R0)+ ; MOVE IN A SPACE SOB R2,10$ ; LOOP UNTIL DONE ; Copy the converted number to the output buffer. 20$: MOV #TBUFF,R1 ; ADDRESS OF CONVERTED # 30$: MOVB (R1)+,(R0)+ ; MOVE THE NUMBER BNE 30$ ; IF NE, MORE TO GO DEC R0 ; POINT AT THE NULL RETURN .END