nam Kermit68K ttl Protocol subroutines module * Kermit68K: source file K68PTF * * Author: Roberto Bagnara (Bagnara@Iboinfn.Bitnet), * Bologna University, Physics Department, July 1987. * * All rights reserved to Bologna University, Italy. * * Permission is granted to any individual or institution * to use, copy, or redistribute this software so long as * it is not sold for profit, provided this copyright * notice is retained. * * Modification History: * * Version Date Who Comments * * 1.0.00 870701 Roberto Bagnara First official release use DefsFile Edition equ 0 psect K68ProtoFuncs,0,0,Edition,0,0 ******************************** NextFil ******************************ok * * * Try to get the next file name copying it to FilName. * * * * Entry conditions : none * * * * Exit conditions : D0.B completion code * * A0.L destroyed * * * *********************************************************************** NextFil: TST.B CtlZSeen(A6) Interrupt flag setted ? BNE.S NextFil2 Yes, return with bad completion code NextFil1 LEA FilName(A6),A0 Points to file name target string BSR GetNxtF Try to get the next file name TST.B D0 Check the completion code BEQ.S NextFil2 No files, return with bad cc BSR ChkInpF Check if file is readable TST.B D0 Ok ? BEQ.S NextFil3 Yes, return this MOVEQ #FlSkippd,D0 No, notify that we are skipping it BSR Screen BRA.S NextFil1 Try another NextFil2 SF D0 Set a bad completion code RTS NextFil3 ST D0 RTS ******************************** SndPack ******************************ok * * * Send a packet. * * * * Entry conditions : D1.B packet type * * D2.B packet number * * D3.B packet length * * * * Exit conditions : D4.W destroyed * * D5.L destroyed * * A0.L destroyed * * A1.L destroyed * * * *********************************************************************** SndPack: LEA SendBuf(A6),A1 Packet buffer start MOVEQ #32,D5 Load register for quick addition MOVE.B OStPckCh(A6),(A1)+ Packet marker MOVE.B D3,D0 Packet length ADDQ.B #2,D0 Add 2 + block_check_type to packet ... ADD.B BlChkUs(A6),D0 length to obtain the character count ADD.B D5,D0 and convert it into a printable character MOVE.B D0,(A1)+ Send the character count ADD.B D5,D2 Make the packet number printable MOVE.B D2,(A1)+ Send the packet number MOVE.B D1,(A1)+ Send the packet type MOVE.B D1,SendType(A6) And save it for echos removal LEA DataBuf(A6),A0 Pointer to data buffer CLR.W D0 Clear the counter register MOVE.B D3,D0 Data length BRA.S SndPack2 Loop for all data characters SndPack1 MOVE.B (A0)+,(A1)+ Get a character and put it in the packet SndPack2 DBF D0,SndPack1 Repeat CLR.B (A1) Mark end for block check LEA SendBuf+1(A6),A0 First char for checksum computation MOVE.B BlChkUs(A6),D0 Block check type in use SUBQ.B #1,D0 Type 1 block check ? BNE.S SndPack3 No, try another BSR Check1 Yes, compute it ADD.B D5,D0 Convert the checksum into printable MOVE.B D0,(A1)+ Send it BRA.S SndPack5 Join common part SndPack3 SUBQ.B #1,D0 Type 2 block check ? BNE.S SndPack4 No, type 3 block check BSR Check2 Yes, compute it MOVE.B D0,D4 Save the lower portion of the result LSR.W #6,D0 Process bits 6 --> 11, right adjusting ANDI.B #$3F,D0 Mask extra bits ADD.B D5,D0 Conversion into a printable character MOVE.B D0,(A1)+ Send the first character MOVE.B D4,D0 Reload the copy ANDI.B #$3F,D0 Now bits 0 --> 5 ADD.B D5,D0 Conversion into a printable character MOVE.B D0,(A1)+ Send the second character BRA.S SndPack5 Join common part SndPack4 BSR Check3 Compute a type 3 block check MOVE.W D0,D4 Make a copy of the result LSR.W #8,D0 Process bits 12 --> 15, right adjusting LSR.W #4,D0 Right adjusting ADD.B D5,D0 Conversion into a printable character MOVE.B D0,(A1)+ Send the first character MOVE.W D4,D0 Reload the copy LSR.W #6,D0 Now process bits 6 --> 11, right adjust ANDI.B #$3F,D0 Mask extra bits ADD.B D5,D0 Conversion into a printable character MOVE.B D0,(A1)+ Send the second character MOVE.B D4,D0 Reload the lower portion of the result ANDI.B #$3F,D0 Now bits 0 --> 5 ADD.B D5,D0 Conversion into a printable character MOVE.B D0,(A1)+ Send the third character SndPack5 MOVE.B OEOL(A6),(A1)+ Extra-packet line terminator CLR.B (A1) End-Of-Buffer marker BSR TxPackt Transmit the packet now prepared MOVEQ #PackType,D0 Display the packet type on the screen BSR Screen RTS ******************************** RdPack *******************************ok * * * Attempts to read a packet. * * * * Entry conditions : none * * * * Exit conditions : D1.B packet type or pseudo-type * * D2.B packet number * * D3.B packet length * * D5.L destroyed * * D6.L destroyed * * A0.L destroyed * * A1.L destroyed * * A2.L destroyed * * * *********************************************************************** RdPack: MOVE.L D4,-(A7) Save working register SUBQ.L #4,A7 Allocate some space on the stack MOVEQ #3-1,D6 Try 3 times to get a line that has RdPack1 BSR InpLine a start-of-packet char in it TST.B D1 Check InpLine completion code BEQ RdPack16 Failed, return a timeout pseudo-packet * Ok, search the start-of-packet char RdPack2 LEA RecBuf(A6),A0 Pointer to receive buffer CLR.W D1 Clear the character counter RdPack3 MOVE.B (A0)+,D2 Get a character CMP.B IStPckCh(A6),D2 Start-of-packet char ? BEQ.S RdPack4 Yes, first goal satisfied ! ADDQ.W #1,D1 Increment character counter CMP.W D0,D1 Last character ? BNE.S RdPack3 No, try the next DBF D6,RdPack1 Repeat max 3 times MOVEQ #'Q',D1 Failed, return a garbage pseudo-packet BRA RdPack19 RdPack4 MOVEQ #32,D6 Load for quick addition/subtraction RdPack5 MOVEA.L A0,A1 Remember where packet started MOVE.B (A0)+,D0 Get character BEQ RdPack15 EOL, garbled packet CMP.B IStPckCh(A6),D0 Start-of-packet char ? BEQ.S RdPack5 Yes, resynchronize MOVE.B D0,D3 This is the packet length SUB.B D6,D3 Convert it to numeric MOVE.B (A0)+,D0 Get character BEQ RdPack15 EOL, garbled packet CMP.B IStPckCh(A6),D0 Start-of-packet char ? BEQ.S RdPack5 Yes, resynchronize MOVE.B D0,D2 This is the packet number SUB.B D6,D2 Convert it to numeric MOVE.B (A0)+,D0 Get character BEQ RdPack15 EOL, garbled packet CMP.B IStPckCh(A6),D0 Start-of-packet char ? BEQ.S RdPack5 Yes, resynchronize MOVE.B D0,D1 This is the packet type * Heuristics for syncing block check type MOVEQ #1,D5 Type 1 block check by default CMPI.B #'S',D1 Send-Init packet ? BEQ.S RdPack7 Yes, type 1 block check CMPI.B #'I',D1 Initialize packet ? BEQ.S RdPack7 Yes, type 1 block check CMPI.B #'N',D1 NAK packet ? BNE.S RdPack6 No MOVE.B D3,D5 Yes, block check type is SUBQ.B #2,D5 bct = packet_length - 2 BRA.S RdPack7 RdPack6 MOVE.B BlChkUs(A6),D5 Otherwise block check type in use RdPack7 SUB.B D5,D3 Now compute data length by subtracting SUBQ.B #2,D3 (block_check_type + 2) LEA DataBuf(A6),A2 Pointer to data buffer CLR.W D4 Clear the counter register MOVE.B D3,D4 Data length BRA.S RdPack9 Read data, if any RdPack8 MOVE.B (A0)+,D0 Get character BEQ RdPack15 EOL, garbled packet CMP.B IStPckCh(A6),D0 Start-of-packet char ? BEQ.S RdPack5 Yes, resynchronize MOVE.B D0,(A2)+ Write character to data buffer RdPack9 DBF D4,RdPack8 CLR.B (A2)+ Mark the end of buffer MOVEA.L A7,A2 Point to temporary storage space CLR.W D4 Clear the counter register MOVE.B D5,D4 Block check type BRA.S RdPack11 Get the block check RdPack10 MOVE.B (A0),D0 Get character BEQ RdPack15 EOL, garbled packet CMP.B IStPckCh(A6),D0 Start-of-packet char ? BEQ RdPack5 Yes, resynchronize MOVE.B D0,(A2)+ Store the block check character CLR.B (A0)+ Nullify checksum characters in RecBuf RdPack11 DBF D4,RdPack10 Repeat * Got packet, now check the block check MOVEA.L A1,A0 Pointer to packet start MOVEA.L A7,A1 Point to received block check characters SUBQ.B #1,D5 Type 1 block check ? BEQ.S RdPack13 Yes, compute it SUBQ.B #1,D5 Type 2 block check ? BEQ.S RdPack12 Yes, compute it SUBQ.B #1,D5 Type 3 block check ? BNE.S RdPack15 No, return garbage pseudo-packet * Yes, compute it, (fall thru) BSR Check3 Compute MOVEQ #$3F,D4 Process bits 0 --> 5 AND.B D0,D4 Move and mask extra bits ADD.B D6,D4 Conversion into a printable character CMP.B 2(A1),D4 Ok, now compare, third byte BNE RdPack15 Compare fails, garbled packet LSR.W #6,D0 Now process bits 6 --> 11, right adjust MOVEQ #$3F,D4 To mask extra bits AND.B D0,D4 Move and mask extra bits ADD.B D6,D4 Conversion into a printable character CMP.B 1(A1),D4 Compare the second byte BNE RdPack15 Compare fails, garbled packet LSR.W #6,D0 Process bits 12 --> 15, right adjusting ADD.B D6,D0 Conversion into a printable character CMP.B (A1),D0 Compare the first byte BRA.S RdPack14 Join common part RdPack12 BSR Check2 Compute MOVEQ #$3F,D4 Process bits 0 --> 5 AND.B D0,D4 Move and mask extra bits ADD.B D6,D4 Conversion into a printable character CMP.B 1(A1),D4 Ok, now compare, second byte BNE RdPack15 Compare fails, garbled packet LSR.W #6,D0 Process bits 6 --> 11, right adjusting ANDI.B #$3F,D0 Mask extra bits ADD.B D6,D0 Conversion into a printable character CMP.B (A1),D0 Compare the first byte BRA.S RdPack14 Join common part RdPack13 BSR Check1 Compute ADD.B D6,D0 Convert it to a printable character CMP.B (A1),D0 Compare it with the received block check * Join common part, (fall thru) RdPack14 BEQ.S RdPack17 If compare succeeds return packet type RdPack15 MOVEQ #'Q',D1 Return a garbage pseudo-packet BRA.S RdPack18 RdPack16 MOVEQ #'T',D1 Return a timeout pseudo-packet BRA.S RdPack18 RdPack17 ADDQ.L #1,PcksRecd(A6) Increment packets received this trans ADDQ.L #1,TPckRecd(A6) Increment total packets received RdPack18 MOVEQ #PackType,D0 We want display the packet type BSR Screen Update the screen, if necessary RdPack19 ADDQ.L #4,A7 Deallocate space on the stack MOVE.L (A7)+,D4 Restore working register RTS ******************************** InpPack ******************************ok * * * Loop until the expected packet arrives or the maximum tries number * * exceeded. If a packet arrives with the same type of the last * * packet sent, it's treated as an echo and another one is expected. * * If the previous packet arrives again, the last packet is resent * * and a new one is expected to come in. * * * * Entry conditions : none * * * * Exit conditions : D1.B packet type or pseudo-type * * D2.B packet number * * D3.B packet length * * D4.B destroyed * * * *********************************************************************** InpPack: CLR.B D4 Clear the retry counter InpPack1 BSR ChekInt Check for console interrupts BSR RdPack Try to read a packet CMP.B SendType(A6),D1 It's the same just sent ? BNE.S InpPack2 No BSR RdPack Yes, it's an echo, read another InpPack2 CMP.B PrevPckN(A6),D2 Previous packet ? BEQ.S InpPack4 Yes, keep trying CMPI.B #'T',D1 Timeout pseudo-packet ? BEQ.S InpPack4 Yes, keep trying CMPI.B #'Q',D1 Garbage pseudo-packet ? BEQ.S InpPack4 Yes, keep trying CMPI.B #'N',D1 NAK packet ? BNE.S InpPack3 No, return the received packet ADDQ.L #1,NAKsRecd(A6) Yes, increment NAKs received counter ADDQ.L #1,TNAKRecd(A6) Increment total NAKs received counter CMP.B NextPckN(A6),D2 It's a NAK for the next packet ? BNE.S InpPack4 No MOVEQ #'Y',D1 Yes, it's like an ACK ... MOVE.B PackNum(A6),D2 ... for current packet InpPack3 MOVE.B D1,D4 Save this for parameter passing MOVEQ #ClrInpBf,D0 Clear the input buffer ... MOVEQ #HostLine,D1 ... of the host line BSR ChanCtrl Call the channel control routine MOVE.B D4,D1 Restore the packet (pseudo) type RTS InpPack4 CMP.B Retry(A6),D4 Too many tries ? BCC.S InpPack3 Yes, return BSR Resend No, send last packet again ADDQ.B #1,D4 Increment the retry counter BRA.S InpPack1 Stay in loop ********************************* GetPack *****************************ok * * * Gets characters from the current source, file or memory string. * * Encodes the data into the packet, filling the packet optimally. * * Returns TRUE on success with Size containing the number of * * characters in DataBuf, or FALSE if DataBuf is empty (Size = 0, * * EOF for file, end of string for memory string). * * * * Entry conditions : none * * * * Exit conditions : D0.B completion code * * * *********************************************************************** GetPack: MOVEM.L A0/D1-D2,-(A7) Save working registers LEA DataBuf(A6),A0 Pointer to data buffer MOVEQ #0,D2 Clear index register TST.B First(A6) First time ? BLT.S GetPack1 No, EOF from last time BEQ.S GetPack2 No, input in progress CLR.B First(A6) Yes, remember BSR GetChx Get first character of file MOVE.B D0,Current(A6) Save current character TST.B D1 Null file ? BNE.S GetPack3 No GetPack1 MOVE.B #1,First(A6) Yes, setup for next time SF D0 Return negative completion code BRA.S GetPack9 GetPack2 MOVE.B LeftOver(A6,D2.W),(A0,D2.W) Do any left-overs BEQ.S GetPack3 Exit if null ADDQ.W #1,D2 Increment index BRA.S GetPack2 Repeat GetPack3 CLR.B LeftOver(A6) Nullify the left-overs buffer CLR.B ReptCnt(A6) Clear out any old repeat count GetPack4 TST.B First(A6) EOF reached ? BLT.S GetPack8 Yes, return partially (?) filled packet BSR GetChx Get a character from file or memory MOVE.B D0,Next(A6) Save next character for lookahead TST.B D1 EOF ? BNE.S GetPack5 No MOVE.B #-1,First(A6) Yes, flag it for next time GetPack5 MOVE.B D2,OldSize(A6) Remember current position MOVE.B Current(A6),D0 Get the current character BSR Encode Encode the current character MOVE.B Next(A6),Current(A6) Next is now current CMP.B OMPckSiz(A6),D2 Check packet size BLT.S GetPack4 Keep filling BEQ.S GetPack8 Return exactly full packet MOVEQ #0,D0 Clear for indexing the left-overs buffer MOVEQ #0,D1 Clear for indexing the data buffer MOVE.B OldSize(A6),D1 Set up the data buffer index GetPack6 MOVE.B (A0,D1.W),LeftOver(A6,D0.W) Save some for next time BEQ.S GetPack7 Exit if null ADDQ.W #1,D0 Increment the first index ADDQ.W #1,D1 Increment the second index BRA.S GetPack6 Repeat GetPack7 MOVE.B OldSize(A6),D2 Size of the truncated packet GetPack8 ST D0 Provide positive completion code GetPack9 MOVE.B D2,Size(A6) CLR.B (A0,D2.W) Write buffer terminator MOVEM.L (A7)+,A0/D1-D2 Restore working registers RTS ********************************* EncStrng ****************************ok * * * Encode a string from memory. * * * * Entry conditions : A0.L memory string start address * * * * Exit conditions : A0.L memory string start address * * * *********************************************************************** EncStrng: MOVE.B MStrFlag(A6),-(A7) Save the old flag MOVE.L MStrgPnt(A6),-(A7) Save the old pointer ST MStrFlag(A6) Say input from memory string MOVE.L A0,MStrgPnt(A6) Point to the memory string MOVE.B #1,First(A6) Initialize character lookahead BSR GetPack Get a packet from the string MOVE.L (A7)+,MStrgPnt(A6) Restore the old pointer MOVE.B (A7)+,MStrFlag(A6) Restore the old flag MOVE.B #1,First(A6) Re-initialize character lookahead RTS ********************************* GetChx ******************************ok * * * Try to get the next character from file or memory string. * * Returns TRUE on success with D0.B set to the character, or FALSE * * on failure (EOF for file, enf of string for memory string). * * * * Entry conditions : none * * * * Exit conditions : D0.B character (if any) * * D1.B completion code * * * *********************************************************************** GetChx MOVE.L A0,-(A7) Save working register TST.B LFSave(A6) Do we have a linefeed saved ? BEQ.S GetChx1 No SF LFSave(A6) Yes, nullify the flag MOVEQ #Asc_LF,D0 Return the saved LF ST D1 Also return a positive cc BRA.S GetChx4 GetChx1 TST.B MStrFlag(A6) Try to get the next character, memory ? BEQ.S GetChx2 No, get it from current file MOVEA.L MStrgPnt(A6),A0 Load pointer to the memory string MOVE.B (A0)+,D0 Get a character SNE D1 Set cc to false if end of string reached MOVE.L A0,MStrgPnt(A6) Save pointer for next time BRA.S GetChx3 Join the common part GetChx2 MOVEQ #IOFile,D1 Get a char from the the current file BSR InpChar TST.B D1 Check the returned completion code SEQ D1 Set completion code accordingly GetChx3 TST.B D1 Have we got a character ? BEQ.S GetChx4 No, return ADDQ.L #1,DChsSent(A6) Yes, count it ADDQ.L #1,TDChSent(A6) TST.B Binary(A6) Are we in binary mode ? BNE.S GetChx4 Yes, nl-CRLF mapping not needed CMPI.B #NewLinCh,D0 No, newline character ? BNE.S GetChx4 No ST LFSave(A6) Yes, remember a linefeed MOVEQ #Asc_CR,D0 Return a carriage return GetChx4 MOVE.L (A7)+,A0 Restore working register RTS ********************************* Resend ******************************ok * * * Resend the last packet sent (the one in SendBuf), if any, send * * a NAK otherwise. * * * * Entry conditions : none * * * * Exit conditions : D0.L destroyed * * D1.L destroyed * * * *********************************************************************** Resend: MOVEQ #ClrInpBf,D0 Clear the input buffer MOVEQ #HostLine,D1 Host line channel BSR ChanCtrl Call the channel control routine TST.B SendBuf(A6) Send buffer empty ? BNE.S Resend1 No, send last packet again BSR SendNAK Yes, send a NAK packet RTS Resend1 BSR TxPackt Send the previous packet again MOVEQ #PackType,D0 Update the screen MOVEQ #'%',D1 This is the symbol for a resent packet BSR Screen RTS ******************************** SndEPack *****************************ok * * * Send an Error packet. * * * * Entry conditions : A1.L point to the reason string * * * * Exit conditions : D0.L destroyed * * D1.L destroyed * * D2.B destroyed * * D3.B destroyed * * A0.L destroyed * * * *********************************************************************** SndEPack: MOVEA.L A1,A0 Point to the reason string BSR EncStrng Encode it MOVEQ #'E',D1 Error packet MOVE.B PackNum(A6),D2 Packet number MOVE.B Size(A6),D3 Packet length BSR SndPack OK, send now BSR ClsInpF Close the input file, if open ST CtlZSeen(A6) This is an interrupted file transfer BSR ClsOutF Close (and maybe delete) the output file MOVEQ #TranCmpl,D0 Give transaction complete message BSR Screen RTS ********************************* SendACK *****************************ok * * * Send an empty ACK packet. * * * * Entry conditions : none * * * * Exit conditions : D1.L destroyed * * D2.B destroyed * * D3.L destroyed * * * *********************************************************************** SendACK: MOVEQ #'Y',D1 ACK MOVE.B PackNum(A6),D2 Packet number MOVEQ #0,D3 Packet length (0, empty packet) BSR SndPack OK, send now BSR BumpPckN Bump packet number, modulo 64 RTS ********************************* SendNAK *****************************ok * * * Send a NAK packet (always empty). * * * * Entry conditions : none * * * * Exit conditions : D1.L destroyed * * D2.B destroyed * * D3.L destroyed * * * *********************************************************************** SendNAK MOVEQ #'N',D1 NAK MOVE.B PackNum(A6),D2 Packet number MOVEQ #0,D3 Packet length (0, empty packet) BSR SndPack OK, send now ADDQ.L #1,NAKsSent(A6) Increment NAKs sent this transaction ADDQ.L #1,TNAKSent(A6) Increment total NAKs sent RTS ends END