kopia lustrzana https://github.com/meshtastic/firmware
				
				
				
			Merge branch 'master' into t-watch-fixes
						commit
						9a7777dbdb
					
				| 
						 | 
				
			
			@ -95,6 +95,7 @@ jobs:
 | 
			
		|||
          - board: tlora-t3s3-v1
 | 
			
		||||
          - board: t-watch-s3
 | 
			
		||||
          - board: t-deck
 | 
			
		||||
          - board: picomputer-s3
 | 
			
		||||
    uses: ./.github/workflows/build_esp32_s3.yml
 | 
			
		||||
    with:
 | 
			
		||||
      board: ${{ matrix.board }}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
version: 0.1
 | 
			
		||||
cli:
 | 
			
		||||
  version: 1.9.1
 | 
			
		||||
  version: 1.10.0
 | 
			
		||||
plugins:
 | 
			
		||||
  sources:
 | 
			
		||||
    - id: trunk
 | 
			
		||||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ lint:
 | 
			
		|||
  enabled:
 | 
			
		||||
    - taplo@0.7.0
 | 
			
		||||
    - ruff@0.0.265
 | 
			
		||||
    - yamllint@1.31.0
 | 
			
		||||
    - yamllint@1.32.0
 | 
			
		||||
    - isort@5.12.0
 | 
			
		||||
    - markdownlint@0.34.0
 | 
			
		||||
    - oxipng@8.0.0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,8 +28,6 @@
 | 
			
		|||
    "flash_size": "8MB",
 | 
			
		||||
    "maximum_ram_size": 327680,
 | 
			
		||||
    "maximum_size": 8388608,
 | 
			
		||||
    "use_1200bps_touch": true,
 | 
			
		||||
    "wait_for_upload_port": true,
 | 
			
		||||
    "require_upload_port": true,
 | 
			
		||||
    "speed": 921600
 | 
			
		||||
  },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1 @@
 | 
			
		|||
Subproject commit c5fa71fbb68b8d4044cb6a6d72f06257ac29dd9c
 | 
			
		||||
Subproject commit d47300965904a8d55d109327568e19a2eb9a12c0
 | 
			
		||||
| 
						 | 
				
			
			@ -108,10 +108,12 @@ class LGFX : public lgfx::LGFX_Device
 | 
			
		|||
    lgfx::Panel_ST7789 _panel_instance;
 | 
			
		||||
    lgfx::Bus_SPI _bus_instance;
 | 
			
		||||
    lgfx::Light_PWM _light_instance;
 | 
			
		||||
#if HAS_TOUCHSCREEN
 | 
			
		||||
#ifdef T_WATCH_S3
 | 
			
		||||
    lgfx::Touch_FT5x06 _touch_instance;
 | 
			
		||||
#else
 | 
			
		||||
    lgfx::Touch_GT911 _touch_instance;
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
| 
						 | 
				
			
			@ -126,13 +128,14 @@ class LGFX : public lgfx::LGFX_Device
 | 
			
		|||
            cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
 | 
			
		||||
                                            // 80MHz by an integer)
 | 
			
		||||
            cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
 | 
			
		||||
            cfg.spi_3wire = false;              // Set to true if reception is done on the MOSI pin
 | 
			
		||||
            cfg.use_lock = true;                // Set to true to use transaction locking
 | 
			
		||||
            cfg.dma_channel = SPI_DMA_CH_AUTO;  // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
 | 
			
		||||
            cfg.pin_sclk = ST7789_SCK;          // Set SPI SCLK pin number
 | 
			
		||||
            cfg.pin_mosi = ST7789_SDA;          // Set SPI MOSI pin number
 | 
			
		||||
            cfg.pin_miso = ST7789_MISO;         // Set SPI MISO pin number (-1 = disable)
 | 
			
		||||
            cfg.pin_dc = ST7789_RS;             // Set SPI DC pin number (-1 = disable)
 | 
			
		||||
            cfg.spi_3wire = false;
 | 
			
		||||
            cfg.use_lock = true;               // Set to true to use transaction locking
 | 
			
		||||
            cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
 | 
			
		||||
                                               // SPI_DMA_CH_AUTO=auto setting)
 | 
			
		||||
            cfg.pin_sclk = ST7789_SCK;         // Set SPI SCLK pin number
 | 
			
		||||
            cfg.pin_mosi = ST7789_SDA;         // Set SPI MOSI pin number
 | 
			
		||||
            cfg.pin_miso = ST7789_MISO;        // Set SPI MISO pin number (-1 = disable)
 | 
			
		||||
            cfg.pin_dc = ST7789_RS;            // Set SPI DC pin number (-1 = disable)
 | 
			
		||||
 | 
			
		||||
            _bus_instance.config(cfg);              // applies the set value to the bus.
 | 
			
		||||
            _panel_instance.setBus(&_bus_instance); // set the bus on the panel.
 | 
			
		||||
