DLOAD.C

/*  DLOAD                  16 Jan 88           Burt Mitchell               */
/*                                                                         */
/*  Host software for an PC compatible to send files to a                  */
/*  Color Computer using the DLOAD command.                                */
/*  The Coco must be running Extended Color Basic v1.1 or OLDER            */

/*  This program uses 1200 baud as it is the default for the Coco.  It is  */
/*  configured to use the PC's com1: port. To change this you will have to */
/*  edit the procedures transmit_char() and receive_char().                */

/*  This program has not been tested in the DLOADM mode as I have no way   */
/*  of getting a Coco machine language routine into the PC in the first    */
/*  place.                                                                 */

/*  To operate DLOAD:                                                      */
/*  on the PC enter     DLOAD filename.ext a                               */
/*  the PC will inform you that it is waiting.                             */
/*  on the Coco enter   DLOAD                                              */

/* Modified for use with unix by Bryan Clingman (bac@realtimeweb.com)	   */
/* 3-Jun-1997															   */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define	true	1
#define	false	0
#define	ok		1
#define	bad		0

/* literals for the DLOAD protocol */

#define	file_req	0x8A
#define	block_req	0x97
#define	NAK			0xDE
#define	ACK			0xC8
#define	EOT			0xBC
#define	ABORT		0xBC
#define	ASCII		0xFF
#define	BINARY		0x00
#define	BASIC		0x00
#define	ML			0x02
#define	block_size	127

unsigned char	chksum,
				file_type,
				asc_flag,
				proceed;
unsigned char		rx_char;
char			*tx_name;
char			*port;
FILE			*infile;
FILE			*fp;
int			tx_delay;

void transmit_char(unsigned char tx_char)
{
	fputc(tx_char, fp);
#ifdef DEBUG
	fprintf(stderr, " [%02X]", tx_char);
#endif
	usleep(tx_delay);
}

void receive_char()
{
	rx_char = fgetc(fp);
#ifdef DEBUG
	if (rx_char != 0xFF && rx_char != 0)
		fprintf(stderr, " %02X", rx_char);
#endif
	if (rx_char == ABORT)
	{
#ifdef DEBUG
		fprintf(stderr, "\n");
#endif
		fprintf(stderr, "transfer aborted by target.\n");
		exit(1);
	}
}

void initiate_transfer()
{
	chksum = (file_type ^ asc_flag);
	transmit_char(ACK);
	transmit_char(file_type);
	transmit_char(asc_flag);
	transmit_char(chksum);
}

char rcv_file_name(char *filename)
{
	int	count;
	char    sum;
	char	status;

	filename[8] = 0;
	count = 0;
	while (count <= 7)
	{
		receive_char();
		filename[count] = rx_char;
		chksum = (chksum ^ rx_char);
		++count;
	}

	receive_char();
	sum = rx_char;

#ifdef DEBUG
	fprintf(stderr, "\n");
#endif
	fprintf(stderr, "target requested \"%s\"\n", filename);

	if (sum != chksum)
	{
#ifdef DEBUG
		fprintf(stderr, "\n");
#endif
		fprintf(stderr, "filename checksum bad.\n");
		status = bad;
		filename[0] = '\0';
	}
	else
		status = ok;
	return status;
}

