diff options
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | sercp.c | 379 |
2 files changed, 64 insertions, 322 deletions
@@ -1,7 +1,10 @@ PROJECT=sercp -all: +all: $(PROJECT) + +sercp: $(PROJECT).c gcc $(PROJECT).c -o $(PROJECT) -Wall -pedantic -MP -MD -std=gnu11 -Werror=format-security -O2 -debug: + +debug: $(PROJECT).c gcc $(PROJECT).c -o $(PROJECT) -Wall -pedantic -MP -MD -std=gnu11 -Werror=format-security -g -O0 clean: @@ -4,6 +4,7 @@ #include <string.h> #include <errno.h> #include <stdint.h> +#include <libgen.h> #include <getopt.h> #include <termios.h> #include <error.h> @@ -18,7 +19,7 @@ #define true 1 #define TRUE 1 - +const char* _version = "v0.2"; // SERIAL char MODEMDEVICE[64]; FILE *tapout_fd = NULL; @@ -26,10 +27,9 @@ int is_outfile = 0; int baud_rate = 0; int wait_us = 200; int wait_ms = 800; -#define FILENAME_LENGTH 400 -char output_dump_file[FILENAME_LENGTH]; -char tap_file[FILENAME_LENGTH]; -unsigned char in_buff[65538]; +char *path; +char tap_file[FILENAME_MAX]; +unsigned char buff[32768]; unsigned char *p_buff; unsigned int is_continue = 1; unsigned int is_binary = 0; @@ -64,69 +64,44 @@ typedef struct { FILEINFO fileinfo; - void usage(void) { - printf ("sercp v0.2 (c)2018-2019 Pavel Vymetálek <pavel@vym.cz>\n"); + printf ("sercp %s (c)2018-2019 Pavel Vymetálek <pavel@vym.cz>\n", _version); printf ("serial copy for transfering file to/from ZX Spectrum 128 AY's RS232\n"); printf ("Uses 1109bytes of fileinfo - blocks sums, filename, etc.\n"); - printf ("Usage:\nsercp -d /dev/serial [-v] [-h] [-b baud_rate] [-w time] [-r] <filename>\n"); + printf ("Usage:\nsercp [-v] [-h] -d /dev/serial [-b baud_rate] [-w time] [-r] <filename>\n"); printf ("\t-v, --version\tShow version info\n"); printf ("\t-h, --help\tShow this text\n"); printf ("\t-d, --device\tCommunication device\n"); printf ("\t-b, --baud\tSet the communication speed. Default 38400Bd\n"); printf ("\t-w, --wait\tWaiting in milliseconds between transmitted blocks. Default is -w 800 milliseconds\n"); - printf ("\t-r, --read\tRead file from other computer (ZX Spectrum)\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); + printf ("\t-r, --read\tRead file from serial port\n"); } -void TestCts(void) { - int status; - do { - ioctl(serial_fd, TIOCMGET, &status); - if (status & 0x20) break; - usleep (100); - if (is_continue == 0) return; - // printf ("status: %X\n",status); - } while (1); -} - - +// fileinfo 1109bytes +/************************************************************************/ 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'}, {"wait", required_argument, NULL, 'w'}, - {"scp", no_argument, NULL, 's'}, {"read", no_argument, NULL, 'r'}, - {"binary", no_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:w:srBvh", long_options, &option_index); + c = getopt_long (argc, argv, "d:b:w:rvh", long_options, &option_index); if (c == -1) { // konec parametru break; } switch (c) { - case 'h': - usage(); - exit(1); + case 'd': + strncpy(MODEMDEVICE, optarg, strlen(optarg)); + // printf ("Serial port: %s\n", MODEMDEVICE); break; case 'b': baud_rate = atoi(optarg); @@ -135,28 +110,15 @@ void TestArgs (int argc, char *argv[]) wait_us = atoi(optarg); wait_ms = atoi(optarg); break; - case 's': - printf ("Serial CP mode is activated\n"); - scp = 1; - break; case 'r': - printf ("scp read...\n"); is_scp_read = 1; 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 'B': - printf ("Running in binary output mode\n"); - is_binary = 1; - break; case 'v': - printf ("Version 0.9.1 2015-07-22\n"); + printf ("%s\n", _version); + exit(1); + break; + case 'h': + usage(); exit(1); break; default: @@ -171,61 +133,14 @@ void TestArgs (int argc, char *argv[]) } -// from tapheader utility -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 header1 -void decode(unsigned char *header) { - char name[11]; - unsigned int n; - printf("\n"); - strncpy(name, (char*)(header+2), 10); - name[10] = '\0'; - printf("Filename: %12s \n", name); - printf("Flag: %4u ", (unsigned int)*header); - n = getword(header+14); - h_len = getword(header+12); - - switch(*(header+1)) { - case '\0': - printf("Type: 0 => program\nProgram length: %6u bytes ", h_len); - if (n < 32768) printf("Runs from line %5u\t", n); - printf("Length without variables: %5u bytes ", getword(header+16)); - break; - case '\1': - printf("Type: 1 => number array\tLength: %6u bytes", h_len); - break; - case '\2': - printf("Type: 2 => character array\tLength: %6u bytes", h_len); - break; - case '\3': - if (n == 16384 && h_len == 6912) - printf("Type: 3 => screen image\n"); - else - printf("Type: 3 => bytes " - "Start address: %5u\t" - "Length: %6u bytes\t3rd param: %4u", - n, h_len, getword(header+16)); - break; - } - printf("\n"); -} +/************************************************************************/ void signal_handler_sigterm (int status) { // CTRL+C pressed is_continue = 0; // do not continue } +/************************************************************************/ int GetTerminalWidth(void) { struct winsize termsize; ioctl (STDOUT_FILENO, TIOCGWINSZ, &termsize); @@ -236,6 +151,7 @@ int GetTerminalWidth(void) { #define PROGRESS_COMPLETTE 1 #define PROGRESS_ERROR_CSUM 2 +/************************************************************************/ void DoProgress(size_t pos, size_t max, unsigned char csum_ok) { width = GetTerminalWidth(); float percent, p, m; @@ -264,183 +180,7 @@ void DoProgress(size_t pos, size_t max, unsigned char csum_ok) { fflush (stdout); } -#define HEADER_RAW_LEN 21 - -void RecvTap() { - unsigned int err; - size_t len; - int result; - size_t block_pos = 0, last_block_pos = 0; - size_t block_len = 10000; - size_t tap_pos = 0; - unsigned char xor_csum, xor_csum_ok; - unsigned char *p_write; - unsigned char block_type; // typ bloku 255 data 0 - hlavicka - unsigned char recv_status = 0; // 0 - zacatek, 1 - hlavicka nactena, 2 - blok se nacita, 3- header less - tapout_fd = fopen (output_dump_file, "a"); - if (tapout_fd == NULL) { - err = errno; - error (1, err, "can't open output file"); - } - printf("Output file is: %s\n", output_dump_file); - p_buff = in_buff; - p_write = in_buff; - while (is_continue) { - result = poll (spolfd_serial, 1, 200); // 200ms timeout - if (result == 0) { - // nic neprislo - continue; - } - if (spolfd_serial[0].revents & POLLIN) { - len = read (serial_fd, p_buff, 256); - block_pos += len; - p_buff += len; - if (is_binary == 0) { - // ulozeni dat ze seriaku jako tap file - while (len) { - fputc(*p_write, tapout_fd); - p_write++; - len--; - } - } - if (block_pos != last_block_pos && recv_status >= 2) { - last_block_pos = block_pos; - DoProgress(block_pos, block_len+2, PROGRESS_PERCENT); - } - if (block_pos >= HEADER_RAW_LEN && recv_status == 0) { - recv_status = 1; // hlavicka nactena - block_len = getword(in_buff); - block_type = *(in_buff + 2); - if (block_type == 0) { - // Hlavicka komplet - decode (in_buff + 2); - block_len = 0; - block_pos = 0; - xor_csum = 0; - recv_status = 0; - p_buff = in_buff; - p_write = in_buff; - } else if (block_type == 255) { - // data block - printf ("Data block len: %6zu\n", block_len-2); - recv_status = 3; - } - continue; - } - if (block_pos > HEADER_RAW_LEN + 3 && recv_status == 1) { - // nactena delka dalsiho bloku - recv_status = 2; - block_len = getword(in_buff + HEADER_RAW_LEN); - block_type = *(in_buff + HEADER_RAW_LEN + 2); - printf ("Block len: %zu Block type: %d\n", block_len, block_type); - continue; - } - if (block_len + 2 == block_pos && recv_status > 2) { - // Blok komplet nacten cekej novy - block_len = getword(in_buff); - block_type = *(in_buff + 2); - for (tap_pos = 0; tap_pos < block_len -1; tap_pos++) { - xor_csum ^= *(in_buff + 2 + tap_pos); - } - xor_csum_ok = *(in_buff + 2 + block_len - 1); - if (xor_csum == xor_csum_ok) { - DoProgress(block_pos, block_len+2, PROGRESS_COMPLETTE); // vypis jeste OK - if (is_binary == 1) { - // binarni vystup do souboru - for (tap_pos = 0; tap_pos < block_len - 2; tap_pos++){ - fputc(*(in_buff + 3 + tap_pos), tapout_fd); // uloz do souboru - } - DoProgress(tap_pos, block_len - 2, PROGRESS_COMPLETTE); - } -// printf ("Checksum OK\n"); - } else { - DoProgress(block_pos, block_len+2, PROGRESS_ERROR_CSUM); // vypis error CSUM - } - block_len = 0; - block_pos = 0; - xor_csum = 0; - recv_status = 0; - p_buff = in_buff; - p_write = in_buff; - continue; - } - } - } - fclose (tapout_fd); - printf ("\n\nulozeno...\n"); -} - -void SendByte(unsigned char *p_dato) { - TestCts(); - write (serial_fd, p_dato, 1); -// tcdrain(serial_fd); // better solution, but usleep at the next line is - usleep (wait_us); // faster solution, TODO change sleep time according to serial communication speed 200us is for 57600Bd -} - -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) { - if (is_continue == 0) break; - pos += no = fread(header, 1, 2, tap_fd); - if (no != 2) - tooshort(tap_fd); - for (out_indx = 0; out_indx < 2; out_indx++) { - 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 ("Header len: %d\n", no); - decode(header); - for (out_indx = 0; out_indx < 19; out_indx++) { - SendByte(&header[out_indx]); - } - } 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); - DoProgress(1, no, PROGRESS_PERCENT); - if (no != 1) tooshort(tap_fd); - printf("Flag: %u\n\n", (int)*header); - len--; - } else { - len = no; - } - pos += len; - for (out_indx = 0; out_indx < len; out_indx++) { - fread(header, 1, 1, tap_fd); - SendByte(header); - DoProgress(out_indx+1, len, PROGRESS_PERCENT); - if (is_continue == 0) break; - } - printf ("\n"); - usleep (800000); - } - } - fclose(tap_fd); -} - +/************************************************************************/ int CheckFileInfo(FILEINFO* p_fi) { unsigned char *p_fiinfo = (unsigned char*)p_fi; @@ -460,6 +200,7 @@ int CheckFileInfo(FILEINFO* p_fi) { return -1; } +/************************************************************************/ void CountFileInfoChecksum(FILEINFO* p_fi) { unsigned char *p_fiinfo = (unsigned char*)p_fi; uint16_t fi_len; @@ -476,6 +217,7 @@ void CountFileInfoChecksum(FILEINFO* p_fi) { p_fi->h_sum = fi_sum; } +/************************************************************************/ int CheckSumBlock(FILEINFO* p_fi, uint8_t block_indx, uint8_t *p_buffer) { uint16_t block_len; uint8_t b_xor = 0; @@ -496,6 +238,7 @@ int CheckSumBlock(FILEINFO* p_fi, uint8_t block_indx, uint8_t *p_buffer) { return -1; // vrat se s chybou bloku } +/************************************************************************/ void CountSumBlock(FILEINFO* p_fi, uint8_t block_indx, uint8_t *p_buffer, uint16_t block_len) { uint8_t block_xor = 0; uint8_t block_sum = 0; @@ -510,8 +253,7 @@ void CountSumBlock(FILEINFO* p_fi, uint8_t block_indx, uint8_t *p_buffer, uint16 } -unsigned char buff[32768]; - +/************************************************************************/ uint32_t GetOverallLen(FILEINFO *p_fi) { uint32_t overall_len = 0; uint8_t block_num = p_fi->fi_numblocks; @@ -521,6 +263,7 @@ uint32_t GetOverallLen(FILEINFO *p_fi) { return overall_len; } +/************************************************************************/ void RecvSCP(void) { int recv_phase = 0; // 0 - fileinfo, 1 - blok 16kiB, 2 - posledni blok uint8_t block_index = 0; @@ -570,8 +313,6 @@ void RecvSCP(void) { err = errno; error (1, err, "can't open output file"); } -// expected_xor = p_fileinfo->fi_blocks[block_index].block_xor; -// expected_sum = p_fileinfo->fi_blocks[block_index].block_sum; } else { printf("Fileinfo neni v cajku. Koncim...\n"); break; @@ -622,8 +363,10 @@ void RecvSCP(void) { printf ("\n\nulozeno...\n"); } +/************************************************************************/ void SendSCP(void) { FILE *tap_fd; + char *bname, *basec; // pinter na kopii nazvu souboru - basename unsigned int err, no, len; struct stat st; FILEINFO *p_fileinfo = &fileinfo; @@ -647,10 +390,17 @@ void SendSCP(void) { err = errno; error(1, err, "can't open input file"); } - printf ("Soubor %s delky: %ld\n", tap_file, st.st_size); + if (st.st_size == 0) { + printf ("Zero length of file. End\n"); + return; + } + printf ("File %s, length: %ld\n", tap_file, st.st_size); memset (p_fileinfo, 0, sizeof(fileinfo)); // smazat fileinfo - memcpy(p_fileinfo->fi_name, tap_file, strlen(tap_file)); + basec = strdup (tap_file); + bname = basename (basec); + + memcpy(p_fileinfo->fi_name, bname, strlen(bname)); file_len = (uint32_t) st.st_size; while (file_len) { len = fread(buff, 1, 16384, tap_fd); // precti 16kiB dat @@ -664,7 +414,7 @@ void SendSCP(void) { CountFileInfoChecksum(p_fileinfo); odeslano = write (serial_fd, (void*)p_fileinfo, sizeof(fileinfo)); tcdrain(serial_fd); - printf("Fileinfo sent...\n"); + printf("Fileinfo sent with filename: %s\n", bname); // TODO Cekat pauzu mezi bloky usleep (wait_ms * 1000); @@ -694,6 +444,8 @@ void SendSCP(void) { fclose(tap_fd); } +/************************************************************************/ +/************************************************************************/ int main(int argc, char** argv, char** env) { // osetreni breaku ^C @@ -705,7 +457,7 @@ int main(int argc, char** argv, char** env) // nastaveni serioveho portu struct termios oldtio, newtio; inp_indx = 0; - if (argc < 3) { + if (argc < 2) { printf("You must specify the Serial device and file\n"); usage(); exit(1); @@ -719,42 +471,38 @@ int main(int argc, char** argv, char** env) } tcgetattr(serial_fd, &oldtio); /* save current port settings */ switch (baud_rate){ - default: - baud_rate = 57600; // default speed - newtio.c_cflag = B57600 | CS8 | CLOCAL | CREAD | CSTOPB;// | CRTSCTS; - break; case 115200: - newtio.c_cflag = B115200 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS; + newtio.c_cflag = B115200 | CS8 | CLOCAL | CREAD | CRTSCTS; break; case 57600: - newtio.c_cflag = B57600 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS; + newtio.c_cflag = B57600 | CS8 | CLOCAL | CREAD | CRTSCTS; break; + default: + baud_rate = 38400; case 38400: newtio.c_cflag = B38400 | CS8 | CLOCAL | CREAD | CRTSCTS; // dva stopbity jsou nastaveny vsude, ale tady ne break; case 19200: - newtio.c_cflag = B19200 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS; + newtio.c_cflag = B19200 | CS8 | CLOCAL | CREAD | CRTSCTS; break; case 9600: - newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS; + newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD | CRTSCTS; break; case 4800: - newtio.c_cflag = B4800 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS; + newtio.c_cflag = B4800 | CS8 | CLOCAL | CREAD | CRTSCTS; break; case 2400: - newtio.c_cflag = B2400 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS; + newtio.c_cflag = B2400 | CS8 | CLOCAL | CREAD | CRTSCTS; break; case 1200: - newtio.c_cflag = B1200 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS; + newtio.c_cflag = B1200 | CS8 | CLOCAL | CREAD | CRTSCTS; break; } - newtio.c_cflag |= CRTSCTS; + newtio.c_cflag |= CRTSCTS; // CSTOPB - dva stop bity NEE printf ("Serial device: %s, communication speed is: %d Bd\n", MODEMDEVICE, baud_rate); -// newtio.c_iflag &= ~(IXON | IXOFF | IXANY); // vypne XON/XOFF - newtio.c_iflag = 0; //IGNPAR | IXOFF; + newtio.c_iflag = 0; newtio.c_oflag = 0; -// newtio.c_oflag &= ~OPOST; - newtio.c_lflag = 0; //NOFLSH; + newtio.c_lflag = 0; newtio.c_cc[VMIN] = 0; newtio.c_cc[VTIME] = 10; tcsetattr(serial_fd, TCSANOW, &newtio); @@ -762,20 +510,11 @@ int main(int argc, char** argv, char** env) spolfd_serial[0].fd = serial_fd; // nastaveni hlidaneho descriptoru spolfd_serial[0].events = POLLIN; // hlidaji se data na vstupu - if (scp) { - // serial copy activated - if (is_scp_read) { - RecvSCP(); - } else { - SendSCP(); - } + // serial copy activated + if (is_scp_read) { + RecvSCP(); } else { - Set_DTR(true); // PC can read data from speccy everytime - if (is_outfile) { - RecvTap(); // cteni tap souboru ze seriaku a zapis na disk pocitace - } else { - SendTap(); // poslat na seriak tap soubor do spectra - } + SendSCP(); } close (serial_fd); return 0; |