mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-25 09:42:35 +00:00
Merge branch 'master' into t3s3-1121
This commit is contained in:
commit
016e1005df
@ -8,7 +8,7 @@ plugins:
|
|||||||
uri: https://github.com/trunk-io/plugins
|
uri: https://github.com/trunk-io/plugins
|
||||||
lint:
|
lint:
|
||||||
enabled:
|
enabled:
|
||||||
- trufflehog@3.82.4
|
- trufflehog@3.82.5
|
||||||
- yamllint@1.35.1
|
- yamllint@1.35.1
|
||||||
- bandit@1.7.10
|
- bandit@1.7.10
|
||||||
- checkov@3.2.255
|
- checkov@3.2.255
|
||||||
|
@ -9,6 +9,7 @@ Lora:
|
|||||||
# IRQ: 16
|
# IRQ: 16
|
||||||
# Busy: 20
|
# Busy: 20
|
||||||
# Reset: 18
|
# Reset: 18
|
||||||
|
# SX126X_ANT_SW: 6
|
||||||
|
|
||||||
# Module: sx1262 # Waveshare SX1302 LISTEN ONLY AT THIS TIME!
|
# Module: sx1262 # Waveshare SX1302 LISTEN ONLY AT THIS TIME!
|
||||||
# CS: 7
|
# CS: 7
|
||||||
|
@ -81,6 +81,7 @@ build_flags = -Wno-missing-field-initializers
|
|||||||
-DRADIOLIB_EXCLUDE_APRS
|
-DRADIOLIB_EXCLUDE_APRS
|
||||||
-DRADIOLIB_EXCLUDE_LORAWAN
|
-DRADIOLIB_EXCLUDE_LORAWAN
|
||||||
-DMESHTASTIC_EXCLUDE_DROPZONE=1
|
-DMESHTASTIC_EXCLUDE_DROPZONE=1
|
||||||
|
-DMESHTASTIC_EXCLUDE_REMOTEHARDWARE=1
|
||||||
-DBUILD_EPOCH=$UNIX_TIME
|
-DBUILD_EPOCH=$UNIX_TIME
|
||||||
;-D OLED_PL
|
;-D OLED_PL
|
||||||
|
|
||||||
|
@ -1068,10 +1068,9 @@ bool Power::axpChipInit()
|
|||||||
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper class for an I2C MAX17048 Lipo battery sensor. If there is no
|
* Wrapper class for an I2C MAX17048 Lipo battery sensor.
|
||||||
* I2C sensor present, the class falls back to analog battery sensing
|
|
||||||
*/
|
*/
|
||||||
class LipoBatteryLevel : public AnalogBatteryLevel
|
class LipoBatteryLevel : public HasBatteryLevel
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
MAX17048Singleton *max17048 = nullptr;
|
MAX17048Singleton *max17048 = nullptr;
|
||||||
@ -1096,52 +1095,27 @@ class LipoBatteryLevel : public AnalogBatteryLevel
|
|||||||
/**
|
/**
|
||||||
* Battery state of charge, from 0 to 100 or -1 for unknown
|
* Battery state of charge, from 0 to 100 or -1 for unknown
|
||||||
*/
|
*/
|
||||||
virtual int getBatteryPercent() override
|
virtual int getBatteryPercent() override { return max17048->getBusBatteryPercent(); }
|
||||||
{
|
|
||||||
if (!max17048->isInitialised())
|
|
||||||
return AnalogBatteryLevel::getBatteryPercent();
|
|
||||||
return max17048->getBusBatteryPercent();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The raw voltage of the battery in millivolts, or NAN if unknown
|
* The raw voltage of the battery in millivolts, or NAN if unknown
|
||||||
*/
|
*/
|
||||||
virtual uint16_t getBattVoltage() override
|
virtual uint16_t getBattVoltage() override { return max17048->getBusVoltageMv(); }
|
||||||
{
|
|
||||||
if (!max17048->isInitialised())
|
|
||||||
return AnalogBatteryLevel::getBattVoltage();
|
|
||||||
return max17048->getBusVoltageMv();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return true if there is a battery installed in this unit
|
* return true if there is a battery installed in this unit
|
||||||
*/
|
*/
|
||||||
virtual bool isBatteryConnect() override
|
virtual bool isBatteryConnect() override { return max17048->isBatteryConnected(); }
|
||||||
{
|
|
||||||
if (!max17048->isInitialised())
|
|
||||||
return AnalogBatteryLevel::isBatteryConnect();
|
|
||||||
return max17048->isBatteryConnected();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return true if there is an external power source detected
|
* return true if there is an external power source detected
|
||||||
*/
|
*/
|
||||||
virtual bool isVbusIn() override
|
virtual bool isVbusIn() override { return max17048->isExternallyPowered(); }
|
||||||
{
|
|
||||||
if (!max17048->isInitialised())
|
|
||||||
return AnalogBatteryLevel::isVbusIn();
|
|
||||||
return max17048->isExternallyPowered();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return true if the battery is currently charging
|
* return true if the battery is currently charging
|
||||||
*/
|
*/
|
||||||
virtual bool isCharging() override
|
virtual bool isCharging() override { return max17048->isBatteryCharging(); }
|
||||||
{
|
|
||||||
if (!max17048->isInitialised())
|
|
||||||
return AnalogBatteryLevel::isCharging();
|
|
||||||
return max17048->isBatteryCharging();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
LipoBatteryLevel lipoLevel;
|
LipoBatteryLevel lipoLevel;
|
||||||
@ -1153,6 +1127,8 @@ bool Power::lipoInit()
|
|||||||
{
|
{
|
||||||
bool result = lipoLevel.runOnce();
|
bool result = lipoLevel.runOnce();
|
||||||
LOG_DEBUG("Power::lipoInit lipo sensor is %s\n", result ? "ready" : "not ready yet");
|
LOG_DEBUG("Power::lipoInit lipo sensor is %s\n", result ? "ready" : "not ready yet");
|
||||||
|
if (!result)
|
||||||
|
return false;
|
||||||
batteryLevel = &lipoLevel;
|
batteryLevel = &lipoLevel;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -916,20 +916,22 @@ void GPS::down()
|
|||||||
softsleepSupported = true;
|
softsleepSupported = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// How long does gps_update_interval need to be, for GPS_HARDSLEEP to become more efficient than GPS_SOFTSLEEP?
|
if (softsleepSupported) {
|
||||||
// Heuristic equation. A compromise manually fitted to power observations from U-blox NEO-6M and M10050
|
// How long does gps_update_interval need to be, for GPS_HARDSLEEP to become more efficient than GPS_SOFTSLEEP?
|
||||||
// https://www.desmos.com/calculator/6gvjghoumr
|
// Heuristic equation. A compromise manually fitted to power observations from U-blox NEO-6M and M10050
|
||||||
// This is not particularly accurate, but probably an impromevement over a single, fixed threshold
|
// https://www.desmos.com/calculator/6gvjghoumr
|
||||||
uint32_t hardsleepThreshold = (2750 * pow(predictedSearchDuration / 1000, 1.22));
|
// This is not particularly accurate, but probably an impromevement over a single, fixed threshold
|
||||||
LOG_DEBUG("gps_update_interval >= %us needed to justify hardsleep\n", hardsleepThreshold / 1000);
|
uint32_t hardsleepThreshold = (2750 * pow(predictedSearchDuration / 1000, 1.22));
|
||||||
|
LOG_DEBUG("gps_update_interval >= %us needed to justify hardsleep\n", hardsleepThreshold / 1000);
|
||||||
// If update interval too short: softsleep (if supported by hardware)
|
|
||||||
if (softsleepSupported && updateInterval < hardsleepThreshold)
|
|
||||||
setPowerState(GPS_SOFTSLEEP, sleepTime);
|
|
||||||
|
|
||||||
|
// If update interval too short: softsleep (if supported by hardware)
|
||||||
|
if (updateInterval < hardsleepThreshold) {
|
||||||
|
setPowerState(GPS_SOFTSLEEP, sleepTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
// If update interval long enough (or softsleep unsupported): hardsleep instead
|
// If update interval long enough (or softsleep unsupported): hardsleep instead
|
||||||
else
|
setPowerState(GPS_HARDSLEEP, sleepTime);
|
||||||
setPowerState(GPS_HARDSLEEP, sleepTime);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "MeshTypes.h"
|
#include "MeshTypes.h"
|
||||||
#include "NodeStatus.h"
|
#include "NodeStatus.h"
|
||||||
|
#include "configuration.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include "mesh/generated/meshtastic/mesh.pb.h" // For CriticalErrorCode
|
#include "mesh/generated/meshtastic/mesh.pb.h" // For CriticalErrorCode
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "FSCommon.h"
|
#include "FSCommon.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
|
#include "PacketHistory.h"
|
||||||
#include "PhoneAPI.h"
|
#include "PhoneAPI.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "RadioInterface.h"
|
#include "RadioInterface.h"
|
||||||
@ -31,6 +32,7 @@
|
|||||||
PhoneAPI::PhoneAPI()
|
PhoneAPI::PhoneAPI()
|
||||||
{
|
{
|
||||||
lastContactMsec = millis();
|
lastContactMsec = millis();
|
||||||
|
std::fill(std::begin(recentToRadioPacketIds), std::end(recentToRadioPacketIds), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
PhoneAPI::~PhoneAPI()
|
PhoneAPI::~PhoneAPI()
|
||||||
@ -109,8 +111,6 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
|||||||
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE); // As long as the phone keeps talking to us, don't let the radio go to sleep
|
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE); // As long as the phone keeps talking to us, don't let the radio go to sleep
|
||||||
lastContactMsec = millis();
|
lastContactMsec = millis();
|
||||||
|
|
||||||
// return (lastContactMsec != 0) &&
|
|
||||||
|
|
||||||
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
|
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
|
||||||
if (pb_decode_from_bytes(buf, bufLength, &meshtastic_ToRadio_msg, &toRadioScratch)) {
|
if (pb_decode_from_bytes(buf, bufLength, &meshtastic_ToRadio_msg, &toRadioScratch)) {
|
||||||
switch (toRadioScratch.which_payload_variant) {
|
switch (toRadioScratch.which_payload_variant) {
|
||||||
@ -572,12 +572,35 @@ void PhoneAPI::sendNotification(meshtastic_LogRecord_Level level, uint32_t reply
|
|||||||
service->sendClientNotification(cn);
|
service->sendClientNotification(cn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PhoneAPI::wasSeenRecently(uint32_t id)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
if (recentToRadioPacketIds[i] == id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (recentToRadioPacketIds[i] == 0) {
|
||||||
|
recentToRadioPacketIds[i] = id;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the array is full, shift all elements to the left and add the new id at the end
|
||||||
|
memmove(recentToRadioPacketIds, recentToRadioPacketIds + 1, (19) * sizeof(uint32_t));
|
||||||
|
recentToRadioPacketIds[19] = id;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool
|
* Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool
|
||||||
*/
|
*/
|
||||||
bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p)
|
bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p)
|
||||||
{
|
{
|
||||||
printPacket("PACKET FROM PHONE", &p);
|
printPacket("PACKET FROM PHONE", &p);
|
||||||
|
|
||||||
|
if (p.id > 0 && wasSeenRecently(p.id)) {
|
||||||
|
LOG_DEBUG("Ignoring packet from phone, already seen recently\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (p.decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP && lastPortNumToRadio[p.decoded.portnum] &&
|
if (p.decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP && lastPortNumToRadio[p.decoded.portnum] &&
|
||||||
Throttle::isWithinTimespanMs(lastPortNumToRadio[p.decoded.portnum], THIRTY_SECONDS_MS)) {
|
Throttle::isWithinTimespanMs(lastPortNumToRadio[p.decoded.portnum], THIRTY_SECONDS_MS)) {
|
||||||
LOG_WARN("Rate limiting portnum %d\n", p.decoded.portnum);
|
LOG_WARN("Rate limiting portnum %d\n", p.decoded.portnum);
|
||||||
@ -586,7 +609,8 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p)
|
|||||||
} else if (p.decoded.portnum == meshtastic_PortNum_POSITION_APP && lastPortNumToRadio[p.decoded.portnum] &&
|
} else if (p.decoded.portnum == meshtastic_PortNum_POSITION_APP && lastPortNumToRadio[p.decoded.portnum] &&
|
||||||
Throttle::isWithinTimespanMs(lastPortNumToRadio[p.decoded.portnum], FIVE_SECONDS_MS)) {
|
Throttle::isWithinTimespanMs(lastPortNumToRadio[p.decoded.portnum], FIVE_SECONDS_MS)) {
|
||||||
LOG_WARN("Rate limiting portnum %d\n", p.decoded.portnum);
|
LOG_WARN("Rate limiting portnum %d\n", p.decoded.portnum);
|
||||||
sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "Position can only be sent once every 5 seconds");
|
// FIXME: Figure out why this continues to happen
|
||||||
|
// sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "Position can only be sent once every 5 seconds");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lastPortNumToRadio[p.decoded.portnum] = millis();
|
lastPortNumToRadio[p.decoded.portnum] = millis();
|
||||||
|
@ -52,6 +52,7 @@ class PhoneAPI
|
|||||||
|
|
||||||
// Hashmap of timestamps for last time we received a packet on the API per portnum
|
// Hashmap of timestamps for last time we received a packet on the API per portnum
|
||||||
std::unordered_map<meshtastic_PortNum, uint32_t> lastPortNumToRadio;
|
std::unordered_map<meshtastic_PortNum, uint32_t> lastPortNumToRadio;
|
||||||
|
uint32_t recentToRadioPacketIds[20]; // Last 20 ToRadio MeshPacket IDs we have seen
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Each packet sent to the phone has an incrementing count
|
* Each packet sent to the phone has an incrementing count
|
||||||
@ -159,6 +160,8 @@ class PhoneAPI
|
|||||||
/// begin a new connection
|
/// begin a new connection
|
||||||
void handleStartConfig();
|
void handleStartConfig();
|
||||||
|
|
||||||
|
bool wasSeenRecently(uint32_t packetId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a packet that the phone wants us to send. We can write to it but can not keep a reference to it
|
* Handle a packet that the phone wants us to send. We can write to it but can not keep a reference to it
|
||||||
* @return true true if a packet was queued for sending
|
* @return true true if a packet was queued for sending
|
||||||
|
@ -52,6 +52,10 @@ template <typename T> bool SX126xInterface<T>::init()
|
|||||||
float tcxoVoltage = 0;
|
float tcxoVoltage = 0;
|
||||||
if (settingsMap[dio3_tcxo_voltage])
|
if (settingsMap[dio3_tcxo_voltage])
|
||||||
tcxoVoltage = 1.8;
|
tcxoVoltage = 1.8;
|
||||||
|
if (settingsMap[sx126x_ant_sw] != RADIOLIB_NC) {
|
||||||
|
digitalWrite(settingsMap[sx126x_ant_sw], HIGH);
|
||||||
|
pinMode(settingsMap[sx126x_ant_sw], OUTPUT);
|
||||||
|
}
|
||||||
// FIXME: correct logic to default to not using TCXO if no voltage is specified for SX126X_DIO3_TCXO_VOLTAGE
|
// FIXME: correct logic to default to not using TCXO if no voltage is specified for SX126X_DIO3_TCXO_VOLTAGE
|
||||||
#elif !defined(SX126X_DIO3_TCXO_VOLTAGE)
|
#elif !defined(SX126X_DIO3_TCXO_VOLTAGE)
|
||||||
float tcxoVoltage =
|
float tcxoVoltage =
|
||||||
@ -99,21 +103,19 @@ template <typename T> bool SX126xInterface<T>::init()
|
|||||||
LOG_DEBUG("Current limit set to %f\n", currentLimit);
|
LOG_DEBUG("Current limit set to %f\n", currentLimit);
|
||||||
LOG_DEBUG("Current limit set result %d\n", res);
|
LOG_DEBUG("Current limit set result %d\n", res);
|
||||||
|
|
||||||
#ifdef SX126X_DIO2_AS_RF_SWITCH
|
|
||||||
LOG_DEBUG("Setting DIO2 as RF switch\n");
|
|
||||||
bool dio2AsRfSwitch = true;
|
|
||||||
#elif defined(ARCH_PORTDUINO)
|
|
||||||
bool dio2AsRfSwitch = false;
|
|
||||||
if (settingsMap[dio2_as_rf_switch]) {
|
|
||||||
LOG_DEBUG("Setting DIO2 as RF switch\n");
|
|
||||||
dio2AsRfSwitch = true;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
LOG_DEBUG("Setting DIO2 as not RF switch\n");
|
|
||||||
bool dio2AsRfSwitch = false;
|
|
||||||
#endif
|
|
||||||
if (res == RADIOLIB_ERR_NONE) {
|
if (res == RADIOLIB_ERR_NONE) {
|
||||||
|
#ifdef SX126X_DIO2_AS_RF_SWITCH
|
||||||
|
bool dio2AsRfSwitch = true;
|
||||||
|
#elif defined(ARCH_PORTDUINO)
|
||||||
|
bool dio2AsRfSwitch = false;
|
||||||
|
if (settingsMap[dio2_as_rf_switch]) {
|
||||||
|
dio2AsRfSwitch = true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
bool dio2AsRfSwitch = false;
|
||||||
|
#endif
|
||||||
res = lora.setDio2AsRfSwitch(dio2AsRfSwitch);
|
res = lora.setDio2AsRfSwitch(dio2AsRfSwitch);
|
||||||
|
LOG_DEBUG("Set DIO2 as %sRF switch, result: %d\n", dio2AsRfSwitch ? "" : "not ", res);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a pin isn't defined, we set it to RADIOLIB_NC, it is safe to always do external RF switching with RADIOLIB_NC as it has
|
// If a pin isn't defined, we set it to RADIOLIB_NC, it is safe to always do external RF switching with RADIOLIB_NC as it has
|
||||||
|
@ -15,26 +15,44 @@
|
|||||||
// a max of one change per 30 seconds
|
// a max of one change per 30 seconds
|
||||||
#define WATCH_INTERVAL_MSEC (30 * 1000)
|
#define WATCH_INTERVAL_MSEC (30 * 1000)
|
||||||
|
|
||||||
|
// Tests for access to read from or write to a specified GPIO pin
|
||||||
|
static bool pinAccessAllowed(uint64_t mask, uint8_t pin)
|
||||||
|
{
|
||||||
|
// If undefined pin access is allowed, don't check the pin and just return true
|
||||||
|
if (moduleConfig.remote_hardware.allow_undefined_pin_access) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test to see if the pin is in the list of allowed pins and return true if found
|
||||||
|
if (mask & (1ULL << pin)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Set pin modes for every set bit in a mask
|
/// Set pin modes for every set bit in a mask
|
||||||
static void pinModes(uint64_t mask, uint8_t mode)
|
static void pinModes(uint64_t mask, uint8_t mode, uint64_t maskAvailable)
|
||||||
{
|
{
|
||||||
for (uint64_t i = 0; i < NUM_GPIOS; i++) {
|
for (uint64_t i = 0; i < NUM_GPIOS; i++) {
|
||||||
if (mask & (1ULL << i)) {
|
if (mask & (1ULL << i)) {
|
||||||
pinMode(i, mode);
|
if (pinAccessAllowed(maskAvailable, i)) {
|
||||||
|
pinMode(i, mode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read all the pins mentioned in a mask
|
/// Read all the pins mentioned in a mask
|
||||||
static uint64_t digitalReads(uint64_t mask)
|
static uint64_t digitalReads(uint64_t mask, uint64_t maskAvailable)
|
||||||
{
|
{
|
||||||
uint64_t res = 0;
|
uint64_t res = 0;
|
||||||
|
|
||||||
pinModes(mask, INPUT_PULLUP);
|
pinModes(mask, INPUT_PULLUP, maskAvailable);
|
||||||
|
|
||||||
for (uint64_t i = 0; i < NUM_GPIOS; i++) {
|
for (uint64_t i = 0; i < NUM_GPIOS; i++) {
|
||||||
uint64_t m = 1ULL << i;
|
uint64_t m = 1ULL << i;
|
||||||
if (mask & m) {
|
if (mask & m && pinAccessAllowed(maskAvailable, i)) {
|
||||||
if (digitalRead(i)) {
|
if (digitalRead(i)) {
|
||||||
res |= m;
|
res |= m;
|
||||||
}
|
}
|
||||||
@ -50,6 +68,11 @@ RemoteHardwareModule::RemoteHardwareModule()
|
|||||||
{
|
{
|
||||||
// restrict to the gpio channel for rx
|
// restrict to the gpio channel for rx
|
||||||
boundChannel = Channels::gpioChannel;
|
boundChannel = Channels::gpioChannel;
|
||||||
|
|
||||||
|
// Pull available pin allowlist from config and build a bitmask out of it for fast comparisons later
|
||||||
|
for (uint8_t i = 0; i < 4; i++) {
|
||||||
|
availablePins += 1ULL << moduleConfig.remote_hardware.available_pins[i].gpio_pin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RemoteHardwareModule::handleReceivedProtobuf(const meshtastic_MeshPacket &req, meshtastic_HardwareMessage *pptr)
|
bool RemoteHardwareModule::handleReceivedProtobuf(const meshtastic_MeshPacket &req, meshtastic_HardwareMessage *pptr)
|
||||||
@ -63,10 +86,10 @@ bool RemoteHardwareModule::handleReceivedProtobuf(const meshtastic_MeshPacket &r
|
|||||||
// Print notification to LCD screen
|
// Print notification to LCD screen
|
||||||
screen->print("Write GPIOs\n");
|
screen->print("Write GPIOs\n");
|
||||||
|
|
||||||
pinModes(p.gpio_mask, OUTPUT);
|
pinModes(p.gpio_mask, OUTPUT, availablePins);
|
||||||
for (uint8_t i = 0; i < NUM_GPIOS; i++) {
|
for (uint8_t i = 0; i < NUM_GPIOS; i++) {
|
||||||
uint64_t mask = 1ULL << i;
|
uint64_t mask = 1ULL << i;
|
||||||
if (p.gpio_mask & mask) {
|
if (p.gpio_mask & mask && pinAccessAllowed(availablePins, i)) {
|
||||||
digitalWrite(i, (p.gpio_value & mask) ? 1 : 0);
|
digitalWrite(i, (p.gpio_value & mask) ? 1 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,7 +102,7 @@ bool RemoteHardwareModule::handleReceivedProtobuf(const meshtastic_MeshPacket &r
|
|||||||
if (screen)
|
if (screen)
|
||||||
screen->print("Read GPIOs\n");
|
screen->print("Read GPIOs\n");
|
||||||
|
|
||||||
uint64_t res = digitalReads(p.gpio_mask);
|
uint64_t res = digitalReads(p.gpio_mask, availablePins);
|
||||||
|
|
||||||
// Send the reply
|
// Send the reply
|
||||||
meshtastic_HardwareMessage r = meshtastic_HardwareMessage_init_default;
|
meshtastic_HardwareMessage r = meshtastic_HardwareMessage_init_default;
|
||||||
@ -121,7 +144,7 @@ int32_t RemoteHardwareModule::runOnce()
|
|||||||
if (moduleConfig.remote_hardware.enabled && watchGpios) {
|
if (moduleConfig.remote_hardware.enabled && watchGpios) {
|
||||||
|
|
||||||
if (!Throttle::isWithinTimespanMs(lastWatchMsec, WATCH_INTERVAL_MSEC)) {
|
if (!Throttle::isWithinTimespanMs(lastWatchMsec, WATCH_INTERVAL_MSEC)) {
|
||||||
uint64_t curVal = digitalReads(watchGpios);
|
uint64_t curVal = digitalReads(watchGpios, availablePins);
|
||||||
lastWatchMsec = millis();
|
lastWatchMsec = millis();
|
||||||
|
|
||||||
if (curVal != previousWatch) {
|
if (curVal != previousWatch) {
|
||||||
|
@ -17,6 +17,9 @@ class RemoteHardwareModule : public ProtobufModule<meshtastic_HardwareMessage>,
|
|||||||
/// The timestamp of our last watch event (we throttle watches to 1 change every 30 seconds)
|
/// The timestamp of our last watch event (we throttle watches to 1 change every 30 seconds)
|
||||||
uint32_t lastWatchMsec = 0;
|
uint32_t lastWatchMsec = 0;
|
||||||
|
|
||||||
|
/// A bitmask of GPIOs that are exposed to the mesh if undefined access is not enabled
|
||||||
|
uint64_t availablePins = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Constructor
|
/** Constructor
|
||||||
* name is for debugging output
|
* name is for debugging output
|
||||||
|
@ -44,6 +44,9 @@ static BluetoothPhoneAPI *bluetoothPhoneAPI;
|
|||||||
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Last ToRadio value received from the phone
|
||||||
|
static uint8_t lastToRadio[MAX_TO_FROM_RADIO_SIZE];
|
||||||
|
|
||||||
class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks
|
class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks
|
||||||
{
|
{
|
||||||
virtual void onWrite(NimBLECharacteristic *pCharacteristic)
|
virtual void onWrite(NimBLECharacteristic *pCharacteristic)
|
||||||
@ -51,7 +54,13 @@ class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks
|
|||||||
LOG_INFO("To Radio onwrite\n");
|
LOG_INFO("To Radio onwrite\n");
|
||||||
auto val = pCharacteristic->getValue();
|
auto val = pCharacteristic->getValue();
|
||||||
|
|
||||||
bluetoothPhoneAPI->handleToRadio(val.data(), val.length());
|
if (memcmp(lastToRadio, val.data(), val.length()) != 0) {
|
||||||
|
LOG_DEBUG("New ToRadio packet\n");
|
||||||
|
memcpy(lastToRadio, val.data(), val.length());
|
||||||
|
bluetoothPhoneAPI->handleToRadio(val.data(), val.length());
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("Dropping duplicate ToRadio packet we just saw\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -141,10 +141,19 @@ void onFromRadioAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_e
|
|||||||
}
|
}
|
||||||
authorizeRead(conn_hdl);
|
authorizeRead(conn_hdl);
|
||||||
}
|
}
|
||||||
|
// Last ToRadio value received from the phone
|
||||||
|
static uint8_t lastToRadio[MAX_TO_FROM_RADIO_SIZE];
|
||||||
|
|
||||||
void onToRadioWrite(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len)
|
void onToRadioWrite(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len)
|
||||||
{
|
{
|
||||||
LOG_INFO("toRadioWriteCb data %p, len %u\n", data, len);
|
LOG_INFO("toRadioWriteCb data %p, len %u\n", data, len);
|
||||||
bluetoothPhoneAPI->handleToRadio(data, len);
|
if (memcmp(lastToRadio, data, len) != 0) {
|
||||||
|
LOG_DEBUG("New ToRadio packet\n");
|
||||||
|
memcpy(lastToRadio, data, len);
|
||||||
|
bluetoothPhoneAPI->handleToRadio(data, len);
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("Dropping duplicate ToRadio packet we just saw\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupMeshService(void)
|
void setupMeshService(void)
|
||||||
|
@ -80,6 +80,7 @@ void portduinoSetup()
|
|||||||
irq,
|
irq,
|
||||||
busy,
|
busy,
|
||||||
reset,
|
reset,
|
||||||
|
sx126x_ant_sw,
|
||||||
txen,
|
txen,
|
||||||
rxen,
|
rxen,
|
||||||
displayDC,
|
displayDC,
|
||||||
@ -180,6 +181,7 @@ void portduinoSetup()
|
|||||||
settingsMap[reset] = yamlConfig["Lora"]["Reset"].as<int>(RADIOLIB_NC);
|
settingsMap[reset] = yamlConfig["Lora"]["Reset"].as<int>(RADIOLIB_NC);
|
||||||
settingsMap[txen] = yamlConfig["Lora"]["TXen"].as<int>(RADIOLIB_NC);
|
settingsMap[txen] = yamlConfig["Lora"]["TXen"].as<int>(RADIOLIB_NC);
|
||||||
settingsMap[rxen] = yamlConfig["Lora"]["RXen"].as<int>(RADIOLIB_NC);
|
settingsMap[rxen] = yamlConfig["Lora"]["RXen"].as<int>(RADIOLIB_NC);
|
||||||
|
settingsMap[sx126x_ant_sw] = yamlConfig["Lora"]["SX126X_ANT_SW"].as<int>(RADIOLIB_NC);
|
||||||
settingsMap[gpiochip] = yamlConfig["Lora"]["gpiochip"].as<int>(0);
|
settingsMap[gpiochip] = yamlConfig["Lora"]["gpiochip"].as<int>(0);
|
||||||
settingsMap[ch341Quirk] = yamlConfig["Lora"]["ch341_quirk"].as<bool>(false);
|
settingsMap[ch341Quirk] = yamlConfig["Lora"]["ch341_quirk"].as<bool>(false);
|
||||||
settingsMap[spiSpeed] = yamlConfig["Lora"]["spiSpeed"].as<int>(2000000);
|
settingsMap[spiSpeed] = yamlConfig["Lora"]["spiSpeed"].as<int>(2000000);
|
||||||
@ -305,6 +307,8 @@ void portduinoSetup()
|
|||||||
gpioInit(max_GPIO + 1); // Done here so we can inform Portduino how many GPIOs we need.
|
gpioInit(max_GPIO + 1); // Done here so we can inform Portduino how many GPIOs we need.
|
||||||
|
|
||||||
// Need to bind all the configured GPIO pins so they're not simulated
|
// Need to bind all the configured GPIO pins so they're not simulated
|
||||||
|
// TODO: Can we do this in the for loop above?
|
||||||
|
// TODO: If one of these fails, we should log and terminate
|
||||||
if (settingsMap.count(cs) > 0 && settingsMap[cs] != RADIOLIB_NC) {
|
if (settingsMap.count(cs) > 0 && settingsMap[cs] != RADIOLIB_NC) {
|
||||||
if (initGPIOPin(settingsMap[cs], gpioChipName) != ERRNO_OK) {
|
if (initGPIOPin(settingsMap[cs], gpioChipName) != ERRNO_OK) {
|
||||||
settingsMap[cs] = RADIOLIB_NC;
|
settingsMap[cs] = RADIOLIB_NC;
|
||||||
@ -325,6 +329,11 @@ void portduinoSetup()
|
|||||||
settingsMap[reset] = RADIOLIB_NC;
|
settingsMap[reset] = RADIOLIB_NC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (settingsMap.count(sx126x_ant_sw) > 0 && settingsMap[sx126x_ant_sw] != RADIOLIB_NC) {
|
||||||
|
if (initGPIOPin(settingsMap[sx126x_ant_sw], gpioChipName) != ERRNO_OK) {
|
||||||
|
settingsMap[sx126x_ant_sw] = RADIOLIB_NC;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (settingsMap.count(user) > 0 && settingsMap[user] != RADIOLIB_NC) {
|
if (settingsMap.count(user) > 0 && settingsMap[user] != RADIOLIB_NC) {
|
||||||
if (initGPIOPin(settingsMap[user], gpioChipName) != ERRNO_OK) {
|
if (initGPIOPin(settingsMap[user], gpioChipName) != ERRNO_OK) {
|
||||||
settingsMap[user] = RADIOLIB_NC;
|
settingsMap[user] = RADIOLIB_NC;
|
||||||
|
@ -8,6 +8,7 @@ enum configNames {
|
|||||||
irq,
|
irq,
|
||||||
busy,
|
busy,
|
||||||
reset,
|
reset,
|
||||||
|
sx126x_ant_sw,
|
||||||
txen,
|
txen,
|
||||||
rxen,
|
rxen,
|
||||||
dio2_as_rf_switch,
|
dio2_as_rf_switch,
|
||||||
|
Loading…
Reference in New Issue
Block a user