aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Vymetálek <pavel@vym.cz>2020-04-03 10:32:08 +0200
committerPavel Vymetálek <pavel@vym.cz>2020-04-03 10:32:08 +0200
commit45c8724e89c7c0d84fa42d2877f5b71c0f70749e (patch)
tree6e86bfa42d1393c967617693e0d46d55b6c7ce63
parentfbf70df02022a77e228d54aa3934101dcd3e0cc5 (diff)
downloadsercp-pc-45c8724e89c7c0d84fa42d2877f5b71c0f70749e.tar.gz
Fixed complicated interrupting by ctrl-cv0.3.1
- ctrl-c stops the program immediatelly - serial buffers are cleaned at startup and at finishing program - pointers renamed to p_... - comments are in english
-rw-r--r--CHANGELOG1
-rw-r--r--Makefile8
-rw-r--r--TODO4
-rw-r--r--sercp.c194
-rw-r--r--sercp.rc8
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 <https://www.gnu.org/licenses/>.
*/
+/*
+ * IFDEFS inspired here:
+ * https://iq.opengenus.org/detect-operating-system-in-c/
+ */
-#ifdef __WIN32
+#ifdef _WIN32
#include <stdio.h>
#include <stdint.h>
#include <io.h>
@@ -33,9 +37,7 @@
#include <time.h>
#include <sys/time.h>
#include <utime.h>
-
#else
-
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
@@ -57,13 +59,12 @@
#include <utime.h>
#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 <pavel@vym.cz>\n", _version);
+ printf ("sercp %s (c)2018-2020 Pavel Vymetalek <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 ("More info at https://vym.cz/sercp/\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");
-#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 <windows.h> // 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"
}
}