.TITLE MONLAT .IDENT /V2.0/ ; This program will listen for LAT multicast messages and display information ; from the messages it finds. ; Author = David Gagne .LIBRARY "SYS$LIBRARY:LIB.MLB" $IODEF ;Define I/O functions and modifiers $NMADEF ;Define Network Management parameters $LNMDEF ;Define logical name parameters .EXTERNAL SYS$FAO ; Modification history ; ; 2.0 David Gagne 06-May-1991 ; 09 Tell people that they should run this for 2 minutes. ; 08 Include the node name and service name in option 1 and 2. ; 07 Print a device summary for option 1. ; 06 Add more SYSID device names. ; 05 Add more driver names. ; 04 Display the group codes as numbers, not as a bit mask. ; 03 Print a better message when the protocol is being used. ; 02 Display the hardware address from the SYSID response. ; 01 Make the output tablized for option 1 and 2. ; 1.2 David Gagne ; 01 Fix a bug where we were printing duplicate entries ; 1.1 David Gagne ; 01 Modify the specific node display ; QIO data structures for the LAT channel. ; Setmode parameter buffer SETPARM: .WORD NMA$C_PCLI_PTY ; Protocol type .LONG ^X0460 .WORD NMA$C_PCLI_BFN ; Number of buffers to save .LONG 4 .WORD NMA$C_PCLI_BUS ; Max. receivable buffer size .LONG 1500 .WORD NMA$C_PCLI_PAD ; Padding .LONG NMA$C_STATE_OFF .WORD NMA$C_PCLI_MCA ; Multicast address .WORD 8 .WORD NMA$C_LINMC_SET .BYTE 09,00,^X2B,00,00,^X0F SETPARMLEN = .-SETPARM SETPARMDSC: .LONG SETPARMLEN .ADDRESS SETPARM ; Read buffer for LAT multicast messages RCVBUF: .BLKB 1504 RCVBUFLEN = .-RCVBUF ; Place to store incoming P5 buffer RCVP5: RCVDA: .BLKB 6 RCVSA: .BLKB 6 RCVPTY: .BLKB 2 ; QIO data structures for the MOP (SYSTEM ID) channel. ; P2 parameter buffer for finding devices of other nodes. SIDPARM: .WORD NMA$C_PCLI_PTY ; Protocol Type .LONG ^X0260 SIDPARMLEN = .-SIDPARM SIDPARMDSC: .LONG SIDPARMLEN .ADDRESS SIDPARM ; P2 transmit data buffer for sending request SYSID messages. XMTP2BUF: .BYTE 05 ; SYSTEM ID request code .BYTE 00 ; Reserved XMTP2RCT: .WORD 4242 ; Receipt number (to be returned) XMTP2LEN = .-XMTP2BUF ; Address of the node whose Device ID we would like to find. SIDADDR: .BLKB 6 ; Read buffer for receiving System IDs RCVBUF2: .BLKB 1504 RCVBUFLEN2 = .-RCVBUF2 ; Place to store incoming P5 buffer RCVP52: RCVDA2: .BLKB 6 RCVSA2: .BLKB 6 RCVPT2: .BLKB 2 ; Message structures ; General message buffer FAODESC: FAOLEN: .LONG 80 .ADDRESS FAOBUF FAOBUF: .BLKB 80 HDRMSG1: .ASCID "MONLAT - Ethernet LAT monitoring program. Version 2.0" INPMSG1: .ASCID "Monitor requests available:" INPMSG2: .ASCID " 1) Monitor service announcements from all nodes" INPMSG3: .ASCID " 2) Monitor service announcements for a specific group code" INPMSG4: .ASCID " 3) Monitor service announcement from a specific node" INPMSG5: .ASCID " any other input will stop the program" TIMMSG: .ASCID "The normal length of time to run this program is two minutes." IOMSG: .ASCID "!/The contents of the 2nd longword in the IOSB is !XL" NDMSG: .ASCID "No device found. Please define ETH appropriately." PT1MSG: .ASCID "Another user is using the LAT protocol (60-04)" PT2MSG: .ASCID "Another user is using the remote console protocol (60-02)" DNEMSG: .ASCID "MONLAT complete. Thank you for your continued support." BLNKMSG: .ASCID "" ; Output strings for monitoring service announcements from all nodes M1HDR1: .ASCID " Current Address Controller Hardware Address DECnet Node/Service" M1HDR2: .ASCID "----------------- ---------- ----------------- ------- --------------" M1DAT1: .ASCID "!XB-!XB-!XB-!XB-!XB-!XB !3UB=!AS " M1DAT2: .ASCID "!XB-!XB-!XB-!XB-!XB-!XB !2UB.!UW " M1DAT3: .ASCID "!AD/!AD" M1CODE: .ASCID " Group codes: !3UB !3UB !3UB !3UB !3UB !3UB !3UB" M1SEP1: .ASCID "----------------------------------------------------------------------------" M1NONE: .ASCID "No service announcement messages were found" M1SUM1: .ASCID " Device usage summary" M1SUM2: .ASCID " Device Amount" M1SUM3: .ASCID " ------ ------" M1SUMM: .ASCID " !5AS !5UW" M1TOTL: .ASCID " TOTAL = !5UW" ; Output strings for monitoring service announcements for a specific group M2HDR0: .ASCID "Nodes using group code #!3UB" M2NONE: .ASCID "No service announcement messages were found using Group Code #!3UB" ; Output strings for monitoring service announcements from a specific node M3ADDR: .ASCID "Address: !XB-!XB-!XB-!XB-!XB-!XB" M3NODE: .ASCID " DECnet node: !2UB.!UW" M3CONT: .ASCID " Controller: !UB = !AS" M3IDN1: .ASCID " Node name: !AD" M3IDN2: .ASCID " Node desc: !AD" M3IDN3: .ASCID " Service name: !AD" M3IDN4: .ASCID " Service desc: !AD" M3HDR1: .ASCID " Group Codes Set:" M3GCOD: .ASCID " !3UW" M3NONE: .ASCID "No service announcement message found from !XB-!XB-!XB-!XB-!XB-!XB" ; Strings for various device names DEV001: .ASCID "DEUNA" DEV003: .ASCID "DECNA" DEV005: .ASCID "DEQNA" DEV011: .ASCID "DELUA" DEV013: .ASCID "MSLAN" DEV017: .ASCID "DS100" DEV021: .ASCID "DEBET" DEV023: .ASCID "DEBNA" DEV025: .ASCID "PCLAN" DEV027: .ASCID "3C501" DEV033: .ASCID "DS200" DEV035: .ASCID "DS500" DEV037: .ASCID "DELQA" DEV039: .ASCID "DESVA" DEV041: .ASCID "MX100" DEV043: .ASCID "DEPCA" DEV045: .ASCID "LTM " DEV047: .ASCID "DESNC" DEV049: .ASCID "MX300" DEV053: .ASCID "LB200" DEV060: .ASCID "DS300" DEV063: .ASCID "VLIII" DEV064: .ASCID "VL350" DEV065: .ASCID "DEBNI" DEV066: .ASCID "DEMNA" DEV067: .ASCID "PMX " DEV072: .ASCID "DP250" DEV073: .ASCID "SGEC " DEV075: .ASCID "DEQTA" DEV076: .ASCID "LB150" DEV086: .ASCID "DR250" DEV090: .ASCID "DB500" DEV091: .ASCID "DB500" DEV092: .ASCID "WC500" DEV093: .ASCID "DEMFA" DEV094: .ASCID "PMAD " DEV104: .ASCID "KFE52" DEV105: .ASCID "RT300" DEV112: .ASCID "LPS20" DEV114: .ASCID "DWT-1" DEV119: .ASCID "DEFZA" DEVUNK: .ASCID "Unkwn" DEVMIS: .ASCID "Misng" DEVNAN: .ASCID "Noans" CTRMIS: .WORD 0 CTRNAN: .WORD 0 DEVTBL: .BYTE 1 .WORD 0 .ADDRESS DEV001 .BYTE 3 .WORD 0 .ADDRESS DEV003 .BYTE 5 .WORD 0 .ADDRESS DEV005 .BYTE 11 .WORD 0 .ADDRESS DEV011 .BYTE 13 .WORD 0 .ADDRESS DEV013 .BYTE 17 .WORD 0 .ADDRESS DEV017 .BYTE 21 .WORD 0 .ADDRESS DEV021 .BYTE 23 .WORD 0 .ADDRESS DEV023 .BYTE 25 .WORD 0 .ADDRESS DEV025 .BYTE 27 .WORD 0 .ADDRESS DEV027 .BYTE 33 .WORD 0 .ADDRESS DEV033 .BYTE 35 .WORD 0 .ADDRESS DEV035 .BYTE 37 .WORD 0 .ADDRESS DEV037 .BYTE 39 .WORD 0 .ADDRESS DEV039 .BYTE 41 .WORD 0 .ADDRESS DEV041 .BYTE 43 .WORD 0 .ADDRESS DEV043 .BYTE 45 .WORD 0 .ADDRESS DEV045 .BYTE 47 .WORD 0 .ADDRESS DEV047 .BYTE 49 .WORD 0 .ADDRESS DEV049 .BYTE 53 .WORD 0 .ADDRESS DEV053 .BYTE 60 .WORD 0 .ADDRESS DEV060 .BYTE 63 .WORD 0 .ADDRESS DEV063 .BYTE 64 .WORD 0 .ADDRESS DEV064 .BYTE 65 .WORD 0 .ADDRESS DEV065 .BYTE 66 .WORD 0 .ADDRESS DEV066 .BYTE 67 .WORD 0 .ADDRESS DEV067 .BYTE 72 .WORD 0 .ADDRESS DEV072 .BYTE 73 .WORD 0 .ADDRESS DEV073 .BYTE 75 .WORD 0 .ADDRESS DEV075 .BYTE 76 .WORD 0 .ADDRESS DEV076 .BYTE 86 .WORD 0 .ADDRESS DEV086 .BYTE 90 .WORD 0 .ADDRESS DEV090 .BYTE 91 .WORD 0 .ADDRESS DEV091 .BYTE 92 .WORD 0 .ADDRESS DEV092 .BYTE 93 .WORD 0 .ADDRESS DEV093 .BYTE 94 .WORD 0 .ADDRESS DEV094 .BYTE 104 .WORD 0 .ADDRESS DEV104 .BYTE 105 .WORD 0 .ADDRESS DEV105 .BYTE 112 .WORD 0 .ADDRESS DEV112 .BYTE 114 .WORD 0 .ADDRESS DEV114 .BYTE 119 .WORD 0 .ADDRESS DEV119 .BYTE 0 .WORD 0 ; Variables to find numerical values for the group codes enabled. GCMAX = 7 GCODES: .BLKB GCMAX ; Where to store the numerical codes GCMASK: .LONG 0 ; Mask to look at NUMGC: .LONG 0 ; Number of Group codes found NODNAM: .BLKB 6 ; Temp storage for node name SERNAM: .BLKB 6 ; Temp storage for service name ; Information from the SYSID response. DEVDSC: .BLKQ ; General device name descriptor DEVID: .BLKB ; Device ID from SYSID response DEVHWA: .BLKB 6 ; Device HWA from SYSID response ; Buffers, variables, and strings for the time control of the program HOURS: .BLKB 1 ; Storage of requested input MINUTES:.BLKB 1 SECONDS:.BLKB 1 ; The following variables are for reading input from the user after prompting. INPSTRDSC: ; Input buffer descriptor .LONG 0 .ADDRESS INPSTR INPSTR: .BLKB 18 ; Input buffer INPSIZ: .BLKL 1 ; The prompts are defined next. RPRMT: .ASCID "Which monitor request would you like to make: " HPRMT: .ASCID "How many hours would you like to monitor: " MPRMT: .ASCID "How many minutes would you like to monitor: " SPRMT: .ASCID "How many seconds would you like to monitor: " GPRMT: .ASCID "Which group code would you like to monitor: " APRMT: .ASCID "Enter the address of the node (ex: AA-00-04-00-75-4C): " ; Input variables from prompts REQ: .LONG 0 ; Request number DSTADR: .BLKB 6 ; Address to look for GCODE: .BYTE 1 ; Group code to look for ENDTIM: .BLKQ 1 ; Time to end test TIME: .BLKQ 1 ; Temporary time buffer DTIME: .ASCID /0 !2ZB:!2ZB:!2ZB.00/ ; String for calculating delta time ; Miscellaneous variables GCBITS: .BLKB 32 ; Used for examining group codes RCVTRY: .BLKL 1 ; Counter for receive attempts IOSB: .BLKQ 1 ; I/O status block ; Device names DEVDSC1:.ASCID 'ETH' ; Units to use for test DEVDSC2:.ASCID 'ESA0' DEVDSC3:.ASCID 'XQA0' DEVDSC4:.ASCID 'ETA0' DEVDSC5:.ASCID 'XEA0' DEVDSC6:.ASCID 'EXA0' DEVDSC7:.ASCID 'EZA0' DEVDSC8:.ASCID 'FXA0' DEVDSC9:.ASCID 'FGA0' ; Table of pointers to device names DEVADR: .ADDRESS DEVDSC1 .ADDRESS DEVDSC2 .ADDRESS DEVDSC3 .ADDRESS DEVDSC4 .ADDRESS DEVDSC5 .ADDRESS DEVDSC6 .ADDRESS DEVDSC7 .ADDRESS DEVDSC8 .ADDRESS DEVDSC9 .LONG 0 ; Channels - one for LAT and one for Remote Console CHNLAT: .BLKL 1 CHNRMC: .BLKL 1 .ENTRY START,^M<> ; Assign both channels to the first device found which is available CLRL R5 ; Check each channel name to see if one 10$: TSTL DEVADR(R5) ; is available until one is found: the BEQL 30$ ; first name checked is "ETH", a dummy MOVL DEVADR(R5),R4 ; name which can be defined to the $ASSIGN_S- ; device desired if either: DEVNAM=(R4),- ; 1) An unregistered device is used CHAN=CHNLAT ; or 2) One device is prefered BLBS R0,20$ ; If success, assign the 2nd channel ADDL #4,R5 ; Skip to next device name CMPW R0,#SS$_NOSUCHDEV ; Was the error "no such device"? BEQL 10$ ; If yes, try next device name BRW ERROR ; Else, exit with error 20$: $ASSIGN_S- ; Assign the 2nd channel to the same DEVNAM=(R4),- ; device name CHAN=CHNRMC BLBS R0,ASSIGN_OK ; If success, continue BRW ERROR ; Else, exit with an error ; No device was found. 30$: BSBW BLANK ; No device was found, so say so and PUSHAB NDMSG ; then exit. CALLS #1,G^LIB$PUT_OUTPUT BRW EXIT ASSIGN_OK: ; Start up the first channel for examining LAV packets. $QIOW_S FUNC=#,- CHAN=CHNLAT,- IOSB=IOSB,- P2=#SETPARMDSC BLBS R0,START_REQ_OK1 BRW ERROR START_REQ_OK1: MOVZWL IOSB,R0 BLBS R0,START_IO_OK1 CMPW #SS$_BADPARAM,R0 ; Was this a bad parameter? BNEQ 10$ ; If not, use general error path CMPW #NMA$C_PCLI_PTY,IOSB+4 ; Was protocol type the bad parameter? BNEQ 10$ ; If not, use general error path BSBW BLANK PUSHAB PT1MSG ; Print the protocol type error CALLS #1,G^LIB$PUT_OUTPUT BRW EXIT 10$: BRW ERROR START_IO_OK1: ; Start up the second channel for getting the device ID and name. $QIOW_S FUNC=#,- CHAN=CHNRMC,- IOSB=IOSB,- P2=#SIDPARMDSC BLBS R0,START_REQ_OK2 BRW ERROR START_REQ_OK2: MOVL IOSB,R0 BLBS R0,START_IO_OK2 CMPW #SS$_BADPARAM,R0 ; Was this a bad parameter? BNEQ 10$ ; If not, use general error path CMPW #NMA$C_PCLI_PTY,IOSB+4 ; Was protocol type the bad parameter? BNEQ 10$ ; If not, use general error path BSBW BLANK PUSHAB PT2MSG ; Print the protocol type error CALLS #1,G^LIB$PUT_OUTPUT BRW EXIT 10$: BRW ERROR START_IO_OK2: ; Print program header BSBW BLANK PUSHAB HDRMSG1 CALLS #1,G^LIB$PUT_OUTPUT GET_TEST: ; Print the prompt that requests which monitor request the user wants. This ; is also the top of the loop that allows the user to make multiple monitor ; requests. BSBW BLANK PUSHAB INPMSG1 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB INPMSG2 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB INPMSG3 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB INPMSG4 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB INPMSG5 CALLS #1,G^LIB$PUT_OUTPUT BSBW BLANK ; Read the user's input to our prompt for the number of the test to run. MOVL #2,INPSTRDSC ; Set number of bytes to read PUSHAB INPSIZ ; Push input size parameter PUSHAB RPRMT ; Push prompt string parameter PUSHAB INPSTRDSC ; Push String descriptor parameter CALLS #3,G^LIB$GET_INPUT ; Read the user's input ; Convert the input to a test number. CLRL R1 ; Start with zero in test number CLRL R2 ; Clear # of input characters done 10$: CMPW R2,INPSIZ ; Have we processed all the input? BGEQU 20$ ; If EQL, yes MOVZBL INPSTR(R2),R0 ; Get an input character SUBL2 #^A/0/,R0 ; Convert to a digit MULL2 #^D10,R1 ; Shift current decimal digits ADDL2 R0,R1 ; Add new digit INCL R2 ; Bump # of input characters done BRB 10$ ; Check next character ; Clear the per-test global variables. 20$: CLRL NODCNT CLRB HOURS CLRB MINUTES CLRB SECONDS MOVL R1,REQ ; Now perform the appropriate test based on the test number. CMPL R1,#1 ; Check if test #1 BNEQ 30$ ; If NEQ, no BSBW TEST_1 ; Do test BRW GET_TEST ; Check for another test to run 30$: CMPL R1,#2 ; Check if test #2 BNEQ 40$ ; If NEQ, no BSBW TEST_2 ; Do test BRW GET_TEST ; Check for another test to run 40$: CMPL R1,#3 ; Check if test #3 BNEQ 50$ ; If NEQ, no BSBW TEST_3 ; Do test BRW GET_TEST ; Check for another test to run ; Not a supported test, so exit. 50$: BRW EXIT ; Not any of above, so exit ; Request #1 ; ; This code receives all LAT packets coming into the node where the program ; is run for a length of time requested by the user. The packets are ; examined, and if the address is the first occurance thereof, the packet ; is stored. After the set time is over, all packets stored (along with ; other information) are displayed. TEST_1: BSBW GET_TIME BSBW SET_TIME ; We need to zero the device totals before we start receiving packets. MOVAB DEVTBL,R5 ; Start at beginning of table 10$: CLRW 1(R5) ; Clear this counter TSTB (R5) ; End of table? BEQL 20$ ; If EQL, yes ADDL #7,R5 ; Skip to next entry BRB 10$ ; Loop for more devices 20$: CLRW CTRMIS CLRW CTRNAN ; Loop receiving and storing packets until time runs out. RCV_T1: BSBW RCV_LAT ; Get a message BLBC R0,PRINT_T1 ; If time ran out, print results BSBW STORE_NODE ; Store this node BRB RCV_T1 ; Loop for more PRINT_T1: ; If we have no data, then print appropriate message. TSTL NODCNT ; Anything in node table? BNEQ PRINT_TBL_T1 ; If NEQ, yes, so print them ; Print "no messages found" message. BSBW BLANK PUSHAB M1NONE CALLS #1,G^LIB$PUT_OUTPUT RSB PRINT_TBL_T1: ; Print the header BSBW BLANK PUSHAB M1HDR1 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB M1HDR2 CALLS #1,G^LIB$PUT_OUTPUT ; Now print all the nodes in the node table. DECL NODCNT 10$: BSBW NEXT_R1 ; Get address of next entry to print BLBS R0,20$ ; If LBS, there's an entry BRW PRINT_SUM_R1 ; Print the node found 20$: BSBW PRINT_NODE ; Now print the group codes enabled. 30$: BSBW GET_GCODES TSTL NUMGC ; Any group codes found? BEQL 50$ ; If EQL, no ; Put the Group codes on the stack for FAO arguments. MOVL #^D33,M1CODE ; Set initial FAO string size MOVL NUMGC,R1 40$: MOVZBL GCODES-1(R1),-(SP) ; R1 was one based offset ADDL #5,M1CODE ; Add to size of FAO string SOBGTR R1,40$ ; Loop if more to store MOVL #80,FAOLEN PUSHAL FAOLEN ; Put length argument PUSHAL FAODESC ; Push descriptor argument PUSHAL M1CODE ; Push input string argument ADDL3 NUMGC,#3,R1 ; Get number of arguments CALLS R1,G^SYS$FAO ; Format the string PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT BRB 30$ ; Get more codes 50$: MOVL #1,(R2) ; Set low order bit so it's skipped PUSHAB M1SEP1 CALLS #1,G^LIB$PUT_OUTPUT BRW 10$ ; Get next node PRINT_SUM_R1: ; Print the device totals. ;========================================================================== ; Print the header PUSHAB M1SUM1 CALLS #1,G^LIB$PUT_OUTPUT BSBW BLANK PUSHAB M1SUM2 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB M1SUM3 CALLS #1,G^LIB$PUT_OUTPUT ;========================================================================== ; Print the device totals MOVAB DEVTBL,R5 ; Start at beginning of table CLRL R7 ; Start running total at zero ; Loop printing each device in the device table. 10$: TSTB (R5) ; End of table? BEQL 20$ ; If EQL, yes TSTW 1(R5) ; Were any found? BEQL 15$ ; If EQL, no, so don't print it ADDW 1(R5),R7 ; Add to running total MOVL 3(R5),R6 ; Get the address of the descriptor MOVL #80,FAOLEN $FAO_S CTRSTR=M1SUMM,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R6,- P2=1(R5) PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT 15$: ADDL #7,R5 ; Skip this entry BRB 10$ ; Loop for more devices ; Now print the number of unknown devices if any were found. 20$: TSTW 1(R5) BEQL 30$ ADDW 1(R5),R7 ; Add to running total MOVL #80,FAOLEN $FAO_S CTRSTR=M1SUMM,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=#DEVUNK,- P2=1(R5) PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Now print the number of missing devices if any were found. 30$: TSTW CTRMIS BEQL 40$ ADDW CTRMIS,R7 ; Add to running total MOVL #80,FAOLEN $FAO_S CTRSTR=M1SUMM,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=#DEVMIS,- P2=CTRMIS PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Now print the number of devices that didn't answer. 40$: TSTW CTRNAN BEQL 50$ ADDW CTRNAN,R7 ; Add to running total MOVL #80,FAOLEN $FAO_S CTRSTR=M1SUMM,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=#DEVNAN,- P2=CTRNAN PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Now print the total. 50$: PUSHAB M1SUM3 CALLS #1,G^LIB$PUT_OUTPUT $FAO_S CTRSTR=M1TOTL,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R7 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT RSB ; Test #2 ; ; This test asks the user for both a length of time to run the test for and ; a group code to watch for. Once the end time has been reached, the addresses ; of all nodes received with the specific group code enabled are printed. TEST_2: BSBW GET_TIME BSBW BLANK BSBW GET_GCODE BSBW SET_TIME ; Loop receiving and storing nodes with a matching group code. RCV_T2: BSBW RCV_LAT ; Get a message BLBC R0,PRINT_T2 ; If time ran out, print results ; First check if the appropriate group code is set in this message. MOVZBL RCVBUF+12,R1 ; Get group code length MOVC5 R1,RCVBUF+13,#0,- ; Copy (with zero extend) into #^X20,GCBITS ; a fixed place MOVZBL GCODE,R1 ; Get requested group code CLRL R0 ; To calc group code bit number, CLRL R2 ; start with 0 in R0 and R2 EDIV #8,R1,R0,R2 ; R0=byte to check in the bit mask ; R2=bit to check in that byte BBC R2,GCBITS(R0),RCV_T2 ; If group code not enabled, discard BSBW STORE_NODE ; Store this node BRW RCV_T2 ; Loop for more nodes PRINT_T2: ; If we have no data, then print appropriate message. TSTL NODCNT ; Anything in DECNET table? BNEQ PRINT_TBL_T2 ; If NEQ, yes, so print them ; Print "no messages found" message. BSBW BLANK MOVL #80,FAOLEN $FAO_S CTRSTR=M2NONE,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=GCODE PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT RSB PRINT_TBL_T2: ; Print the header BSBW BLANK MOVL #80,FAOLEN $FAO_S CTRSTR=M2HDR0,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=GCODE PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT PUSHAB M1HDR1 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB M1HDR2 CALLS #1,G^LIB$PUT_OUTPUT ; Now print all the nodes in the node table. DECL NODCNT 10$: BSBW NEXT_R1 ; Get address of next entry to print BLBS R0,20$ ; If LBS, there's an entry RSB ; Print the node found 20$: BSBW PRINT_NODE MOVL #1,(R2) ; Set low order bit so it's skipped BRW 10$ ; Get next node ; Test #3 ; ; This test asks the user for one address, and waits for a message from that ; address. Once a message from that address is found, a listing of all group ; codes enabled is given. TEST_3: ; Start the test; continue until the end time is reached. BSBW GET_TIME BSBW BLANK BSBW GET_ADDR BSBW SET_TIME RCV_T3: BSBW RCV_LAT ; Get a message BLBS R0,10$ ; If we have a message, process it ; Print "no messages found" message. BSBW BLANK MOVL #80,FAOLEN $FAO_S CTRSTR=M3NONE,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=DSTADR,- P2=DSTADR+1,- P3=DSTADR+2,- P4=DSTADR+3,- P5=DSTADR+4,- P6=DSTADR+5 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT RSB ; Check if the source address is the desired one. 10$: MOVZBL RCVBUF+12,R1 MOVC5 R1,RCVBUF+13,#0,#^X20,GCBITS CMPC3 #6,RCVSA,DSTADR BNEQ RCV_T3 ; The address was the desired one, so print the results PRINT_T3: ; Print the address. BSBW BLANK MOVL #80,FAOLEN $FAO_S CTRSTR=M3ADDR,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=RCVSA,- P2=RCVSA+1,- P3=RCVSA+2,- P4=RCVSA+3,- P5=RCVSA+4,- P6=RCVSA+5 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Print the DECnet node if this is a DECnet address CMPL #^X000400AA,RCVSA ; Is this a DECnet address? BNEQ 1$ ; If NEQ, no MOVW RCVSA+4,R0 BICW #^XFC00,R0 MOVZBL RCVSA+5,R3 ASHL #-2,R3,R3 MOVL #80,FAOLEN $FAO_S CTRSTR=M3NODE,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R3,- P2=R0 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Print the device ID and device name. 1$: MOVL DSTADR,SIDADDR MOVW DSTADR+4,SIDADDR+4 BSBW GET_DEVID MOVL #80,FAOLEN $FAO_S CTRSTR=M3CONT,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=DEVID,- P2=#DEVDSC PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Print the node name if there is one. MOVZBL RCVBUF+12,R1 ; Get size of group code bits ADDL3 #^D13,R1,R4 ; Offset to node name size MOVAL RCVBUF+1,R5 ; Calc address of string ADDL R4,R5 ; Address of string MOVZBL RCVBUF(R4),R3 ; Get size BEQL 10$ ; If EQL, none to print MOVL #80,FAOLEN $FAO_S CTRSTR=M3IDN1,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R3,- P2=R5 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Print the node descriptor if there is one. 10$: ADDL R3,R5 ; Address of size MOVZBL (R5)+,R3 ; Get size BEQL 20$ ; If EQL, none to print MOVL #80,FAOLEN $FAO_S CTRSTR=M3IDN2,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R3,- P2=R5 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Print each service set. 20$: ADDL R3,R5 ; Address of number of sets MOVZBL (R5)+,R6 ; Get number of sets BEQL 60$ ; Branch if none CLRL R3 ; Nothing to skip right now ; Print the service name if there is one. 30$: INCL R5 ; Skip service rating ADDL R3,R5 ; Address of size MOVZBL (R5)+,R3 ; Get size BEQL 40$ ; If EQL, none to print MOVL #80,FAOLEN $FAO_S CTRSTR=M3IDN3,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R3,- P2=R5 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Print the service descriptor if there is one. 40$: ADDL R3,R5 ; Address of size MOVZBL (R5)+,R3 ; Get size BEQL 50$ ; If EQL, none to print MOVL #80,FAOLEN $FAO_S CTRSTR=M3IDN4,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R3,- P2=R5 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; If more service sets, print them. 50$: SOBGTR R6,30$ ; Print the group code header. 60$: PUSHAB M3HDR1 CALLS #1,G^LIB$PUT_OUTPUT ; Print all the enabled group code's. CLRL R1 70$: CLRL R0 CLRL R2 EDIV #8,R1,R0,R2 BBC R2,GCBITS(R0),80$ PUSHL R1 MOVL #80,FAOLEN $FAO_S CTRSTR=M3GCOD,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R1 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT POPL R1 80$: INCL R1 CMPL R1,#^D256 BLSS 70$ RSB RCV_LAT: ; Read a LAT multicast service announcement frame. Return if time has run ; out (R0=0) or if a frame was received successfully (R0=1). ; First check if time has run out. $GETTIM_S- ; Get current time TIMADR=TIME CMPL TIME+4,ENDTIM+4 ; Did we look long enough? BEQL 10$ ; If equal, need to check low longword BLSSU 30$ ; If LSSU, continue BRB 20$ ; Else end search for the node 10$: CMPL TIME,ENDTIM ; Check low longword BLSSU 30$ ; If LSSU, continue 20$: CLRL R0 ; Say that time ran out RSB 30$: $QIOW_S FUNC=#IO$_READVBLK!IO$M_NOW,- CHAN=CHNLAT,- IOSB=IOSB,- P1=RCVBUF,- P2=#RCVBUFLEN,- P5=#RCVP5 BLBS R0,RCV_REQ_OK BRW ERROR RCV_REQ_OK: MOVZWL IOSB,R0 BLBS R0,RCV_IO_OK CMPW R0,#SS$_ENDOFFILE BEQL RCV_LAT BRW ERROR RCV_IO_OK: ; Check if this is a multicast message. If not, throw it away and look for ; another message. BLBC RCVDA,RCV_LAT ; Ignore packet if sent to physical ; Make sure this is a service announcement message. If not, throw it away ; and look for another message. CMPB #^X28,RCVBUF ; Is this a service announcement? BNEQ RCV_LAT ; If NEQ, no, try again ; The message is good, return success MOVZBL #1,R0 RSB STORE_NODE: ; RCVSA = Source address ; RCVBUF = Received LAT message ; Check if this is a new node. If so, store it. However, if the source ; address is multicast, then we will throw the packet away because we use ; a multicast source address to show that the node has already been printed. BLBC RCVSA,10$ ; If not multicast source, store it RSB 10$: CMPL #2,REQ ; Is this test 2? BEQL 20$ ; If EQL, yes, don't need GCBITS MOVZBL RCVBUF+12,R1 ; Get size of mask in message MOVC5 R1,RCVBUF+13,#0,- ; Store the group codes in GCBITS #^X20,GCBITS ; Check to see if the source address is already in the node table. If so, ; throw this message away and read another one. 20$: MOVAL NODTBL,R2 ; Start at beginning of table SUBL #NODSIZ,R2 ; Get to negative one entry MOVL NODCNT,R1 ; Get number of entries BEQL 50$ ; If none, just add this one 30$: ADDL #NODSIZ,R2 ; Get to next entry CMPL RCVSA,(R2) ; Source address match? BNEQ 40$ ; If NEQ, no, so check next entry CMPW RCVSA+4,4(R2) ; Source address match? BEQL 60$ ; If EQL, yes, so ignore message 40$: SOBGTR R1,30$ ; Check next entry in table ; The node was not in the table, so add it if there's room. 50$: CMPL NODCNT,#NODMAX ; Is there room? BEQL 60$ ; If EQL, no, so ignore message ADDL #NODSIZ,R2 ; Get to next entry MOVL RCVSA,(R2) ; Store SA MOVW RCVSA+4,4(R2) ; Store SA MOVQ GCBITS+00,06(R2) ; Store group code mask MOVQ GCBITS+08,14(R2) ; Store group code mask MOVQ GCBITS+16,22(R2) ; Store group code mask MOVQ GCBITS+24,30(R2) ; Store group code mask BSBB STORE_NAME INCL NODCNT ; Bump number of used entries 60$: RSB STORE_NAME: ; R2 = Address of node entry ; ; Now get the node name and service name (if they exist). First fill the ; node name section of the entry with spaces. If the first service name is ; the same as the node name, then store the second service name (if there ; is one). MOVL #^X20202020,38(R2) ; Start with spaces for the node name MOVW #^X2020,42(R2) MOVZBL RCVBUF+12,R1 ; Get size of group code bits ADDL3 #^D13,R1,R4 ; Offset to node name size MOVAL RCVBUF+1,R5 ; Calc address of string ADDL R4,R5 ; Address of string MOVZBL RCVBUF(R4),R3 ; Get size BEQL 20$ ; If EQL, none to print PUSHR #^M ; Save registers CMPL R3,#6 ; String too big? BLEQU 10$ ; If LEQU, no MOVL #6,R3 ; Only copy what fits 10$: SUBL3 R3,#6,R0 ; Number of bytes to skip in dest MOVAL 38(R2),R1 ; Node name storage area ADDL R1,R0 ; Where to store this node name PUSHR #^M ; Save registers MOVC3 R3,(R5),(R0) ; Store the name POPR #^M ; Restore registers MOVC3 R3,(R5),NODNAM ; Store here for comparison POPR #^M ; Restore registers ; Skip over the node descriptor. 20$: ADDL R3,R5 ; Address of size MOVZBL (R5)+,R3 ; Get size ADDL R3,R5 ; Skip over node descriptor ; See if there are any service sets. MOVL #^X20202020,SERNAM ; Start with spaces in service name MOVW #^X2020,SERNAM+4 MOVZBL (R5)+,R6 ; Get number of sets BEQL 40$ ; Branch if none ; Save the first service name if there is one. 25$: INCL R5 ; Skip service rating MOVZBL (R5)+,R3 ; Get size BEQL 40$ ; Exit if none PUSHL R3 ; Save the size CMPL R3,#6 ; String too big? BLEQU 30$ ; If LEQU, no MOVL #6,R3 ; Only copy what fits 30$: MOVL #^X20202020,SERNAM ; Put spaces in service name again MOVW #^X2020,SERNAM+4 ; because there may be junk there PUSHR #^M ; Save registers MOVC3 R3,(R5),SERNAM ; Store the name POPR #^M ; Restore registers PUSHR #^M ; Save registers CMPC3 R3,SERNAM,NODNAM ; Are the names the same? BNEQ 35$ ; If NEQ, no, so use this name POPR #^M ; Restore registers POPL R3 ; Get original size back ADDL R3,R5 ; Get to service description MOVZBL (R5)+,R3 ; Get size of service description ADDL R3,R5 ; Get to next service name SOBGTR R6,25$ ; Loop if more entries BRB 40$ ; Else use what we have 35$: POPR #^M ; Restore registers POPL R3 ; Clean up the stack 40$: PUSHR #^M ; Save registers MOVC3 #6,SERNAM,44(R2) ; Store the service name we found POPR #^M ; Restore registers RSB PRINT_NODE: ; R2 is pointing to the entry we want to print. MOVL (R2),SIDADDR ; Get the source address so we can ... MOVW 4(R2),SIDADDR+4 BSBW GET_DEVID ; Get the device information MOVL #80,FAOLEN $FAO_S CTRSTR=M1DAT1,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=0(R2),- P2=1(R2),- P3=2(R2),- P4=3(R2),- P5=4(R2),- P6=5(R2),- P7=DEVID,- P8=#DEVDSC CMPL (R2),#^X000400AA ; Is this a DECnet address? BNEQ 10$ ; If NEQ, no MOVW 4(R2),R0 BICW #^XFC00,R0 MOVZBL 5(R2),R1 ASHL #-2,R1,R3 MOVL #80-33,FAOLEN MOVAL 33+FAOBUF,FAODESC+4 $FAO_S CTRSTR=M1DAT2,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=DEVHWA,- P2=DEVHWA+1,- P3=DEVHWA+2,- P4=DEVHWA+3,- P5=DEVHWA+4,- P6=DEVHWA+5,- P7=R3,- P8=R0 10$: MOVL #80-62,FAOLEN MOVAL 62+FAOBUF,FAODESC+4 MOVAL 38(R2),R3 MOVAL 44(R2),R0 $FAO_S CTRSTR=M1DAT3,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=#6,- P2=R3,- P3=#6,- P4=R0 ADDL #62,FAOLEN MOVAL FAOBUF,FAODESC+4 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT RSB GET_DEVID: ; Get the node's device ID and device name. This is done by requesting a ; SYSID message from the node. The response (if any) contains the device ; ID. From the device ID, we will select the correct device name. Upon ; completion of this routine, DEVID (a byte) will have the device ID, ; DEVDSC will point to the device name, and DEVHWA will have the device's ; hardware address. ; Transmit the request ID message to the node we want to find out about. $QIOW_S FUNC=#IO$_WRITEVBLK,- CHAN=CHNRMC,- IOSB=IOSB,- P1=XMTP2BUF,- P2=#XMTP2LEN,- P5=#SIDADDR BLBS R0,DXMT_REQ_OK BRW ERROR DXMT_REQ_OK: MOVL IOSB,R0 BLBS R0,DXMT_IO_OK BRW ERROR DXMT_IO_OK: ; Receive the SYSID response. If there is no data ready to receive, then the ; Ethernet driver will return immediately with SS$_ENDOFFILE. CLRL RCVTRY ; Clear the number of read attempts DRCV: $QIOW_S FUNC=#IO$_READVBLK!IO$M_NOW,- CHAN=CHNRMC,- IOSB=IOSB,- P1=RCVBUF2,- P2=#RCVBUFLEN2,- P5=#RCVP52 BLBS R0,DRCV_REQ_OK BRW ERROR DRCV_REQ_OK: MOVL IOSB,R0 BLBS R0,DRCV_IO_OK CMPW IOSB,#SS$_ENDOFFILE BEQL DRCV_TRY BRW ERROR DRCV_TRY: CMPL RCVTRY,#4000 ; Have we tried enough times? BGTR 20$ ; If GTR, yes, so message is lost INCL RCVTRY ; Count this attempt BRB DRCV ; Try again 20$: CLRB DEVID ; Clear the Device ID number MOVQ DEVNAN,DEVDSC ; Set the device name to no response INCW CTRNAN ; Count this no answer case CLRL DEVHWA ; No Hardware address CLRW DEVHWA+4 RSB ; Return to caller DRCV_IO_OK: ; Check that this is a SYSTEM ID message from the correct node. CMPB RCVBUF2,#7 ; Is this a SYSTEM ID message? BNEQ DRCV_TRY ; If NEQ, no, try again CMPL RCVSA2,SIDADDR ; Correct node? BNEQ DRCV_TRY ; If NEQ, no CMPW RCVSA2+4,SIDADDR+4 ; Correct node? BNEQ DRCV_TRY ; If NEQ, no ; We received a message from the remote node. Look for the Device ID entry ; in this SYSID message. MOVL #4,R3 ; Skip over SYSID header ; Loop through the entries in the SYSID looking for the Device ID entry. 10$: CMPW R3,IOSB+2 ; Any buffer left to look at? BLSSU 20$ ; If LSSU, yes, so look for more BRW 70$ ; Else report Device ID missing 20$: CMPW RCVBUF2(R3),#^D100 ; Is this the device ID entry? BEQL 30$ ; If EQL, yes MOVZBL RCVBUF2+2(R3),R1 ; Get size of this entry ADDL #3,R3 ; Skip over entry type and size ADDL R1,R3 ; Skip over entry value BRW 10$ ; Check next entry ; The Device ID was found. Store the Device ID. 30$: ADDL #3,R3 ; Skip over Device ID header MOVB RCVBUF2(R3),DEVID ; Store the Device ID ; See if the device ID is one we know about. If so, store the address of ; the text descriptor in DEVDSC. MOVAB DEVTBL,R5 ; Start at beginning of table 40$: TSTB (R5) ; End of table? BEQL 60$ ; If EQL, yes CMPB DEVID,(R5)+ ; Device number match? BEQL 50$ ; If EQL, yes ADDL #6,R5 ; Skip to next entry BRB 40$ ; Check next entry ; We found a match in the table. 50$: INCW (R5)+ ; Count one more of these devices MOVQ @(R5),DEVDSC ; Save descriptor BRB 140$ ; There was no match for the DEVICE entry in the SYSID response. 60$: INCW 1(R5) ; One more of these devices found MOVQ DEVUNK,DEVDSC ; This is an unknown device BRB 140$ ; There was no DEVICE entry in the SYSID response. 70$: INCW CTRMIS ; Count this missing device ID CLRB DEVID ; No Device ID was found MOVQ DEVMIS,DEVDSC ; Device ID is missing ; Now look for the Hardware address entry in this SYSID message. 140$: MOVL #4,R3 ; Skip over SYSID header ; Loop through the entries in the SYSID looking for the hardware address ; entry. 150$: CMPW R3,IOSB+2 ; Any buffer left to look at? BGEQU 160$ ; If GEQU, no, so clear DEVHWA CMPW RCVBUF2(R3),#7 ; Is this the HWA entry? BEQL 170$ ; If EQL, yes MOVZBL RCVBUF2+2(R3),R1 ; Get size of this entry ADDL #3,R3 ; Skip over entry type and size ADDL R1,R3 ; Skip over entry value BRW 150$ ; Check next entry ; There was no HWA field in the SYSID; so just return a value of all zeros. 160$: CLRL DEVHWA ; Zero first longword CLRW DEVHWA+4 ; Zero last word BRB 180$ ; Skip over "found HWA" code ; The Hardware address was found; so store it in DEVHWA. 170$: ADDL #3,R3 ; Skip over Device ID header MOVL RCVBUF2(R3),DEVHWA ; Store first longword MOVW RCVBUF2+4(R3),DEVHWA+4 ; Store last word 180$: RSB GET_GCODES: ; R2 = address where the entry is stored. ; Convert the group code bit mask into the actual group codes enabled. We ; will only convert as many as we have space for. CLRL NUMGC ; Start with no group codes found CLRL R0 ; Group code number starts at 0 MOVL 06(R2),GCMASK ; Convert the 1st longword BEQL 1$ BSBW 20$ MOVL GCMASK,06(R2) ; Save the longword 1$: ADDL #32,R0 ; Add 32 to group code base number MOVL 10(R2),GCMASK ; Convert the 2nd longword BEQL 2$ BSBW 20$ MOVL GCMASK,10(R2) ; Save the longword 2$: ADDL #32,R0 ; Add 32 to group code base number MOVL 14(R2),GCMASK ; Convert the 3rd longword BEQL 3$ BSBB 20$ MOVL GCMASK,14(R2) ; Save the longword 3$: ADDL #32,R0 ; Add 32 to group code base number MOVL 18(R2),GCMASK ; Convert the 4th longword BEQL 4$ BSBB 20$ MOVL GCMASK,18(R2) ; Save the longword 4$: ADDL #32,R0 ; Add 32 to group code base number MOVL 22(R2),GCMASK ; Convert the 5th longword BEQL 5$ BSBB 20$ MOVL GCMASK,22(R2) ; Save the longword 5$: ADDL #32,R0 ; Add 32 to group code base number MOVL 26(R2),GCMASK ; Convert the 6th longword BEQL 6$ BSBB 20$ MOVL GCMASK,26(R2) ; Save the longword 6$: ADDL #32,R0 ; Add 32 to group code base number MOVL 30(R2),GCMASK ; Convert the 7th longword BEQL 7$ BSBB 20$ MOVL GCMASK,30(R2) ; Save the longword 7$: ADDL #32,R0 ; Add 32 to group code base number MOVL 34(R2),GCMASK ; Convert the 8th longword BEQL 8$ BSBB 20$ MOVL GCMASK,34(R2) ; Save the longword 8$: RSB ; This routine will store the Group code number of all the bits set in ; GCMASK. 20$: PUSHL R3 ; Save R3 PUSHL R1 ; Save R1 MOVL NUMGC,R1 ; Get number already stored 30$: CMPL R1,#GCMAX ; Any more room? BGEQU 40$ ; If GEQU, no more room FFS #0,#32,GCMASK,R3 ; Look for a set bit BEQL 40$ ; If EQL, none found BBCC R3,GCMASK,35$ ; Clear the bit 35$: ADDB3 R0,R3,GCODES(R1) ; Save group code number INCL R1 ; Count group code number BRB 30$ ; Look for more 40$: MOVL R1,NUMGC ; Save new number of Group codes POPL R1 ; Restore R1 POPL R3 ; Restore R3 RSB ; Done with this longword GET_GCODE: ; Get group code to watch for MOVL #18,INPSTRDSC PUSHAB INPSIZ PUSHAB GPRMT PUSHAB INPSTRDSC CALLS #3,G^LIB$GET_INPUT ; Convert group code CLRL R1 CLRW R2 10$: MOVZBL INPSTR(R2),R0 SUBL2 #^A/0/,R0 MULL2 #^D10,R1 ADDL2 R0,R1 INCW R2 CMPW R2,INPSIZ BLSS 10$ MOVB R1,GCODE RSB GET_ADDR: ; Get the address to look for from the user. MOVL #18,INPSTRDSC ; Maximum input size is 18 bytes PUSHAB INPSIZ ; Place to store # of bytes entered PUSHAB APRMT ; Prompt to display PUSHAB INPSTRDSC ; Place to store input string CALLS #3,G^LIB$GET_INPUT CLRL R1 ; Index to next input character CLRL R3 ; Index to next address byte ; Get the first digit of the next address byte. 10$: MOVZBL INPSTR(R1),R0 ; Get next input character INCL R1 ; Bump input character index CMPB R0,#^A/A/ ; Is this a letter or greater? BGEQU 20$ ; If GEQU, yes, so branch SUBL3 #^A/0/,R0,R2 ; Convert digit character to digit BRB 30$ ; Get the next input character 20$: SUBL2 #^A/A/,R0 ; Convert letter character to digit ADDL3 #^D10,R0,R2 ; Add ten to have correct digit ; Get the second digit of the next address byte. 30$: MULL2 #^D16,R2 ; Put the first digit into its place MOVZBL INPSTR(R1),R0 ; Get next input character INCL R1 ; Bump input character index CMPB R0,#^A/A/ ; Is this a letter or greater? BGEQU 40$ ; If GEQU, yes, so branch SUBL2 #^A/0/,R0 ; Convert digit character to digit BRB 50$ ; Go to add the second digit 40$: SUBL2 #^A/A/,R0 ; Convert letter character to digit ADDL2 #^D10,R0 ; Add ten to have correct digit 50$: ADDL R0,R2 ; Add lower digit to address ; Store this address byte and see if we need to do more. MOVB R2,DSTADR(R3) ; Store this address byte INCL R3 ; Bump to next address byte CMPL R3,#^D06 ; Have we processed 6 bytes? BLSS 60$ ; Branch if not, more to do RSB ; Else return to caller 60$: INCL R1 ; Skip over "-" in input string BRW 10$ ; Do next address byte GET_TIME: ; Tell them what the normal run time is. BSBW BLANK PUSHAB TIMMSG ; Print the protocol type error CALLS #1,G^LIB$PUT_OUTPUT ; Get number of hours to run test for GET_HOUR: BSBW BLANK MOVL #6,INPSTRDSC PUSHAB INPSIZ PUSHAB HPRMT PUSHAB INPSTRDSC CALLS #3,G^LIB$GET_INPUT ; Convert number of hours CLRL R1 CLRW R2 NUM_LOOP2: MOVZBL INPSTR(R2),R0 SUBL2 #^A/0/,R0 MULL2 #^D10,R1 ADDL2 R0,R1 INCW R2 CMPW R2,INPSIZ BLSS NUM_LOOP2 CMPL R1,#^D23 BGTR GET_HOUR MOVL R1,HOURS ; Get number of minutes to run test for GET_MINUTE: MOVL #6,INPSTRDSC PUSHAB INPSIZ PUSHAB MPRMT PUSHAB INPSTRDSC CALLS #3,G^LIB$GET_INPUT ; Convert number of minutes CLRL R1 CLRW R2 NUM_LOOP3: MOVZBL INPSTR(R2),R0 SUBL2 #^A/0/,R0 MULL2 #^D10,R1 ADDL2 R0,R1 INCW R2 CMPW R2,INPSIZ BLSS NUM_LOOP3 CMPL R1,#^D59 BGTR GET_MINUTE MOVL R1,MINUTES ; Get number of seconds to run test for GET_SECOND: MOVL #6,INPSTRDSC PUSHAB INPSIZ PUSHAB SPRMT PUSHAB INPSTRDSC CALLS #3,G^LIB$GET_INPUT ; Convert number of seconds CLRL R1 CLRW R2 NUM_LOOP4: MOVZBL INPSTR(R2),R0 SUBL2 #^A/0/,R0 MULL2 #^D10,R1 ADDL2 R0,R1 INCW R2 CMPW R2,INPSIZ BLSS NUM_LOOP4 CMPL R1,#^D59 BGTR GET_SECOND MOVL R1,SECONDS RSB SET_TIME: ; Determine the time to stop the test ; Now put the total time into one string MOVL #80,FAOLEN $FAO_S CTRSTR=DTIME,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=HOURS,- P2=MINUTES,- P3=SECONDS ; Change the ASCII string for the time to a quadword value. $BINTIM_S- TIMBUF=FAODESC,- TIMADR=TIME MNEGL TIME+4,TIME+4 MNEGL TIME,TIME SBWC #0,TIME+4 ; Now get the present time and add the test time to get the end time. $GETTIM_S- TIMADR=ENDTIM ADDL TIME,ENDTIM ADWC TIME+4,ENDTIM+4 RSB NEXT_R1: ; Get the next node entry to print. We do this based on a scan of the ; nodes in the node table. Any node that has LBS in the first entry has ; already been printed. Note that the caller has to set the low order ; bit when it's done with the entry. ; ; Output: ; R0 = LBS if a node was found, else LBC ; R2 = address of entry if R0=LBS MOVL NODCNT,R0 MOVAL NODTBL,R2 10$: BLBC (R2),20$ ; If LBC, this is a real entry ADDL #NODSIZ,R2 ; Get to next entry SOBGTR R0,10$ ; Loop if more to check CLRL R0 ; No more RSB 20$: MOVL R2,R1 ; Save current lowest as current 30$: ADDL #NODSIZ,R1 ; Get to next entry BLBS (R1),50$ ; If LBS, this is not a real entry CMPL (R1),(R2) ; Is the new entry lower? BGTRU 50$ ; If GTR, no BLSSU 40$ ; If LSS, yes CMPW 4(R1),4(R2) ; Is the new entry lower? BGEQU 50$ ; If GEQ, no 40$: MOVL R1,R2 ; Save new lowest 50$: SOBGTR R0,30$ ; Loop if more to check MOVL #1,R0 ; Found one RSB EXIT: BSBW BLANK PUSHAB DNEMSG CALLS #1,G^LIB$PUT_OUTPUT BSBW BLANK $DASSGN_S- CHAN=CHNLAT $DASSGN_S- CHAN=CHNRMC $EXIT_S BLANK: ; Print blank line PUSHAB BLNKMSG CALLS #1,G^LIB$PUT_OUTPUT RSB ; An error has occured, so print R0 value and 2nd longword of IOSB. ERROR: PUSHL R0 ; Pass R0 error code CALLS #1,RBL$ERCODE ; Print error code ; Print IOSB 2nd longword value in hex MOVL #80,FAOLEN $FAO_S CTRSTR=IOMSG,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=IOSB+4 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT BRW EXIT ; Now exit normally .PAGE ; RBL$ERCODE ; ; This subroutine accepts a VMS error code in binary ; and print the message on the terminal. ; ; INPUT: 4(AP) = Error Code ; ; OUTPUT: all registers saved except R0 and R1 ; ; CALLING SEQ: PUSHx error code ; CALL_S #1,RBL$ERCODE ; .ENTRY RBL$ERCODE,^M MOVL 4(AP),R3 ; Get error code $GETMSG_S- ; Convert error code to message MSGID=R3,- MSGLEN=ERRMSG_LEN,- BUFADR=ERRMSG_BUF_DESC PUSHAB ERRMSG_BUF_DESC CALLS #1,G^LIB$PUT_OUTPUT RET ; Return to caller ; Structures used to build error message from error code ERRMSG_BUF_DESC: ERRMSG_LEN: .LONG 256 .ADDRESS- ERRMSG_BUF ERRMSG_BUF: .BLKB 256 ; Node table for node addresses already found ; ; The node table contains: ; ; 06 bytes for the current address ; 32 bytes for the mask ; 06 bytes for the node name ; 06 bytes for the service name NODSIZ = 50 NODMAX = 1000 NODCNT: .LONG 0 ; Number currently in the table NODTBL: .BLKB NODMAX*NODSIZ ; Node entries .END START