TITLE 'PACKET TRANSMISSION / RECEPTION PROGRAM' ; 11-8-80 ; LAST MODIFIED 4-12-81 ; ;WRITTEN BY DALE A. HEATHERINGTON, WA4DSY ; 3126 FLAMINGO DR. ; DECATUR, GA 30033 ; tel: 404-292-1499 ; ;*************************************************************** ;This program has not been perfected and probably has a few bugs ;in it. It is for the 2.2 version of CP/M only. At this time ;(4-19-81) it has been used by only 2 stations in the Atlanta Ga. ;area so I have no idea what will happen when several stations ;get into a "pile up" . The program could become confused. There ;are several fields in the packet which have no function now and ;may be changed later. There are some packet types which have not ;been implemented ie: FS (file seperator). Also beware of comments ;;which don't match the code..... ;Consider this version (1.8) to be in PUBLIC DOMAIN for non-commercial ;use and distribution. This might not be true for future versions. ;******************************************************************** ;THIS PROGRAM MUST BE ASSEMBLED WITH THE ;CP/M RELOACATING MACRO ASSEMBLER (RMAC) AND THE ;MACRO LIBRARY "SEQIO.LIB" MUST BE AVALABLE. ;NOTE: SEQIO.LIB WILL NOT WORK WITH RMAC UNLESS ;MODIFICATIONS ARE MADE. MACLIB SEQIO2 ;MODIFIED SEQIO.LIB VERSION EQU '1' PTVER EQU '8' ;VERSION 1.8 ON EQU 1 OFF EQU 0 ; ;--------------------------------------------------------; ; ; PACKET LAYOUT ; ; BYTE # BYTES DESCRIPTION ; 1 4 LEADER FF,7FH,1FH,7 ; 5 1 SOH START OF HEADER ; 6 2 TOTAL LENGTH OF MESSAGE (STARTING AT CRC) ; 8 2 CRC BYTES (LOW BYTE FIRST) ; 10 6 DESTINATION CALL SIGN ; 16 1 DESTINATION PHYSICAL LOCATION CODE ; 17 1 DESTINATION REPEATER # (0 = DIRECT) ; 18 6 SOURCE CALL SIGN ; 24 1 SOURCE PHYSICAL LOCATION CODE ; 25 1 SOURCE REPEATER # (0= DIRECT) ; 26 1 PACKET TYPE (ENQ,ACK,NAK,FS,DTA,FRQ,EOT) ; 27 12 PACKET NAME (CP/M FILE NAME) ; 39 2 PACKET NUMBER ( 0..65535 ) ; 41 0..1024 DATA BYTES ; ;NOTES: CRC IS CRC-16 REVERSE X^16+X^14+X+1 (SAME AS CLINK 3.0) ; ; THE PACKET NAME CONFORMS TO CP/M FILE CONTROL BLOCK FORMAT ; THE FIRST CHARACTER IS THE DRIVE INDICATOR (0=DEFAULT DRIVE) ; THE NEXT 8 ARE THE FILE NAME PADDED WITH TRAILING BLANKS. ; THE LAST 3 ARE THE FILE TYPE ; ; ALL PACKETS TYPES EXCEPT DATA HAVE A PACKET NUMBER OF ZERO. ; DATA PACKETS START WITH PACKET NUMBER 1 AND ARE TRANSMITTED ; IN SEQUENCE. ; ; FOUR RETRYS ARE ALLOWED IF PACKETS ARE "NAK'ED" ; ; PACKET TYPES ; ; ENQ REQUEST TO ESTABLISH COMMUNICATION AND SEND A FILE ; FRQ REQUEST A FILE ; FNF FILE NOT FOUND ; DTA PACKET CONTAINS DATA ; EOT END OF TRANSMISSION ; FS FILE SEPERATOR ; ACK ACKNOWLEDGE RECEIVING PACKET ; NAK DID NOT RECEIVE PACKET ; NAV RECEIVED ENQ BUT NOT AVALABLE TO RECV. DATA ; ;---------------------------------------------------------------------; SYN EQU 255 DTA EQU 0 SOH EQU 1 FRQ EQU 3 EOT EQU 4 ENQ EQU 5 ACK EQU 6 FNF EQU 7 NAV EQU 8 NAK EQU 15H FS EQU 1CH NULL EQU 0 CR EQU 0DH LF EQU 0AH BDOS EQU 5 FCB EQU 5CH CPMBOOT EQU 0 CRCPLY EQU 8005H HDRLEN SET TDATA-TCRC ;HEADER LENGTH ; CRC TO DATA ;ENTRY LOCATIONS IN THIS MODULE PUBLIC RECVIT PUBLIC SENDIT ;EXTERNAL ENTRY LOCATIONS EXTRN CPUCLK ;CPU CLOCK RATE IN MHZ EXTRN INITX ;INITIALIZE FOR XMITTING EXTRN INIRX ;INITIALIZE FOR RECEIVING EXTRN SENDCHR ;SEND A BYTE (IN REG. C ) EXTRN RECVCHR ;GET A BYTE (IN REG. A) EXTRN RXSTAT ;RETURN NON ZERO IF BYTE READY EXTRN RFON ;KEY TRANSMITTER EXTRN RFOFF ;UNKEY TRANSMITTER EXTRN CKCD ;RETURN NON ZERO IF CARRIER EXTRN TONEON ;AUDIO SUBCARRIER ON EXTRN TONEOFF ;AUDIO SUBCARRIER OFF EXTRN WAIT1 ;WAIT 1 MILLISECOND EXTRN MYCALL ;USERS CALL SIGN EXTRN MYLOC ;USERS LOCATION CODE EXTRN QUIT ;PATH BACK TO CP/M ;-------------------------------------------------------- ;HERE ARE SOME STRING CONSTANTS WHO$R$U: DB '????????????' ;12 QUESTION MARKS NOFN: DB 0,' ' ;0+11 BLANKS (A BLANK FILE NAME) DIRFILE:DB 0,'DIR ' ;SPECIAL CASE FOR DIRECTORY SYNCS: DB 0FFH,07FH,01FH,7,SOH ;PREAMBLE FOR PACKETS ;---------------------------------------------------------- ;CODE STARTS HERE INIBUFFR: ;INITIALIZE TX BUFFER LEADER LXI H,SYNCS LXI D,TBUFFR MVI B,5 CALL MOVE RET CLEARBUF: ;CLEARS RECEIVE BUFFER HEADER MVI B,RDATA-RBUFFR ;LENGTH OF HEADER LXI H,RBUFFR ;RECEIVE HEADER LXI D,RBUFFR+1 JMP MOVE ;CLEAR RECEIVE HEADER ;THIS IS THE FILE TRANSMITTING ROUTINE SENDIT: MVI A,0 STA ID$INH ;DONT INHIBIT NEXT CW ID SENDIT2:CALL INIBUFFR LXI H,MYCALL MVI B,6 CALL PRNMEM ;PRINT OUR CALL SIGN CALL PRINT DB ' PACKET TRANSMISSION PROGRAM VER. ',VERSION,'.',PTVER,CR CALL PRINT DB 'CPU CLOCK(MHZ) = @' LDA CPUCLK ADI 30H MOV C,A CALL CONOUT ;PRINT CPU CLOCK CONSTANT CALL CRLF LXI H,HDRLEN ;GET LENGTH OF ENQ PACKET SHLD TLEN ;PUT IT IN BUFFER MVI A,ENQ STA TPTYPE ;PUT PACKET TYPE IN BUFFER LXI H,FCB+17 ;GET DESTINATION CALL SIGN LXI D,TDSTCAL MVI B,6 CALL MOVE MVI A,4 ;GET LOCATION CODE STA TDSTLOC MVI A,0 ;NON REPEATER STA TDSTRPT LXI H,MYCALL ;GET OUR CALL SIGN LXI D,TSRCCAL MVI B,6 CALL MOVE ;PUT IT IN XMIT BUFFER LDA MYLOC ;GET OUR LOCATION CODE STA TSRCLOC ;PUT IT IN BUFFER MVI A,0 STA TSRCRPT ;REPEATER # IS ZERO LXI H,FCB ;GET FILE NAME LXI D,TTITLE MVI B,12 CALL MOVE ;PUT IT IN BUFFER SUB A STA TTITLE ;DESTINATE IT TO DEFAULT DRIVE LXI H,0 SHLD TPACNUM ;ZERO THE PACKET NUMBER LXI H,TTITLE+1 ;SEE IF DIRECTORY REQUEST "DIR" LXI D,DIRFILE+1 MVI B,11 CALL COMPARE$ JNZ REALFILE ;JUMP IF NOT DIRECTORY REQUEST MVI A,255 STA DIRFLAG ;SET DIRECTORY FLAG CALL OPEN$DIR ;SET UP DIRECTORY ROUTINE JMP FIRSTID ;START SENDING REALFILE: MVI A,0 STA DIRFLAG ;CLEAR DIRECTORY FLAG FILE SETFILE,CHECK,,1,, DIRECT CHECK ;SEE IF THE FILE IS THERE JNZ GOTIT ;JUMP IF WE FOUND IT CALL PRINT DB 'FILE NOT FOUND',CR MVI A,1 ;RETURN A=1 IF NOT FOUND ORA A RET GOTIT: FILE INFILE,SOURCE,,1,,1024,INBUFFER FIRSTID: CALL CWID ;ID IN (YUK) MORSE CODE FOR FCC CALL SENDPAC ;SEND THE BUFFER CONTENTS (ENQ PACKET) JZ OK2SEND CALL NORPLY ;SAY HE'S NOT HOME RET ;QUIT OK2SEND:LXI H,1 ;SET PACKET NUMBER TO 1 SHLD TPACNUM TXLP: LXI H,1024 ;MAX DATA LENGTH SHLD DATACNT LXI H,TDATA ;POINTER TO XMIT DATA BUFFER SHLD DATAPTR LXI H,HDRLEN ;RESET LENGTH FIELD SHLD TLEN FILBUF: LDA DIRFLAG ORA A ;DIRECTORY OR FILE?? JZ FLB1 ;JMP IF FILE ;ELSE... CALL GETABYTE ;GET A BYTE FROM DIRECTORY JMP FLB2 FLB1: GET SOURCE ;GET A BYTE FROM SOURCE FILE FLB2: JZ DONE LHLD DATAPTR MOV M,A ;PUT IT IN BUFFER INX H ;ADVANCE POINTER SHLD DATAPTR ;SAVE IT LHLD TLEN INX H ;ADVANCE LENGTH FIELD SHLD TLEN LHLD DATACNT DCX H SHLD DATACNT MOV A,L ORA H ;SEE IF WE DID 1024 BYTES JNZ FILBUF MVI A,DTA STA TPTYPE ;PACKET TYPE IS DATA CALL SENDPAC ;NOW TRANSMIT THE PACKET JNZ ERRR LHLD TPACNUM INX H SHLD TPACNUM ;COUNT THE PACKET MOV A,L DCR A ANI 7 ;ID IN CW EVERY 8TH PACKET CZ CWID JMP TXLP ;GO BACK TO DO ANOTHER PACKET DONE: LHLD TLEN ;SEE IF LENGTH IS ZERO LXI D,-HDRLEN DAD D MOV A,L ORA H JZ SNDEOT ;IF ZERO LENGTH JUST DO EOT MVI A,DTA ;ELSE SEND SHORT DATA PACKET STA TPTYPE CALL SENDPAC JNZ ERRR ;QUIT IF BAD OR NO RESPONSE SNDEOT: MVI A,EOT SND2: STA TPTYPE LXI H,HDRLEN ; SHLD TLEN ;SET LENGTH LXI H,0 ;CONTROL PACKETS HAVE NUMBER 0 SHLD TPACNUM CALL SENDPAC ;SEND LAST PACKET PUSH PSW CALL CWID ;LET FCC KNOW WHO WE ARE POP PSW JNZ ERRR CALL PRINT DB 'ALL PACKETS SENT',CR XRA A ;RETURN ZERO IF OK RET ERRR: CALL PRINT DB 'TRANSMISSION ABORTED',7,CR MVI A,255 ORA A RET ;RETURN NON ZERO IF ERROR ;THIS IS THE FILE REQUEST ROUTINE ;COME HERE IF PACKET IS REQUESTING A FILE FROM US. ; FLREQ: CALL CWID ;ID IN CRUDE MORSE CODE MVI A,ACK STA TPTYPE CALL SENDAPAC ;ACK HIS FILE REQUEST LXI H,RSRCCAL ;GET HIS CALL SIGN LXI D,FCB+17 MVI B,6 CALL MOVE ;MOVE IT TO FCB MVI A,1 STA ID$INH ;INHIBIT NEXT CW ID CALL SENDIT2 ;SEND THE FILE IF WE HAVE IT RZ ;QUIT NOW IF FILE WAS SENT CPI 1 ;SEE IF THE FILE WAS NOT IN DIR RNZ ;RETURN IF JUST BAD SIGNALS MVI A,FNF ;ELSE SEND FILE NOT FOUND PACKET STA TPTYPE LXI H,HDRLEN SHLD TLEN ;INIT HEADER LENGTH LXI H,0 SHLD TPACNUM ;SET PACKET NUMBER TO ZERO CALL SENDAPAC ;SEND THE FNF PACKET CALL CWID XRA A RET ;ALL DONE ;THIS SENDS A FILE REQUEST PACKET TO THE OTHER GUY IF ;WE WANTED TO GET A FILE FROM HIM. ; SENDFRQ: LXI H,HDRLEN SHLD TLEN MVI A,FRQ STA TPTYPE LXI H,MYCALL LXI D,TSRCCAL MVI B,6 ;SET UP SOURCE CALL CALL MOVE LXI H,FCB+17 ;GET DESTINATION CALL LXI D,TDSTCAL MVI B,6 CALL MOVE MVI A,0 STA TSRCRPT MVI A,14H ;DEST. LOCATION CODE STA TDSTLOC LDA MYLOC STA TSRCLOC LXI H,FCB LXI D,TTITLE ;GET FILE NAME MVI B,12 CALL MOVE LXI H,0 SHLD TPACNUM ;CLEAR PACKET NUMBER CALL CWID CALL SENDPAC ;SEND FRQ PACKET AND GET REPLY RET ;RETURN ZERO WITH PACKET TYPE IN ACC ;------------------------------------------------------------------- ; TITLE 'DIRECTORY LISTER' ;THIS IS A SELF CONTAINED SUBROUTINE WHICH WILL ;RETURN THE CP/M DIRECTORY A BYTE AT A TIME BY ;CALLING "GETABYTE". ;THE ZERO FLAG WILL BE SET AFTER THE LAST BYTE ;IS RETURNED. ;THE SUBROUTINE MUST BE INITIALIZED BY ;CALLING "OPEN$DIR" FIRST. SETDMA EQU 26 SEARCH EQU 17 SEARCH$NEXT EQU 18 GET$ALLOC EQU 27 GET$DPBLK EQU 31 DIRFCB: DB 0 ;DR DB '???????????',0 DS 20 PWR10: DW -1000 DW -100 DW -10 DW -1 DSEG ;DATA SEGMENT N1: DS 0 SWITCH: DS 1 KLEFT: DS 2 ;K BYTES LEFT ON DISK ENCNT: DS 1 COUNTER:DS 1 DPBADR: DS 2 ;ADDRESS OF DISK PARAMETER BLOCK POINTER:DS 2 ENTBUF: DS 16 ;BUFFER FOR 1 DIR. ENTRY BUFFER: DS 128 ;------------------------------------------------------------- CSEG ;CODE SEGMENT ;RETURNS HL POINTING TO NEXT DIRECTORY ENTRY ;A=ZERO IF OK OR 255 IF NO MORE ENTRYS GET$ENTRY: LDA SWITCH ORA A JZ SNXT ;DO SEARCH NEXT IF ZERO MVI C,SETDMA LXI D,BUFFER CALL BDOS ;SET UP DIRECTORY BUFFER LXI D,DIRFCB MVI C,SEARCH ;SEARCH FOR FIRST ENTRY CALL BDOS JMP GE2 SNXT: LXI D,DIRFCB MVI C,SEARCH$NEXT CALL BDOS ;SEARCH FOR NEXT ENTRY GE2: CPI 255 ;DONE? RZ ADD A ;MPY BY 32 ADD A ADD A ADD A ADD A MOV E,A MVI D,0 LXI H,BUFFER DAD D XRA A STA SWITCH ;CLEAR THE SWITCH RET ;A=0 HL->ENTRY ;------------------------------------------------------------- OPEN$DIR: ;INITIALIZE DIRECTORY LISTER MVI A,255 STA SWITCH MVI A,4 ;INIT ENTRY COUNTER STA ENCNT MVI A,1 STA COUNTER LXI H,ENTBUF SHLD POINTER ;AT NO EXTRA CHARGE WE NOW GIVE YOU THE NUMBER OF K BYTES ;LEFT ON THE DISK... RETURNED IN HL MVI C,GET$DPBLK ;GET DISK PRAM. BLOCK ADDRESS CALL BDOS SHLD DPBADR ;SAVE IT LXI D,5 DAD D ;POINT TO DISK CAPACITY MOV E,M ;GET IT INX H MOV D,M PUSH D ;SAVE IT MVI C,GET$ALLOC CALL BDOS ;GET ADDRESS OF ALLOCATION MAP POP B PUSH B ;GET AND SAVE DISK CAPACITY LXI D,0 ; BLOCK COUNTER CNTK: MOV A,M ;GET 8 ALLOCATION UNIT BITS PUSH H ;SAVE POINTER MVI L,8 MOV H,A ;BITS OF ALLOCATION TO H CBITS: MOV A,H ADD A ;SHIFT OVER A BIT MOV H,A JNC ZEROB INX D ;COUNT THE ONE'S ZEROB: DCX B ;COUNT A BLOCK MOV A,C ORA B JZ NOMORE DCR L ;COUNT BITS JNZ CBITS ;LOOP 8 TIMES POP H ;GET POINTER BACK INX H JMP CNTK ;LOOP NOMORE: POP H MOV A,E ;TWOS COMPLIMENT BLOCKS USED CMA MOV E,A MOV A,D CMA MOV D,A INX D POP H ;GET MAX DISK CAPACITY DAD D ;ADD THE -KBYTES USED INX H ;CORRECTION PUSH H ;PUSH BLOCKS USED ON STACK LHLD DPBADR ;GET ADDRESS OF DISK PARAMETER BLOCK LXI D,2 DAD D ;POINT TO BLOCK SHIFT FACTOR MOV A,M ;GET IT SUI 3 ;REMOVE BIAS POP H ;GET BLOCKS LEFT KLOOP: ORA A ;TEST FOR ZERO JZ KDONE DAD H ;SHIFT HL DCR A JMP KLOOP KDONE: SHLD KLEFT ;SAVE THE NUMBER RET ;------------------------------------------------------------- GETABYTE: ;GET 1 CHARACTER OF DIRECTORY LXI H,COUNTER DCR M JZ ANOTHER LHLD POINTER MOV A,M INX H SHLD POINTER ORA A ;RETURN NON ZERO IF NOT DONE RET ANOTHER: LXI H,ENTBUF ;CLEAR ENTRY BUFFER POINTER SHLD POINTER CALL GET$ENTRY CPI 255 JZ PUTK ;DONE, SAY HOW MANY BYTES LEFT NOW MVI B,8 LXI D,ENTBUF AN1: INX H MOV A,M ;MOVE FILE NAME TO BUFFER STAX D INX D DCR B JNZ AN1 MVI A,' ' MVI B,4 AN2: STAX D INX D INX H MOV A,M DCR B JNZ AN2 XCHG LDA ENCNT ;GET ENTRY COUNT DCR A JNZ AN3 ;END OF LINE IF ZERO CALL EOL JMP GETABYTE AN3: STA ENCNT MVI M,' ' ;ELSE PUT UP FENCE INX H MVI M,':' INX H MVI M,' ' MVI A,16 STA COUNTER JMP GETABYTE EOL: MVI M,0DH INX H MVI M,0AH INX H MVI A,15 STA COUNTER MVI A,4 STA ENCNT RET PUTK: LXI H,ENTBUF ;PUTS "XXXX K LEFT" IN BUFF CALL EOL SHLD POINTER LHLD KLEFT CALL DECONV ;CONVERT K TO DECIMAL & PUT IN BUFFER LHLD POINTER LXI D,KMSG MVI B,11 PKLP: LDAX D ;PUT IN " K LEFT " MOV M,A INX D INX H DCR B JNZ PKLP LXI H,ENTBUF SHLD POINTER MVI A,17 STA COUNTER JMP GETABYTE KMSG: DB ' K LEFT',0DH,0AH,0 ;-------------------------------------------------------------- ;CONVERT NUMBER IN HL TO DECIMAL STRING AND PUT IN BUFFER ;USING "POINTER" DECONV: SHLD N1 LXI H,PWR10 DECV0: MOV E,M INX H MOV D,M ;GET POWER OF 10 INX H PUSH H LHLD N1 MVI C,'0' DECV1: DAD D ;SUB POWER OF 10 FROM N1 JNC DECV2 INR C JMP DECV1 ;LOOP TIL IT GOES NEG. DECV2: MOV A,E CMA MOV E,A ;TWOS COMPLIMENT MOV A,D CMA MOV D,A INX D DAD D ;RESTORE TO + SHLD N1 LHLD POINTER MOV M,C ;OUTPUT DIGIT TO BUFFER INX H SHLD POINTER POP H MVI A,1 CMP E ;DONE YET? JNZ DECV0 RET ;END OF DIRECTORY LISTER ;-------------------------------------------------------------------- ; ;THIS IS THE FILE RECEIVE ROUTINE ; ; RECVIT: MVI A,0 STA ID$INH ;DONT INHIBIT NEXT CW ID CALL INIBUFFR LXI H,MYCALL MVI B,6 CALL PRNMEM ;PRINT OUR CALL SIGN CALL PRINT DB ' PACKET RECEPTION PROGRAM VER. ',VERSION,'.',PTVER,CR CALL PRINT DB 'CPU CLOCK(MHZ)= @' LDA CPUCLK ADI 30H MOV C,A CALL CONOUT CALL CRLF LDA 80H ;SEE IF FILE NAME WAS ENTERED ORA A JZ RCV0 ;JUMP IF NORMAL RECEIVE CALL SENDFRQ ;DO FILE REQUEST IF LENGTH NON ZERO RNZ ;RETURN IF BAD CPI ACK ;SEE IF HE HAD THE FILE RNZ ;RETURN AND QUIT IF NOT MVI A,1 STA ID$INH ;ALL OK, INHIBIT NEXT CW ID RCV0: LXI H,HDRLEN ;INIT THE TRANSMIT HEADER SHLD TLEN MVI A,ACK STA TPTYPE ;BE OPTIMISTIC LXI H,MYCALL LXI D,TSRCCAL ;PUT IN OUR CALL MVI B,6 CALL MOVE LDA MYLOC ;GET LOCATION CODE STA TSRCLOC MVI A,0 STA TSRCRPT ;WE ARE NOT A REPEATER (YET) STA TDSTLOC ;CLEAR THE DEST. LOC. CODE LXI H,WHO$R$U ;INIT. THE DEST. CALL WITH ?????? LXI D,TDSTCAL MVI B,6 CALL MOVE LXI H,NOFN ;CLEAR THE FILE NAME FIELD LXI D,TTITLE MVI B,12 CALL MOVE CALL PRINT DB 'WAITING FOR ENQ PACKET',CR LXI H,0 SHLD 80H ;CLEAR CP/M DEFAULT BUFFER SHLD TPACNUM ;CLEAR PACKET NUMBER LXI D,0 ;ZERO TELLS IT TO WAIT FOREVER CALL RECVPAC ;GET A PACKET JNZ RECVIT ;JUMP IF BAD CPI FRQ ;REQUEST FOR FILE? JZ RCV1 ;YES, THEN JUMP CPI ENQ JNZ RECVIT ;JUMP IF NOT ENQ RCV1: LXI H,RSRCCAL ;POINT TO SOURCE CALL SIGN LXI D,TDSTCAL ;MOVE IT TO DESTINATION MVI B,6 CALL MOVE CALL CKCALL ;SEE IF PACKET IS FOR US JNZ RECVIT ;NO, GO BACK LXI H,RTITLE ;GET FILE NAME TO FCB LXI D,FCB MVI B,12 CALL MOVE LDA RPTYPE ;CHECK PACKET TYPE AGAIN CPI FRQ ;FILE REQUEST? JNZ RXD3 ;YUP, PROCESS THAT INSTEAD CALL FLREQ LXI H,80H ;POINT TO CP/M DEFAULT BUFFER MVI M,0 ;CLEAR LENGTH BYTE JMP RECVIT ;AND GO BACK AND WAIT FOR ENQ RXD3: FILE OUTFILE,TEMP,,1,$$$,1024,OUTBUFFER ;OPEN THE TEMP. FILE FILE SETFILE,DEST,,1,, ;SET UP FOR REAL FILE LXI H,1 ;INIT THE SEQUENCE NUMBER SHLD SEQNUM ;FOR THE FIRST PACKET RXDLP2: CALL CWID ;WASTE TIME WITH PRIMITIVE MORSE CODE RXDLP1: MVI A,ACK ;NOW DO MODERN ASCII STUFF STA TPTYPE CALL SENDAPAC ;SEND ACK PACK RECVDATA: LXI D,15000 ;SET FOR 15 SEC TIMEOUT CALL RECVPAC ;GO GET A PACKET JNZ BADPAC CPI FS ;FS NOT REALLY IMPLIMENTED YET JZ CLOSEIT ;BUT CLOSE FILE ANYWAY CPI EOT JZ CLOSEIT CPI ENQ JZ RXDLP1 ;ACK THE EXTRA ENQ CPI DTA ;DATA? RNZ LHLD RLEN ;CHECK FOR ZERO LENGTH LXI D,-HDRLEN DAD D MOV A,L ORA H JZ RXDLP1 ;DISCARD ZERO LENGTH DATA PACKET LHLD SEQNUM ;CHECK FOR DUPLICATE PACKET LDA RPACNUM CMP L JNZ DISCARD ;DISCARD IF OUT OF SEQUENCE LDA RPACNUM+1 CMP H JNZ DISCARD INX H ;COUNT THIS PACKET SHLD SEQNUM ;UPDATE SEQUENCE NUMBER LXI D,-HDRLEN LHLD RLEN ;GET LENGTH DAD D ;DATA LENGTH=TOTAL-HEADER SHLD DATACNT ;SAVE DATA COUNT LXI H,RDATA ;DATA BUFFER POINTER SHLD DATAPTR ;SAVE IT RXDLP: LHLD DATAPTR MOV A,M ;PUT BUFFER CONTENTS ON DISK INX H SHLD DATAPTR PUT TEMP ;WRITE TO TEMPORARY FILE LHLD DATACNT DCX H SHLD DATACNT ;COUNT BYTES MOV A,L ORA H JNZ RXDLP ;LOOP TILL ZERO LDA SEQNUM ;GET LOW BYTE OF SEQUENCE NUMBER ANI 7 JZ RXDLP2 ;DO CW ID EVERY 8TH ACK JMP RXDLP1 ;SEND ACK AND DO IT AGAIN DISCARD: CALL PRINT DB 'EXTRA PACKET DISCARDED',CR JMP RXDLP1 CLOSEIT: FINIS TEMP ERASE DEST RENAME DEST,TEMP MVI A,ACK STA TPTYPE ;SEND FINAL ACK CALL SENDAPAC CALL CWID ;FINAL CW ID CALL PRINT DB 'FILE RECEIVED',CR LXI H,80H MVI M,0 JMP RECVIT ;GO WAIT FOR ENQ AGAIN BADPAC: FINIS TEMP ERASE TEMP CALL PRINT DB 'TOO MANY ERRORS, RECEPTION ABORTED',7,CR LXI H,80H MVI M,0 JMP RECVIT ;WAIT FOR A SYNC STREAM FOLOWED BY SOH ;"TIME" HAS TIMEOUT VALUE IN MS ;"TIME"= ZERO MEANS WAIT FOREVER ; WAITSOH: CALL RFOFF ;BE SURE WE DONT TRANSMIT CALL INIRX ;INIT MODEM FOR RECEIVE LHLD TIME SHLD TEMPTIME ;GET TIMEOUT VALUE WSOH3: CALL CKCRLC ;CHECK FOR CONTROL C CALL COUNTDOWN ;DO TIMEOUT TEST RZ ;RETURN ZERO IF TIMEOUT CALL RXSTAT ;CHECK FOR A CHARACTER ORA A JZ WSOH3 ;LOOP BACK IF WE DONT HAVE ONE LXI H,LEADBB+1 ;LEADIN BUFFER END POINTER LXI D,LEADBB ;LEADIN START POINTER MVI B,4 ;NUMBER OF BYTES TO SHIFT CALL MOVE ;SHIFT BYTES OVER LXI D,1 ;1 MS TIMEOUT (CHAR. THERE ALREADY) CALL RECVCHR ;GET THE CHARACTER STA LEADBE ;STORE AT END OF BUFFER LXI H,LEADBB ;ADDRESS OF UNKNOWN STRING LXI D,SYNCS ;THIS IS WHAT WERE LOOKING FOR MVI B,5 ;WE WANT TO CHECK 5 CHARACTERS CALL COMPARE$ ;NOW COMPARE SYNCS WITH UNKNOWN JNZ WSOH3 ;NO MATCH, LOOP BACK MVI A,SOH ;RETURN WITH SOH MEANS WE GOT IT RET COUNTDOWN: LHLD TEMPTIME ;GET TIMEOUT VALUE MOV A,L ORA H ;PRETEST FOR ZERO JZ NEVERMIND ;ZERO MEANS WAIT FOREVER DCX H ;COUNT 1 MS SHLD TEMPTIME ;SAVE NEW VALUE CALL WAIT1 ;WAIT 1 MS MOV A,L ORA H RET ;RET ZERO IF TIMED OUT NEVERMIND: MVI A,255 ORA A RET ;PRETEND WE DIDN'T TIMEOUT ;CHECKS CONSOLE FOR CONTROL C TO ABORT CKCRLC: CALL CONST ;CHECK CONSOLE ORA A RZ CALL CONIN ;GET CONSOLE CHAR CPI 3 ;CONTROL C? RNZ JMP QUIT ;--------------------------------------------------------- ; ;RECEIVES 1 PACKET OF ANY TYPE TO ANY DESTINATION ;ENTER WITH DE CONTAINING THE TIMEOUT VALUE IN MILLISECONDS. ;IF DE=0 THE TIMEOUT IS FOREVER ;IT WILL TRY 4 TIMES TO HEAR THE PACKET BEFORE GIVING UP. ;RETURNS WITH PACKET TYPE IN REG. A WITH ZERO FLAG SET. ;RETURNS NON-ZERO IF ERROR. ; RECVPAC: XCHG SHLD TIME ;SET TIMEOUT VALUE MVI A,4 ;SET RETRY COUNTER STA RETRYS RP1: CALL RECVAPAC ;GET 1 PACKET JNZ RP4 ;JUMP IF ERROR XRA A LDA RPTYPE ;A HAS PACKET TYPE RET ;EXIT RP4: LDA RETRYS ;COUNT THE RETRYS DCR A STA RETRYS JNZ RP3 INR A RET ;RETURN NON ZERO IF ERROR RP3: CALL CKCALL ;SEE IF IT WAS FOR US JNZ RP1 ;DONT NAK IF NOT FOR US MVI A,NAK STA TPTYPE CALL SENDAPAC ;SEND NAK PAC JMP RP1 ;GO BACK AND TRY AGAIN ;GETS 1 PACKET (NO RETRYS, SEE RECVPAC ABOVE) ;RETURNS ZERO FLAG SET WITH PACKET TYPE IN REG. A ;IF NO ERRORS ;"TIME" HAS TIMEOUT VALUE... 0=FOREVER RECVAPAC: CALL CLEARBUF ;CLEAR RECEIVE HEADER CALL WAITSOH ;WAIT FOR NEW LEADER CPI SOH JNZ TOOLONG ;MUST BE TIMEOUT IF NO SOH LXI H,HDRLEN+2 ;TOTAL LENGTH OF HEADER SHLD RLEN ;INITIAL LENGTH LXI H,RCRC ;SET UP BUFFER POINTER SHLD DATAPTR LXI D,100 ;100 MS TIMEOUT CALL RECVCHR ;TRY TO GET A CHAR JC TOOLONG STA RLEN ;GET LOW LENGTH BYTE CALL RECVCHR JC TOOLONG STA RLEN+1 ;HIGH LENGTH BYTE LHLD RLEN ;GET COUNT SHLD DATACNT ;SAVE IT CPI 5 ;SEE IF LENGTH TOO BIG JNC TOOBIG RCVLP: CALL RECVCHR ;START GETTING REST OF DATA NOW JC TOOLONG LHLD DATAPTR MOV M,A ;PUT A BYTE IN PACKET BUFFER INX H SHLD DATAPTR LHLD DATACNT ;COUNT THE BYTES DCX H SHLD DATACNT MOV A,L ORA H JNZ RCVLP ;LOOP FOR MORE BYTES CALL RXCRC ;CHECK RECEIVED CRC JNZ CRCERR ;JUMP IF ERROR CALL PRNRXHEADER ;PRINT WHAT WE RECEIVED LDA RPTYPE ;GET PACKET TYPE CMP A ;SET ZERO FLAG RET CRCERR: CALL PRINT DB '** CRC ERROR **',7,CR XRA A INR A RET ;RETURN NON ZERO DUE TO ERROR ;COME HERE AFTER TIMEOUT ERROR ; TOOLONG: CALL PRINT DB '** TIMEOUT ERROR **',7,CR XRA A INR A ;RETURN NON ZERO RET TOOBIG: CALL PRINT DB '** PACKET TOO BIG FOR BUFFER **',7,CR XRA A INR A RET ; ; ; ; ;---------------------------------------------------------- ;THIS IS THE PACKET TRANSMISSION SECTION ;SEND 1 PACKET AND WAIT FOR REPLY ;AND DO IT UP TO 4 TIMES IF IT GETS A NAK BACK ;OR A TIMEOUT SENDPAC:MVI A,4 ;RETRY COUNTER STA RETRYS AGAIN: CALL SENDAPAC ;SEND THE PACKET CALL INIRX ;SET UP FOR RECEIVE LXI H,23000 ;23 SEC TIMEOUT SHLD TIME CALL RECVAPAC ;GET REPLY PACKET JNZ SNDP1 ;ERROR IF NON ZERO CPI NAK JZ SNDP1 ;TRY AGAIN IF NAK CMP A ;SET ZERO FLAG RET ;RETURN PACKET TYPE IN ACC SNDP1: LDA RETRYS DCR A STA RETRYS JZ SP2 CALL PRINT DB 'RETRANSMITTING',CR JMP AGAIN ;TRY AGAIN SP2: MVI A,1 ;1=ERROR ORA A RET ; ; ;THIS SENDS 1 PACKET ; SENDAPAC: CALL INITX ;SET UP FOR TRANSMIT LXI D,3000 ;3 SEC WAIT AFTER KEYDOWN CALL RFON ;KEY TRANSMITTER CALL TXCRC ;COMPUTE TRANSMIT CRC CALL PRNTXHEADER ;TELL USER WHAT WERE SENDING LHLD TLEN ;GET PACKET LENGTH INX H INX H INX H INX H INX H ;ADD 7 FOR LEADER AND LENGTH BYTES INX H INX H XCHG ;TRUE LENGTH IN DE LXI H,TBUFFR ;POINT TO START OF BUFFER SP1: MOV C,M ;GET A BYTE CALL SENDCHR ;SEND IT CALL CKCRLC ;ABORT IF CONTROL C TYPED INX H DCX D MOV A,E ORA D JNZ SP1 ;LOOP TIL ALL BYTES SENT LXI D,100 CALL DELAY ;100 MS TRAILER CALL RFOFF ;KILL TRANSMITTER RET ; ; ; ;--------------------------------------------------- ;THIS MESS PRINTS THE HEADER INFORMATION TO THE CONSOLE ;FOR PACKETS TO BE SENT OR PACKETS WHICH HAVE BEEN RECEIVED. PRNTXHEADER: LXI H,TBUFFR LXI D,BUFFR MVI B,TDATA-TBUFFR CALL MOVE ;GET TRANSMIT HEADER CALL PRINT DB 'TX-@' CALL PRINFO RET PRNRXHEADER: LXI H,RBUFFR LXI D,BUFFR MVI B,RDATA-RBUFFR CALL MOVE ;GET RECEIVER HEADER CALL PRINT DB 'RX-@' ; PRINFO: LHLD LEN CALL BXDEC ;PRINT LENGTH CALL PRINT DB ' BYTES #@' LHLD PACNUM CALL BXDEC ;PRINT PACKET NUMBER CALL PRINT DB ' @' LXI H,SRCCAL MVI B,6 CALL PRNMEM ;PRINT SOURCE CALL CALL PRINT DB ' -> @' LXI H,DSTCAL MVI B,6 CALL PRNMEM ;PRINT DESTINATION CALL CALL PRINT DB ', @' LXI H,STITLE+1 MVI B,11 CALL PRNMEM ;PRINT FILE NAME CALL PRINT DB ' = @' CALL PRTYPE JMP CRLF PRTYPE: LDA PTYPE CPI DTA JZ TPDTA CPI ENQ JZ TPENQ CPI ACK JZ TPACK CPI NAK JZ TPNAK CPI FS JZ TPFS CPI EOT JZ TPEOT CPI FRQ JZ TPFRQ CPI FNF JZ TPFNF CALL PRINT DB 'UNKNOWN @' RET TPDTA: CALL PRINT DB 'DATA @' RET TPENQ: CALL PRINT DB 'ENQ @' RET TPACK: CALL PRINT DB 'ACK @' RET TPNAK: CALL PRINT DB 'NAK @' RET TPFS: CALL PRINT DB 'FS @' RET TPEOT: CALL PRINT DB 'EOT @' RET TPFRQ: CALL PRINT DB 'FRQ @' RET TPDRQ: CALL PRINT DB 'DRQ @' RET TPFNF: CALL PRINT DB 'FNF @' RET ;----------------------------------------------------- CRLF: CALL PRINT DB CR RET ;COMPARES 2 STRINGS ;POINTED TO BY HL & DE (B HAS LENGTH) ;RETURNS ZERO FLAG SET IF EQUAL ; COMPARE$: LDAX D CMP M RNZ INX H INX D DCR B JNZ COMPARE$ XRA A RET ;CHECKS THE RECEIVED CALL SIGN AGAINST OUR OWN ;RETURNS ZERO IF MATCHED. CKCALL: LXI H,MYCALL LXI D,RDSTCAL MVI B,6 JMP COMPARE$ ; ;PRINTS A STRING IN MEMORY POINTED TO BY HL ;B HAS LENGTH. PRNMEM: MOV C,M CALL CONOUT INX H DCR B JNZ PRNMEM RET ; ;SENDS A CHARACTER IN REG C TO CONSOLE ; CONOUT: PUSH PSW PUSH B PUSH D PUSH H MOV E,C MVI C,2 CALL BDOS POP H POP D POP B POP PSW RET ;CHECK CONSOLE STATUS ;RETURN A=ZERO IF NO KEY PRESSED ; CONST: PUSH B PUSH D PUSH H MVI C,11 ;CP/M CONSOLE STATUS CODE CALL BDOS POP H POP D POP B RET ;A=FF IF KEY PRESSED ; ; ;GETS A CHARACTER FROM CONSOLE ;A=CHAR. ; CONIN: PUSH B PUSH D PUSH H MVI C,1 ;READ CONSOLE CPM COMMAND CALL BDOS POP H POP D POP B RET ;A=CHAR ; ; ;PRINT A STRING POINTED TO BY THE CONTENTS OF THE ;TOP OF STACK. OR @ TERMINATES THE STRING. PRINT: XTHL PUSH PSW PUSH B PRN1: MOV A,M INX H CPI '@' JZ PRN2 MOV C,A CALL CONOUT CPI CR JNZ PRN1 CALL PRINT DB LF,'@' PRN2: POP B POP PSW XTHL RET ;CONVERTS BINARY NUMBER IN HL TO DECIMAL ASCII ;AND SENDS IT TO CONSOLE BXDEC: SHLD N ;SAVE NUMBER LXI H,P10TAB ;POINT TO POWER OF 10 TABLE BX0: MOV E,M INX H MOV D,M ;POWER OF 10 INX H PUSH H LHLD N MVI C,'0' BX1: DAD D ;SUBTRACT POWER OF TEN JNC BX2 INR C JMP BX1 ;LOOP TILL IT GOES NEG. BX2: MOV A,E CMA ;TWOS COMPLIMENT MOV E,A MOV A,D CMA MOV D,A INX D DAD D ;RESTORE TO + SHLD N ;SAVE IT CALL CONOUT POP H MVI A,1 CMP E ;SEE IF WE ARE DONE JNZ BX0 ;NO, DO AGAIN RET ; ; P10TAB: DW -10000 DW -1000 DW -100 DW -10 DW -1 ; ; ;THIS TELLS THE USER THAT THERE WAS NO RESPONSE NORPLY: LXI D,NOTHOME+2 LXI H,TDSTCAL MVI B,6 CALL MOVE LXI D,NOTHOME MVI C,9 CALL BDOS RET NOTHOME: DB CR,LF,' DOES NOT RESPOND',CR,LF,'$' ;GENERAL PURPOSE MEMORY TO MEMORY MOVE SUBROUTINE ;ENTER WITH HL POINTING TO SOURCE, DE POINTING TO ;DESTINATION AND B HAS THE LENGTH (0..255, 0=256 BYTES) MOVE: MOV A,M STAX D INX H INX D DCR B JNZ MOVE RET ; ;ENTER THIS DELAY ROUTINE WITH DE CONTAINING ;THE DELAY VALUE IN MILLISECONDS. DELAY: CALL WAIT1 ;WAIT 1MS * DE DCX D MOV A,E ORA D JNZ DELAY RET ;THIS COMPUTES THE CRC FOR TRANSMISSION TXCRC: LXI H,0 SHLD CRCREG ;CLEAR CRC LDA TLEN MOV C,A CALL CALCRC ;COMPUTE CRC FOR LENGTH FIELD LDA TLEN+1 MOV B,A ;BC HAS LENGTH NOW CALL CALCRC LXI H,TDSTCAL ;SKIP OVER CRC FIELD DCX B DCX B ;ADJUST LENGTH TXCRC1: MOV A,M ;GET A BYTE FROM BUFFER CALL CALCRC ;COMPUTE CRC ON IT INX H ;ADVANCE BUFFER POINTER DCX B ;COUNT THE BYTES MOV A,C ORA B JNZ TXCRC1 ;LOOP UNTIL COUNTER IS ZERO LHLD CRCREG ;GET COMPLETE CRC SHLD TCRC ;PUT IT IN THE BUFFER RET ;COMPUTE CRC ON RECEIVE BUFFER CONTENTS ;RETURNS A=0 IF OK RXCRC: LHLD RLEN ;GET LENGTH MOV C,L MOV B,H ;BC IS COUNTER LXI H,0 SHLD CRCREG ;CLEAR CRC MOV A,C ;COMPUTE CRC ON LENGTH WORD CALL CALCRC MOV A,B CALL CALCRC LXI H,RDSTCAL ;HL POINT TO BUFFER & SKIP CRC FIELD DCX B DCX B ;ADJUST COUNT RXCRC1: MOV A,M ;GET A BYTE CALL CALCRC ;DO CRC CALC. INX H DCX B MOV A,C ORA B JNZ RXCRC1 ;LOOP UNTIL DONE LHLD CRCREG ;GET COMPLETE CRC XCHG ;TO DE LHLD RCRC ;GET RECEIVED CRC MOV A,E SUB L RNZ ;RETURN NON ZERO IF BAD CRC MOV A,D SUB H RET ; ;THIS COMPUTES THE CRC FROM VALUES IN REGISTER A AND ;MEMORY LOCATION "CRCREG". CALCRC: PUSH B PUSH H MOV B,A ;SAVE BYTE MVI C,8 ;BIT COUNTER CALC1: ANI 80H ;KEEP MSB LHLD CRCREG ;GET CRC XRA H MOV H,A ;XOR CRC INTO DATA DAD H ;SHIFT CRC LEFT JNC CALC2 MOV A,H XRI CRCPLY SHR 8 ; HL = HL XOR CRC POLYNOMIAL MOV H,A MOV A,L XRI CRCPLY AND 255 MOV L,A CALC2: SHLD CRCREG ;SAVE RESULT DCR C JZ CALC3 MOV A,B ;GET DATA ADD A ;SHIFT IT LEFT 1 BIT MOV B,A JMP CALC1 ;DO IT AGAIN CALC3: POP H POP B RET ; ;------------------------------------------------------------; ; ;THIS IS A CW ID SUBROUTINE PACKAGE ;HERE IS THE ASCII TO CW TRANSLATE TABLE ASCII$CW: DB 5+10010000B ; / -..-. DB 5+11111000B ;ZERO DB 5+01111000B ;1 DB 5+00111000B ;2 DB 5+00011000B ;3 DB 5+00001000B ;4 DB 5+00000000B ;5 DB 5+10000000B ;6 DB 5+11000000B ;7 DB 5+11100000B ;8 DB 5+11110000B ;9 DB 0 ;: NOT USED DB 0 ; ; NOT USED DB 0 ; < NOT USED DB 0 ; = NOT USED DB 0 ; > NOT USED DB 0 ; ? NOT USED DB 0 ; @ NOT USED DB 2+01000000B ; A .- DB 4+10000000B ;B -... DB 4+10100000B ; C -.-. DB 3+10000000B ; D -.. DB 1+00000000B ; E . DB 4+00100000B ; F ..-. DB 3+11000000B ;G --. DB 4+00000000B ;H DB 2+00000000B ; I .. DB 4+01110000B ; J .--- DB 3+10100000B ; K -.- DB 4+01000000B ; L .-.. DB 2+11000000B ; M -- DB 2+10000000B ; N -. DB 3+11100000B ; O --- DB 4+01100000B ; P .--. DB 4+11010000B ; Q --.- DB 3+01000000B ; R .-. DB 3+00000000B ; S ... DB 1+10000000B ; T - DB 3+00100000B ; U ..- DB 4+00010000B ; V ...- DB 3+01100000B ; W .-- DB 4+10010000B ; X -..- DB 4+10110000B ; Y -.-- DB 4+11000000B ; Z --.. ;THIS IS THE END OF THE TABLE ID$STRING: DS 20 ;RESERVE 20 BYTES FOR ID STRING DE$STR: DB ' DE ' CWID: LXI H,ID$INH ;ID INHIBIT FLAG MOV A,M MVI M,0 ;CLEAR IT ORA A ;TEST IT RNZ ;DONT ID THIS TIME IF TRUE LXI H,TDSTCAL ;GET DESTINATION CALL LXI D,ID$STRING MVI B,6 CALL MOVE LXI H,DE$STR ;POINT TO "DE" STRING MVI B,4 CALL MOVE LXI H,MYCALL ;PUT OUR CALL IN MVI B,6 CALL MOVE XCHG MVI M,' ' ;TRAILING SPACE INX H MVI M,0 ;NULL TERMINATES STRING CALL INITX ;INIT. FOR TRANSMITTING CALL TONEOFF LXI D,200 ;DELAY 200 MS AFTER KEY DOWN CALL RFON ;KEY TRANSMITTER LXI H,ID$STRING CWID1: MOV A,M ;GET A ASCII CHAR. ORA A ;NULL? JZ RFOFF ;QUIT IF NULL CPI '0' JC CWID2 ;IGNORE INVALID CHAR PUSH H MOV C,A CALL SEND$CW$CHAR ;CONVERT TO CW AND SEND POP H CWID2: INX H JMP CWID1 ;LOOP TILL DONE SEND$CW$CHAR: PUSH B CALL TONEOFF MVI C,2 CALL DELAYX ;WAIT 2 DOT TIMES POP B ;GET ASCII CHARACTER BACK LXI H,ASCII$CW-2FH ;POINT TO CONVERSION TABLE MOV A,C CPI 20H ;TEST FOR SPACE JNZ CW1 MVI C,7 ;7 DOT TIMES FOR SPACE JMP DELAYX CW1: MVI B,0 DAD B ;INDEX INTO TABLE MOV A,M ;GET CW CODE ANI 7 ;KEEP COUNT RZ ;RETURN IF ZERO COUNT MOV B,A ;PUT COUNT IN REG. B MOV A,M ;GET CODE AGAIN CW2: ADD A ;SHIFT MSB INTO CARRY MVI E,1 ;ASSUME A DOT JNC CW3 ;JUMP IF DOT MVI E,3 ;ELSE SET FOR DASH CW3: PUSH B ;SAVE COUNT PUSH PSW ;SAVE CODE CALL TONEON ;TURN ON TONE MOV C,E ;GET TIME CALL DELAYX CALL TONEOFF ; TONE OFF MVI C,1 CALL DELAYX ;WAIT 1 DOT TIME POP PSW ;RESTORE CODE POP B ;RESTORE COUNT DCR B ;COUNT DOWN JNZ CW2 ;LOOP TILL FINISHED RET ;THIS TIMES 1 DIT. DELAYX: MOV A,C ORA A RZ PUSH B PUSH D DLY1: LXI D,50 ;50 MS DELAY CALL DELAY DCR C JNZ DLY1 POP D POP B RET ;END OF CW ID ROUTINES ;--------------------------------------------------------; ; ; DSEG ;BEGIN DATA SEGMENT ; ;THIS IS THE VARIABLE STORAGE AREA CRCREG: DS 2 ;USED BY CRC ROUTINE N: DS 2 ;USED BY BXDEC ROUTINE DATAPTR:DS 2 DATACNT:DS 2 RETRYS: DS 1 ;RETRY COUNTER SEQNUM: DS 2 ;LOCAL COUNT OF RECEIVED PACKETS DIRFLAG:DS 1 ;1=DIRECTORY 0=NORMAL FILE ID$INH: DS 1 ;1=INHIBIT NEXT ID LEADBB: DS 4 ;LEADER BUFFER BEGINNING LEADBE: DS 1 ;LEADER BUFFER END TIME: DS 2 ;USED FOR TIMEOUTS TEMPTIME: DS 2 ;SCRATCH PAD PACKET HEADER BUFFR: DS 5 ;LEADER LEN: DS 2 ;TOTAL LENGTH OF MESSAGE CRC: DS 2 ;CRC BYTES DSTCAL: DS 6 ;DESTINATION CALL SIGN DSTLOC: DS 1 ;DESTINATION LOCATION CODE DSTRPT: DS 1 ;DESTINATION REPEATER (0=DIRECT) SRCCAL: DS 6 ;SOURCE CALL SIGN SRCLOC: DS 1 ;SOURCE LOCATION CODE SRCRPT: DS 1 ;SOURCE REPEATER (0=DIRECT) PTYPE: DS 1 ; PACKET TYPE STITLE: DS 12 ;NAME OF PACKET GROUP (CP/M FILE NAME) PACNUM: DS 2 ;PACKET NUMBER ;TRANSMIT PACKET BUFFER TBUFFR: DS 5 ;LEADER TLEN: DS 2 ;TOTAL LENGTH OF MESSAGE TCRC: DS 2 ;CRC BYTES TDSTCAL:DS 6 ;DESTINATION CALL SIGN TDSTLOC:DS 1 ;DESTINATION LOCATION CODE TDSTRPT:DS 1 ;DESTINATION REPEATER (0=DIRECT) TSRCCAL:DS 6 ;SOURCE CALL SIGN TSRCLOC:DS 1 ;SOURCE LOCATION CODE TSRCRPT:DS 1 ;SOURCE REPEATER (0=DIRECT) TPTYPE: DS 1 ; PACKET TYPE TTITLE: DS 12 ;NAME OF PACKET GROUP (CP/M FILE NAME) TPACNUM:DS 2 ;PACKET NUMBER TDATA: DS 1024 ;THIS IS THE DATA ;RECEIVE PACKET BUFFER ; RBUFFR: DS 5 ;LEADER RLEN: DS 2 ;LENGTH OF RECEIVED PACKET RCRC: DS 2 ;RECEIVED CRC BYTES RDSTCAL:DS 6 ;DESTINATION CALL SIGN RDSTLOC:DS 1 ;DESTINATION LOCATION CODE RDSTRPT:DS 1 ;DESTINATION REPEATER (0=DIRECT) RSRCCAL:DS 6 ;SOURCE CALL SIGN RSCRLOC:DS 1 ;SOURCE LOCATION CODE RSCRRPT:DS 1 ;SOURCE REPEATER (0=DIRECT) RPTYPE: DS 1 ;PACKET TYPE RTITLE: DS 12 ;NAME OF PACKET GROUP (FILE NAME) RPACNUM:DS 2 ;PACKET NUMBER RDATA: DS 1024 ;RECEIVED DATA ; ; ; ; INBUFFER: DS 1024 ;FILE READ BUFFER OUTBUFFER: DS 1024 ;FILE OUTPUT BUFFER END