Escape-символы (0x1b/27) в бинарных пакетах не отправляются через Wi-Fi, а поврежденные сообщения при передаче
Я занимаюсь разработкой встроенной системы (STM32F4) и попытался отправить некоторые данные в простую клиентскую программу Windows Forms на стороне ПК. Когда я использовал символьный формат строки, все работало нормально, но когда я перешел на бинарный пакет для увеличения производительности, я столкнулся с проблемой с символами Escape.
Я использую nanopb для реализации Googles Protocol Buffer для передачи, и я заметил, что в 5% пакетов я получаю исключения в своей клиентской программе, сообщающие, что мои пакеты повреждены.
Я отладил в WireShark и увидел, что в этом поврежденном пакете размер был на 2-4 байта меньше исходного размера пакета. После дальнейшей проверки я обнаружил, что поврежденные пакеты всегда включали двоичное значение 27, а другие пакеты никогда не включали это значение. Я искал его и увидел, что это значение представляет собой escape-символ и что это может привести к проблемам.
В техническом документе модуля Wi-Fi, который я использую (Gainspan GSM2100), упоминается, что командам предшествует escape-символ, поэтому я думаю, что мне нужно избавиться от этих значений в моем пакете.
Я не мог найти решение своей проблемы, поэтому я был бы признателен, если бы кто-то более опытный мог привести меня к правильному подходу к решению этой проблемы.
1 ответ
Как вы отправляете данные? Вы используете библиотеку или отправляете необработанные байты? Согласно руководству, ваши команды данных должны начинаться с escape-последовательности, но также должны иметь указанную длину данных:
// Each escape sequence starts with the ASCII character 27 (0x1B),
// the equivalent to the ESC key. The contents of < > are a byte or byte stream.
// - Cid is connection id (udp, tcp, etc)
// - Data Length is 4 ASCII char represents decimal value
// i.e. 1400 bytes would be '1' '4' '0' '0' (0x31 0x34 0x30 0x30).
// - Data size must match with specified length.
// Ignore all command or esc sequence in between data pay load.
<Esc>Z<Cid><Data Length xxxx 4 ascii char><data>
Обратите внимание на замечание, касающееся размера данных: "Игнорировать все команды или последовательности esc между полезной нагрузкой данных".
Например, вот так выглядит функция GSCore::writeData в GSCore.cpp:
// Including a trailing 0 that snprintf insists to write
uint8_t header[8];
// Prepare header: <esc> Z <cid> <ascii length>
snprintf((char*)header, sizeof(header), "\x1bZ%x%04d", cid, len);
// First, write the escape sequence up to the cid. After this, the
// module responds with <ESC>O or <ESC>F.
writeRaw(header, 3);
if (!readDataResponse()) {
if (GS_LOG_ERRORS && this->error)
this->error->println("Sending bulk data frame failed");
return false;
}
// Then, write the rest of the escape sequence (-1 to not write the
// trailing 0)
writeRaw(header + 3, sizeof(header) - 1 - 3);+
// And write the actual data
writeRaw(buf, len);
Скорее всего, это должно сработать. В качестве альтернативы, грязный хак может заключаться в том, чтобы "убежать от escape-символа" перед отправкой, т.е. заменить каждый 0x27 двумя символами (0x27 0x27) перед отправкой - но это всего лишь дикая догадка, и я предполагаю, что вам следует просто проверить руководство.