Merge branch 'master' into portexpander-keyboard

This commit is contained in:
Thomas Göttgens 2024-10-23 21:27:26 +02:00 committed by GitHub
commit cfc3facc4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 767 additions and 55 deletions

View File

@ -20,6 +20,7 @@ Lora:
# CS: 0
# IRQ: 10
# Busy: 11
# DIO2_AS_RF_SWITCH: true
# spidev: spidev0.1
# Module: RF95 # Adafruit RFM9x
@ -154,4 +155,4 @@ Webserver:
General:
MaxNodes: 200
MaxMessageQueue: 100
MaxMessageQueue: 100

View File

@ -1,12 +1,16 @@
[Unit]
Description=Meshtastic Native Daemon
After=network-online.target
StartLimitInterval=200
StartLimitBurst=5
[Service]
User=root
Group=root
Type=simple
ExecStart=/usr/sbin/meshtasticd
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
WantedBy=multi-user.target

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
cp "release/meshtasticd_linux_$(uname -m)" /usr/sbin/meshtasticd
mkdir /etc/meshtasticd
mkdir -p /etc/meshtasticd
if [[ -f "/etc/meshtasticd/config.yaml" ]]; then
cp bin/config-dist.yaml /etc/meshtasticd/config-upgrade.yaml
else

@ -1 +1 @@
Subproject commit e22381a3c6bbdd428f127ed8c0aa0a37789c3907
Subproject commit 8686d049c22c232f57121e66dfb29e7be65010f0

View File

