Sending files over serial port

22,890

Solution 1

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

Solution 2

I was also going to suggest Z-Modem or X-Modem for file transferring. But what you've got to understand is that there's nothing special about files. As far as the transferring computer and receiving terminal are concerned, the file being sent is just a stream of binary data, no matter if it's a jpeg image, a compressed file or just a text file.

All you've got to do is write the incoming stream into a file an make sure it has the right extension so it can be properly handled.

The transfer protocols mentioned above only add layers to ensure the whole file is being sent and that it is not corrupted, but you can dismiss them on a first instance to understand the concept.

Share:
22,890
capcom
Author by

capcom

I like to learn, teach, and share. I ask a lot of questions because I am curious. I hope to apply what I learn from my fellow humans in my quest to make the world a better place. Be kind to all, stay true to yourself. Personal success is secondary.

Updated on November 15, 2020

Comments

  • capcom
    capcom over 3 years

    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!