Files
Manuel d234bd98c7 feat: Serial connection from portduino (#256)
* fix standalone reboot

* add LinuxSerialClient

* trunk fmt

* debug log levels
2025-12-29 13:06:31 +01:00

129 lines
4.2 KiB
C++

#include "comms/MeshEnvelope.h"
#include "mesh-pb-constants.h"
#include "util/ILog.h"
#include <pb_decode.h>
#include <pb_encode.h>
extern const uint8_t MT_MAGIC_0 = 0x94;
extern const uint8_t MT_MAGIC_1 = 0xc3;
MeshEnvelope::MeshEnvelope(void) : envelope(PB_BUFSIZE + MT_HEADER_SIZE) {}
MeshEnvelope::MeshEnvelope(const uint8_t *pb_buf, size_t length) : envelope(pb_buf, pb_buf + length) {}
std::vector<uint8_t> &MeshEnvelope::encode(const meshtastic_ToRadio &toRadio)
{
pb_ostream_t stream = pb_ostream_from_buffer(&envelope[MT_HEADER_SIZE], PB_BUFSIZE);
if (pb_encode(&stream, meshtastic_ToRadio_fields, &toRadio)) {
// Store the payload length in the header
envelope[0] = MT_MAGIC_0;
envelope[1] = MT_MAGIC_1;
envelope[2] = (stream.bytes_written & 0xFF00) >> 8;
envelope[3] = stream.bytes_written & 0xFF;
if (stream.bytes_written <= PB_BUFSIZE) {
ILOG_TRACE("encoding %d byte successful", stream.bytes_written);
envelope.resize(stream.bytes_written + MT_HEADER_SIZE);
} else {
ILOG_ERROR("PB_BUFSIZE too small (<%d)", stream.bytes_written);
envelope.resize(0);
}
} else {
ILOG_ERROR("Couldn't encode toRadio");
envelope.resize(0);
}
return envelope;
}
/**
* @brief decoding of validated bytestream
*
* @param pb_size
* @return meshtastic_FromRadio
*/
meshtastic_FromRadio MeshEnvelope::decode()
{
meshtastic_FromRadio fromRadio = meshtastic_FromRadio_init_zero;
uint16_t payload_len = envelope[2] << 8 | envelope[3];
pb_istream_t stream = pb_istream_from_buffer(&envelope[MT_HEADER_SIZE], payload_len);
bool status = pb_decode(&stream, meshtastic_FromRadio_fields, &fromRadio);
if (!status) {
ILOG_ERROR("Decoding failed!");
return meshtastic_FromRadio(meshtastic_FromRadio_init_zero);
}
envelope.resize(payload_len + MT_HEADER_SIZE);
return fromRadio;
}
/**
* @brief search packet magic in byte stream and move it to beginning
*
* @param pb_buf inout: byte stream
* @param pb_size inout: length of byte stream
* @param size out: length of packet
* @return true if stream contains full packet at beginning of buffer
*/
bool MeshEnvelope::validate(uint8_t *pb_buf, size_t &pb_size, size_t &payload_len)
{
size_t startpos = 0;
if (pb_size < MT_HEADER_SIZE) {
return false;
}
while ((pb_buf[startpos] != MT_MAGIC_0 || pb_buf[startpos + 1] != MT_MAGIC_1) && startpos <= pb_size) {
startpos++;
}
if (startpos >= pb_size) {
ILOG_TRACE("MeshEnvelope: no magic found, skipping %d bytes (%02x%02x%02x...)", pb_size, (int)pb_buf[0], (int)pb_buf[1],
(int)pb_buf[2]);
pb_size = 0;
return false;
}
payload_len = (pb_buf[startpos + 2] << 8) | pb_buf[startpos + 3];
if (startpos > 0) {
if (payload_len > PB_BUFSIZE) {
ILOG_ERROR("Got packet claiming to be ridiculous length (%d bytes)", payload_len);
pb_size = 0;
payload_len = 0;
return false;
}
// re-align magic header to front of buffer
ILOG_TRACE("Skipping first %d bytes (%02x%02x%02x...)", startpos, (int)pb_buf[0], (int)pb_buf[1], (int)pb_buf[2]);
pb_size -= startpos;
memmove(&pb_buf[0], &pb_buf[startpos], pb_size);
}
if ((size_t)(payload_len + MT_HEADER_SIZE) > pb_size) {
ILOG_TRACE("Partial packet received. Expected %d, have only %d", payload_len + MT_HEADER_SIZE, pb_size);
return false;
}
ILOG_TRACE("Valididated packet, payload_len=%d, pb_size=%d", payload_len, pb_size);
return true;
}
/**
* @brief remove old packet from buffer and move next payload to front
*
* @param pb_buf inout: byte stream
* @param pb_size inout: length of byte stream
* @param size out: length of packet
*/
void MeshEnvelope::invalidate(uint8_t *pb_buf, size_t &pb_size, size_t &payload_len)
{
pb_buf[0] = 0x00;
pb_buf[1] = 0x00;
if (pb_size < payload_len + MT_HEADER_SIZE) {
pb_size = 0;
} else {
pb_size -= payload_len + MT_HEADER_SIZE;
}
ILOG_TRACE("Invalidating %d bytes, pb_size=%d", payload_len + MT_HEADER_SIZE, pb_size);
memmove(&pb_buf[0], &pb_buf[payload_len + MT_HEADER_SIZE], pb_size);
}