aboutsummaryrefslogtreecommitdiffstats
path: root/sercp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sercp.c')
-rw-r--r--sercp.c193
1 files changed, 148 insertions, 45 deletions
diff --git a/sercp.c b/sercp.c
index a726055..fdc9fb8 100644
--- a/sercp.c
+++ b/sercp.c
@@ -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