C编程检查缓冲区中的消息

时间:2019-01-26 22:26:36

标签: c buffer

我是C编程的新手,所以这可能是一个基本问题。

我有一个Arduino通过串行与PC通讯。我遇到的问题是PC读取速度快于输入串行数据的速度(可能是常见问题)。

将在PC和arduino之间发送的消息将具有一些已定义的程序包结构。对于此示例,每条消息均以ASCII'<'开头,以'>'

结尾

我能够打开/创建串行端口并接收数据(复制some code from stackoverflow),但是我想将该程序修改为:

1)将所有可用数据从串行端口读取到消息缓冲区中,并且不阻塞,因此如果没有可用数据,请继续执行#2

2)如果存在“ <”,则从消息缓冲区的开头开始查找完整的消息,直到找到“>”为止。找到完整的消息后,将消息打印到屏幕上,然后从缓冲区中删除消息,将所有未处理的数据移动到缓冲区的开头(这是我真正坚持的部分 )。如果未找到“>”,则继续执行#1

我想将逻辑/功能复制到arduino,以便arduino和PC都以相同的方式进行通信。

这是我复制的代码,用于打开串行端口并连续读取串行端口中的任何内容

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

int set_interface_attribs(int fd, int speed)
{
    struct termios tty;

    if (tcgetattr(fd, &tty) < 0) {
        printf("Error from tcgetattr: %s\n", strerror(errno));
        return -1;
    }

    cfsetospeed(&tty, (speed_t)speed);
    cfsetispeed(&tty, (speed_t)speed);

    tty.c_cflag |= (CLOCAL | CREAD);    /* ignore modem controls*/
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;         /* 8-bit characters */
    tty.c_cflag &= ~PARENB;     /* no parity bit */
    tty.c_cflag &= ~CSTOPB;     /* only need 1 stop bit */
    tty.c_cflag &= ~CRTSCTS;    /* no hardware flowcontrol */

    /* setup for non-canonical mode */
    tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
    tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
    tty.c_oflag &= ~OPOST;

    /* fetch bytes as they become available */
    tty.c_cc[VMIN] = 1;
    tty.c_cc[VTIME] = 1;

    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
        printf("Error from tcsetattr: %s\n", strerror(errno));
        return -1;
    }
    return 0;
}

void set_mincount(int fd, int mcount)
{
    struct termios tty;

    if (tcgetattr(fd, &tty) < 0) {
        printf("Error tcgetattr: %s\n", strerror(errno));
        return;
    }

    tty.c_cc[VMIN] = mcount ? 1 : 0;
    tty.c_cc[VTIME] = 5;        /* half second timer */

    if (tcsetattr(fd, TCSANOW, &tty) < 0)
        printf("Error tcsetattr: %s\n", strerror(errno));
}


int main()
{
    char *portname = "/dev/ttyACM0";
    int fd;
    int wlen;

    fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
    if (fd < 0) {
        printf("Error opening %s: %s\n", portname, strerror(errno));
        return -1;
    }
    /*baudrate 9600, 8 bits, no parity, 1 stop bit */
    set_interface_attribs(fd, B9600);
    //set_mincount(fd, 0);                /* set to pure timed read */

    /* simple output */
    wlen = write(fd, "<Hello Arduino!>", 7);
    if (wlen != 7) {
        printf("Error from write: %d, %d\n", wlen, errno);
    }
    tcdrain(fd);    /* delay for output */


    /* simple noncanonical input */
    do {
        unsigned char buf[80];
        int rdlen;

        rdlen = read(fd, buf, sizeof(buf) - 1);
        if (rdlen > 0) {
            unsigned char   *p;
            printf("Read %d:", rdlen);
            for (p = buf; rdlen-- > 0; p++)
                printf(" 0x%x", *p);
            printf("\n");
        } else if (rdlen < 0) {
            printf("Error from read: %d: %s\n", rdlen, strerror(errno));
        } else {  /* rdlen == 0 */
            printf("Timeout from read\n");
        }
        /* repeat read to get full message */
    } while (1);
}

1 个答案:

答案 0 :(得分:0)

(1)打开时将文件描述符设置为非阻塞,或仅使用poll()检查是否有要读取的数据。如果您需要进入内核缓冲区并检查缓冲区中有多少字节,则可以使用ioctl(fd,FIONREAD,&result),但是正如有人指出的那样,您确实不需要。无论哪种方式,man ioctl_tty(2)都会提供有关可用于ttys的ioctl的详细信息。

(2)遍历输入时,只需检查缓冲区中的“ <”即可。像这样:

int in_tag = 0;
for (;;) {
   // read block
   // for each char 'c'
       if (in_tag) {
           if (c == '>') in_tag = 0;
       } else if (c == '<') in_tag = 1;

当然,弄清楚如何处理“ <>”之类的问题完全是另外一个问题。...