From 45c8724e89c7c0d84fa42d2877f5b71c0f70749e Mon Sep 17 00:00:00 2001 From: Pavel Vymetálek Date: Fri, 3 Apr 2020 10:32:08 +0200 Subject: Fixed complicated interrupting by ctrl-c - ctrl-c stops the program immediatelly - serial buffers are cleaned at startup and at finishing program - pointers renamed to p_... - comments are in english --- CHANGELOG | 1 + Makefile | 8 +-- TODO | 4 ++ sercp.c | 194 +++++++++++++++++++++++++++++--------------------------------- sercp.rc | 8 +-- 5 files changed, 104 insertions(+), 111 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fb4ed35..2c3b436 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +2020-04-03 v0.3.1 fixed complicated interrupting by ctrl-c 2019-03-26 v0.3.0 add support for time/date handling 2019-03-16 v0.2.3 fixed serial port setup to work on Mac 2019-03-09 v0.2.2 remove unnecessary waiting after last block diff --git a/Makefile b/Makefile index 4cb7232..a107f8c 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ all: $(PROJECT) windows: $(PROJECT).w32 $(PROJECT).w64 sercp: $(PROJECT).c - $(CC) $(PROJECT).c -o $(PROJECT) -Wall -pedantic -MP -MD -std=gnu11 -Werror=format-security -O2 + $(CC) $(PROJECT).c -o $(PROJECT) -Wall -pedantic -MP -MD -std=gnu11 -Werror=format-security -O2 -Wformat install: $(PROJECT) install -d $(DESTDIR)$(PREFIX)/bin/ @@ -18,17 +18,17 @@ install: $(PROJECT) sercp.w64: $(PROJECT).c rm -f $(PROJECT).res $(WINCC64_PREFIX)-windres -i $(PROJECT).rc --input-format=rc --codepage=65001 -o $(PROJECT).res -O coff - $(WINCC64_PREFIX)-gcc $(PROJECT).c $(PROJECT).res -o $(PROJECT).exe -Wall -pedantic -MP -MD -std=gnu11 -Werror=format-security -O2 + $(WINCC64_PREFIX)-gcc $(PROJECT).c $(PROJECT).res -o $(PROJECT).exe -Wall -pedantic -MP -MD -std=gnu11 -Werror=format-security -Wformat -O2 $(WINCC64_PREFIX)-strip $(PROJECT).exe sercp.w32: $(PROJECT).c rm -f $(PROJECT).res $(WINCC_PREFIX)-windres -i $(PROJECT).rc --input-format=rc --codepage=65001 -o $(PROJECT).res -O coff - $(WINCC_PREFIX)-gcc $(PROJECT).res $(PROJECT).c -o $(PROJECT)32.exe -Wall -pedantic -MP -MD -std=gnu11 -Werror=format-security -O2 + $(WINCC_PREFIX)-gcc $(PROJECT).res $(PROJECT).c -o $(PROJECT)32.exe -Wall -pedantic -MP -MD -std=gnu11 -Werror=format-security -Wformat -O2 $(WINCC_PREFIX)-strip $(PROJECT)32.exe debug: $(PROJECT).c - $(CC) $(PROJECT).c -o $(PROJECT) -Wall -pedantic -MP -MD -std=gnu11 -Werror=format-security -g -O0 + $(CC) $(PROJECT).c -o $(PROJECT) -Wall -pedantic -MP -MD -std=gnu11 -Werror=format-security -g -O0 -Wformat clean: rm -f $(PROJECT) $(PROJECT).d $(PROJECT).o $(PROJECT).res $(PROJECT)*.d $(PROJECT)*.exe diff --git a/TODO b/TODO index 074c8e8..d376bf1 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,7 @@ +2019-09-03 + - fix progressbar for files smaller than 16kB + + 2019-03-16 + add support for handling time/date of files * info at https://docs.microsoft.com/en-us/windows/desktop/api/Winbase/nf-winbase-filetimetodosdatetime diff --git a/sercp.c b/sercp.c index abfa3b1..b99dc42 100644 --- a/sercp.c +++ b/sercp.c @@ -15,8 +15,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +/* + * IFDEFS inspired here: + * https://iq.opengenus.org/detect-operating-system-in-c/ + */ -#ifdef __WIN32 +#ifdef _WIN32 #include #include #include @@ -33,9 +37,7 @@ #include #include #include - #else - #include #include #include @@ -57,13 +59,12 @@ #include #endif - #define false 0 #define FALSE 0 #define true 1 #define TRUE 1 -const char* _version = "v0.3.0"; +const char* _version = "v0.3.1"; // SERIAL FILE *tapout_fd = NULL; int is_outfile = 0; @@ -74,7 +75,6 @@ char *path; char sercp_file[FILENAME_MAX]; unsigned char buff[32768]; unsigned char *p_buff; -unsigned int is_continue = 1; unsigned int is_binary = 0; static int inp_indx = 0; @@ -84,16 +84,17 @@ float width; // width of terminal long pos = 0; int scp = 0; int is_scp_read = 0; +int is_continue = 1; char MODEMDEVICE[64] = { -#ifdef __WIN32 +#ifdef _WIN32 "\\\\.\\COM1" #else "/dev/ttyUSB0" #endif }; -#ifdef __WIN32 +#ifdef _WIN32 static HANDLE serial_fd; #else int serial_fd; @@ -123,14 +124,14 @@ typedef struct { FILEINFO fileinfo; void usage(void) { - printf ("sercp %s (c)2018-2019 Pavel Vymetalek \n", _version); + printf ("sercp %s (c)2018-2020 Pavel Vymetalek \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 ("More info at https://vym.cz/sercp/\n"); printf ("Usage:\nsercp [-v] [-h] -d /dev/serial [-b baud_rate] [-w time] [-r] \n"); printf ("\t-v, --version\tShow version info\n"); printf ("\t-h, --help\tShow this text\n"); -#ifdef __WIN32 +#ifdef _WIN32 printf ("\t-d, --device\tSerial com port\n"); #else printf ("\t-d, --device\tSerial communication device\n"); @@ -163,7 +164,7 @@ void TestArgs (int argc, char *argv[]) } switch (c) { case 'd': -#ifdef __WIN32 +#ifdef _WIN32 sprintf(MODEMDEVICE, "\\\\.\\%s", optarg); #else sprintf(MODEMDEVICE, "%s", optarg); @@ -206,7 +207,7 @@ void TestArgs (int argc, char *argv[]) // uSleep win32 implementation void uSleep(int waitTime) { - #ifdef __WIN32 + #ifdef _WIN32 __int64 time1 = 0, time2 = 0, freq = 0; QueryPerformanceCounter((LARGE_INTEGER *) &time1); @@ -228,16 +229,9 @@ void sleep_ms(int milliseconds) { #endif } - -/************************************************************************/ -void signal_handler_sigterm (int status) { - // CTRL+C pressed - is_continue = 0; // do not continue -} - /************************************************************************/ int GetTerminalWidth(void) { -#ifdef __WIN32 +#ifdef _WIN32 CONSOLE_SCREEN_BUFFER_INFO csbi; int columns; // int rows; @@ -294,7 +288,7 @@ int CheckFileInfo(FILEINFO* p_fi) { 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 + p_fiinfo += 4; // sum is counting from offset 4 for (uint16_t indx = 0; indx < (fi_len-4); indx++) { fi_xor ^= *p_fiinfo; fi_sum += *p_fiinfo; @@ -313,7 +307,7 @@ void CountFileInfoChecksum(FILEINFO* p_fi) { 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 + p_fiinfo += 4; // sum is counting from offset 4 for (uint16_t indx = 0; indx < (fi_len-4); indx++) { fi_xor ^= *p_fiinfo; fi_sum += *p_fiinfo; @@ -339,9 +333,9 @@ int CheckSumBlock(FILEINFO* p_fi, uint8_t block_indx, uint8_t *p_buffer) { p_buffer++; } if (b_xor == block_xor && b_sum == block_sum) { - return 0; // vrat se, je to v poradku + return 0; // success } - return -1; // vrat se s chybou bloku + return -1; // sum error } /************************************************************************/ @@ -371,39 +365,38 @@ uint32_t GetOverallLen(FILEINFO *p_fi) { /************************************************************************/ void sercpRecv(void) { - int recv_phase = 0; // 0 - fileinfo, 1 - blok 16kiB, 2 - posledni blok + int recv_phase = 0; // 0 - fileinfo, 1 - 16kiB block, 2 - last block uint8_t block_index = 0; uint16_t len; uint16_t length = 0; uint16_t expected_len = 0; - uint32_t overall_length = 0; // celkova delka souboru - uint32_t recv_length = 0; // zatim prijatych dat ze souboru + uint32_t overall_length = 0; // overall length of file + uint32_t recv_length = 0; // receive length counter struct utimbuf f_datetime; struct tm timdat; -#ifndef __WIN32 +#ifndef _WIN32 int result; #endif FILEINFO *p_fileinfo = &fileinfo; unsigned char *p_buff = buff; tapout_fd = NULL; -#ifdef __WIN32 +#ifdef _WIN32 unsigned long ulNumBytes; #endif memset (p_fileinfo, 0, sizeof(fileinfo)); while (is_continue) { -#ifndef __WIN32 +#ifndef _WIN32 result = poll (spolfd_serial, 1, 200); // 200ms timeout if (result == 0) { - // nic neprislo + // nothing is comming continue; } #endif switch (recv_phase) { case 0: - // prijem fileinfo -// if (spolfd_serial[0].revents & POLLIN) { -#ifdef __WIN32 + // receive fileinfo +#ifdef _WIN32 sleep_ms(10); ReadFile(serial_fd, p_buff, sizeof(fileinfo), &ulNumBytes, NULL); len = (uint16_t) ulNumBytes; @@ -418,17 +411,14 @@ void sercpRecv(void) { if (CheckFileInfo(p_fileinfo) == 0) { overall_length = GetOverallLen(p_fileinfo); printf("File: \"%s\" number of blocks:%d, length of file: %u\n", p_fileinfo->fi_name, p_fileinfo->fi_numblocks, overall_length); -// printf("Recv file date: %4d-%02d-%02d\t ", ((*p_fileinfo->fi_date & 0xFE00) >> 9)+1980, ((*p_fileinfo->fi_date & 0x1E0) >> 5),* p_fileinfo->fi_date & 0x1F); -// printf("%02d:%02d:%02d\t%4X, %4X\n", ((*p_fileinfo->fi_time ) >> 11), ((*p_fileinfo->fi_time & 0x7e0) >> 5),(*p_fileinfo->fi_time & 0x1F)*2, *p_fileinfo->fi_date, *p_fileinfo->fi_time); - - recv_phase++; // priste se uz prijimaji bloky - block_index = 0; // zacina se prvnim blokem - p_buff = buff; // buffer na zacatek + recv_phase++; // will follow receive data blocks + block_index = 0; // begins from first block + p_buff = buff; // initialize buffer pointer length = 0; expected_len = p_fileinfo->fi_blocks[block_index].block_len; tapout_fd = fopen ((char*)p_fileinfo->fi_name, "wb"); if (tapout_fd == NULL) { - #ifdef __WIN32 + #ifdef _WIN32 printf ("can't open output file"); exit (EXIT_FAILURE); @@ -442,23 +432,20 @@ void sercpRecv(void) { } break; } else if (length > sizeof(fileinfo)){ -#ifdef __WIN32 +#ifdef _WIN32 ReadFile(serial_fd, p_buff, sizeof(fileinfo), &ulNumBytes, NULL); len = (uint16_t)ulNumBytes; #else - len = read (serial_fd, p_buff, sizeof(fileinfo)); #endif printf("Received unknown data. End...\n"); exit (EXIT_FAILURE); break; } -// } break; case 1: - // prijem datoveho bloku - max. delka 16kiB -// if (spolfd_serial[0].revents & POLLIN) { -#ifdef __WIN32 + // receive of data block - max. length 16kiB +#ifdef _WIN32 ReadFile(serial_fd, p_buff, expected_len, &ulNumBytes, NULL); len = (uint16_t)ulNumBytes; sleep_ms(10); @@ -474,7 +461,7 @@ void sercpRecv(void) { if (length == p_fileinfo->fi_blocks[block_index].block_len) { // prijaty prvni block if (CheckSumBlock(p_fileinfo, block_index, buff) == 0) { - // blok je v cajku - zapsat do souboru + // block is ok - write to file if (tapout_fd) fwrite(buff, length, 1, tapout_fd); } length = 0; @@ -484,11 +471,11 @@ void sercpRecv(void) { } if (expected_len == 0 || block_index == 255) { printf ("\nTransfer successful\n"); - recv_phase++; is_continue = 0; + recv_phase++; break; } -// } + break; } } if (tapout_fd) { @@ -515,10 +502,10 @@ void sercpRecv(void) { /************************************************************************/ void sercpSend(void) { FILE *tap_fd; - char *bname, *basec; // pinter na kopii nazvu souboru - basename - char *shortfilename; + char *p_bname, *p_basec; + char *p_shortfilename; size_t fn_len; - unsigned int no, len; //err, + unsigned int no, len; struct stat st; FILEINFO *p_fileinfo = &fileinfo; unsigned char *p_buff = buff; @@ -528,7 +515,7 @@ void sercpSend(void) { uint32_t len_sent; uint16_t sent_size; uint32_t overall_sent; -#ifdef __WIN32 +#ifdef _WIN32 unsigned long ulNumBytes; #endif struct tm *timdat; @@ -548,33 +535,39 @@ void sercpSend(void) { printf ("Zero length of file. End\n"); return; } + +// FIXME do this more sophisticated and crossplatform, for example by __SIZE_WIDTH__ +#if defined (__linux__) || defined(_WIN32) + printf ("File %s, length: %ld\n", sercp_file, st.st_size); +#else printf ("File %s, length: %lld\n", sercp_file, st.st_size); +#endif + timdat = localtime(&st.st_mtime); uint16_t FatDate = ((timdat->tm_year - 80) << 9) | ((timdat->tm_mon + 1) << 5) | timdat->tm_mday; uint16_t FatTime = ((timdat->tm_hour << 11) | (timdat->tm_min << 5) | (timdat->tm_sec >> 1)); - memset (p_fileinfo, 0, sizeof(fileinfo)); // smazat fileinfo + memset (p_fileinfo, 0, sizeof(fileinfo)); // erase fileinfo - basec = strdup (sercp_file); - bname = basename (basec); - if (strlen(bname) > 12) { + p_basec = strdup(sercp_file); + p_bname = basename (p_basec); + if (strlen(p_bname) > 12) { printf ("Short filename: "); - shortfilename = strdup(bname); - fn_len = strlen(shortfilename); - memcpy(shortfilename+4, shortfilename+fn_len-8, 8); - *(shortfilename+12) = 0; - printf ("%s\n", shortfilename); - bname = shortfilename; + p_shortfilename = strdup(p_bname); + fn_len = strlen(p_shortfilename); + memcpy(p_shortfilename+4, p_shortfilename+fn_len-8, 8); + *(p_shortfilename+12) = 0; + printf ("%s\n", p_shortfilename); + p_bname = p_shortfilename; } - memcpy(p_fileinfo->fi_name, bname, strlen(bname)); + memcpy(p_fileinfo->fi_name, p_bname, strlen(p_bname)); memcpy(p_fileinfo->fi_date, &FatDate, sizeof(FatDate)); memcpy(p_fileinfo->fi_time, &FatTime, sizeof(FatTime)); -// printf("Sent file date: %4d-%02d-%02d\t%4X, %4X\n", ((FatDate & 0xFE00) >> 9)+1980, ((FatDate & 0x1E0) >> 5), FatDate & 0x1F, FatDate, FatTime); file_len = (uint32_t) st.st_size; while (file_len) { - len = fread(buff, 1, 16384, tap_fd); // precti 16kiB dat + len = fread(buff, 1, 16384, tap_fd); // read 16kiB from file CountSumBlock(p_fileinfo, num_blocks, buff, len); file_len -= len; num_blocks++; @@ -582,30 +575,36 @@ void sercpSend(void) { p_fileinfo->fi_numblocks = num_blocks; p_fileinfo->length = num_blocks*4 + 85; CountFileInfoChecksum(p_fileinfo); -#ifdef __WIN32 +#ifdef _WIN32 WriteFile(serial_fd, (void*)p_fileinfo, sizeof(fileinfo), &ulNumBytes, NULL); #else odeslano = write (serial_fd, (void*)p_fileinfo, sizeof(fileinfo)); - tcdrain(serial_fd); + if (tcdrain(serial_fd) == -1) { + perror("tcdrain err1: "); + return; + } #endif - printf("Fileinfo sent with filename: %s\n", bname); + printf("Fileinfo sent with filename: %s\n", p_bname); sleep_ms(wait_ms); - rewind(tap_fd); // prenaseny soubor na zacatek + rewind(tap_fd); file_len = (uint32_t) st.st_size; overall_sent = 0; - while (file_len && is_continue) { - len = fread(buff, 1, 16384, tap_fd); // precti 16kiB dat + while (file_len) { + len = fread(buff, 1, 16384, tap_fd); // read 16kiB from file p_buff = buff; sent_size = 256; len_sent = len; - while (len_sent && is_continue) { -#ifdef __WIN32 + while (len_sent) { +#ifdef _WIN32 WriteFile(serial_fd, (void*)p_buff, sent_size, &ulNumBytes, NULL); odeslano = (size_t)ulNumBytes; #else odeslano = write (serial_fd, (void*)p_buff, sent_size); - tcdrain(serial_fd); + if (tcdrain(serial_fd) == -1) { + perror("tcdrain err2: "); + return; + } #endif p_buff += odeslano; overall_sent += odeslano; @@ -620,16 +619,12 @@ void sercpSend(void) { sleep_ms(wait_ms); } } - if (is_continue) { - printf("\nFile sent...\n"); - } else { - printf("\nend...\n"); - } + printf("\nFile sent...\n"); fclose(tap_fd); } int OpenUart() { -#ifdef __WIN32 +#ifdef _WIN32 DCB sDCB; COMMTIMEOUTS sCommTimeouts; @@ -677,7 +672,7 @@ int OpenUart() { return(-1); } tcgetattr(serial_fd, &oldtio); /* save current port settings */ - bzero(&newtio, sizeof (newtio)); + explicit_bzero(&newtio, sizeof (newtio)); switch (baud_rate){ case 115200: newtio.c_cflag = B115200; @@ -708,9 +703,9 @@ int OpenUart() { newtio.c_cflag = B38400; break; } - cfmakeraw(&newtio); - cfsetspeed(&newtio, baud_rate); - newtio.c_cflag |= CS8 | CLOCAL | CREAD | CRTSCTS; // CSTOPB - dva stop bity NEE + cfmakeraw(&newtio); + cfsetspeed(&newtio, baud_rate); + newtio.c_cflag |= CS8 | CLOCAL | CREAD | CRTSCTS; // CSTOPB - two stop bits NOT printf ("Serial device: %s, communication speed is: %d Bd\n", MODEMDEVICE, baud_rate); newtio.c_cc[VMIN] = 1; newtio.c_cc[VTIME] = 0; @@ -720,12 +715,14 @@ int OpenUart() { #endif } -void CloseUart() { +void CloseSerialPort() { if (serial_fd) { -#ifdef __WIN32 +#ifdef _WIN32 + PurgeComm(serial_fd, PURGE_RXABORT| PURGE_TXABORT | PURGE_RXCLEAR | PURGE_TXCLEAR); CloseHandle(serial_fd); #else - close (serial_fd); + tcflush(serial_fd, TCIOFLUSH); + close (serial_fd); #endif } } @@ -736,15 +733,7 @@ void CloseUart() { /************************************************************************/ int main(int argc, char** argv, char** env) { - #ifndef __WIN32 - // osetreni breaku ^C v unixech - saterm.sa_handler = signal_handler_sigterm; - saterm.sa_flags = 0; - sigaction (SIGINT, &saterm, NULL); -#endif width = GetTerminalWidth(); - - // nastaveni serioveho portu inp_indx = 0; if (argc < 2) { printf("You must specify the Serial device and file\n"); @@ -758,16 +747,15 @@ int main(int argc, char** argv, char** env) exit (EXIT_FAILURE); } - #ifndef __WIN32 - spolfd_serial[0].fd = serial_fd; // nastaveni hlidaneho descriptoru - spolfd_serial[0].events = POLLIN; // hlidaji se data na vstupu - #endif - // serial copy activated +#ifndef _WIN32 + spolfd_serial[0].fd = serial_fd; // watching descriptor + spolfd_serial[0].events = POLLIN; // watch data on input +#endif if (is_scp_read) { sercpRecv(); } else { sercpSend(); } - CloseUart(); + CloseSerialPort(); return 0; } diff --git a/sercp.rc b/sercp.rc index fafa7b7..ea02ace 100644 --- a/sercp.rc +++ b/sercp.rc @@ -1,8 +1,8 @@ // RC file, codepage utf-8 !!!!! #include // include for version info constants 1 VERSIONINFO -FILEVERSION 0,3,0,0 -PRODUCTVERSION 0,3,0,0 +FILEVERSION 0,3,1,0 +PRODUCTVERSION 0,3,1,0 FILETYPE VFT_APP { BLOCK "StringFileInfo" @@ -10,14 +10,14 @@ FILETYPE VFT_APP BLOCK "040904E4" { VALUE "CompanyName", "vym.cz" - VALUE "FileVersion", "0.3.0" + VALUE "FileVersion", "0.3.1" VALUE "FileDescription", "sercp - serial copy for ZX Spectrum" VALUE "InternalName", "sercp" VALUE "LegalCopyright", "GNU GPL v3 or above" VALUE "LegalTrademarks", "Pavel Vymetálek" VALUE "OriginalFilename", "sercp" VALUE "ProductName", "sercp" - VALUE "ProductVersion", "0.3.0" + VALUE "ProductVersion", "0.3.1" VALUE "Build environment", "Linux: Mingw64, x86_64" } } -- cgit