简体   繁体   English

从C ++中的串行端口读取具有不同封装大小的数据流的最佳方法

[英]Best way to read data streams with different package sizes from serial port in c++

I am working on firmware of an ATMEL sensor board (accelerometer and gyro)and trying to read the data in a platform in Ubuntu. 我正在研究ATMEL传感器板(加速度计和陀螺仪)的固件,并试图在Ubuntu平台上读取数据。

Currently the firmware is like this: 当前固件是这样的:

Ubuntu sends a character "D" and the firmware in response sends back 20 bytes of data that ends in "\\n" then ubuntu uses serialport_read_until(fd, buff, '\\n') and assumes that buff[0] is byte zero and so on.The frequency of acquisition is 200hz. Ubuntu发送一个字符“ D”,作为响应,固件发送回以“ \\ n”结尾的20个字节的数据,然后ubuntu使用serialport_read_until(fd,buff,'\\ n')并假定buff [0]为字节零,并且采集频率为200hz。 BUT using this method sometimes I receive corrupted values and it is not working well. 但是使用这种方法有时会收到损坏的值,并且效果不佳。 Also there are many "Unable to write on serial port" error in ubuntu. 在ubuntu中也有许多“无法在串行端口上写”错误。

I have found an example code from ATMEL for the firmware and there the data is sent in different packages and continuously (without waiting for the computer to ask for it) the structure is like this: 我从ATMEL找到了用于固件的示例代码,并且数据以不同的包形式发送并且连续地发送(无需等待计算机发出请求),其结构如下所示:

    void adv_data_send_3(uint8_t stream_num, uint32_t timestamp,
        int32_t value0, int32_t value1, int32_t value2)
{
    /* Define packet format with 3 data fields */
    struct {
        adv_data_start_t start;       /* Starting fields of packet */
        adv_data_field_t field [3];   /* 3 data fields */
        adv_data_end_t end;           /* Ending fields of packet */
    } packet;

    /* Construct packet */
    packet.start.header1 = ADV_PKT_HEADER_1;
    packet.start.header2 = ADV_PKT_HEADER_2;
    packet.start.length  = cpu_to_le16(sizeof(packet));
    packet.start.type    = ADV_PKT_DATA;
    packet.start.stream_num = stream_num;
    packet.start.time_stamp = cpu_to_le32(timestamp);

    packet.field[0].value = cpu_to_le32(value0);
    packet.field[1].value = cpu_to_le32(value1);
    packet.field[2].value = cpu_to_le32(value2);

    packet.end.crc = 0x00;  /* Not used */
    packet.end.mark = ADV_PKT_END;

    /* Write packet */
    adv_write_buf((uint8_t *)&packet, sizeof(packet));
}

but I don't know how I can continuously read the data that is sent in a structure like above. 但我不知道如何连续读取以上述结构发送的数据。

Sorry if it is a trivial question. 抱歉,这是一个琐碎的问题。 I am not a programmer but I need to solve this and I could not find a solution (that I can understand!) after searching for a couple of days. 我不是程序员,但是我需要解决这个问题,搜索了几天后,找不到解决方案(我能理解!)。

The reading function I use in linux: 我在linux中使用的阅读功能:

int serialport_read_until(int fd, unsigned char* buf, char until){
char b[1];
int i=0;
do { 
    int n = read(fd, b, 1);  // read a char at a time
    if( n==-1) return -1;    // couldn't read
    if( n==0 ) {
        usleep( 1 * 1000 ); // wait 1 msec try again
        continue;
    }
    buf[i] = b[0]; i++;
} while( b[0] != until );
buf[i] = 0;  // null terminate the string
return 0;}

The new Reading Func: 新的阅读功能:

    // Read the header part
adv_data_start_t start;
serial_read_buf(fd, reinterpret_cast<uint8_t*>(&start), sizeof(start));

// Create a buffer for the data and the end marker
std::vector<uint8_t> data_and_end(start.length - sizeof(start));

// Read the data and end marker
serial_read_buf(fd, data_and_end.data(), data_and_end.size());

// Iterate over the data
size_t num_data_fields = (data_and_end.size() - sizeof(adv_data_end_t)) / sizeof(adv_data_field_t);

adv_data_field_t* fields = reinterpret_cast<adv_data_field_t*>(data_and_end.data());


for (size_t i = 0; i < num_data_fields; i++)
    std::cout << "Field #" << (i + 1) << " = " << fields[i].value << '\n';

The data packets that are sent from the firmware: 从固件发送的数据包:

typedef struct {
uint8_t         header1;        // header bytes - always 0xFF5A
uint8_t         header2;        // header bytes - always 0xFF5A
uint16_t        length;         // packet length (bytes)
uint32_t        time_stamp;     // time stamp (tick count)
    } adv_data_start_t;


typedef struct {
int32_t         value;          // data field value (3 VALUES)
} adv_data_field_t;


 typedef struct {
uint8_t         crc;            // 8-bit checksum
uint8_t         mark;           // 1-byte end-of-packet marker
uint16_t         mark2;           // 2-byte end-of-packet marker (Added to avoid data structure alignment problem)
 } adv_data_end_t;

Well you have the length of the packet in the packet "header", so read the header fields (the start structure) in one read, and in a second read you read the data and the end. 好吧,您在“标头”中有数据包的长度,因此在一次读取中读取标头字段( start结构),在第二次读取中读取数据和结束。

If the start and end parts are the same for all packets (which I guess they are), you can easily figure out the amount of data fields after the second read. 如果所有数据包的start部分和end部分都相同(我想它们是相同的),则可以在第二次读取后轻松确定数据字段的数量。


Something like this: 像这样:

// Read the header part
adv_data_start_t start;
adv_read_buf(reinterpret_cast<uint8_t*>(&start), sizeof(start));

// Create a buffer for the data and the end marker
std::vector<uint8_t> data_and_end(start.length - sizeof(start));

// Read the data and end marker
adv_read_buf(data_and_end.data(), data_and_end.size());

// Iterate over the data
size_t num_data_fields = (data_and_end.size() - sizeof(adv_data_end_t)) / sizeof(adv_data_field_t);

adv_data_end_t* fields = reinterpret_cast<adv_data_end_t*>(data_and_end.data());

for (size_t i = 0; i < num_data_fields; i++)
    std::cout << "Field #" << (i + 1) << " = " << fields[i] << '\n';

Possible read_buf implementation: 可能的read_buf实现:

// Read `bufsize` bytes into `buffer` from a file descriptor
// Will block until `bufsize` bytes has been read
// Returns -1 on error, or `bufsize` on success
int serial_read_buf(int fd, uint8_t* buffer, const size_t bufsize)
{
    uint8_t* current = buffer;
    size_t remaining = bufsize

    while (remaining > 0)
    {
        ssize_t ret = read(fd, current, remaining);

        if (ret == -1)
            return -1;  // Error
        else if (ret == 0)
        {
            // Note: For some descriptors, this means end-of-file or
            //       connection closed.
            usleep(1000);
        }
        else
        {
            current += ret;  // Advance read-point in buffer
            remaining -= ret;  // Less data remaining to read
        }
    }

    return bufsize;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM