THE TOPS-20 IMPLEMENTATION OF THE MODEM7 PROTOCOL Copyright (C) 1985 Frank J. Wancho This draft document describes the MODEM7 Protocol as implemented in the TOPS-20 MODEM program. The TOPS-20 MODEM program was originally written by Bill Westfield (BILLW@SCORE), and is currently maintained by Frank Wancho (WANCHO@SIMTEL20). The current source file is available in MICRO:MODEM.MAC along with other TOPS-20 utilities via ANONYMOUS FTP to SIMTEL20. The sections are: A. SEND A FILE B. SEND A FILENAME C. RECEIVE A FILE D. RECEIVE A FILENAME E. ABORT PROCESSING For file transfer operations, the TOPS-20 MODEM program accepts the following command format: S|R [B|A] [N] filespec S or R for Send or Receive. B or A for Binary or ASCII storage (Receive only). N for Network Binary Mode, which must be specified if the user is connected through a TAC port. filespec may be unambiguous (a single filename) or ambiguous (containing wildcard characters). If the filespec is ambiguous, Batch Mode is automatically assumed and the received files are stored in Binary format for subsequent post-processing, whether or not the A or B sub-options were specified. A. SEND A FILE: 1. Get sub-options and set flag if N option requested to handle binary negotiations for an end-user on a TAC. Ignore all other sub-options. 2. Disable ^C interrupts if not a controlling terminal. A controlling terminal is the one a user is one when using a dialout modem. 3. Parse the filename requested. 4. Get next filename if it is a wildcard filename. 5. Determine type of file and open file accordingly. Files may be any one of three types: ASCII, TOPS-20 Binary, or ITS Binary. ITS Binary is the same as TOPS-20 Binary, but has a unique four-byte header which must be skipped. 6. Turn on network binary mode if the N sub-option flag is set. By default, a TAC connection is 7 bits per character. Network binary mode turns on 8-bit transparency at the TAC. 7. If the parsed filename was wildcarded, assume implicit batch mode and send filename. The SEND FILENAME protocol is described in a separate section below. 8. Set record number to zero. 9. Clear the CRC flag. 10. Set timeout counter to 120 (two minutes). 11. Wait one second for a character: a. If no character is received within one second, decrement and check the timeout counter. If timeout counter has not reached zero, wait another second for a character, otherwise abort process. b. If a character has been received within the one-second timeout, check its value: 1). If it is a "C", set the CRC flag and proceed to Step 12. 2). If it is a CAN (^X), go to ABORT PROCESSING. 3). If it is a NAK (^U), proceed to Step 12. 4). If it is none of the above, decrement and check the timeout counter. If timeout counter has not reached zero, wait another second for a character, otherwise go to ABORT PROCESSING. 12. Set the error counter to 10. 13. If EOF has been reached: a. Send EOT (^D) and wait for ACK (^F). If ACK is not received within 15 seconds, send EOT again, and wait for ACK. b. If wildcard flag is on, go to Step 4. c. Close file and exit program or return to command mode. 14. Get the next 128-byte buffer to send. If the buffer is not full, pad the buffer with SUBs (^Zs) if the file is ASCII, or with NULLs (^@s) if the file is binary. 15. If buffer is empty, go to Step 13. 16. Increment record count and set timeout counter to 10. 17. Zero Checksum and CRC registers. 18. Send header consisting of an SOH (^A), record count modulo 256 and its ones complement. 19. Send the buffer as a binary string. 20. Compute and send either the checksum byte or the two-byte CRC value (high order byte first), depending on the setting of the CRC flag. 21. Set the timeout counter to 192 (192 seconds). 22. Wait for an character with one-second timeout. a. If an ACK (^F), go to Step 12 to send next buffer. b. If a NAK (^U), decrement and check the error counter. If the error counter is exhausted, go do ABORT PROCESSING. Otherwise go to Step 17 to resend the same buffer. c. If neither character received was an ACK or a NAK, or the one-second receive character routine timed out, decrement and check the timeout counter. If the timeout counter is exhausted, go do ABORT PROCESSING. Othewise go wait for another character. B. SEND A FILENAME: 1. Get filename into a buffer with a maximum of the first eight characters blank filled stuffed into the first eight positions of the buffer and with a maximum of the first three characters of the extent blank filled stuffed into the next three positions of the buffer. 2. Wait up to two minutes for the initial NAK (^U). If two minutes elapses, send an ACK (^F), then send an EOT (^D) to indicate no more files, and either exit the program or return to command mode. 3. Send an ACK (^F). 4. Set the character counter to 11. 5. Zero the checksum register. 6. Set the buffer pointer to the first character in the buffer. 7. Skip any TOPS-20 quoting characters (^V) and get the next character to be sent. 8. Add it to the checksum register. 9. Send the character. 10. Wait up to 15 seconds for an ACK. If 15 seconds elapses without receiving an ACK, send a "u" and go to Step 2. 11. If an ACK is received, decrement and check the character counter. If the counter is not zero, got to Step 7. 12. Send a SUB (^Z) indicating the end of the filename. 13. Wait up to 16 seconds to receive the checksum byte computed by the receiving end. If 16 seconds elapses without receiving anything, send a "u" and go to Step 2. 14. Add a SUB to the checksum register modulo 256 and compare it with the received checksum. If there is no match, send a "u" and go to Step 2. 15. Send an ACK and proceed to sending the file itself. C. RECEIVE A FILE: 1. Get any sub-options, setting a flag if the N sub-option is requested, and the Binary flag if the B sub-option is requested. Otherwise, assume the file to be received is to be stored as an ASCII file. 2. Parse the filename from the command line. 3. If a wildcard filespec is given, set a flag. Otherwise open the specified filename according to the mode requested in the sub-options. 4. Determine the block wait time from the speed of the line. This value is computed to be three times the length of time it should take for the sending end to transmit a 128-byte block. The default value is 13 seconds if the speed of the line cannot be determined, as is currently the case with a network connection. 5. Turn on network binary mode if requested. 6. Disable ^C interrupts if not a controlling terminal. 7. If wildcard mode is on, get the filename and open the file in Binary Mode regardless of any requested suboption. The RECEIVE A FILENAME Protocol is described below in a separate section. 8. Zero the record number counter. 9. Zero the last record received counter. 10. Set the timeout counter to 7. 11. Turn the CRC flag ON. 12. Decrement and check the timeout counter. Go to Step 14 if exhausted. 13. Send a "C" and wait ten seconds for a reply: a. If ten seconds lapse without receiving a character, go to Step 12. b. If the received character is an EOT (^D), go to Step 34. c. If the received character is a CAN (^X), go to ABORT PROCESSING. d. If the received character is an SOH (^A), reset the timeout counter to 11 and go to Step 20. e. If none of the above, go to Step 12. 14. Turn the CRC flag off. 15. Set the timeout (error) counter to 11. 16. Decrement and check the timeout counter. Go to ABORT PROCESSING if exhausted. 17. Send a NAK. 18. Zero the Checksum register. 19. Wait up to 16 seconds for a response: a. If the 16 seconds elapses without receiving a character, go to Step 16. b. If the received character is an EOT (^D), go to Step 34. c. If the received character is a CAN (^X), go do ABORT PROCESSING. d. If the received character is not an SOH (^A), go to Step 19. 20. Add the received character to the checksum register. 21. Wait up to 16 seconds for the next byte. If 16 seconds elapse, wait for the line to go quiet for one second, send a NAK (i.e., flush the line), and go to Step 16. 22. Save the received byte as the record number. 23. Add the record number to the checksum register. 24. Wait up to 16 seconds for the record number complement. If 16 seconds elapse, flush the line and go to Step 16. 25. Add the received record number complement to the checksum register. 26. If the checksum register is not zero, flush the line and go to Step 16. 27. Accumulate the next 128 bytes in the block wait time computed in Step 4. Most implementations of this protocol set a counter to 128 and wait with a one-second timeout for each of the 128 characters, falling through to the next Step if any timout occurs. 28. If the block wait time expires without receiving all 128 bytes, flush the line and go to Step 16. 29. If the CRC flag is OFF: a. Wait up to 16 seconds for the sender's checksum and if a timeout occurs, flush the line and go to Step 16. b. Save the received checksum and compute the checksum for the received block. c. If the checksums do not match, flush the line and go to Step 16. 30. If the CRC flag is ON: a. Wait up to 16 seconds for each of the two bytes of the sender's CRC. If a timeout occurs, flush the line and go to Step 16. b. Save each received byte of the CRC and compute the CRC value for the received block. c. If the CRCs do not match, flush the line and go to Step 16. 31. Check the received record number: a. If the received record number matches the expected record number, i.e., the previously received record number plus one, save the current record number as the previously received record number. b. If the received record number is the same as the previously received record number, go to Step 33. c. If neither, go to ABORT PROCESSING. 32. Save the 128-byte buffer to disk. 33. Send an ACK, reset the timeout counter to 10, and go to Step 18. 34. Send an ACK and close the file. 35. If the wildcard flag is set, go to Step 7. Otherwise, go back to command mode or exit the program. D. RECEIVE A FILENAME: 1. Zero the checksum register. 2. Set the timeout counter to 180 for a three-minute wait. 3. Send a NAK. 4. Wait one second for a response: a. If no response in one second, decrement and check the timeout counter. If the counter has expired, go to Step 14. Otherwise, go to Step 3. b. If a character is received and it is not an ACK (^F), decrement and check the timeout counter. If the counter has expired, go to Step 14. Otherwise, go to Step 3. 5. Set up the filename buffer for 12 characters and character counter to receive 11 characters of the filename. 6. Wait up to 16 seconds for a character of the file name: a. If 16 seconds elapse without receiving a character, go to Step 1. b. If the received character is an EOT (^D), go to Step 14. (An EOT means no more files to receive.) 7. Add the received character to the checksum register. 8. Check the received character: a. If it is neither a SPACE nor a NULL, and is not the "ninth" received character, stuff a ^V (the TOPS-20 quote character) into the filename buffer and then the received character. b. If it is the ninth, stuff a period into the filename buffer, then a ^V and the received character. c. If it is either a SPACE or a NULL and the ninth character has not yet been received, stuff a period into the filename buffer and set character counter to indicate that the "ninth" character has been received. 9. Send an ACK, decrement the character counter and go to Step 6 if the counter is not exhausted. 10. Wait up to 16 seconds for the next character. If the received character is not a SUB (^Z) or 16 seconds elapsed without receiving any character, go to Step 1. 11. Add the ^Z to the checksum register and send the contents of the checksum register. 12. Wait up to 15 seconds for an ACK. If the timeout expires, go to Step 1. 13. Open the requested filename, wait two seconds, and return to the caller. 14. Send an ACK and wait for the line to be quiet for one second. Restore the stack and return to command mode or exit the program. E. ABORT PROCESSING 1. Close any open file. 2. Flush the line. 3. Return to command mode or exit the program.