Разобрать и прочитать данные фрейма в C? - PullRequest
3 голосов
/ 23 марта 2010

Я пишу программу, которая считывает данные с последовательного порта в Linux. Данные отправляются другим устройством в следующем формате:

|start | Command | Data               | CRC  | End |
|0x02  | 0x41    | (0-127 octets)     |      | 0x03|
----------------------------------------------------

Поле данных содержит 127 октетов, как показано, а октет 1,2 содержит данные одного типа; Октет 3,4 содержит другие данные. Мне нужно получить эти данные

Я знаю, как записывать и читать данные в последовательный порт в Linux и из него, но это просто запись и чтение простой строки (например, «ABD»)

Моя проблема в том, что я не знаю, как проанализировать фрейм данных, отформатированный как указано выше, чтобы я мог:

  • получить данные в октете 1,2 в поле данных
  • получить данные в октете 3,4 в поле данных
  • получить значение в поле CRC для проверки согласованности данных

Вот пример снипп-кода, который читает и записывает простую строку с и на последовательный порт в Linux:

int writeport(int fd, char *chars) {
    int len = strlen(chars);
    chars[len] = 0x0d; // stick a <CR> after the command
    chars[len+1] = 0x00; // terminate the string properly
    int n = write(fd, chars, strlen(chars));
    if (n < 0) {
        fputs("write failed!\n", stderr);
        return 0;
    }
    return 1;                                                                                                           
}

int readport(int fd, char *result) {
    int iIn = read(fd, result, 254);
    result[iIn-1] = 0x00;
    if (iIn < 0) {
        if (errno == EAGAIN) {
            printf("SERIAL EAGAIN ERROR\n");
            return 0;
        } else {
            printf("SERIAL read error %d %s\n", errno, strerror(errno));
            return 0;
        }
    }                    
    return 1;
}

У кого-нибудь есть идеи?

Ответы [ 2 ]

5 голосов
/ 23 марта 2010

result - это массив char с шириной в 1 октет.

для чтения октета n использование:

char octet_n = result[n];

Итак, чтобы делать то, что вы хотите, вам нужно:

// skip the start and command fields
char *data_field = result + 2; 

int octet_1_2 = data_field[1] | (data_field[2] << 8);
int octet_3_4 = data_field[3] | (data_field[4] << 8);

// crc is at byte 128 + 2 = 130
int crc = result[130];

Редактировать : Объяснение для этой строки:

int octet_1_2 = data_field[1] | (data_field[2] << 8);

Вы хотите прочитать два последовательных октета в одно 16-битное слово:

            1
       bits 5        8 7       0
            --------------------
octet_1_2 = | octet 2 | octet 1|
            --------------------

Итак, вы хотите взять биты 7: 0 октета 1 и поместить их в биты 7: 0 octet_1_2:

octet_1_2 = data_field[1];

Затем вы хотите взять биты 7: 0 октета 2 и поместить их в биты 15: 8 octet_1_2. Вы делаете это, сдвигая октет на 2 8 бит влево и OR 'получая результат в octet_1_2:

octet_1_2 |= data_field[2] << 8;

Эти две строки можно объединить в одну, как я делал выше.

0 голосов
/ 23 марта 2010

Лучшая вещь для чтения отформатированных данных в C - это чтение структуры. Учитывая ваш формат кадра, я бы сделал следующее.


typedef struct special_data
{
    char first_data[2];
    char second data[2];
} special_data_t;

union data_u
{
    special_data_t my_special_data;
    char           whole_data[128];
};

typedef struct data_frame
{
    unsigned char start;
    unsigned char cmd;
    union data_u  data;
    unsigned char crc;
    unsigned char end;
} data_frame_t;

void func_read(int fd)
{
    data_frame_t my_data;

    if (read(fd, &my_data, sizeof(my_data)) != -1)
    {
        // Do something
    }
    return;
}

Таким образом, вы можете получить доступ к нужным данным через поля структуры. Первая структура и объединение являются просто помощниками для доступа к нужным байтам в поле данных фрейма.

...