Итак, в настоящее время я разрабатываю простой протокол передачи для кольцевой сети, реализованный в UART.
Для передачи я конвертирую данные из структуры в поток символов, начинающийся <и завершающийся> - Я знаю о возможности того, что любое значение 0x3 c или 0x3e будет ошибочно принято за <или> соответственно, я работаю над решением, чтобы избежать этого. Это не часть моего вопроса.
Итак, его структура похожа на <UINT32UINT32UINT8UINT8UINT16char[0...n]>
, эти типы представляют: <destinationId senderId TimeToLive Cmdtype CmdId Payloadlength Payload>
. Это всегда остается неизменным, поэтому я могу предположить это без каких-либо разделителей между значениями. Это работает, и я теоретически тоже могу это расшифровать. Чтобы легко получить доступ к байтам, я реализовал структуру с объединениями:
typedef struct{
union{
uint32_t val;
char bytes[sizeof(uint32_t)];
} recipientId;
union{
uint32_t val;
char bytes[sizeof(uint32_t)];
} senderId;
union{
uint8_t val;
char bytes[sizeof(uint8_t)];
} timeToLive;
union{
uint8_t val;
char bytes[sizeof(uint8_t)];
} cmdType;
union{
uint8_t val;
char bytes[sizeof(uint8_t)];
} cmdId;
union{
uint16_t val;
char bytes[sizeof(uint16_t)];
} payloadLength;
char *payload;
char *commandRaw;
} aurPacket_t;
Как только пакет существует, я декодирую его чем-то похожим на это:
void decode_command(aurPacket_t packet){
if((packet.commandRaw[0] != '<' ) || (packet.commandRaw[strlen(packet.commandRaw) - 1] != '>') ){
printf("\n\nINVALID COMMAND\n\n");
}
else{
aurPacket_t newpacket;
// EITHER:
// for (int i = 0; i < strlen(newpacket.recipientId.bytes); i++){
// newpacket.recipientId.bytes[i] = (char)*(packet.commandRaw + 1 + i);
// }
// OR:
strncpy(newpacket.recipientId.bytes, (packet.commandRaw + 1), sizeof(newpacket.recipientId.bytes));
}
}
commandRaw содержит поток символов который будет получен в сообщении.
Используя что-то вроде этого, я смог бы это сделать, но мне нужно было бы повторять его одно за другим, поскольку не все значения имеют один и тот же тип данных - копирование строки до моей полезной нагрузки в конце концов. Есть ли способ сделать это более элегантным, чем итерация по каждой отдельной переменной, чтобы как-то итерировать, используя мою структуру в качестве руководства для итератора?
Я был осведомлен о memcpy, но поскольку я хочу сохранить протокол не зависит от платформы, я бы предпочел не использовать его, если нет элегантного способа. Или есть способ использовать это элегантно? Мой метод добавления переменных отличается от простого использования memcpy? Думая об этом, это не похоже на то, что было бы, учитывая порядок варов внутри моей структуры. Если бы я сделал строку, содержащую <
, memcpy-добавил все до полезной нагрузки, затем memcpy-добавил полезную нагрузку, а затем добавил >
, будет ли какая-то реальная разница в данных? Если нет, я мог бы просто использовать этот процесс в обратном порядке для декодирования сообщения.
В настоящее время я кодирую сообщение, используя эту функцию:
#define RAW_PACKET_LEN 1024
void parse_command(aurPacket_t packet){
snprintf(packet.commandRaw, RAW_PACKET_LEN, "<%.4s%.4s%.1s%.1s%.1s%.02s%.*s>",
packet.recipientId.bytes,
packet.senderId.bytes,
packet.timeToLive.bytes,
packet.cmdType.bytes,
packet.cmdId.bytes,
packet.payloadLength.bytes,
packet.payloadLength.val, packet.payload
);
} // memory for commandRaw allocated outside of function
, проблема в том, что на самом деле это не так. запись в поток 0x00 байтов, но это не часть вопроса - я ищу ответ на этот момент (конечно, если вы знаете простое решение, дайте мне знать :))
Система представляет собой ESP32, запрограммированный с использованием ESP-IDF.