aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--sercp.c379
2 files changed, 64 insertions, 322 deletions
diff --git a/Makefile b/Makefile
index ffe0501..9bcd37f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,10 @@
PROJECT=sercp
-all:
+all: $(PROJECT)
+
+sercp: $(PROJECT).c
gcc $(PROJECT).c -o $(PROJECT) -Wall -pedantic -MP -MD -std=gnu11 -Werror=format-security -O2
-debug:
+
+debug: $(PROJECT).c
gcc $(PROJECT).c -o $(PROJECT) -Wall -pedantic -MP -MD -std=gnu11 -Werror=format-security -g -O0
clean:
diff --git a/sercp.c b/sercp.c
index 4a34951..4d5b2b7 100644
--- a/sercp.c
+++ b/sercp.c
@@ -4,6 +4,7 @@
#include <string.h>
#include <errno.h>
#include <stdint.h>
+#include <libgen.h>
#include <getopt.h>
#include <termios.h>
#include <error.h>
@@ -18,7 +19,7 @@
#define true 1
#define TRUE 1
-
+const char* _version = "v0.2";
// SERIAL
char MODEMDEVICE[64];
FILE *tapout_fd = NULL;
@@ -26,10 +27,9 @@ int is_outfile = 0;
int baud_rate = 0;
int wait_us = 200;
int wait_ms = 800;
-#define FILENAME_LENGTH 400
-char output_dump_file[FILENAME_LENGTH];
-char tap_file[FILENAME_LENGTH];
-unsigned char in_buff[65538];
+char *path;
+char tap_file[FILENAME_MAX];
+unsigned char buff[32768];
unsigned char *p_buff;
unsigned int is_continue = 1;
unsigned int is_binary = 0;
@@ -64,69 +64,44 @@ typedef struct {
FILEINFO fileinfo;
-
void usage(void) {
- printf ("sercp v0.2 (c)2018-2019 Pavel Vymetálek <pavel@vym.cz>\n");
+ printf ("sercp %s (c)2018-2019 Pavel Vymetálek <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 ("Usage:\nsercp -d /dev/serial [-v] [-h] [-b baud_rate] [-w time] [-r] <filename>\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");
printf ("\t-d, --device\tCommunication device\n");
printf ("\t-b, --baud\tSet the communication speed. Default 38400Bd\n");
printf ("\t-w, --wait\tWaiting in milliseconds between transmitted blocks. Default is -w 800 milliseconds\n");
- printf ("\t-r, --read\tRead file from other computer (ZX Spectrum)\n");
-}
-
-void Set_DTR(unsigned short level) {
- int status;
- ioctl(serial_fd, TIOCMGET, &status);
- if (level) {
- status |= TIOCM_DTR;
- } else {
- status &= ~TIOCM_DTR;
- }
- ioctl(serial_fd, TIOCMSET, &status);
+ printf ("\t-r, --read\tRead file from serial port\n");
}
-void TestCts(void) {
- int status;
- do {
- ioctl(serial_fd, TIOCMGET, &status);
- if (status & 0x20) break;
- usleep (100);
- if (is_continue == 0) return;
- // printf ("status: %X\n",status);
- } while (1);
-}
-
-
+// fileinfo 1109bytes
+/************************************************************************/
void TestArgs (int argc, char *argv[])
{
int c;
while (1) {
int option_index = 0;
static struct option long_options[] = {
- {"outfile", required_argument, NULL, 'o'},
{"device", required_argument, NULL, 'd'},
{"baud", required_argument, NULL, 'b'},
{"wait", required_argument, NULL, 'w'},
- {"scp", no_argument, NULL, 's'},
{"read", no_argument, NULL, 'r'},
- {"binary", no_argument, NULL, 'B'},
{"version", no_argument, NULL, 'v'},
{"help", no_argument, NULL, 'h'},
{0, 0, 0, 0}
};
- c = getopt_long (argc, argv, "o:d:b:w:srBvh", long_options, &option_index);
+ c = getopt_long (argc, argv, "d:b:w:rvh", long_options, &option_index);
if (c == -1) {
// konec parametru
break;
}
switch (c) {
- case 'h':
- usage();
- exit(1);
+ case 'd':
+ strncpy(MODEMDEVICE, optarg, strlen(optarg));
+ // printf ("Serial port: %s\n", MODEMDEVICE);
break;
case 'b':
baud_rate = atoi(optarg);
@@ -135,28 +110,15 @@ void TestArgs (int argc, char *argv[])
wait_us = atoi(optarg);
wait_ms = atoi(optarg);
break;
- case 's':
- printf ("Serial CP mode is activated\n");
- scp = 1;
- break;
case 'r':
- printf ("scp read...\n");
is_scp_read = 1;
break;
- case 'd':
- strncpy(MODEMDEVICE, optarg, strlen(optarg));
-// printf ("Serial port: %s\n", MODEMDEVICE);
- break;
- case 'o':
- strncpy (output_dump_file, optarg, strlen(optarg));
- is_outfile = 1;
- break;
- case 'B':
- printf ("Running in binary output mode\n");
- is_binary = 1;
- break;
case 'v':
- printf ("Version 0.9.1 2015-07-22\n");
+ printf ("%s\n", _version);
+ exit(1);
+ break;
+ case 'h':
+ usage();
exit(1);
break;
default:
@@ -171,61 +133,14 @@ void TestArgs (int argc, char *argv[])
}
-// from tapheader utility
-unsigned int h_len;
-
-unsigned int getword(unsigned char* data) {
- return *data + 256 * (*(data + 1));
-}
-
-void tooshort(FILE *fd) {
- printf("Input file too short.\n\n");
- fclose(fd);
- exit(2);
-}
-
-// decode header1
-void decode(unsigned char *header) {
- char name[11];
- unsigned int n;
- printf("\n");
- strncpy(name, (char*)(header+2), 10);
- name[10] = '\0';
- printf("Filename: %12s \n", name);
- printf("Flag: %4u ", (unsigned int)*header);
- n = getword(header+14);
- h_len = getword(header+12);
-
- switch(*(header+1)) {
- case '\0':
- printf("Type: 0 => program\nProgram length: %6u bytes ", h_len);
- if (n < 32768) printf("Runs from line %5u\t", n);
- printf("Length without variables: %5u bytes ", getword(header+16));
- break;
- case '\1':
- printf("Type: 1 => number array\tLength: %6u bytes", h_len);
- break;
- case '\2':
- printf("Type: 2 => character array\tLength: %6u bytes", h_len);
- break;
- case '\3':
- if (n == 16384 && h_len == 6912)
- printf("Type: 3 => screen image\n");
- else
- printf("Type: 3 => bytes "
- "Start address: %5u\t"
- "Length: %6u bytes\t3rd param: %4u",
- n, h_len, getword(header+16));
- break;
- }
- printf("\n");
-}
+/************************************************************************/
void signal_handler_sigterm (int status) {
// CTRL+C pressed
is_continue = 0; // do not continue
}
+/************************************************************************/
int GetTerminalWidth(void) {
struct winsize termsize;
ioctl (STDOUT_FILENO, TIOCGWINSZ, &termsize);
@@ -236,6 +151,7 @@ int GetTerminalWidth(void) {
#define PROGRESS_COMPLETTE 1
#define PROGRESS_ERROR_CSUM 2
+/************************************************************************/
void DoProgress(size_t pos, size_t max, unsigned char csum_ok) {
width = GetTerminalWidth();
float percent, p, m;
@@ -264,183 +180,7 @@ void DoProgress(size_t pos, size_t max, unsigned char csum_ok) {
fflush (stdout);
}
-#define HEADER_RAW_LEN 21
-
-void RecvTap() {
- unsigned int err;
- size_t len;
- int result;
- size_t block_pos = 0, last_block_pos = 0;
- size_t block_len = 10000;
- size_t tap_pos = 0;
- unsigned char xor_csum, xor_csum_ok;
- unsigned char *p_write;
- unsigned char block_type; // typ bloku 255 data 0 - hlavicka
- unsigned char recv_status = 0; // 0 - zacatek, 1 - hlavicka nactena, 2 - blok se nacita, 3- header less
- tapout_fd = fopen (output_dump_file, "a");
- if (tapout_fd == NULL) {
- err = errno;
- error (1, err, "can't open output file");
- }
- printf("Output file is: %s\n", output_dump_file);
- p_buff = in_buff;
- p_write = in_buff;
- while (is_continue) {
- result = poll (spolfd_serial, 1, 200); // 200ms timeout
- if (result == 0) {
- // nic neprislo
- continue;
- }
- if (spolfd_serial[0].revents & POLLIN) {
- len = read (serial_fd, p_buff, 256);
- block_pos += len;
- p_buff += len;
- if (is_binary == 0) {
- // ulozeni dat ze seriaku jako tap file
- while (len) {
- fputc(*p_write, tapout_fd);
- p_write++;
- len--;
- }
- }
- if (block_pos != last_block_pos && recv_status >= 2) {
- last_block_pos = block_pos;
- DoProgress(block_pos, block_len+2, PROGRESS_PERCENT);
- }
- if (block_pos >= HEADER_RAW_LEN && recv_status == 0) {
- recv_status = 1; // hlavicka nactena
- block_len = getword(in_buff);
- block_type = *(in_buff + 2);
- if (block_type == 0) {
- // Hlavicka komplet
- decode (in_buff + 2);
- block_len = 0;
- block_pos = 0;
- xor_csum = 0;
- recv_status = 0;
- p_buff = in_buff;
- p_write = in_buff;
- } else if (block_type == 255) {
- // data block
- printf ("Data block len: %6zu\n", block_len-2);
- recv_status = 3;
- }
- continue;
- }
- if (block_pos > HEADER_RAW_LEN + 3 && recv_status == 1) {
- // nactena delka dalsiho bloku
- recv_status = 2;
- block_len = getword(in_buff + HEADER_RAW_LEN);
- block_type = *(in_buff + HEADER_RAW_LEN + 2);
- printf ("Block len: %zu Block type: %d\n", block_len, block_type);
- continue;
- }
- if (block_len + 2 == block_pos && recv_status > 2) {
- // Blok komplet nacten cekej novy
- block_len = getword(in_buff);
- block_type = *(in_buff + 2);
- for (tap_pos = 0; tap_pos < block_len -1; tap_pos++) {
- xor_csum ^= *(in_buff + 2 + tap_pos);
- }
- xor_csum_ok = *(in_buff + 2 + block_len - 1);
- if (xor_csum == xor_csum_ok) {
- DoProgress(block_pos, block_len+2, PROGRESS_COMPLETTE); // vypis jeste OK
- if (is_binary == 1) {
- // binarni vystup do souboru
- for (tap_pos = 0; tap_pos < block_len - 2; tap_pos++){
- fputc(*(in_buff + 3 + tap_pos), tapout_fd); // uloz do souboru
- }
- DoProgress(tap_pos, block_len - 2, PROGRESS_COMPLETTE);
- }
-// printf ("Checksum OK\n");
- } else {
- DoProgress(block_pos, block_len+2, PROGRESS_ERROR_CSUM); // vypis error CSUM
- }
- block_len = 0;
- block_pos = 0;
- xor_csum = 0;
- recv_status = 0;
- p_buff = in_buff;
- p_write = in_buff;
- continue;
- }
- }
- }
- fclose (tapout_fd);
- printf ("\n\nulozeno...\n");
-}
-
-void SendByte(unsigned char *p_dato) {
- TestCts();
- write (serial_fd, p_dato, 1);
-// tcdrain(serial_fd); // better solution, but usleep at the next line is
- usleep (wait_us); // faster solution, TODO change sleep time according to serial communication speed 200us is for 57600Bd
-}
-
-void SendTap() {
- FILE *tap_fd;
- unsigned int err, no, len;
- struct stat st;
- unsigned char header[19];
-
- no = stat(tap_file, &st);
- if (no != 0) {
- err = errno;
- error(1, err, "can't stat input file");
- }
-
- tap_fd = fopen(tap_file, "r");
- if (tap_fd == NULL) {
- err = errno;
- error(1, err, "can't open input file");
- }
- while (pos < st.st_size) {
- if (is_continue == 0) break;
- pos += no = fread(header, 1, 2, tap_fd);
- if (no != 2)
- tooshort(tap_fd);
- for (out_indx = 0; out_indx < 2; out_indx++) {
- SendByte(&header[out_indx]);
- }
- no = getword(header);
- if (no == 19) /* HEADER */
- {
- pos += no = fread(header, 1, 19, tap_fd);
- if (no != 19)
- tooshort(tap_fd);
-// printf ("Header len: %d\n", no);
- decode(header);
- for (out_indx = 0; out_indx < 19; out_indx++) {
- SendByte(&header[out_indx]);
- }
- } else {
- if (h_len != no - 2) { /* zobrazuj iba bloky bez hl. */
- len = no;
- printf ("NO datablock without header: %d\n", no);
- printf("Type: datablock\nLength: %u\n", len - 2);
- pos += no = fread(header, 1, 1, tap_fd);
- SendByte(header);
- DoProgress(1, no, PROGRESS_PERCENT);
- if (no != 1) tooshort(tap_fd);
- printf("Flag: %u\n\n", (int)*header);
- len--;
- } else {
- len = no;
- }
- pos += len;
- for (out_indx = 0; out_indx < len; out_indx++) {
- fread(header, 1, 1, tap_fd);
- SendByte(header);
- DoProgress(out_indx+1, len, PROGRESS_PERCENT);
- if (is_continue == 0) break;
- }
- printf ("\n");
- usleep (800000);
- }
- }
- fclose(tap_fd);
-}
-
+/************************************************************************/
int CheckFileInfo(FILEINFO* p_fi) {
unsigned char *p_fiinfo = (unsigned char*)p_fi;
@@ -460,6 +200,7 @@ int CheckFileInfo(FILEINFO* p_fi) {
return -1;
}
+/************************************************************************/
void CountFileInfoChecksum(FILEINFO* p_fi) {
unsigned char *p_fiinfo = (unsigned char*)p_fi;
uint16_t fi_len;
@@ -476,6 +217,7 @@ void CountFileInfoChecksum(FILEINFO* p_fi) {
p_fi->h_sum = fi_sum;
}
+/************************************************************************/
int CheckSumBlock(FILEINFO* p_fi, uint8_t block_indx, uint8_t *p_buffer) {
uint16_t block_len;
uint8_t b_xor = 0;
@@ -496,6 +238,7 @@ int CheckSumBlock(FILEINFO* p_fi, uint8_t block_indx, uint8_t *p_buffer) {
return -1; // vrat se s chybou bloku
}
+/************************************************************************/
void CountSumBlock(FILEINFO* p_fi, uint8_t block_indx, uint8_t *p_buffer, uint16_t block_len) {
uint8_t block_xor = 0;
uint8_t block_sum = 0;
@@ -510,8 +253,7 @@ void CountSumBlock(FILEINFO* p_fi, uint8_t block_indx, uint8_t *p_buffer, uint16
}
-unsigned char buff[32768];
-
+/************************************************************************/
uint32_t GetOverallLen(FILEINFO *p_fi) {
uint32_t overall_len = 0;
uint8_t block_num = p_fi->fi_numblocks;
@@ -521,6 +263,7 @@ uint32_t GetOverallLen(FILEINFO *p_fi) {
return overall_len;
}
+/************************************************************************/
void RecvSCP(void) {
int recv_phase = 0; // 0 - fileinfo, 1 - blok 16kiB, 2 - posledni blok
uint8_t block_index = 0;
@@ -570,8 +313,6 @@ void RecvSCP(void) {
err = errno;
error (1, err, "can't open output file");
}
-// expected_xor = p_fileinfo->fi_blocks[block_index].block_xor;
-// expected_sum = p_fileinfo->fi_blocks[block_index].block_sum;
} else {
printf("Fileinfo neni v cajku. Koncim...\n");
break;
@@ -622,8 +363,10 @@ void RecvSCP(void) {
printf ("\n\nulozeno...\n");
}
+/************************************************************************/
void SendSCP(void) {
FILE *tap_fd;
+ char *bname, *basec; // pinter na kopii nazvu souboru - basename
unsigned int err, no, len;
struct stat st;
FILEINFO *p_fileinfo = &fileinfo;
@@ -647,10 +390,17 @@ void SendSCP(void) {
err = errno;
error(1, err, "can't open input file");
}
- printf ("Soubor %s delky: %ld\n", tap_file, st.st_size);
+ if (st.st_size == 0) {
+ printf ("Zero length of file. End\n");
+ return;
+ }
+ printf ("File %s, length: %ld\n", tap_file, st.st_size);
memset (p_fileinfo, 0, sizeof(fileinfo)); // smazat fileinfo
- memcpy(p_fileinfo->fi_name, tap_file, strlen(tap_file));
+ basec = strdup (tap_file);
+ bname = basename (basec);
+
+ memcpy(p_fileinfo->fi_name, bname, strlen(bname));
file_len = (uint32_t) st.st_size;
while (file_len) {
len = fread(buff, 1, 16384, tap_fd); // precti 16kiB dat
@@ -664,7 +414,7 @@ void SendSCP(void) {
CountFileInfoChecksum(p_fileinfo);
odeslano = write (serial_fd, (void*)p_fileinfo, sizeof(fileinfo));
tcdrain(serial_fd);
- printf("Fileinfo sent...\n");
+ printf("Fileinfo sent with filename: %s\n", bname);
// TODO Cekat pauzu mezi bloky
usleep (wait_ms * 1000);
@@ -694,6 +444,8 @@ void SendSCP(void) {
fclose(tap_fd);
}
+/************************************************************************/
+/************************************************************************/
int main(int argc, char** argv, char** env)
{
// osetreni breaku ^C
@@ -705,7 +457,7 @@ int main(int argc, char** argv, char** env)
// nastaveni serioveho portu
struct termios oldtio, newtio;
inp_indx = 0;
- if (argc < 3) {
+ if (argc < 2) {
printf("You must specify the Serial device and file\n");
usage();
exit(1);
@@ -719,42 +471,38 @@ int main(int argc, char** argv, char** env)
}
tcgetattr(serial_fd, &oldtio); /* save current port settings */
switch (baud_rate){
- default:
- baud_rate = 57600; // default speed
- newtio.c_cflag = B57600 | CS8 | CLOCAL | CREAD | CSTOPB;// | CRTSCTS;
- break;
case 115200:
- newtio.c_cflag = B115200 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS;
+ newtio.c_cflag = B115200 | CS8 | CLOCAL | CREAD | CRTSCTS;
break;
case 57600:
- newtio.c_cflag = B57600 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS;
+ newtio.c_cflag = B57600 | CS8 | CLOCAL | CREAD | CRTSCTS;
break;
+ default:
+ baud_rate = 38400;
case 38400:
newtio.c_cflag = B38400 | CS8 | CLOCAL | CREAD | CRTSCTS; // dva stopbity jsou nastaveny vsude, ale tady ne
break;
case 19200:
- newtio.c_cflag = B19200 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS;
+ newtio.c_cflag = B19200 | CS8 | CLOCAL | CREAD | CRTSCTS;
break;
case 9600:
- newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS;
+ newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD | CRTSCTS;
break;
case 4800:
- newtio.c_cflag = B4800 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS;
+ newtio.c_cflag = B4800 | CS8 | CLOCAL | CREAD | CRTSCTS;
break;
case 2400:
- newtio.c_cflag = B2400 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS;
+ newtio.c_cflag = B2400 | CS8 | CLOCAL | CREAD | CRTSCTS;
break;
case 1200:
- newtio.c_cflag = B1200 | CS8 | CLOCAL | CREAD | CSTOPB | CRTSCTS;
+ newtio.c_cflag = B1200 | CS8 | CLOCAL | CREAD | CRTSCTS;
break;
}
- newtio.c_cflag |= CRTSCTS;
+ newtio.c_cflag |= CRTSCTS; // CSTOPB - dva stop bity NEE
printf ("Serial device: %s, communication speed is: %d Bd\n", MODEMDEVICE, baud_rate);
-// newtio.c_iflag &= ~(IXON | IXOFF | IXANY); // vypne XON/XOFF
- newtio.c_iflag = 0; //IGNPAR | IXOFF;
+ newtio.c_iflag = 0;
newtio.c_oflag = 0;
-// newtio.c_oflag &= ~OPOST;
- newtio.c_lflag = 0; //NOFLSH;
+ newtio.c_lflag = 0;
newtio.c_cc[VMIN] = 0;
newtio.c_cc[VTIME] = 10;
tcsetattr(serial_fd, TCSANOW, &newtio);
@@ -762,20 +510,11 @@ int main(int argc, char** argv, char** env)
spolfd_serial[0].fd = serial_fd; // nastaveni hlidaneho descriptoru
spolfd_serial[0].events = POLLIN; // hlidaji se data na vstupu
- if (scp) {
- // serial copy activated
- if (is_scp_read) {
- RecvSCP();
- } else {
- SendSCP();
- }
+ // serial copy activated
+ if (is_scp_read) {
+ RecvSCP();
} else {
- Set_DTR(true); // PC can read data from speccy everytime
- if (is_outfile) {
- RecvTap(); // cteni tap souboru ze seriaku a zapis na disk pocitace
- } else {
- SendTap(); // poslat na seriak tap soubor do spectra
- }
+ SendSCP();
}
close (serial_fd);
return 0;