@ -55,6 +55,18 @@ void playBeep()
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
void playGPSEnableBeep()
{
ToneDuration melody[] = {{NOTE_C3, DURATION_1_8}, {NOTE_FS3, DURATION_1_4}, {NOTE_CS4, DURATION_1_4}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
void playGPSDisableBeep()
{
ToneDuration melody[] = {{NOTE_CS4, DURATION_1_8}, {NOTE_FS3, DURATION_1_4}, {NOTE_C3, DURATION_1_4}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
void playStartMelody()
{
ToneDuration melody[] = {{NOTE_FS3, DURATION_1_8}, {NOTE_AS3, DURATION_1_8}, {NOTE_CS4, DURATION_1_4}};

View File

@ -3,3 +3,5 @@
void playBeep();
void playStartMelody();
void playShutdownMelody();
void playGPSEnableBeep();
void playGPSDisableBeep();

View File

@ -114,6 +114,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define CARDKB_ADDR 0x5F
#define TDECK_KB_ADDR 0x55
#define BBQ10_KB_ADDR 0x1F
#define MPR121_KB_ADDR 0x5A
#define PCF8574A_ADDRESS 0x20
// -----------------------------------------------------------------------------

View File

@ -31,8 +31,8 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
{
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004, PCF8574A};
return firstOfOrNONE(5, types);
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004, PCF8574A, MPR121KB};
return firstOfOrNONE(6, types);
}
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const

View File

@ -62,7 +62,8 @@ class ScanI2C
STK8BAXX,
ICM20948,
MAX30102,
TPS65233
TPS65233,
MPR121KB
} DeviceType;
// typedef uint8_t DeviceAddress;

View File

@ -243,6 +243,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found");
SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10 keyboard found");
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found");
#ifndef HAS_TCA9535
SCAN_SIMPLE_CASE(PCF8574A_ADDRESS, PCF8574A, "PCF8574A based keyboard found\n");
@ -413,7 +414,17 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
#ifdef HAS_TPS65233
SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233 BIAS-T found");
#endif
SCAN_SIMPLE_CASE(MLX90614_ADDR_DEF, MLX90614, "MLX90614 IR temp sensor found");
case MLX90614_ADDR_DEF:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1);
if (registerValue == 0x5a) {
type = MLX90614;
LOG_INFO("MLX90614 IR temp sensor found");
} else {
type = MPR121KB;
LOG_INFO("MPR121KB keyboard found");
}
break;
case ICM20948_ADDR: // same as BMX160_ADDR
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR

View File

@ -7,6 +7,7 @@
#include "PowerMon.h"
#include "RTC.h"
#include "Throttle.h"
#include "buzz.h"
#include "meshUtils.h"
#include "main.h" // pmu_found
@ -266,6 +267,9 @@ GPS_RESPONSE GPS::getACK(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
uint32_t startTime = millis();
const char frame_errors[] = "More than 100 frame errors";
int sCounter = 0;
#ifdef GPS_DEBUG
std::string debugmsg = "";
#endif
for (int j = 2; j < 6; j++) {
buf[8] += buf[j];
@ -291,20 +295,24 @@ GPS_RESPONSE GPS::getACK(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
if (b == frame_errors[sCounter]) {
sCounter++;
if (sCounter == 26) {
#ifdef GPS_DEBUG
LOG_DEBUG(debugmsg.c_str());
#endif
return GNSS_RESPONSE_FRAME_ERRORS;
}
} else {
sCounter = 0;
}
#ifdef GPS_DEBUG
LOG_DEBUG("%02X", b);
debugmsg += vformat("%02X", b);
#endif
if (b == buf[ack]) {
ack++;
} else {
if (ack == 3 && b == 0x00) { // UBX-ACK-NAK message
#ifdef GPS_DEBUG
LOG_DEBUG("");
LOG_DEBUG(debugmsg.c_str());
#endif
LOG_WARN("Got NAK for class %02X message %02X", class_id, msg_id);
return GNSS_RESPONSE_NAK; // NAK received
@ -314,7 +322,7 @@ GPS_RESPONSE GPS::getACK(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
}
}
#ifdef GPS_DEBUG
LOG_DEBUG("");
LOG_DEBUG(debugmsg.c_str());
LOG_WARN("No response for class %02X message %02X", class_id, msg_id);
#endif
return GNSS_RESPONSE_NONE; // No response received within timeout
@ -1623,6 +1631,9 @@ bool GPS::whileActive()
{
unsigned int charsInBuf = 0;
bool isValid = false;
#ifdef GPS_DEBUG
std::string debugmsg = "";
#endif
if (powerState != GPS_ACTIVE) {
clearBuffer();
return false;
@ -1640,7 +1651,7 @@ bool GPS::whileActive()
int c = _serial_gps->read();
UBXscratch[charsInBuf] = c;
#ifdef GPS_DEBUG
LOG_DEBUG("%c", c);
debugmsg += vformat("%c", (c >= 32 && c <= 126) ? c : '.');
#endif
isValid |= reader.encode(c);
if (charsInBuf > sizeof(UBXscratch) - 10 || c == '\r') {
@ -1652,6 +1663,9 @@ bool GPS::whileActive()
charsInBuf++;
}
}
#ifdef GPS_DEBUG
LOG_DEBUG(debugmsg.c_str());
#endif
return isValid;
}
void GPS::enable()
@ -1680,6 +1694,7 @@ void GPS::toggleGpsMode()
if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED;
LOG_INFO("User toggled GpsMode. Now DISABLED.");
playGPSDisableBeep();
#ifdef GNSS_AIROHA
if (powerState == GPS_ACTIVE) {
LOG_DEBUG("User power Off GPS");
@ -1690,6 +1705,7 @@ void GPS::toggleGpsMode()
} else if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_DISABLED) {
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
LOG_INFO("User toggled GpsMode. Now ENABLED");
playGPSEnableBeep();
enable();
}
}

View File

@ -75,7 +75,7 @@ class GPS : private concurrency::OSThread
uint8_t fixType = 0; // fix type from GPGSA
#endif
private:
const int serialSpeeds[6] = {9600, 4800, 38400, 57600, 115200, 9600};
const int serialSpeeds[6] = {9600, 115200, 38400, 4800, 57600, 9600};
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastFixStartMsec = 0;
uint32_t rx_gpio = 0;
uint32_t tx_gpio = 0;

View File

@ -0,0 +1,430 @@
// Based on the BBQ10 Keyboard
#include "MPR121Keyboard.h"
#include "configuration.h"
#include <Arduino.h>
#define _MPR121_REG_KEY 0x5a
#define _MPR121_REG_TOUCH_STATUS 0x00
#define _MPR121_REG_ELECTRODE_FILTERED_DATA
#define _MPR121_REG_BASELINE_VALUE 0x1E
// Baseline filters
#define _MPR121_REG_MAX_HALF_DELTA_RISING 0x2B
#define _MPR121_REG_NOISE_HALF_DELTA_RISING 0x2C
#define _MPR121_REG_NOISE_COUNT_LIMIT_RISING 0x2D
#define _MPR121_REG_FILTER_DELAY_COUNT_RISING 0x2E
#define _MPR121_REG_MAX_HALF_DELTA_FALLING 0x2F
#define _MPR121_REG_NOISE_HALF_DELTA_FALLING 0x30
#define _MPR121_REG_NOISE_COUNT_LIMIT_FALLING 0x31
#define _MPR121_REG_FILTER_DELAY_COUNT_FALLING 0x32
#define _MPR121_REG_NOISE_HALF_DELTA_TOUCHED 0x33
#define _MPR121_REG_NOISE_COUNT_LIMIT_TOUCHED 0x34
#define _MPR121_REG_FILTER_DELAY_COUNT_TOUCHED 0x35
#define _MPR121_REG_TOUCH_THRESHOLD 0x41 // First input, +2 for subsequent
#define _MPR121_REG_RELEASE_THRESHOLD 0x42 // First input, +2 for subsequent
#define _MPR121_REG_DEBOUNCE 0x5B
#define _MPR121_REG_CONFIG1 0x5C
#define _MPR121_REG_CONFIG2 0x5D
#define _MPR121_REG_ELECTRODE_CONFIG 0x5E
#define _MPR121_REG_SOFT_RESET 0x80
#define _KEY_MASK 0x0FFF // Key mask for the first 12 bits
#define _NUM_KEYS 12
#define ECR_CALIBRATION_TRACK_FROM_ZERO (0 << 6)
#define ECR_CALIBRATION_LOCK (1 << 6)
#define ECR_CALIBRATION_TRACK_FROM_PARTIAL_FILTER (2 << 6) // Recommended Typical Mode
#define ECR_CALIBRATION_TRACK_FROM_FULL_FILTER (3 << 6)
#define ECR_PROXIMITY_DETECTION_OFF (0 << 0) // Not using proximity detection
#define ECR_TOUCH_DETECTION_12CH (12 << 0) // Using all 12 channels
#define MPR121_NONE 0x00
#define MPR121_REBOOT 0x90
#define MPR121_LEFT 0xb4
#define MPR121_UP 0xb5
#define MPR121_DOWN 0xb6
#define MPR121_RIGHT 0xb7
#define MPR121_ESC 0x1b
#define MPR121_BSP 0x08
#define MPR121_SELECT 0x0d
#define MPR121_FN_ON 0xf1
#define MPR121_FN_OFF 0xf2
#define LONG_PRESS_THRESHOLD 2000
#define MULTI_TAP_THRESHOLD 2000
uint8_t TapMod[12] = {1, 2, 1, 13, 7, 7, 7, 7, 7, 9, 7, 9}; // Num chars per key, Modulus for rotating through characters
unsigned char MPR121_TapMap[12][13] = {{MPR121_BSP},
{'0', ' '},
{MPR121_SELECT},
{'1', '.', ',', '?', '!', ':', ';', '-', '_', '\\', '/', '(', ')'},
{'2', 'a', 'b', 'c', 'A', 'B', 'C'},
{'3', 'd', 'e', 'f', 'D', 'E', 'F'},
{'4', 'g', 'h', 'i', 'G', 'H', 'I'},
{'5', 'j', 'k', 'l', 'J', 'K', 'L'},
{'6', 'm', 'n', 'o', 'M', 'N', 'O'},
{'7', 'p', 'q', 'r', 's', 'P', 'Q', 'R', 'S'},
{'8', 't', 'u', 'v', 'T', 'U', 'V'},
{'9', 'w', 'x', 'y', 'z', 'W', 'X', 'Y', 'Z'}};
unsigned char MPR121_LongPressMap[12] = {MPR121_ESC, ' ', MPR121_NONE, MPR121_NONE, MPR121_UP, MPR121_NONE,
MPR121_LEFT, MPR121_NONE, MPR121_RIGHT, MPR121_NONE, MPR121_DOWN, MPR121_NONE};
// Translation map from left to right, top to bottom layout to a more convenient layout to manufacture, matching the
// https://www.amazon.com.au/Capacitive-Sensitive-Sensitivity-Replacement-Traditional/dp/B0CTJD5KW9/ref=pd_ci_mcx_mh_mcx_views_0_title?th=1
/*uint8_t MPR121_KeyMap[12] = {
9, 6, 3, 0,
10, 7, 4, 1,
11, 8, 5, 2
};*/
// Rotated Layout
uint8_t MPR121_KeyMap[12] = {2, 5, 8, 11, 1, 4, 7, 10, 0, 3, 6, 9};
MPR121Keyboard::MPR121Keyboard() : m_wire(nullptr), m_addr(0), readCallback(nullptr), writeCallback(nullptr)
{
// LOG_DEBUG("MPR121 @ %02x\n", m_addr);
state = Init;
last_key = -1;
last_tap = 0L;
char_idx = 0;
queue = "";
}
void MPR121Keyboard::begin(uint8_t addr, TwoWire *wire)
{
m_addr = addr;
m_wire = wire;
m_wire->begin();
reset();
}
void MPR121Keyboard::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr)
{
m_addr = addr;
m_wire = nullptr;
writeCallback = w;
readCallback = r;
reset();
}
void MPR121Keyboard::reset()
{
LOG_DEBUG("MPR121 Resetting...");
// Trigger a MPR121 Soft Reset
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(_MPR121_REG_SOFT_RESET);
m_wire->endTransmission();
}
if (writeCallback) {
uint8_t data = 0;
writeCallback(m_addr, _MPR121_REG_SOFT_RESET, &data, 0);
}
delay(100);
// Reset Electrode Configuration to 0x00, Stop Mode
writeRegister(_MPR121_REG_ELECTRODE_CONFIG, 0x00);
delay(100);
LOG_DEBUG("MPR121 Configuring");
// Set touch release thresholds
for (uint8_t i = 0; i < 12; i++) {
// Set touch threshold
writeRegister(_MPR121_REG_TOUCH_THRESHOLD + (i * 2), 15);
delay(20);
// Set release threshold
writeRegister(_MPR121_REG_RELEASE_THRESHOLD + (i * 2), 7);
delay(20);
}
// Configure filtering and baseline registers
writeRegister(_MPR121_REG_MAX_HALF_DELTA_RISING, 0x01);
delay(20);
writeRegister(_MPR121_REG_MAX_HALF_DELTA_FALLING, 0x01);
delay(20);
writeRegister(_MPR121_REG_NOISE_HALF_DELTA_RISING, 0x01);
delay(20);
writeRegister(_MPR121_REG_NOISE_HALF_DELTA_FALLING, 0x05);
delay(20);
writeRegister(_MPR121_REG_NOISE_HALF_DELTA_TOUCHED, 0x00);
delay(20);
writeRegister(_MPR121_REG_NOISE_COUNT_LIMIT_RISING, 0x0e);
delay(20);
writeRegister(_MPR121_REG_NOISE_COUNT_LIMIT_FALLING, 0x01);
delay(20);
writeRegister(_MPR121_REG_NOISE_COUNT_LIMIT_TOUCHED, 0x00);
delay(20);
writeRegister(_MPR121_REG_FILTER_DELAY_COUNT_RISING, 0x00);
delay(20);
writeRegister(_MPR121_REG_FILTER_DELAY_COUNT_FALLING, 0x00);
delay(20);
writeRegister(_MPR121_REG_FILTER_DELAY_COUNT_TOUCHED, 0x00);
delay(20);
// Set Debounce to 0x02
writeRegister(_MPR121_REG_DEBOUNCE, 0x00);
delay(20);
// Set Filter1 itterations and discharge current 6x and 16uA respectively (0x10)
writeRegister(_MPR121_REG_CONFIG1, 0x10);
delay(20);
// Set CDT to 0.5us, Filter2 itterations to 4x, and Sample interval = 0 (0x20)
writeRegister(_MPR121_REG_CONFIG2, 0x20);
delay(20);
// Enter run mode by Seting partial filter calibration tracking, disable proximity detection, enable 12 channels
writeRegister(_MPR121_REG_ELECTRODE_CONFIG,
ECR_CALIBRATION_TRACK_FROM_PARTIAL_FILTER | ECR_PROXIMITY_DETECTION_OFF | ECR_TOUCH_DETECTION_12CH);
delay(100);
LOG_DEBUG("MPR121 Running");
state = Idle;
}
void MPR121Keyboard::attachInterrupt(uint8_t pin, void (*func)(void)) const
{
pinMode(pin, INPUT_PULLUP);
::attachInterrupt(digitalPinToInterrupt(pin), func, RISING);
}
void MPR121Keyboard::detachInterrupt(uint8_t pin) const
{
::detachInterrupt(pin);
}
uint8_t MPR121Keyboard::status() const
{
return readRegister16(_MPR121_REG_KEY);
}
uint8_t MPR121Keyboard::keyCount() const
{
// Read the key register
uint16_t keyRegister = readRegister16(_MPR121_REG_KEY);
return keyCount(keyRegister);
}
uint8_t MPR121Keyboard::keyCount(uint16_t value) const
{
// Mask the first 12 bits
uint16_t buttonState = value & _KEY_MASK;
// Count how many bits are set to 1 (i.e., how many buttons are pressed)
uint8_t numButtonsPressed = 0;
for (uint8_t i = 0; i < 12; ++i) {
if (buttonState & (1 << i)) {
numButtonsPressed++;
}
}
return numButtonsPressed;
}
bool MPR121Keyboard::hasEvent()
{
return queue.length() > 0;
}
void MPR121Keyboard::queueEvent(char next)
{
if (next == MPR121_NONE) {
return;
}
queue.concat(next);
}
char MPR121Keyboard::dequeueEvent()
{
if (queue.length() < 1) {
return MPR121_NONE;
}
char next = queue.charAt(0);
queue.remove(0, 1);
return next;
}
void MPR121Keyboard::trigger()
{
// Intended to fire in response to an interrupt from the MPR121 or a longpress callback
// Only functional if not in Init state
if (state != Init) {
// Read the key register
uint16_t keyRegister = readRegister16(_MPR121_REG_KEY);
uint8_t keysPressed = keyCount(keyRegister);
if (keysPressed == 0) {
// No buttons pressed
if (state == Held)
released();
state = Idle;
return;
}
if (keysPressed == 1) {
// No buttons pressed
if (state == Held || state == HeldLong)
held(keyRegister);
if (state == Idle)
pressed(keyRegister);
return;
}
if (keysPressed > 1) {
// Multipress
state = Busy;
return;
}
} else {
reset();
}
}
void MPR121Keyboard::pressed(uint16_t keyRegister)
{
if (state == Init || state == Busy) {
return;
}
if (keyCount(keyRegister) != 1) {
LOG_DEBUG("Multipress");
return;
} else {
LOG_DEBUG("Pressed");
}
uint16_t buttonState = keyRegister & _KEY_MASK;
uint8_t next_pin = 0;
for (uint8_t i = 0; i < 12; ++i) {
if (buttonState & (1 << i)) {
next_pin = i;
}
}
uint8_t next_key = MPR121_KeyMap[next_pin];
LOG_DEBUG("MPR121 Pin: %i Key: %i", next_pin, next_key);
uint32_t now = millis();
int32_t tap_interval = now - last_tap;
if (tap_interval < 0) {
// long running, millis has overflowed.
last_tap = 0;
state = Busy;
return;
}
if (next_key != last_key || tap_interval > MULTI_TAP_THRESHOLD) {
char_idx = 0;
} else {
char_idx += 1;
}
last_key = next_key;
last_tap = now;
state = Held;
return;
}
void MPR121Keyboard::held(uint16_t keyRegister)
{
if (state == Init || state == Busy) {
return;
}
if (keyCount(keyRegister) != 1) {
return;
}
LOG_DEBUG("Held");
uint16_t buttonState = keyRegister & _KEY_MASK;
uint8_t next_key = 0;
for (uint8_t i = 0; i < 12; ++i) {
if (buttonState & (1 << i)) {
next_key = MPR121_KeyMap[i];
}
}
uint32_t now = millis();
int32_t held_interval = now - last_tap;
if (held_interval < 0 || next_key != last_key) {
// long running, millis has overflowed, or a key has been switched quickly...
last_tap = 0;
state = Busy;
return;
}
if (held_interval > LONG_PRESS_THRESHOLD) {
// Set state to heldlong, send a longpress, and reset the timer...
state = HeldLong; // heldlong will allow this function to still fire, but prevent a "release"
queueEvent(MPR121_LongPressMap[last_key]);
last_tap = now;
LOG_DEBUG("Long Press Key: %i Map: %i", last_key, MPR121_LongPressMap[last_key]);
}
return;
}
void MPR121Keyboard::released()
{
if (state != Held) {
return;
}
// would clear longpress callback... later.
if (last_key < 0 || last_key > _NUM_KEYS) { // reset to idle if last_key out of bounds
last_key = -1;
state = Idle;
return;
}
LOG_DEBUG("Released");
if (char_idx > 0 && TapMod[last_key] > 1) {
queueEvent(MPR121_BSP);
LOG_DEBUG("Multi Press, Backspace");
}
queueEvent(MPR121_TapMap[last_key][(char_idx % TapMod[last_key])]);
LOG_DEBUG("Key Press: %i Index:%i if %i Map: %i", last_key, char_idx, TapMod[last_key],
MPR121_TapMap[last_key][(char_idx % TapMod[last_key])]);
}
uint8_t MPR121Keyboard::readRegister8(uint8_t reg) const
{
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(reg);
m_wire->endTransmission();
m_wire->requestFrom(m_addr, (uint8_t)1);
if (m_wire->available() < 1)
return 0;
return m_wire->read();
}
if (readCallback) {
uint8_t data;
readCallback(m_addr, reg, &data, 1);
return data;
}
return 0;
}
uint16_t MPR121Keyboard::readRegister16(uint8_t reg) const
{
uint8_t data[2] = {0};
// uint8_t low = 0, high = 0;
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(reg);
m_wire->endTransmission();
m_wire->requestFrom(m_addr, (uint8_t)2);
if (m_wire->available() < 2)
return 0;
data[0] = m_wire->read();
data[1] = m_wire->read();
}
if (readCallback) {
readCallback(m_addr, reg, data, 2);
}
return (data[1] << 8) | data[0];
}
void MPR121Keyboard::writeRegister(uint8_t reg, uint8_t value)
{
uint8_t data[2];
data[0] = reg;
data[1] = value;
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(data, sizeof(uint8_t) * 2);
m_wire->endTransmission();
}
if (writeCallback) {
writeCallback(m_addr, data[0], &(data[1]), 1);
}
}

