2015-02-24 4 views
1

Я пытаюсь отправить сообщения через последовательный интерфейс USB моего Arduino (C++) в Paspon Raspberry (Python).Arduino to Raspberry crc32 check

На стороне Arduino я определяю структуру, которую затем копирую в char []. Последняя часть структуры содержит контрольную сумму, которую я хочу вычислить с помощью CRC32. Я копирую структуру во временный массив символов -4 байта, чтобы удалить поле контрольной суммы. Затем контрольная сумма вычисляется с использованием временного массива, и результат добавляется в структуру. Затем структура копируется в byteMsg, который получает передачу по последовательному соединению.

На конце малины я делаю обратное, я получаю bytestring и вычисляю контрольную сумму над сообщением - 4 байта. Затем распакуйте байтовую строку и сравните полученную и вычисленную контрольную сумму, но это, к сожалению, не выполняется.

Для отладки я сравнил проверку crc32 как на python, так и на arduino для строки «Hello World», и они сгенерировали ту же контрольную сумму, что, похоже, не представляет проблемы с библиотекой. Малина также может декодировать остальную часть сообщения просто отлично, поэтому распаковка данных в переменные, похоже, тоже в порядке.

Любая помощь будет высоко оценена.

Питон Код:

def unpackMessage(self, message): 
     """ Processes a received byte string from the arduino """ 

     # Unpack the received message into struct 
     (messageID, acknowledgeID, module, commandType, 
     data, recvChecksum) = struct.unpack('<LLBBLL', message) 

     # Calculate the checksum of the recv message minus the last 4 
     # bytes that contain the sent checksum 
     calcChecksum = crc32(message[:-4]) 
     if recvChecksum == calcChecksum: 
      print "Checksum checks out" 

crc32 библиотека Aruino взяты из http://excamera.com/sphinx/article-crc.html

crc32.h

#include <avr/pgmspace.h> 

static PROGMEM prog_uint32_t crc_table[16] = { 
    0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 
    0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 
    0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 
    0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c 
}; 

unsigned long crc_update(unsigned long crc, byte data) 
{ 
    byte tbl_idx; 
    tbl_idx = crc^(data >> (0 * 4)); 
    crc = pgm_read_dword_near(crc_table + (tbl_idx & 0x0f))^(crc >> 4); 
    tbl_idx = crc^(data >> (1 * 4)); 
    crc = pgm_read_dword_near(crc_table + (tbl_idx & 0x0f))^(crc >> 4); 
    return crc; 
} 

unsigned long crc_string(char *s) 
{ 
    unsigned long crc = ~0L; 
    while (*s) 
    crc = crc_update(crc, *s++); 
    crc = ~crc; 
    return crc; 
} 

Главная Arduino эскиз

struct message_t { 
    unsigned long messageID; 
    unsigned long acknowledgeID; 
    byte module; 
    byte commandType; 
    unsigned long data; 
    unsigned long checksum; 
}; 

