Classic Computer Magazine Archive COMPUTE! ISSUE 80 / JANUARY 1987 / PAGE 75

XMODEM
File Transfer For Commodore 64 And 128

Bert Kerkhof

By adding XMODEM capabilities to telecommunications, you can increase the reliability of file transfers. The program included with this article lets you upload or download files with the XMODEM protocol.


One of the most popular uses for computer telecommunications is the exchange of programs. Commercial information services offer thousands of public domain programs which can be yours simply for the cost of downloading (capturing) them over the telephone lines. Or, you may wish to upload (send) a copy of a program you have written to a friend in some distant city.
    The simplest way to send a program is in the form of a sequential series of characters, without any error checking. However, if you're communicating over long distances, noise on the phone line may cause characters to be dropped or garbled in the transmission. When you're transmitting text, a garbled character here and there probably won't cause serious problems, but when you're transferring programs, even a single incorrect character may prevent the program from working.
    XMODEM is the name of a filetransfer protocol devised by Ward Christensen (who also set up the first computer bulletin board). The XMODEM scheme allows you to send any kind of data-executable programs as well as plain ASCII text-and includes error checking which guarantees a reliability rate in excess of 99 percent. There are other, more sophisticated protocols, but XMODEM is by far the most popular. Nearly every commercial information service and many bulletin boards give you the option of transferring files in this reliable format.

Getting Started
The program below is a simple terminal (telecommunications) program with the ability to upload and download files using the XMODEM protocol. If you have a Commodore 64, type in and save Program 1 as listed. If you have a 128, type in Program 1, but add or change the following lines:

DB 116 KEY 1,CHR$(133):KEY 3,C
       HR$(134)
JE 117 KEY 5,CHR$(135):KEY 7,C
       HR$(136)
SK 130 PRINT CHR$(11);SPC(10);
BX 495 DO:GET#2,B$:GOSUB 730
MG 500 LOOP UNTIL W AND 8:RETU

       RN
PX 620 GET#2,B$:GOSUB 730:IF W
       THEN 630
BX 655 GET#2,B$:GOSUB 730:IF W
       <>8 THEN 650
PR 725 REM ** GET RS-232 STATU
       S **
PQ 730 W=PEEK(2580):POKE 2580,
       0:RETURN

    If you have an 80-column monitor for your 128, also change the following lines to create a version for 80-column mode:

DS 105 FAST:COLOR 6,16
QG 185 PRINT CHR$(5);CHR$(27);
       "U";
KH 230 PRINT :PRINT CHR$(144);
SC 250 PRINT CHR$(R(B));:RETUR

       N

    For either the 128 or 64, add this line if you have a Commodore 1660 modem. This line causes the modem to receive the call when the modem is in answer mode:

GD 112 POKE56579,PEEK(56579)OR
       32:POKE56577,PEEK(56577
       )AND223

    Be sure that your modem is connected and turned on before you run the program. The program begins in terminal mode, which is very easy to understand. Every character that you type on the keyboard is sent out through the modem, and every character received from the modem is displayed on the screen.
    Each of the four function keys has a purpose in this program. The f1 key turns local echo on and off. If you are communicating with a computer that does not echo what you send, press the f1 function key to turn on local echo. In this mode, your computer displays each character as you type it. When the program begins, echo is turned off, meaning that the computer doesn't automatically print characters that you type. Instead, it relies on the computer at the other end of the line to send an echo, or copy, of each character you send. Most commercial information services and computer bulletin boards provide an echo, which is compatible with this mode. Note that the echo feature affects what you see on the screen, but does not change what you send or receive from the modem.
    The f7 key displays a list of the function-key actions in case you forget what the function keys do. The f3 and f5 keys are used, respectively, to initiate the reception or transmission of a file with XMODEM error checking.