View File

@ -0,0 +1,56 @@
// Based on the BBQ10 Keyboard
#include "concurrency/NotifiedWorkerThread.h"
#include "configuration.h"
#include <Wire.h>
#include <main.h>
class MPR121Keyboard
{
public:
typedef uint8_t (*i2c_com_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);
enum MPR121States { Init = 0, Idle, Held, HeldLong, Busy };
MPR121States state;
int8_t last_key;
uint32_t last_tap;
uint8_t char_idx;
String queue;
MPR121Keyboard();
void begin(uint8_t addr = MPR121_KB_ADDR, TwoWire *wire = &Wire);
void begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr = MPR121_KB_ADDR);
void reset(void);
void attachInterrupt(uint8_t pin, void (*func)(void)) const;
void detachInterrupt(uint8_t pin) const;
void trigger(void);
void pressed(uint16_t value);
void held(uint16_t value);
void released(void);
uint8_t status(void) const;
uint8_t keyCount(void) const;
uint8_t keyCount(uint16_t value) const;
bool hasEvent(void);
char dequeueEvent(void);
void queueEvent(char);
uint8_t readRegister8(uint8_t reg) const;
uint16_t readRegister16(uint8_t reg) const;
void writeRegister(uint8_t reg, uint8_t value);
private:
TwoWire *m_wire;
uint8_t m_addr;
i2c_com_fptr_t readCallback;
i2c_com_fptr_t writeCallback;
};