| 
						 | 
				
			
			@ -181,6 +184,7 @@ class LGFX : public lgfx::LGFX_Device
 | 
			
		|||
            _panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#if HAS_TOUCHSCREEN
 | 
			
		||||
        // Configure settings for touch screen control.
 | 
			
		||||
        {
 | 
			
		||||
            auto cfg = _touch_instance.config();
 | 
			
		||||
| 
						 | 
				
			
			@ -210,6 +214,7 @@ class LGFX : public lgfx::LGFX_Device
 | 
			
		|||
            _touch_instance.config(cfg);
 | 
			
		||||
            _panel_instance.setTouch(&_touch_instance);
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        setPanel(&_panel_instance); // Sets the panel to use.
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -434,7 +439,7 @@ bool TFTDisplay::connect()
 | 
			
		|||
    tft.init();
 | 
			
		||||
#if defined(M5STACK)
 | 
			
		||||
    tft.setRotation(0);
 | 
			
		||||
#elif defined(T_DECK)
 | 
			
		||||
#elif defined(T_DECK) || defined(PICOMPUTER_S3)
 | 
			
		||||
    tft.setRotation(1); // T-Deck has the TFT in landscape
 | 
			
		||||
#elif defined(T_WATCH_S3)
 | 
			
		||||
    tft.setRotation(2); // T-Watch S3 left-handed orientation
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,17 +28,6 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len
 | 
			
		|||
    return readflag;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Unused for now - flagging it off
 | 
			
		||||
#if 0
 | 
			
		||||
void write_to_14004(const TwoWire * i2cBus, uint8_t reg, uint8_t data)
 | 
			
		||||
{
 | 
			
		||||
    i2cBus->beginTransmission(CARDKB_ADDR);
 | 
			
		||||
    i2cBus->write(reg);
 | 
			
		||||
    i2cBus->write(data);
 | 
			
		||||
    i2cBus->endTransmission(); // stop transmitting
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int32_t KbI2cBase::runOnce()
 | 
			
		||||
{
 | 
			
		||||
    if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,131 @@
 | 
			
		|||
#include "kbMatrixBase.h"
 | 
			
		||||
#include "configuration.h"
 | 
			
		||||
 | 
			
		||||
#ifdef INPUTBROKER_MATRIX_TYPE
 | 
			
		||||
 | 
			
		||||
const byte keys_cols[] = KEYS_COLS;
 | 
			
		||||
const byte keys_rows[] = KEYS_ROWS;
 | 
			
		||||
 | 
			
		||||
#if INPUTBROKER_MATRIX_TYPE == 1
 | 
			
		||||
 | 
			
		||||
unsigned char KeyMap[3][sizeof(keys_rows)][sizeof(keys_cols)] = {{{' ', '.', 'm', 'n', 'b', 0xb6},
 | 
			
		||||
                                                                  {0x0d, 'l', 'k', 'j', 'h', 0xb4},
 | 
			
		||||
                                                                  {'p', 'o', 'i', 'u', 'y', 0xb5},
 | 
			
		||||
                                                                  {0x08, 'z', 'x', 'c', 'v', 0xb7},
 | 
			
		||||
                                                                  {'a', 's', 'd', 'f', 'g', 0x09},
 | 
			
		||||
                                                                  {'q', 'w', 'e', 'r', 't', 0x1a}},
 | 
			
		||||
                                                                 {// SHIFT
 | 
			
		||||
                                                                  {':', ';', 'M', 'N', 'B', 0xb6},
 | 
			
		||||
                                                                  {0x0d, 'L', 'K', 'J', 'H', 0xb4},
 | 
			
		||||
                                                                  {'P', 'O', 'I', 'U', 'Y', 0xb5},
 | 
			
		||||
                                                                  {0x08, 'Z', 'X', 'C', 'V', 0xb7},
 | 
			
		||||
                                                                  {'A', 'S', 'D', 'F', 'G', 0x09},
 | 
			
		||||
                                                                  {'Q', 'W', 'E', 'R', 'T', 0x1a}},
 | 
			
		||||
                                                                 {// SHIFT-SHIFT
 | 
			
		||||
                                                                  {'_', ',', '>', '<', '"', '{'},
 | 
			
		||||
                                                                  {'~', '-', '*', '&', '+', '['},
 | 
			
		||||
                                                                  {'0', '9', '8', '7', '6', '}'},
 | 
			
		||||
                                                                  {'=', '(', ')', '?', '/', ']'},
 | 
			
		||||
                                                                  {'!', '@', '#', '$', '%', '\\'},
 | 
			
		||||
                                                                  {'1', '2', '3', '4', '5', 0x1a}}};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
KbMatrixBase::KbMatrixBase(const char *name) : concurrency::OSThread(name)
 | 
			
		||||
{
 | 
			
		||||
    this->_originName = name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t KbMatrixBase::runOnce()
 | 
			
		||||
{
 | 
			
		||||
    if (!INPUTBROKER_MATRIX_TYPE) {
 | 
			
		||||
        // Input device is not requested.
 | 
			
		||||
        return disable();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (firstTime) {
 | 
			
		||||
        // This is the first time the OSThread library has called this function, so do port setup
 | 
			
		||||
        firstTime = 0;
 | 
			
		||||
        for (byte i = 0; i < sizeof(keys_rows); i++) {
 | 
			
		||||
            pinMode(keys_rows[i], OUTPUT);
 | 
			
		||||
            digitalWrite(keys_rows[i], HIGH);
 | 
			
		||||
        }
 | 
			
		||||
        for (byte i = 0; i < sizeof(keys_cols); i++) {
 | 
			
		||||
            pinMode(keys_cols[i], INPUT_PULLUP);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    key = 0;
 | 
			
		||||
 | 
			
		||||
    if (INPUTBROKER_MATRIX_TYPE == 1) {
 | 
			
		||||
        // scan for keypresses
 | 
			
		||||
        for (byte i = 0; i < sizeof(keys_rows); i++) {
 | 
			
		||||
            digitalWrite(keys_rows[i], LOW);
 | 
			
		||||
            for (byte j = 0; j < sizeof(keys_cols); j++) {
 | 
			
		||||
                if (digitalRead(keys_cols[j]) == LOW) {
 | 
			
		||||
                    key = KeyMap[shift][i][j];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            digitalWrite(keys_rows[i], HIGH);
 | 
			
		||||
        }
 | 
			
		||||
        // debounce
 | 
			
		||||
        if (key != prevkey) {
 | 
			
		||||
            if (key != 0) {
 | 
			
		||||
                LOG_DEBUG("Key 0x%x pressed\n", key);
 | 
			
		||||
                // reset shift now that we have a keypress
 | 
			
		||||
                InputEvent e;
 | 
			
		||||
                e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
 | 
			
		||||
                e.source = this->_originName;
 | 
			
		||||
                switch (key) {
 | 
			
		||||
                case 0x1b: // ESC
 | 
			
		||||
                    e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0x08: // Back
 | 
			
		||||
                    e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
 | 
			
		||||
                    e.kbchar = key;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0xb5: // Up
 | 
			
		||||
                    e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0xb6: // Down
 | 
			
		||||
                    e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0xb4: // Left
 | 
			
		||||
                    e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
 | 
			
		||||
                    e.kbchar = key;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0xb7: // Right
 | 
			
		||||
                    e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
 | 
			
		||||
                    e.kbchar = key;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0x0d: // Enter
 | 
			
		||||
                    e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0x00: // nopress
 | 
			
		||||
                    e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0x1a: // Shift
 | 
			
		||||
                    shift++;
 | 
			
		||||
                    if (shift > 2) {
 | 
			
		||||
                        shift = 0;
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                default: // all other keys
 | 
			
		||||
                    e.inputEvent = ANYKEY;
 | 
			
		||||
                    e.kbchar = key;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
 | 
			
		||||
                    this->notifyObservers(&e);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            prevkey = key;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        LOG_WARN("Unknown kb_model 0x%02x\n", INPUTBROKER_MATRIX_TYPE);
 | 
			
		||||
        return disable();
 | 
			
		||||
    }
 | 
			
		||||
    return 50; // Keyscan every 50msec to avoid key bounce
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // INPUTBROKER_MATRIX_TYPE
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "InputBroker.h"
 | 
			
		||||
#include "concurrency/OSThread.h"
 | 
			
		||||
 | 
			
		||||
class KbMatrixBase : public Observable<const InputEvent *>, public concurrency::OSThread
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    explicit KbMatrixBase(const char *name);
 | 
			
		||||
 | 
			
		||||
  protected:
 | 
			
		||||
    virtual int32_t runOnce() override;
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    const char *_originName;
 | 
			
		||||
    bool firstTime = 1;
 | 
			
		||||
    int shift = 0;
 | 
			
		||||
    char key = 0;
 | 
			
		||||
    char prevkey = 0;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
#include "kbMatrixImpl.h"
 | 
			
		||||
#include "InputBroker.h"
 | 
			
		||||
 | 
			
		||||
#ifdef INPUTBROKER_MATRIX_TYPE
 | 
			
		||||
 | 
			
		||||
KbMatrixImpl *kbMatrixImpl;
 | 
			
		||||
 | 
			
		||||
KbMatrixImpl::KbMatrixImpl() : KbMatrixBase("matrixKB") {}
 | 
			
		||||
 | 
			
		||||
void KbMatrixImpl::init()
 | 
			
		||||
{
 | 
			
		||||
    if (!INPUTBROKER_MATRIX_TYPE) {
 | 
			
		||||
        disable();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inputBroker->registerSource(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // INPUTBROKER_MATRIX_TYPE
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
#include "kbMatrixBase.h"
 | 
			
		||||
#include "main.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief The idea behind this class to have static methods for the event handlers.
 | 
			
		||||
 *      Check attachInterrupt() at RotaryEncoderInteruptBase.cpp
 | 
			
		||||
 *      Technically you can have as many rotary encoders hardver attached
 | 
			
		||||
 *      to your device as you wish, but you always need to have separate event
 | 
			
		||||
 *      handlers, thus you need to have a RotaryEncoderInterrupt implementation.
 | 
			
		||||
 */
 | 
			
		||||
class KbMatrixImpl : public KbMatrixBase
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    KbMatrixImpl();
 | 
			
		||||
    void init();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern KbMatrixImpl *kbMatrixImpl;
 | 
			
		||||
| 
						 | 
				
			
			@ -480,7 +480,7 @@ void setup()
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
    // We do this as early as possible because this loads preferences from flash
 | 
			
		||||
    // but we need to do this after main cpu iniot (esp32setup), because we need the random seed set
 | 
			
		||||
    // but we need to do this after main cpu init (esp32setup), because we need the random seed set
 | 
			
		||||
    nodeDB.init();
 | 
			
		||||
 | 
			
		||||
    // If we're taking on the repeater role, use flood router
 | 
			
		||||
| 
						 | 
				
			
			@ -545,6 +545,7 @@ void setup()
 | 
			
		|||
#else
 | 
			
		||||
    // ESP32
 | 
			
		||||
    SPI.begin(RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS);
 | 
			
		||||
    LOG_WARN("SPI.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)\n", RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS);
 | 
			
		||||
    SPI.setFrequency(4000000);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
 | 
			
		|||
{
 | 
			
		||||
    if (wasSeenRecently(p)) { // Note: this will also add a recent packet record
 | 
			
		||||
        printPacket("Ignoring incoming msg, because we've already seen it", p);
 | 
			
		||||
        if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER &&
 | 
			
		||||
        if (!moduleConfig.mqtt.enabled && config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER &&
 | 
			
		||||
            config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT &&
 | 
			
		||||
            config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
 | 
			
		||||
            // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater!
 | 
			
		||||
| 
						 | 
				
			
			@ -49,10 +49,13 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
 | 
			
		|||
 | 
			
		||||
                tosend->hop_limit--; // bump down the hop count
 | 
			
		||||
 | 
			
		||||
                // If it is a traceRoute request, update the route that it went via me
 | 
			
		||||
                if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && traceRouteModule &&
 | 
			
		||||
                    traceRouteModule->wantPacket(p)) {
 | 
			
		||||
                    traceRouteModule->updateRoute(tosend);
 | 
			
		||||
                if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
 | 
			
		||||
                    // If it is a traceRoute request, update the route that it went via me
 | 
			
		||||
                    if (traceRouteModule && traceRouteModule->wantPacket(p))
 | 
			
		||||
                        traceRouteModule->updateRoute(tosend);
 | 
			
		||||
                    // If it is a neighborInfo packet, update last_sent_by_id
 | 
			
		||||
                    if (neighborInfoModule && neighborInfoModule->wantPacket(p))
 | 
			
		||||
                        neighborInfoModule->updateLastSentById(tosend);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                LOG_INFO("Rebroadcasting received floodmsg to neighbors\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
 | 
			
		||||
#include "PacketHistory.h"
 | 
			
		||||
#include "Router.h"
 | 
			
		||||
#include "modules/NeighborInfoModule.h"
 | 
			
		||||
#include "modules/TraceRouteModule.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -57,4 +58,4 @@ class FloodingRouter : public Router, protected PacketHistory
 | 
			
		|||
     * Look for broadcasts we need to rebroadcast
 | 
			
		||||
     */
 | 
			
		||||
    virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override;
 | 
			
		||||
};
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -15,6 +15,7 @@
 | 
			
		|||
#include "error.h"
 | 
			
		||||
#include "main.h"
 | 
			
		||||
#include "mesh-pb-constants.h"
 | 
			
		||||
#include "modules/NeighborInfoModule.h"
 | 
			
		||||
#include <ErriezCRC32.h>
 | 
			
		||||
#include <pb_decode.h>
 | 
			
		||||
#include <pb_encode.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -63,11 +64,7 @@ uint32_t error_address = 0;
 | 
			
		|||
 | 
			
		||||
static uint8_t ourMacAddr[6];
 | 
			
		||||
 | 
			
		||||
NodeDB::NodeDB()
 | 
			
		||||
    : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count), meshNodes(devicestate.node_db_lite),
 | 
			
		||||
      numMeshNodes(&devicestate.node_db_lite_count)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
NodeDB::NodeDB() : meshNodes(devicestate.node_db_lite), numMeshNodes(&devicestate.node_db_lite_count) {}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on
 | 
			
		||||
| 
						 | 
				
			
			@ -248,6 +245,9 @@ void NodeDB::installDefaultModuleConfig()
 | 
			
		|||
    strncpy(moduleConfig.mqtt.username, default_mqtt_username, sizeof(moduleConfig.mqtt.username));
 | 
			
		||||
    strncpy(moduleConfig.mqtt.password, default_mqtt_password, sizeof(moduleConfig.mqtt.password));
 | 
			
		||||
 | 
			
		||||
    moduleConfig.has_neighbor_info = true;
 | 
			
		||||
    moduleConfig.neighbor_info.enabled = false;
 | 
			
		||||
 | 
			
		||||
    initModuleConfigIntervals();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -271,6 +271,7 @@ void NodeDB::initModuleConfigIntervals()
 | 
			
		|||
    moduleConfig.telemetry.device_update_interval = default_broadcast_interval_secs;
 | 
			
		||||
    moduleConfig.telemetry.environment_update_interval = default_broadcast_interval_secs;
 | 
			
		||||
    moduleConfig.telemetry.air_quality_interval = default_broadcast_interval_secs;
 | 
			
		||||
    moduleConfig.neighbor_info.update_interval = default_broadcast_interval_secs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NodeDB::installDefaultChannels()
 | 
			
		||||
| 
						 | 
				
			
			@ -282,12 +283,11 @@ void NodeDB::installDefaultChannels()
 | 
			
		|||
 | 
			
		||||
void NodeDB::resetNodes()
 | 
			
		||||
{
 | 
			
		||||
    devicestate.node_db_count = 0;
 | 
			
		||||
    memset(devicestate.node_db, 0, sizeof(devicestate.node_db));
 | 
			
		||||
 | 
			
		||||
    devicestate.node_db_lite_count = 0;
 | 
			
		||||
    memset(devicestate.node_db_lite, 0, sizeof(devicestate.node_db_lite));
 | 
			
		||||
    saveDeviceStateToDisk();
 | 
			
		||||
    if (neighborInfoModule && moduleConfig.neighbor_info.enabled)
 | 
			
		||||
        neighborInfoModule->resetNeighbors();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NodeDB::installDefaultDeviceState()
 | 
			
		||||
| 
						 | 
				
			
			@ -295,12 +295,11 @@ void NodeDB::installDefaultDeviceState()
 | 
			
		|||
    LOG_INFO("Installing default DeviceState\n");
 | 
			
		||||
    memset(&devicestate, 0, sizeof(meshtastic_DeviceState));
 | 
			
		||||
 | 
			
		||||
    *numNodes = 0;
 | 
			
		||||
    *numMeshNodes = 0;
 | 
			
		||||
 | 
			
		||||
    // init our devicestate with valid flags so protobuf writing/reading will work
 | 
			
		||||
    devicestate.has_my_node = true;
 | 
			
		||||
    devicestate.has_owner = true;
 | 
			
		||||
    devicestate.node_db_count = 0;
 | 
			
		||||
    devicestate.node_db_lite_count = 0;
 | 
			
		||||
    devicestate.version = DEVICESTATE_CUR_VER;
 | 
			
		||||
    devicestate.receive_queue_count = 0; // Not yet implemented FIXME
 | 
			
		||||
| 
						 | 
				
			
			@ -328,11 +327,9 @@ void NodeDB::init()
 | 
			
		|||
    int saveWhat = 0;
 | 
			
		||||
 | 
			
		||||
    // likewise - we always want the app requirements to come from the running appload
 | 
			
		||||
    myNodeInfo.min_app_version = 20300;         // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
 | 
			
		||||
    myNodeInfo.max_channels = MAX_NUM_CHANNELS; // tell others the max # of channels we can understand
 | 
			
		||||
    myNodeInfo.min_app_version = 30200; // format is Mmmss (where M is 1+the numeric major number. i.e. 30200 means 2.2.00
 | 
			
		||||
    // Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
 | 
			
		||||
    // keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
 | 
			
		||||
    strncpy(myNodeInfo.firmware_version, optstr(APP_VERSION), sizeof(myNodeInfo.firmware_version));
 | 
			
		||||
    pickNewNodeNum();
 | 
			
		||||
 | 
			
		||||
    // Set our board type so we can share it with others
 | 
			
		||||
| 
						 | 
				
			
			@ -343,19 +340,6 @@ void NodeDB::init()
 | 
			
		|||
    info->user = owner;
 | 
			
		||||
    info->has_user = true;
 | 
			
		||||
 | 
			
		||||
    if (*numNodes > 0) {
 | 
			
		||||
        LOG_DEBUG("Legacy NodeDB detected... Migrating to NodeDBLite\n");
 | 
			
		||||
        uint32_t readIndex = 0;
 | 
			
		||||
        const meshtastic_NodeInfo *oldNodeInfo = nodeDB.readNextNodeInfo(readIndex);
 | 
			
		||||
        while (oldNodeInfo != NULL) {
 | 
			
		||||
            migrateToNodeInfoLite(oldNodeInfo);
 | 
			
		||||
            oldNodeInfo = nodeDB.readNextNodeInfo(readIndex);
 | 
			
		||||
        }
 | 
			
		||||
        LOG_DEBUG("Migration complete! Clearing out legacy NodeDB...\n");
 | 
			
		||||
        devicestate.node_db_count = 0;
 | 
			
		||||
        memset(devicestate.node_db, 0, sizeof(devicestate.node_db));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef ARCH_ESP32
 | 
			
		||||
    Preferences preferences;
 | 
			
		||||
    preferences.begin("meshtastic", false);
 | 
			
		||||
| 
						 | 
				
			
			@ -365,7 +349,7 @@ void NodeDB::init()
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
    resetRadioConfig(); // If bogus settings got saved, then fix them
 | 
			
		||||
    LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d\n", config.lora.region, myNodeInfo.my_node_num, *numNodes);
 | 
			
		||||
    LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d\n", config.lora.region, myNodeInfo.my_node_num, *numMeshNodes);
 | 
			
		||||
 | 
			
		||||
    if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate)))
 | 
			
		||||
        saveWhat |= SEGMENT_DEVICESTATE;
 | 
			
		||||
| 
						 | 
				
			
			@ -611,14 +595,6 @@ void NodeDB::saveToDisk(int saveWhat)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const meshtastic_NodeInfo *NodeDB::readNextNodeInfo(uint32_t &readIndex)
 | 
			
		||||
{
 | 
			
		||||
    if (readIndex < *numNodes)
 | 
			
		||||
        return &nodes[readIndex++];
 | 
			
		||||
    else
 | 
			
		||||
        return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const meshtastic_NodeInfoLite *NodeDB::readNextMeshNode(uint32_t &readIndex)
 | 
			
		||||
{
 | 
			
		||||
    if (readIndex < *numMeshNodes)
 | 
			
		||||
| 
						 | 
				
			
			@ -796,17 +772,6 @@ uint8_t NodeDB::getMeshNodeChannel(NodeNum n)
 | 
			
		|||
    return info->channel;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Find a node in our DB, return null for missing
 | 
			
		||||
/// NOTE: This function might be called from an ISR
 | 
			
		||||
meshtastic_NodeInfo *NodeDB::getNodeInfo(NodeNum n)
 | 
			
		||||
{
 | 
			
		||||
    for (int i = 0; i < *numNodes; i++)
 | 
			
		||||
        if (nodes[i].num == n)
 | 
			
		||||
            return &nodes[i];
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Find a node in our DB, return null for missing
 | 
			
		||||
/// NOTE: This function might be called from an ISR
 | 
			
		||||
meshtastic_NodeInfoLite *NodeDB::getMeshNode(NodeNum n)
 | 
			
		||||
| 
						 | 
				
			
			@ -852,57 +817,6 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
 | 
			
		|||
    return lite;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NodeDB::migrateToNodeInfoLite(const meshtastic_NodeInfo *node)
 | 
			
		||||
{
 | 
			
		||||
    meshtastic_NodeInfoLite *lite = getMeshNode(node->num);
 | 
			
		||||
 | 
			
		||||
    if (!lite) {
 | 
			
		||||
        if ((*numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) {
 | 
			
		||||
            screen->print("warning: node_db_lite full! erasing oldest entry\n");
 | 
			
		||||
            // look for oldest node and erase it
 | 
			
		||||
            uint32_t oldest = UINT32_MAX;
 | 
			
		||||
            int oldestIndex = -1;
 | 
			
		||||
            for (int i = 0; i < *numMeshNodes; i++) {
 | 
			
		||||
                if (meshNodes[i].last_heard < oldest) {
 | 
			
		||||
                    oldest = meshNodes[i].last_heard;
 | 
			
		||||
                    oldestIndex = i;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // Shove the remaining nodes down the chain
 | 
			
		||||
            for (int i = oldestIndex; i < *numMeshNodes - 1; i++) {
 | 
			
		||||
                meshNodes[i] = meshNodes[i + 1];
 | 
			
		||||
            }
 | 
			
		||||
            (*numMeshNodes)--;
 | 
			
		||||
        }
 | 
			
		||||
        // add the node at the end
 | 
			
		||||
        lite = &meshNodes[(*numMeshNodes)++];
 | 
			
		||||
 | 
			
		||||
        // everything is missing except the nodenum
 | 
			
		||||
        memset(lite, 0, sizeof(*lite));
 | 
			
		||||
        lite->num = node->num;
 | 
			
		||||
        lite->snr = node->snr;
 | 
			
		||||
        lite->last_heard = node->last_heard;
 | 
			
		||||
        lite->channel = node->channel;
 | 
			
		||||
 | 
			
		||||
        if (node->has_position) {
 | 
			
		||||
            lite->has_position = true;
 | 
			
		||||
            lite->position.latitude_i = node->position.latitude_i;
 | 
			
		||||
            lite->position.longitude_i = node->position.longitude_i;
 | 
			
		||||
            lite->position.altitude = node->position.altitude;
 | 
			
		||||
            lite->position.location_source = node->position.location_source;
 | 
			
		||||
            lite->position.time = node->position.time;
 | 
			
		||||
        }
 | 
			
		||||
        if (node->has_user) {
 | 
			
		||||
            lite->has_user = true;
 | 
			
		||||
            lite->user = node->user;
 | 
			
		||||
        }
 | 
			
		||||
        if (node->has_device_metrics) {
 | 
			
		||||
            lite->has_device_metrics = true;
 | 
			
		||||
            lite->device_metrics = node->device_metrics;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Record an error that should be reported via analytics
 | 
			
		||||
void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, const char *filename)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ DeviceState versions used to be defined in the .proto file but really only this
 | 
			
		|||
#define SEGMENT_DEVICESTATE 4
 | 
			
		||||
#define SEGMENT_CHANNELS 8
 | 
			
		||||
 | 
			
		||||
#define DEVICESTATE_CUR_VER 20
 | 
			
		||||
#define DEVICESTATE_CUR_VER 22
 | 
			
		||||
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
 | 
			
		||||
 | 
			
		||||
extern meshtastic_DeviceState devicestate;
 | 
			
		||||
| 
						 | 
				
			
			@ -45,9 +45,6 @@ class NodeDB
 | 
			
		|||
    // Eventually use a smarter datastructure
 | 
			
		||||
    // HashMap<NodeNum, NodeInfo> nodes;
 | 
			
		||||
    // Note: these two references just point into our static array we serialize to/from disk
 | 
			
		||||
    meshtastic_NodeInfo *nodes;
 | 
			
		||||
    pb_size_t *numNodes;
 | 
			
		||||
 | 
			
		||||
    meshtastic_NodeInfoLite *meshNodes;
 | 
			
		||||
    pb_size_t *numMeshNodes;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -137,18 +134,6 @@ class NodeDB
 | 
			
		|||
  private:
 | 
			
		||||
    /// Find a node in our DB, create an empty NodeInfoLite if missing
 | 
			
		||||
    meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n);
 | 
			
		||||
    void migrateToNodeInfoLite(const meshtastic_NodeInfo *node);
 | 
			
		||||
    /// Find a node in our DB, return null for missing
 | 
			
		||||
    meshtastic_NodeInfo *getNodeInfo(NodeNum n);
 | 
			
		||||
    /// Allow the bluetooth layer to read our next nodeinfo record, or NULL if done reading
 | 
			
		||||
    const meshtastic_NodeInfo *readNextNodeInfo(uint32_t &readIndex);
 | 
			
		||||
    size_t getNumNodes() { return *numNodes; }
 | 
			
		||||
 | 
			
		||||
    meshtastic_NodeInfo *getNodeByIndex(size_t x)
 | 
			
		||||
    {
 | 
			
		||||
        assert(x < *numNodes);
 | 
			
		||||
        return &nodes[x];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Notify observers of changes to the DB
 | 
			
		||||
    void notifyObservers(bool forceUpdate = false)
 | 
			
		||||
| 
						 | 
				
			
			@ -226,10 +211,6 @@ inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t d
 | 
			
		|||
 | 
			
		||||
/// Sometimes we will have Position objects that only have a time, so check for
 | 
			
		||||
/// valid lat/lon
 | 
			
		||||
static inline bool hasValidPosition(const meshtastic_NodeInfo *n)
 | 
			
		||||
{
 | 
			
		||||
    return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
 | 
			
		||||
}
 | 
			
		||||
static inline bool hasValidPosition(const meshtastic_NodeInfoLite *n)
 | 
			
		||||
{
 | 
			
		||||
    return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -279,6 +279,10 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
 | 
			
		|||
            fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_remote_hardware_tag;
 | 
			
		||||
            fromRadioScratch.moduleConfig.payload_variant.remote_hardware = moduleConfig.remote_hardware;
 | 
			
		||||
            break;
 | 
			
		||||
        case meshtastic_ModuleConfig_neighbor_info_tag:
 | 
			
		||||
            fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_neighbor_info_tag;
 | 
			
		||||
            fromRadioScratch.moduleConfig.payload_variant.neighbor_info = moduleConfig.neighbor_info;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            LOG_ERROR("Unknown module config type %d\n", config_state);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,6 +55,8 @@ typedef enum _meshtastic_AdminMessage_ModuleConfigType {
 | 
			
		|||
    /* TODO: REPLACE */
 | 
			
		||||
    meshtastic_AdminMessage_ModuleConfigType_REMOTEHARDWARE_CONFIG = 8,
 | 
			
		||||
    /* TODO: REPLACE */
 | 
			
		||||
    meshtastic_AdminMessage_ModuleConfigType_NEIGHBORINFO_CONFIG = 9,
 | 
			
		||||
    /* TODO: REPLACE */
 | 
			
		||||
    meshtastic_AdminMessage_ModuleConfigType_AMBIENTLIGHTING_CONFIG = 10
 | 
			
		||||
} meshtastic_AdminMessage_ModuleConfigType;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
				
			
			@ -103,10 +103,12 @@ typedef enum _meshtastic_HardwareModel {
 | 
			
		|||
    meshtastic_HardwareModel_HELTEC_WIRELESS_TRACKER = 48,
 | 
			
		||||
    /* Heltec Wireless Paper with ESP32-S3 CPU and E-Ink display */
 | 
			
		||||
    meshtastic_HardwareModel_HELTEC_WIRELESS_PAPER = 49,
 | 
			
		||||
    /* LilyGo T-Deck with ESP32-S3 CPU, Keyboard, and IPS display */
 | 
			
		||||
    /* LilyGo T-Deck with ESP32-S3 CPU, Keyboard and IPS display */
 | 
			
		||||
    meshtastic_HardwareModel_T_DECK = 50,
 | 
			
		||||
    /* LilyGo T-Watch S3 with ESP32-S3 CPU and IPS display */
 | 
			
		||||
    meshtastic_HardwareModel_T_WATCH_S3 = 51,
 | 
			
		||||
    /* Bobricius Picomputer with ESP32-S3 CPU, Keyboard and IPS display */
 | 
			
		||||
    meshtastic_HardwareModel_PICOMPUTER_S3 = 52,
 | 
			
		||||
    /* ------------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
 | 
			
		||||
 ------------------------------------------------------------------------------------------------------------------------------------------ */
 | 
			
		||||
| 
						 | 
				
			
			@ -605,60 +607,12 @@ typedef struct _meshtastic_MyNodeInfo {
 | 
			
		|||
    /* Tells the phone what our node number is, default starting value is
 | 
			
		||||
 lowbyte of macaddr, but it will be fixed if that is already in use */
 | 
			
		||||
    uint32_t my_node_num;
 | 
			
		||||
    /* Deprecated in 2.1.x (Source from device_metadata)
 | 
			
		||||
 Note: This flag merely means we detected a hardware GPS in our node.
 | 
			
		||||
 Not the same as UserPreferences.location_sharing */
 | 
			
		||||
    bool has_gps;
 | 
			
		||||
    /* Deprecated in 2.1.x
 | 
			
		||||
 The maximum number of 'software' channels that can be set on this node. */
 | 
			
		||||
    uint32_t max_channels;
 | 
			
		||||
    /* Deprecated in 2.1.x (Source from device_metadata)
 | 
			
		||||
 0.0.5 etc... */
 | 
			
		||||
    char firmware_version[18];
 | 
			
		||||
    /* An error message we'd like to report back to the mothership through analytics.
 | 
			
		||||
 It indicates a serious bug occurred on the device, the device coped with it,
 | 
			
		||||
 but we still want to tell the devs about the bug.
 | 
			
		||||
 This field will be cleared after the phone reads MyNodeInfo
 | 
			
		||||
 (i.e. it will only be reported once)
 | 
			
		||||
 a numeric error code to go with error message, zero means no error */
 | 
			
		||||
    meshtastic_CriticalErrorCode error_code;
 | 
			
		||||
    /* A numeric error address (nonzero if available) */
 | 
			
		||||
    uint32_t error_address;
 | 
			
		||||
    /* The total number of errors this node has ever encountered
 | 
			
		||||
 (well - since the last time we discarded preferences) */
 | 
			
		||||
    uint32_t error_count;
 | 
			
		||||
    /* The total number of reboots this node has ever encountered
 | 
			
		||||
 (well - since the last time we discarded preferences) */
 | 
			
		||||
    uint32_t reboot_count;
 | 
			
		||||
    /* Deprecated in 2.1.x
 | 
			
		||||
 Calculated bitrate of the current channel (in Bytes Per Second) */
 | 
			
		||||
    float bitrate;
 | 
			
		||||
    /* Deprecated in 2.1.x
 | 
			
		||||
 How long before we consider a message abandoned and we can clear our
 | 
			
		||||
 caches of any messages in flight Normally quite large to handle the worst case
 | 
			
		||||
 message delivery time, 5 minutes.
 | 
			
		||||
 Formerly called FLOOD_EXPIRE_TIME in the device code */
 | 
			
		||||
    uint32_t message_timeout_msec;
 | 
			
		||||
    /* The minimum app version that can talk to this device.
 | 
			
		||||
 Phone/PC apps should compare this to their build number and if too low tell the user they must update their app */
 | 
			
		||||
    uint32_t min_app_version;
 | 
			
		||||
    /* Deprecated in 2.1.x (Only used on device to keep track of utilization)
 | 
			
		||||
 24 time windows of 1hr each with the airtime transmitted out of the device per hour. */
 | 
			
		||||
    pb_size_t air_period_tx_count;
 | 
			
		||||
    uint32_t air_period_tx[8];
 | 
			
		||||
    /* Deprecated in 2.1.x (Only used on device to keep track of utilization)
 | 
			
		||||
 24 time windows of 1hr each with the airtime of valid packets for your mesh. */
 | 
			
		||||
    pb_size_t air_period_rx_count;
 | 
			
		||||
    uint32_t air_period_rx[8];
 | 
			
		||||
    /* Deprecated in 2.1.x (Source from DeviceMetadata instead)
 | 
			
		||||
 Is the device wifi capable? */
 | 
			
		||||
    bool has_wifi;
 | 
			
		||||
    /* Deprecated in 2.1.x (Source from DeviceMetrics telemetry payloads)
 | 
			
		||||
 Utilization for the current channel, including well formed TX, RX and malformed RX (aka noise). */
 | 
			
		||||
    float channel_utilization;
 | 
			
		||||
    /* Deprecated in 2.1.x (Source from DeviceMetrics telemetry payloads)
 | 
			
		||||
 Percent of airtime for transmission used within the last hour. */
 | 
			
		||||
    float air_util_tx;
 | 
			
		||||
} meshtastic_MyNodeInfo;
 | 
			
		||||
 | 
			
		||||
/* Debug output from the device.
 | 
			
		||||
| 
						 | 
				
			
			@ -729,6 +683,12 @@ typedef struct _meshtastic_Neighbor {
 | 
			
		|||
    uint32_t node_id;
 | 
			
		||||
    /* SNR of last heard message */
 | 
			
		||||
    float snr;
 | 
			
		||||
    /* Reception time (in secs since 1970) of last message that was last sent by this ID.
 | 
			
		||||
 Note: this is for local storage only and will not be sent out over the mesh. */
 | 
			
		||||
    uint32_t last_rx_time;
 | 
			
		||||
    /* Broadcast interval of this neighbor (in seconds).
 | 
			
		||||
 Note: this is for local storage only and will not be sent out over the mesh. */
 | 
			
		||||
    uint32_t node_broadcast_interval_secs;
 | 
			
		||||
} meshtastic_Neighbor;
 | 
			
		||||
 | 
			
		||||
/* Full info on edges for a single node */
 | 
			
		||||
| 
						 | 
				
			
			@ -737,6 +697,8 @@ typedef struct _meshtastic_NeighborInfo {
 | 
			
		|||
    uint32_t node_id;
 | 
			
		||||
    /* Field to pass neighbor info for the next sending cycle */
 | 
			
		||||
    uint32_t last_sent_by_id;
 | 
			
		||||
    /* Broadcast interval of the represented node (in seconds) */
 | 
			
		||||
    uint32_t node_broadcast_interval_secs;
 | 
			
		||||
    /* The list of out edges from this node */
 | 
			
		||||
    pb_size_t neighbors_count;
 | 
			
		||||
    meshtastic_Neighbor neighbors[10];
 | 
			
		||||
| 
						 | 
				
			
			@ -871,7 +833,6 @@ extern "C" {
 | 
			
		|||
#define meshtastic_MeshPacket_delayed_ENUMTYPE meshtastic_MeshPacket_Delayed
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define meshtastic_MyNodeInfo_error_code_ENUMTYPE meshtastic_CriticalErrorCode
 | 
			
		||||
 | 
			
		||||
#define meshtastic_LogRecord_level_ENUMTYPE meshtastic_LogRecord_Level
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -896,14 +857,14 @@ extern "C" {
 | 
			
		|||
#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0}
 | 
			
		||||
#define meshtastic_MeshPacket_init_default       {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN}
 | 
			
		||||
#define meshtastic_NodeInfo_init_default         {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0}
 | 
			
		||||
#define meshtastic_MyNodeInfo_init_default       {0, 0, 0, "", _meshtastic_CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0}
 | 
			
		||||
#define meshtastic_MyNodeInfo_init_default       {0, 0, 0}
 | 
			
		||||
#define meshtastic_LogRecord_init_default        {"", 0, "", _meshtastic_LogRecord_Level_MIN}
 | 
			
		||||
#define meshtastic_QueueStatus_init_default      {0, 0, 0, 0}
 | 
			
		||||
#define meshtastic_FromRadio_init_default        {0, 0, {meshtastic_MeshPacket_init_default}}
 | 
			
		||||
#define meshtastic_ToRadio_init_default          {0, {meshtastic_MeshPacket_init_default}}
 | 
			
		||||
#define meshtastic_Compressed_init_default       {_meshtastic_PortNum_MIN, {0, {0}}}
 | 
			
		||||
#define meshtastic_NeighborInfo_init_default     {0, 0, 0, {meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default}}
 | 
			
		||||
#define meshtastic_Neighbor_init_default         {0, 0}
 | 
			
		||||
#define meshtastic_NeighborInfo_init_default     {0, 0, 0, 0, {meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default}}
 | 
			
		||||
#define meshtastic_Neighbor_init_default         {0, 0, 0, 0}
 | 
			
		||||
#define meshtastic_DeviceMetadata_init_default   {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0}
 | 
			
		||||
#define meshtastic_Position_init_zero            {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
 | 
			
		||||
#define meshtastic_User_init_zero                {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0}
 | 
			
		||||
| 
						 | 
				
			
			@ -914,14 +875,14 @@ extern "C" {
 | 
			
		|||
#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0}
 | 
			
		||||
#define meshtastic_MeshPacket_init_zero          {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN}
 | 
			
		||||
#define meshtastic_NodeInfo_init_zero            {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0}
 | 
			
		||||
#define meshtastic_MyNodeInfo_init_zero          {0, 0, 0, "", _meshtastic_CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0}
 | 
			
		||||
#define meshtastic_MyNodeInfo_init_zero          {0, 0, 0}
 | 
			
		||||
#define meshtastic_LogRecord_init_zero           {"", 0, "", _meshtastic_LogRecord_Level_MIN}
 | 
			
		||||
#define meshtastic_QueueStatus_init_zero         {0, 0, 0, 0}
 | 
			
		||||
#define meshtastic_FromRadio_init_zero           {0, 0, {meshtastic_MeshPacket_init_zero}}
 | 
			
		||||
#define meshtastic_ToRadio_init_zero             {0, {meshtastic_MeshPacket_init_zero}}
 | 
			
		||||
#define meshtastic_Compressed_init_zero          {_meshtastic_PortNum_MIN, {0, {0}}}
 | 
			
		||||
#define meshtastic_NeighborInfo_init_zero        {0, 0, 0, {meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero}}
 | 
			
		||||
#define meshtastic_Neighbor_init_zero            {0, 0}
 | 
			
		||||
#define meshtastic_NeighborInfo_init_zero        {0, 0, 0, 0, {meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero}}
 | 
			
		||||
#define meshtastic_Neighbor_init_zero            {0, 0, 0, 0}
 | 
			
		||||
#define meshtastic_DeviceMetadata_init_zero      {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0}
 | 
			
		||||
 | 
			
		||||
/* Field tags (for use in manual encoding/decoding) */
 | 
			
		||||
| 
						 | 
				
			
			@ -998,21 +959,8 @@ extern "C" {
 | 
			
		|||
#define meshtastic_NodeInfo_device_metrics_tag   6
 | 
			
		||||
#define meshtastic_NodeInfo_channel_tag          7
 | 
			
		||||
#define meshtastic_MyNodeInfo_my_node_num_tag    1
 | 
			
		||||
#define meshtastic_MyNodeInfo_has_gps_tag        2
 | 
			
		||||
#define meshtastic_MyNodeInfo_max_channels_tag   3
 | 
			
		||||
#define meshtastic_MyNodeInfo_firmware_version_tag 4
 | 
			
		||||
#define meshtastic_MyNodeInfo_error_code_tag     5
 | 
			
		||||
#define meshtastic_MyNodeInfo_error_address_tag  6
 | 
			
		||||
#define meshtastic_MyNodeInfo_error_count_tag    7
 | 
			
		||||
#define meshtastic_MyNodeInfo_reboot_count_tag   8
 | 
			
		||||
#define meshtastic_MyNodeInfo_bitrate_tag        9
 | 
			
		||||
#define meshtastic_MyNodeInfo_message_timeout_msec_tag 10
 | 
			
		||||
#define meshtastic_MyNodeInfo_min_app_version_tag 11
 | 
			
		||||
#define meshtastic_MyNodeInfo_air_period_tx_tag  12
 | 
			
		||||
#define meshtastic_MyNodeInfo_air_period_rx_tag  13
 | 
			
		||||
#define meshtastic_MyNodeInfo_has_wifi_tag       14
 | 
			
		||||
#define meshtastic_MyNodeInfo_channel_utilization_tag 15
 | 
			
		||||
#define meshtastic_MyNodeInfo_air_util_tx_tag    16
 | 
			
		||||
#define meshtastic_LogRecord_message_tag         1
 | 
			
		||||
#define meshtastic_LogRecord_time_tag            2
 | 
			
		||||
#define meshtastic_LogRecord_source_tag          3
 | 
			
		||||
| 
						 | 
				
			
			@ -1030,9 +978,12 @@ extern "C" {
 | 
			
		|||
#define meshtastic_Compressed_data_tag           2
 | 
			
		||||
#define meshtastic_Neighbor_node_id_tag          1
 | 
			
		||||
#define meshtastic_Neighbor_snr_tag              2
 | 
			
		||||
#define meshtastic_Neighbor_last_rx_time_tag     3
 | 
			
		||||
#define meshtastic_Neighbor_node_broadcast_interval_secs_tag 4
 | 
			
		||||
#define meshtastic_NeighborInfo_node_id_tag      1
 | 
			
		||||
#define meshtastic_NeighborInfo_last_sent_by_id_tag 2
 | 
			
		||||
#define meshtastic_NeighborInfo_neighbors_tag    3
 | 
			
		||||
#define meshtastic_NeighborInfo_node_broadcast_interval_secs_tag 3
 | 
			
		||||
#define meshtastic_NeighborInfo_neighbors_tag    4
 | 
			
		||||
#define meshtastic_DeviceMetadata_firmware_version_tag 1
 | 
			
		||||
#define meshtastic_DeviceMetadata_device_state_version_tag 2
 | 
			
		||||
#define meshtastic_DeviceMetadata_canShutdown_tag 3
 | 
			
		||||
| 
						 | 
				
			
			@ -1175,21 +1126,8 @@ X(a, STATIC,   SINGULAR, UINT32,   channel,           7)
 | 
			
		|||
 | 
			
		||||
#define meshtastic_MyNodeInfo_FIELDLIST(X, a) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, UINT32,   my_node_num,       1) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, BOOL,     has_gps,           2) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, UINT32,   max_channels,      3) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, STRING,   firmware_version,   4) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, UENUM,    error_code,        5) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, UINT32,   error_address,     6) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, UINT32,   error_count,       7) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, UINT32,   reboot_count,      8) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, FLOAT,    bitrate,           9) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, UINT32,   message_timeout_msec,  10) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, UINT32,   min_app_version,  11) \
 | 
			
		||||
X(a, STATIC,   REPEATED, UINT32,   air_period_tx,    12) \
 | 
			
		||||
X(a, STATIC,   REPEATED, UINT32,   air_period_rx,    13) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, BOOL,     has_wifi,         14) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, FLOAT,    channel_utilization,  15) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, FLOAT,    air_util_tx,      16)
 | 
			
		||||
X(a, STATIC,   SINGULAR, UINT32,   min_app_version,  11)
 | 
			
		||||
#define meshtastic_MyNodeInfo_CALLBACK NULL
 | 
			
		||||
#define meshtastic_MyNodeInfo_DEFAULT NULL
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1259,14 +1197,17 @@ X(a, STATIC,   SINGULAR, BYTES,    data,              2)
 | 
			
		|||
#define meshtastic_NeighborInfo_FIELDLIST(X, a) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, UINT32,   node_id,           1) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, UINT32,   last_sent_by_id,   2) \
 | 
			
		||||
X(a, STATIC,   REPEATED, MESSAGE,  neighbors,         3)
 | 
			
		||||
X(a, STATIC,   SINGULAR, UINT32,   node_broadcast_interval_secs,   3) \
 | 
			
		||||
X(a, STATIC,   REPEATED, MESSAGE,  neighbors,         4)
 | 
			
		||||
#define meshtastic_NeighborInfo_CALLBACK NULL
 | 
			
		||||
#define meshtastic_NeighborInfo_DEFAULT NULL
 | 
			
		||||
#define meshtastic_NeighborInfo_neighbors_MSGTYPE meshtastic_Neighbor
 | 
			
		||||
 | 
			
		||||
#define meshtastic_Neighbor_FIELDLIST(X, a) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, UINT32,   node_id,           1) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, FLOAT,    snr,               2)
 | 
			
		||||
X(a, STATIC,   SINGULAR, FLOAT,    snr,               2) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, FIXED32,  last_rx_time,      3) \
 | 
			
		||||
X(a, STATIC,   SINGULAR, UINT32,   node_broadcast_interval_secs,   4)
 | 
			
		||||
#define meshtastic_Neighbor_CALLBACK NULL
 | 
			
		||||
#define meshtastic_Neighbor_DEFAULT NULL
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1331,9 +1272,9 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
 | 
			
		|||
#define meshtastic_LogRecord_size                81
 | 
			
		||||
#define meshtastic_MeshPacket_size               321
 | 
			
		||||
#define meshtastic_MqttClientProxyMessage_size   501
 | 
			
		||||
#define meshtastic_MyNodeInfo_size               179
 | 
			
		||||
#define meshtastic_NeighborInfo_size             142
 | 
			
		||||
#define meshtastic_Neighbor_size                 11
 | 
			
		||||
#define meshtastic_MyNodeInfo_size               18
 | 
			
		||||
#define meshtastic_NeighborInfo_size             258
 | 
			
		||||
#define meshtastic_Neighbor_size                 22
 | 
			
		||||
#define meshtastic_NodeInfo_size                 261
 | 
			
		||||
#define meshtastic_Position_size                 137
 | 
			
		||||
#define meshtastic_QueueStatus_size              23
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,73 +25,99 @@
 | 
			
		|||
typedef enum _meshtastic_PortNum {
 | 
			
		||||
    /* Deprecated: do not use in new code (formerly called OPAQUE)
 | 
			
		||||
 A message sent from a device outside of the mesh, in a form the mesh does not understand
 | 
			
		||||
 NOTE: This must be 0, because it is documented in IMeshService.aidl to be so */
 | 
			
		||||
 NOTE: This must be 0, because it is documented in IMeshService.aidl to be so
 | 
			
		||||
 ENCODING: binary undefined */
 | 
			
		||||
    meshtastic_PortNum_UNKNOWN_APP = 0,
 | 
			
		||||
    /* A simple UTF-8 text message, which even the little micros in the mesh
 | 
			
		||||
 can understand and show on their screen eventually in some circumstances
 | 
			
		||||
 even signal might send messages in this form (see below) */
 | 
			
		||||
 even signal might send messages in this form (see below)
 | 
			
		||||
 ENCODING: UTF-8 Plaintext (?) */
 | 
			
		||||
    meshtastic_PortNum_TEXT_MESSAGE_APP = 1,
 | 
			
		||||
    /* Reserved for built-in GPIO/example app.
 | 
			
		||||
 See remote_hardware.proto/HardwareMessage for details on the message sent/received to this port number */
 | 
			
		||||
 See remote_hardware.proto/HardwareMessage for details on the message sent/received to this port number
 | 
			
		||||
 ENCODING: Protobuf */
 | 
			
		||||
    meshtastic_PortNum_REMOTE_HARDWARE_APP = 2,
 | 
			
		||||
    /* The built-in position messaging app.
 | 
			
		||||
 Payload is a [Position](/docs/developers/protobufs/api#position) message */
 | 
			
		||||
 Payload is a [Position](/docs/developers/protobufs/api#position) message
 | 
			
		||||
 ENCODING: Protobuf */
 | 
			
		||||
    meshtastic_PortNum_POSITION_APP = 3,
 | 
			
		||||
    /* The built-in user info app.
 | 
			
		||||
 Payload is a [User](/docs/developers/protobufs/api#user) message */
 | 
			
		||||
 Payload is a [User](/docs/developers/protobufs/api#user) message
 | 
			
		||||
 ENCODING: Protobuf */
 | 
			
		||||
    meshtastic_PortNum_NODEINFO_APP = 4,
 | 
			
		||||
    /* Protocol control packets for mesh protocol use.
 | 
			
		||||
 Payload is a [Routing](/docs/developers/protobufs/api#routing) message */
 | 
			
		||||
 Payload is a [Routing](/docs/developers/protobufs/api#routing) message
 | 
			
		||||
 ENCODING: Protobuf */
 | 
			
		||||
    meshtastic_PortNum_ROUTING_APP = 5,
 | 
			
		||||
    /* Admin control packets.
 | 
			
		||||
 Payload is a [AdminMessage](/docs/developers/protobufs/api#adminmessage) message */
 | 
			
		||||
 Payload is a [AdminMessage](/docs/developers/protobufs/api#adminmessage) message
 | 
			
		||||
 ENCODING: Protobuf */
 | 
			
		||||
    meshtastic_PortNum_ADMIN_APP = 6,
 | 
			
		||||
    /* Compressed TEXT_MESSAGE payloads. */
 | 
			
		||||
    /* Compressed TEXT_MESSAGE payloads.
 | 
			
		||||
 ENCODING: UTF-8 Plaintext (?) with Unishox2 Compression
 | 
			
		||||
 NOTE: The Device Firmware converts a TEXT_MESSAGE_APP to TEXT_MESSAGE_COMPRESSED_APP if the compressed
 | 
			
		||||
 payload is shorter. There's no need for app developers to do this themselves. Also the firmware will decompress
 | 
			
		||||
 any incoming TEXT_MESSAGE_COMPRESSED_APP payload and convert to TEXT_MESSAGE_APP. */
 | 
			
		||||
    meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP = 7,
 | 
			
		||||
    /* Waypoint payloads.
 | 
			
		||||
 Payload is a [Waypoint](/docs/developers/protobufs/api#waypoint) message */
 | 
			
		||||
 Payload is a [Waypoint](/docs/developers/protobufs/api#waypoint) message
 | 
			
		||||
 ENCODING: Protobuf */
 | 
			
		||||
    meshtastic_PortNum_WAYPOINT_APP = 8,
 | 
			
		||||
    /* Audio Payloads.
 | 
			
		||||
 Encapsulated codec2 packets. On 2.4 GHZ Bandwidths only for now */
 | 
			
		||||
 Encapsulated codec2 packets. On 2.4 GHZ Bandwidths only for now
 | 
			
		||||
 ENCODING: codec2 audio frames
 | 
			
		||||
 NOTE: audio frames contain a 3 byte header (0xc0 0xde 0xc2) and a one byte marker for the decompressed bitrate.
 | 
			
		||||
 This marker comes from the 'moduleConfig.audio.bitrate' enum minus one. */
 | 
			
		||||
    meshtastic_PortNum_AUDIO_APP = 9,
 | 
			
		||||
    /* Provides a 'ping' service that replies to any packet it receives.
 | 
			
		||||
 Also serves as a small example module. */
 | 
			
		||||
 Also serves as a small example module.
 | 
			
		||||
 ENCODING: ASCII Plaintext */
 | 
			
		||||
    meshtastic_PortNum_REPLY_APP = 32,
 | 
			
		||||
    /* Used for the python IP tunnel feature */
 | 
			
		||||
    /* Used for the python IP tunnel feature
 | 
			
		||||
 ENCODING: IP Packet. Handled by the python API, firmware ignores this one and pases on. */
 | 
			
		||||
    meshtastic_PortNum_IP_TUNNEL_APP = 33,
 | 
			
		||||
    /* Provides a hardware serial interface to send and receive from the Meshtastic network.
 | 
			
		||||
 Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic
 | 
			
		||||
 network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network.
 | 
			
		||||
 Maximum packet size of 240 bytes.
 | 
			
		||||
 Module is disabled by default can be turned on by setting SERIAL_MODULE_ENABLED = 1 in SerialPlugh.cpp. */
 | 
			
		||||
 Module is disabled by default can be turned on by setting SERIAL_MODULE_ENABLED = 1 in SerialPlugh.cpp.
 | 
			
		||||
 ENCODING: binary undefined */
 | 
			
		||||
    meshtastic_PortNum_SERIAL_APP = 64,
 | 
			
		||||
    /* STORE_FORWARD_APP (Work in Progress)
 | 
			
		||||
 Maintained by Jm Casler (MC Hamster) : jm@casler.org */
 | 
			
		||||
 Maintained by Jm Casler (MC Hamster) : jm@casler.org
 | 
			
		||||
 ENCODING: Protobuf */
 | 
			
		||||
    meshtastic_PortNum_STORE_FORWARD_APP = 65,
 | 
			
		||||
    /* Optional port for messages for the range test module. */
 | 
			
		||||
    /* Optional port for messages for the range test module.
 | 
			
		||||
 ENCODING: ASCII Plaintext */
 | 
			
		||||
    meshtastic_PortNum_RANGE_TEST_APP = 66,
 | 
			
		||||
    /* Provides a format to send and receive telemetry data from the Meshtastic network.
 | 
			
		||||
 Maintained by Charles Crossan (crossan007) : crossan007@gmail.com */
 | 
			
		||||
 Maintained by Charles Crossan (crossan007) : crossan007@gmail.com
 | 
			
		||||
 ENCODING: Protobuf */
 | 
			
		||||
    meshtastic_PortNum_TELEMETRY_APP = 67,
 | 
			
		||||
    /* Experimental tools for estimating node position without a GPS
 | 
			
		||||
 Maintained by Github user a-f-G-U-C (a Meshtastic contributor)
 | 
			
		||||
 Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS */
 | 
			
		||||
 Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS
 | 
			
		||||
 ENCODING: arrays of int64 fields */
 | 
			
		||||
    meshtastic_PortNum_ZPS_APP = 68,
 | 
			
		||||
    /* Used to let multiple instances of Linux native applications communicate
 | 
			
		||||
 as if they did using their LoRa chip.
 | 
			
		||||
 Maintained by GitHub user GUVWAF.
 | 
			
		||||
 Project files at https://github.com/GUVWAF/Meshtasticator */
 | 
			
		||||
 Project files at https://github.com/GUVWAF/Meshtasticator
 | 
			
		||||
 ENCODING: Protobuf (?) */
 | 
			
		||||
    meshtastic_PortNum_SIMULATOR_APP = 69,
 | 
			
		||||
    /* Provides a traceroute functionality to show the route a packet towards
 | 
			
		||||
 a certain destination would take on the mesh. */
 | 
			
		||||
 a certain destination would take on the mesh.
 | 
			
		||||
 ENCODING: Protobuf */
 | 
			
		||||
    meshtastic_PortNum_TRACEROUTE_APP = 70,
 | 
			
		||||
    /* Aggregates edge info for the network by sending out a list of each node's neighbors */
 | 
			
		||||
    /* Aggregates edge info for the network by sending out a list of each node's neighbors
 | 
			
		||||
 ENCODING: Protobuf */
 | 
			
		||||
    meshtastic_PortNum_NEIGHBORINFO_APP = 71,
 | 
			
		||||
    /* Private applications should use portnums >= 256.
 | 
			
		||||
 To simplify initial development and testing you can use "PRIVATE_APP"
 | 
			
		||||
 in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) */
 | 
			
		||||
    meshtastic_PortNum_PRIVATE_APP = 256,
 | 
			
		||||
    /* ATAK Forwarder Module https://github.com/paulmandal/atak-forwarder */
 | 
			
		||||
    /* ATAK Forwarder Module https://github.com/paulmandal/atak-forwarder
 | 
			
		||||
 ENCODING: libcotshrink */
 | 
			
		||||
    meshtastic_PortNum_ATAK_FORWARDER = 257,
 | 
			
		||||
    /* Currently we limit port nums to no higher than this value */
 | 
			
		||||
    meshtastic_PortNum_MAX = 511
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@
 | 
			
		|||
#define MAX_RX_TOPHONE 32
 | 
			
		||||
 | 
			
		||||
/// max number of nodes allowed in the mesh
 | 
			
		||||
#define MAX_NUM_NODES (member_size(meshtastic_DeviceState, node_db) / member_size(meshtastic_DeviceState, node_db[0]))
 | 
			
		||||
#define MAX_NUM_NODES (member_size(meshtastic_DeviceState, node_db_lite) / member_size(meshtastic_DeviceState, node_db_lite[0]))
 | 
			
		||||
 | 
			
		||||
/// Max number of channels allowed
 | 
			
		||||
#define MAX_NUM_CHANNELS (member_size(meshtastic_ChannelFile, channels) / member_size(meshtastic_ChannelFile, channels[0]))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -368,6 +368,11 @@ void AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
 | 
			
		|||
        moduleConfig.has_remote_hardware = true;
 | 
			
		||||
        moduleConfig.remote_hardware = c.payload_variant.remote_hardware;
 | 
			
		||||
        break;
 | 
			
		||||
    case meshtastic_ModuleConfig_neighbor_info_tag:
 | 
			
		||||
        LOG_INFO("Setting module config: Neighbor Info\n");
 | 
			
		||||
        moduleConfig.has_neighbor_info = true;
 | 
			
		||||
        moduleConfig.neighbor_info = c.payload_variant.neighbor_info;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    saveChanges(SEGMENT_MODULECONFIG);
 | 
			
		||||
| 
						 | 
				
			
			@ -503,6 +508,11 @@ void AdminModule::handleGetModuleConfig(const meshtastic_MeshPacket &req, const
 | 
			
		|||
            res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_remote_hardware_tag;
 | 
			
		||||
            res.get_module_config_response.payload_variant.remote_hardware = moduleConfig.remote_hardware;
 | 
			
		||||
            break;
 | 
			
		||||
        case meshtastic_AdminMessage_ModuleConfigType_NEIGHBORINFO_CONFIG:
 | 
			
		||||
            LOG_INFO("Getting module config: Neighbor Info\n");
 | 
			
		||||
            res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_neighbor_info_tag;
 | 
			
		||||
            res.get_module_config_response.payload_variant.neighbor_info = moduleConfig.neighbor_info;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // NOTE: The phone app needs to know the ls_secsvalue so it can properly expect sleep behavior.
 | 
			
		||||
| 
						 | 
				
			
			@ -663,4 +673,4 @@ AdminModule::AdminModule() : ProtobufModule("Admin", meshtastic_PortNum_ADMIN_AP
 | 
			
		|||
{
 | 
			
		||||
    // restrict to the admin channel for rx
 | 
			
		||||
    boundChannel = Channels::adminChannel;
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -10,6 +10,10 @@
 | 
			
		|||
 | 
			
		||||
#include "main.h" // for cardkb_found
 | 
			
		||||
 | 
			
		||||
#ifndef INPUTBROKER_MATRIX_TYPE
 | 
			
		||||
#define INPUTBROKER_MATRIX_TYPE 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef OLED_RU
 | 
			
		||||
#include "graphics/fonts/OLEDDisplayFontsRU.h"
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +66,7 @@ CannedMessageModule::CannedMessageModule()
 | 
			
		|||
    if (moduleConfig.canned_message.enabled) {
 | 
			
		||||
        this->loadProtoForModule();
 | 
			
		||||
        if ((this->splitConfiguredMessages() <= 0) && (cardkb_found.address != CARDKB_ADDR) &&
 | 
			
		||||
            (cardkb_found.address != TDECK_KB_ADDR)) {
 | 
			
		||||
            (cardkb_found.address != TDECK_KB_ADDR) && !INPUTBROKER_MATRIX_TYPE) {
 | 
			
		||||
            LOG_INFO("CannedMessageModule: No messages are configured. Module is disabled\n");
 | 
			
		||||
            this->runState = CANNED_MESSAGE_RUN_STATE_DISABLED;
 | 
			
		||||
            disable();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,8 +4,10 @@
 | 
			
		|||
#include "input/TrackballInterruptImpl1.h"
 | 
			
		||||
#include "input/UpDownInterruptImpl1.h"
 | 
			
		||||
#include "input/cardKbI2cImpl.h"
 | 
			
		||||
#include "input/kbMatrixImpl.h"
 | 
			
		||||
#include "modules/AdminModule.h"
 | 
			
		||||
#include "modules/CannedMessageModule.h"
 | 
			
		||||
#include "modules/NeighborInfoModule.h"
 | 
			
		||||
#include "modules/NodeInfoModule.h"
 | 
			
		||||
#include "modules/PositionModule.h"
 | 
			
		||||
#include "modules/RemoteHardwareModule.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +49,7 @@ void setupModules()
 | 
			
		|||
        waypointModule = new WaypointModule();
 | 
			
		||||
        textMessageModule = new TextMessageModule();
 | 
			
		||||
        traceRouteModule = new TraceRouteModule();
 | 
			
		||||
        neighborInfoModule = new NeighborInfoModule();
 | 
			
		||||
 | 
			
		||||
        // Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance
 | 
			
		||||
        // to a global variable.
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +63,11 @@ void setupModules()
 | 
			
		|||
        upDownInterruptImpl1->init();
 | 
			
		||||
        cardKbI2cImpl = new CardKbI2cImpl();
 | 
			
		||||
        cardKbI2cImpl->init();
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef INPUTBROKER_MATRIX_TYPE
 | 
			
		||||
        kbMatrixImpl = new KbMatrixImpl();
 | 
			
		||||
        kbMatrixImpl->init();
 | 
			
		||||
#endif // INPUTBROKER_MATRIX_TYPE
 | 
			
		||||
#endif // HAS_BUTTON
 | 
			
		||||
#if HAS_TRACKBALL
 | 
			
		||||
        trackballInterruptImpl1 = new TrackballInterruptImpl1();
 | 
			
		||||
        trackballInterruptImpl1->init();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,319 @@
 | 
			
		|||
#include "NeighborInfoModule.h"
 | 
			
		||||
#include "MeshService.h"
 | 
			
		||||
#include "NodeDB.h"
 | 
			
		||||
#include "RTC.h"
 | 
			
		||||
 | 
			
		||||
#define MAX_NUM_NEIGHBORS 10 // also defined in NeighborInfo protobuf options
 | 
			
		||||
NeighborInfoModule *neighborInfoModule;
 | 
			
		||||
 | 
			
		||||
static const char *neighborInfoConfigFile = "/prefs/neighbors.proto";
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Prints a single neighbor info packet and associated neighbors
 | 
			
		||||
Uses LOG_DEBUG, which equates to Console.log
 | 
			
		||||
NOTE: For debugging only
 | 
			
		||||
*/
 | 
			
		||||
void NeighborInfoModule::printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np)
 | 
			
		||||
{
 | 
			
		||||
    LOG_DEBUG("%s NEIGHBORINFO PACKET from Node %d to Node %d (last sent by %d)\n", header, np->node_id, nodeDB.getNodeNum(),
 | 
			
		||||
              np->last_sent_by_id);
 | 
			
		||||
    LOG_DEBUG("----------------\n");
 | 
			
		||||
    LOG_DEBUG("Packet contains %d neighbors\n", np->neighbors_count);
 | 
			
		||||
    for (int i = 0; i < np->neighbors_count; i++) {
 | 
			
		||||
        LOG_DEBUG("Neighbor %d: node_id=%d, snr=%.2f\n", i, np->neighbors[i].node_id, np->neighbors[i].snr);
 | 
			
		||||
    }
 | 
			
		||||
    LOG_DEBUG("----------------\n");
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
Prints the nodeDB nodes so we can see whose nodeInfo we have
 | 
			
		||||
NOTE: for debugging only
 | 
			
		||||
*/
 | 
			
		||||
void NeighborInfoModule::printNodeDBNodes(const char *header)
 | 
			
		||||
{
 | 
			
		||||
    int num_nodes = nodeDB.getNumMeshNodes();
 | 
			
		||||
    LOG_DEBUG("%s NODEDB SELECTION from Node %d:\n", header, nodeDB.getNodeNum());
 | 
			
		||||
    LOG_DEBUG("----------------\n");
 | 
			
		||||
    LOG_DEBUG("DB contains %d nodes\n", num_nodes);
 | 
			
		||||
    for (int i = 0; i < num_nodes; i++) {
 | 
			
		||||
        meshtastic_NodeInfoLite *dbEntry = nodeDB.getMeshNodeByIndex(i);
 | 
			
		||||
        LOG_DEBUG("     Node %d: node_id=%d, snr=%.2f\n", i, dbEntry->num, dbEntry->snr);
 | 
			
		||||
    }
 | 
			
		||||
    LOG_DEBUG("----------------\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Prints the nodeDB neighbors
 | 
			
		||||
NOTE: for debugging only
 | 
			
		||||
*/
 | 
			
		||||
void NeighborInfoModule::printNodeDBNeighbors(const char *header)
 | 
			
		||||
{
 | 
			
		||||
    int num_neighbors = getNumNeighbors();
 | 
			
		||||
    LOG_DEBUG("%s NODEDB SELECTION from Node %d:\n", header, nodeDB.getNodeNum());
 | 
			
		||||
    LOG_DEBUG("----------------\n");
 | 
			
		||||
    LOG_DEBUG("DB contains %d neighbors\n", num_neighbors);
 | 
			
		||||
    for (int i = 0; i < num_neighbors; i++) {
 | 
			
		||||
        meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
 | 
			
		||||
        LOG_DEBUG("     Node %d: node_id=%d, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
 | 
			
		||||
    }
 | 
			
		||||
    LOG_DEBUG("----------------\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Prints the nodeDB with selectors for the neighbors we've chosen to send (inefficiently)
 | 
			
		||||
Uses LOG_DEBUG, which equates to Console.log
 | 
			
		||||
NOTE: For debugging only
 | 
			
		||||
*/
 | 
			
		||||
void NeighborInfoModule::printNodeDBSelection(const char *header, const meshtastic_NeighborInfo *np)
 | 
			
		||||
{
 | 
			
		||||
    int num_neighbors = getNumNeighbors();
 | 
			
		||||
    LOG_DEBUG("%s NODEDB SELECTION from Node %d:\n", header, nodeDB.getNodeNum());
 | 
			
		||||
    LOG_DEBUG("----------------\n");
 | 
			
		||||
    LOG_DEBUG("Selected %d neighbors of %d DB neighbors\n", np->neighbors_count, num_neighbors);
 | 
			
		||||
    for (int i = 0; i < num_neighbors; i++) {
 | 
			
		||||
        meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
 | 
			
		||||
        bool chosen = false;
 | 
			
		||||
        for (int j = 0; j < np->neighbors_count; j++) {
 | 
			
		||||
            if (np->neighbors[j].node_id == dbEntry->node_id) {
 | 
			
		||||
                chosen = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (!chosen) {
 | 
			
		||||
            LOG_DEBUG("     Node %d: neighbor=%d, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
 | 
			
		||||
        } else {
 | 
			
		||||
            LOG_DEBUG("---> Node %d: neighbor=%d, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    LOG_DEBUG("----------------\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Send our initial owner announcement 35 seconds after we start (to give network time to setup) */
 | 
			
		||||
NeighborInfoModule::NeighborInfoModule()
 | 
			
		||||
    : neighbors(neighborState.neighbors), numNeighbors(&neighborState.neighbors_count),
 | 
			
		||||
      ProtobufModule("neighborinfo", meshtastic_PortNum_NEIGHBORINFO_APP, &meshtastic_NeighborInfo_msg), concurrency::OSThread(
 | 
			
		||||
                                                                                                             "NeighborInfoModule")
 | 
			
		||||
{
 | 
			
		||||
    ourPortNum = meshtastic_PortNum_NEIGHBORINFO_APP;
 | 
			
		||||
 | 
			
		||||
    if (moduleConfig.neighbor_info.enabled) {
 | 
			
		||||
        this->loadProtoForModule();
 | 
			
		||||
        setIntervalFromNow(35 * 1000);
 | 
			
		||||
    } else {
 | 
			
		||||
        LOG_DEBUG("NeighborInfoModule is disabled\n");
 | 
			
		||||
        disable();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Allocate a zeroed neighbor info packet
 | 
			
		||||
*/
 | 
			
		||||
meshtastic_NeighborInfo *NeighborInfoModule::allocateNeighborInfoPacket()
 | 
			
		||||
{
 | 
			
		||||
    meshtastic_NeighborInfo *neighborInfo = (meshtastic_NeighborInfo *)malloc(sizeof(meshtastic_NeighborInfo));
 | 
			
		||||
    memset(neighborInfo, 0, sizeof(meshtastic_NeighborInfo));
 | 
			
		||||
    return neighborInfo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time
 | 
			
		||||
Assumes that the neighborInfo packet has been allocated
 | 
			
		||||
@returns the number of entries collected
 | 
			
		||||
*/
 | 
			
		||||
uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo)
 | 
			
		||||
{
 | 
			
		||||
    int my_node_id = nodeDB.getNodeNum();
 | 
			
		||||
    neighborInfo->node_id = my_node_id;
 | 
			
		||||
    neighborInfo->last_sent_by_id = my_node_id;
 | 
			
		||||
    neighborInfo->node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
 | 
			
		||||
 | 
			
		||||
    int num_neighbors = cleanUpNeighbors();
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < num_neighbors; i++) {
 | 
			
		||||
        meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
 | 
			
		||||
        if ((neighborInfo->neighbors_count < MAX_NUM_NEIGHBORS) && (dbEntry->node_id != my_node_id)) {
 | 
			
		||||
            neighborInfo->neighbors[neighborInfo->neighbors_count].node_id = dbEntry->node_id;
 | 
			
		||||
            neighborInfo->neighbors[neighborInfo->neighbors_count].snr = dbEntry->snr;
 | 
			
		||||
            // Note: we don't set the last_rx_time and node_broadcast_intervals_secs here, because we don't want to send this over
 | 
			
		||||
            // the mesh
 | 
			
		||||
            neighborInfo->neighbors_count++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    printNodeDBNodes("DBSTATE");
 | 
			
		||||
    printNodeDBNeighbors("NEIGHBORS");
 | 
			
		||||
    printNodeDBSelection("COLLECTED", neighborInfo);
 | 
			
		||||
    return neighborInfo->neighbors_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Remove neighbors from the database that we haven't heard from in a while
 | 
			
		||||
@returns new number of neighbors
 | 
			
		||||
*/
 | 
			
		||||
size_t NeighborInfoModule::cleanUpNeighbors()
 | 
			
		||||
{
 | 
			
		||||
    uint32_t now = getTime();
 | 
			
		||||
    int num_neighbors = getNumNeighbors();
 | 
			
		||||
    NodeNum my_node_id = nodeDB.getNodeNum();
 | 
			
		||||
 | 
			
		||||
    // Find neighbors to remove
 | 
			
		||||
    std::vector<int> indices_to_remove;
 | 
			
		||||
    for (int i = 0; i < num_neighbors; i++) {
 | 
			
		||||
        meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
 | 
			
		||||
        // We will remove a neighbor if we haven't heard from them in twice the broadcast interval
 | 
			
		||||
        if ((now - dbEntry->last_rx_time > dbEntry->node_broadcast_interval_secs * 2) && (dbEntry->node_id != my_node_id)) {
 | 
			
		||||
            indices_to_remove.push_back(i);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Update the neighbor list
 | 
			
		||||
    for (int i = 0; i < indices_to_remove.size(); i++) {
 | 
			
		||||
        int index = indices_to_remove[i];
 | 
			
		||||
        LOG_DEBUG("Removing neighbor with node ID 0x%x\n", neighbors[index].node_id);
 | 
			
		||||
        for (int j = index; j < num_neighbors - 1; j++) {
 | 
			
		||||
            neighbors[j] = neighbors[j + 1];
 | 
			
		||||
        }
 | 
			
		||||
        (*numNeighbors)--;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Save the neighbor list if we removed any neighbors
 | 
			
		||||
    if (indices_to_remove.size() > 0) {
 | 
			
		||||
        saveProtoForModule();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return *numNeighbors;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Send neighbor info to the mesh */
 | 
			
		||||
void NeighborInfoModule::sendNeighborInfo(NodeNum dest, bool wantReplies)
 | 
			
		||||
{
 | 
			
		||||
    meshtastic_NeighborInfo *neighborInfo = allocateNeighborInfoPacket();
 | 
			
		||||
    collectNeighborInfo(neighborInfo);
 | 
			
		||||
    meshtastic_MeshPacket *p = allocDataProtobuf(*neighborInfo);
 | 
			
		||||
    // send regardless of whether or not we have neighbors in our DB,
 | 
			
		||||
    // because we want to get neighbors for the next cycle
 | 
			
		||||
    p->to = dest;
 | 
			
		||||
    p->decoded.want_response = wantReplies;
 | 
			
		||||
    printNeighborInfo("SENDING", neighborInfo);
 | 
			
		||||
    service.sendToMesh(p, RX_SRC_LOCAL, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Encompasses the full construction and sending packet to mesh
 | 
			
		||||
Will be used for broadcast.
 | 
			
		||||
*/
 | 
			
		||||
int32_t NeighborInfoModule::runOnce()
 | 
			
		||||
{
 | 
			
		||||
    bool requestReplies = false;
 | 
			
		||||
    sendNeighborInfo(NODENUM_BROADCAST, requestReplies);
 | 
			
		||||
    return getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Collect a recieved neighbor info packet from another node
 | 
			
		||||
Pass it to an upper client; do not persist this data on the mesh
 | 
			
		||||
*/
 | 
			
		||||
bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np)
 | 
			
		||||
{
 | 
			
		||||
    printNeighborInfo("RECEIVED", np);
 | 
			
		||||
    updateNeighbors(mp, np);
 | 
			
		||||
    // Allow others to handle this packet
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Copy the content of a current NeighborInfo packet into a new one and update the last_sent_by_id to our NodeNum
 | 
			
		||||
*/
 | 
			
		||||
void NeighborInfoModule::updateLastSentById(meshtastic_MeshPacket *p)
 | 
			
		||||
{
 | 
			
		||||
    auto &incoming = p->decoded;
 | 
			
		||||
    meshtastic_NeighborInfo scratch;
 | 
			
		||||
    meshtastic_NeighborInfo *updated = NULL;
 | 
			
		||||
    memset(&scratch, 0, sizeof(scratch));
 | 
			
		||||
    pb_decode_from_bytes(incoming.payload.bytes, incoming.payload.size, &meshtastic_NeighborInfo_msg, &scratch);
 | 
			
		||||
    updated = &scratch;
 | 
			
		||||
 | 
			
		||||
    updated->last_sent_by_id = nodeDB.getNodeNum();
 | 
			
		||||
 | 
			
		||||
    // Set updated last_sent_by_id to the payload of the to be flooded packet
 | 
			
		||||
    p->decoded.payload.size =
 | 
			
		||||
        pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_NeighborInfo_msg, updated);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NeighborInfoModule::resetNeighbors()
 | 
			
		||||
{
 | 
			
		||||
    *numNeighbors = 0;
 | 
			
		||||
    neighborState.neighbors_count = 0;
 | 
			
		||||
    memset(neighborState.neighbors, 0, sizeof(neighborState.neighbors));
 | 
			
		||||
    saveProtoForModule();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NeighborInfoModule::updateNeighbors(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np)
 | 
			
		||||
{
 | 
			
		||||
    // The last sent ID will be 0 if the packet is from the phone, which we don't count as
 | 
			
		||||
    // an edge. So we assume that if it's zero, then this packet is from our node.
 | 
			
		||||
    if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) {
 | 
			
		||||
        getOrCreateNeighbor(mp.from, np->last_sent_by_id, np->node_broadcast_interval_secs, mp.rx_snr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSender, NodeNum n,
 | 
			
		||||
                                                             uint32_t node_broadcast_interval_secs, int snr)
 | 
			
		||||
{
 | 
			
		||||
    // our node and the phone are the same node (not neighbors)
 | 
			
		||||
    if (n == 0) {
 | 
			
		||||
        n = nodeDB.getNodeNum();
 | 
			
		||||
    }
 | 
			
		||||
    // look for one in the existing list
 | 
			
		||||
    for (int i = 0; i < (*numNeighbors); i++) {
 | 
			
		||||
        meshtastic_Neighbor *nbr = &neighbors[i];
 | 
			
		||||
        if (nbr->node_id == n) {
 | 
			
		||||
            // if found, update it
 | 
			
		||||
            nbr->snr = snr;
 | 
			
		||||
            nbr->last_rx_time = getTime();
 | 
			
		||||
            // Only if this is the original sender, the broadcast interval corresponds to it
 | 
			
		||||
            if (originalSender == n)
 | 
			
		||||
                nbr->node_broadcast_interval_secs = node_broadcast_interval_secs;
 | 
			
		||||
            saveProtoForModule(); // Save the updated neighbor
 | 
			
		||||
            return nbr;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // otherwise, allocate one and assign data to it
 | 
			
		||||
    // TODO: max memory for the database should take neighbors into account, but currently doesn't
 | 
			
		||||
    if (*numNeighbors < MAX_NUM_NODES) {
 | 
			
		||||
        (*numNeighbors)++;
 | 
			
		||||
    }
 | 
			
		||||
    meshtastic_Neighbor *new_nbr = &neighbors[((*numNeighbors) - 1)];
 | 
			
		||||
    new_nbr->node_id = n;
 | 
			
		||||
    new_nbr->snr = snr;
 | 
			
		||||
    new_nbr->last_rx_time = getTime();
 | 
			
		||||
    // Only if this is the original sender, the broadcast interval corresponds to it
 | 
			
		||||
    if (originalSender == n)
 | 
			
		||||
        new_nbr->node_broadcast_interval_secs = node_broadcast_interval_secs;
 | 
			
		||||
    saveProtoForModule(); // Save the new neighbor
 | 
			
		||||
    return new_nbr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NeighborInfoModule::loadProtoForModule()
 | 
			
		||||
{
 | 
			
		||||
    if (!nodeDB.loadProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, sizeof(meshtastic_NeighborInfo),
 | 
			
		||||
                          &meshtastic_NeighborInfo_msg, &neighborState)) {
 | 
			
		||||
        neighborState = meshtastic_NeighborInfo_init_zero;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Save the module config to file.
 | 
			
		||||
 *
 | 
			
		||||
 * @return true On success.
 | 
			
		||||
 * @return false On error.
 | 
			
		||||
 */
 | 
			
		||||
bool NeighborInfoModule::saveProtoForModule()
 | 
			
		||||
{
 | 
			
		||||
    bool okay = true;
 | 
			
		||||
 | 
			
		||||
#ifdef FS
 | 
			
		||||
    FS.mkdir("/prefs");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    okay &= nodeDB.saveProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, &meshtastic_NeighborInfo_msg, &neighborState);
 | 
			
		||||
 | 
			
		||||
    return okay;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,84 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
#include "ProtobufModule.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Neighborinfo module for sending info on each node's 0-hop neighbors to the mesh
 | 
			
		||||
 */
 | 
			
		||||
class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, private concurrency::OSThread
 | 
			
		||||
{
 | 
			
		||||
    meshtastic_Neighbor *neighbors;
 | 
			
		||||
    pb_size_t *numNeighbors;
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    /*
 | 
			
		||||
     * Expose the constructor
 | 
			
		||||
     */
 | 
			
		||||
    NeighborInfoModule();
 | 
			
		||||
 | 
			
		||||
    /* Reset neighbor info after clearing nodeDB*/
 | 
			
		||||
    void resetNeighbors();
 | 
			
		||||
 | 
			
		||||
    bool saveProtoForModule();
 | 
			
		||||
 | 
			
		||||
    // Let FloodingRouter call updateLastSentById upon rebroadcasting a NeighborInfo packet
 | 
			
		||||
    friend class FloodingRouter;
 | 
			
		||||
 | 
			
		||||
  protected:
 | 
			
		||||
    // Note: this holds our local info.
 | 
			
		||||
    meshtastic_NeighborInfo neighborState;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Called to handle a particular incoming message
 | 
			
		||||
     * @return true if you've guaranteed you've handled this message and no other handlers should be considered for it
 | 
			
		||||
     */
 | 
			
		||||
    virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *nb) override;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time
 | 
			
		||||
     * @return the number of entries collected
 | 
			
		||||
     */
 | 
			
		||||
    uint32_t collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo);
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    Remove neighbors from the database that we haven't heard from in a while
 | 
			
		||||
    @returns new number of neighbors
 | 
			
		||||
    */
 | 
			
		||||
    size_t cleanUpNeighbors();
 | 
			
		||||
 | 
			
		||||
    /* Allocate a new NeighborInfo packet */
 | 
			
		||||
    meshtastic_NeighborInfo *allocateNeighborInfoPacket();
 | 
			
		||||
 | 
			
		||||
    // Find a neighbor in our DB, create an empty neighbor if missing
 | 
			
		||||
    meshtastic_Neighbor *getOrCreateNeighbor(NodeNum originalSender, NodeNum n, uint32_t node_broadcast_interval_secs, int snr);
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Send info on our node's neighbors into the mesh
 | 
			
		||||
     */
 | 
			
		||||
    void sendNeighborInfo(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
 | 
			
		||||
 | 
			
		||||
    size_t getNumNeighbors() { return *numNeighbors; }
 | 
			
		||||
 | 
			
		||||
    meshtastic_Neighbor *getNeighborByIndex(size_t x)
 | 
			
		||||
    {
 | 
			
		||||
        assert(x < *numNeighbors);
 | 
			
		||||
        return &neighbors[x];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* update neighbors with subpacket sniffed from network */
 | 
			
		||||
    void updateNeighbors(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np);
 | 
			
		||||
 | 
			
		||||
    /* update a NeighborInfo packet with our NodeNum as last_sent_by_id */
 | 
			
		||||
    void updateLastSentById(meshtastic_MeshPacket *p);
 | 
			
		||||
 | 
			
		||||
    void loadProtoForModule();
 | 
			
		||||
 | 
			
		||||
    /* Does our periodic broadcast */
 | 
			
		||||
    int32_t runOnce() override;
 | 
			
		||||
 | 
			
		||||
    /* These are for debugging only */
 | 
			
		||||
    void printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np);
 | 
			
		||||
    void printNodeDBNodes(const char *header);
 | 
			
		||||
    void printNodeDBNeighbors(const char *header);
 | 
			
		||||
    void printNodeDBSelection(const char *header, const meshtastic_NeighborInfo *np);
 | 
			
		||||
};
 | 
			
		||||
extern NeighborInfoModule *neighborInfoModule;
 | 
			
		||||
| 
						 | 
				
			
			@ -363,6 +363,19 @@ JSONValue::JSONValue(int m_integer_value)
 | 
			
		|||
    number_value = (double)m_integer_value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Basic constructor for creating a JSON Value of type Number
 | 
			
		||||
 *
 | 
			
		||||
 * @access public
 | 
			
		||||
 *
 | 
			
		||||
 * @param uint m_integer_value The number to use as the value
 | 
			
		||||
 */
 | 
			
		||||
JSONValue::JSONValue(uint m_integer_value)
 | 
			
		||||
{
 | 
			
		||||
    type = JSONType_Number;
 | 
			
		||||
    number_value = (double)m_integer_value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Basic constructor for creating a JSON Value of type Array
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -874,4 +887,4 @@ std::string JSONValue::Indent(size_t depth)
 | 
			
		|||
    depth ? --depth : 0;
 | 
			
		||||
    std::string indentStr(depth * indent_step, ' ');
 | 
			
		||||
    return indentStr;
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +45,7 @@ class JSONValue
 | 
			
		|||
    JSONValue(bool m_bool_value);
 | 
			
		||||
    JSONValue(double m_number_value);
 | 
			
		||||
    JSONValue(int m_integer_value);
 | 
			
		||||
    JSONValue(uint m_integer_value);
 | 
			
		||||
    JSONValue(const JSONArray &m_array_value);
 | 
			
		||||
    JSONValue(const JSONObject &m_object_value);
 | 
			
		||||
    JSONValue(const JSONValue &m_source);
 | 
			
		||||
| 
						 | 
				
			
			@ -91,4 +92,4 @@ class JSONValue
 | 
			
		|||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -541,7 +541,7 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
 | 
			
		|||
            if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch)) {
 | 
			
		||||
                decoded = &scratch;
 | 
			
		||||
                if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) {
 | 
			
		||||
                    msgPayload["battery_level"] = new JSONValue((int)decoded->variant.device_metrics.battery_level);
 | 
			
		||||
                    msgPayload["battery_level"] = new JSONValue((uint)decoded->variant.device_metrics.battery_level);
 | 
			
		||||
                    msgPayload["voltage"] = new JSONValue(decoded->variant.device_metrics.voltage);
 | 
			
		||||
                    msgPayload["channel_utilization"] = new JSONValue(decoded->variant.device_metrics.channel_utilization);
 | 
			
		||||
                    msgPayload["air_util_tx"] = new JSONValue(decoded->variant.device_metrics.air_util_tx);
 | 
			
		||||
| 
						 | 
				
			
			@ -588,10 +588,10 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
 | 
			
		|||
            if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch)) {
 | 
			
		||||
                decoded = &scratch;
 | 
			
		||||
                if ((int)decoded->time) {
 | 
			
		||||
                    msgPayload["time"] = new JSONValue((int)decoded->time);
 | 
			
		||||
                    msgPayload["time"] = new JSONValue((uint)decoded->time);
 | 
			
		||||
                }
 | 
			
		||||
                if ((int)decoded->timestamp) {
 | 
			
		||||
                    msgPayload["timestamp"] = new JSONValue((int)decoded->timestamp);
 | 
			
		||||
                    msgPayload["timestamp"] = new JSONValue((uint)decoded->timestamp);
 | 
			
		||||
                }
 | 
			
		||||
                msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i);
 | 
			
		||||
                msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i);
 | 
			
		||||
| 
						 | 
				
			
			@ -599,13 +599,13 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
 | 
			
		|||
                    msgPayload["altitude"] = new JSONValue((int)decoded->altitude);
 | 
			
		||||
                }
 | 
			
		||||
                if ((int)decoded->ground_speed) {
 | 
			
		||||
                    msgPayload["ground_speed"] = new JSONValue((int)decoded->ground_speed);
 | 
			
		||||
                    msgPayload["ground_speed"] = new JSONValue((uint)decoded->ground_speed);
 | 
			
		||||
                }
 | 
			
		||||
                if (int(decoded->ground_track)) {
 | 
			
		||||
                    msgPayload["ground_track"] = new JSONValue((int)decoded->ground_track);
 | 
			
		||||
                    msgPayload["ground_track"] = new JSONValue((uint)decoded->ground_track);
 | 
			
		||||
                }
 | 
			
		||||
                if (int(decoded->sats_in_view)) {
 | 
			
		||||
                    msgPayload["sats_in_view"] = new JSONValue((int)decoded->sats_in_view);
 | 
			
		||||
                    msgPayload["sats_in_view"] = new JSONValue((uint)decoded->sats_in_view);
 | 
			
		||||
                }
 | 
			
		||||
                if ((int)decoded->PDOP) {
 | 
			
		||||
                    msgPayload["PDOP"] = new JSONValue((int)decoded->PDOP);
 | 
			
		||||
| 
						 | 
				
			
			@ -632,11 +632,11 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
 | 
			
		|||
            memset(&scratch, 0, sizeof(scratch));
 | 
			
		||||
            if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) {
 | 
			
		||||
                decoded = &scratch;
 | 
			
		||||
                msgPayload["id"] = new JSONValue((int)decoded->id);
 | 
			
		||||
                msgPayload["id"] = new JSONValue((uint)decoded->id);
 | 
			
		||||
                msgPayload["name"] = new JSONValue(decoded->name);
 | 
			
		||||
                msgPayload["description"] = new JSONValue(decoded->description);
 | 
			
		||||
                msgPayload["expire"] = new JSONValue((int)decoded->expire);
 | 
			
		||||
                msgPayload["locked_to"] = new JSONValue((int)decoded->locked_to);
 | 
			
		||||
                msgPayload["expire"] = new JSONValue((uint)decoded->expire);
 | 
			
		||||
                msgPayload["locked_to"] = new JSONValue((uint)decoded->locked_to);
 | 
			
		||||
                msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i);
 | 
			
		||||
                msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i);
 | 
			
		||||
                jsonObj["payload"] = new JSONValue(msgPayload);
 | 
			
		||||
| 
						 | 
				
			
			@ -646,16 +646,34 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
 | 
			
		|||
        };
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case meshtastic_PortNum_NEIGHBORINFO_APP: {
 | 
			
		||||
        msgType = "neighborinfo";
 | 
			
		||||
        meshtastic_NeighborInfo scratch;
 | 
			
		||||
        meshtastic_NeighborInfo *decoded = NULL;
 | 
			
		||||
        if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
 | 
			
		||||
            memset(&scratch, 0, sizeof(scratch));
 | 
			
		||||
            if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg,
 | 
			
		||||
                                     &scratch)) {
 | 
			
		||||
                decoded = &scratch;
 | 
			
		||||
                msgPayload["node_id"] = new JSONValue((uint)decoded->node_id);
 | 
			
		||||
                msgPayload["neighbors_count"] = new JSONValue(decoded->neighbors_count);
 | 
			
		||||
                msgPayload["neighbors"] = new JSONValue(decoded->neighbors);
 | 
			
		||||
            } else {
 | 
			
		||||
                LOG_ERROR("Error decoding protobuf for neighborinfo message!\n");
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    // add more packet types here if needed
 | 
			
		||||
    default:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    jsonObj["id"] = new JSONValue((int)mp->id);
 | 
			
		||||
    jsonObj["timestamp"] = new JSONValue((int)mp->rx_time);
 | 
			
		||||
    jsonObj["to"] = new JSONValue((int)mp->to);
 | 
			
		||||
    jsonObj["from"] = new JSONValue((int)mp->from);
 | 
			
		||||
    jsonObj["channel"] = new JSONValue((int)mp->channel);
 | 
			
		||||
    jsonObj["id"] = new JSONValue((uint)mp->id);
 | 
			
		||||
    jsonObj["timestamp"] = new JSONValue((uint)mp->rx_time);
 | 
			
		||||
    jsonObj["to"] = new JSONValue((uint)mp->to);
 | 
			
		||||
    jsonObj["from"] = new JSONValue((uint)mp->from);
 | 
			
		||||
    jsonObj["channel"] = new JSONValue((uint)mp->channel);
 | 
			
		||||
    jsonObj["type"] = new JSONValue(msgType.c_str());
 | 
			
		||||
    jsonObj["sender"] = new JSONValue(owner.id);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -117,6 +117,8 @@
 | 
			
		|||
#define HW_VENDOR meshtastic_HardwareModel_NANO_G1_EXPLORER
 | 
			
		||||
#elif defined(BETAFPV_900_TX_NANO)
 | 
			
		||||
#define HW_VENDOR meshtastic_HardwareModel_BETAFPV_900_NANO_TX
 | 
			
		||||
#elif defined(PICOMPUTER_S3)
 | 
			
		||||
#define HW_VENDOR meshtastic_HardwareModel_PICOMPUTER_S3
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ void powerCommandsCheck()
 | 
			
		|||
        rp2040.reboot();
 | 
			
		||||
#else
 | 
			
		||||
        rebootAtMsec = -1;
 | 
			
		||||
        LOG_WARN("FIXME implement reboot for this platform. Skipping for now.\n");
 | 
			
		||||
        LOG_WARN("FIXME implement reboot for this platform. Note that some settings require a restart to be applied.\n");
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,10 @@
 | 
			
		|||
#define I2C_SDA SDA_OLED // I2C pins for this board
 | 
			
		||||
#define I2C_SCL SCL_OLED
 | 
			
		||||
 | 
			
		||||
// Enable secondary bus for external periherals
 | 
			
		||||
#define I2C_SDA1 SDA
 | 
			
		||||
#define I2C_SCL1 SCL
 | 
			
		||||
 | 
			
		||||
#define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost
 | 
			
		||||
#define BUTTON_PIN 0
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,9 @@
 | 
			
		|||
#define LED_PIN 18
 | 
			
		||||
 | 
			
		||||
// Enable bus for external periherals
 | 
			
		||||
#define I2C_SDA SDA
 | 
			
		||||
#define I2C_SCL SCL
 | 
			
		||||
 | 
			
		||||
#define USE_EINK
 | 
			
		||||
/*
 | 
			
		||||
 * eink display pins
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
#define I2C_SCL 47
 | 
			
		||||
#define I2C_SDA 48
 | 
			
		||||
#define I2C_SCL SCL
 | 
			
		||||
#define I2C_SDA SDA
 | 
			
		||||
 | 
			
		||||
#define LED_PIN LED
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
#ifndef Pins_Arduino_h
 | 
			
		||||
#define Pins_Arduino_h
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#define USB_VID 0x303a
 | 
			
		||||
#define USB_PID 0x1001
 | 
			
		||||
 | 
			
		||||
#define EXTERNAL_NUM_INTERRUPTS 46
 | 
			
		||||
#define NUM_DIGITAL_PINS 48
 | 
			
		||||
#define NUM_ANALOG_INPUTS 20
 | 
			
		||||
 | 
			
		||||
#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
 | 
			
		||||
#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1)
 | 
			
		||||
#define digitalPinHasPWM(p) (p < 46)
 | 
			
		||||
 | 
			
		||||
static const uint8_t TX = 43;
 | 
			
		||||
static const uint8_t RX = 44;
 | 
			
		||||
 | 
			
		||||
// The default Wire will be mapped to PMU and RTC
 | 
			
		||||
static const uint8_t SDA = 8;
 | 
			
		||||
static const uint8_t SCL = 9;
 | 
			
		||||
 | 
			
		||||
// Default SPI
 | 
			
		||||
static const uint8_t MISO = 39;
 | 
			
		||||
static const uint8_t SCK = 21;
 | 
			
		||||
static const uint8_t MOSI = 38;
 | 
			
		||||
static const uint8_t SS = 40;
 | 
			
		||||
 | 
			
		||||
#endif /* Pins_Arduino_h */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
[env:picomputer-s3]
 | 
			
		||||
extends = esp32s3_base
 | 
			
		||||
board = bpi_picow_esp32_s3
 | 
			
		||||
board_level = extra
 | 
			
		||||
;OpenOCD flash method
 | 
			
		||||
;upload_protocol = esp-builtin
 | 
			
		||||
;Normal method
 | 
			
		||||
upload_protocol = esptool
 | 
			
		||||
 | 
			
		||||
build_flags = 
 | 
			
		||||
  ${esp32s3_base.build_flags}
 | 
			
		||||
  -DPICOMPUTER_S3
 | 
			
		||||
  -I variants/picomputer-s3
 | 
			
		||||
 | 
			
		||||
lib_deps = 
 | 
			
		||||
  ${esp32s3_base.lib_deps}
 | 
			
		||||
  lovyan03/LovyanGFX@^1.1.8
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
#undef GPS_RX_PIN
 | 
			
		||||
#undef GPS_TX_PIN
 | 
			
		||||
 | 
			
		||||
#define BUTTON_PIN 0
 | 
			
		||||
 | 
			
		||||
#define PIN_BUZZER 43
 | 
			
		||||
 | 
			
		||||
#define HAS_GPS 0
 | 
			
		||||
#define HAS_WIRE 0
 | 
			
		||||
 | 
			
		||||
#define USE_RF95 // RFM95/SX127x
 | 
			
		||||
 | 
			
		||||
#define RF95_SCK SCK   // 21
 | 
			
		||||
#define RF95_MISO MISO // 39
 | 
			
		||||
#define RF95_MOSI MOSI // 38
 | 
			
		||||
#define RF95_NSS SS    // 40
 | 
			
		||||
#define LORA_RESET RADIOLIB_NC
 | 
			
		||||
 | 
			
		||||
// per SX1276_Receive_Interrupt/utilities.h
 | 
			
		||||
#define LORA_DIO0 10
 | 
			
		||||
#define LORA_DIO1 RADIOLIB_NC
 | 
			
		||||
#define LORA_DIO2 RADIOLIB_NC
 | 
			
		||||
 | 
			
		||||
// Default SPI1 will be mapped to the display
 | 
			
		||||
#define ST7789_SDA 4
 | 
			
		||||
#define ST7789_SCK 3
 | 
			
		||||
#define ST7789_CS 6
 | 
			
		||||
#define ST7789_RS 1
 | 
			
		||||
#define ST7789_BL 5
 | 
			
		||||
 | 
			
		||||
#define ST7789_RESET -1
 | 
			
		||||
#define ST7789_MISO -1
 | 
			
		||||
#define ST7789_BUSY -1
 | 
			
		||||
#define ST7789_SPI_HOST SPI3_HOST
 | 
			
		||||
#define ST7789_BACKLIGHT_EN 5
 | 
			
		||||
#define SPI_FREQUENCY 40000000
 | 
			
		||||
#define SPI_READ_FREQUENCY 16000000
 | 
			
		||||
#define TFT_HEIGHT 320
 | 
			
		||||
#define TFT_WIDTH 240
 | 
			
		||||
#define TFT_OFFSET_X 0
 | 
			
		||||
#define TFT_OFFSET_Y 0
 | 
			
		||||
#define SCREEN_ROTATE
 | 
			
		||||
#define SCREEN_TRANSITION_FRAMERATE 5
 | 
			
		||||
 | 
			
		||||
#define INPUTBROKER_MATRIX_TYPE 1
 | 
			
		||||
 | 
			
		||||
#define KEYS_COLS                                                                                                                \
 | 
			
		||||
    {                                                                                                                            \
 | 
			
		||||
        44, 47, 17, 15, 13, 41                                                                                                   \
 | 
			
		||||
    }
 | 
			
		||||
#define KEYS_ROWS                                                                                                                \
 | 
			
		||||
    {                                                                                                                            \
 | 
			
		||||
        12, 16, 42, 18, 14, 7                                                                                                    \
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
[VERSION]  
 | 
			
		||||
major = 2
 | 
			
		||||
minor = 1
 | 
			
		||||
build = 23
 | 
			
		||||
minor = 2
 | 
			
		||||
build = 0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue