1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-06-26 21:43:25 -04:00
Files
sdrangel/modemmeshcore/meshcorepacket.h
T

194 lines
5.9 KiB
C++

///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2026 Tom Hensel <code@jitter.eu> //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef MODEMMESHCORE_MESHCOREPACKET_H_
#define MODEMMESHCORE_MESHCOREPACKET_H_
#include <QByteArray>
#include <QProcessEnvironment>
#include <QString>
#include <QtGlobal>
#include <QVector>
#include <stdint.h>
#include "export.h"
namespace modemmeshcore
{
// MeshCore default radio params (EU primary): 869.618 MHz / 62.5 kHz / SF 8 / CR 8
constexpr int kDefaultBandwidthHz = 62500;
constexpr int kDefaultSpreadFactor = 8;
constexpr int kDefaultParityBits = 4; // 4 -> CR 4/8
constexpr uint8_t kDefaultSyncWord = 0x12; // MeshCore wire sync (verify against firmware)
constexpr int kDefaultPreambleChirps = 16; // MeshCore minimum: 16 for SF>8, 32 for SF<9
constexpr qint64 kDefaultCenterFrequencyHz = 869618000LL;
// ---- Crypto sizes (MeshCore wire spec) ----
constexpr int kPubKeySize = 32; // Ed25519 / X25519 public key
constexpr int kPrvKeySize = 64; // expanded Ed25519 private key
constexpr int kSignatureSize = 64; // Ed25519 signature
constexpr int kCipherKeySize = 16; // AES-128
constexpr int kCipherBlockSize = 16;
constexpr int kCipherMacSize = 2; // HMAC-SHA256 truncated to 2 bytes
// ---- Header byte (first OTA byte) layout ----
// bits [1:0] route_type (4 values)
// bits [5:2] payload_type (12 named + reserved)
// bits [7:6] version (currently 0)
constexpr uint8_t kRouteMask = 0x03;
constexpr int kPayloadTypeShift = 2;
constexpr uint8_t kPayloadTypeMask = 0x0F;
constexpr int kVersionShift = 6;
constexpr uint8_t kVersionMask = 0x03;
enum RouteType : uint8_t
{
RouteTFlood = 0x00,
RouteFlood = 0x01,
RouteDirect = 0x02,
RouteTDirect = 0x03,
};
enum PayloadType : uint8_t
{
PayloadReq = 0x00,
PayloadResp = 0x01,
PayloadTxt = 0x02,
PayloadAck = 0x03,
PayloadAdvert = 0x04,
PayloadGrpTxt = 0x05,
PayloadGrpData = 0x06,
PayloadAnonReq = 0x07,
PayloadPath = 0x08,
PayloadTrace = 0x09,
PayloadMulti = 0x0A,
PayloadCtrl = 0x0B,
PayloadRawCustom = 0x0F,
};
// ---- Path packing ----
// path_len byte:
// bits [7:6] hash size selector: 0=>1B, 1=>2B, 2=>3B, 3=>reserved
// bits [5:0] hash count (0..63)
// total path bytes on wire = hash_count * hash_size
constexpr uint8_t kPathModeMask = 0xC0;
constexpr int kPathModeShift = 6;
constexpr uint8_t kPathCountMask = 0x3F;
struct PathLen
{
int hashCount; // number of hop hashes (0..63)
int hashSize; // bytes per hash (1, 2, or 3)
int totalBytes; // hashCount * hashSize
};
MODEMMESHCORE_API PathLen decodePathLen(uint8_t raw);
MODEMMESHCORE_API uint8_t encodePathLen(int hashCount, int hashSize);
// ---- ADVERT app-data flags ----
enum AdvertFlags : uint8_t
{
AdvertNodeChat = 0x01,
AdvertNodeRepeater = 0x02,
AdvertNodeRoom = 0x03,
AdvertNodeSensor = 0x04,
AdvertHasLocation = 0x10,
AdvertHasFeature1 = 0x20,
AdvertHasFeature2 = 0x40,
AdvertHasName = 0x80,
};
struct MODEMMESHCORE_API DecodeResult
{
struct Field
{
QString path;
QString value;
};
bool isFrame = false;
bool dataDecoded = false; // any meaningful payload-level decode produced
bool decrypted = false;
uint8_t routeType = 0;
uint8_t payloadType = 0;
uint8_t payloadVer = 0;
QString keyLabel;
QString summary;
QVector<Field> fields;
};
struct MODEMMESHCORE_API TxRadioSettings
{
bool hasCommand = false;
bool hasLoRaParams = false;
int bandwidthHz = kDefaultBandwidthHz;
int spreadFactor = kDefaultSpreadFactor;
int parityBits = kDefaultParityBits;
int deBits = 0;
uint8_t syncWord = kDefaultSyncWord;
int preambleChirps = kDefaultPreambleChirps;
bool hasCenterFrequency = false;
qint64 centerFrequencyHz = kDefaultCenterFrequencyHz;
QString summary;
};
class MODEMMESHCORE_API Packet
{
public:
static bool isCommand(const QString& text);
static bool buildFrameFromCommand(
const QString& command,
QByteArray& frame,
QString& summary,
QString& error
);
static bool decodeFrame(
const QByteArray& frame,
DecodeResult& result
);
static bool decodeFrame(
const QByteArray& frame,
DecodeResult& result,
const QString& keySpecList
);
static bool validateKeySpecList(
const QString& keySpecList,
QString& error,
int* keyCount = nullptr
);
static QString defaultKeysFromEnv();
static bool deriveTxRadioSettings(
const QString& command,
TxRadioSettings& settings,
QString& error
);
};
} // namespace modemmeshcore
#endif // MODEMMESHCORE_MESHCOREPACKET_H_