Sending files over serial port

c, file, linux, serial-port

Solution

If you want to transfer files, you should break the file up into chunks, and use a checksum on each chunk; then verify the checksums as you rejoin the chunks on the other side.

This is not a new problem. Others have solved it for you. You should get an existing reliable file-transfer program and run it over the serial link.

The top choice would be rsync. That is GPL, so the license may keep you from using it if you are doing proprietary work.

Another good choice would be XMODEM (or YMODEM or ZMODEM). I found a C implementation of XMODEM with a BSD license, so you can use this for sure. This is also smaller and simpler than rsync.

http://www.menie.org/georges/embedded/#xmodem

http://en.wikipedia.org/wiki/XMODEM

Problem

I need some help sending a file over a serial connection. I have two RS232 to USB cables, and I am testing out my code by using one to send data, and the other to receive it. I have them both physically connected to each other. So I wrote some code adapted from a few sources, and I can successfully transfer a series of characters. One program receives the data, the other sends it. I have these two open in two separate terminals. Find the two blocks of code below: serialout.c ``` #include <stdio.h> /* Standard input/output definitions */ #include <string.h> /* String function definitions */ #include <unistd.h> /* UNIX standard function definitions */ #include <fcntl.h> /* File control definitions */ #include <errno.h> /* Error number definitions */ #include <termios.h> /* POSIX terminal control definitions */ int main() { //writing int writeport = open_port("/dev/ttyUSB0"); char str[] = "hello how are you?"; int n = write(writeport, str, strlen(str)); if (n < 0) fputs("write() of bytes failed!\n", stderr); //closing ports close(writeport); } int open_port(char str[]) { int fd = open(str, O_RDWR | O_NOCTTY | O_NONBLOCK); // ?? NDELAY or NONBLOCK? if (fd == -1) { perror("open_port: Unable to open /dev/ttyS0 - "); } else fcntl(fd, F_SETFL, 0); struct termios options; tcgetattr(fd, &options); //this gets the current options set for the port // setting the options cfsetispeed(&options, B9600); //input baudrate cfsetospeed(&options, B9600); // output baudrate options.c_cflag |= (CLOCAL | CREAD); // ?? enable receicer and set local mode //options.c_cflag &= ~CSIZE; /* mask the character size bits */ options.c_cflag |= CS8; /* select 8 data bits */ options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // choosing raw input options.c_iflag &= ~INPCK; // disable parity check options.c_iflag &= ~(IXON | IXOFF | IXANY); // disable software flow control options.c_oflag |= OPOST; // ?? choosing processed output options.c_cc[VMIN] = 0; // Wait until x bytes read (blocks!) options.c_cc[VTIME] = 0; // Wait x * 0.1s for input (unblocks!) // settings for no parity bit options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; tcsetattr(fd, TCSANOW, &options); //set the new options ... TCSANOW specifies all option changes to occur immediately return (fd); } ``` serialin.c ``` #include <stdio.h> /* Standard input/output definitions */ #include <string.h> /* String function definitions */ #include <unistd.h> /* UNIX standard function definitions */ #include <fcntl.h> /* File control definitions */ #include <errno.h> /* Error number definitions */ #include <termios.h> /* POSIX terminal control definitions */ int main() { //reading int readport = open_port("/dev/ttyUSB1"); //trying to read one character at a time char buff; int n = 1; while (n > 0) { n = read(readport, &buff, 1); printf("%c", buff, buff); } printf("\n"); //closing ports close(readport); } int open_port(char str[]) { int fd = open(str, O_RDWR | O_NOCTTY | O_NONBLOCK); // ?? NDELAY or NONBLOCK? if (fd == -1) { perror("open_port: Unable to open /dev/ttyS0 - "); } else fcntl(fd, F_SETFL, 0); struct termios options; tcgetattr(fd, &options); //this gets the current options set for the port // setting the options cfsetispeed(&options, B9600); //input baudrate cfsetospeed(&options, B9600); // output baudrate options.c_cflag |= (CLOCAL | CREAD); // ?? enable receicer and set local mode //options.c_cflag &= ~CSIZE; /* mask the character size bits */ options.c_cflag |= CS8; /* select 8 data bits */ options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // choosing raw input options.c_iflag &= ~INPCK; // disable parity check options.c_iflag &= ~(IXON | IXOFF | IXANY); // disable software flow control options.c_oflag |= OPOST; // ?? choosing processed output options.c_cc[VMIN] = 0; // Wait until x bytes read (blocks!) options.c_cc[VTIME] = 0; // Wait x * 0.1s for input (unblocks!) // settings for no parity bit options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; tcsetattr(fd, TCSANOW, &options); //set the new options ... TCSANOW specifies all option changes to occur immediately return (fd); } ``` So what I'd like to do is send a file. For example, a jpeg file. Is there some way to convert it to bytecode and reassemble it as a jpeg? I have searched around but have found little relevant information unfortunately - maybe I'm searching the wrong terms. Even better would be to send the files after they are zipped. Ultimately, I am using gzip to zip jpeg files, then send them over the serial connection. Thanks everyone!

Original source