通过串口发送文件

时间:2012-07-23 20:04:22

标签: c linux file serial-port

我需要一些通过串行连接发送文件的帮助。我有两条RS232转USB电缆,我用一个发送数据测试我的代码,另一个用来接收它。我让它们彼此物理连接。

所以我编写了一些改编自几个来源的代码,我可以成功转移一系列字符。一个程序接收数据,另一个程序发送数据。我将这两个在两个独立的终端中打开。找到下面的两个代码块:

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);
}

所以我想做的是发送文件。例如,一个jpeg文件。有没有办法将其转换为字节码并将其重组为jpeg?我一直在搜索,但遗憾的是找不到相关信息 - 也许我正在搜索错误的条款。

更好的方法是在压缩文件后发送文件。最后,我使用gzip压缩jpeg文件,然后通过串行连接发送它们。谢谢大家!

2 个答案:

答案 0 :(得分:5)

如果要传输文件,则应将文件分成块,并在每个块上使用校验和;然后在你重新加入另一方的块时验证校验和。

这不是一个新问题。其他人已经为你解决了。您应该获得一个现有的可靠文件传输程序,并通过串行链接运行它。

最佳选择是rsync。这是GPL,因此如果您正在进行专有工作,许可证可能会阻止您使用它。

另一个不错的选择是XMODEM(或YMODEM或ZMODEM)。我找到了带有BSD许可证的XMODEM的C实现,所以你可以肯定地使用它。这比rsync更小更简单。

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

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

答案 1 :(得分:4)

我还建议使用Z-Modem或X-Modem进行文件传输。但你必须明白的是文件并没有什么特别之处。就转移计算机和接收终端而言,正在发送的文件只是二进制数据流,无论它是jpeg图像,压缩文件还是文本文件。

您需要做的就是将传入的流写入文件,确保它具有正确的扩展名,以便正确处理。

上面提到的传输协议只添加图层以确保整个文件正在发送并且没有损坏,但你可以在第一个实例上解除它们以理解这个概念。