Выполнение этого будет полностью зависеть от операционной системы и целевой платформы. Поскольку упомянутое вами устройство монтируется внутри самолета в общем случае использования, я предполагаю, что вы не нацелены на платформу 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
и т. Д., Но она должна помочь вам начать работу.