mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-20 22:13:47 +00:00
Initial commit
This commit is contained in:
commit
6c7efdd0f6
59 changed files with 8604 additions and 0 deletions
27
src/helpers/ArduinoHelpers.h
Normal file
27
src/helpers/ArduinoHelpers.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <Mesh.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
class VolatileRTCClock : public mesh::RTCClock {
|
||||
long millis_offset;
|
||||
public:
|
||||
VolatileRTCClock() { millis_offset = 1715770351; } // 15 May 2024, 8:50pm
|
||||
uint32_t getCurrentTime() override { return (millis()/1000 + millis_offset); }
|
||||
void setCurrentTime(uint32_t time) override { millis_offset = time - millis()/1000; }
|
||||
};
|
||||
|
||||
class ArduinoMillis : public mesh::MillisecondClock {
|
||||
public:
|
||||
unsigned long getMillis() override { return millis(); }
|
||||
};
|
||||
|
||||
class StdRNG : public mesh::RNG {
|
||||
public:
|
||||
void begin(long seed) { randomSeed(seed); }
|
||||
void random(uint8_t* dest, size_t sz) override {
|
||||
for (int i = 0; i < sz; i++) {
|
||||
dest[i] = (::random(0, 256) & 0xFF);
|
||||
}
|
||||
}
|
||||
};
|
||||
16
src/helpers/CustomSX1262.h
Normal file
16
src/helpers/CustomSX1262.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <RadioLib.h>
|
||||
|
||||
#define SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received
|
||||
|
||||
class CustomSX1262 : public SX1262 {
|
||||
public:
|
||||
CustomSX1262(Module *mod) : SX1262(mod) { }
|
||||
|
||||
bool isReceiving() {
|
||||
uint16_t irq = getIrqStatus();
|
||||
bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID);
|
||||
return hasPreamble;
|
||||
}
|
||||
};
|
||||
12
src/helpers/CustomSX1262Wrapper.h
Normal file
12
src/helpers/CustomSX1262Wrapper.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "CustomSX1262.h"
|
||||
#include "RadioLibWrappers.h"
|
||||
|
||||
class CustomSX1262Wrapper : public RadioLibWrapper {
|
||||
public:
|
||||
CustomSX1262Wrapper(CustomSX1262& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { }
|
||||
bool isReceiving() override { return ((CustomSX1262 *)_radio)->isReceiving(); }
|
||||
float getLastRSSI() const override { return ((CustomSX1262 *)_radio)->getRSSI(); }
|
||||
float getLastSNR() const override { return ((CustomSX1262 *)_radio)->getSNR(); }
|
||||
};
|
||||
16
src/helpers/CustomSX1268.h
Normal file
16
src/helpers/CustomSX1268.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <RadioLib.h>
|
||||
|
||||
#define SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received
|
||||
|
||||
class CustomSX1268 : public SX1268 {
|
||||
public:
|
||||
CustomSX1268(Module *mod) : SX1268(mod) { }
|
||||
|
||||
bool isReceiving() {
|
||||
uint16_t irq = getIrqStatus();
|
||||
bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID);
|
||||
return hasPreamble;
|
||||
}
|
||||
};
|
||||
12
src/helpers/CustomSX1268Wrapper.h
Normal file
12
src/helpers/CustomSX1268Wrapper.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "CustomSX1268.h"
|
||||
#include "RadioLibWrappers.h"
|
||||
|
||||
class CustomSX1268Wrapper : public RadioLibWrapper {
|
||||
public:
|
||||
CustomSX1268Wrapper(CustomSX1268& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { }
|
||||
bool isReceiving() override { return ((CustomSX1268 *)_radio)->isReceiving(); }
|
||||
float getLastRSSI() const override { return ((CustomSX1268 *)_radio)->getRSSI(); }
|
||||
float getLastSNR() const override { return ((CustomSX1268 *)_radio)->getSNR(); }
|
||||
};
|
||||
48
src/helpers/ESP32Board.h
Normal file
48
src/helpers/ESP32Board.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
#include <MeshCore.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#if defined(ESP_PLATFORM)
|
||||
|
||||
#include <rom/rtc.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
class ESP32Board : public mesh::MainBoard { // abstract class
|
||||
public:
|
||||
void begin() {
|
||||
// for future use, sub-classes SHOULD call this from their begin()
|
||||
}
|
||||
|
||||
void reboot() override {
|
||||
esp_restart();
|
||||
}
|
||||
};
|
||||
|
||||
class ESP32RTCClock : public mesh::RTCClock {
|
||||
public:
|
||||
ESP32RTCClock() { }
|
||||
void begin() {
|
||||
esp_reset_reason_t reason = esp_reset_reason();
|
||||
if (reason == ESP_RST_POWERON) {
|
||||
// start with some date/time in the recent past
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 1715770351; // 15 May 2024, 8:50pm
|
||||
tv.tv_usec = 0;
|
||||
settimeofday(&tv, NULL);
|
||||
}
|
||||
}
|
||||
uint32_t getCurrentTime() override {
|
||||
time_t _now;
|
||||
time(&_now);
|
||||
return _now;
|
||||
}
|
||||
void setCurrentTime(uint32_t time) override {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = time;
|
||||
tv.tv_usec = 0;
|
||||
settimeofday(&tv, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
91
src/helpers/HeltecV3Board.h
Normal file
91
src/helpers/HeltecV3Board.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#pragma once
|
||||
|
||||
#include "ESP32Board.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
// LoRa radio module pins for Heltec V3
|
||||
#define P_LORA_DIO_1 14
|
||||
#define P_LORA_NSS 8
|
||||
#define P_LORA_RESET RADIOLIB_NC
|
||||
#define P_LORA_BUSY 13
|
||||
#define P_LORA_SCLK 9
|
||||
#define P_LORA_MISO 11
|
||||
#define P_LORA_MOSI 10
|
||||
|
||||
// built-ins
|
||||
#define PIN_VBAT_READ 1
|
||||
#define PIN_ADC_CTRL 37
|
||||
#define PIN_ADC_CTRL_ACTIVE LOW
|
||||
#define PIN_ADC_CTRL_INACTIVE HIGH
|
||||
#define PIN_LED_BUILTIN 35
|
||||
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
class HeltecV3Board : public ESP32Board {
|
||||
uint8_t startup_reason;
|
||||
public:
|
||||
void begin() {
|
||||
startup_reason = BD_STARTUP_NORMAL;
|
||||
ESP32Board::begin();
|
||||
|
||||
esp_reset_reason_t reason = esp_reset_reason();
|
||||
if (reason == ESP_RST_DEEPSLEEP) {
|
||||
long wakeup_source = esp_sleep_get_ext1_wakeup_status();
|
||||
if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep)
|
||||
startup_reason = BD_STARTUP_RX_PACKET;
|
||||
}
|
||||
|
||||
rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS);
|
||||
rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1);
|
||||
}
|
||||
|
||||
// battery read support
|
||||
pinMode(PIN_VBAT_READ, INPUT);
|
||||
adcAttachPin(PIN_VBAT_READ);
|
||||
analogReadResolution(10);
|
||||
pinMode(PIN_ADC_CTRL, OUTPUT);
|
||||
}
|
||||
|
||||
uint8_t getStartupReason() const { return startup_reason; }
|
||||
|
||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) {
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
|
||||
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
|
||||
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
|
||||
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
|
||||
if (pin_wake_btn < 0) {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
|
||||
} else {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
|
||||
}
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000);
|
||||
}
|
||||
|
||||
// Finally set ESP32 into sleep
|
||||
esp_deep_sleep_start(); // CPU halts here and never returns!
|
||||
}
|
||||
|
||||
uint16_t getBattMilliVolts() override {
|
||||
digitalWrite(PIN_ADC_CTRL, PIN_ADC_CTRL_ACTIVE);
|
||||
|
||||
uint32_t raw = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
raw += analogRead(PIN_VBAT_READ);
|
||||
}
|
||||
raw = raw / 8;
|
||||
|
||||
digitalWrite(PIN_ADC_CTRL, PIN_ADC_CTRL_INACTIVE);
|
||||
|
||||
return (5.2 * (3.3 / 1024.0) * raw) * 1000;
|
||||
}
|
||||
|
||||
const char* getManufacturerName() const override {
|
||||
return "Heltec V3";
|
||||
}
|
||||
};
|
||||
27
src/helpers/IdentityStore.cpp
Normal file
27
src/helpers/IdentityStore.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#include "IdentityStore.h"
|
||||
|
||||
bool IdentityStore::load(const char *name, mesh::LocalIdentity& id) {
|
||||
bool loaded = false;
|
||||
char filename[40];
|
||||
sprintf(filename, "%s/%s.id", _dir, name);
|
||||
if (_fs->exists(filename)) {
|
||||
File file = _fs->open(filename);
|
||||
if (file) {
|
||||
loaded = id.readFrom(file);
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
|
||||
bool IdentityStore::save(const char *name, const mesh::LocalIdentity& id) {
|
||||
char filename[40];
|
||||
sprintf(filename, "%s/%s.id", _dir, name);
|
||||
File file = _fs->open(filename, "w", true);
|
||||
if (file) {
|
||||
id.writeTo(file);
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
15
src/helpers/IdentityStore.h
Normal file
15
src/helpers/IdentityStore.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <FS.h>
|
||||
#include <Identity.h>
|
||||
|
||||
class IdentityStore {
|
||||
fs::FS* _fs;
|
||||
const char* _dir;
|
||||
public:
|
||||
IdentityStore(fs::FS& fs, const char* dir): _fs(&fs), _dir(dir) { }
|
||||
|
||||
void begin() { _fs->mkdir(_dir); }
|
||||
bool load(const char *name, mesh::LocalIdentity& id);
|
||||
bool save(const char *name, const mesh::LocalIdentity& id);
|
||||
};
|
||||
93
src/helpers/RadioLibWrappers.cpp
Normal file
93
src/helpers/RadioLibWrappers.cpp
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
#define RADIOLIB_STATIC_ONLY 1
|
||||
#include "RadioLibWrappers.h"
|
||||
|
||||
#define STATE_IDLE 0
|
||||
#define STATE_RX 1
|
||||
#define STATE_TX_WAIT 3
|
||||
#define STATE_TX_DONE 4
|
||||
#define STATE_INT_READY 16
|
||||
|
||||
static volatile uint8_t state = STATE_IDLE;
|
||||
|
||||
// this function is called when a complete packet
|
||||
// is transmitted by the module
|
||||
static
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
ICACHE_RAM_ATTR
|
||||
#endif
|
||||
void setFlag(void) {
|
||||
// we sent a packet, set the flag
|
||||
state |= STATE_INT_READY;
|
||||
}
|
||||
|
||||
void RadioLibWrapper::begin() {
|
||||
_radio->setPacketReceivedAction(setFlag); // this is also SentComplete interrupt
|
||||
state = STATE_IDLE;
|
||||
|
||||
if (_board->getStartupReason() == BD_STARTUP_RX_PACKET) { // received a LoRa packet (while in deep sleep)
|
||||
setFlag(); // LoRa packet is already received
|
||||
}
|
||||
}
|
||||
|
||||
int RadioLibWrapper::recvRaw(uint8_t* bytes, int sz) {
|
||||
if (state & STATE_INT_READY) {
|
||||
int len = _radio->getPacketLength();
|
||||
if (len > 0) {
|
||||
if (len > sz) { len = sz; }
|
||||
int err = _radio->readData(bytes, len);
|
||||
if (err != RADIOLIB_ERR_NONE) {
|
||||
MESH_DEBUG_PRINTLN("RadioLibWrapper: error: readData()");
|
||||
} else {
|
||||
// Serial.print(" readData() -> "); Serial.println(len);
|
||||
}
|
||||
n_recv++;
|
||||
}
|
||||
state = STATE_IDLE; // need another startReceive()
|
||||
return len;
|
||||
}
|
||||
|
||||
if (state != STATE_RX) {
|
||||
int err = _radio->startReceive();
|
||||
if (err != RADIOLIB_ERR_NONE) {
|
||||
MESH_DEBUG_PRINTLN("RadioLibWrapper: error: startReceive()");
|
||||
}
|
||||
state = STATE_RX;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t RadioLibWrapper::getEstAirtimeFor(int len_bytes) {
|
||||
return _radio->getTimeOnAir(len_bytes) / 1000;
|
||||
}
|
||||
|
||||
void RadioLibWrapper::startSendRaw(const uint8_t* bytes, int len) {
|
||||
state = STATE_TX_WAIT;
|
||||
_board->onBeforeTransmit();
|
||||
int err = _radio->startTransmit((uint8_t *) bytes, len);
|
||||
if (err != RADIOLIB_ERR_NONE) {
|
||||
MESH_DEBUG_PRINTLN("RadioLibWrapper: error: startTransmit()");
|
||||
}
|
||||
}
|
||||
|
||||
bool RadioLibWrapper::isSendComplete() {
|
||||
if (state & STATE_INT_READY) {
|
||||
state = STATE_IDLE;
|
||||
n_sent++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RadioLibWrapper::onSendFinished() {
|
||||
_radio->finishTransmit();
|
||||
_board->onAfterTransmit();
|
||||
state = STATE_IDLE;
|
||||
}
|
||||
|
||||
float RadioLibWrapper::getLastRSSI() const {
|
||||
return _radio->getRSSI();
|
||||
}
|
||||
float RadioLibWrapper::getLastSNR() const {
|
||||
return _radio->getSNR();
|
||||
}
|
||||
42
src/helpers/RadioLibWrappers.h
Normal file
42
src/helpers/RadioLibWrappers.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include <Mesh.h>
|
||||
#include <RadioLib.h>
|
||||
|
||||
class RadioLibWrapper : public mesh::Radio {
|
||||
protected:
|
||||
PhysicalLayer* _radio;
|
||||
mesh::MainBoard* _board;
|
||||
uint32_t n_recv, n_sent;
|
||||
|
||||
public:
|
||||
RadioLibWrapper(PhysicalLayer& radio, mesh::MainBoard& board) : _radio(&radio), _board(&board) { n_recv = n_sent = 0; }
|
||||
|
||||
void begin() override;
|
||||
int recvRaw(uint8_t* bytes, int sz) override;
|
||||
uint32_t getEstAirtimeFor(int len_bytes) override;
|
||||
void startSendRaw(const uint8_t* bytes, int len) override;
|
||||
bool isSendComplete() override;
|
||||
void onSendFinished() override;
|
||||
|
||||
uint32_t getPacketsRecv() const { return n_recv; }
|
||||
uint32_t getPacketsSent() const { return n_sent; }
|
||||
virtual float getLastRSSI() const;
|
||||
virtual float getLastSNR() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief an RNG impl using the noise from the LoRa radio as entropy.
|
||||
* NOTE: this is VERY SLOW! Use only for things like creating new LocalIdentity
|
||||
*/
|
||||
class RadioNoiseListener : public mesh::RNG {
|
||||
PhysicalLayer* _radio;
|
||||
public:
|
||||
RadioNoiseListener(PhysicalLayer& radio): _radio(&radio) { }
|
||||
|
||||
void random(uint8_t* dest, size_t sz) override {
|
||||
for (int i = 0; i < sz; i++) {
|
||||
dest[i] = _radio->randomByte() ^ (::random(0, 256) & 0xFF);
|
||||
}
|
||||
}
|
||||
};
|
||||
56
src/helpers/SimpleMeshTables.h
Normal file
56
src/helpers/SimpleMeshTables.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#pragma once
|
||||
|
||||
#include <MeshTables.h>
|
||||
|
||||
#ifdef ESP32
|
||||
#include <FS.h>
|
||||
#endif
|
||||
|
||||
#define MAX_PACKET_HASHES 64
|
||||
|
||||
class SimpleMeshTables : public mesh::MeshTables {
|
||||
uint8_t _fwd_hashes[MAX_PACKET_HASHES*MAX_HASH_SIZE];
|
||||
int _next_fwd_idx;
|
||||
|
||||
int lookupHashIndex(const uint8_t* hash) const {
|
||||
const uint8_t* sp = _fwd_hashes;
|
||||
for (int i = 0; i < MAX_PACKET_HASHES; i++, sp += MAX_HASH_SIZE) {
|
||||
if (memcmp(hash, sp, MAX_HASH_SIZE) == 0) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public:
|
||||
SimpleMeshTables() {
|
||||
memset(_fwd_hashes, 0, sizeof(_fwd_hashes));
|
||||
_next_fwd_idx = 0;
|
||||
}
|
||||
|
||||
#ifdef ESP32
|
||||
void restoreFrom(File f) {
|
||||
f.read(_fwd_hashes, sizeof(_fwd_hashes));
|
||||
f.read((uint8_t *) &_next_fwd_idx, sizeof(_next_fwd_idx));
|
||||
}
|
||||
void saveTo(File f) {
|
||||
f.write(_fwd_hashes, sizeof(_fwd_hashes));
|
||||
f.write((const uint8_t *) &_next_fwd_idx, sizeof(_next_fwd_idx));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool hasForwarded(const uint8_t* packet_hash) const override {
|
||||
int i = lookupHashIndex(packet_hash);
|
||||
return i >= 0;
|
||||
}
|
||||
|
||||
void setHasForwarded(const uint8_t* packet_hash) override {
|
||||
int i = lookupHashIndex(packet_hash);
|
||||
if (i >= 0) {
|
||||
// already in table
|
||||
} else {
|
||||
memcpy(&_fwd_hashes[_next_fwd_idx*MAX_HASH_SIZE], packet_hash, MAX_HASH_SIZE);
|
||||
|
||||
_next_fwd_idx = (_next_fwd_idx + 1) % MAX_PACKET_HASHES; // cyclic table
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
33
src/helpers/SimpleSeenTable.h
Normal file
33
src/helpers/SimpleSeenTable.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include <Packet.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_PACKET_HASHES 64
|
||||
|
||||
class SimpleSeenTable {
|
||||
uint8_t _hashes[MAX_PACKET_HASHES*MAX_HASH_SIZE];
|
||||
int _next_idx;
|
||||
|
||||
public:
|
||||
SimpleSeenTable() {
|
||||
memset(_hashes, 0, sizeof(_hashes));
|
||||
_next_idx = 0;
|
||||
}
|
||||
|
||||
bool hasSeenPacket(const mesh::Packet* packet) {
|
||||
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; // cyclic table
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
97
src/helpers/StaticPoolPacketManager.cpp
Normal file
97
src/helpers/StaticPoolPacketManager.cpp
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
#include "StaticPoolPacketManager.h"
|
||||
|
||||
PacketQueue::PacketQueue(int max_entries) {
|
||||
_table = new mesh::Packet*[max_entries];
|
||||
_pri_table = new uint8_t[max_entries];
|
||||
_schedule_table = new uint32_t[max_entries];
|
||||
_size = max_entries;
|
||||
_num = 0;
|
||||
}
|
||||
|
||||
mesh::Packet* PacketQueue::get(uint32_t now) {
|
||||
uint8_t min_pri = 0xFF;
|
||||
int best_idx = -1;
|
||||
for (int j = 0; j < _num; j++) {
|
||||
if (_schedule_table[j] > now) continue; // scheduled for future... ignore for now
|
||||
if (_pri_table[j] < min_pri) { // select most important priority amongst non-future entries
|
||||
min_pri = _pri_table[j];
|
||||
best_idx = j;
|
||||
}
|
||||
}
|
||||
if (best_idx < 0) return NULL; // empty, or all items are still in the future
|
||||
|
||||
mesh::Packet* top = _table[best_idx];
|
||||
int i = best_idx;
|
||||
_num--;
|
||||
while (i < _num) {
|
||||
_table[i] = _table[i+1];
|
||||
_pri_table[i] = _pri_table[i+1];
|
||||
_schedule_table[i] = _schedule_table[i+1];
|
||||
i++;
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
||||
mesh::Packet* PacketQueue::removeByIdx(int i) {
|
||||
if (i >= _num) return NULL; // invalid index
|
||||
|
||||
mesh::Packet* item = _table[i];
|
||||
_num--;
|
||||
while (i < _num) {
|
||||
_table[i] = _table[i+1];
|
||||
_pri_table[i] = _pri_table[i+1];
|
||||
_schedule_table[i] = _schedule_table[i+1];
|
||||
i++;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
void PacketQueue::add(mesh::Packet* packet, uint8_t priority, uint32_t scheduled_for) {
|
||||
if (_num == _size) {
|
||||
// TODO: log "FATAL: queue is full!"
|
||||
return;
|
||||
}
|
||||
_table[_num] = packet;
|
||||
_pri_table[_num] = priority;
|
||||
_schedule_table[_num] = scheduled_for;
|
||||
_num++;
|
||||
}
|
||||
|
||||
StaticPoolPacketManager::StaticPoolPacketManager(int pool_size): unused(pool_size), send_queue(pool_size) {
|
||||
// load up our unusued Packet pool
|
||||
for (int i = 0; i < pool_size; i++) {
|
||||
unused.add(new mesh::Packet(), 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
mesh::Packet* StaticPoolPacketManager::allocNew() {
|
||||
return unused.removeByIdx(0); // just get first one (returns NULL if empty)
|
||||
}
|
||||
|
||||
void StaticPoolPacketManager::free(mesh::Packet* packet) {
|
||||
unused.add(packet, 0, 0);
|
||||
}
|
||||
|
||||
void StaticPoolPacketManager::queueOutbound(mesh::Packet* packet, uint8_t priority, uint32_t scheduled_for) {
|
||||
send_queue.add(packet, priority, scheduled_for);
|
||||
}
|
||||
|
||||
mesh::Packet* StaticPoolPacketManager::getNextOutbound(uint32_t now) {
|
||||
//send_queue.sort(); // sort by scheduled_for/priority first
|
||||
return send_queue.get(now);
|
||||
}
|
||||
|
||||
int StaticPoolPacketManager::getOutboundCount() const {
|
||||
return send_queue.count();
|
||||
}
|
||||
|
||||
int StaticPoolPacketManager::getFreeCount() const {
|
||||
return unused.count();
|
||||
}
|
||||
|
||||
mesh::Packet* StaticPoolPacketManager::getOutboundByIdx(int i) {
|
||||
return send_queue.itemAt(i);
|
||||
}
|
||||
mesh::Packet* StaticPoolPacketManager::removeOutboundByIdx(int i) {
|
||||
return send_queue.removeByIdx(i);
|
||||
}
|
||||
34
src/helpers/StaticPoolPacketManager.h
Normal file
34
src/helpers/StaticPoolPacketManager.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include <Dispatcher.h>
|
||||
|
||||
class PacketQueue {
|
||||
mesh::Packet** _table;
|
||||
uint8_t* _pri_table;
|
||||
uint32_t* _schedule_table;
|
||||
int _size, _num;
|
||||
|
||||
public:
|
||||
PacketQueue(int max_entries);
|
||||
mesh::Packet* get(uint32_t now);
|
||||
void add(mesh::Packet* packet, uint8_t priority, uint32_t scheduled_for);
|
||||
int count() const { return _num; }
|
||||
mesh::Packet* itemAt(int i) const { return _table[i]; }
|
||||
mesh::Packet* removeByIdx(int i);
|
||||
};
|
||||
|
||||
class StaticPoolPacketManager : public mesh::PacketManager {
|
||||
PacketQueue unused, send_queue;
|
||||
|
||||
public:
|
||||
StaticPoolPacketManager(int pool_size);
|
||||
|
||||
mesh::Packet* allocNew() override;
|
||||
void free(mesh::Packet* packet) override;
|
||||
void queueOutbound(mesh::Packet* packet, uint8_t priority, uint32_t scheduled_for) override;
|
||||
mesh::Packet* getNextOutbound(uint32_t now) override;
|
||||
int getOutboundCount() const override;
|
||||
int getFreeCount() const override;
|
||||
mesh::Packet* getOutboundByIdx(int i) override;
|
||||
mesh::Packet* removeOutboundByIdx(int i) override;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue