#include #include #include #include #include #include #include #include #include #include #include #include #define false 0 #define FALSE 0 #define true 1 #define TRUE 1 // SERIAL char MODEMDEVICE[64]; FILE *tapout_fd = NULL; int is_outfile = 0; int baud_rate = 0; #define FILENAME_LENGTH 400 char output_dump_file[FILENAME_LENGTH]; char tap_file[FILENAME_LENGTH]; unsigned char in_buff[16386]; unsigned char *p_buff; unsigned int is_reading = 1; static int inp_indx = 0; int serial_fd; size_t out_indx; struct sigaction saterm; /* definition of signal action */ // variables for progress bar unsigned int pos_progress; float width, progress_pos, progress_part; long pos = 0; void usage(void) { printf ("Tap file serial port uploader/downloader. (c)2012 Pavel Vymetálek \n"); printf ("Usage:\ntaptoser [-v] [-h] [-o filename.tap] [-b|--baud baud_rate] -d /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-d, --device\tCommunication device\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); if (status & 0x20) break; usleep (100); // 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'}, {"device", required_argument, NULL, 'd'}, {"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:d: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 'd': strncpy(MODEMDEVICE, optarg, strlen(optarg)); // printf ("Serial port: %s\n", MODEMDEVICE); break; case 'o': strncpy (output_dump_file, optarg, strlen(optarg)); 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 (&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); } // decode header 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"); } void signal_handler_sigterm (int status) { is_reading = 0; // if (is_outfile) { // fclose (tapout_fd); // } // printf ("\n\nbye...\n"); // exit (0); } int GetTerminalWidth(void) { struct winsize termsize; ioctl (STDOUT_FILENO, TIOCGWINSZ, &termsize); return (termsize.ws_col); } void DoProgress(size_t pos, size_t max) { width = GetTerminalWidth(); float percent, p, m; int imax = width - 40; int ipercent; int px; p = pos; m = max; percent = 100 / m * p; ipercent = percent / 100 * imax; // printf ("\npercent: %f, ipercent: %d\n", percent, ipercent); printf ("Received bytes: %6d/%6d [", (int) pos, (int)max); for (px = 0; px < imax; px++) { if (px < ipercent) printf ("="); else printf (" "); } printf ("] %3d %%\r", (int)percent); fflush (stdout); } void RecvTap() { unsigned int err, len; size_t total_len = 0, last_len = 0; tapout_fd = fopen (output_dump_file, "a"); if (tapout_fd == NULL) { err = errno; error (1, err, "can't open output file"); } // if (is_outfile) { printf("Output file is: %s\n", output_dump_file); // } else { // outfile = stdout; // } while (is_reading) { usleep (100000); len = read (serial_fd, in_buff, 256); p_buff = in_buff; total_len += len; p_buff += len; while (len) { fputc(*p_buff, tapout_fd); p_buff++; len--; if (total_len != last_len) { last_len = total_len; DoProgress(total_len, 16384); } } } fclose (tapout_fd); printf ("\n\nulozeno...\n"); } void SendByte(unsigned char *p_dato) { unsigned char dat; // TestCts(); // write byte to serial port dat = *p_dato; printf ("%2.2X ", dat); // write (serial_fd, p_dato, 1); // // tcdrain(serial_fd); usleep (200); } void SendTap() { FILE *tap_fd; unsigned int err, no, len; struct stat st; unsigned char header[19]; no = stat(tap_file, &st); if (no != 0) { err = errno; error(1, err, "can't stat input file"); } tap_fd = fopen(tap_file, "r"); if (tap_fd == NULL) { err = errno; error(1, err, "can't open input file"); } while (pos < st.st_size) { pos += no = fread(header, 1, 2, tap_fd); if (no != 2) tooshort(tap_fd); for (out_indx = 0; out_indx < 2; out_indx++) { progress_pos = 0; printf("["); SendByte(&header[out_indx]); } no = getword(header); if (no == 19) /* HEADER */ { pos += no = fread(header, 1, 19, tap_fd); if (no != 19) tooshort(tap_fd); printf ("NO header: %d\n", no); decode(header); for (out_indx = 0; out_indx < 19; out_indx++) { SendByte(&header[out_indx]); usleep (3000); } usleep (10000); } else { if (h_len != no - 2) /* zobrazuj iba bloky bez hl. */ { len = no; printf ("NO datablock without header: %d\n", no); printf("Type: datablock\nLength: %u\n", len - 2); pos += no = fread(header, 1, 1, tap_fd); SendByte(header); progress_part = h_len / width; // for (progress_pos = 0; progress_pos < out_indx*progress_part; progress_pos++) { // printf ("#\r"); // } // usleep (1000); if (no != 1) tooshort(tap_fd); printf("Flag: %u\n\n", (int)*header); len--; } else { len = no; } pos += len; // 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", len); for (out_indx = 0; out_indx < len; out_indx++) { fread(header, 1, 1, tap_fd); SendByte(header); // printf ("len: %5d\r", out_indx); // usleep (621); } printf ("\n"); } } fclose(tap_fd); } int main(int argc, char** argv, char** env) { // osetreni breaku ^C saterm.sa_handler = signal_handler_sigterm; saterm.sa_flags = 0; sigaction (SIGINT, &saterm, NULL); width = GetTerminalWidth(); struct termios oldtio, newtio; inp_indx = 0; if (argc < 3) { printf("You must specify the Serial device and file\n"); usage(); exit(1); } printf ("tu som... \n"); TestArgs (argc, argv); printf ("Serial device: %s, communication speed is: %d Bd\n", MODEMDEVICE, baud_rate); /* 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 57600: newtio.c_cflag = B57600 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS; break; 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); if (is_outfile) { // cteni souboru ze seriaku RecvTap(); } else { // poslat na seriak tap soubor SendTap(); } close (serial_fd); return 0; }