gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:02:56 25 4
gpt4 key购买 nike

我正在研究 ATMEL 传感器板(加速度计和陀螺仪)的固件,并尝试在 Ubuntu 的平台中读取数据。

目前固件是这样的:

Ubuntu 发送字符“D”,作为响应,固件发回以“\n”结尾的 20 字节数据,然后 ubuntu 使用 serialport_read_until(fd, buff, '\n') 并假设 buff[0] 是字节零等。采集频率为200hz。但是使用这种方法有时我会收到损坏的值并且效果不佳。在ubuntu中也有很多“Unable to write on serial port”的错误。

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

但我不知道如何连续读取以上述结构发送的数据。

抱歉,如果这是一个微不足道的问题。我不是程序员,但我需要解决这个问题,但在搜索了几天后我找不到解决方案(我能理解!)。

我在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;}

新的阅读功能:

    // 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';

从固件发送的数据包:

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;

最佳答案

嗯,你在数据包“头”中有数据包的长度,所以一次读取头字段(start 结构),然后在第二次读取中读取数据和结束。

如果 startend 部分对于所有数据包都是相同的(我猜它们是),你可以很容易地计算出第二个之后的数据字段的数量阅读。


像这样:

// 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';

可能的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;
}

关于c++ - 在 C++ 中从串行端口读取具有不同包大小的数据流的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17794705/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com