diff options
| author | Pavel Vymetálek <pavel@vym.cz> | 2020-04-03 10:32:08 +0200 | 
|---|---|---|
| committer | Pavel Vymetálek <pavel@vym.cz> | 2020-04-03 10:32:08 +0200 | 
| commit | 45c8724e89c7c0d84fa42d2877f5b71c0f70749e (patch) | |
| tree | 6e86bfa42d1393c967617693e0d46d55b6c7ce63 | |
| parent | fbf70df02022a77e228d54aa3934101dcd3e0cc5 (diff) | |
| download | sercp-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-- | CHANGELOG | 1 | ||||
| -rw-r--r-- | Makefile | 8 | ||||
| -rw-r--r-- | TODO | 4 | ||||
| -rw-r--r-- | sercp.c | 194 | ||||
| -rw-r--r-- | sercp.rc | 8 | 
5 files changed, 104 insertions, 111 deletions
| @@ -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 @@ -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 @@ -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 @@ -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;  } @@ -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"  		 }  	 } | 
