XMODEM PROTOCOL (How DOES it work?) by Dave Larsen Update 1.1 ~ 22Jan87 Copyright (C) 1986, All rights reserved. On more than one occasion, I've been asked to reveal the secrets of Xmodem protocol. Xmodem is probably the most widely used communications protocol in the personal computer world. Everyone knows what it is and yet no one seems to know how it works. This text will help to relieve that problem. Or just add to it... Xmodem was originally described by Ward Christensen and has been known variously as Christensen protocol, KMD and so on. In the years since its first development, Xmodem has gone through many modifications. Xmodem with CRC, 1k packet transfers and batch transfers are all improvements upon the original Xmodem protocol which relies on the generation of checksum values for error detection in file transfers. This is the flavor I will describe here. NOTE: This text is designed to help you write your own Xmodem protocol file transfer routine regardless of the language you happen to be using and thus is necessarily explained in generic terms. Programming details are entirely your problem. DEFINITIONS: A. "Flag Byte" and "Status Byte" Arbitrary names I've given to bytes transferred during an Xmodem protocol data transfer. B. "Block Number" Xmodem sends its data in 128 Byte "Blocks." "Block Number" refers to the number of the block being transferred. C. "Local Block Number" The Block Number that you keep track of internally when receiving a file. D. "Remote Block Number" The Block Number that the sending computer sends to you when you're receiving a file. E. "Checksum #1" and "Checksum #2" One byte values that Xmodem uses in order to detect errors in data transfer. F. "Prompt the keyboard." By this I mean that you should send an appropriate message to the monitor and wait for a reply. G. "Check the keyboard." In this instance, you should check the keyboard to see if a key has been pressed. Do not wait for a reply. H. "Get the __________." When I say to "get" something, that means you should check your status port and wait until it tells you there is something in your data port. Then, get the data from the data port. I. "Send the __________." When I say to "send" something, that means you should send the indicated data out the data port. If you are receiving a file, as a precautionary measure you should check the status port and make sure that the line is clear. OVERVIEW: Xmodem could be described as "receiver driven." In other words, the receiving computer is in control of the file transfer. It dictates to the sending computer when it is ready to receive data, whether or not there is an error, and so on. Below is a simplified example of an Xmodem transfer session. Data sent by the receiving computer is in parenthesis "()" and data sent by the sending computer is in square brackets "[]". 1. (Flag Byte) 2. [Status Byte] 3. [Block Number] 4. [Checksum Byte #1] 5. [128 Byte "Block" of Data] 6. [Checksum Byte #2]...............go back to #1 First, the receiving computer sends a Flag Byte to the sending computer. Depending on this value, the sending computer will resend the current block, send the next block, or abort the transfer. Then, the sending computer sends a Status Byte. This byte informs the receiving computer that the transfer has been canceled, is complete, or that it is ready to continue. Next, the sending computer sends the Block Number, then the first Checksum Byte, then the 128 Byte Block of Data and finally, the second Checksum Byte. The receiving computer evaluates the checksum data and sends the appropriate Flag Byte and so on. RECEIVING A FILE: 1. Prompt the keyboard for a file name and open it for input. 2. You should use this step to set aside whatever buffers, arrays, and/or variables you may need. 3. Check the keyboard for a cancel command. This is done primarily to allow you to gracefully escape from an unwanted transfer session. If you've canceled the transfer, go to #4c below. 4. Send a Flag Byte to the sending computer. The Flag Byte will be one of the following: a. ACK (Acknowledge 06 HEX, crtl-F) - Indicates that there were no errors in the last block sent. The sending computer will send the next block. b. NAK (Not Acknowledge 15 HEX, crtl-U) - Indicates that there was an error in the last block sent. The sending computer will resend that block. NOTE: WHEN A FILE TRANSFER IS STARTED UP, THE VERY FIRST FLAG BYTE THAT YOU SEND OUT MUST BE A NAK. In this way, the sending computer is prompted to send you the first block. Essentially, you've tricked it in to thinking that there was an error in the first block so it resends it. Tricky huh? c. CAN (Cancel 18 HEX, crtl-X) - Indicates that the transfer has been canceled by the receiving computer. Generally, you will have to send more than one CAN. Five to ten CAN's in as many seconds should do the trick. This is done in order to prevent aborting a file transfer accidentally. It should be noted however that a CAN is generally, but not universally, recognized by Xmodem protocols. You may have to wait until the sending computer gets tired and abandons the send. In any event, you should close the file that you opened in #1 and end. 5. Get the Status Byte. The Status Byte will be one of the following: a. SOH (Start of Heading 01 HEX, ctrl-A) - Indicates that the sending computer is ready to send a block. b. EOT (End of Transmission 04 HEX, ctrl-D) - Indicates that the file transfer is complete. To prevent accidentally ending the file transfer session, it would be advisable to wait for five to ten seconds to see if a byte other than EOT comes. If different data is received, go back to #4b. If not, close the file that you opened in #1, send out a final ACK, and end. c. CAN (Cancel 18 HEX, crtl-X) - Indicates that the transfer has been canceled by the sending computer. Again, to prevent accidentally ending the file transfer session, it would be advisable to wait for five to ten seconds to see if a byte other than CAN comes. If different data is received, go back to #4b. If not, close the file that you opened in #1, and end. NOTE: If the Status Byte is not one of the above, or if no Status Byte is received within 10 seconds, go back to #4b. If you do not receive an appropriate Status Byte after 10 tries, you might as well forget it. Close the file that you opened in #1, and end. 6. Get the Block Number. Put this value into a variable, you will need it to calculate the checksum. If no Block Number is received within about 2 seconds, go back to #4b. NOTE: This value is the nth block according to the sending computer. Referred to hereafter as Remote Block Number. You should keep track of the Block Number internally as well (Local Block Number). Additionally, you should know that at the beginning of the file transfer, the Block Number will be 1 and will go up to 255. After the 255th block has been received, the Block Number will reset to 0. 7. Get Checksum Byte #1. Put this value into a variable, you will need it later. Again, if no checksum is received within about 2 seconds, go back to #4b. 8. Get a Block (128 Bytes) of Data. As this data comes in, store it in a buffer or array of some sort. If you have to wait more than a second for any single data byte chances are good that something is seriously wrong. Go to #4b. 9. Get Checksum Byte #2. Put this value into a variable as well. Again, if no checksum is received within about 2 seconds, go back to #4b. **************************************************************************** * The sending computer is now waiting for you to send it a NAK or an ACK. * * Before you can do that, you must decide if you've received everything * * without error. The sending computer will wait for several seconds while * * you do this, so don't panic. * **************************************************************************** 10. Compare the Local Block Number and the Remote Block Number. If they are equal fine, go to #14. 11. If they are unequal, you'll want to keep track of how many times this happens. Then go back to #4b. If the Block Numbers are unequal three times in a row then that probably means that the sending computer is either a block ahead of you or a block behind you. 12. If the sending computer is a block ahead of you there is nothing you can do about it. Go to #4c. 13. If the sending computer is 1 block behind you all you have to do is tell it to send the next block. Go to #4a. If the sending computer is more than one block behind, you should give it up and try again. Go to #4c. 14. Evaluate the checksum data. Perform the following calculations: (1) + (Remote Block Number) + (Checksum Byte #1) + (The ASCII value of each character in the 128 Byte Block of Data). Let's call this value X. Plug X into one of the following formulas: In Hexadecimal form: Let Y = (X-(X/100h)*100h) (ie. If X = 213D, Y = 3D) In Decimal form: Let Y = (X-INT(X/256)*256) (ie. X = 8509, Y=61) Where INT returns the largest integer less than or equal to (X/256). 15. If Y = Checksum #2 then there are no errors. Save the 128 Byte Block to disk or whatever. Increment the counter you are using for Local Block Number and go to #3. 16. If Y is unequal to Checksum #2 then you've got an error. Go to #4b. NOTE: Any time that you "go to" someplace, you will probably want to reset some of the variables you are using. In particular, you will probably want to clear out the buffer or array you are using to hold the block of data. Again, exact program details are left up to you. SENDING A FILE: Since sending a file is pretty much the same as receiving a file, only in reverse, this section is a little shorter. But not to fear, all will be made clear. 1. Prompt the keyboard for a file name and open it for output. 2. You should use this step to set aside whatever buffers, arrays, and/or variables you may need. 3. Check the keyboard for a cancel command. If you've canceled the transfer, then go to #9c. 4. Get a Flag Byte. a. If it's an ACK, send the next block. b. If it's a NAK, resend the current block. Go to #9a. c. If it's a CAN, close the file that you opened in #1, and end. Note, you should check to make sure this is correct. (See RECEIVING A FILE, #5c.) NOTE: Many implementations of Xmodem protocol that I've seen will assume a NAK and resend the block if an appropriate Flag Byte is not received within 10 seconds. I do not recommend this. Rather, let the protocol be completely receiver driven. In other words, simply wait for an appropriate Flag Byte. If you do not receive it within 1 minute close the file that you opened in #1, and end. **************************************************************************** * As you should know by now, the receiving computer is currently waiting * * for you to send the Status Byte. In this time, you'll prepare the data * * you need to send. * **************************************************************************** 5. Check to see if there are still 128 bytes left in the file. If yes, go to #7. 6. Since Xmodem can only send data in 128 Byte Blocks, if there are fewer than 128 bytes left in the file you will need to pad the end of the file with control-Z's (1AH) so that you'll have a complete block. There are no "short" blocks. 7. Calculate Checksum #1. Checksum #1 is calculated as FF (Hex) or 255 (Decimal) minus the Block Number. 8. Calculate Checksum #2. This is done the same as before. (See RECEIVING A FILE, #14.) 9. Send a Status Byte. a. Send a SOH if you're ready to send a block. b. Send an EOT if you're finished with the transfer. c. Send a CAN if you've canceled the transfer in #3 above. Close the file that you opened in #1, and end. Note, you may have to send more than one CAN. (See RECEIVING A FILE, #4c.) 10. Send the Block Number. Again, remember that the first Block Number will be 1 and go to 255. After the 255th block, reset to zero. 11. Send Checksum Byte #1. 12. Send a Block (128 Bytes) of Data. 13. Send Checksum Byte #2. 14. Go to #3. HEX DUMP: I've included here a hex dump of an example file transfer session so you can see exactly what happens. Only the data received is shown. 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 ----------------------------------------------- A 01 01 FE 20 20 20 20 20 20 20 20 20 20 20 20 20 Receiving computer B 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 sends out a NAK. The C 20 20 20 20 20 20 20 20 0D 0A 20 20 43 4C 45 41 sending computer sends D 52 49 4E 47 48 4F 55 53 45 20 4C 4F 43 41 4C 20 Status Byte: A01 (01H) E 53 59 53 54 45 4D 53 20 44 49 52 45 43 54 4F 52 Block #: A02 (01H) F 59 0D 0A 20 20 20 20 20 20 20 20 20 20 20 55 70 Checksum #1: A03 (FEH) G 64 61 74 65 64 20 28 30 36 2F 31 36 2F 38 36 29 Data: A04-I03 [OK] H 0D 0A 20 20 20 20 20 20 20 20 54 68 61 6E 6B 73 Checksum #2: I04 (43H) I 20 74 6F 43 01 02 FD 20 42 72 69 61 63 20 48 65 Receiving computer J 72 73 74 69 67 0D 0A 20 20 20 20 20 20 20 20 20 sends out an ACK. The K 20 20 61 6E 64 20 4A 6F 65 20 57 68 69 70 70 6C sending computer sends L 65 20 21 21 0D 0A 0D 0A 0D 0A 20 34 2D 42 20 43 Status Byte: I05 (01H) M 4F 4D 57 68 79 20 64 69 64 20 79 6F 75 20 64 65 Block #: I06 (02H) N 63 6F 64 65 20 74 68 69 73 3F 20 20 2D 38 39 36 Checksum #1: I07 (FDH) O 36 0D 0A 0D 0A 20 37 54 48 20 46 4F 52 43 45 2E Data I08-Q07 [ERROR] P 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E Checksum #2: Q08 (77H) Q 2E 2E 2E 2E 38 38 35 77 01 02 FD 20 42 72 69 61 Receiving computer R 6E 20 48 65 72 73 74 69 67 0D 0A 20 20 20 20 20 sends out a NAK. The S 20 20 20 20 20 20 61 6E 64 20 4A 6F 65 20 57 68 sending computer sends T 69 70 70 6C 65 20 21 21 0D 0A 0D 0A 0D 0A 20 34 Status Byte: Q09 (01H) U 2D 42 20 43 4F 4D 50 55 54 45 52 20 53 54 4F 52 Block #: Q10 (02H) V 45 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 38 39 30 Checksum #1: Q11 (FDH) W 2D 38 39 36 36 0D 0A 0D 0A 20 37 54 48 20 46 4F Data Q12-Y11 [OK] X 52 43 45 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E Checksum #2: Y12 (77H) Y 2E 2E 2E 2E 2E 2E 2E 2E 38 38 35 77 01 03 FC 2D Receiving computer Z 34 31 31 33 0D 0A 0D 0A 20 41 52 4D 41 44 41 2E sends out an ACK. The AA 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E sending computer sends BB 2E 2E 2E 2E 2E 2E 2E 38 35 35 2D 37 32 33 30 0D Status Byte: Y13 (01H) CC 0A 0D 0A 20 41 52 4D 41 44 41 20 2F 2F 2E 2E 2E Block #: Y14 (03H) DD 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E Checksum #1: Y15 (FCH) EE 2E 2E 38 35 35 2D 32 37 30 36 0D 0A 0D 0A 20 41 Data: Y16-GG15 [OK] FF 54 41 52 49 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E Checksum #2: GG16(50H) GG 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 32 36 50 Receiving computer HH 04 sends out an ACK. The sending computer sends Status Byte: HH01(04H) Receiving computer recognizes EOT, sends ACK and quits. [DONE] A FEW FINAL NOTES: As far as I know, there is no set "standard" for Xmodem protocol. Ward Christensen developed it, placed it in the public domain, and from then on it was subject to change and modification by many people. The basic frame work is the same but there are many different methods for achieving the same end. I have presented but one of them. Experienced programmers will probably notice that putting 128 Bytes of Data into a buffer, then pulling the data out of the buffer to calculate the ASCII value of each character is somewhat redundant. The justification for this is simple. Since part of the idea behind this document is to describe Xmodem protocol for implementation on many different computers and in many different languages, I had to take into account the simple fact that some computers and programming languages are faster than others. I had to describe Xmodem so that it would work if you were programming in slow BASIC or the fast Assembler. By calculating the ASCII value of each character outside of the sending/receiving loop, no processing time is used which could cause data loss in slower languages like BASIC. (Or at high baud rates.) Once you understand the ins and outs of Xmodem and the limitations of your hardware and software, streamlining your program should be no trouble and is recommended. I sincerely hope that this information has been of benefit to you. I know I could have used something like this when I started out! Donations will be gladly accepted (College students are always broke!) but are not expected. In any case, please send suggestions, corrections, complaints, and the like to: Out To Lunch Software c/o Dave Larsen 101 E. 14th ave. Suite S Columbus, OH 43201-1855 Permission to reprint this text, in part or in whole, is freely given for non-commercial uses only as long as proper credit is given to the author. Any other uses of this text are strictly forbidden without the expressed written consent of the author. - eof -uthor. Any other uses of this text are strictly forbidden without the expressed written consent of