1 OPTION TYPE=EXPLICIT & !& ! This program demonstrates the use of Ethernet devices & ! for user programming purposes. The program has a MACRO & ! interface to perform reads, writes, and .SPEC functions & !& ! DISCLAIMER: & ! This program is meant for demonstration purposes only. & ! No responsibilty is implied for any errors that exist. & 100 EXTERNAL SUB & !& ! Declare the MACRO-11 subroutines & !& CHGPHY BY REF (WORD, STRING), & ENBMUL BY REF (WORD, STRING, WORD), & XFRCIR BY REF (WORD, STRING, WORD, WORD), & XFRLIN BY REF (WORD, STRING, WORD, WORD), & EREAD BY REF (WORD, STRING, WORD, WORD), & EWRITE BY REF (WORD, STRING, WORD, WORD) & 110 EXTERNAL WORD BCOUNT & ! Byte count of .READ by MACRO subroutine & 900 DECLARE WORD BUF_LEN,CHNL,PADDED,I,J,I.,J.,I1.,I2., & READ_LOOP & ! Local variables & 910 DECLARE STRING TEMP,CMD,DEV,HEX.SET,ASCII.SET(255%), & CMASK,T.,T1.,T2. & ! Local strings & 920 DECLARE STRING FUNCTION & !& ! Internal functions & !& FN.HEX(WORD), & FN.CVT_TO_HEX(STRING), & FN.CVT_TO_ADDRESS(STRING) & 930 MAP (FSS) STRING FIRQB = 30% & !& ! Layout of FSS SYS call & !& \ MAP (FSS) BYTE FQJOB, BYTE FQSIZM, & WORD RESERVED, & WORD FQPPN, & LONG FQNAM1, & WORD FQEXT, & WORD FQSIZ, & WORD FQCLUS, & WORD FQMODE, & WORD FQNENT, & BYTE FQPFLG, BYTE FQPROT, & STRING FQDEV = 2%, & BYTE FQDEVN, BYTE FQDEVF, & WORD FLAG1, & WORD FLAG2 & 940!& ! The I/O buffer for Ethernet functions: & !& MAP (ETHER) STRING ETHER = 1514% & !& ! Standard send/receive items: & ! Also used for Change Physical Address & !& \ MAP (ETHER) STRING DEST = 6%, & SRC = 6%, & WORD PROTOCOL, & LENGTH & !& \ MAP (ETHER) STRING FILL = 14%, & BYTE DATA_BUFFER(1500) & !& \ MAP DYNAMIC (ETHER) STRING DATA_BUF & !& ! Enable Multicast Address layout: & !& \ MAP (ETHER) STRING ADDRESS(5%) = 6% & !& ! Transfer Circuit Counters layout: & !& \ MAP (ETHER) WORD CUR_DATE, & CUR_TIME, & ZER_DATE, & ZER_TIME, & LONG BYTES_RECEIVED, & BYTES_SENT, & CIR_PACKETS_RECEIVED, & CIR_PACKETS_SENT, & WORD CIR_BUFFER_UNAVAILABLE & !& ! Transfer Line Counters layout: & !& \ MAP (ETHER) STRING FILL = 16%, !Same as circuit & LONG BYTES_MULTICAST, & LINE_PACKETS_RECEIVED, & LINE_PACKETS_SENT, & MULTICAST_RECEIVED, & DEFERRED_PACKETS, & SINGLE_COLLISIONS, & MULTIPLE_COLLISIONS, & WORD TRANSMIT_FAILURES, & TRANSMIT_FAILURE_FLAGS, & COLLISION_FAILURES, & RECEIVE_FAILURES, & RECEIVE_FAILURE_FLAGS, & PROTOCOL_FAILURES, & DATA_OVERRUN, & SYSTEM_BUFFER_UNAVAILABLE, & LINE_BUFFER_UNAVAILABLE & 999 ON ERROR GOTO 19000 !Standard error trap & \ I = CTRLC !Trap CTRL/C's & 1000 CHNL = 1% !Channel to use & \ READ_LOOP = 0% & \ CMASK = " ########## 'E" !Counters mask & \ HEX.SET = "0123456789ABCDEF" & !& ! Set up the character display set. Most characters are & ! printable, but the ones that aren't will display as: & ! & !& ! Use the full 8-bit character set if possible & !& \ READ ASCII.SET(I) FOR I = 0% TO 31% & \ ASCII.SET(I) = CHR$(I) FOR I = 32% TO 126% & \ READ ASCII.SET(I) FOR I = 127% TO 159% & \ TEMP = SYS(CHR$(6%)+CHR$(16%)+CHR$(0%)+CHR$(255%)) & \ J = (ASCII(SEG$(TEMP,29%,29%)) = 24%) & \ FOR I = 160% TO 254% & \ IF J & THEN ASCII.SET(I) = CHR$(I) & ELSE ASCII.SET(I) = "X" + FN.HEX(I) & 1010 NEXT I & \ ASCII.SET(255%) = "X" + FN.HEX(255%) & !& \ ASCII.SET(I) = "<" + ASCII.SET(I) + ">" & IF LEN(ASCII.SET(I)) <> 1% & FOR I = 0% TO 255% & !& \ DATA NUL,SOH,STX,ETX,EOT,ENQ,ACK,BEL, & BS,HT,LF,VT,FF,CR,SO,SI, & DLE,DC1,DC2,DC3,DC4,NAK,SYN,ETB, & CAN,EM,SUB,ESC,FS,GS,RS,US,DEL, & X80,X81,X82,X83,IND,NEL,SSA,ESA, & HTS,HTJ,VTS,PLD,PLU,RI,SS2,SS3, & DCS,PU1,PU2,STS,CCH,MW,SPA,EPA, & X98,X99,X9A,CSI,ST,OSC,PM,APC & 1100 INPUT "Ethernet device ";DEV & \ PRINT & !& ! Parse the input and check for illegal things & !& \ FIRQB = SYS(CHR$(6%)+CHR$(-10%)+DEV) & \ GOTO 1100 IF FLAG2 AND (1%+8%+128%+1024%+(1%+32767%)) & \ GOTO 1100 IF FLAG1 AND 4% & !& ! Reconstruct the file spec using the defaults as needed & !& \ DEV = FQDEV & \ DEV = "XE" UNLESS FLAG2 AND 8192% & \ DEV = DEV + NUM1$(FQDEVN) IF FQDEVF & \ DEV = DEV + ":" & \ FQCLUS = 4% UNLESS FLAG1 AND 1% & \ FQMODE = 0% UNLESS FLAG1 AND 2% & \ FQNENT = 1632% UNLESS FLAG1 AND 8% & \ DEV = DEV + "/CL:" + NUM1$(FQCLUS) & + "/PO:" + NUM1$(FQNENT) & + "/MO:" + NUM1$(FQMODE AND 32767%) & \ PADDED = ((FQMODE AND 128%) = 0%) * -2% & 1200 OPEN DEV AS FILE CHNL, MAP ETHER, RECORDSIZE 1514% & !& ! Its open. Make sure its an Ethernet device & !& \ IF (STATUS AND 255%) <> 40% & THEN PRINT "That device is not an Ethernet device." & \ PRINT & \ CLOSE CHNL & \ GOTO 1100 & 1210 IF PADDED & THEN REMAP (ETHER) & STRING FILL = 16%, & DATA_BUF = 1498% & ELSE REMAP (ETHER) & STRING FILL = 14%, & DATA_BUF = 1500% & 1300 INPUT "[R]ead, S[T]alled Read, [W]rite, [S]pec, or xit";CMD & \ PRINT & \ CMD = SEG$(EDIT$(CMD,2%+4%+32%),1%,1%) & \ CMD = "E" UNLESS LEN(CMD) & \ ON POS("ERTWS",CMD,1%) GOSUB 32000,1500,1600,1700,1800 & OTHERWISE 1400 & \ GOTO 1300 & 1400 RETURN & 1500!& ! The normal read command will begin reading immediately & ! without stalling for a receive to occur. If a receive & ! does occur, then we will continue with further receives & ! until there is no more data to be gotten. & !& I = 0% & \ GOTO 1650 & 1600!& ! The stalled read command works just like the normal & ! read except that the job will stall if no receive is & ! initially pending. & !& I = 8192% & 1650!& ! The minimum buffer size should be 16 bytes. The & ! program allows smaller sizes in order to test & ! the driver interface. (Force a MAGRLE) & !& INPUT "Length of buffer to use for receive [0-<1514>]";CMD & \ PRINT & \ BUF_LEN = 1514% & \ BUF_LEN = VAL%(CMD) IF LEN(CMD) & \ GOTO 1650 IF (BUF_LEN < 0%) OR (BUF_LEN > 1514%) & \ READ_LOOP = -1% & 1660 CALL EREAD( CHNL, ETHER, BUF_LEN, I ) & 1670!& ! Read successful, or record length error. Dump out & ! what we got, then see if there's more data to get. & !& BCOUNT = BCOUNT - 14% - PADDED & \ GOSUB 15000 & \ PRINT & \ I = 0 ! (Don't stall from now on) & \ GOTO 1660 IF READ_LOOP & \ RETURN & 1700!& ! The write command allows you to send to any Ethernet & ! address. This address could be a real physical address & ! or a multicast address (to which several controllers & ! could be listening.) & !& INPUT "Destination address";TEMP & \ PRINT & \ TEMP = EDIT$(TEMP,2%+4%+32%) & \ RETURN UNLESS LEN(TEMP) & \ TEMP = FN.CVT_TO_HEX(TEMP) & \ GOTO 1700 UNLESS LEN(TEMP) & \ DEST = TEMP & 1710 PRINT "Data for transmission"; & \ INPUT LINE TEMP & \ PRINT & \ GOTO 1700 IF EDIT$(TEMP,4%) = "" & \ DATA_BUF = TEMP & 1720!& ! The minimum buffer size to use is 60 bytes. The & ! program allows fewer smaller sizes in order to test & ! the interface. & !& INPUT "Length of buffer to use for xmit [0-<1514>]";CMD & \ PRINT & \ BUF_LEN = 1514% & \ BUF_LEN = VAL%(CMD) IF LEN(CMD) & \ GOTO 1720 IF (BUF_LEN < 0%) OR (BUF_LEN > 1514%) & 1730 I = LEN(TEMP) & \ PRINT "Number of bytes of the DATA to transmit [0-"; & NUM1$(1498 + PADDED); "] <"; NUM1$(I); ">"; & \ INPUT CMD & \ PRINT & \ I = VAL%(CMD) IF LEN(CMD) & \ GOTO 1730 IF (I < 0%) OR (I > (1498% + PADDED)) & \ BCOUNT = I & \ I = I + 6% + 6% + 2% + PADDED & 1740 CALL EWRITE( CHNL, ETHER, BUF_LEN, I ) & !& ! Transmit successful. Go print out the details and & ! see if the user want to send more data & !& \ GOSUB 15100 & \ PRINT & \ GOTO 1710 & 1800 INPUT "[A]ddress, [M]ulticast, [C]ircuit, [L]ine, or xit";CMD & \ PRINT & \ CMD = SEG$(EDIT$(CMD,2%+4%+32%),1%,1%) & \ CMD = "E" UNLESS LEN(CMD) & \ RETURN IF CMD = "E" & \ ON POS("AMCL",CMD,1%) GOSUB 2000, 2100, 2200, 2300 & OTHERWISE 1900 & \ GOTO 1800 & 1900 RETURN & 2000!& ! Change Physical Address. This is only allowed if the & ! user is the SOLE user of the Ethernet device. DECNET, & ! when running, grabs the controller and changes the & ! address before anyone else can open it as well. & !& INPUT "New physical address";TEMP & \ PRINT & \ TEMP = FN.CVT_TO_HEX(EDIT$(TEMP,2%+4%+32%)) & \ GOTO 2000 UNLESS LEN(TEMP) & \ DEST = TEMP & 2010 CALL CHGPHY( CHNL, DEST ) & \ RETURN & 2100!& ! Enable Multicast Address(es). This functions sets up & ! additional addresses to listen to in addition to the & ! controller's physical address. Note that each device & ! has a limit as to how many addresses it can handle, and & ! once that limit is reached, the driver has to enable & ! all multicast addresses and filter them itself. & !& ! A maximum of 5 multicast addresses are allowed, but the & ! program allows the attempt to set 6 to test the drivers & !& FOR J = 0% WHILE J < 6% & 2110 PRINT "Enter multicast address #";NUM1$(J+1%); & \ INPUT TEMP & \ PRINT & \ GOTO 2120 UNLESS LEN(TEMP) & \ TEMP = FN.CVT_TO_HEX(EDIT$(TEMP,2%+4%+32%)) & \ GOTO 2110 UNLESS LEN(TEMP) & \ ADDRESS(J) = TEMP & \ NEXT J & 2120 CALL ENBMUL( CHNL, ETHER, J ) & \ RETURN & 2200!& ! Read Circuit Counters. The circuit counters are the & ! counters specific only to the open portal (This job). & !& GOSUB 2400 !Check for zeroing & \ RETURN IF BUF_LEN < 0% !CTRL/Z typed & \ CALL XFRCIR( CHNL, ETHER, BUF_LEN, I ) & 2210 PRINT "Circuit counters:" & \ PRINT & \ PRINT USING CMASK, & BYTES_RECEIVED, "Bytes Received", & BYTES_SENT, "Bytes Sent", & CIR_PACKETS_RECEIVED, "Data Blocks Received", & CIR_PACKETS_SENT, "Data Blocks Sent", & CIR_BUFFER_UNAVAILABLE, "User Buffer Unavailable" & \ PRINT & \ RETURN & 2300!& ! Read Line Counters. The line counters are the counters & ! for the whole Ethernet controller. Be careful if you & ! zero them! & !& GOSUB 2400 !Check for zeroing & \ RETURN IF BUF_LEN < 0% !CTRL/Z typed & \ CALL XFRLIN( CHNL, ETHER, BUF_LEN, I ) & 2310 PRINT "Line counters:" & \ PRINT & \ PRINT USING CMASK, & BYTES_RECEIVED, "Bytes Received", & BYTES_SENT, "Bytes Sent", & BYTES_MULTICAST, "Mulitcast Bytes Received", & LINE_PACKETS_RECEIVED, "Data Blocks Received", & LINE_PACKETS_SENT, "Data Blocks Sent", & MULTICAST_RECEIVED, "Multicast Blocks Received", & DEFERRED_PACKETS, "Blocks Sent, Initially Deferred", & SINGLE_COLLISIONS, "Blocks Sent, Single Collision", & MULTIPLE_COLLISIONS, "Blocks Sent, Multiple Collisions", & TRANSMIT_FAILURES, "Send Failures", & TRANSMIT_FAILURE_FLAGS, "Send Failure Flags", & COLLISION_FAILURES, "Collision Detect Check Failures", & RECEIVE_FAILURES, "Receive Failures", & RECEIVE_FAILURE_FLAGS, "Receive Failure Flags", & PROTOCOL_FAILURES, "Unrecognized Frame Destinations", & DATA_OVERRUN, "Data Overruns", & SYSTEM_BUFFER_UNAVAILABLE, "System Buffer Unavailable", & LINE_BUFFER_UNAVAILABLE,"User Buffer Unavailable" & \ PRINT & \ RETURN & 2400 BUF_LEN = -1% & \ INPUT "Clear counters after read [Y/N] ";CMD & \ PRINT & \ I = (SEG$(EDIT$(CMD,2%+4%+32%),1%,1%) = "Y") & 2410!& ! Allow various buffer lengths to test the drivers. They & ! will only return as many counters as you have room for, & ! and you cannot zero the counters unless you read all of & ! them. & !& INPUT "Length of buffer to use for transfer [0-<1514>]";CMD & \ PRINT & \ BUF_LEN = 1514% & \ BUF_LEN = VAL%(CMD) IF LEN(CMD) & \ GOTO 2410 IF (BUF_LEN < 0%) OR (BUF_LEN > 1514%) & \ RETURN & 10000 DEF STRING FN.CVT_TO_HEX(STRING ADDR) & !& ! This function converts a printable Ethernet address & ! into the internal format needed for command purposes. & !& ! Ethernet addresses are of the type 'A-B-C-D-E-F', where & ! each letter represents a pair of hexadecimal digits. & !& \ FN.CVT_TO_HEX = "" & \ GOTO 10010 UNLESS LEN(ADDR) = 17% & \ T. = "" & \ FOR I. = 1% TO 6% & \ J. = I. * 3% - 2% & \ T1. = SEG$(ADDR, J., J.) & \ T2. = SEG$(ADDR, J.+1%, J.+1%) & \ I1. = POS(HEX.SET,T1.,1%) - 1% & \ I2. = POS(HEX.SET,T2.,1%) - 1% & \ GOTO 10010 IF (I1. < 0%) OR (I2. < 0%) & \ T. = T. + CHR$(16% * I1. + I2.) & \ GOTO 10010 IF SEG$(ADDR, J.+2%, J.+2%) <> "-" & UNLESS I. = 6% & \ NEXT I. & \ FN.CVT_TO_HEX = T. & 10010 FNEND & 10100 DEF STRING FN.CVT_TO_ADDRESS(STRING ADDR) & !& ! This function convert the internal Ethernet address & ! format to the printable format. & !& \ T. = "" & \ FOR I. = 1% TO 6% & \ T. = T. + FN.HEX(ASCII(SEG$(ADDR, I., I.))) & \ T. = T. + "-" UNLESS I. = 6% & \ NEXT I. & \ FN.CVT_TO_ADDRESS = T. & \ FNEND & 10200 DEF STRING FN.HEX(WORD J) & !& ! Compute the hexadecimal equivalent of a byte. & !& \ I1. = (J / 16%) + 1% & \ I2. = (J AND 15%) + 1% & \ FN.HEX = SEG$(HEX.SET, I1., I1.) & + SEG$(HEX.SET, I2., I2.) & \ FNEND 15000!& ! Print out the details of a received message. & !& GOSUB 15100 & \ PRINT "Message : "; & \ FOR I = PADDED TO BCOUNT + PADDED - 1% & \ PRINT ASCII.SET(DATA_BUFFER(I) AND 255%); & \ IF CCPOS(0%) > 75% & THEN PRINT & \ PRINT " "; & 15010 NEXT I & \ PRINT IF CCPOS(0%) <> 21% & \ RETURN & 15100 PRINT "Source address : ";FN.CVT_TO_ADDRESS(SRC) & \ PRINT "Destination address: ";FN.CVT_TO_ADDRESS(DEST) & \ PRINT "Protocol type : ";NUM1$(PROTOCOL) & \ PRINT "Message length : ";NUM1$(BCOUNT) & \ RETURN & 19000 IF ERR = 28% !CTRL/C trap & THEN J = CTRLC & \ RESUME 32000 UNLESS READ_LOOP & \ PRINT & \ PRINT "Read cancelled" & \ PRINT & \ READ_LOOP = 0% & \ RESUME 1400 & 19100 IF ERR = 11% !CTRL/Z 'trap' & THEN PRINT & \ RESUME 32000 IF (ERL = 1100%) OR (ERL = 1300%) & \ RESUME 1400 IF (ERL = 1700%) OR (ERL = 1650%) & \ RESUME 1700 IF ERL = 1710% & \ RESUME 1710 IF ERL = 1720% & \ RESUME 1720 IF ERL = 1730% & \ RESUME 1900 IF (ERL = 1800%) OR (ERL = 2000%) & OR (ERL = 2100%) OR (ERL = 2110%) & OR (ERL = 2400%) & \ RESUME 2400 IF ERL = 2410% & 19200 IF ERR = 52% !Illegal number & THEN RESUME 1650 IF ERL = 1650% & \ RESUME 1720 IF ERL = 1720% & \ RESUME 1730 IF ERL = 1730% & \ RESUME 2100 IF ERL = 2100% & \ RESUME 2410 IF ERL = 2410% & 19300 IF ERR = 40% !Record length error, continue & THEN RESUME 1670 IF ERL = 1660% & \ RESUME 2210 IF ERL = 2200% & \ RESUME 2310 IF ERL = 2300% & 19400 IF ERR = 10% !Protection violation & THEN IF (ERL = 2010%) OR (ERL = 2200%) & OR (ERL = 2300%) & THEN PRINT "SWCTL privilege required" & \ PRINT & \ RESUME 1900 & 19500 IF ERR = 2% !Illegal file name & THEN IF (ERL = 2010%) OR (ERL = 2120) & THEN PRINT "Illegal address specified" & \ PRINT & \ RESUME 1900 & 19600 RESUME 1100 IF ERL = 1100% !Trap any FSS errors & \ GOTO 19700 IF ERL <> 1200% !Errors on OPEN & \ IF ERR = 3% & THEN PRINT "Protocol in use on device" & ELSE IF ERR = 14% & THEN PRINT "Device disabled" & ELSE IF ERR = 32% & THEN PRINT "Not enough system buffers" & ELSE IF ERR = 6% & THEN PRINT "Not a valid device" & ELSE ON ERROR GOTO 0 & 19610 PRINT & \ RESUME 1100 & 19700 IF ERL = 1660% !Errors in receive & THEN RESUME 1400 IF ERR = 5% UNLESS I = 8192% & \ PRINT "Error #";NUM1$(ERR);" during read" & \ PRINT & \ RESUME 1660 IF ERR = 13% !Missed packet & \ RESUME 1400 & 19800 IF ERL = 1740 !Errors in transmit & THEN PRINT "Error #";NUM1$(ERR);" during write" & \ PRINT & \ RESUME 1710 & 19900 IF (ERR = 3%) AND (ERL = 2010%) & THEN PRINT "Device open on another portal" & \ PRINT & \ RESUME 1900 & 19950 IF (ERL = 2010%) OR (ERL = 2120%) OR (ERL = 2200%) & OR (ERL = 2300%) & THEN PRINT "Error #";NUM1$(ERR);" during .SPEC" & \ PRINT & \ RESUME 1900 & 19999 ON ERROR GOTO 0 !Catch anything we missed & 32000 CLOSE CHNL !All done & 32767 END !Good-bye cruel world.