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:
#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 */
#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. */
/* */
/****************************************************************************/
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 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");
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;