void send_file()
{
	int				count,
					j;
	char			tx_flag,
					xfer_done,
					first_time,
					send_new_block;
	unsigned char	file_char[130],
					xfer_length,
					sum,
					block_num,
					old_block_num;
	long int		total_xfer;

	/**/

	first_time = true;
	total_xfer = 0;
	xfer_length = 0;
	xfer_done = false;
	tx_flag = true;

	while (tx_flag == true)
	{
		send_new_block = true;

		while (rx_char != block_req)
			receive_char();

		transmit_char(block_req);

		chksum = 0;

		/* get the MSByte of the block number */

		receive_char();
		chksum = (chksum ^ rx_char);
		block_num = (rx_char << 7);

		/* get the LSByte of the block number */

		receive_char();
		chksum = (chksum ^ rx_char);
		block_num = (rx_char | block_num);

#ifdef DEBUG
		fprintf(stderr, "\nRequested block # %i\n", block_num);
#endif
		/* should we retransmit the previous block? */

		if (first_time == false)
			if (block_num == old_block_num)
				send_new_block = false;


		/* Get the checksum for the block number being requested. */
		/* Does it match our calculation?                         */
		
		receive_char();
		sum = rx_char;

		if (sum == chksum)
		{
			transmit_char(ACK);
			first_time = false;
		
			if (xfer_done == true)
			{
				/* Send a block with a length of 0 and 128 bytes of */
				/* anything along with a checksum for the block.    */
				/* This tells the Coco that the file is ended.      */
		
				tx_flag = false;
				xfer_length = 0;
		
				j = 0;
				while (j <= block_size)
				{
					file_char[j] = 0;
					++j;
				}
			}
			else
			{
				/* go ahead and read in another 128 bytes.           */
				/* If there aren't 128 bytes available pad the data  */
				/* to 128 bytes. The checksum must still be correct. */

				if (send_new_block == true)
				{
					count = 0;
					while (count <= block_size)
					{
						file_char[count] = getc(infile);
						/* The Coco can't handle linefeeds */
						if (asc_flag == ASCII)
							if (file_char[count] == '\n')
								file_char[count] = '\r';
						xfer_length = (count + 1);
						++count;
						if (feof(infile))
						{
							xfer_done = true;
							while (count <= block_size)
							{
								file_char[count] = 0;
								++count;
								if (asc_flag != ASCII)
									tx_flag = false;
							}
						}
					}
				}
				else
				{
#ifdef DEBUG
					fprintf(stderr, "\n");
#endif
					fprintf(stderr, "Re-transmitting block #%d\n", block_num);
				}
			}

			/* transmit whatever is in the buffer */

			transmit_char(xfer_length);

			chksum = 0;
			chksum = (chksum ^ xfer_length);
			count = 0;
			while (count <= block_size)
			{
				transmit_char(file_char[count]);
				chksum = (chksum ^ file_char[count]);
				++count;
			}
			transmit_char(chksum); 
		
			total_xfer = (total_xfer + xfer_length);
#ifdef DEBUG
			fprintf(stderr, "\n");
#endif
			fprintf(stderr, "Total transmitted = %ld\r", total_xfer);
#ifdef DEBUG
			fprintf(stderr, "\n");
#endif
			old_block_num = block_num;
		}
		else
		{
			fprintf(stderr, "checksum mismatch\n");
			transmit_char(NAK);
		}
	}
	fprintf(stderr, "\n");
}

void xfer_abort()
{
	transmit_char(NAK);
#ifdef DEBUG
	fprintf(stderr, "\n");
#endif
	fprintf(stderr, "transfer aborted by host\n");
	exit(1);
}

void init_port()
{
	fp = fopen(port,"a+");
	if (!fp)
		fprintf(stderr, "Error opening port\n");
	setvbuf(fp, NULL, _IONBF, 0);
}

int main(int argc, char *argv[])
{
	char    filename[9];
	char    status;

	if (argc < 4)
	{
		fprintf(stderr, "usage: DLOAD [filename.ext] [A or B] [port]\n");
		exit(1);
	}

	tx_name = argv[1];

	if ((*argv[2] == 'B') || (*argv[2] == 'b'))
	{
		file_type = ML;
		asc_flag = BINARY;
		infile = fopen(tx_name,"rb");
	}
	else
		if ((*argv[2] == 'A') || (*argv[2] == 'a'))
		{
			file_type = BASIC;
			asc_flag = ASCII;
			infile = fopen(tx_name,"r");
		}
		else
		{
			fprintf(stderr, "unknown file type\n");
			exit(1);
		}

	if (infile == NULL)
	{
		fprintf(stderr, "cant open the file to be transmitted\n");
		exit(1);
	}

	if (argc > 4)
		tx_delay = atoi(argv[4]);
	else
		tx_delay = 0;

	port = argv[3];
	init_port();

	/* wait for the coco to start the transfer */

	while (rx_char != file_req)
		receive_char();

	proceed = true;

	/* proceed with the file transfer */
	while (proceed == true)
	{
		/* get the file name from the coco. We arent using it but */
		/* it's part of the protocol. */

		transmit_char(file_req);

		status = rcv_file_name(filename);
		/* if non-empty file name, switch file */
		if (status == ok && strcmp(filename, "        "))
		{
			int lastc;

			/* zero out trailing spaces */
			for (lastc = 7; lastc > 0; lastc--)
			{
				if (filename[lastc] == ' ')
					filename[lastc] = '\0';
				else
					break;
			}
			fprintf(stderr, "trimmed to \"%s\"\n", filename);
			fclose(infile);
			/* only binary supported for now */
			infile = fopen(filename,"rb");
			if (infile == NULL)
			{
				fprintf(stderr, "cannot open %s\n", filename);
				/* abort and wait for new request */
				/* FIXME Dragon does not interpret NAK here */
				transmit_char(NAK);
				while (rx_char != file_req)
					receive_char();
				infile = fopen(tx_name, "rb");
				continue;
			}
		}

		/* tell the coco about the file it will receive. */

		initiate_transfer();

		/* now send the file */

		send_file();

		if (status == ok)
		{
			proceed = false;
		}
		else
		{
			proceed = false;
			fprintf(stderr, "file not transmitted successfully\n");
		}
	}
	return 0;
}

RTS

Return to DLOAD :: Tandy Color Computer