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