从串行设备读取字节(并理解它们??)

问题描述 投票:0回答:1

如果有人可以向您展示代码来“理解”字节流,作为这个问题的答案,我会感到惊讶。

c++ serial-port device
1个回答
3
投票

实现这一点将完全取决于您的目标操作系统和平台。由于您提到的设备在一般用例中安装在飞机内部,因此我假设您的目标不是 Windows 平台,而更可能是 Linux 或嵌入式系统。您应该查看许多可用于在此类平台上执行串行 I/O 的资源(例如:串行编程方法)。此外,正如设备安装手册中所建议的(可在页面中间找到此处),您应该“查阅 SP-4 OEM 手册以了解消息格式和消息类型选择。”我怀疑您将获得最相关的信息以及该文档中的有用信息。您可能需要检查制造商是否为您的平台提供 API,因为这将消除您实现实际通信例程的需要。

理解数据而言,一旦您可以从串行接口读取字节,您就可以利用

struct
union
使访问数据更加方便程序员。对于您提供的粗略消息大纲,类似这样的内容可能比较合适:

struct _message
{
    uint8_t  DestinationAddress;
    uint8_t  MessageLength;
    uint8_t  MessageType;
    uint8_t  MessageSubtype;
    int32_t  BankAngle; //assuming an int is 32 bits
    int32_t  PitchAngle;
    int32_t  YawAngle;
    sint_t   Slip; //not sure what a 'sint' is
    fps_t    GForce; //likewise 'fps'
    uint8_t  MISC;
    uint16_t Heading; //assuming a word is 16 bits
    uint8_t  Unused[UNUSED_BYTES]; //however many there are
    uintt_t  Voltage;
}

struct myMessage
{
    union
    {
        char raw[MAX_MESSAGE_SIZE]; //sizeof(largest possible message)
        struct _message message;
    }
}

这样,如果您要声明

struct myMessage serialData;
,您可以将消息读入
serialData.raw
,然后方便地访问其成员(例如
serialData.message.DestinationAddress
)。

编辑:为了响应您的编辑,我将提供一个示例来说明如何理解您的数据。此示例假设您只需要担心一种消息类型,但它可以轻松扩展到其他类型。

struct myMessage serialData;
memcpy(serialData.raw, serialDataBuffer, MAX_MESSAGE_SIZE); //copy data from your buffer
if(serialData.message.MessageType == SOME_MESSAGE_TYPE)
{
    //you have usable data here.
    printf("I am a SOME_MESSAGE!\n");
}

现在,假设这些整数类型实际上仅对数据传输有用,您需要将这些位转换为“可用数据”。假设这些字段之一实际上是一个编码的浮点数。一种常见的方案是选择位权重(有时也称为分辨率)。我不知道这是否直接适用于您的设备,或者它是否是真实值,但为了讨论起见,我们假设

YawAngle
字段的分辨率为
0.00014 degrees/bit
。例如,要将消息中的值 (
serialData.message.YawAngle
) 从
uint32_t
值转换为
double
,您可以执行以下操作:

double YawAngleValue = 0.00014 * serialData.message.YawAngle;

...仅此而已。 OEM 手册应该告诉您数据是如何编码的,并且您应该能够从那里找出如何解码它。

现在,假设您有两种消息类型需要处理。我已经向您展示了这一点,以及一条理论上的

CRITICAL_BITS
消息。要使用我列出的方案添加该类型,您首先需要定义
CRITICAL_BITS
结构(可能如下):

struct _critical_bits
{
    uint8_t  DestinationAddress;
    uint8_t  MessageLength;
    uint8_t  MessageType;
    uint8_t  MessageSubtype;
    uint32_t SomeCriticalData;
}

...然后将其添加到

struct myMessage
定义中,如下所示:

struct myMessage
{
    union
    {
        char raw[MAX_MESSAGE_SIZE]; //sizeof(largest possible message)
        struct _message message;
        struct _critical_bits critical_message;
    }
}

...然后您可以像其他字段一样访问

SomeCriticalData

if(serialData.message.MessageType == CRITICAL_MESSAGE_TYPE)
{
    uint32_t critical_bits = serialData.critical_message.SomeCriticalData;
}

您可以通过阅读

struct
s 找到有关其工作原理的更多信息。请记住,
struct myMessage
类型的实例一次仅包含一组有意义的数据。更简单地说,如果
serialData
包含
CRITICAL_MESSAGE_TYPE
数据,则
serialData.critical_message
中的数据有效,但
serialData.message
无效——即使该语言不会阻止您在请求时访问该数据。

编辑: 再举一个例子;要使用您指定的算法计算消息的校验和,您可能需要这样的东西(假设您已经知道消息完全在缓冲区内):

uint8_t calculate_checksum(struct myMessage *data)
{
    uint8_t number_bytes = data->message.MessageLength;
    uint8_t checksum = 0;
    int i;
    for(i=0; i<number_bytes; ++i)
    {
        //this performs a XOR with checksum and the byte
        //in the message at offset i
        checksum ^= data->raw[i];
    }
    return checksum;
}

您可能需要针对未包含的字节调整该函数,检查以确保

data != NULL
等,但它应该可以帮助您开始。

© www.soinside.com 2019 - 2024. All rights reserved.