diff options
-rw-r--r-- | taptoser.c | 207 |
1 files changed, 201 insertions, 6 deletions
@@ -3,6 +3,7 @@ #include <stdlib.h> #include <string.h> #include <errno.h> +#include <stdint.h> #include <getopt.h> #include <termios.h> #include <error.h> @@ -40,6 +41,27 @@ struct sigaction saterm; /* definition of signal action */ float width; // width of terminal long pos = 0; +int scp = 0; +int is_scp_read = 0; + +typedef struct { + uint16_t block_len; + uint8_t block_xor; + uint8_t block_sum; +} __attribute__((packed)) fi_sum; + +typedef struct { + uint16_t length; // delka dat ve fileinfo + uint8_t h_xor; // xor bajtu fileinfa od fi_numblocks + uint8_t h_sum; // sum bajtu fileinfa od fi_numblocks + uint8_t fi_numblocks; // pocet bloku + uint8_t fi_name[64]; // jmeno souboru - prozatim musi byt ve fromatu 8.3 - kvuli esxdosu + uint8_t fi_date[8]; // nepouzito + uint8_t fi_time[8]; // nepouzito + fi_sum fi_blocks[256]; // delky a soucty bloku +} __attribute__((packed)) FILEINFO; + +FILEINFO fileinfo; void usage(void) { @@ -88,12 +110,14 @@ void TestArgs (int argc, char *argv[]) {"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:Bvh", long_options, &option_index); + c = getopt_long (argc, argv, "o:d:b:w:srBvh", long_options, &option_index); if (c == -1) { // konec parametru break; @@ -109,6 +133,14 @@ void TestArgs (int argc, char *argv[]) case 'w': wait_us = 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); @@ -408,6 +440,160 @@ void SendTap() { } +int CheckFileInfo(FILEINFO* p_fi) { + unsigned char *p_fiinfo = (unsigned char*)p_fi; + uint16_t fi_len; + uint8_t fi_xor = 0; + uint8_t fi_sum = 0; + fi_len = p_fi->length; + p_fiinfo += 4; // suma se bude pocitat od offsetu 4 + for (uint16_t indx = 0; indx < (fi_len-4); indx++) { + fi_xor ^= *p_fiinfo; + fi_sum += *p_fiinfo; + p_fiinfo++; + } + if (fi_xor == p_fi->h_xor && fi_sum == p_fi->h_sum) { + return 0; + } + return -1; +} + +int CheckSumBlock(FILEINFO* p_fi, uint8_t block_indx, uint8_t *p_buffer) { + uint16_t block_len; + uint8_t b_xor = 0; + uint8_t b_sum = 0; + uint8_t block_xor; + uint8_t block_sum; + block_len = p_fi->fi_blocks[block_indx].block_len; + block_sum = p_fi->fi_blocks[block_indx].block_sum; + block_xor = p_fi->fi_blocks[block_indx].block_xor; + for (uint16_t indx = 0; indx < block_len; indx++) { + b_xor ^= *p_buffer; + b_sum += *p_buffer; + p_buffer++; + } + if (b_xor == block_xor && b_sum == block_sum) { + return 0; // vrat se, je to v poradku + } + return -1; // vrat se s chybou bloku +} + +unsigned char buff[32768]; + +uint32_t GetOverallLen(FILEINFO *p_fi) { + uint32_t overall_len = 0; + uint8_t block_num = p_fi->fi_numblocks; + for (uint8_t indx = 0; indx < block_num; indx++) { + overall_len += p_fi->fi_blocks[indx].block_len; + } + return overall_len; +} + +void RecvSCP(void) { + int recv_phase = 0; // 0 - fileinfo, 1 - blok 16kiB, 2 - posledni blok + uint8_t block_index = 0; + int result; + uint16_t len; + uint16_t length = 0; + uint16_t expected_len = 0; +// uint8_t expected_xor; +// uint8_t expected_sum; + uint32_t overall_length = 0; // celkova delka souboru + uint32_t recv_length = 0; // zatim prijatych dat ze souboru + int err; + + FILEINFO *p_fileinfo = &fileinfo; + unsigned char *p_buff = buff; + tapout_fd = NULL; + + memset (p_fileinfo, 0, sizeof(fileinfo)); + while (is_continue) { + result = poll (spolfd_serial, 1, 200); // 200ms timeout + if (result == 0) { + // nic neprislo + continue; + } + switch (recv_phase) { + case 0: + // prijem fileinfo + if (spolfd_serial[0].revents & POLLIN) { + len = read (serial_fd, p_buff, sizeof(fileinfo)); + p_buff += len; + length += len; + if (length == sizeof(fileinfo)) { + memcpy((unsigned char*) p_fileinfo, buff, sizeof(fileinfo)); + if (CheckFileInfo(p_fileinfo) == 0) { + printf("Prijato fileinfo\n"); + overall_length = GetOverallLen(p_fileinfo); + printf("Nazev souboru: \"%s\" pocet bloku:%d, delka souboru: %u\n", p_fileinfo->fi_name, p_fileinfo->fi_numblocks, overall_length); + recv_phase++; // priste se uz prijimaji bloky + block_index = 0; // zacina se prvnim blokem + p_buff = buff; // buffer na zacatek + length = 0; + expected_len = p_fileinfo->fi_blocks[block_index].block_len; + + + tapout_fd = fopen ((char*)p_fileinfo->fi_name, "w"); + if (tapout_fd == NULL) { + 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; + } + break; + } else if (length > sizeof(fileinfo)){ + len = read (serial_fd, p_buff, sizeof(fileinfo)); + printf("Nejaky bordel. Koncim...\n"); + break; + } + } + break; + case 1: + // prijem datoveho bloku - max. delka 16kiB + if (spolfd_serial[0].revents & POLLIN) { + len = read (serial_fd, p_buff, expected_len); + p_buff += len; + expected_len -= len; + length += len; + recv_length += len; + DoProgress(recv_length, overall_length, PROGRESS_PERCENT); + if (length == p_fileinfo->fi_blocks[block_index].block_len) { + // prijaty prvni block +// printf("Prijaty blok c.%d delky: %d\n", block_index, length); + if (CheckSumBlock(p_fileinfo, block_index, buff) == 0) { + // blok je v cajku - zapsat do souboru + if (tapout_fd) fwrite(buff, length, 1, tapout_fd); + } + length = 0; + p_buff = buff; + block_index++; + expected_len = p_fileinfo->fi_blocks[block_index].block_len; + } + if (expected_len == 0 || block_index == 255) { + printf ("\nKonec prenosu\n"); + recv_phase++; + is_continue = 0; + break; + } + } else if (length > 16384) { + len = read (serial_fd, p_buff, 16384); + printf("Nejaky bordel. Koncim...\n"); + break; + } + } + } + if (tapout_fd) fclose (tapout_fd); + printf ("\n\nulozeno...\n"); +} + +void SendSCP(void) { + +} + int main(int argc, char** argv, char** env) { // osetreni breaku ^C @@ -444,7 +630,7 @@ int main(int argc, char** argv, char** env) newtio.c_cflag = B57600 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS; break; case 38400: - newtio.c_cflag = B38400 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS; // dva stopbity jsou nastaveny vsude + newtio.c_cflag = B38400 | CS8 | CLOCAL | CREAD | CRTSCTS; // dva stopbity jsou nastaveny vsude break; case 19200: newtio.c_cflag = B19200 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS; @@ -475,11 +661,20 @@ 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 - Set_DTR(true); // PC can read data from speccy everytime - if (is_outfile) { - RecvTap(); // cteni tap souboru ze seriaku a zapis na disk pocitace + if (scp) { + // serial copy activated + if (is_scp_read) { + RecvSCP(); + } else { + SendSCP(); + } } else { - SendTap(); // poslat na seriak tap soubor do spectra + 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 + } } close (serial_fd); return 0; |