Downloading With XMODEM
Once you're ready to download (receive) a file, simply press the f3 key. The program prompts you to enter the name and file type you wish the resulting disk file to have. For the file type, enter a P for a program (PRG) file, an S for a sequential (SEQ) file, or a U for a user (USR) file. This program does not support the transfer of relative (REL) files. You must type the filename and file type on the same line, separated by a comma. For instance, this command tells the program to store the incoming file in a PRG type file named MYPROG:
MYPROG,P

    You have 60 seconds in which to respond to this prompt. If you don't type anything, the program assumes that you've changed your mind, and it aborts the transfer and returns to terminal mode. After you enter the filename and file type, the program begins to receive the file and store it on disk.
    To upload (send) a file, press the f5 key and enter the filename and type of the file you wish to send. Again, you have 60 seconds in which to respond to the prompt before the program aborts the transfer and returns to terminal mode.

Monitor The Transmission
Once the transfer begins, the program keeps you informed about its progress. It prints a plus sign (+) for every block (see below) that is transferred without any errors. If a block is rejected, the program prints an O. If nothing is received within the allotted time, the program prints a period (.) to signal a timeout.
    If a disk error occurs on your end during the transfer, the program prints the disk-error message on the screen and automatically cancels the transfer. Under some circumstances (very noisy phone lines, a disk error at the other end of the link, or whatever), the program may have no choice but to give up on the transfer. When this occurs, it prints the message Timeout on the screen. If the entire transfer is successful, the program prints the message Complete.

ACK Or NAK
In the XMODEM protocol, files are always sent in blocks, or packages, containing 128 bytes of data. The sender sends 128 bytes at a time, along with a header, block numbers, and a checksum. When the receiving computer gets the block, it checks to make sure that the header, block numbers, and checksum match up correctly. If no errors are found, the receiver sends an ACK character (ACKnowledge, ASCII 6) to signal "All is well; send the next block." If an error occurs, the receiver sends a NAK character (Negative AcKnowledge, ASCII 21) to say "That block was not received correctly; send it again." At the end of the transmission, the sender transmits an EOT character (End Of Text, ASCII 4) to signal that the transfer is complete.
    Each block has a maximum of ten chances to get through. After ten failed attempts, the receiver sends a CAN character (CANcel, ASCII 26) to inform the sender that the transfer has failed. A timeout (excessive delay) also counts as an error. By these simple means, XMODEM achieves a very high reliability rate. The 128 data bytes can contain any eight-bit values, so this method can be used to transmit machine language programs, tokenized BASIC programs, or any other eight-bit data.
    This program includes several features that help insure error-free transmissions. One important point involves flushing the RS-232 line at appropriate spots. This is done to prevent data bytes from being mistaken as control signals (ACK, NAK, or whatever). Thus, before it sends an ACK or NAK, the receiver gets characters until no more characters are waiting to be received. Likewise, the sender waits until no characters are incoming before it sends each new block.
    In many XMODEM implementations, the sending computer automatically resends a block if a timeout occurs without any response from the receiver. In this program, the sender retransmits only when it receives a NAK from the receiver. This program is designed to operate at 300 bps (bits per second, often termed baud). Due to the slowness of BASIC, it will not work correctly at higher transmission speeds.


XMODEM File Transfer

For instructions on entering this program, please refer to "COMPUTE!'s Guide to Typing In Programs" in this issue of COMPUTEI.

BA 100 REM ++ XMODEM FILE TRAN
       SFER ++
QQ 105 POKE 53280,11:POKE 5328
       1,11
EC 110 OPEN 2,2,0,CHR$(6)+CHR$
       (0):M=255
CE 115 G$=CHR$(20):U$=CHR$(175
       )
FB 120 Z$=CHR$(0):OPEN 15,8,15
XE 125 PRINT CHR$(144);CHR$(14
       7);CHR$(14);
GG 130 PRINT CHR$(8);SPC(10);
CQ 135 PRINT "XMODEM FILE TRAN
       SFER":PRINT
EQ 140 GOSUB 275:DIM R(255),S(
       255)
SE 145 FOR B=0 TO 31:S(B)=B:NE
       XT:R(8)=20
