home *** CD-ROM | disk | FTP | other *** search
- /*
-
- LMODEM.C -- Little MODEM program
-
- Byte, Nov. 1983, pages 410-28
-
- This program implements the Ward Christensen assembly-language
- program in C. It is derived from the cmodem13.c program
- by Jack M. Wierda and Roderick W. Hart. The modes available have
- been greatly reduced. The program provides terminal emulation
- and text capture as well as file send and receive capabilities.
-
- Hardware-dependent functions have been isolated from the
- majority of the program.
-
- Written by David D. Clark
- 9-Jan-83
-
- Adapted to the KayPro II and Software Toolworks' (C/80 V. 3.0)
- C compiler by Lee R. Bradley
-
- To compile and assemble with AS.COM, use the following:
-
- A>C -C2500 -D800 B:LMODEM.ASM=LMODEM.C
- A>AS B:LMODEM.COM=B:LMODEM.ASM
-
- Incorporated dynamic allocation of buffer space. Used ideas in Clark's
- version 2.
-
- To compile, assemble and link with M80 and L80, use the following commands
-
- A>C -C2500 -D800 -M1 B:LMODEM.MAC=LMODEM.C
- A>M80 B:LMODEM.REL=B:LMODEM.MAC
- A>L80 B:LMODEM,STDLIB,CLIBRARY,B:LMODEM/N/E
-
- */
-
- #include "printf.h"
- #include "printf.c"
- #include "scanf.h"
- #include "scanf.c"
-
- #define DOTS 50 /* sector counting dots per line */
- #define SPS 12000 /* loops per second */
- #define SECSIZ 0x80
- #define DATAMASK 0x7f
- #define BUFSECS 128 /* number of file sectors to buffer */
- #define BLKSIZ 16384 /* size of blocks written (1 extent) */
- #define ERRORMAX 10 /* maximum errors before abort */
- #define RETRYMAX 5 /* maximum retrys before abort */
- #define DIRCTIO 6 /* cpm bdos direct-console io command */
- #define INPUT 0xff /* direct-console io input */
- #define FALSE 0
- #define TRUE 1 /* lrb */
- #define NULL 0 /* lrb */
-
- /***************************************************************************/
- /* */
- /* Special characters used in the file transfer-protocol. */
- /* */
- /***************************************************************************/
-
- #define TIMEOUT -1 /* timeout character */
- #define SOH 1 /* start of sector character */
- #define EOT 4 /* end of transmission character */
- #define ACK 6 /* acknowledge sector transmission */
- #define NAK 21 /* error in transmission detected */
-
- /****************************************************************************/
- /* */
- /* Miscellaneous ASCII characters */
- /* */
- /****************************************************************************/
-
- #define TAB 9
- #define LF 10
- #define CR 13
- #define CTRLZ 26 /* end of text-file character */
-
- /****************************************************************************/
- /* */
- /* These #defines determine which keys will be interpreted as */
- /* command characters. */
- /* */
- /****************************************************************************/
-
- #define CTRLB 2
- #define CTRLE 5
- #define CTRLK 11
- #define CTRLL 12
- #define CTRLQ 17
- #define CTRLR 18
- #define CTRLS 19
- #define CTRLT 20
- #define CTRLV 22
-
- #define SETBAUD CTRLB /* set baudrate */
- #define CAPTURE CTRLT /* toggle text capture */
- #define HELP CTRLE /* get instructions */
- #define KEEP CTRLK /* keep text buffer */
- #define LITERAL CTRLL /* send literal character */
- #define QUIT CTRLQ /* quit */
- #define RECEIVE CTRLR /* receive file by sectors */
- #define SEND CTRLS /* send file by sectors */
- #define VIEW CTRLV /* view data transfered */
-
- char ViewMode, BFlag, KbData, ModData;
- char AsciiFlg, ShowTrans, ShowRec, View;
- char *Bufr;
- char FileName[14];
- int Fd;
- unsigned BufSiz,BufPtr;
-
- char *baudrate;
- extern char Cmode;
-
- main(argc, argv)
- int argc;
- char **argv;
- {
-
- Cmode = 0;
- AsciiFlg = ShowRecv = ShowTrans = BFlag = View = FALSE;
- BufPtr = 0;
- BufSiz=0x7f80; /* make sure this isn't too big !! */
- ViewMode = KbData = NULL;
- if ((Bufr = alloc(BufSiz)) == 0) {
- printf("Can't allocate the buffer\n");
- exit();
- }
-
- instruct();
- initializemodem();
-
- while (ctsready() && (KbData != QUIT)) {
- if (KbData = bdos(DIRCTIO, INPUT)) /* get any char at kbd */
- switch (KbData) {
-
- case SETBAUD:
- printf("\nEnter 1 for 300, 2 for 1200 or 3 for 2400 baud.\n");
- switch (getchar())
- { case '1': baud(5); baudrate = "300"; break;
- case '2': baud(7); baudrate = "1200"; break;
- case '3': baud(10); baudrate = "2400";
- }
- printf("\nBaud rate set at %s bps.\n", baudrate);
- break;
-
- case HELP:
- instruct();
- break;
-
- case CAPTURE:
- BFlag = ~BFlag;
- if (BFlag)
- printf("Capture initiated");
- else
- printf("Capture terminated");
- printf(", %u", BufSiz - BufPtr);
- printf(" bytes free\n");
- break;
-
- case KEEP:
- if (!BufPtr)
- printf("Nothing to save\n");
- else {
- printf("Save as what file? ");
- scanf("%s", FileName);
- Bufr[BufPtr] = CTRLZ;
- Fd = fopen(FileName,"w");
- if (Fd == NULL)
- printf("Cannot create %s\n",
- FileName);
- else {
- write(Fd, Bufr,
- (BufPtr/SECSIZ+1)*SECSIZ);
- fclose(Fd);
- BFlag = FALSE;
- BufPtr = 0;
- }
- }
- break;
-
- case RECEIVE:
- printf("Receive what file? ");
- scanf("%s", FileName);
- readfile(FileName);
- break;
-
- case SEND:
- printf("Send what file? ");
- scanf("%s", FileName);
- sendfile(FileName);
- break;
-
- case QUIT:
- hangup();
- break;
-
- case VIEW:
- View = ~View;
- if (View) {
- printf("View as Ascii or Hex? ");
- ViewMode = toupper(getchar());
- printf("\nDisplay will be in ");
- if (ViewMode == 'A')
- printf("Ascii\n");
- else
- printf("Hex\n");
- }
- else
- printf("Viewing disabled\n");
- break;
-
- case LITERAL:
- while ( !(KbData = bdos(DIRCTIO, INPUT)) );
- mcharout(KbData);
- break;
-
- default:
- mcharout(KbData);
- break;
- }
-
- if (minprdy()) {
- ModData = mcharinp();
- if (BFlag && (BufPtr < BufSiz))
- Bufr[BufPtr++] = ModData;
- else if (BFlag)
- printf("Capture Bufr overflow\n");
- putchar(ModData);
- }
- }
- }
-
- instruct()
- {
- printf("\n\nLMODEM.C, 5/21/86");
- printf("\nDavid D. Clark, Byte, Nov. '83, pages 410-428");
- printf("\n");
- printf("\nAdapted to C/80 \n");
- printf("Lee R. Bradley, Mouse House Software\n");
- printf("\n");
- printf("LMODEM.C is a small remote communication program.\n");
- printf("When started it acts simply as a dumb terminal. \n");
- printf("The following commands are available:\n\n");
-
- printf("Press RETURN to continue\n");
- getchar();
-
- show_char(SETBAUD);
- printf("\t- Set baudrate. \n");
-
- show_char(CAPTURE);
- printf("\t- Toggles text capture. Initially inactive. When\n");
- printf("\t acting as a terminal, all text received will be\n");
- printf("\t saved in a buffer. The buffer may be saved on disk\n");
- printf("\t with the 'keep' command below.\n");
-
- show_char(HELP);
- printf("\t- Help on the commands. In case you forget what\n");
- printf("\t you are reading right now, type ctrl-E and you will\n");
- printf("\t be told what commands do what.\n");
-
- show_char(KEEP);
- printf("\t- Keep. Lets you save captured text in a diskfile. \n");
- printf("\t You will be asked to name the file in which the text\n");
- printf("\t will be saved. The text buffer will be cleared if the\n");
- printf("\t text is saved successfully.\n");
-
- show_char(RECEIVE);
- printf("\t- Receive file in Ward Christensen protocol. You will\n");
- printf("\t be asked for the name of the file to write into.\n");
-
- show_char(SEND);
- printf("\t- Send file in Ward Christensen protocol.\n");
-
- show_char(VIEW);
- printf("\t- Toggle data viewing. Initially inactive. Data \n");
- printf("\t transmitted will be displayed in Ascii or Hex.\n");
-
- show_char(LITERAL);
- printf("\t- Send literal character. A character typed after this\n");
- printf("\t character will be sent as is. In this way, characters\n");
- printf("\t that represent commands may be sent without being\n");
- printf("\t interpreted as a command.\n");
-
- show_char(QUIT);
- printf("\t- Quit. Exit program.\n\n");
-
- return;
-
- }
- show_char(c)
- char c;
- {
- if ((c>= 0) && (c<= 31))
- printf("ctrl-%c", c + '@');
- else if (c == ' ')
- printf("<spc>");
- else if ((c >='@') && (c <= '~'))
- putchar(c);
- else if (c == 127)
- printf("<del>");
- else
- printf("%xH", c);
- return;
- }
-
- readfile(file)
- char *file;
- {
- int firstchar, sectnum, sectcurr, sectcomp, errors;
- int checksum;
- int errorflag;
- unsigned j, bufptr;
-
- if (View) {
- ShowRecv = TRUE;
- ShowTrans = FALSE;
- }
-
- Fd = fopen(file,"w");
- if (Fd == 0) {
- printf("Cannot create %s\n", file);
- return;
- }
- else
- printf("Receiving %s\n\n", file);
- sectnum = errors = bufptr = 0;
- initializemodem();
- sendchar(NAK);
- do {
- errorflag = FALSE;
- do { /* get synchronization character */
- firstchar = readchar(5);
- } while ( firstchar != SOH
- && firstchar != EOT
- && firstchar != TIMEOUT);
- if (firstchar == TIMEOUT) {
- errorflag = TRUE;
- printf("Timeout error\n");
- }
- if (firstchar == SOH) { /* main if */
- sectcurr = readchar(1);
- sectcomp = readchar(1);
- if ((sectcurr + sectcomp) == -1) {
- if ((sectcurr & 0xff) == (sectnum + 1 & 0xff)) { /* lrb */
- checksum = 0;
- if (ViewMode == 'A')
- AsciiFlg = TRUE;
- for (j = bufptr; j < (bufptr + SECSIZ); j++) {
- Bufr[j] = readchar(1);
- checksum = (checksum + Bufr[j]) & 0xff;
- }
- AsciiFlg = FALSE;
- if ((checksum & 0xff) == (readchar(1) & 0xff)) { /* lrb */
- errors = 0;
- sectnum++;
- bufptr += SECSIZ;
- if ((sectnum % BUFSECS) == 0) {
- bufptr = 0;
- if (write(Fd, Bufr, BLKSIZ) == NULL) {
- printf("Error writing file\n");
- fclose(Fd);
- return;
- }
- do ;
- while (readchar(1) != TIMEOUT);
- }
- if (!ShowRecv)
- if (((sectnum - 1 ) % DOTS) ==0)
- printf("\n<%4d>.", sectnum);
- else
- printf(".");
- sendchar(ACK);
- }
- else {
- printf("\nChecksum error, expected ");
- printf("<%0x>\n", checksum);
- errorflag = TRUE;
- } /* This is a comment */
- }
- else
- if ((sectcurr & 0xff) == (sectnum & 0xff)) { /* lrb */
- printf("\nReceived duplicate sector %d\n", sectnum);
- /* wait for silence on the line */
- do ; /* nothing */
- while (readchar(1) != TIMEOUT);
- sendchar(ACK);
- }
- else {
- printf("\nSynchronization error\n");
- errorflag = TRUE;
- }
- }
- else {
- printf("\nSector number error\n");
- errorflag = TRUE;
- }
- } /* end of main if. This right brace was missing from Byte */
-
- if (errorflag == TRUE) {
- errors++;
- printf("Error %d\n", errors);
- while (readchar(1) != TIMEOUT);
- sendchar(NAK);
- }
-
- } while (firstchar != EOT && errors != ERRORMAX);
-
- if ((firstchar == EOT) && (errors < ERRORMAX)) {
- sendchar(ACK);
- write(Fd, Bufr, bufptr);
- fclose(Fd);
- printf("\n\nTransfer complete\n");
- }
- else
- printf("\n\nAborting\n");
- }
-
-
- readchar (seconds)
- unsigned seconds;
- {
- char data;
- seconds = seconds*SPS;
- while (!minprdy() && seconds) /* wait until input ready */
- --seconds;
- if (!seconds)
- return(TIMEOUT); /* nothing arrived in time */
- data = mcharinp(); /* get it */
- if (ShowRecv) { /* show if needed */
- if (AsciiFlg)
- if (((data >= ' ') && (data <= DATAMASK))
- || data == LF || data == CR || data == TAB)
- putchar(data);
- else
- printf("[%0x]", data);
- else
- printf("[%0x]", data);
- }
- return data;
- }
-
- sendfile(file)
- char *file;
- {
- int sectnum, sectors, attempts;
- int checksum;
- unsigned j, bufptr;
-
- if (View) {
- ShowRecv = FALSE;
- ShowTrans = TRUE;
- }
- Fd = fopen(file, "r");
- if (Fd == NULL) {
- printf("Cannot open %s\n", file);
- return;
- }
- else
- printf("Sending %s\n\n", file);
- initializemodem();
- attempts = 0;
- sectnum = 1;
-
- while ((sectors = read(Fd, Bufr, BufSiz)) && (attempts != RETRYMAX)) {
- if (sectors == NULL) {
- printf("\nError reading file\n");
- fclose(Fd);
- return;
- }
- else {
- sectors = sectors / SECSIZ + 1;
- bufptr = 0;
- do {
- attempts = 0;
- do {
- if (!ShowTrans)
- if (((sectnum - 1) % DOTS) == 0)
- printf("\n<%4d>.", sectnum);
- else
- printf(".");
- sendchar(SOH);
- sendchar(sectnum);
- sendchar(~sectnum);
- checksum = 0;
- if (ViewMode = 'A')
- AsciiFlg = TRUE;
- for (j= bufptr; j < (bufptr + SECSIZ); j++) {
- sendchar(Bufr[j]);
- checksum = (checksum + Bufr[j]) & 0xff;
- }
- AsciiFlg = FALSE;
- sendchar(checksum);
- purgeline();
- attempts++;
- } while ((readchar(10) != ACK) &&
- (attempts != RETRYMAX));
- bufptr += SECSIZ;
- sectnum++;
- sectors--;
- } while (sectors && (attempts != RETRYMAX));
- }
- }
-
- if (attempts == RETRYMAX)
- printf("\nNo acknowledgement of sector, aborting\n");
- else {
- attempts = 0;
- do {
- sendchar(EOT);
- purgeline();
- attempts++;
- } while ((readchar(10) != ACK) && (attempts != RETRYMAX));
- if (attempts == RETRYMAX) {
- printf("\nNo acknowledgement of end of file");
- printf(", aborting\n");
- }
- else
- printf("\nTransfer complete\n");
- }
- fclose(Fd);
- return;
- }
-
- sendchar(data)
- char data;
- {
- while (!moutrdy()); /* wait until output ready */
-
- mcharout(data); /* send it */
-
- if (ShowTrans) { /* show it, if needed */
- if (AsciiFlg)
- if (((data >= ' ') && (data <= DATAMASK))
- || data == LF || data == CR || data == TAB)
- putchar(data);
- else
- printf("[%0x]", data);
- else
- printf("[%0x]", data);
- }
- return;
- }
-
- /* Hardware dependent code */
-
- #define BAUDRATE 0
- #define DATAPORT 4
- #define STATUSPORT 6
- #define DAV 1
- #define TBE 4
-
- initializemodem()
- {
- purgeline(); /* minimal code */
- }
-
- purgeline()
- {
- while (minprdy()) /* while there are characters ... */
- mcharinp(); /* gobble them */
- }
-
- mcharinp()
- {
- char c;
-
- while (!minprdy()); /* do nothing until ready */
- c = rx(); /* get data */
- return c;
- }
-
- mcharout(c)
- char c;
- {
- while (!moutrdy()); /* do nothing until ready */
- tx(c); /* put data */
- }
-
- int rx()
- {
- #asm
- IN DATAPORT ; get data from port
- MVI H,0
- MOV L,A
- #endasm
- }
-
- minprdy()
- { /* returns 0 or 1 if (un)ready */
- #asm
- IN STATUSPORT
- ANI DAV
- MVI H,0
- MOV L,A
- RZ
- MVI L,1
- #endasm
- }
-
- moutrdy()
- { /* returns 0 of 1 if (un)ready */
- #asm
- IN STATUSPORT
- ANI TBE
- MVI H,0
- MOV L,A
- RZ
- MVI L,1
- #endasm
- }
-
- int tx(c)
- char c;
- {
- #asm
- POP H
- POP D
- PUSH D
- PUSH H
- MOV A,E
- OUT DATAPORT
- #endasm
- }
-
- int baud(c)
- char c;
- {
- #asm
- POP H
- POP D
- PUSH D
- PUSH H
- MOV A,E
- OUT BAUDRATE
- #endasm
- }
- ctsready()
- {
- return TRUE;
- }
-
- hangup()
- {
- return TRUE; /* nothing to do */
- }
-
- #include "stdlib.c"
- }
- ctsready()
- {
- return TRUE;
- }
-
- hangup()
- {
- return TRUE; /* noth