View File

@ -16,8 +16,8 @@ void CardKbI2cImpl::init()
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO)
if (cardkb_found.address == 0x00) {
LOG_DEBUG("Rescanning for I2C keyboard");
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR};
uint8_t i2caddr_asize = 3;
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR, MPR121_KB_ADDR};
uint8_t i2caddr_asize = 4;
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
#if WIRE_INTERFACES_COUNT == 2
@ -43,12 +43,17 @@ void CardKbI2cImpl::init()
// assign an arbitrary value to distinguish from other models
kb_model = 0x11;
break;
case ScanI2C::DeviceType::MPR121KB:
// assign an arbitrary value to distinguish from other models
kb_model = 0x37;
break;
default:
// use this as default since it's also just zero
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00", kb_info.type);
kb_model = 0x00;
}
}
LOG_DEBUG("Keyboard Type: 0x%02x Model: 0x%02x Address: 0x%02x\n", kb_info.type, kb_model, cardkb_found.address);
if (cardkb_found.address == 0x00) {
disable();
return;

View File

@ -40,6 +40,9 @@ int32_t KbI2cBase::runOnce()
Q10keyboard.begin(BBQ10_KB_ADDR, &Wire1);
Q10keyboard.setBacklight(0);
}
if (cardkb_found.address == MPR121_KB_ADDR) {
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire1);
}
break;
#endif
case ScanI2C::WIRE:
@ -49,6 +52,9 @@ int32_t KbI2cBase::runOnce()
Q10keyboard.begin(BBQ10_KB_ADDR, &Wire);
Q10keyboard.setBacklight(0);
}
if (cardkb_found.address == MPR121_KB_ADDR) {
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire);
}
break;
case ScanI2C::NO_I2C:
default:
@ -157,6 +163,69 @@ int32_t KbI2cBase::runOnce()
}
break;
}
case 0x37: { // MPR121
MPRkeyboard.trigger();
InputEvent e;
while (MPRkeyboard.hasEvent()) {
char nextEvent = MPRkeyboard.dequeueEvent();
e.inputEvent = ANYKEY;
e.kbchar = 0x00;
e.source = this->_originName;
switch (nextEvent) {
case 0x00: // MPR121_NONE
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.kbchar = 0x00;
break;
case 0x90: // MPR121_REBOOT
e.inputEvent = ANYKEY;
e.kbchar = INPUT_BROKER_MSG_REBOOT;
break;
case 0xb4: // MPR121_LEFT
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
e.kbchar = 0x00;
break;
case 0xb5: // MPR121_UP
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
e.kbchar = 0x00;
break;
case 0xb6: // MPR121_DOWN
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
e.kbchar = 0x00;
break;
case 0xb7: // MPR121_RIGHT
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.kbchar = 0x00;
break;
case 0x1b: // MPR121_ESC
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
e.kbchar = 0x1b;
break;
case 0x08: // MPR121_BSP
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
e.kbchar = 0x08;
break;
case 0x0d: // MPR121_SELECT
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
e.kbchar = 0x0d;
break;
default:
if (nextEvent > 127) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.kbchar = 0x00;
break;
}
e.inputEvent = ANYKEY;
e.kbchar = nextEvent;
break;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
LOG_DEBUG("MP121 Notifying: %i Char: %i", e.inputEvent, e.kbchar);
this->notifyObservers(&e);
}
}
break;
}
case 0x02: {
// RAK14004
uint8_t rDataBuf[8] = {0};

View File

@ -2,6 +2,7 @@
#include "BBQ10Keyboard.h"
#include "InputBroker.h"
#include "MPR121Keyboard.h"
#include "Wire.h"
#include "concurrency/OSThread.h"
@ -19,5 +20,6 @@ class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OST
TwoWire *i2cBus = 0;
BBQ10Keyboard Q10keyboard;
MPR121Keyboard MPRkeyboard;
bool is_sym = false;
};
};