DK 150 R(13)=13:S(20)=8:FOR B=
       32 TO 64
EJ 155 R(B)=B:S(B)=B:NEXT:S(16
       0)=32
RF 160 FOR B=65 TO 90:I=B+128:
       R(B)=I
ED 165 S(I)=B:NEXT:FOR B=91 TO
       96:R(B)=B
ER 170 S(B)=B:NEXT:FOR B=97 TO
        122:I=B-32
AK 175 R(B)=I:S(I)=B:NEXT:FOR
       {SPACE}B=123 TO 127
EB 180 I=B+96:R(B)=I:S(I)=B:NE
       XT
HE 185 PRINT CHR$(152);U$;
CQ 190 GET#2,B$:IF B$="" THEN
       {SPACE}200
EB 195 B=ASC(B$):GOSUB 245:GOT
       O 190
BS 200 GET B$:IF B$="" THEN 19
       0
XK 205 B=ASC(B$)
MQ 210 IF B>132 AND B<137 THEN
       230
KF 215 B=S(B):PRINT#2,CHR$(B);
HK 220 IF H THEN GOSUB 250
KE 225 GOTO 190
FM 230 PRINT G$:PRINT CHR$(144
       );
KG 235 ON B-132 GOSUB 260,415,
       290,275
MH 240 GOTO 185
HC 245 REM ++ PRINT BYTE ++
DB 250 PRINT G$;CHR$(R(B));U$;
       :RETURN
