diff options
| author | Pavel Vymetálek <pavel@vym.cz> | 2024-01-11 13:44:10 +0100 | 
|---|---|---|
| committer | Pavel Vymetálek <pavel@vym.cz> | 2024-01-11 13:44:10 +0100 | 
| commit | 9951618476f25d92907510eddd83ab51bbbd58d3 (patch) | |
| tree | 388e891829eccc7e43691fb5da7c8c32fac009b7 | |
| parent | af2ed1c080cc5a8635a498b9dbcc66d230024969 (diff) | |
| download | sercp-pc-9951618476f25d92907510eddd83ab51bbbd58d3.tar.gz | |
Communication confirmed by Ack messages without hw-flow control
- default confirmation by Ack messages
- still compatible with old .sercp by -l switch for hw flow control
- switch -w is not used when using ack messages
- new switch for turbo speed - 115200Bd. Same as on the Speccy
TODO
 - check Ack messages properly
| -rw-r--r-- | CHANGELOG | 1 | ||||
| -rw-r--r-- | TODO | 6 | ||||
| -rw-r--r-- | sercp.c | 193 | ||||
| -rw-r--r-- | sercp.rc | 10 | 
4 files changed, 160 insertions, 50 deletions
| @@ -1,3 +1,4 @@ +2024-01-11	v0.4.0 use new ACK messages instead hw-flow control  2020-05-01	v0.3.5 use gnu99 instead of gnu11, add O_NDELAY to serial port initialization  2020-04-08	v0.3.4 removed hw flow control for mac and bsd  2020-04-06	v0.3.3 fixed progressbar for files smaller than 256 bytes @@ -1,3 +1,9 @@ +2024-01-11 +    - check Ack messages properly + +2023-07-29 +    - add support for ack of messages +  2020-04-05  	+ for short files < 256 bytes does not work the progressbar - underflow counter  	- listing of enumerated serial ports - linux, win, mac @@ -68,12 +68,12 @@  #define FALSE 0  #define true 1  #define TRUE 1 -const char* _version = "v0.3.7"; +const char* _version = "v0.4.0";  // SERIAL  FILE *tapout_fd = NULL;  int is_outfile = 0;  int baud_rate = 0; -int wait_ms	= 800; +int wait_ms = 800  char *path;  char sercp_file[FILENAME_MAX];  unsigned char buff[32768]; @@ -88,7 +88,7 @@ long pos = 0;  int scp = 0;  int is_scp_read = 0;  int is_continue = 1; -int is_flow_control_none = 0;			// 1 - set flow control to NONE +int is_flow_control_hw = 0;			// 1 - set flow control to NONE  // prototypes @@ -132,21 +132,28 @@ typedef struct {  FILEINFO fileinfo;  void usage(void) { -	printf ("sercp %s (c)2018-2023 Pavel Vymetalek <pavel@vym.cz>\n", _version); +	printf ("sercp %s (c)2018-2024 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 ("Use 1109-bytes of fileinfo - blocks sums, filename, etc.\n"); +	printf ("Confirmation of communication using ack messages - no HW flow control\n"); +	printf ("Still compatible with old .sercp - with -l switch\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"); +#ifdef _WIN32 +	printf ("Usage:\nsercp.exe -d com1 [-t] [-r] <filename>\n"); +#else +	printf ("Usage:\nsercp -d /dev/serial [-t] [-r] <filename>\n"); +#endif  	printf ("\t-v, --version\tShow version info\n");  	printf ("\t-h, --help\tShow this text\n");  #ifdef _WIN32  	printf ("\t-d, --device\tSerial com port\n");  #else -	printf ("\t-d, --device\tSerial communication device\n"); +	printf ("\t-d, --device\tSerial communication device. Default /dev/ttyUSB0\n");  #endif -	printf ("\t-b, --baud\tSet the communication speed. Default 38400Bd\n"); -	printf ("\t-n, --none\tSet the flow control to NONE. Default is CTS/RTS\n\t\t\tThis is useful for eLeMeNt ZX and machines or serial port without CTS/RTS wires\n"); -	printf ("\t-w, --wait\tWaiting in milliseconds between transmitted blocks.\n\t\t\tDefault is -w 800 ms\n"); +	printf ("\t-b, --baud\tSet the communication baud rate. Default 38400Bd\n"); +	printf ("\t-t, --turbo\tSet the baud rate 115200Bd\n"); +	printf ("\t-l, --hwflow\tSet the flow control to CTS/RTS. Default is NONE.\n\t\t\tThis is useful for old .sercp with HW flow control\n"); +	printf ("\t-w, --wait\tWaiting in milliseconds between transmitted blocks.\n\t\t\tIn case of improperly functioning hw flow control\n");  	printf ("\t-r, --read\tRead file from serial port\n");  } @@ -161,13 +168,14 @@ void TestArgs (int argc, char *argv[])  			{"device", required_argument, NULL, 'd'},  			{"baud", required_argument, NULL, 'b'},  			{"wait", required_argument, NULL, 'w'}, -			{"none", no_argument, NULL, 'n'}, +			{"hwflow", no_argument, NULL, 'l'},  			{"read", no_argument, NULL, 'r'}, +			{"turbo", no_argument, NULL, 't'},  			{"version", no_argument, NULL, 'v'},  			{"help", no_argument, NULL, 'h'},  			{0, 0, 0, 0}  		}; -		c = getopt_long (argc, argv, "d:b:w:nrvh", long_options, &option_index); +		c = getopt_long (argc, argv, "d:b:w:lrtvh", long_options, &option_index);  		if (c == -1) {  			// end of arguments  			break; @@ -183,14 +191,17 @@ void TestArgs (int argc, char *argv[])  			case 'b':  				baud_rate = atoi(optarg);  				break; +			case 't': +				baud_rate = 115200; +				break;  			case 'w':  				wait_ms = atoi(optarg);  				break;  			case 'r':  				is_scp_read = 1;  				break; -			case 'n': -				is_flow_control_none = 1; +			case 'l': +				is_flow_control_hw = 1;  				break;  			case 'v':  				printf ("%s\n", _version); @@ -242,22 +253,6 @@ void CloseSerialPort() {  //*****************************************************************************  // -// uSleep win32 implementation - -void uSleep(int waitTime) { -	#ifdef _WIN32 -	__int64 time1 = 0, time2 = 0, freq = 0; - -	QueryPerformanceCounter((LARGE_INTEGER *) &time1); -	QueryPerformanceFrequency((LARGE_INTEGER *)&freq); - -	do { -		QueryPerformanceCounter((LARGE_INTEGER *) &time2); -	} while ((time2 - time1) < waitTime); -	#else -	usleep(waitTime); -	#endif -}  void sleep_ms(int milliseconds) {  #ifdef WIN32 @@ -401,6 +396,99 @@ uint32_t GetOverallLen(FILEINFO *p_fi) {  	return overall_len;  } +void sendFileinfoAck(void) { +uint8_t fi_ack_buffer[] = {'A','c','k',0, 0x49, 0x0F}; +#ifdef _WIN32 +	unsigned long ulNumBytes; +	WriteFile(serial_fd, (void*)fi_ack_buffer, sizeof(fi_ack_buffer), &ulNumBytes, NULL); +#else +	size_t odeslano; +	odeslano = write (serial_fd, (void*)fi_ack_buffer, sizeof(fi_ack_buffer)); +	if (tcdrain(serial_fd) == -1) { +		perror("tcdrain err1: "); +		return; +	} +#endif +} + +void sendBlockAck(uint8_t block_num) { +	uint8_t fi_ack_buffer[] = {'A','C','K',0, 0x49, 0x0F}; +	int x; +	uint8_t s_xor = 0; +	uint8_t s_sum = 0; +	fi_ack_buffer[3] = block_num; +	// printf("\n Ack sent: "); +	for (x=0; x<(sizeof(fi_ack_buffer)-2);x++) { +		s_xor ^= fi_ack_buffer[x]; +		s_sum += fi_ack_buffer[x]; +		fi_ack_buffer[4] = s_xor; +		fi_ack_buffer[5] = s_sum; +		// printf("%2X ",fi_ack_buffer[x]); +	} +		// printf("%2X ",fi_ack_buffer[4]); +		// printf("%2X \n",fi_ack_buffer[5]); +#ifdef _WIN32 +	unsigned long ulNumBytes; +	WriteFile(serial_fd, (void*)fi_ack_buffer, sizeof(fi_ack_buffer), &ulNumBytes, NULL); +#else +	size_t odeslano; +	odeslano = write (serial_fd, (void*)fi_ack_buffer, sizeof(fi_ack_buffer)); +	if (tcdrain(serial_fd) == -1) { +		perror("tcdrain err1: "); +		return; +	} +#endif +} + +uint8_t buf_ack[8]; + +uint8_t* WaitReadAck(void) { +int result; +int x; +size_t len = 0; + +#ifdef _WIN32 +	unsigned long ulNumBytes; +	sleep_ms(10); +	ReadFile(serial_fd, buf_ack,  6, &ulNumBytes, NULL); +#else +	memset(buf_ack, 0, 8); +	while (1) { +		result = poll (spolfd_serial, 1, 300);		// 200ms timeout +		if (result == 0) { +			// nothing is comming +			continue; +		} else if (result == -1) { +			FlushSerialPort(); +			CloseSerialPort(); +			exit(EXIT_FAILURE); +		} else if (result) { +			len += read (serial_fd, &buf_ack[len], 6); +			if (len == 6) { +				// printf("\nAck ok: "); +				// for (x = 0; x < 6; x++) { +				// 	printf("%2X ", buf_ack[x]); +				// } +				// printf("\n"); +				break; +			} +		} +	} +#endif +	return (buf_ack); +} +// receive fileinfo ACK + +void RecvAckFileinfo(void) { +	WaitReadAck(); +	sleep_ms(100);		// 100ms to wait speccy +} + +void RecvAckBlock(uint8_t block_number) { +	WaitReadAck(); +	sleep_ms(100);		// 100ms to wait speccy +} +  /************************************************************************/  void sercpRecv(void) {  	int recv_phase = 0;			// 0 - fileinfo, 1 - 16kiB block, 2 - last block @@ -454,6 +542,9 @@ void sercpRecv(void) {  							p_buff = buff;			// initialize buffer pointer  							length = 0;  							expected_len = p_fileinfo->fi_blocks[block_index].block_len; +							// TODO Send FileinfoAck +							sleep_ms(100); +							sendFileinfoAck();  							tapout_fd = fopen ((char*)p_fileinfo->fi_name, "wb");  							if (tapout_fd == NULL) {  								#ifdef _WIN32 @@ -504,6 +595,9 @@ void sercpRecv(void) {  						if (CheckSumBlock(p_fileinfo, block_index, buff) == 0) {  							// block is ok - write to file  							if (tapout_fd) fwrite(buff, length, 1, tapout_fd); +							// TODO +							sleep_ms(100); +							sendBlockAck(block_index);  						}  						length = 0;  						p_buff = buff; @@ -556,6 +650,7 @@ void sercpSend(void) {  	uint32_t len_sent;  	uint16_t send_size;  	uint32_t overall_sent; +	uint8_t blck_num = 0;  #ifdef _WIN32  	unsigned long ulNumBytes;  #endif @@ -626,8 +721,11 @@ void sercpSend(void) {  	}  #endif  	printf("Fileinfo sent with filename: %s\n", p_bname); -	sleep_ms(wait_ms); - +	if (!is_flow_control_hw) { +		RecvAckFileinfo(); +	} else { +		sleep_ms(wait_ms); +	}  	rewind(tap_fd);  	file_len = (uint32_t) st.st_size;  	overall_sent = 0; @@ -660,9 +758,14 @@ void sercpSend(void) {  			DoProgress(overall_sent, st.st_size, PROGRESS_PERCENT);  		}  		file_len -= len; -		if (file_len > 0) { -			sleep_ms(wait_ms); +		if (!is_flow_control_hw) { +			RecvAckBlock(blck_num); +		} else { +			if (file_len > 0) { +				sleep_ms(wait_ms); +			}  		} +		blck_num++;  	}  	printf("\nFile sent...\n");  #ifdef __APPLE__ @@ -693,12 +796,12 @@ int OpenUart() {  	sDCB.fAbortOnError = TRUE;  	sDCB.fOutxDsrFlow = FALSE;  	sDCB.fDtrControl = DTR_CONTROL_DISABLE; -	if (is_flow_control_none) { -		sDCB.fRtsControl = RTS_CONTROL_DISABLE; -		sDCB.fOutxCtsFlow = FALSE; -	} else { +	if (is_flow_control_hw) {  		sDCB.fRtsControl = RTS_CONTROL_HANDSHAKE;  		sDCB.fOutxCtsFlow = TRUE; +	} else { +		sDCB.fRtsControl = RTS_CONTROL_DISABLE; +		sDCB.fOutxCtsFlow = FALSE;  	}  	if (SetCommState(serial_fd, &sDCB) == 0) {  		return (-1); @@ -788,18 +891,18 @@ int OpenUart() {  		newtio.c_cflag |= CS8 | CLOCAL | CREAD | CCTS_OFLOW | CRTS_IFLOW | HUPCL;  	}  #else -	if (is_flow_control_none) { -		// usefull for eLeMeNt ZX and machines or serial port without CTS/RTS wires -		newtio.c_cflag |= CS8 | CLOCAL | CREAD; -	} else { +	if (is_flow_control_hw) {  		// standard CTS/RTS flow control  		newtio.c_cflag |= CS8 | CLOCAL | CREAD | CRTSCTS; +	} else { +		// usefull for eLeMeNt ZX and machines or serial port without CTS/RTS wires +		newtio.c_cflag |= CS8 | CLOCAL | CREAD;  	}  #endif  	newtio.c_iflag &= ~(IXON | IXOFF | IXANY);  	newtio.c_oflag &= ~(OPOST);  	newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);		// raw input -	printf ("Serial device: %s, communication speed is: %d Bd, flow control: %s\n", SERIALDEVICE, baud_rate, (is_flow_control_none)?"None":"CTS/RTS"); +	printf ("Serial device: %s, communication speed is: %d Bd, flow control: %s\n", SERIALDEVICE, baud_rate, (is_flow_control_hw)?"CTS/RTS":"None");  	// http://unixwiz.net/techtips/termios-vmin-vtime.html  	newtio.c_cc[VMIN] = 1;	// minimum number to read @@ -820,7 +923,7 @@ int main(int argc, char** argv, char** env)  	width = GetTerminalWidth();  	inp_indx = 0;  	if (argc < 2) { -		printf("You must specify the Serial device and file\n"); +		// printf("You must specify the Serial device and file\n");  		usage();  		exit(1);  	} @@ -830,7 +933,7 @@ int main(int argc, char** argv, char** env)  		printf ("Can't open serial port\n");  		exit (EXIT_FAILURE);  	} - +	FlushSerialPort();  #ifndef _WIN32  	spolfd_serial[0].fd = serial_fd;		// watching descriptor  	spolfd_serial[0].events = POLLIN;		// watch data on input @@ -1,8 +1,8 @@ -// RC file, codepage utf-8 !!!!! +// RC file, codepage utf-8!  #include <windows.h> // include for version info constants  1 VERSIONINFO -FILEVERSION 0,3,7,0 -PRODUCTVERSION 0,3,7,0 +FILEVERSION 0,4,0,0 +PRODUCTVERSION 0,4,0,0  FILETYPE VFT_APP  {    BLOCK "StringFileInfo" @@ -10,14 +10,14 @@ FILETYPE VFT_APP  		 BLOCK "040904E4"  		 {  			 VALUE "CompanyName", "vym.cz" -			 VALUE "FileVersion", "0.3.7" +			 VALUE "FileVersion", "0.4.0"  			 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.7" +			 VALUE "ProductVersion", "0.4.0"  			 VALUE "Build environment", "Linux: Mingw64, x86_64"  		 }  	 } | 
