summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--taptoser.c304
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;
+}