FB 255 REM ++ F1, ECHO ++
RD 260 PRINT "ECHO: ";MID$("ON
        OFF",H+1,3)
MS 265 H=3-H:RETURN
CR 270 REM ++ F7, HELP ++
HX 275 PRINT "{RVS}Fl{OFF}=ECH
       O {RVS}F3{OFF}=RECEIVE
       {SPACE}{RVS}F5{OFF}=TRA
       NSMIT {RVS}F7{OFF}=HELP
       "
MJ 280 RETURN
JF 285 REM ++ F5, TRANSMIT FIL
       E ++
AH 290 PRINT "NAME OF FILE TO
       {SPACE}UPLOAD:":B$="R"
EM 295 GOSUB 675:IF F THEN RET
       URN
FE 300 C$=CHR$(21):GOSUB 395:C
       $=C$+CHR$(6)
JA 305 FOR K=1 TO M+1:K=K AND
       {SPACE}M
QM 310 IF F THEN 370
MF 315 S=0:D$="":FOR I=1 TO 12
       8:GET#8,B$
FA 320 B=ASC(B$+Z$):D$=D$+CHR$
       (B):S=S+B
GC 325 IF ST THEN A=4:F=1:GOTO
        335
KG 330 NEXT
EG 335 IF LEN(D$)=128 THEN 345
HJ 340 D$=D$+Z$:GOTO 335
FX 345 GOSUB 495
BG 350 PRINT#2,CHR$(1);CHR$(K)
       ;CHR$(M-K);D$;CHR$(S AN
       D M);
CS 355 GOSUB 395:PRINT MID$("O
       +",C,1);
FR 360 IF C=1 THEN 345
PX 365 NEXT K
AR 370 PRINT:CLOSE B:GOSUB 700
BR 375 GOSUB 485:IF F>1 THEN 7
       15
GC 380 GOSUB 395:IF C=2 THEN 7
       15
PC 385 GOTO 375
GQ 390 REM ++ GET CONTROL BYTE
       100 SEC ++
SB 395 FOR J=1 TO 10:GOSUB 510
DC 400 IF E THEN NEXT:A=24:F=2
RA 405 RETURN
CG 410 REM ++ F3, RECEIVE FILE
        ++
XX 415 PRINT "FILENAME FOR DOW
       NLOADED DATA:":B$="W":A
       =21
DA 420 GOSUB 675:IF F THEN RET
       URN
RK 425 C$=CHR$(1)+CHR$(4)
FJ 430 FOR K=1 TO M+1:K=K AND
       {SPACE}M
XE 435 IF F THEN 470
SP 440 FOR J=1 TO 10:GOSUB 485
       :A=21
MR 445 GOSUB 510
AH 450 IF C=1 THEN GOSUB 550:P
       RINT MID$("+O",E+1,1);
GJ 455 IF C=2 THEN A=6:F=1
EP 460 IF E AND F=0 THEN NEXT:
       A=24:F=2
KF 465 NEXT K
FP 470 PRINT:CLOSE 8:GOSUB 700
RR 475 GOSUB 485:GOTO 715
FM 480 REM ++ SEND ANSWER BYTE
        ++
DX 485 GOSUB 495:PRINT#2,CHR$(
       A);:RETURN
BB 490 REM ++ CLEAR INPUT BUFF
       ER ++
XD 495 GET#2,B$:IF (ST AND 8)=
       0 THEN 495
QF 500 RETURN
EC 505 REM ++ GET CONTROL BYTE
        10 SEC ++
XE 510 E=0:P=600:T=TI
PK 515 C=3:GOSUB 620
MH 520 IF E THEN PRINT ".";:RE
       TURN
AK 525 IF B$=CHR$(24) THEN A=2
       4:F=4:RETURN
KD 530 FOR C=1 TO LEN(C$)
EX 535 IF B$=MID$(C$,C,1) THEN
        RETURN
BH 540 NEXT:GOSUB 650:GOTO 515
MM 545 REM ++ GET DATA ++
HB 550 P=60:T=TI:GOSUB 620:IF
       {SPACE}E THEN RETURN
PH 555 N=B:T=TI:GOSUB 620:IF E
        THEN RETURN
BB 560 IF N+B<>M THEN E=1:GOTO
        650
BJ 565 S=0:D$="":FOR I=1 TO 12
       8
AF 570 T=TI:GOSUB 620:IF E THE
       N RETURN
FE 575 D$=D$+CHR$(B):S=S+B:NEX
       T
EG 580 T=TI:GOSUB 620:IF E THE
       N RETURN
CS 585 IF B<>(S AND M) THEN E=
       1:GOT0 650
SK 590 A=6:D=K-N-AND M
XF 595 IF D>1 THEN A=24:F=3
SQ 600 IF D THEN E=1:RETURN
FJ 605 PRINT#8,D$;:IF ST THEN
       {SPACE}A=24:F=5
PQ 610 RETURN
DA 615 REM ++ GET BYTE ++
QP 620 GET#2,B$:W=ST:IF W THEN
        630
KD 625 B=ASC(B$+Z$):RETURN
SF 630 IF W AND 247 THEN GOSUB
        650
GC 635 IF TI>T+P THEN E=1:RETU
       RN
HQ 640 GOTO 620
ME 645 REM ++ SKIP UNTIL SILEN
       CE ++
QD 650 U=TI
GK 655 GET#2,B$:IF ST<>8 THEN
       {SPACE}650
SG 660 IF TI>U+60 THEN RETURN
BF 665 GOTO 655
PJ 670 REM ++ TRANSFER BEGIN +
       +
KM 675 F=0:N$="*":T$="P"
ED 680 N$="":T$="":INPUT "[ NA
       ME, TYPE ]";N$,T$
DS 685 IF N$="" OR (T$<>"P" AN
       D T$<>"S" AND T$<>"U")
       {SPACE}THEN 680
DB 690 OPEN 8,8,8,"0:"+N$+","+
       T$+","+B$
BK 695 REM ++ READ ERROR CHANN
       EL ++
RK 700 INPUT#15,I,M$:IF I=0 TH
       EN RETURN
MA 705 PRINT"{RVS}";M$:A=24:F=
       5:CLOSE 8:RETURN
MJ 710 REM ++ TRANSFER END ++
HR 715 M$="COMPLETETIMEOUT DIS
       ORDERCANCEL"
KF 720 PRINT MID$(M$,F*8-7,8):
       RETURN