; This module contains the routines that actually implement the Kermit ; protocol. ; Packet definitions. maxpkt EQU '~'-' '+2O ; Maximum size of a packet. maxtry EQU 05O ; Default number of retries on a packet. imxtry EQU 20O ; Default number of retries send initiate. drpsiz EQU 5EH ; Default receive packet size. dspsiz EQU 20H ; Default send packet size. dstime EQU 08H ; Default send time out interval. drtime EQU 05H ; Default receive time out interval. dspad EQU 00H ; Default send padding. drpad EQU 00H ; Default receive padding. dspadc EQU 00H ; Default send padding char. drpadc EQU 00H ; Default receive padding char. dseol EQU cr ; Default send EOL char. dreol EQU cr ; Default receive EOL char. dsquot EQU '#' ; Default send quote char. drquot EQU '#' ; Default receive quote char. bufsiz EQU 80H ; Size of DMA. diasw EQU 01H ; Default is diagnostics on. DSEG $ ; Program storage. bufhex rw 80H belflg db 1 ; Use bell. incmod db 0 ; Insert Character mode. hierr db 0 ; Non-ascii char (non-zero if yes). parflg db defpar ; Parity flag (default none.) flwflg db 0 ; File warning flag (default off). ibmflg db 0 ; IBM flag (default off). incnt dw 0 ; Number of chars read in from port. pktptr dw 0 ; Position in receive packet. spsiz db dspsiz ; Send packet size. rpsiz db drpsiz ; Receive packet size. stime db dstime ; Send time out. rtime db drtime ; Receive time out. spad db dspad ; Send padding. rpad db drpad ; Receive padding. spadch db dspadc ; Send padding char. rpadch db drpadc ; Receive padding char. seol db dseol ; Send EOL char. reol db dreol ; Receive EOL char. squote db dsquot ; Send quote char. rquote db drquot ; Receive quote char. pktnum dw 0 ; Packet number. numpkt dw 0 ; Total number of packets sent. numrtr dw 0 ; Total number of retries. numtry db 0 ; Number of tries on this packet. oldtry db 0 ; Number of tries on previous packet. state db 0 ; Present state of the automaton. packet rb 4 ; Packet (data is part of it). data rb 5AH ; Data and checksum field of packet. recpkt rb 60H ; Receive packet storage (use the following). temp dw 0 argblk dw 0 ; For subroutine arguments. argbk1 dw 0 argbk2 dw 0 argbk3 dw 0 CSEG $ ; Send the generic finish command to the remote Kermit. finsen: mov ah, 'F' ; Ask for the finish command. call gensen ret ; Send the generic logout command to the remote Kermit. byesen: mov ah, 'L' ; Ask for the logout command. call gensen ret ; This procedure processes all the generic single packet sends. gensen: mov temp, ax ; Save the specific generic command. mov numtry, 0 ; Initialize count. call serini ; Initialize port. fins1: mov ah, numtry cmp ah, maxtry ; Too many times? js fins3 ; Nope, try it. fins2: lea dx, erms18 call tcrmsg ret fins3: inc numtry ; Increment number of tries. mov argblk, 0 ; Packet number zero. mov argbk1, 1 ; One piece of data. lea bx, data mov ax, temp ; Get the generic command. mov [bx], ah ; Finish running Kermit. mov ah, 'G' ; Generic command packet. call spack jmp fins2 ; Tell user and die. call rpack ; Get ACK. jmp fins1 ; Go try again. cmp ah, 'Y' ; Got an ACK? jnz fins4 ret ; Yes, then we're done. fins4: cmp ah, 'E' ; Error packet? jnz fins1 ; Try sending it again. call error1 ret ; Packet routines ; Send_Packet ; This routine assembles a packet from the arguments given and sends it ; to the host. ; ; Expects the following: ; AH - Type of packet (D,Y,N,S,R,E,F,Z,T) ; ARGBLK - Packet sequence number ; ARGBK1 - Number of data characters ; ; Returns: +1 always spack: push ax ; Save the packet type. lea bx, packet ; Get address of the send packet. mov ah, soh ; Get the start of header char. mov [bx], ah ; Put in the packet. inc bx ; Point to next char. mov ax, argbk1 ; Get the number of data chars. xchg ah, al add ah, ' '+3 ; Real packet character count made printable. mov [bx], ah ; Put in the packet. inc bx ; Point to next char. mov cl, ah ; Start the checksum. mov ax, argblk ; Get the packet number. xchg ah, al add ah, ' ' ; Add a space so the number is printable. mov [bx], ah ; Put in the packet. inc bx ; Point to next char. add cl, ah ; Add the packet number to the checksum. pop ax ; Get the packet type. mov [bx], ah ; Put in the packet. inc bx ; Point to next char. add cl, ah ; Add the type to the checksum. mov dx, argbk1 ; Get the packet size. spack2: cmp dx, 0 ; Are there any chars of data? jz spack3 ; No, finish up. dec dx ; Decrement the char count. mov ah, [bx] ; Get the next char. inc bx ; Point to next char. add cl, ah ; Add the char to the checksum. ; cmp ah, 0 ; jns spack2 ; mov hierr, 0FFH ; Set err flag. jmp spack2 ; Go try again. spack3: ; cmp hierr, 0 ; je sp3x ; Nothing special to do. ; call biterr ; mov hierr, 0 ; Reset. sp3x: mov ah, cl ; Get the character total. mov ch, cl ; Save here too (need 'cl' for shift). and ah, 0C0H ; Turn off all but the two high order bits. mov cl, 6 shr ah, cl ; Shift them into the low order position. mov cl, ch add ah, cl ; Add it to the old bits. and ah, 3FH ; Turn off the two high order bits. (MOD 64) add ah, ' ' ; Add a space so the number is printable. mov [bx], ah ; Put in the packet. inc bx ; Point to next char. mov ah, seol ; Get the EOL the other host wants. mov [bx], ah ; Put in the packet. inc bx ; Point to next char. mov ah, 0 ; Get a null. mov [bx], ah ; Put in the packet. cmp debug, 0 ; debug mode. je spack4 inc bx mov ah, '$' mov [bx], ah lea dx, scrsp ; Print string to move cursor. call tmsg lea dx, spmes call tmsg lea dx, packet call tmsg ; Debug end. spack4: call outpkt ; Call the system dependent routine. jmp rskp ; Write out a packet. outpkt: mov dh, spad ; Get the number of padding chars. outpk2: dec dh cmp dh, 0 jl outpk3 ; If none left proceed. mov al, spadch ; Get the padding char. call prtout ; Output it. jmp outpk2 outpk3: lea bx, packet ; Point to the packet. outlup: mov al, [bx] ; Get the next character. cmp al, 0 ; Is it a null? jnz outlp2 ret outlp2: call prtout ; Output the character. inc bx ; Increment the char pointer. jmp outlup ; Receive_Packet ; This routine waits for a packet arrive from the host. rpack: call inpkt ; Read up to a carriage return. rpack0: call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cmp ah, soh ; Is the char the start of header char? jne rpack0 ; No, go until it is. rpack1: call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cmp ah, soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. mov cl, ah ; Start the checksum. sub ah, ' '+3 ; Get the real data count. mov dh, ah ; Save it for later. mov al, ah ; Swap halves. mov ah, 0 mov argbk1, ax ; Save the data count. call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cmp ah, soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. add cl, ah ; Add it to the checksum. sub ah, ' ' ; Get the real packet number. mov al, ah ; Swap halves. mov ah, 0 mov argblk, ax ; Save the packet number. call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cmp ah, soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. mov temp, ax ; Save the message type. add cl, ah ; Add it to the checksum. lea bx, data ; Point to the data buffer. rpack2: dec dh ; Any data characters? js rpack3 ; If not go get the checksum. call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cmp ah, soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. mov [bx], ah ; Put the char into the packet. inc bx ; Point to the next character. add cl, ah ; Add it to the checksum. jmp rpack2 ; Go get another. rpack3: call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cmp ah, soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. sub ah, ' ' ; Turn the char back into a number. mov dh, cl ; Get the character total. and dh, 0C0H ; Turn off all but the two high order bits. mov ch, cl mov cl, 6 shr dh, cl ; Shift them into the low order position. mov cl, ch add dh, cl ; Add it to the old bits. and dh, 3FH ; Turn off the two high order bits. (MOD 64) cmp dh, ah ; Are they equal? jz rpack4 ; If so finish up. ret rpack4: mov ah, 0 mov [bx], ah ; Put a null at the end of the data. mov ax, temp ; Get the type. jmp rskp inpkt: lea bx, recpkt ; Point to the beginning of the packet. mov incnt, 0 inpkt2: call instat ; Any char there? jmp inpkt2 ; Go until there is one. call inchr ; Get the character. mov [bx], al ; Put the char in the packet. inc bx inc incnt cmp al, reol ; Is it the EOL char? jne inpkt2 ; If not loop for another. cmp incnt, 1 ; Ignore bare CR. jne inpkt6 mov incnt, 0 lea bx, recpkt jmp inpkt2 inpkt6: cmp ibmflg, 0 ; Is this the (dumb) IBM mainframe? jz inpkt4 ; If not then proceed. inpkt5: cmp state, 'S' ; Check if this is the Send-Init packet. jz inpkt4 ; If so don't wait for the XON. inpkt3: call inchr ; Wait for the turn around char. jmp inpkt4 cmp ah, xon ; Is it the IBM turn around character? jne inpkt3 ; If not, go until it is. inpkt4: cmp debug, 0 jz inpkt7 ; If not debugging don't print the packet. mov al, '$' ; Get a dollar sign. mov [bx], al ; Put in the packet. inc bx ; Point to next char. lea dx, scrrp ; Print the packet. call tmsg lea dx, rpmes call tmsg lea dx, recpkt call tmsg inpkt7: lea bx, recpkt mov pktptr, bx ; Save the packet pointer. ret ; If so we are done. getchr: push bx mov bx, pktptr ; Get the packet pointer. mov ah, [bx] ; Get the char. inc bx mov pktptr, bx pop bx ; Restore BX. cmp ah, reol ; Is it the EOL char? jne getcr2 ; If not return retskp. ret ; If so return failure. getcr2: jmp rskp ; This is where we go if we get an error packet. A call to ERROR ; positions the cursor and prints the message. A call to ERROR1 ; just prints a CRLF and then the message. error: mov state, 'A' ; Set the state to abort. lea dx, screrr call tmsg ; Position the cursor. jmp error2 error1: lea dx, cmcrlf call tmsg error2: lea bx, data ; Get to the string. add bx, argbk1 ; Add the length of the data. mov ah, '$' ; Put a dollar sign at the end. mov [bx], ah lea dx, data ; Print the error message. call tmsg ret ; Jump here if we die during a transfer. Print the error message in ; DX and abort. fatal: push dx ; Save the error message. lea dx, screrr call tmsg ; Position cursor. pop dx call tmsg jmp abort ; Change the state to abort. ; Print the status message in DX, ring the bell and position of the prompt. fnstat: push dx lea dx, scrst ; Print string to move cursor. call tmsg pop dx call tmsg lea dx, ender ; Ring them bells. call tmsg lea dx, scrrpr ; Print string to move cursor. call tmsg ret ; This routine sets up the data for init packet (either the ; Send_init or ACK packet). rpar: mov ah, rpsiz ; Get the receive packet size. add ah, ' ' ; Add a space to make it printable. mov [bx], ah ; Put it in the packet. mov ah, rtime ; Get the receive packet time out. add ah, ' ' ; Add a space. mov 1[bx], ah ; Put it in the packet. mov ah, rpad ; Get the number of padding chars. add ah, ' ' mov 2[bx], ah ; Put it in the packet. mov ah, rpadch ; Get the padding char. add ah, 100O ; Uncontrol it. and ah, 7FH mov 3[bx], ah ; Put it in the packet. mov ah, reol ; Get the EOL char. add ah, ' ' mov 4[bx], ah ; Put it in the packet. mov ah, rquote ; Get the quote char. mov 5[bx], ah ; Put it in the packet. mov ah, 06H ; Six pieces of data. ret ; This routine reads in all the send_init packet information. spar: push cx ; Save CX. mov cx, ax ; Save the number of arguments. mov ah, [bx] ; Get the max packet size. sub ah, ' ' ; Subtract a space. mov spsiz, ah ; Save it. mov ax, cx cmp al, 3 ; Fewer than three pieces? jl spar1 mov ah, 2[bx] ; Get the number of padding chars. sub ah, ' ' mov spad, ah mov ax, cx cmp al, 4 ; Fewer than four pieces? jl spar1 mov ah, 3[bx] ; Get the padding char. add ah, 100O ; Re-controlify it. and ah, 7FH mov spadch, ah mov ax, cx cmp al, 5 ; Fewer than five pieces? jl spar1 mov ah, 4[bx] ; Get the EOL char. sub ah, ' ' mov seol, ah mov ax, cx cmp al, 6 ; Fewer than six pieces? jl spar1 mov ah, 5[bx] ; Get the quote char. mov squote, ah spar1: pop cx ret ; If so we are done. ; These are some utility routines. ; Increment the packet number. incpkt: inc ax ; Increment it. and ax, 3FH ; Turn off the two high order bits. mov pktnum, ax ; Save modulo 64 of the number. inc numpkt ; Increment the number of packets. ret ; Check if the packet number is the present packet. chkpeq: mov ax, argblk ; Get the packet number. cmp ax, pktnum ; Is it the right packet number? je chkpe2 ret ; No. chkpe2: jmp rskp ; Yes. ; Is the packet number one more than present. chkpom: mov ax, pktnum ; Get the present packet number. inc ax ; Increment. and ax, 03FH ; Account for wraparound. cmp ax, argblk ; Is the packet's number one more than now? jz chkpm2 ; Yes, success. ret chkpm2: jmp rskp ; Check if the packet number is the previous packet. chkpol: inc oldtry ; Save the updated number of tries. mov ax, pktnum ; Get the present packet number. cmp ax, 0 ; Had we wrapped around? jne chkpl2 mov ax, 64 chkpl2: dec ax ; Decrement. cmp ax, argblk ; Is the packet's number one less than now? je chkpl3 jmp rskp chkpl3: ret ; Abort abort: mov state, 'A' ; Otherwise abort. ret ; ACK the packet. upack: call updat ; Updat the number of tries. ack: mov argbk1, 0 ; No data. (Packet number already in argblk). ack1: mov ah, 'Y' ; Acknowledge packet. call spack ; Send the packet. jmp r jmp rskp updat: mov ah, numtry ; Get the number of tries. mov oldtry, ah ; Save it. mov numtry, 0 ; Reset the number of tries. ret ; Re-ACK the previous packet. reack: call nretry ; Increment and print the number of retries. mov numtry, 0 ; Reset the number of tries. mov ah, 'Y' ; Acknowledge packet. call spack ; Send the packet. jmp r jmp rskp ; NAK that packet. nak: mov ax, pktnum ; Get the packet number we're waiting for. mov argblk, ax mov argbk1, 0 mov ah, 'N' ; NAK that packet. call spack jmp abort call nretry ; Increment and print the number of retries. ret ; Go around again. ; Print the number of retries. nretry: inc numrtr ; Increment the number of retries. pretry: lea dx, scrnrt call tmsg ; Position cursor. mov ax, numrtr call nout ; Write the number of retries. ret ; Print the number of packets. pnmpkt: lea dx, scrnp ; Print string to move cursor. call tmsg mov ax, numpkt call nout ; Write the number of packets. ret ; This routine prints the number in AX on the screen. nout: push bx ; Save some stuff. push cx push dx push ax mov bh, 0 ; Don't print leading zeros. and ah, F0H ; Only want high order nibble. mov cl, 4 shr ah, cl call pdig ; Print the digit. pop ax ; Restore argument. and ah, 0FH ; Just the low order nibble. call pdig mov ah, al and ah, 0F0H ; Only want high order nibble. mov cl, 4 shr ah, cl call pdig ; Print the digit. mov ah, al and ah, 0FH ; Just the low order nibble. mov bh, 0FFH ; Make sure at least one zero is printed. call pdig pop dx ; Restore some stuff. pop cx pop bx ret ; print the digit in register AH pdig: push ax ; Save it. cmp ah, 0 jne pdig2 cmp bh, 0 jne pdig2 pop ax ret pdig2: mov bh, 0FFH ; Set the print zero flag. cmp ah, 10 ; Do we use digits or a-f? jl usedig ; Digit. add ah, 'A'-10 ; Compute digit jmp havdig ; and proceed. usedig: add ah, '0' ; Convert to digit havdig: mov dl, ah mov ah, conout int dos pop ax ret ; Initialize buffers and clear line. init: call cmblnk lea dx, outlin ; Put statistics headers on the screen. call tmsg lea dx, outln2 call tmsg init1: mov chrcnt, bufsiz ; Number of chars left. lea dx, dma ; Addr for beginning. mov bufpnt, dx ret ; Clear out the old filename on the screen. clrfln: lea dx, scrfln ; Print string to move cursor. call tmsg lea dx, clreol ; The sequence to clear to EOL. call tmsg ret ; RECEIVE command read: call init ; Clear the line and initialize the buffers. read1: mov numpkt, 0 ; Set the number of packets to zero. mov numrtr, 0 ; Set the number of retries to zero. mov pktnum, 0 ; Set the packet number to zero. mov numtry, 0 ; Set the number of tries to zero. call serini ; Initialize serial port. call pretry mov state, 'R' ; Set the state to receive initiate. read2: call pnmpkt mov ah, state ; Get the state. cmp ah, 'D' ; Are we in the data send state? jne read3 call rdata jmp read2 read3: cmp ah, 'F' ; Are we in the file receive state? jne read4 call rfile ; Call receive file. jmp read2 read4: cmp ah, 'R' ; Are we in the receive initiate state? jne read5 call rinit jmp read2 read5: cmp ah, 'C' ; Are we in the receive complete state? jne read6 lea dx, infms3 ; Plus a little cuteness. call fnstat ret read6: lea dx, infms4 ; Plus a little cuteness. call fnstat ret ; Receive routines ; Receive init rinit: mov ah, numtry ; Get the number of tries. cmp ah, imxtry ; Have we reached the maximum number of tries? jl rinit2 lea dx, ermes7 ; Print this error and die. jmp fatal rinit2: inc ah ; Increment it. mov numtry, ah ; Save the updated number of tries. call rpack ; Get a packet. jmp nak ; Trashed packet: nak, retry. cmp ah, 'S' ; Is it a send initiate packet? jne rinit3 ; If not see if its an error. mov ah, numtry ; Get the number of tries. mov oldtry, ah ; Save it. mov numtry, 0 ; Reset the number of tries. mov ax, argblk ; Returned packet number. (Synchronize them.) call incpkt ; Increment the packet number. mov ax, argbk1 ; Get the number of arguments received. lea bx, data ; Get a pointer to the data. call spar ; Get the data into the proper variables. lea bx, data ; Get a pointer to our data block. call rpar ; Set up the receive parameters. xchg ah, al mov ah, 0 mov argbk1, ax ; Store the returned number of arguments. call ack1 ; ACK the packet. jmp abort mov ah, 'F' ; Set the state to file send. mov state, ah ret rinit3: cmp ah, 'E' ; Is it an error packet? jne rinit4 call error rinit4: jmp abort ; Receive file rfile: cmp numtry, maxtry ; Have we reached the maximum number of tries? jl rfile1 lea dx, ermes8 ; Print this error and die. jmp fatal rfile1: inc numtry ; Save the updated number of tries. call rpack ; Get a packet. jmp nak ; Trashed packet: nak, retry. cmp ah, 'S' ; Is it a send initiate packet? jne rfile2 ; No, try next type. cmp oldtry, imxtry ; Have we reached the maximum number of tries? jl rfil12 ; If not proceed. lea dx, ermes7 ; Print this error and die. jmp fatal rfil12: call chkpol ; Check the packet number, is it right? jmp nak ; No, NAK and try again. lea bx, data ; Get a pointer to our data block. call rpar ; Set up the parameter information. xchg ah, al mov ah, 0 mov argbk1, ax ; Save the number of arguments. call reack ; Re-ACK the old packet. jmp abort ret rfile2: cmp ah, 'Z' ; Is it an EOF packet? jne rfile3 ; No, try next type. cmp oldtry, maxtry ; Have we reached the maximum number of tries? jl rfil21 ; If not proceed. lea dx, ermes9 ; Print this error and die. jmp fatal rfil21: call chkpol ; Check the packet number, is it right? jmp nak ; No, NAK and try again. mov argbk1, 0 ; No data. call reack ; Re-ACK the previous packet jmp abort ret rfile3: cmp ah, 'F' ; Start of file? jne rfile4 call chkpeq ; Packet numbers equal? jmp nak ; No, NAK it and try again. call incpkt ; Increment the number of packets. call gofil ; Get a file to write to. jmp abort call init1 ; Initialize all the buffers. call upack ; Update counters and ACK the packet. jmp abort mov state, 'D' ; Set the state to data receive. ret rfile4: cmp ah, 'B' ; End of transmission? jne rfile5 call chkpeq ; Packet numbers equal? jmp nak ; No, NAK it and try again. call ack ; ACK the packet. jmp abort mov state, 'C' ; Set the state to complete. ret rfile5: cmp ah, 'E' ; Is it an error packet? jne rfile6 call error rfile6: jmp abort ; Receive data rdata: cmp numtry, maxtry ; Get the number of tries. jl rdata1 lea dx, erms10 ; Print this error and die. jmp fatal rdata1: inc numtry ; Save the updated number of tries. call rpack ; Get a packet. jmp nak ; Trashed packet: nak, retry. cmp ah, 'D' ; Is it a data packet? je rdat11 jmp rdata2 ; No, try next type. rdat11: call chkpeq ; Packet numbers equal? jmp rdat12 ; No, check if previous packet. call incpkt ; Increment the number of packets. mov ax, argbk1 ; Get the length of the data. call ptchr jmp abort ; Unable to write out chars; abort. call upack ; ACK the packet. jmp abort ret rdat12: cmp oldtry, maxtry ; Have we reached the maximum number of tries? jl rdat13 ; If not proceed. lea dx, erms10 ; Print this error and die. jmp fatal rdat13: call chkpol ; Check the packet number, is it right? jmp nak ; No, NAK it and try again. mov argbk1, 0 ; No data. call reack ; Re-ACK the previous packet. jmp abort ret rdata2: cmp ah, 'F' ; Start of file? jne rdata3 ; No, try next type. cmp oldtry, maxtry ; Have we reached the maximum number of tries? jl rdat21 ; If not proceed. lea dx, ermes8 ; Print this error and die. jmp fatal rdat21: call chkpol ; Check the packet number, is it right? jmp nak ; No, NAK it and try again. mov argbk1, 0 ; No data. call reack ; Re-ACK the previous packet jmp abort ret rdata3: cmp ah, 'Z' ; Is it a EOF packet? je rdat32 jmp rdata4 ; Try and see if its an error. rdat32: call chkpeq ; Packet numbers equal? jmp nak ; No, NAK it and try again. call incpkt ; Increment the packet number. mov bx, bufpnt ; Get the dma pointer. mov ax, 80H sub ax, chrcnt ; Get the number of chars left in the DMA. cmp ax, 80H jne rdat34 call outbuf ; Write out buffer if no room for ^Z. jmp abort jmp rdat36 ; Go close the file. rdat34: mov cl, 'Z'-100O ; Put in a ^Z for EOF. mov [bx], cl inc ax dec chrcnt mov cx, chrcnt mov temp, cx inc bx rdt3: inc ax cmp ax, 80H jg rdat35 ; Pad till full. mov cl, 0 ; Use nulls. mov [bx], cl inc bx jmp rdt3 rdat35: call outbuf ; Output the last buffer. jmp abort ; Give up if the disk is full. rdat36: lea dx, fcb call closf ; Close up the file. call upack ; ACK the packet. jmp abort mov state, 'F' ret rdata4: cmp ah, 'E' ; Is it an error packet. jne rdata5 call error rdata5: jmp abort ; Send a file. send: lea dx, fcb call gtjfn ; Get the first file. cmp al, 0FFH ;* Any found? jne send12 lea dx, erms15 call tcrmsg ret send12: cmp wldflg, 0 ; Any wildcards. je send16 ; Nope, so no problem. ; lea bx, fcb ;* Remember what FCB looked like. ; lea di, cpfcb ; mov cl, 37 ; Size of FCB. ; call fcbcpy ; lea di, fcb+1 ; Copy filename from DTA to FCB. ; lea bx, buff+1 ; mov cl, 11 ; call fcbcpy send16: call init ; Clear the line and initialize the buffers. call serini ; Initialize serial port. mov pktnum, 0 ; Set the packet number to zero. mov numtry, 0 ; Set the number of tries to zero. mov numpkt, 0 ; Set the number of packets to zero. mov numrtr, 0 ; Set the number of retries to zero. call pretry ; Print the number of retries. mov state,'S' ; Set the state to receive initiate. send2: call pnmpkt ; Print the number of packets. cmp state, 'D' ; Are we in the data send state? jne send3 call sdata jmp send2 send3: cmp state, 'F' ; Are we in the file send state? jne send4 call sfile ; Call send file. jmp send2 send4: cmp state, 'Z' ; Are we in the EOF state? jne send5 call seof jmp send2 send5: cmp state, 'S' ; Are we in the send initiate state? jne send6 call sinit jmp send2 send6: cmp state, 'B' ; Are we in the eot state? jne send7 call seot jmp send2 send7: cmp state, 'C' ; Are we in the send complete state? jne send8 lea dx, infms3 ; Plus a little cuteness. call fnstat ret send8: lea dx, infms4 ; Plus a little cuteness. call fnstat ret ; Send routines ; Send initiate sinit: cmp numtry, imxtry ; Have we reached the maximum number of tries? jl sinit2 lea dx, erms14 call fatal sinit2: inc numtry ; Save the updated number of tries. lea bx, data ; Get a pointer to our data block. call rpar ; Set up the parameter information. xchg ah, al mov ah, 0 mov argbk1, ax ; Save the number of arguments. mov ax, numpkt ; Get the packet number. mov argblk, ax mov ah, 'S' ; Send initiate packet. call spack ; Send the packet. jmp abort call rpack ; Get a packet. jmp r ; Trashed packet don't change state, retry. cmp ah, 'Y' ; ACK? jne sinit3 ; If not try next. call chkpeq ; Is it the right packet number? jmp nretry ; Increment the retries and go try again. call incpkt ; Increment the packet number. mov ax, argbk1 ; Get the number of pieces of data. lea bx, data ; Pointer to the data. call spar ; Read in the data. mov ah, numtry ; Get the number of tries. mov oldtry, ah ; Save it. mov numtry, 0 ; Reset the number of tries. mov state, 'F' ; Set the state to file send. call getfil ; Open the file. jmp abort ; Something is wrong, die. ret sinit3: cmp ah, 'N' ; NAK? jne sinit4 ; If not see if its an error. call nretry ret sinit4: cmp ah, 'E' ; Is it an error packet? jne sinit5 call error sinit5: jmp abort ; Send file header sfile: cmp numtry, maxtry ; Have we reached the maximum number of tries? jl sfile1 lea dx, erms14 call fatal sfile1: inc numtry ; Increment it. lea bx, data ; Get a pointer to our data block. mov datptr, bx lea bx, fcb+1 ; Pointer to file name in FCB. mov fcbptr, bx ; Save position in FCB. mov cl, 0 ; Counter for chars in file name. mov ch, 0 ; Counter for number of chars in FCB. sfil11: cmp ch, 8H ; Ninth char? jne sfil12 mov ah, '.' mov bx, datptr mov [bx], ah ; Put dot in data packet. inc bx mov datptr, bx ; Save new position in data packet. inc cl sfil12: inc ch cmp ch, 0CH ; Twelve? jns sfil13 mov bx, fcbptr mov ah, [bx] ; Get char of filename. inc bx mov fcbptr, bx ; Save position in FCB. cmp ah, '!' ; Is it a good char? jl sfil11 ; If not, get the next. mov bx, datptr mov [bx], ah ; Put char in data buffer. inc cl ; Increment counter. inc bx mov datptr, bx ; Save new position. jmp sfil11 ; Get another char. sfil13: mov ch, 0 mov argbk1, cx ; Save number of char in filename. mov bx, datptr mov ah, '$' mov [bx], ah ; Put dollar sign for printing. call clrfln lea dx, data ; Print file name. call tmsg mov ax, pktnum ; Get the packet number. mov argblk, ax mov ah, 'F' ; File header packet. call spack ; Send the packet. jmp abort call rpack ; Get a packet. jmp r ; Trashed packet don't change state, retry. cmp ah, 'Y' ; ACK? jne sfile2 ; If not try next. call chkpeq ; Packet number right. jmp nretry ; Increment the retries and go try again. sfil14: call incpkt ; Increment the packet number. call updat ; Update the number of tries. sfil15: mov ah, 0 ; Get a zero. lea bx, fcb add bx, 20H mov [bx], ah ; Set the record number to zero. mov eoflag, ah ; Indicate not EOF. mov ah, 0FFH mov filflg, ah ; Indicate file buffer empty. call gtchr jmp sfil16 ; Error go see if its EOF. jmp sfil18 ; Got the chars, proceed. sfil16: cmp ah, 0FFH ; Is it EOF? je sfil17 jmp abort ; If not give up. sfil17: mov ah, 'Z' ; Set the state to EOF. mov state, ah ret sfil18: mov siz, ax mov state, 'D' ; Set the state to data send. ret sfile2: cmp ah, 'N' ; NAK? jne sfile3 ; Try if error packet. call chkpom ; Is the packet's number one more than now? jmp nretry ; Increment the retries and go try again. jmp sfil14 ; If so, join the ACK. sfile3: cmp ah, 'E' ; Is it an error packet. jne sfile4 call error sfile4: jmp abort ; Send data sdata: cmp numtry, maxtry ; Have we reached the maximum number of tries? jl sdata1 lea dx, erms14 call fatal sdata1: inc numtry ; Increment it. lea dx, data ; Get a pointer to our data block. mov datptr, dx lea dx, filbuf ; Pointer to chars to be sent. mov cbfptr, dx mov cx, 1 ; First char. sdat11: mov bx, cbfptr mov ah, [bx] inc cbfptr mov bx, datptr mov [bx], ah ; Put the char in the data packet. inc datptr ; Save position in data packet. inc cx ; Increment the count. cmp cx, siz ; Have we transfered that many? jle sdat11 ; If not get another. mov ax, siz ; Number of char in char buffer. mov argbk1, ax mov ax, pktnum ; Get the packet number. mov argblk, ax mov ah, 'D' ; Data packet. call spack ; Send the packet. jmp abort call rpack ; Get a packet. jmp r ; Trashed packet don't change state, retry. cmp ah, 'Y' ; ACK? jne sdata2 ; If not try next. call chkpeq ; Right packet number? jmp nretry ; Increment the retries and go try again. sdat12: call incpkt ; Increment the packet number. call updat ; Update the number of tries. call gtchr jmp sdat13 ; Error go see if its EOF. mov siz, ax ; Save the size of the data gotten. ret sdat13: cmp ah, 0FFH ; Is it EOF? je sdat14 jmp abort ; If not give up. sdat14: mov state, 'Z' ; Set the state to EOF. ret sdata2: cmp ah, 'N' ; NAK? jne sdata3 ; See if is an error packet. call chkpom ; Is the packet's number one more than now? jmp nretry ; Increment the retries and go try again. jmp sdat12 sdata3: cmp ah, 'E' ; Is it an error packet. jne sdata4 call error sdata4: jmp abort ; Send EOF seof: cmp numtry, maxtry ; Have we reached the maximum number of tries? jl seof1 lea dx, erms14 call fatal seof1: inc numtry ; Increment it. mov ax, pktnum ; Get the packet number. mov argblk, ax mov argbk1, 0 ; No data. mov ah, 'Z' ; EOF packet. call spack ; Send the packet. jmp abort call rpack ; Get a packet. jmp r ; Trashed packet don't change state, retry. cmp ah, 'Y' ; ACK? jne seof2 ; If not try next. call chkpeq ; Is it the right packet number? jmp nretry ; Increment the retries and go try again. seof12: call incpkt ; Increment the packet number. call updat ; Update the number of tries. lea dx, fcb ; Close the file. call closf call gtnfil ; Get the next file. jmp seof13 ; No more. mov state, 'F' ; Set the state to file send. ret seof13: mov state, 'B' ; Set the state to EOT. ret seof2: cmp ah, 'N' ; NAK? jne seof3 ; Try and see if its an error packet. call chkpom ; Is the packet's number one more than now? jmp nretry ; Increment the retries and go try again. jmp seof12 seof3: cmp ah, 'E' ; Is it an error packet? jne seof4 call error seof4: jmp abort ; Send EOT seot: cmp numtry, maxtry ; Have we reached the maximum number of tries? jl seot1 lea dx, erms14 call fatal seot1: inc numtry ; Increment it. mov ax, pktnum ; Get the packet number. mov argblk, ax mov argbk1, 0 ; No data. mov ah, 'B' ; EOF packet. call spack ; Send the packet. jmp abort call rpack ; Get a packet. jmp r ; Trashed packet don't change state, retry. cmp ah, 'Y' ; ACK? jne seot2 ; If not try next. call chkpeq ; Is it the right packet number. jmp nretry ; Increment the retries and go try again. seot12: call incpkt ; Increment the packet number. call updat ; Update the number of tries. mov state, 'C' ; Set the state to file send. ret seot2: cmp ah, 'N' ; NAK? jne seot3 ; Is it error. call chkpom ; Is the packet's number one more than now? jmp nretry ; Increment the retries and go try again. jmp seot12 seot3: cmp ah, 'E' ; Is it an error packet. jne seot4 call error seot4: jmp abort f4: jmp abort ; Send EOT seot: cmp