View File

@ -526,6 +526,10 @@ void setup()
case ScanI2C::DeviceType::PCF8574A:
kb_model = 0x12;
break;
case ScanI2C::DeviceType::MPR121KB:
// assign an arbitrary value to distinguish from other models
kb_model = 0x37;
break;
default:
// use this as default since it's also just zero
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00", kb_info.type);

View File

@ -117,13 +117,18 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
static const uint8_t defaultpsk0[] = USERPREFS_CHANNEL_0_PSK;
memcpy(channelSettings.psk.bytes, defaultpsk0, sizeof(defaultpsk0));
channelSettings.psk.size = sizeof(defaultpsk0);
#endif
#ifdef USERPREFS_CHANNEL_0_NAME
strcpy(channelSettings.name, USERPREFS_CHANNEL_0_NAME);
#endif
#ifdef USERPREFS_CHANNEL_0_PRECISION
channelSettings.module_settings.position_precision = USERPREFS_CHANNEL_0_PRECISION;
#endif
#ifdef USERPREFS_CHANNEL_0_UPLINK_ENABLED
channelSettings.uplink_enabled = USERPREFS_CHANNEL_0_UPLINK_ENABLED;
#endif
#ifdef USERPREFS_CHANNEL_0_DOWNLINK_ENABLED
channelSettings.downlink_enabled = USERPREFS_CHANNEL_0_DOWNLINK_ENABLED;
#endif
break;
case 1:
@ -131,13 +136,18 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
static const uint8_t defaultpsk1[] = USERPREFS_CHANNEL_1_PSK;
memcpy(channelSettings.psk.bytes, defaultpsk1, sizeof(defaultpsk1));
channelSettings.psk.size = sizeof(defaultpsk1);
#endif
#ifdef USERPREFS_CHANNEL_1_NAME
strcpy(channelSettings.name, USERPREFS_CHANNEL_1_NAME);
#endif
#ifdef USERPREFS_CHANNEL_1_PRECISION
channelSettings.module_settings.position_precision = USERPREFS_CHANNEL_1_PRECISION;
#endif
#ifdef USERPREFS_CHANNEL_1_UPLINK_ENABLED
channelSettings.uplink_enabled = USERPREFS_CHANNEL_1_UPLINK_ENABLED;
#endif
#ifdef USERPREFS_CHANNEL_1_DOWNLINK_ENABLED
channelSettings.downlink_enabled = USERPREFS_CHANNEL_1_DOWNLINK_ENABLED;
#endif
break;
case 2:
@ -145,13 +155,18 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
static const uint8_t defaultpsk2[] = USERPREFS_CHANNEL_2_PSK;
memcpy(channelSettings.psk.bytes, defaultpsk2, sizeof(defaultpsk2));
channelSettings.psk.size = sizeof(defaultpsk2);
#endif
#ifdef USERPREFS_CHANNEL_2_NAME
strcpy(channelSettings.name, USERPREFS_CHANNEL_2_NAME);
#endif
#ifdef USERPREFS_CHANNEL_2_PRECISION
channelSettings.module_settings.position_precision = USERPREFS_CHANNEL_2_PRECISION;
#endif
#ifdef USERPREFS_CHANNEL_2_UPLINK_ENABLED
channelSettings.uplink_enabled = USERPREFS_CHANNEL_2_UPLINK_ENABLED;
#endif
#ifdef USERPREFS_CHANNEL_2_DOWNLINK_ENABLED
channelSettings.downlink_enabled = USERPREFS_CHANNEL_2_DOWNLINK_ENABLED;
#endif
break;
default:

View File

