Считать байты с последовательного устройства (и разобраться в них ??) - PullRequest
0 голосов
/ 27 января 2012

Я дергаю себя за волосы, пытаясь понять, как считывать байты с последовательного устройства, проверять контрольную сумму, а затем преобразовывать их во что-то, что я действительно могу прочитать.

У меня есть устройство, которое«Должно» отправлять мне различные сообщения, каждое из которых начинается с байта $ 83 и заканчивается байтом $ 84.Предпоследний байт, предположительно, является контрольной суммой, сгенерированной XORign для всех других значений вместе и сравнения.

Фактические возвращаемые значения должны быть буквенно-цифровыми, но я не могу сделать заголовки или хвост данных.Я новичок в C ++ - я уверен, что это не помогает.

Я прочитал несколько руководств по серийному программированию, но я заблудился.

Может ли кто-нибудь помочь мне, связать меня или показать, как считывать байты с устройства с последовательным интерфейсом, наблюдать за 83–84 долл., А затем разбираться в данных между?

Вот формат каждого сообщения:

$FF byte Destination Address
$10 byte Message Length 16 Bytes
$37 byte Message Type
$00 byte Message subtype
BankAngle int -179 to +180
PitchAngle int -90 to +90
YawAngle int -179 to +180
Slip sint -50 to +50
GForce fps 0 to 6G
MISC byte Mode bits
Heading word 0 to 359 
N/A not used
Voltage byte input voltage

Это все из MGL SP-4 AHRS, и для простоты использования я нацеливаюсь на систему Linux, в частности на Ubuntu.Я использую компилятор GCC и заканчиваю Eclipse CDT для разработки.

Там, где я потерян Я могу прочитать данные в буфер, но тогда я недостаточно разбираюсь в C ++, чтобы понять это после этого, поскольку это не ASCII.Мне интересно узнать, что мне нужно знать, но я не знаю, что мне нужно знать.

У меня есть фон Perl / Java.

1 Ответ

3 голосов
/ 27 января 2012

Выполнение этого будет полностью зависеть от операционной системы и целевой платформы. Поскольку упомянутое вами устройство монтируется внутри самолета в общем случае использования, я предполагаю, что вы не нацелены на платформу Windows, а скорее на Linux или встроенную систему. Существует ряд ресурсов, доступных для выполнения последовательного ввода-вывода на таких платформах (например: Последовательное программирование HOW-TO ), на которые вам следует обратить внимание. Кроме того, как указано в Руководстве по установке устройства (доступно здесь примерно на полпути вниз по странице), вам следует " Обратиться к руководству OEM SP-4 для получения информации о форматах сообщений и выборе типа сообщений. " Я подозреваю, что вы получите наиболее актуальную и полезную информацию из этого документа. Возможно, вы захотите проверить, предоставляет ли производитель API для вашей платформы, так как это сведет на нет необходимость для вас реализовывать фактическую процедуру связи.

Что касается понимания данных , как только вы сможете читать байты из вашего последовательного интерфейса, вы можете использовать struct s и union s, чтобы сделать доступ к вашим данным более удобным для программиста. Для грубой схемы сообщения, которую вы предоставили, может подойти что-то вроде этого:

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 и т. Д., Но она должна помочь вам начать работу.

...