mirror of
https://github.com/meshtastic/firmware.git
synced 2025-05-01 03:39:18 +00:00
Merge branch 'master' into t3s3-1121
This commit is contained in:
commit
5c77e29d66
@ -13,10 +13,7 @@
|
|||||||
},
|
},
|
||||||
"customizations": {
|
"customizations": {
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"extensions": [
|
"extensions": ["ms-vscode.cpptools", "platformio.platformio-ide"]
|
||||||
"ms-vscode.cpptools",
|
|
||||||
"platformio.platformio-ide",
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -24,5 +21,5 @@
|
|||||||
"forwardPorts": [4403],
|
"forwardPorts": [4403],
|
||||||
|
|
||||||
// Run commands to prepare the container for use
|
// Run commands to prepare the container for use
|
||||||
"postCreateCommand": ".devcontainer/setup.sh",
|
"postCreateCommand": ".devcontainer/setup.sh"
|
||||||
}
|
}
|
||||||
|
12
SECURITY.md
Normal file
12
SECURITY.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
| Firmware Version | Supported |
|
||||||
|
| ---------------- | ------------------ |
|
||||||
|
| 2.5.x | :white_check_mark: |
|
||||||
|
| <= 2.4.x | :x: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
We support the private reporting of potential security vulnerabilities. Please go to the Security tab to file a report with a description of the potential vulnerability and reproduction scripts (preferred) or steps, and our developers will review.
|
@ -147,6 +147,8 @@ using namespace meshtastic;
|
|||||||
*/
|
*/
|
||||||
static HasBatteryLevel *batteryLevel; // Default to NULL for no battery level sensor
|
static HasBatteryLevel *batteryLevel; // Default to NULL for no battery level sensor
|
||||||
|
|
||||||
|
#ifdef BATTERY_PIN
|
||||||
|
|
||||||
static void adcEnable()
|
static void adcEnable()
|
||||||
{
|
{
|
||||||
#ifdef ADC_CTRL // enable adc voltage divider when we need to read
|
#ifdef ADC_CTRL // enable adc voltage divider when we need to read
|
||||||
@ -171,6 +173,8 @@ static void adcDisable()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple battery level sensor that assumes the battery voltage is attached via a voltage-divider to an analog input
|
* A simple battery level sensor that assumes the battery voltage is attached via a voltage-divider to an analog input
|
||||||
*/
|
*/
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "PowerMon.h"
|
#include "PowerMon.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "Throttle.h"
|
#include "Throttle.h"
|
||||||
|
#include "meshUtils.h"
|
||||||
|
|
||||||
#include "main.h" // pmu_found
|
#include "main.h" // pmu_found
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
@ -511,7 +512,7 @@ bool GPS::setup()
|
|||||||
delay(250);
|
delay(250);
|
||||||
_serial_gps->write("$CFGMSG,6,1,0\r\n");
|
_serial_gps->write("$CFGMSG,6,1,0\r\n");
|
||||||
delay(250);
|
delay(250);
|
||||||
} else if (gnssModel == GNSS_MODEL_AG3335 || gnssModel == GNSS_MODEL_AG3352) {
|
} else if (IS_ONE_OF(gnssModel, GNSS_MODEL_AG3335, GNSS_MODEL_AG3352)) {
|
||||||
|
|
||||||
_serial_gps->write("$PAIR066,1,0,1,0,0,1*3B\r\n"); // Enable GPS+GALILEO+NAVIC
|
_serial_gps->write("$PAIR066,1,0,1,0,0,1*3B\r\n"); // Enable GPS+GALILEO+NAVIC
|
||||||
|
|
||||||
@ -553,7 +554,7 @@ bool GPS::setup()
|
|||||||
} else {
|
} else {
|
||||||
LOG_INFO("GNSS module configuration saved!\n");
|
LOG_INFO("GNSS module configuration saved!\n");
|
||||||
}
|
}
|
||||||
} else if (gnssModel == GNSS_MODEL_UBLOX7 || gnssModel == GNSS_MODEL_UBLOX8 || gnssModel == GNSS_MODEL_UBLOX9) {
|
} else if (IS_ONE_OF(gnssModel, GNSS_MODEL_UBLOX7, GNSS_MODEL_UBLOX8, GNSS_MODEL_UBLOX9)) {
|
||||||
if (gnssModel == GNSS_MODEL_UBLOX7) {
|
if (gnssModel == GNSS_MODEL_UBLOX7) {
|
||||||
LOG_DEBUG("Setting GPS+SBAS\n");
|
LOG_DEBUG("Setting GPS+SBAS\n");
|
||||||
msglen = makeUBXPacket(0x06, 0x3e, sizeof(_message_GNSS_7), _message_GNSS_7);
|
msglen = makeUBXPacket(0x06, 0x3e, sizeof(_message_GNSS_7), _message_GNSS_7);
|
||||||
@ -826,8 +827,7 @@ void GPS::setPowerPMU(bool on)
|
|||||||
void GPS::setPowerUBLOX(bool on, uint32_t sleepMs)
|
void GPS::setPowerUBLOX(bool on, uint32_t sleepMs)
|
||||||
{
|
{
|
||||||
// Abort: if not UBLOX hardware
|
// Abort: if not UBLOX hardware
|
||||||
if (!(gnssModel == GNSS_MODEL_UBLOX6 || gnssModel == GNSS_MODEL_UBLOX7 || gnssModel == GNSS_MODEL_UBLOX8 ||
|
if (!IS_ONE_OF(gnssModel, GNSS_MODEL_UBLOX6, GNSS_MODEL_UBLOX7, GNSS_MODEL_UBLOX8, GNSS_MODEL_UBLOX9, GNSS_MODEL_UBLOX10))
|
||||||
gnssModel == GNSS_MODEL_UBLOX9 || gnssModel == GNSS_MODEL_UBLOX10))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If waking
|
// If waking
|
||||||
@ -910,8 +910,7 @@ void GPS::down()
|
|||||||
// If not, fallback to GPS_HARDSLEEP instead
|
// If not, fallback to GPS_HARDSLEEP instead
|
||||||
bool softsleepSupported = false;
|
bool softsleepSupported = false;
|
||||||
// U-blox is supported via PMREQ
|
// U-blox is supported via PMREQ
|
||||||
if (gnssModel == GNSS_MODEL_UBLOX6 || gnssModel == GNSS_MODEL_UBLOX7 || gnssModel == GNSS_MODEL_UBLOX8 ||
|
if (IS_ONE_OF(gnssModel, GNSS_MODEL_UBLOX6, GNSS_MODEL_UBLOX7, GNSS_MODEL_UBLOX8, GNSS_MODEL_UBLOX9, GNSS_MODEL_UBLOX10))
|
||||||
gnssModel == GNSS_MODEL_UBLOX9 || gnssModel == GNSS_MODEL_UBLOX10)
|
|
||||||
softsleepSupported = true;
|
softsleepSupported = true;
|
||||||
#ifdef PIN_GPS_STANDBY // L76B, L76K and clones have a standby pin
|
#ifdef PIN_GPS_STANDBY // L76B, L76K and clones have a standby pin
|
||||||
softsleepSupported = true;
|
softsleepSupported = true;
|
||||||
@ -987,8 +986,8 @@ int32_t GPS::runOnce()
|
|||||||
setConnected();
|
setConnected();
|
||||||
} else {
|
} else {
|
||||||
if ((config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) &&
|
if ((config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) &&
|
||||||
(gnssModel == GNSS_MODEL_UBLOX6 || gnssModel == GNSS_MODEL_UBLOX7 || gnssModel == GNSS_MODEL_UBLOX8 ||
|
IS_ONE_OF(gnssModel, GNSS_MODEL_UBLOX6, GNSS_MODEL_UBLOX7, GNSS_MODEL_UBLOX8, GNSS_MODEL_UBLOX9,
|
||||||
gnssModel == GNSS_MODEL_UBLOX9 || gnssModel == GNSS_MODEL_UBLOX10)) {
|
GNSS_MODEL_UBLOX10)) {
|
||||||
// reset the GPS on next bootup
|
// reset the GPS on next bootup
|
||||||
if (devicestate.did_gps_reset && scheduling.elapsedSearchMs() > 60 * 1000UL && !hasFlow()) {
|
if (devicestate.did_gps_reset && scheduling.elapsedSearchMs() > 60 * 1000UL && !hasFlow()) {
|
||||||
LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n");
|
LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n");
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "graphics/Screen.h"
|
#include "graphics/Screen.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mesh/generated/meshtastic/config.pb.h"
|
#include "mesh/generated/meshtastic/config.pb.h"
|
||||||
|
#include "meshUtils.h"
|
||||||
#include "modules/Modules.h"
|
#include "modules/Modules.h"
|
||||||
#include "shutdown.h"
|
#include "shutdown.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
@ -628,9 +629,9 @@ void setup()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// only play start melody when role is not tracker or sensor
|
// only play start melody when role is not tracker or sensor
|
||||||
if (config.power.is_power_saving == true && (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER ||
|
if (config.power.is_power_saving == true &&
|
||||||
config.device.role == meshtastic_Config_DeviceConfig_Role_TAK_TRACKER ||
|
IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TRACKER,
|
||||||
config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR))
|
meshtastic_Config_DeviceConfig_Role_TAK_TRACKER, meshtastic_Config_DeviceConfig_Role_SENSOR))
|
||||||
LOG_DEBUG("Tracker/Sensor: Skipping start melody\n");
|
LOG_DEBUG("Tracker/Sensor: Skipping start melody\n");
|
||||||
else
|
else
|
||||||
playStartMelody();
|
playStartMelody();
|
||||||
|
@ -296,29 +296,8 @@ template <typename T> bool LR11x0Interface<T>::isActivelyReceiving()
|
|||||||
{
|
{
|
||||||
// The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet
|
// The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet
|
||||||
// received and handled the interrupt for reading the packet/handling errors.
|
// received and handled the interrupt for reading the packet/handling errors.
|
||||||
|
return receiveDetected(lora.getIrqStatus(), RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID,
|
||||||
uint16_t irq = lora.getIrqStatus();
|
RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED);
|
||||||
bool detected = (irq & (RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID | RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED));
|
|
||||||
// Handle false detections
|
|
||||||
if (detected) {
|
|
||||||
if (!activeReceiveStart) {
|
|
||||||
activeReceiveStart = millis();
|
|
||||||
} else if (!Throttle::isWithinTimespanMs(activeReceiveStart, 2 * preambleTimeMsec) &&
|
|
||||||
!(irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID)) {
|
|
||||||
// The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag
|
|
||||||
activeReceiveStart = 0;
|
|
||||||
LOG_DEBUG("Ignore false preamble detection.\n");
|
|
||||||
return false;
|
|
||||||
} else if (!Throttle::isWithinTimespanMs(activeReceiveStart, maxPacketTimeMsec)) {
|
|
||||||
// We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag
|
|
||||||
activeReceiveStart = 0;
|
|
||||||
LOG_DEBUG("Ignore false header detection.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (detected) LOG_DEBUG("rx detected\n");
|
|
||||||
return detected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> bool LR11x0Interface<T>::sleep()
|
template <typename T> bool LR11x0Interface<T>::sleep()
|
||||||
|
@ -65,7 +65,4 @@ template <class T> class LR11x0Interface : public RadioLibInterface
|
|||||||
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;
|
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;
|
||||||
|
|
||||||
virtual void setStandby() override;
|
virtual void setStandby() override;
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t activeReceiveStart = 0;
|
|
||||||
};
|
};
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "Observer.h"
|
#include "Observer.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <algorithm>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -129,6 +129,28 @@ bool RadioLibInterface::canSendImmediately()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RadioLibInterface::receiveDetected(uint16_t irq, ulong syncWordHeaderValidFlag, ulong preambleDetectedFlag)
|
||||||
|
{
|
||||||
|
bool detected = (irq & (syncWordHeaderValidFlag | preambleDetectedFlag));
|
||||||
|
// Handle false detections
|
||||||
|
if (detected) {
|
||||||
|
if (!activeReceiveStart) {
|
||||||
|
activeReceiveStart = millis();
|
||||||
|
} else if (!Throttle::isWithinTimespanMs(activeReceiveStart, 2 * preambleTimeMsec) && !(irq & syncWordHeaderValidFlag)) {
|
||||||
|
// The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag
|
||||||
|
activeReceiveStart = 0;
|
||||||
|
LOG_DEBUG("Ignore false preamble detection.\n");
|
||||||
|
return false;
|
||||||
|
} else if (!Throttle::isWithinTimespanMs(activeReceiveStart, maxPacketTimeMsec)) {
|
||||||
|
// We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag
|
||||||
|
activeReceiveStart = 0;
|
||||||
|
LOG_DEBUG("Ignore false header detection.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return detected;
|
||||||
|
}
|
||||||
|
|
||||||
/// Send a packet (possibly by enquing in a private fifo). This routine will
|
/// Send a packet (possibly by enquing in a private fifo). This routine will
|
||||||
/// later free() the packet to pool. This routine is not allowed to stall because it is called from
|
/// later free() the packet to pool. This routine is not allowed to stall because it is called from
|
||||||
/// bluetooth comms code. If the txmit queue is empty it might return an error
|
/// bluetooth comms code. If the txmit queue is empty it might return an error
|
||||||
|
@ -167,6 +167,10 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
|||||||
meshtastic_QueueStatus getQueueStatus();
|
meshtastic_QueueStatus getQueueStatus();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
uint32_t activeReceiveStart = 0;
|
||||||
|
|
||||||
|
bool receiveDetected(uint16_t irq, ulong syncWordHeaderValidFlag, ulong preambleDetectedFlag);
|
||||||
|
|
||||||
/** Do any hardware setup needed on entry into send configuration for the radio.
|
/** Do any hardware setup needed on entry into send configuration for the radio.
|
||||||
* Subclasses can customize, but must also call this base method */
|
* Subclasses can customize, but must also call this base method */
|
||||||
virtual void configHardwareForSend();
|
virtual void configHardwareForSend();
|
||||||
|
@ -316,29 +316,7 @@ template <typename T> bool SX126xInterface<T>::isActivelyReceiving()
|
|||||||
{
|
{
|
||||||
// The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet
|
// The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet
|
||||||
// received and handled the interrupt for reading the packet/handling errors.
|
// received and handled the interrupt for reading the packet/handling errors.
|
||||||
|
return receiveDetected(lora.getIrqFlags(), RADIOLIB_SX126X_IRQ_HEADER_VALID, RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED);
|
||||||
uint16_t irq = lora.getIrqFlags();
|
|
||||||
bool detected = (irq & (RADIOLIB_SX126X_IRQ_HEADER_VALID | RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED));
|
|
||||||
// Handle false detections
|
|
||||||
if (detected) {
|
|
||||||
if (!activeReceiveStart) {
|
|
||||||
activeReceiveStart = millis();
|
|
||||||
} else if (!Throttle::isWithinTimespanMs(activeReceiveStart, 2 * preambleTimeMsec) &&
|
|
||||||
!(irq & RADIOLIB_SX126X_IRQ_HEADER_VALID)) {
|
|
||||||
// The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag
|
|
||||||
activeReceiveStart = 0;
|
|
||||||
LOG_DEBUG("Ignore false preamble detection.\n");
|
|
||||||
return false;
|
|
||||||
} else if (!Throttle::isWithinTimespanMs(activeReceiveStart, maxPacketTimeMsec)) {
|
|
||||||
// We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag
|
|
||||||
activeReceiveStart = 0;
|
|
||||||
LOG_DEBUG("Ignore false header detection.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (detected) LOG_DEBUG("rx detected\n");
|
|
||||||
return detected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> bool SX126xInterface<T>::sleep()
|
template <typename T> bool SX126xInterface<T>::sleep()
|
||||||
|
@ -67,7 +67,4 @@ template <class T> class SX126xInterface : public RadioLibInterface
|
|||||||
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;
|
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;
|
||||||
|
|
||||||
virtual void setStandby() override;
|
virtual void setStandby() override;
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t activeReceiveStart = 0;
|
|
||||||
};
|
};
|
||||||
|
@ -290,28 +290,7 @@ template <typename T> bool SX128xInterface<T>::isChannelActive()
|
|||||||
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
|
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
|
||||||
template <typename T> bool SX128xInterface<T>::isActivelyReceiving()
|
template <typename T> bool SX128xInterface<T>::isActivelyReceiving()
|
||||||
{
|
{
|
||||||
uint16_t irq = lora.getIrqStatus();
|
return receiveDetected(lora.getIrqStatus(), RADIOLIB_SX128X_IRQ_HEADER_VALID, RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED);
|
||||||
bool detected = (irq & (RADIOLIB_SX128X_IRQ_HEADER_VALID | RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED));
|
|
||||||
|
|
||||||
// Handle false detections
|
|
||||||
if (detected) {
|
|
||||||
if (!activeReceiveStart) {
|
|
||||||
activeReceiveStart = millis();
|
|
||||||
} else if (!Throttle::isWithinTimespanMs(activeReceiveStart, 2 * preambleTimeMsec) &&
|
|
||||||
!(irq & RADIOLIB_SX128X_IRQ_HEADER_VALID)) {
|
|
||||||
// The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag
|
|
||||||
activeReceiveStart = 0;
|
|
||||||
LOG_DEBUG("Ignore false preamble detection.\n");
|
|
||||||
return false;
|
|
||||||
} else if (Throttle::isWithinTimespanMs(activeReceiveStart, maxPacketTimeMsec)) {
|
|
||||||
// We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag
|
|
||||||
activeReceiveStart = 0;
|
|
||||||
LOG_DEBUG("Ignore false header detection.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return detected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> bool SX128xInterface<T>::sleep()
|
template <typename T> bool SX128xInterface<T>::sleep()
|
||||||
|
@ -67,7 +67,4 @@ template <class T> class SX128xInterface : public RadioLibInterface
|
|||||||
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;
|
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;
|
||||||
|
|
||||||
virtual void setStandby() override;
|
virtual void setStandby() override;
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t activeReceiveStart = 0;
|
|
||||||
};
|
};
|
||||||
|
@ -81,3 +81,18 @@ bool memfll(const uint8_t *mem, uint8_t find, size_t numbytes)
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isOneOf(int item, int count, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, count);
|
||||||
|
bool found = false;
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
if (item == va_arg(args, int)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
return found;
|
||||||
|
}
|
@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "DebugConfiguration.h"
|
#include "DebugConfiguration.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <iterator>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/// C++ v17+ clamp function, limits a given value to a range defined by lo and hi
|
/// C++ v17+ clamp function, limits a given value to a range defined by lo and hi
|
||||||
@ -18,3 +21,7 @@ void printBytes(const char *label, const uint8_t *p, size_t numbytes);
|
|||||||
|
|
||||||
// is the memory region filled with a single character?
|
// is the memory region filled with a single character?
|
||||||
bool memfll(const uint8_t *mem, uint8_t find, size_t numbytes);
|
bool memfll(const uint8_t *mem, uint8_t find, size_t numbytes);
|
||||||
|
|
||||||
|
bool isOneOf(int item, int count, ...);
|
||||||
|
|
||||||
|
#define IS_ONE_OF(item, ...) isOneOf(item, sizeof((int[]){__VA_ARGS__}) / sizeof(int), __VA_ARGS__)
|
||||||
|
@ -11,6 +11,41 @@ DetectionSensorModule *detectionSensorModule;
|
|||||||
#define GPIO_POLLING_INTERVAL 100
|
#define GPIO_POLLING_INTERVAL 100
|
||||||
#define DELAYED_INTERVAL 1000
|
#define DELAYED_INTERVAL 1000
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DetectionSensorVerdictDetected,
|
||||||
|
DetectionSensorVerdictSendState,
|
||||||
|
DetectionSensorVerdictNoop,
|
||||||
|
} DetectionSensorTriggerVerdict;
|
||||||
|
|
||||||
|
typedef DetectionSensorTriggerVerdict (*DetectionSensorTriggerHandler)(bool prev, bool current);
|
||||||
|
|
||||||
|
static DetectionSensorTriggerVerdict detection_trigger_logic_level(bool prev, bool current)
|
||||||
|
{
|
||||||
|
return current ? DetectionSensorVerdictDetected : DetectionSensorVerdictNoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DetectionSensorTriggerVerdict detection_trigger_single_edge(bool prev, bool current)
|
||||||
|
{
|
||||||
|
return (!prev && current) ? DetectionSensorVerdictDetected : DetectionSensorVerdictNoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DetectionSensorTriggerVerdict detection_trigger_either_edge(bool prev, bool current)
|
||||||
|
{
|
||||||
|
if (prev == current) {
|
||||||
|
return DetectionSensorVerdictNoop;
|
||||||
|
}
|
||||||
|
return current ? DetectionSensorVerdictDetected : DetectionSensorVerdictSendState;
|
||||||
|
}
|
||||||
|
|
||||||
|
const static DetectionSensorTriggerHandler handlers[_meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_MAX + 1] = {
|
||||||
|
[meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_LOGIC_LOW] = detection_trigger_logic_level,
|
||||||
|
[meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_LOGIC_HIGH] = detection_trigger_logic_level,
|
||||||
|
[meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_FALLING_EDGE] = detection_trigger_single_edge,
|
||||||
|
[meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_RISING_EDGE] = detection_trigger_single_edge,
|
||||||
|
[meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_EITHER_EDGE_ACTIVE_LOW] = detection_trigger_either_edge,
|
||||||
|
[meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_EITHER_EDGE_ACTIVE_HIGH] = detection_trigger_either_edge,
|
||||||
|
};
|
||||||
|
|
||||||
int32_t DetectionSensorModule::runOnce()
|
int32_t DetectionSensorModule::runOnce()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -22,7 +57,8 @@ int32_t DetectionSensorModule::runOnce()
|
|||||||
// moduleConfig.detection_sensor.monitor_pin = 21; // WisBlock RAK12013 Radar IO6
|
// moduleConfig.detection_sensor.monitor_pin = 21; // WisBlock RAK12013 Radar IO6
|
||||||
// moduleConfig.detection_sensor.minimum_broadcast_secs = 30;
|
// moduleConfig.detection_sensor.minimum_broadcast_secs = 30;
|
||||||
// moduleConfig.detection_sensor.state_broadcast_secs = 120;
|
// moduleConfig.detection_sensor.state_broadcast_secs = 120;
|
||||||
// moduleConfig.detection_sensor.detection_triggered_high = true;
|
// moduleConfig.detection_sensor.detection_trigger_type =
|
||||||
|
// meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_LOGIC_HIGH;
|
||||||
// strcpy(moduleConfig.detection_sensor.name, "Motion");
|
// strcpy(moduleConfig.detection_sensor.name, "Motion");
|
||||||
|
|
||||||
if (moduleConfig.detection_sensor.enabled == false)
|
if (moduleConfig.detection_sensor.enabled == false)
|
||||||
@ -51,19 +87,30 @@ int32_t DetectionSensorModule::runOnce()
|
|||||||
// LOG_DEBUG("Detection Sensor Module: Current pin state: %i\n", digitalRead(moduleConfig.detection_sensor.monitor_pin));
|
// LOG_DEBUG("Detection Sensor Module: Current pin state: %i\n", digitalRead(moduleConfig.detection_sensor.monitor_pin));
|
||||||
|
|
||||||
if (!Throttle::isWithinTimespanMs(lastSentToMesh,
|
if (!Throttle::isWithinTimespanMs(lastSentToMesh,
|
||||||
Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.minimum_broadcast_secs)) &&
|
Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.minimum_broadcast_secs))) {
|
||||||
hasDetectionEvent()) {
|
bool isDetected = hasDetectionEvent();
|
||||||
|
DetectionSensorTriggerVerdict verdict =
|
||||||
|
handlers[moduleConfig.detection_sensor.detection_trigger_type](wasDetected, isDetected);
|
||||||
|
wasDetected = isDetected;
|
||||||
|
switch (verdict) {
|
||||||
|
case DetectionSensorVerdictDetected:
|
||||||
sendDetectionMessage();
|
sendDetectionMessage();
|
||||||
return DELAYED_INTERVAL;
|
return DELAYED_INTERVAL;
|
||||||
|
case DetectionSensorVerdictSendState:
|
||||||
|
sendCurrentStateMessage(isDetected);
|
||||||
|
return DELAYED_INTERVAL;
|
||||||
|
case DetectionSensorVerdictNoop:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Even if we haven't detected an event, broadcast our current state to the mesh on the scheduled interval as a sort
|
// Even if we haven't detected an event, broadcast our current state to the mesh on the scheduled interval as a sort
|
||||||
// of heartbeat. We only do this if the minimum broadcast interval is greater than zero, otherwise we'll only broadcast state
|
// of heartbeat. We only do this if the minimum broadcast interval is greater than zero, otherwise we'll only broadcast state
|
||||||
// change detections.
|
// change detections.
|
||||||
else if (moduleConfig.detection_sensor.state_broadcast_secs > 0 &&
|
if (moduleConfig.detection_sensor.state_broadcast_secs > 0 &&
|
||||||
!Throttle::isWithinTimespanMs(lastSentToMesh,
|
!Throttle::isWithinTimespanMs(lastSentToMesh,
|
||||||
Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.state_broadcast_secs,
|
Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.state_broadcast_secs,
|
||||||
default_telemetry_broadcast_interval_secs))) {
|
default_telemetry_broadcast_interval_secs))) {
|
||||||
sendCurrentStateMessage();
|
sendCurrentStateMessage(hasDetectionEvent());
|
||||||
return DELAYED_INTERVAL;
|
return DELAYED_INTERVAL;
|
||||||
}
|
}
|
||||||
return GPIO_POLLING_INTERVAL;
|
return GPIO_POLLING_INTERVAL;
|
||||||
@ -89,10 +136,10 @@ void DetectionSensorModule::sendDetectionMessage()
|
|||||||
delete[] message;
|
delete[] message;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetectionSensorModule::sendCurrentStateMessage()
|
void DetectionSensorModule::sendCurrentStateMessage(bool state)
|
||||||
{
|
{
|
||||||
char *message = new char[40];
|
char *message = new char[40];
|
||||||
sprintf(message, "%s state: %i", moduleConfig.detection_sensor.name, hasDetectionEvent());
|
sprintf(message, "%s state: %i", moduleConfig.detection_sensor.name, state);
|
||||||
|
|
||||||
meshtastic_MeshPacket *p = allocDataPacket();
|
meshtastic_MeshPacket *p = allocDataPacket();
|
||||||
p->want_ack = false;
|
p->want_ack = false;
|
||||||
@ -108,5 +155,5 @@ bool DetectionSensorModule::hasDetectionEvent()
|
|||||||
{
|
{
|
||||||
bool currentState = digitalRead(moduleConfig.detection_sensor.monitor_pin);
|
bool currentState = digitalRead(moduleConfig.detection_sensor.monitor_pin);
|
||||||
// LOG_DEBUG("Detection Sensor Module: Current state: %i\n", currentState);
|
// LOG_DEBUG("Detection Sensor Module: Current state: %i\n", currentState);
|
||||||
return moduleConfig.detection_sensor.detection_trigger_type ? currentState : !currentState;
|
return (moduleConfig.detection_sensor.detection_trigger_type & 1) ? currentState : !currentState;
|
||||||
}
|
}
|
@ -15,8 +15,9 @@ class DetectionSensorModule : public SinglePortModule, private concurrency::OSTh
|
|||||||
private:
|
private:
|
||||||
bool firstTime = true;
|
bool firstTime = true;
|
||||||
uint32_t lastSentToMesh = 0;
|
uint32_t lastSentToMesh = 0;
|
||||||
|
bool wasDetected = false;
|
||||||
void sendDetectionMessage();
|
void sendDetectionMessage();
|
||||||
void sendCurrentStateMessage();
|
void sendCurrentStateMessage(bool state);
|
||||||
bool hasDetectionEvent();
|
bool hasDetectionEvent();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "gps/GeoCoord.h"
|
#include "gps/GeoCoord.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mesh/compression/unishox2.h"
|
#include "mesh/compression/unishox2.h"
|
||||||
|
#include "meshUtils.h"
|
||||||
#include "meshtastic/atak.pb.h"
|
#include "meshtastic/atak.pb.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
#include "target_specific.h"
|
#include "target_specific.h"
|
||||||
@ -347,8 +348,8 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha
|
|||||||
|
|
||||||
service->sendToMesh(p, RX_SRC_LOCAL, true);
|
service->sendToMesh(p, RX_SRC_LOCAL, true);
|
||||||
|
|
||||||
if ((config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER ||
|
if (IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TRACKER,
|
||||||
config.device.role == meshtastic_Config_DeviceConfig_Role_TAK_TRACKER) &&
|
meshtastic_Config_DeviceConfig_Role_TAK_TRACKER) &&
|
||||||
config.power.is_power_saving) {
|
config.power.is_power_saving) {
|
||||||
LOG_DEBUG("Starting next execution in 5 seconds and then going to sleep.\n");
|
LOG_DEBUG("Starting next execution in 5 seconds and then going to sleep.\n");
|
||||||
sleepOnNextExecution = true;
|
sleepOnNextExecution = true;
|
||||||
|
@ -11,14 +11,15 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include <OLEDDisplay.h>
|
#include <OLEDDisplay.h>
|
||||||
#include <OLEDDisplayUi.h>
|
#include <OLEDDisplayUi.h>
|
||||||
|
#include <meshUtils.h>
|
||||||
|
|
||||||
#define MAGIC_USB_BATTERY_LEVEL 101
|
#define MAGIC_USB_BATTERY_LEVEL 101
|
||||||
|
|
||||||
int32_t DeviceTelemetryModule::runOnce()
|
int32_t DeviceTelemetryModule::runOnce()
|
||||||
{
|
{
|
||||||
refreshUptime();
|
refreshUptime();
|
||||||
bool isImpoliteRole = config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR ||
|
bool isImpoliteRole =
|
||||||
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER;
|
IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_SENSOR, meshtastic_Config_DeviceConfig_Role_ROUTER);
|
||||||
if (((lastSentToMesh == 0) ||
|
if (((lastSentToMesh == 0) ||
|
||||||
((uptimeLastMs - lastSentToMesh) >=
|
((uptimeLastMs - lastSentToMesh) >=
|
||||||
Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.device_update_interval,
|
Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.device_update_interval,
|
||||||
|
@ -158,7 +158,6 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
|||||||
result = bme680Sensor.runTrigger();
|
result = bme680Sensor.runTrigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t now = millis();
|
|
||||||
if (((lastSentToMesh == 0) ||
|
if (((lastSentToMesh == 0) ||
|
||||||
!Throttle::isWithinTimespanMs(lastSentToMesh, Default::getConfiguredOrDefaultMsScaled(
|
!Throttle::isWithinTimespanMs(lastSentToMesh, Default::getConfiguredOrDefaultMsScaled(
|
||||||
moduleConfig.telemetry.environment_update_interval,
|
moduleConfig.telemetry.environment_update_interval,
|
||||||
|
@ -32,6 +32,9 @@ static MemoryDynamic<meshtastic_ServiceEnvelope> staticMqttPool;
|
|||||||
|
|
||||||
Allocator<meshtastic_ServiceEnvelope> &mqttPool = staticMqttPool;
|
Allocator<meshtastic_ServiceEnvelope> &mqttPool = staticMqttPool;
|
||||||
|
|
||||||
|
// FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets
|
||||||
|
static uint8_t bytes[meshtastic_MqttClientProxyMessage_size + 30]; // 12 for channel name and 16 for nodeid
|
||||||
|
|
||||||
void MQTT::mqttCallback(char *topic, byte *payload, unsigned int length)
|
void MQTT::mqttCallback(char *topic, byte *payload, unsigned int length)
|
||||||
{
|
{
|
||||||
mqtt->onReceive(topic, payload, length);
|
mqtt->onReceive(topic, payload, length);
|
||||||
@ -482,9 +485,7 @@ void MQTT::publishQueuedMessages()
|
|||||||
{
|
{
|
||||||
if (!mqttQueue.isEmpty()) {
|
if (!mqttQueue.isEmpty()) {
|
||||||
LOG_DEBUG("Publishing enqueued MQTT message\n");
|
LOG_DEBUG("Publishing enqueued MQTT message\n");
|
||||||
// FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets
|
|
||||||
meshtastic_ServiceEnvelope *env = mqttQueue.dequeuePtr(0);
|
meshtastic_ServiceEnvelope *env = mqttQueue.dequeuePtr(0);
|
||||||
static uint8_t bytes[meshtastic_MqttClientProxyMessage_size];
|
|
||||||
size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, env);
|
size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, env);
|
||||||
std::string topic;
|
std::string topic;
|
||||||
if (env->packet->pki_encrypted) {
|
if (env->packet->pki_encrypted) {
|
||||||
@ -570,8 +571,6 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, const meshtastic_MeshPacket &
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (moduleConfig.mqtt.proxy_to_client_enabled || this->isConnectedDirectly()) {
|
if (moduleConfig.mqtt.proxy_to_client_enabled || this->isConnectedDirectly()) {
|
||||||
// FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets
|
|
||||||
static uint8_t bytes[meshtastic_MqttClientProxyMessage_size];
|
|
||||||
size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, env);
|
size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, env);
|
||||||
std::string topic = cryptTopic + channelId + "/" + owner.id;
|
std::string topic = cryptTopic + channelId + "/" + owner.id;
|
||||||
LOG_DEBUG("MQTT Publish %s, %u bytes\n", topic.c_str(), numBytes);
|
LOG_DEBUG("MQTT Publish %s, %u bytes\n", topic.c_str(), numBytes);
|
||||||
@ -666,8 +665,6 @@ void MQTT::perhapsReportToMap()
|
|||||||
&meshtastic_MapReport_msg, &mapReport);
|
&meshtastic_MapReport_msg, &mapReport);
|
||||||
se->packet = mp;
|
se->packet = mp;
|
||||||
|
|
||||||
// FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets
|
|
||||||
static uint8_t bytes[meshtastic_MqttClientProxyMessage_size];
|
|
||||||
size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, se);
|
size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, se);
|
||||||
|
|
||||||
LOG_INFO("MQTT Publish map report to %s\n", mapTopic.c_str());
|
LOG_INFO("MQTT Publish map report to %s\n", mapTopic.c_str());
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "PowerMon.h"
|
#include "PowerMon.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "meshUtils.h"
|
||||||
|
|
||||||
#ifdef BQ25703A_ADDR
|
#ifdef BQ25703A_ADDR
|
||||||
#include "BQ25713.h"
|
#include "BQ25713.h"
|
||||||
@ -157,6 +158,7 @@ void nrf52Loop()
|
|||||||
|
|
||||||
#ifdef USE_SEMIHOSTING
|
#ifdef USE_SEMIHOSTING
|
||||||
#include <SemihostingStream.h>
|
#include <SemihostingStream.h>
|
||||||
|
#include <meshUtils.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note: this variable is in BSS and therfore false by default. But the gdbinit
|
* Note: this variable is in BSS and therfore false by default. But the gdbinit
|
||||||
@ -261,10 +263,9 @@ void cpuDeepSleep(uint32_t msecToWake)
|
|||||||
// Sleepy trackers or sensors can low power "sleep"
|
// Sleepy trackers or sensors can low power "sleep"
|
||||||
// Don't enter this if we're sleeping portMAX_DELAY, since that's a shutdown event
|
// Don't enter this if we're sleeping portMAX_DELAY, since that's a shutdown event
|
||||||
if (msecToWake != portMAX_DELAY &&
|
if (msecToWake != portMAX_DELAY &&
|
||||||
(config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER ||
|
(IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TRACKER,
|
||||||
config.device.role == meshtastic_Config_DeviceConfig_Role_TAK_TRACKER ||
|
meshtastic_Config_DeviceConfig_Role_TAK_TRACKER, meshtastic_Config_DeviceConfig_Role_SENSOR) &&
|
||||||
config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR) &&
|
config.power.is_power_saving == true)) {
|
||||||
config.power.is_power_saving == true) {
|
|
||||||
sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
|
sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
|
||||||
delay(msecToWake);
|
delay(msecToWake);
|
||||||
NVIC_SystemReset();
|
NVIC_SystemReset();
|
||||||
|
Loading…
Reference in New Issue
Block a user