@ -43,6 +43,15 @@ uint32_t Default::getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t d
return getConfiguredOrDefaultMs(configured, defaultValue) * congestionScalingCoefficient(numOnlineNodes);
}
uint32_t Default::getConfiguredOrMinimumValue(uint32_t configured, uint32_t minValue)
{
// If zero, intervals should be coalesced later by getConfiguredOrDefault... methods
if (configured == 0)
return configured;
return configured < minValue ? minValue : configured;
}
uint8_t Default::getConfiguredOrDefaultHopLimit(uint8_t configured)
{
#if USERPREFS_EVENT_MODE

View File

@ -6,8 +6,9 @@
#define THIRTY_SECONDS_MS 30 * 1000
#define FIVE_SECONDS_MS 5 * 1000
#define min_default_telemetry_interval_secs 30 * 60
#define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60)
#define default_telemetry_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 30 * 60)
#define default_telemetry_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 60 * 60)
#define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60)
#define default_wait_bluetooth_secs IF_ROUTER(1, 60)
#define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep
@ -35,6 +36,7 @@ class Default
static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue);
static uint32_t getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t defaultValue, uint32_t numOnlineNodes);
static uint8_t getConfiguredOrDefaultHopLimit(uint8_t configured);
static uint32_t getConfiguredOrMinimumValue(uint32_t configured, uint32_t minValue);
private:
static float congestionScalingCoefficient(int numOnlineNodes)

View File