void sendMessage(message_t &msg) 
{ 
    // Set the messageID 
    msg.messageID = 10; 
    msg.checksum = 0; 

    // Copy the message minus the checksum into a char* 
    // Then perform the checksum on the message and copy 
    // the full msg into byteMsg 
    char byteMsgForCrc32[sizeof(msg)-4]; 
    memcpy(byteMsgForCrc32, &msg, sizeof(msg)-4); 
    msg.checksum = crc_string(byteMsgForCrc32); 

    char byteMsg[sizeof(msg)]; 
    memcpy(byteMsg, &msg, sizeof(msg)); 

    Serial.write(byteMsg, sizeof(byteMsg)); 

void loop() { 
    message_t msg; 
    msg.module = 0x31; 
    msg.commandType = 0x64; 
    msg.acknowledgeID = 0; 
    msg.data = 10; 

    sendMessage(msg); 

С уважением, Thiezn

ответ

0

Вы делаете классическую ошибку уровня связи между сетью/последовательностью/вставкой. Структуры имеют скрытое дополнение для выравнивания элементов на соответствующих границах памяти. Это не гарантируется на разных компьютерах, не говоря уже о разных процессорах/микроконтроллерах.

Возьмите эту структуру в качестве примера:

struct Byte_Int 
{ 
    int x; 
    char y; 
    int z; 
} 

Теперь на основном 32-разрядный x86 CPU у вас есть граница памяти 4 байта. Это означает, что переменные выровнены по 4 байта, 2 байта или вообще не соответствуют типу переменной. Пример будет выглядеть так в памяти: int x on bytes 0,1,2,3, char y on byte 4, int z по байтам 8,9,10,11. Почему бы не использовать три байта во второй строке? Потому что тогда контроллер памяти должен будет сделать две выборки, чтобы получить один номер! Контроллер может читать только одну строку за раз. Таким образом, структуры (и все другие типы данных) имеют скрытое заполнение, чтобы получить переменные, выровненные по памяти. Пример struct будет иметь sizeof() из 12, а не 9!

Теперь, как это относится к вашей проблеме? Вы являетесь memcpy(), создавая структуру непосредственно в буфер, включая дополнение. Компьютер на другом конце не знает об этом дополнении и неверно истолковывает данные. Что вам нужно для функции сериализации, которая берет членов ваших структур и заполняет их в буфер по одному, таким образом вы теряете заполнение и в итоге получаете что-то вроде этого: [0,1,2,3: int x ] [4: char y] [5,6,7,8: int z]. Все как один длинный bytearray/string, который можно безопасно отправить с помощью Serial(). Конечно, с другой стороны вам придется разбирать эту строку в понятные данные.Packon unpack() делает это для вас до тех пор, пока вы даете правильную строку формата.

Наконец, int на Arduino имеет длину 16 бит. На ПК вообще 4! Так что аккуратно соберите строку формата распаковки.

+0

Спасибо за быстрый ответ! Ясное объяснение и буду реализовывать его сегодня вечером и отчитываться о своих результатах. – thiezn

+0

Я пробовал сериализовать структуру (беря каждый элемент и копируя их в char *, но результат был такого же размера (в этом случае 18 байт). иногда я получал результат контрольной суммы в 0, пока я определенно заполнял структуру данными. Это дало мне догадку о том, что функция crc32 уходит, когда находит строку NULL '\ 0' в строке и после некоторых тестов кажется, что это действительно, дело. Теперь я должен признать, что функция crc32 немного из моей лиги, кто-нибудь знает, как заставить ее обрабатывать символы с завершающим символом NULL? – thiezn

+0

При ближайшем рассмотрении crc_string() я заметил ваше время (* s). Теперь '\ 0' действительно является 0, поэтому ваш цикл * будет * останавливаться всякий раз, когда он встречается с ним. Это недостаток использования строки, а не байтового массива! Таким образом, решение перестает рассматривать его как строку. Не проверяйте (* s), но p по длине вашей «строки» и запустить цикл for на основе этой длины. И наконец: CRC 0 отлично подходит. Все это просто добавление и смещение битов, так что в итоге вы можете получить 0. Особенно с более короткими CRC, которые могут переполняться более легко. – Nathilion

0

Массив char Я передавал функцию crc_string, содержащую символы '\ 0'. Crc_string выполнял итерацию по массиву до тех пор, пока не обнаружил «\ 0», который не должен происходить в этом случае, поскольку я использовал массив символов как поток байтов, отправляемый по последовательному соединению.

Я изменил функцию crc_string, чтобы принять размер массива в качестве аргумента и выполнить итерацию по массиву с использованием этого значения. Это решило проблему.

Вот новая функция

unsigned long crc_string(char *s, size_t arraySize) 
{ 
    unsigned long crc = ~0L; 
    for (int i=0; i < arraySize; i++) { 
    crc = crc_update(crc, s[i]); 
    } 
    crc = ~crc; 
    return crc; 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^