*********************** * MAIN ROUTINES FOR * * XMODEM AND TXTMODEM * *********************** ****************************** * PTDOS DEVICE DRIVER HEADER * ****************************** ORG MAIN DTRB DW DORB ;READ BLOCK DTRNB DW DORB ;READ NEXT BLOCK DTRLB DW 0000H ;READ PREVIOUS BLOCK (NOT SUPPORTED) DTWBR DW DOWB ;WRITE BLOCK THEN READ NEXT BLOCK DTWB DW DOWB ;WRITE BLOCK DTREW DW DOREW ;REWIND DTEOF DW DOEOF ;EOF DTCLO DW DOCLO ;CLOSE DRIVER DTSEK DW 0000H ;SEEK (NOT SUPPORTED) DTCTL DW 0000H ;CTRL/STAT REQUEST (NOT SUPPORTED) DTBLK DW 128 ;MAX PTDOS TRANSFER BLOCK SIZE DTITO DB 0 ;NO IMMEDIATE-TRANSFER OPTION DTINI DW DOINI ;INITIALIZE DRIVER ************************ * RAM VARIABLES * * INITIALIZED BY DOINI * ************************ RABEG EQU $ BUFIP DW 0 ;BLKBF IN-POINTER OR GENERAL PTR BUFOP DW 0 ;BLKBF OUT-POINTER BUFBC DW 0 ;BLKBF BYTE COUNT CRC16 DW 0 ;16-BIT CRC BLKNO DW 0 ;XMODEM BLOCK NUMBER/COUNT RTRYS DW 0 ;TOTAL NUMBER OF RETRIES RXBLK DB 0 ;RECEIVED BLOCK NUMBER RXDFL DB 0 ;0 FOR SEND, 1 FOR RECEIVE ERRCT DB 0 ;BLOCK ERROR COUNTER EOFFL DB 0 ;<>0 WHEN EOF NEEDS TO BE SENT INIFL DB 0 ;<>0 MEANS WE ALREADY GOT 1ST RECORD CRCFL DB 0 ;0 MEANS TX/RX WITH CHKSUM, >0 MEANS CRC SAVSP DW 0 ;SP SAVE FOR RX ABORT RAEND EQU $ ;END OF DOINI-INITIALIZED VARIABLES *************************** * PTDOS FUNCTION ROUTINES * *************************** *================================* * FUNCTION: INITIALIZE DRIVER * Note: We don't know yet whenter * we will be sending or receiving * ON ENTRY: NO PARAMETERS * ON RETURN: * RETURN1=NORMAL RETURN *================================* DOINI: LXI H,RABEG ;CLEAR ALL RAM VARS LXI B,RAEND-RABEG ;CLEARS B ALSO INILP: MOV M,B INX H DCR C JNZ INILP LXI H,BLKBF ;INITIALIZE BLKBF POINTERS SHLD BUFIP SHLD BUFOP MVI A,CRTRY ;NUMBER OF TIMES TO TRY CRC MODE STA INIFL ;NZ MEANS NEED TO INIT FOR TX LXI D,INIMS ;XMODEM BANNER CALL PRNTF CALL RXBY0 ;FLUSH TRASH FROM SERIAL PORT JMP RXBY0 ;DOUBLE-BUFFER *=============================================* * FUNCTION: CLOSE DRIVER * If we were sending, flush out whatever data * remains in BLKBF, which will require padding * out the last XMODEM block. Then send an * XMODEM EOF, and exit with a console message. * If we were sending, just exit with a console * message. * ON ENTRY * RXDFL = 1 IF WE WERE RECEIVING * ON EXIT: * IF WE WERE SENDING, EOFFL <> 0 * AND ALL BUFFER DATA HAS BEEN SENT * RETURN1=NORMAL RETURN *=============================================* DOCLO: LXI D,RXSMS ;'RECEIVED' LDA RXDFL ;SENDING OR RECEIVING? ORA A ;DONE ALREADY IF RECEIVING JNZ CLDON LDA EOFFL ;DID WE ALREADY SEND THE EOF? ORA A RNZ . ;DONE IF SO LXI H,0 ;SAVE SP IN CASE OF ABORT DAD SP SHLD SAVSP *--------------------------------- * PAD & SEND LAST BLOCK, IF NEEDED *--------------------------------- LHLD BUFBC ;HOW MANY BYTES LEFT IN BLKBF? MOV A,H ORA L JZ TXEOF ;NONE: SEND FINAL EOF *PAD DATA OUT TO EVEN BLKSZ BOUNDARY XCHG . ;DE = BYTE COUNT LHLD BUFIP PADLP: MVI M,PADCH ;PAD CHR INX H INR E MOV A,E ;ENOUGH? CPI BLKSZ JNZ PADLP STA BUFBC ;ONLY LOW BYTE CHANGED CALL PDATA ;SEND PADDED LAST BLOCK *------------------------------------------- * EOF: SEND EOT'S TO XMODEM INTIL WE GET ACK *------------------------------------------- TXEOF: MVI B,EOT ;SEND AN EOT MOV A,B STA EOFFL ;REMEMBER EOF'S BEEN SENT CALL TXBYT CALL GTACK ;Z WHEN WE GET AN ACK JNZ TXEOF ;LOOP UNTIL WE GET ONE *------------------------------------------- * TERMINATION MESSAGE WITH ERROR CHECK MODE, * AND WITH BLOCK & RETRY COUNTS IN DECIMAL *------------------------------------------- LXI D,TXSMS ;'SENT ' CLDON: CALL PRNTF ;'SENT' OR 'RECEIVED' LHLD BLKNO ;HOW MANY BLOCKS SENT/RECEIVED? CALL PRNTD ;BINARY TO DECIMAL PRINT LXI D,BLKMS ;'XMODEM BLOCKS USING' CALL PRNTF LXI D,CRWMS ;'CRCS WITH' LDA CRCFL ORA A JNZ DON01 LXI D,CKWMS ;CHECKSUMS WITH' DON01: CALL PRNTF LHLD RTRYS ;RETRY COUNT CALL PRNTD ;IN DECIMAL LXI D,RTYMS ;'RETRIES' JMP PRNTF ;PRINT IT AND RET TO PTDOS *================================================* * FUNCTION: READ BLOCK * If this is the first block, then negotiate * checksum or CRC reception with the sender. * If BLKBUF is empty, then get another buffer- * full from the serial port. * Transfer as much data as possible from BLKBUF * to PTDOS * If the last of the data has been sent to PTDOS, * then tell PTDOS 'EOF' by using RETURN1 * ON ENTRY: * HL = DEST ADDRESS IN PTDOS * DE = MAX BYTES PTDOS CAN HANDLE * INIFL > 0 NUMBER OF TIMES TO TRY CRC MODE * 0FFH: NOT THE FIRST BLOCK * ON RETURN: * RETURN1 IF EOF OR ABORT, RETURN2 OTHERWISE * INIFL = 0FFH * HL = # OF BYTES READ SINCE CALL * ON ENTRY AND RETURN: * CRCFL = 0 FOR CHECKSUM, >0 FOR CRC * EOFFL = 1 IF EOF ALREADY RECEIVED FROM SENDER * BUFIP = CURRENT ADDRESS IN BLKBF * BUFBC = REMAINING BYTES IN BLKBF * BLKNO = LAST BLOCK NUMBER RECEIVED *================================================* DORB: MVI A,1 ;REMEMBER WE ARE RECEIVING STA RXDFL PUSH D ;MAX PTDOS BYTES PUSH H ;PTDOS ADDRESS LXI H,4 ;THERE ARE 2 ITEMS ON THE STACK NOW DAD SP ;CALCULATE ORIGINAL SP SHLD SAVSP ;REMEMBER SP IN CASE WE ABORT *----------------------------- * IF BLKBF'S EMPTY, GO LOAD IT *----------------------------- LHLD BUFBC ;BUFFER EMPTY? MOV A,H ORA L CZ GDATA ;YES: BLKBF. SET Z IF NO DATA (EOF) POP B ;PTDOS ADDRESS POP D ;PTDOS MAX BYTES LXI H,0 ;BYTE COUNT SENT TO PTDOS RZ . ;RETURN1 IF EOF AND ALL DATA TRANSFERED *--------------------------------------------- * LOOP TO TRANSFER DATA FROM BLKBF TO PTDOS * UNTIL BLKBF IS EMPTY OR PTDOS BUFFER IS FULL * EOFFL=1 IF EOF ALREADY RECEIVED FROM SENDER *--------------------------------------------- PUSH H ;SENT-BYTE-COUNT ONTO STACK LHLD BUFIP ;HL=BLKBF ADDRESS DORB1: PUSH H ;SAVE SOURCE ADDRESS LHLD BUFBC ;DEC/TEST BLKBF BYTE COUNT DCX H MOV A,H ;UNDERFLOW? INR A JZ DORB0 SHLD BUFBC DORB0: POP H ;SOURCE ADDRESS JZ DORB2 ;Z IF WE HAVE EMPTIED BLKBF XTHL . ;BUMP PTDOS BYTE COUNT INX H ;...WHICH IS ON THE STACK XTHL MOV A,M ;MOVE A BYTE FROM BLKBF STAX B ;...TO PTDOS INX H ;BUMP ADDRESS POINTERS INX B DCX D ;DEC PTDOS BYTE COUNT MOV A,D ;STILL ROOM IN PTDOS BUFFER? ORA E ;...16-BIT TEST JNZ DORB1 ;GO AS LONG AS WE CAN *-------------------------------------------- * SAVE STATE & RETURN TO PTDOS EITHER BECAUSE * PTDOS'S BUFFER IS FULL OR BLKBUF IS EMPTY. * HL=CURRENT BUFFER ADDRESS * TOP-OF-STACK=TRANSFER BYTE COUNT *-------------------------------------------- DORB2: SHLD BUFIP ;SAVE INPUT BUFFER POINTER POP H ;HL=COUNT OF BYTES TRANSFERED POP D ;NO EOF: GET RETURN ADDRESS INX D ;...MAKE IT RETURN2 INX D INX D PUSH D ;...AND PUT IT BACK RET . ;WITH HL=BYTES TRANSFERED TO PTDOS *=============================================* * FUNCTION: ENDFILE * Send last block of data from PTDOS * NOTE: This does NOT send an XMODEM EOF, nor * does it flush BLKBUF. DTCLO does this. * ON ENTRY: * HL=SOURCE BUFFER ADDRESS * DE=BUFFER SIZE * ON ENTRY AND RETURN: * BUFBC = # OF BYTES ALREADY IN BLKBF * BUFIP = BLKBF IN-POINTER = ADDRESS * OF EMPTY NEXT SLOT * BUFOP = BLKBF OUT-POINTER = ADDRESS * OF NEXT BYTE TO SEND * BLKNO = LAST XMODEM BLOCK # SENT * ON RETURN: * RETURN1=NORMAL RETURN *=============================================* DOEOF: LDA RXDFL ;SENDING OR RECEIVING? ORA A RNZ . ;DONE ALREADY IF RECEIVING CALL DOWB ;WRITE WHAT CAME WITH CALL RET . ;IN CASE OF ABORT NOP . ;NORMAL RETURN 2 SKIPS 3 NOP RET . ;DTEOF MUST USE RETURN1 *================================================* * FUNCTION: WRITE BLOCK * Transfer DE bytes of data frOm PTDOS buffer to * BLKBF. Then send as much as possible as XMODEM * blocks. Quit when there is less than one XMODEM * block (BLKSZ bytes) of data left on BLKBF. * BLKBF's size is big enough to hold the max * PTDOS transfer (defined at DTBLK) plus at least * two more XMODEM blocks (BLKSZ). * * ON ENTRY: * HL=PTDOS SOURCE BUFFER ADDRESS * DE=NUMBER OF BYTES TO GET FROM PTDOS * * ON RETURN: * RETURN2=NORMAL RETURN * HL=0=NUMBER OF BLOCKS READ * ON ENTRY AND RETURN: * BUFBC = NUMBER OF BYTES ALREADY IN BLKBF * BUFIP = BLKBF IN-POINTER = ADDRESS OF NEXT SLOT * BUFOP = BLKBUF OUT-POINTER = ADDRESS * OF NEXT BYTE TO SEND * BLKNO = BLOCK NUMBER OF THE LAST BLOCK SENT * CRCFL = 0 FOR CHECKSUM, >0 FOR CRC *================================================* DOWB: MOV A,D ;CHECK FOR ZERO TRANSFER BYTES ORA E JZ DOWB5 ;NO BYTES: DONE MOV B,H ;BC GETS PTDOS ADDRESS MOV C,L LXI H,0 ;REMEMBER SP IN CASE WE ABORT DAD SP ;CALCULATE ORIGINAL SP SHLD SAVSP *------------------------------------------- * LOOP TO GET DE BYTES FROM PTDOS AT BC INTO * BLKBF AT BUFIP. GUARANTEED TO HAVE ROOM. * BLKBF IS A CIRCULAR QUEUE DURING TX. *------------------------------------------- LHLD BUFIP ;HL=BLKBF IN-POINTER DOWB1: LDAX B ;GET PTDOS DATA INX B ;BUMP PTDOS POINTER PUSH B ;SAVE POINTER DOWB2: MOV C,A ;FOR CRLF TEST CALL ENQUE ;PUT A IN QUEUE IF TXTMO ;FOLLOW CRS WITH LFS IN TEXT FILES MOV A,C ;WAS IT A CR? CPI CR MVI A,LF CZ ENQUE ;YES:FOLLOW IT WITH AN LF ENDF POP B ;PTDOS POINTER DCX D ;MORE PTDOS DATA? MOV A,D ORA E JNZ DOWB1 SHLD BUFIP ;SAVE NEW IN-POINTER *------------------------------------ * LOOP TO SEND DATA AS XMODEM BLOCKS. * STOP WHEN < BLKSIZ BYTES REMAIN *------------------------------------ DOWB3: LHLD BUFBC ;BLKSZ BYTES IN BUFFER? MOV A,H ORA A JNZ DOWB4 ;MORE THAN 256 MOV A,L CPI BLKSZ ;C SET IF BLKSZ>A JC DOWB5 DOWB4: CALL PDATA ;SEND AN XMODEM BLOCK JMP DOWB3 *----------------- * NORMAL DOWB EXIT *----------------- DOWB5: POP H ;FIX STACK FOR RETURN2 INX H INX H INX H PUSH H * FALL INTO DOREW *=================================* * FUNCTION: REWIND * PTDOS DOC SAYS SEQUENTIAL DEVICE * DRIVERS SHOULD RETURN WITH HL=0 * ON ENTRY: DOESN'T MATTER * ON RETURN: * RETURN1=NORMAL RETURN * HL=0 *=================================* DOREW: LXI H,0 RET