2000

                              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.


2000

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 2
b00
E 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 
0

