diff options
-rw-r--r-- | taptoser.c | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/taptoser.c b/taptoser.c new file mode 100644 index 0000000..834c2a7 --- /dev/null +++ b/taptoser.c @@ -0,0 +1,304 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <getopt.h> +#include <termios.h> +#include <error.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> + +#define false 0 +#define FALSE 0 +#define true 1 +#define TRUE 1 + + +// SERIAL +char MODEMDEVICE[64]; +FILE *outfile = NULL; +int is_outfile = 0; +int baud_rate = 0; +#define FILENAME_LENGTH 2048 +char output_dump_file[FILENAME_LENGTH]; +char tap_file[FILENAME_LENGTH]; +static int inp_indx = 0; +int serial_fd; +size_t out_indx; + +void usage(void) { + printf ("Tap file serial port uploader/downloader. (c)2012 Pavel Vymetálek <pvymetalek@seznam.cz>\n"); + printf ("Usage:\ntaptoser [-v] [-h] [-o] [-b|--baud baud_rate] /dev/serial tap_file\n"); + printf ("\t-v, --version\tShow version info (program and protocol)\n"); + printf ("\t-h, --help\tShow this text\n"); + printf ("\t-b, --baud\tSet the communication speed. 9600Bd or 19200Bd are supported by ZX Spectrum\n"); + printf ("\t-o, --outfile\tOutput to file, instead of stdout. Without coloring ESC sequences\n"); +} + +void Set_DTR(unsigned short level) { + int status; + ioctl(serial_fd, TIOCMGET, &status); + if (level) { + status |= TIOCM_DTR; + } + else { + status &= ~TIOCM_DTR; + } + ioctl(serial_fd, TIOCMSET, &status); +} + +void TestCts(void) { + int status; + do { + ioctl(serial_fd, TIOCMGET, &status); + usleep (100); + if (status & 0x20) break; +// printf ("status: %X\n",status); + } while (1); +} + + +void TestArgs (int argc, char *argv[]) +{ + int c; + while (1) { + int option_index = 0; + static struct option long_options[] = { + {"outfile", required_argument, NULL, 'o'}, + {"baud", required_argument, NULL, 'b'}, + {"version", no_argument, NULL, 'v'}, + {"help", no_argument, NULL, 'h'}, + {0, 0, 0, 0} + }; + c = getopt_long (argc, argv, "o:b:vh", long_options, &option_index); + if (c == -1) + // konec parametru + break; + + switch (c) { + case 'h': + usage(); + exit(1); + break; + case 'b': + baud_rate = atoi(optarg); + break; + case 'o': + strncpy (&output_dump_file[0], optarg, FILENAME_LENGTH); + is_outfile = 1; + break; + case 'v': + printf ("Version 0.0.1\n"); + exit(1); + break; + default: + break; + } + } + if (baud_rate != 9600 && baud_rate != 19200) baud_rate = 19200; +/* Done with options. OPTIND points to first nonoption argument. */ + if (optind < argc) { + while (optind < argc){ + strncpy (&MODEMDEVICE[0], argv[optind++], 63); + strncpy (&tap_file[0], argv[optind++], 63); + } + } +} + + + +// TAP + + + +unsigned int h_len; + +unsigned int getword(unsigned char* data) +{ + return *data + 256 * (*(data + 1)); +} + +void tooshort(FILE *fd) +{ + printf("Input file too short.\n\n"); + fclose(fd); + exit(2); +} + +void decode(unsigned char *header) +{ + char name[11]; + unsigned int n; + + strncpy(name, (char*)(header+2), 10); + name[10] = '\0'; + printf("Filename: %s\n", name); + printf("Flag: %u\n", (unsigned int)*header); + n = getword(header+14); + h_len = getword(header+12); + switch(*(header+1)) + { + case '\0': + printf("Type: 0 => program\nProgram length: %u bytes\n", h_len); + if (n < 32768) + printf("Runs from line %u\n", n); + printf("Length without variables: %u bytes\n", + getword(header+16)); + break; + case '\1': + printf("Type: 1 => number array\nLength: %u bytes\n", h_len); + break; + case '\2': + printf("Type: 2 => character array\nLength: %u bytes\n", h_len); + break; + case '\3': + if (n == 16384 && h_len == 6912) + printf("Type: 3 => screen image\n"); + else + printf("Type: 3 => bytes\n" + "Start address: %u bytes\n" + "Length: %u\n3rd param: %u\n", + n, h_len, getword(header+16)); + break; + } + printf("\n"); +} + +int main(int argc, char** argv, char** env) +{ + FILE *fd; + unsigned int err, no, l; + long pos = 0; + struct stat st; + unsigned char header[19]; + + struct termios oldtio, newtio; + int z; + inp_indx = 0; + if (argc < 3) { + printf("You must specify the Serial device and file\n"); + usage(); + exit(1); + } + TestArgs (argc, argv); + printf ("Serial device: %s, communication speed is: %d Bd\n", MODEMDEVICE, baud_rate); + if (is_outfile) { + outfile = fopen (output_dump_file, "a"); + printf("Output file is: %s\n", output_dump_file); + } else { + outfile = stdout; + } + /* open the device to be non-blocking (read will return immediatly) */ + serial_fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (serial_fd < 0) { + perror(MODEMDEVICE); + return(-1); + } + tcgetattr(serial_fd, &oldtio); /* save current port settings */ + switch (baud_rate){ + default: + case 19200: + newtio.c_cflag = B19200 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS; + break; + case 9600: + newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS; + break; + } + newtio.c_iflag &= ~(IXON | IXOFF | IXANY); // zrusit XON XOFF + newtio.c_iflag = IGNPAR | IXOFF; + newtio.c_oflag = 0; + newtio.c_oflag &= ~OPOST; + newtio.c_lflag = NOFLSH; + newtio.c_cc[VMIN] = 0; + newtio.c_cc[VTIME] = 10; + tcflush(serial_fd, TCIOFLUSH); + tcsetattr(serial_fd, TCSANOW, &newtio); + Set_DTR(true); + + + no = stat(tap_file, &st); + if (no != 0) + { + err = errno; + error(1, err, "can't stat input file"); + } + + fd = fopen(tap_file, "r"); + if (fd == NULL) + { + err = errno; + error(1, err, "can't open input file"); + } + + while (pos < st.st_size) + { + pos += no = fread(header, 1, 2, fd); + if (no != 2) + tooshort(fd); + for (out_indx = 0; out_indx < 2; out_indx++) { + TestCts(); + write (serial_fd, &header[out_indx], 1); + usleep (200); + } + + no = getword(header); + if (no == 19) /* HEADER */ + { + pos += no = fread(header, 1, 19, fd); + if (no != 19) + tooshort(fd); + printf ("NO header: %d\n", no); + decode(header); + for (out_indx = 0; out_indx < 19; out_indx++) { + TestCts(); + write (serial_fd, &header[out_indx], 1); + usleep (3000); + } + usleep (10000); + + } else { + if (h_len != no - 2) /* zobrazuj iba bloky bez hl. */ + { + l = no; + printf ("NO datablock without header: %d\n", no); + printf("Type: datablock\nLength: %u\n", l - 2); + pos += no = fread(header, 1, 1, fd); + TestCts(); + write (serial_fd, header, 1); + usleep (1000); + if (no != 1) + tooshort(fd); + printf("Flag: %u\n\n", (int)*header); + l--; + } + else + { + l = no; + } + + pos += l; + + + +// no = fseek(fd, pos, SEEK_SET); +// if (no != 0) +// { +// err = errno; +// error(1, err, "can't seek in input file"); +// } + printf ("NO datablock: %d\n\n", l); + for (out_indx = 0; out_indx < l; out_indx++) { + fread(header, 1, 1, fd); + TestCts(); + write (serial_fd, header, 1); +// printf ("len: %5d\r", out_indx); + usleep (621); + } + printf ("\n"); + } + } + + fclose(fd); + return 0; +} |