mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-10-23 19:12:47 +00:00
First iteration that seems to work
This commit is contained in:
commit
8d1823d0b6
205 files changed
+41989
No files matched your search
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore MainBoard interface - matches MeshCore.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
#define BD_STARTUP_NORMAL 0
|
||||
#define BD_STARTUP_RX_PACKET 1
|
||||
|
||||
class MainBoard {
|
||||
public:
|
||||
virtual uint16_t getBattMilliVolts() = 0;
|
||||
virtual float getMCUTemperature() { return NAN; }
|
||||
virtual bool setAdcMultiplier(float multiplier) { (void)multiplier; return false; }
|
||||
virtual float getAdcMultiplier() const { return 0.0f; }
|
||||
virtual const char *getManufacturerName() const = 0;
|
||||
virtual void onBeforeTransmit() {}
|
||||
virtual void onAfterTransmit() {}
|
||||
virtual void reboot() = 0;
|
||||
virtual void powerOff() {}
|
||||
virtual void sleep(uint32_t secs) { (void)secs; }
|
||||
virtual uint32_t getGpio() { return 0; }
|
||||
virtual void setGpio(uint32_t values) { (void)values; }
|
||||
virtual uint8_t getStartupReason() const = 0;
|
||||
virtual bool startOTAUpdate(const char *id, char reply[]) { (void)id; (void)reply; return false; }
|
||||
|
||||
virtual bool isExternalPowered() { return false; }
|
||||
virtual uint16_t getBootVoltage() { return 0; }
|
||||
virtual uint32_t getResetReason() const { return 0; }
|
||||
virtual const char *getResetReasonString(uint32_t reason) { (void)reason; return "Not available"; }
|
||||
virtual uint8_t getShutdownReason() const { return 0; }
|
||||
virtual const char *getShutdownReasonString(uint8_t reason) { (void)reason; return "Not available"; }
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore clock interfaces - matches Dispatcher.h / MeshCore.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
class MillisecondClock {
|
||||
public:
|
||||
virtual unsigned long getMillis() = 0;
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore Dispatcher - packet queue and radio scheduling
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mesh/MeshCore.h>
|
||||
#include <mesh/Identity.h>
|
||||
#include <mesh/Packet.h>
|
||||
#include <mesh/Utils.h>
|
||||
#include <mesh/Radio.h>
|
||||
#include <mesh/Clock.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
/* EU ETSI EN 300 220 duty cycle tracker.
|
||||
* Fixed 1-hour window, tracks cumulative TX airtime in ms.
|
||||
* duty_pct=0 disables all tracking (zero overhead). */
|
||||
struct DutyCycleTracker {
|
||||
uint32_t window_start;
|
||||
uint32_t window_airtime_ms;
|
||||
uint8_t duty_pct; /* 0=disabled, 1-99=percentage */
|
||||
|
||||
void init(uint8_t pct) {
|
||||
window_start = 0;
|
||||
window_airtime_ms = 0;
|
||||
duty_pct = pct;
|
||||
}
|
||||
|
||||
void recordTx(uint32_t duration_ms, uint32_t now) {
|
||||
if (duty_pct == 0) return;
|
||||
if (now - window_start > 3600000UL) {
|
||||
window_start = now;
|
||||
window_airtime_ms = 0;
|
||||
}
|
||||
window_airtime_ms += duration_ms;
|
||||
}
|
||||
|
||||
bool isExceeded(uint32_t now) const {
|
||||
if (duty_pct == 0) return false;
|
||||
if (now - window_start > 3600000UL) return false; /* window expired */
|
||||
uint32_t budget_ms = (3600000UL / 100) * (uint32_t)duty_pct;
|
||||
return window_airtime_ms >= budget_ms;
|
||||
}
|
||||
|
||||
uint32_t budgetMs() const {
|
||||
if (duty_pct == 0) return 0;
|
||||
return (3600000UL / 100) * (uint32_t)duty_pct;
|
||||
}
|
||||
};
|
||||
|
||||
class PacketManager {
|
||||
public:
|
||||
virtual Packet *allocNew() = 0;
|
||||
virtual void free(Packet *packet) = 0;
|
||||
virtual void queueOutbound(Packet *packet, uint8_t priority, uint32_t scheduled_for) = 0;
|
||||
virtual Packet *getNextOutbound(uint32_t now) = 0;
|
||||
virtual int getOutboundCount(uint32_t now) const = 0;
|
||||
virtual int getFreeCount() const = 0;
|
||||
virtual Packet *getOutboundByIdx(int i) = 0;
|
||||
virtual Packet *removeOutboundByIdx(int i) = 0;
|
||||
virtual void queueInbound(Packet *packet, uint32_t scheduled_for) = 0;
|
||||
virtual Packet *getNextInbound(uint32_t now) = 0;
|
||||
};
|
||||
|
||||
typedef uint32_t DispatcherAction;
|
||||
|
||||
#define ACTION_RELEASE (0)
|
||||
#define ACTION_MANUAL_HOLD (1)
|
||||
#define ACTION_RETRANSMIT(pri) (((uint32_t)1 + (pri))<<24)
|
||||
#define ACTION_RETRANSMIT_DELAYED(pri, _delay) ((((uint32_t)1 + (pri))<<24) | (_delay))
|
||||
|
||||
#define ERR_EVENT_FULL (1 << 0)
|
||||
#define ERR_EVENT_CAD_TIMEOUT (1 << 1)
|
||||
#define ERR_EVENT_STARTRX_TIMEOUT (1 << 2)
|
||||
|
||||
class Dispatcher {
|
||||
Packet *outbound;
|
||||
uint32_t outbound_expiry, outbound_start, total_air_time, rx_air_time;
|
||||
uint32_t next_tx_time;
|
||||
uint32_t cad_busy_start;
|
||||
DutyCycleTracker _duty_cycle;
|
||||
uint32_t radio_nonrx_start;
|
||||
uint32_t next_floor_calib_time, next_agc_reset_time;
|
||||
bool prev_isrecv_mode;
|
||||
uint32_t n_sent_flood, n_sent_direct;
|
||||
uint32_t n_recv_flood, n_recv_direct;
|
||||
|
||||
void processRecvPacket(Packet *pkt);
|
||||
|
||||
protected:
|
||||
Radio *_radio;
|
||||
MillisecondClock *_ms;
|
||||
PacketManager *_mgr;
|
||||
uint16_t _err_flags;
|
||||
|
||||
Dispatcher(Radio &radio, MillisecondClock &ms, PacketManager &mgr);
|
||||
virtual DispatcherAction onRecvPacket(Packet *pkt) = 0;
|
||||
virtual void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) { (void)snr; (void)rssi; (void)raw; (void)len; }
|
||||
virtual void logRx(Packet *packet, int len, float score) { (void)packet; (void)len; (void)score; }
|
||||
virtual void logTx(Packet *packet, int len) { (void)packet; (void)len; }
|
||||
virtual void logTxFail(Packet *packet, int len) { (void)packet; (void)len; }
|
||||
virtual const char *getLogDateTime() { return ""; }
|
||||
virtual uint8_t getDutyCyclePercent() const;
|
||||
static bool isAdminPacket(const Packet *pkt);
|
||||
virtual int calcRxDelay(float score, uint32_t air_time) const;
|
||||
virtual uint32_t getCADFailRetryDelay() const;
|
||||
virtual uint32_t getCADFailMaxDuration() const;
|
||||
virtual int getInterferenceThreshold() const { return 0; }
|
||||
virtual int getAGCResetInterval() const { return 0; }
|
||||
|
||||
public:
|
||||
void begin();
|
||||
void loop();
|
||||
Packet *obtainNewPacket();
|
||||
void releasePacket(Packet *packet);
|
||||
void sendPacket(Packet *packet, uint8_t priority, uint32_t delay_millis = 0);
|
||||
|
||||
uint32_t getTotalAirTime() const { return total_air_time; }
|
||||
uint32_t getReceiveAirTime() const { return rx_air_time; }
|
||||
uint32_t getNumSentFlood() const { return n_sent_flood; }
|
||||
uint32_t getNumSentDirect() const { return n_sent_direct; }
|
||||
uint32_t getNumRecvFlood() const { return n_recv_flood; }
|
||||
uint32_t getNumRecvDirect() const { return n_recv_direct; }
|
||||
uint16_t getErrFlags() const { return _err_flags; }
|
||||
void resetStats() {
|
||||
n_sent_flood = n_sent_direct = 0;
|
||||
n_recv_flood = n_recv_direct = 0;
|
||||
_err_flags = 0;
|
||||
}
|
||||
bool millisHasNowPassed(uint32_t timestamp) const;
|
||||
uint32_t futureMillis(int millis_from_now) const;
|
||||
|
||||
private:
|
||||
void checkRecv();
|
||||
void checkSend();
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore Identity - Ed25519 public identity
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mesh/Utils.h>
|
||||
#include <mesh/MeshCore.h>
|
||||
#include <mesh/RNG.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
class Identity {
|
||||
public:
|
||||
uint8_t pub_key[PUB_KEY_SIZE];
|
||||
|
||||
Identity();
|
||||
Identity(const char *pub_hex);
|
||||
Identity(const uint8_t *_pub) { memcpy(pub_key, _pub, PUB_KEY_SIZE); }
|
||||
|
||||
int copyHashTo(uint8_t *dest) const {
|
||||
memcpy(dest, pub_key, PATH_HASH_SIZE);
|
||||
return PATH_HASH_SIZE;
|
||||
}
|
||||
bool isHashMatch(const uint8_t *hash) const {
|
||||
return memcmp(hash, pub_key, PATH_HASH_SIZE) == 0;
|
||||
}
|
||||
bool isHashMatch(const uint8_t *hash, uint8_t len) const {
|
||||
return memcmp(hash, pub_key, len) == 0;
|
||||
}
|
||||
bool verify(const uint8_t *sig, const uint8_t *message, int msg_len) const;
|
||||
bool matches(const Identity &other) const { return memcmp(pub_key, other.pub_key, PUB_KEY_SIZE) == 0; }
|
||||
bool matches(const uint8_t *other_pubkey) const { return memcmp(pub_key, other_pubkey, PUB_KEY_SIZE) == 0; }
|
||||
bool readFrom(const uint8_t *src, size_t len);
|
||||
bool writeTo(uint8_t *dest, size_t max_len) const;
|
||||
};
|
||||
|
||||
class LocalIdentity : public Identity {
|
||||
uint8_t prv_key[PRV_KEY_SIZE];
|
||||
public:
|
||||
LocalIdentity();
|
||||
LocalIdentity(const char *prv_hex, const char *pub_hex);
|
||||
LocalIdentity(RNG *rng);
|
||||
|
||||
void sign(uint8_t *sig, const uint8_t *message, int msg_len) const;
|
||||
void calcSharedSecret(uint8_t *secret, const Identity &other) const { calcSharedSecret(secret, other.pub_key); }
|
||||
void calcSharedSecret(uint8_t *secret, const uint8_t *other_pub_key) const;
|
||||
static bool validatePrivateKey(const uint8_t prv[64]);
|
||||
|
||||
bool readFrom(const uint8_t *src, size_t len);
|
||||
size_t writeTo(uint8_t *dest, size_t max_len) const;
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore LoRa default parameters
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
struct LoRaConfig {
|
||||
static constexpr uint32_t FREQ_HZ = 869618000;
|
||||
static constexpr uint16_t BANDWIDTH = 62; /* BW_62_KHZ */
|
||||
static constexpr uint8_t SPREADING_FACTOR = 8;
|
||||
static constexpr uint8_t CODING_RATE = 8; /* CR_4_8 */
|
||||
static constexpr uint16_t PREAMBLE_LEN = 16;
|
||||
static constexpr int8_t TX_POWER_DBM = 22;
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore Mesh - routing protocol layer
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mesh/Dispatcher.h>
|
||||
#include <mesh/RTC.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
struct GroupChannel {
|
||||
uint8_t hash[PATH_HASH_SIZE];
|
||||
uint8_t secret[PUB_KEY_SIZE];
|
||||
};
|
||||
|
||||
class MeshTables {
|
||||
public:
|
||||
virtual bool hasSeen(const Packet *packet) = 0;
|
||||
virtual void clear(const Packet *packet) = 0;
|
||||
};
|
||||
|
||||
class Mesh : public Dispatcher {
|
||||
RNG *_rng;
|
||||
RTCClock *_rtc;
|
||||
MeshTables *_tables;
|
||||
|
||||
void removeSelfFromPath(Packet *packet);
|
||||
void routeDirectRecvAcks(Packet *packet, uint32_t delay_millis);
|
||||
DispatcherAction forwardMultipartDirect(Packet *pkt);
|
||||
|
||||
protected:
|
||||
DispatcherAction onRecvPacket(Packet *pkt) override;
|
||||
virtual uint32_t getCADFailRetryDelay() const override;
|
||||
virtual DispatcherAction routeRecvPacket(Packet *packet);
|
||||
virtual bool filterRecvFloodPacket(Packet *packet) { return false; }
|
||||
virtual bool allowPacketForward(const Packet *packet);
|
||||
virtual uint32_t getRetransmitDelay(const Packet *packet);
|
||||
virtual uint32_t getDirectRetransmitDelay(const Packet *packet) { return 0; }
|
||||
virtual uint8_t getExtraAckTransmitCount() const { return 0; }
|
||||
virtual int searchPeersByHash(const uint8_t *hash) { (void)hash; return 0; }
|
||||
virtual void getPeerSharedSecret(uint8_t *dest_secret, int peer_idx) { (void)dest_secret; (void)peer_idx; }
|
||||
virtual void onPeerDataRecv(Packet *packet, uint8_t type, int sender_idx, const uint8_t *secret, uint8_t *data, size_t len) { (void)packet; (void)type; (void)sender_idx; (void)secret; (void)data; (void)len; }
|
||||
virtual void onTraceRecv(Packet *packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t *path_snrs, const uint8_t *path_hashes, uint8_t path_len) { (void)packet; (void)tag; (void)auth_code; (void)flags; (void)path_snrs; (void)path_hashes; (void)path_len; }
|
||||
virtual bool onPeerPathRecv(Packet *packet, int sender_idx, const uint8_t *secret, uint8_t *path, uint8_t path_len, uint8_t extra_type, uint8_t *extra, uint8_t extra_len) { (void)packet; (void)sender_idx; (void)secret; (void)path; (void)path_len; (void)extra_type; (void)extra; (void)extra_len; return false; }
|
||||
virtual void onAdvertRecv(Packet *packet, const Identity &id, uint32_t timestamp, const uint8_t *app_data, size_t app_data_len) { (void)packet; (void)id; (void)timestamp; (void)app_data; (void)app_data_len; }
|
||||
virtual void onAnonDataRecv(Packet *packet, const uint8_t *secret, const Identity &sender, uint8_t *data, size_t len) { (void)packet; (void)secret; (void)sender; (void)data; (void)len; }
|
||||
virtual void onPathRecv(Packet *packet, Identity &sender, uint8_t *path, uint8_t path_len, uint8_t extra_type, uint8_t *extra, uint8_t extra_len) { (void)packet; (void)sender; (void)path; (void)path_len; (void)extra_type; (void)extra; (void)extra_len; }
|
||||
virtual void onControlDataRecv(Packet *packet) { (void)packet; }
|
||||
virtual void onRawDataRecv(Packet *packet) { (void)packet; }
|
||||
virtual int searchChannelsByHash(const uint8_t *hash, GroupChannel channels[], int max_matches) { (void)hash; (void)channels; (void)max_matches; return 0; }
|
||||
virtual void onGroupDataRecv(Packet *packet, uint8_t type, const GroupChannel &channel, uint8_t *data, size_t len) { (void)packet; (void)type; (void)channel; (void)data; (void)len; }
|
||||
virtual void onAckRecv(Packet *packet, uint32_t ack_crc) { (void)packet; (void)ack_crc; }
|
||||
|
||||
public:
|
||||
Mesh(Radio &radio, MillisecondClock &ms, RNG &rng, RTCClock &rtc, PacketManager &mgr, MeshTables &tables);
|
||||
void begin();
|
||||
void loop();
|
||||
|
||||
LocalIdentity self_id;
|
||||
|
||||
RNG *getRNG() const { return _rng; }
|
||||
RTCClock *getRTCClock() const { return _rtc; }
|
||||
MeshTables *getTables() const { return _tables; }
|
||||
|
||||
Packet *createAdvert(const LocalIdentity &id, const uint8_t *app_data = nullptr, size_t app_data_len = 0);
|
||||
Packet *createAck(uint32_t ack_crc);
|
||||
Packet *createMultiAck(uint32_t ack_crc, uint8_t remaining);
|
||||
Packet *createControlData(const uint8_t *data, size_t len);
|
||||
Packet *createDatagram(uint8_t type, const Identity &dest, const uint8_t *secret, const uint8_t *data, size_t len);
|
||||
Packet *createAnonDatagram(uint8_t type, const LocalIdentity &sender, const Identity &dest, const uint8_t *secret, const uint8_t *data, size_t data_len);
|
||||
Packet *createGroupDatagram(uint8_t type, const GroupChannel &channel, const uint8_t *data, size_t data_len);
|
||||
Packet *createPathReturn(const Identity &dest, const uint8_t *secret, const uint8_t *path, uint8_t path_len, uint8_t extra_type, const uint8_t *extra, size_t extra_len);
|
||||
Packet *createPathReturn(const uint8_t *dest_hash, const uint8_t *secret, const uint8_t *path, uint8_t path_len, uint8_t extra_type, const uint8_t *extra, size_t extra_len);
|
||||
Packet *createRawData(const uint8_t *data, size_t len);
|
||||
Packet *createTrace(uint32_t tag, uint32_t auth_code, uint8_t flags = 0);
|
||||
|
||||
void sendFlood(Packet *packet, uint32_t delay_millis = 0);
|
||||
void sendFlood(Packet *packet, uint16_t *transport_codes, uint32_t delay_millis = 0);
|
||||
void sendDirect(Packet *packet, const uint8_t *path, uint8_t path_len, uint32_t delay_millis = 0);
|
||||
void sendZeroHop(Packet *packet, uint32_t delay_millis = 0);
|
||||
void sendZeroHop(Packet *packet, uint16_t *transport_codes, uint32_t delay_millis = 0);
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore constants and base types (Zephyr port)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
#define MAX_HASH_SIZE 8
|
||||
#define PUB_KEY_SIZE 32
|
||||
#define PRV_KEY_SIZE 64
|
||||
#define SEED_SIZE 32
|
||||
#define SIGNATURE_SIZE 64
|
||||
#define MAX_ADVERT_DATA_SIZE 32
|
||||
#define CIPHER_KEY_SIZE 16
|
||||
#define CIPHER_BLOCK_SIZE 16
|
||||
#define CIPHER_MAC_SIZE 2
|
||||
#define PATH_HASH_SIZE 1
|
||||
|
||||
#define MAX_PACKET_PAYLOAD 184
|
||||
#define MAX_PATH_SIZE 64
|
||||
#define MAX_TRANS_UNIT 255
|
||||
|
||||
#define MESH_DEBUG_PRINT(...)
|
||||
#define MESH_DEBUG_PRINTLN(...)
|
||||
|
||||
namespace mesh {
|
||||
|
||||
#define BD_STARTUP_NORMAL 0
|
||||
#define BD_STARTUP_RX_PACKET 1
|
||||
|
||||
} /* namespace mesh */
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore Packet - fundamental transmission unit
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mesh/MeshCore.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
#define PH_ROUTE_MASK 0x03
|
||||
#define PH_TYPE_SHIFT 2
|
||||
#define PH_TYPE_MASK 0x0F
|
||||
#define PH_VER_SHIFT 6
|
||||
#define PH_VER_MASK 0x03
|
||||
|
||||
#define ROUTE_TYPE_TRANSPORT_FLOOD 0x00
|
||||
#define ROUTE_TYPE_FLOOD 0x01
|
||||
#define ROUTE_TYPE_DIRECT 0x02
|
||||
#define ROUTE_TYPE_TRANSPORT_DIRECT 0x03
|
||||
|
||||
#define PAYLOAD_TYPE_REQ 0x00
|
||||
#define PAYLOAD_TYPE_RESPONSE 0x01
|
||||
#define PAYLOAD_TYPE_TXT_MSG 0x02
|
||||
#define PAYLOAD_TYPE_ACK 0x03
|
||||
#define PAYLOAD_TYPE_ADVERT 0x04
|
||||
#define PAYLOAD_TYPE_GRP_TXT 0x05
|
||||
#define PAYLOAD_TYPE_GRP_DATA 0x06
|
||||
#define PAYLOAD_TYPE_ANON_REQ 0x07
|
||||
#define PAYLOAD_TYPE_PATH 0x08
|
||||
#define PAYLOAD_TYPE_TRACE 0x09
|
||||
#define PAYLOAD_TYPE_MULTIPART 0x0A
|
||||
#define PAYLOAD_TYPE_CONTROL 0x0B
|
||||
#define PAYLOAD_TYPE_RAW_CUSTOM 0x0F
|
||||
|
||||
#define PAYLOAD_VER_1 0x00
|
||||
#define PAYLOAD_VER_2 0x01
|
||||
#define PAYLOAD_VER_3 0x02
|
||||
#define PAYLOAD_VER_4 0x03
|
||||
|
||||
class Packet {
|
||||
public:
|
||||
Packet();
|
||||
|
||||
uint8_t header;
|
||||
uint16_t payload_len, path_len;
|
||||
uint16_t transport_codes[2];
|
||||
uint8_t path[MAX_PATH_SIZE];
|
||||
uint8_t payload[MAX_PACKET_PAYLOAD];
|
||||
int8_t _snr;
|
||||
|
||||
void calculatePacketHash(uint8_t *dest_hash) const;
|
||||
uint8_t getRouteType() const { return header & PH_ROUTE_MASK; }
|
||||
bool isRouteFlood() const { return getRouteType() == ROUTE_TYPE_FLOOD || getRouteType() == ROUTE_TYPE_TRANSPORT_FLOOD; }
|
||||
bool isRouteDirect() const { return getRouteType() == ROUTE_TYPE_DIRECT || getRouteType() == ROUTE_TYPE_TRANSPORT_DIRECT; }
|
||||
bool hasTransportCodes() const { return getRouteType() == ROUTE_TYPE_TRANSPORT_FLOOD || getRouteType() == ROUTE_TYPE_TRANSPORT_DIRECT; }
|
||||
uint8_t getPayloadType() const { return (header >> PH_TYPE_SHIFT) & PH_TYPE_MASK; }
|
||||
uint8_t getPayloadVer() const { return (header >> PH_VER_SHIFT) & PH_VER_MASK; }
|
||||
void markDoNotRetransmit() { header = 0xFF; }
|
||||
bool isMarkedDoNotRetransmit() const { return header == 0xFF; }
|
||||
float getSNR() const { return ((float)_snr) / 4.0f; }
|
||||
int getRawLength() const;
|
||||
uint8_t writeTo(uint8_t dest[]) const;
|
||||
bool readFrom(const uint8_t src[], uint8_t len);
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore RNG interface - matches Utils.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
class RNG {
|
||||
public:
|
||||
virtual void random(uint8_t *dest, size_t sz) = 0;
|
||||
|
||||
uint32_t nextInt(uint32_t _min, uint32_t _max);
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore RTC interface - matches MeshCore.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
class RTCClock {
|
||||
uint32_t last_unique;
|
||||
|
||||
protected:
|
||||
RTCClock() : last_unique(0) {}
|
||||
|
||||
public:
|
||||
virtual uint32_t getCurrentTime() = 0;
|
||||
virtual void setCurrentTime(uint32_t time) = 0;
|
||||
virtual void tick() {}
|
||||
|
||||
uint32_t getCurrentTimeUnique() {
|
||||
uint32_t t = getCurrentTime();
|
||||
if (t <= last_unique) {
|
||||
return ++last_unique;
|
||||
}
|
||||
return last_unique = t;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore Radio interface - matches Dispatcher.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
class Radio {
|
||||
public:
|
||||
virtual void begin() {}
|
||||
|
||||
virtual int recvRaw(uint8_t *bytes, int sz) = 0;
|
||||
virtual uint32_t getEstAirtimeFor(int len_bytes) = 0;
|
||||
virtual float packetScore(float snr, int packet_len) = 0;
|
||||
virtual bool startSendRaw(const uint8_t *bytes, int len) = 0;
|
||||
virtual bool isSendComplete() = 0;
|
||||
virtual void onSendFinished() = 0;
|
||||
|
||||
virtual int getNoiseFloor() const { return 0; }
|
||||
virtual void triggerNoiseFloorCalibrate(int threshold) { (void)threshold; }
|
||||
virtual void resetAGC() {}
|
||||
|
||||
virtual bool isInRecvMode() const = 0;
|
||||
virtual bool isReceiving() { return false; }
|
||||
virtual float getLastRSSI() const { return 0; }
|
||||
virtual float getLastSNR() const { return 0; }
|
||||
|
||||
/* Packet statistics */
|
||||
virtual uint32_t getPacketsRecv() const { return 0; }
|
||||
virtual uint32_t getPacketsSent() const { return 0; }
|
||||
virtual uint32_t getPacketsRecvErrors() const { return 0; }
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore - Common radio includes for LoRa mesh roles
|
||||
*
|
||||
* Shared by companion, repeater, and any future role that uses the
|
||||
* LoRa radio. Selects LR1110 or SX126x based on Kconfig/devicetree.
|
||||
*/
|
||||
|
||||
#ifndef ZEPHCORE_RADIO_INCLUDES_H
|
||||
#define ZEPHCORE_RADIO_INCLUDES_H
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZEPHCORE_RADIO_LR1110) || DT_NODE_HAS_STATUS(DT_ALIAS(lora0), okay)
|
||||
|
||||
#include <zephyr/drivers/lora.h>
|
||||
#include <mesh/LoRaConfig.h>
|
||||
#include <adapters/board/ZephyrBoard.h>
|
||||
#include <adapters/clock/ZephyrMillisecondClock.h>
|
||||
#include <adapters/rng/ZephyrRNG.h>
|
||||
#include <mesh/SimpleMeshTables.h>
|
||||
#include <mesh/StaticPoolPacketManager.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZEPHCORE_RADIO_LR1110)
|
||||
#include <adapters/radio/LR1110Radio.h>
|
||||
#else
|
||||
#include <adapters/radio/SX126xRadio.h>
|
||||
#endif
|
||||
|
||||
#define ZEPHCORE_LORA 1
|
||||
|
||||
#endif /* CONFIG_ZEPHCORE_RADIO_LR1110 || lora0 */
|
||||
|
||||
#endif /* ZEPHCORE_RADIO_INCLUDES_H */
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* SimpleMeshTables - hash-based deduplication
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mesh/Mesh.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
#define MAX_PACKET_HASHES 64
|
||||
#define MAX_PACKET_ACKS 32
|
||||
|
||||
class SimpleMeshTables : public MeshTables {
|
||||
uint8_t _hashes[MAX_PACKET_HASHES * MAX_HASH_SIZE];
|
||||
int _next_idx;
|
||||
uint32_t _acks[MAX_PACKET_ACKS];
|
||||
int _next_ack_idx;
|
||||
|
||||
public:
|
||||
SimpleMeshTables() {
|
||||
memset(_hashes, 0, sizeof(_hashes));
|
||||
_next_idx = 0;
|
||||
memset(_acks, 0, sizeof(_acks));
|
||||
_next_ack_idx = 0;
|
||||
}
|
||||
|
||||
bool hasSeen(const Packet *packet) override {
|
||||
if (packet->getPayloadType() == PAYLOAD_TYPE_ACK) {
|
||||
uint32_t ack;
|
||||
memcpy(&ack, packet->payload, 4);
|
||||
for (int i = 0; i < MAX_PACKET_ACKS; i++) {
|
||||
if (ack == _acks[i]) return true;
|
||||
}
|
||||
_acks[_next_ack_idx] = ack;
|
||||
_next_ack_idx = (_next_ack_idx + 1) % MAX_PACKET_ACKS;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t hash[MAX_HASH_SIZE];
|
||||
packet->calculatePacketHash(hash);
|
||||
const uint8_t *sp = _hashes;
|
||||
for (int i = 0; i < MAX_PACKET_HASHES; i++, sp += MAX_HASH_SIZE) {
|
||||
if (memcmp(hash, sp, MAX_HASH_SIZE) == 0) return true;
|
||||
}
|
||||
memcpy(&_hashes[_next_idx * MAX_HASH_SIZE], hash, MAX_HASH_SIZE);
|
||||
_next_idx = (_next_idx + 1) % MAX_PACKET_HASHES;
|
||||
return false;
|
||||
}
|
||||
|
||||
void clear(const Packet *packet) override {
|
||||
if (packet->getPayloadType() == PAYLOAD_TYPE_ACK) {
|
||||
uint32_t ack;
|
||||
memcpy(&ack, packet->payload, 4);
|
||||
for (int i = 0; i < MAX_PACKET_ACKS; i++) {
|
||||
if (ack == _acks[i]) {
|
||||
_acks[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint8_t hash[MAX_HASH_SIZE];
|
||||
packet->calculatePacketHash(hash);
|
||||
uint8_t *sp = _hashes;
|
||||
for (int i = 0; i < MAX_PACKET_HASHES; i++, sp += MAX_HASH_SIZE) {
|
||||
if (memcmp(hash, sp, MAX_HASH_SIZE) == 0) {
|
||||
memset(sp, 0, MAX_HASH_SIZE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Static pool PacketManager
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mesh/Dispatcher.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
class StaticPoolPacketManager : public PacketManager {
|
||||
public:
|
||||
Packet *allocNew() override;
|
||||
void free(Packet *packet) override;
|
||||
void queueOutbound(Packet *packet, uint8_t priority, uint32_t scheduled_for) override;
|
||||
Packet *getNextOutbound(uint32_t now) override;
|
||||
int getOutboundCount(uint32_t now) const override;
|
||||
int getFreeCount() const override;
|
||||
Packet *getOutboundByIdx(int i) override;
|
||||
Packet *removeOutboundByIdx(int i) override;
|
||||
void queueInbound(Packet *packet, uint32_t scheduled_for) override;
|
||||
Packet *getNextInbound(uint32_t now) override;
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore Utils - crypto and helpers (Zephyr port)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mesh/MeshCore.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
class Utils {
|
||||
public:
|
||||
static void sha256(uint8_t *hash, size_t hash_len, const uint8_t *msg, int msg_len);
|
||||
static void sha256(uint8_t *hash, size_t hash_len, const uint8_t *frag1, int frag1_len, const uint8_t *frag2, int frag2_len);
|
||||
static int encrypt(const uint8_t *shared_secret, uint8_t *dest, const uint8_t *src, int src_len);
|
||||
static int decrypt(const uint8_t *shared_secret, uint8_t *dest, const uint8_t *src, int src_len);
|
||||
static int encryptThenMAC(const uint8_t *shared_secret, uint8_t *dest, const uint8_t *src, int src_len);
|
||||
static int MACThenDecrypt(const uint8_t *shared_secret, uint8_t *dest, const uint8_t *src, int src_len);
|
||||
static void toHex(char *dest, const uint8_t *src, size_t len);
|
||||
static bool fromHex(uint8_t *dest, int dest_size, const char *src_hex);
|
||||
static bool isHexChar(char c);
|
||||
static int parseTextParts(char *text, const char *parts[], int max_num, char separator = ',');
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
Reference in new issue
Block a user