@ -44,7 +44,7 @@ bool FloodingRouter::isRebroadcaster()
void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c)
{
bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0);
if (isAckorReply && !isToUs(p) && p->to != NODENUM_BROADCAST) {
if (isAckorReply && !isToUs(p) && !isBroadcast(p->to)) {
// do not flood direct message that is ACKed or replied to
LOG_DEBUG("Rxd an ACK/reply not for me, cancel rebroadcast.");
Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM

View File

@ -67,8 +67,10 @@ template <typename T> bool LR11x0Interface<T>::init()
power = LR1110_MAX_POWER;
if ((power > LR1120_MAX_POWER) &&
(config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) // clamp again if wide freq range
(config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) { // clamp again if wide freq range
power = LR1120_MAX_POWER;
preambleLength = 12; // 12 is the default for operation above 2GHz
}
limitPower();

View File

@ -86,7 +86,7 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
// Was this message directed to us specifically? Will be false if we are sniffing someone elses packets
auto ourNodeNum = nodeDB->getNodeNum();
bool toUs = mp.to == NODENUM_BROADCAST || isToUs(&mp);
bool toUs = isBroadcast(mp.to) || isToUs(&mp);
for (auto i = modules->begin(); i != modules->end(); ++i) {
auto &pi = **i;

View File

@ -57,4 +57,6 @@ bool isFromUs(const meshtastic_MeshPacket *p);
bool isToUs(const meshtastic_MeshPacket *p);
/* Some clients might not properly set priority, therefore we fix it here. */
void fixPriority(meshtastic_MeshPacket *p);
void fixPriority(meshtastic_MeshPacket *p);
bool isBroadcast(uint32_t dest);

View File

@ -171,6 +171,22 @@ NodeDB::NodeDB()
resetRadioConfig(); // If bogus settings got saved, then fix them
// nodeDB->LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d", config.lora.region, myNodeInfo.my_node_num, numMeshNodes);
// If we are setup to broadcast on the default channel, ensure that the telemetry intervals are coerced to the minimum value
// of 30 minutes or more
if (channels.isDefaultChannel(channels.getPrimaryIndex())) {
LOG_DEBUG("Coercing telemetry to min of 30 minutes on defaults");
moduleConfig.telemetry.device_update_interval = Default::getConfiguredOrMinimumValue(
moduleConfig.telemetry.device_update_interval, min_default_telemetry_interval_secs);
moduleConfig.telemetry.environment_update_interval = Default::getConfiguredOrMinimumValue(
moduleConfig.telemetry.environment_update_interval, min_default_telemetry_interval_secs);
moduleConfig.telemetry.air_quality_interval = Default::getConfiguredOrMinimumValue(
moduleConfig.telemetry.air_quality_interval, min_default_telemetry_interval_secs);
moduleConfig.telemetry.power_update_interval = Default::getConfiguredOrMinimumValue(
moduleConfig.telemetry.power_update_interval, min_default_telemetry_interval_secs);
moduleConfig.telemetry.health_update_interval = Default::getConfiguredOrMinimumValue(
moduleConfig.telemetry.health_update_interval, min_default_telemetry_interval_secs);
}
if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate)))
saveWhat |= SEGMENT_DEVICESTATE;
if (configCRC != crc32Buffer(&config, sizeof(config)))
@ -206,6 +222,11 @@ bool isToUs(const meshtastic_MeshPacket *p)
return p->to == nodeDB->getNodeNum();
}
bool isBroadcast(uint32_t dest)
{
return dest == NODENUM_BROADCAST || dest == NODENUM_BROADCAST_NO_LORA;
}
bool NodeDB::resetRadioConfig(bool factory_reset)
{
bool didFactoryReset = false;

View File

@ -467,7 +467,10 @@ void RadioLibInterface::setStandby()
void RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
{
printPacket("Starting low level send", txp);
if (disabled || !config.lora.tx_enabled) {
if (txp->to == NODENUM_BROADCAST_NO_LORA) {
LOG_DEBUG("Drop Tx packet because dest is broadcast no-lora");
packetPool.release(txp);
} else if (disabled || !config.lora.tx_enabled) {
LOG_WARN("Drop Tx packet because LoRa Tx disabled");
packetPool.release(txp);
} else {

View File

@ -181,7 +181,7 @@ ErrorCode Router::sendLocal(meshtastic_MeshPacket *p, RxSource src)
} else {
// If we are sending a broadcast, we also treat it as if we just received it ourself
// this allows local apps (and PCs) to see broadcasts sourced locally
if (p->to == NODENUM_BROADCAST) {
if (isBroadcast(p->to)) {
handleReceived(p, src);
}
@ -240,7 +240,7 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
// assert
// Never set the want_ack flag on broadcast packets sent over the air.
if (p->to == NODENUM_BROADCAST)
if (isBroadcast(p->to))
p->want_ack = false;
// Up until this point we might have been using 0 for the from address (if it started with the phone), but when we send over
@ -328,7 +328,7 @@ bool perhapsDecode(meshtastic_MeshPacket *p)
memcpy(ScratchEncrypted, p->encrypted.bytes, rawSize);
#if !(MESHTASTIC_EXCLUDE_PKI)
// Attempt PKI decryption first
if (p->channel == 0 && isToUs(p) && p->to > 0 && p->to != NODENUM_BROADCAST && nodeDB->getMeshNode(p->from) != nullptr &&
if (p->channel == 0 && isToUs(p) && p->to > 0 && !isBroadcast(p->to) && nodeDB->getMeshNode(p->from) != nullptr &&
nodeDB->getMeshNode(p->from)->user.public_key.size > 0 && nodeDB->getMeshNode(p->to)->user.public_key.size > 0 &&
rawSize > MESHTASTIC_PKC_OVERHEAD) {
LOG_DEBUG("Attempting PKI decryption");
@ -493,7 +493,7 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
// Don't use PKC if it's not explicitly requested and a non-primary channel is requested
!(p->pki_encrypted != true && p->channel > 0) &&
// Check for valid keys and single node destination
config.security.private_key.size == 32 && p->to != NODENUM_BROADCAST && node != nullptr &&
config.security.private_key.size == 32 && !isBroadcast(p->to) && node != nullptr &&
// Check for a known public key for the destination
(node->user.public_key.size == 32) &&
// Some portnums either make no sense to send with PKC
@ -615,7 +615,7 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
#if !MESHTASTIC_EXCLUDE_MQTT
// Mark as pki_encrypted if it is not yet decoded and MQTT encryption is also enabled, hash matches and it's a DM not to
// us (because we would be able to decrypt it)
if (!decoded && moduleConfig.mqtt.encryption_enabled && p->channel == 0x00 && p->to != NODENUM_BROADCAST && !isToUs(p))
if (!decoded && moduleConfig.mqtt.encryption_enabled && p->channel == 0x00 && !isBroadcast(p->to) && !isToUs(p))
p_encrypted->pki_encrypted = true;
// After potentially altering it, publish received message to MQTT if we're not the original transmitter of the packet
if ((decoded || p_encrypted->pki_encrypted) && moduleConfig.mqtt.enabled && !isFromUs(p) && mqtt)

View File

@ -75,7 +75,10 @@ typedef enum _meshtastic_Config_DeviceConfig_RebroadcastMode {
but takes it step further by also ignoring messages from nodenums not in the node's known list (NodeDB) */
meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY = 3,
/* Only permitted for SENSOR, TRACKER and TAK_TRACKER roles, this will inhibit all rebroadcasts, not unlike CLIENT_MUTE role. */
meshtastic_Config_DeviceConfig_RebroadcastMode_NONE = 4
meshtastic_Config_DeviceConfig_RebroadcastMode_NONE = 4,
/* Ignores packets from non-standard portnums such as: TAK, RangeTest, PaxCounter, etc.
Only rebroadcasts packets with standard portnums: NodeInfo, Text, Position, Telemetry, and Routing. */
meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY = 5
} meshtastic_Config_DeviceConfig_RebroadcastMode;
/* Bit field of boolean configuration options, indicating which optional
@ -587,8 +590,8 @@ extern "C" {
#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_TAK_TRACKER+1))
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN meshtastic_Config_DeviceConfig_RebroadcastMode_ALL
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_NONE
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_ARRAYSIZE ((meshtastic_Config_DeviceConfig_RebroadcastMode)(meshtastic_Config_DeviceConfig_RebroadcastMode_NONE+1))
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_ARRAYSIZE ((meshtastic_Config_DeviceConfig_RebroadcastMode)(meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY+1))
#define _meshtastic_Config_PositionConfig_PositionFlags_MIN meshtastic_Config_PositionConfig_PositionFlags_UNSET
#define _meshtastic_Config_PositionConfig_PositionFlags_MAX meshtastic_Config_PositionConfig_PositionFlags_SPEED

View File

@ -765,6 +765,7 @@ typedef struct _meshtastic_NodeInfo {
bool is_favorite;
} meshtastic_NodeInfo;
typedef PB_BYTES_ARRAY_T(16) meshtastic_MyNodeInfo_device_id_t;
/* Unique local debugging info for this node
Note: we don't include position or the user info, because that will come in the
Sent to the phone in response to WantNodes. */
@ -778,6 +779,8 @@ typedef struct _meshtastic_MyNodeInfo {
/* 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;
/* Unique hardware identifier for this device */
meshtastic_MyNodeInfo_device_id_t device_id;
} meshtastic_MyNodeInfo;
/* Debug output from the device.
@ -1112,7 +1115,7 @@ 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, 0, 0, {0, {0}}, 0}
#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0}
#define meshtastic_MyNodeInfo_init_default {0, 0, 0}
#define meshtastic_MyNodeInfo_init_default {0, 0, 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}}
@ -1137,7 +1140,7 @@ 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, 0, 0, {0, {0}}, 0}
#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0}
#define meshtastic_MyNodeInfo_init_zero {0, 0, 0}
#define meshtastic_MyNodeInfo_init_zero {0, 0, 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}}
@ -1244,6 +1247,7 @@ extern "C" {
#define meshtastic_MyNodeInfo_my_node_num_tag 1
#define meshtastic_MyNodeInfo_reboot_count_tag 8
#define meshtastic_MyNodeInfo_min_app_version_tag 11
#define meshtastic_MyNodeInfo_device_id_tag 12
#define meshtastic_LogRecord_message_tag 1
#define meshtastic_LogRecord_time_tag 2
#define meshtastic_LogRecord_source_tag 3
@ -1446,7 +1450,8 @@ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10)
#define meshtastic_MyNodeInfo_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, my_node_num, 1) \
X(a, STATIC, SINGULAR, UINT32, reboot_count, 8) \
X(a, STATIC, SINGULAR, UINT32, min_app_version, 11)
X(a, STATIC, SINGULAR, UINT32, min_app_version, 11) \
X(a, STATIC, SINGULAR, BYTES, device_id, 12)
#define meshtastic_MyNodeInfo_CALLBACK NULL
#define meshtastic_MyNodeInfo_DEFAULT NULL
@ -1669,7 +1674,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
#define meshtastic_LogRecord_size 426
#define meshtastic_MeshPacket_size 367
#define meshtastic_MqttClientProxyMessage_size 501
#define meshtastic_MyNodeInfo_size 18
#define meshtastic_MyNodeInfo_size 36
#define meshtastic_NeighborInfo_size 258
#define meshtastic_Neighbor_size 22
#define meshtastic_NodeInfo_size 317

View File

@ -122,7 +122,7 @@ Will be used for broadcast.
int32_t NeighborInfoModule::runOnce()
{
if (airTime->isTxAllowedChannelUtil(true) && airTime->isTxAllowedAirUtil()) {
sendNeighborInfo(NODENUM_BROADCAST, false);
sendNeighborInfo(NODENUM_BROADCAST_NO_LORA, false);
}
return Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_neighbor_info_broadcast_secs);
}

View File

@ -16,7 +16,7 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
bool hasChanged = nodeDB->updateUser(getFrom(&mp), p, mp.channel);
bool wasBroadcast = mp.to == NODENUM_BROADCAST;
bool wasBroadcast = isBroadcast(mp.to);
// Show new nodes on LCD screen
if (wasBroadcast) {

View File

@ -10,11 +10,7 @@ RoutingModule *routingModule;
bool RoutingModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Routing *r)
{
printPacket("Routing sniffing", &mp);
router->sniffReceived(&mp, r);
bool maybePKI =
mp.which_payload_variant == meshtastic_MeshPacket_encrypted_tag && mp.channel == 0 && mp.to != NODENUM_BROADCAST;
bool maybePKI = mp.which_payload_variant == meshtastic_MeshPacket_encrypted_tag && mp.channel == 0 && !isBroadcast(mp.to);
// Beginning of logic whether to drop the packet based on Rebroadcast mode
if (mp.which_payload_variant == meshtastic_MeshPacket_encrypted_tag &&
(config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY ||
@ -26,9 +22,12 @@ bool RoutingModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mesh
return false;
}
printPacket("Routing sniffing", &mp);
router->sniffReceived(&mp, r);
// FIXME - move this to a non promsicious PhoneAPI module?
// Note: we are careful not to send back packets that started with the phone back to the phone
if ((mp.to == NODENUM_BROADCAST || isToUs(&mp)) && (mp.from != 0)) {
if ((isBroadcast(mp.to) || isToUs(&mp)) && (mp.from != 0)) {
printPacket("Delivering rx packet", &mp);
service->handleFromRadio(&mp);
}

View File

@ -706,22 +706,48 @@ bool MQTT::isValidJsonEnvelope(JSONObject &json)
bool MQTT::isPrivateIpAddress(const char address[])
{
// Min. length like 10.0.0.0, max like 192.168.255.255
// Min. length like 10.0.0.0 (8), max like 192.168.255.255:65535 (21)
size_t length = strlen(address);
if (length < 8 || length > 15) {
if (length < 8 || length > 21) {
return false;
}
// Ensure the address contains only digits and dots.
// Ensure the address contains only digits and dots and maybe a colon.
// Some limited validation is done.
// Even if it's not a valid IP address, we will know it's not a domain.
bool hasColon = false;
int numDots = 0;
for (int i = 0; i < length; i++) {
if (!isdigit(address[i]) && address[i] != '.') {
if (!isdigit(address[i]) && address[i] != '.' && address[i] != ':') {
return false;
}
// Dots can't be the first character, immediately follow another dot,
// occur more than 3 times, or occur after a colon.
if (address[i] == '.') {
if (++numDots > 3 || i == 0 || address[i - 1] == '.' || hasColon) {
return false;
}
}
// There can only be a single colon, and it can only occur after 3 dots
else if (address[i] == ':') {
if (hasColon || numDots < 3) {
return false;
}
hasColon = true;
}
}
// Final validation for IPv4 address and port format.
// Note that the values of octets haven't been tested, only the address format.
if (numDots != 3) {
return false;
}
// Check the easy ones first.
if (strcmp(address, "127.0.0.1") == 0 || strncmp(address, "10.", 3) == 0 || strncmp(address, "192.168", 7) == 0) {
if (strcmp(address, "127.0.0.1") == 0 || strncmp(address, "10.", 3) == 0 || strncmp(address, "192.168", 7) == 0 ||
strncmp(address, "169.254", 7) == 0) {
return true;
}

View File

@ -26,6 +26,8 @@
*/
// #define USERPREFS_CHANNEL_0_NAME "DEFCONnect"
// #define USERPREFS_CHANNEL_0_PRECISION 14
// #define USERPREFS_CHANNEL_0_UPLINK_ENABLED true
// #define USERPREFS_CHANNEL_0_DOWNLINK_ENABLED true
/*
#define USERPREFS_CHANNEL_1_PSK \
{ \
@ -35,6 +37,8 @@
*/
// #define USERPREFS_CHANNEL_1_NAME "REPLACEME"
// #define USERPREFS_CHANNEL_1_PRECISION 14
// #define USERPREFS_CHANNEL_1_UPLINK_ENABLED true
// #define USERPREFS_CHANNEL_1_DOWNLINK_ENABLED true
/*
#define USERPREFS_CHANNEL_2_PSK \
{ \
@ -44,6 +48,8 @@
*/
// #define USERPREFS_CHANNEL_2_NAME "REPLACEME"
// #define USERPREFS_CHANNEL_2_PRECISION 14
// #define USERPREFS_CHANNEL_2_UPLINK_ENABLED true
// #define USERPREFS_CHANNEL_2_DOWNLINK_ENABLED true
// #define USERPREFS_CONFIG_OWNER_LONG_NAME "My Long Name"
// #define USERPREFS_CONFIG_OWNER_SHORT_NAME "MLN"

View File

@ -1,4 +1,5 @@
[env:heltec-v2_1]
board_level = extra
;build_type = debug ; to make it possible to step through our jtag debugger
extends = esp32_base
board = heltec_wifi_lora_32_V2

View File

@ -1,5 +1,6 @@
[env:heltec-v2_0]
;build_type = debug ; to make it possible to step through our jtag debugger
;build_type = debug ; to make it possible to step through our jtag debugger
board_level = extra
extends = esp32_base
board = heltec_wifi_lora_32_V2
build_flags =

View File

@ -54,7 +54,7 @@
#define SX126X_DIO1 LORA_DIO1
#define SX126X_BUSY LORA_BUSY
#define SX126X_RESET LORA_RESET
#define SX126X_DIO2_AS_RF_SWITCH // Antenna switch CTRL
#define SX126X_POWER_EN LORA_DIO4 // Antenna switch !CTRL via GPIO17
#define SX126X_DIO2_AS_RF_SWITCH // Antenna switch CTRL
#define SX126X_RXEN LORA_DIO4 // Antenna switch !CTRL via GPIO17
// #define SX126X_DIO3_TCXO_VOLTAGE 1.8
#endif
#endif

View File

@ -1,4 +1,5 @@
[env:tlora-v1]
board_level = extra
extends = esp32_base
board = ttgo-lora32-v1
build_flags =

View File

@ -1,4 +1,5 @@
[env:tlora_v1_3]
board_level = extra
extends = esp32_base
board = ttgo-lora32-v1
build_flags =

View File

@ -1,4 +1,5 @@
[env:tlora-v2]
board_level = extra
extends = esp32_base
board = ttgo-lora32-v1
build_flags =

View File

@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 5
build = 7
build = 8