mirror of
https://github.com/meshtastic/firmware.git
synced 2025-09-09 12:49:40 +00:00
Compare commits
12 Commits
108195a38a
...
60f05e357e
Author | SHA1 | Date | |
---|---|---|---|
![]() |
60f05e357e | ||
![]() |
0bd4cefad3 | ||
![]() |
9b1fb795d7 | ||
![]() |
3040e5a7bb | ||
![]() |
3b82d55176 | ||
![]() |
a6b8202cd4 | ||
![]() |
cfc1bf10c9 | ||
![]() |
7d1300ab66 | ||
![]() |
a7435b85a1 | ||
![]() |
729d6c576f | ||
![]() |
15b84fca01 | ||
![]() |
285b30dff0 |
@ -9,7 +9,7 @@ plugins:
|
||||
lint:
|
||||
enabled:
|
||||
- checkov@3.2.467
|
||||
- renovate@41.90.1
|
||||
- renovate@41.91.3
|
||||
- prettier@3.6.2
|
||||
- trufflehog@3.90.5
|
||||
- yamllint@1.37.1
|
||||
|
@ -5,7 +5,7 @@
|
||||
},
|
||||
"core": "stm32",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DSTM32WLxx -DSTM32WLE5xx -DARDUINO_GENERIC_WLE5CCUX",
|
||||
"extra_flags": "-DSTM32WLxx -DSTM32WLE5xx -DARDUINO_RAK3172_MODULE",
|
||||
"f_cpu": "48000000L",
|
||||
"mcu": "stm32wle5ccu",
|
||||
"variant": "STM32WLxx/WL54CCU_WL55CCU_WLE4C(8-B-C)U_WLE5C(8-B-C)U",
|
||||
|
@ -48,6 +48,7 @@ build_flags = -Wno-missing-field-initializers
|
||||
-DRADIOLIB_EXCLUDE_APRS=1
|
||||
-DRADIOLIB_EXCLUDE_LORAWAN=1
|
||||
-DMESHTASTIC_EXCLUDE_DROPZONE=1
|
||||
-DMESHTASTIC_EXCLUDE_ZPS=1
|
||||
-DMESHTASTIC_EXCLUDE_REMOTEHARDWARE=1
|
||||
-DMESHTASTIC_EXCLUDE_HEALTH_TELEMETRY=1
|
||||
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
|
||||
|
@ -1,7 +1,14 @@
|
||||
#include "DisplayFormatters.h"
|
||||
|
||||
const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName)
|
||||
const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName,
|
||||
bool usePreset)
|
||||
{
|
||||
|
||||
// If use_preset is false, always return "Custom"
|
||||
if (!usePreset) {
|
||||
return "Custom";
|
||||
}
|
||||
|
||||
switch (preset) {
|
||||
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO:
|
||||
return useShortName ? "ShortT" : "ShortTurbo";
|
||||
|
@ -4,5 +4,6 @@
|
||||
class DisplayFormatters
|
||||
{
|
||||
public:
|
||||
static const char *getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName);
|
||||
static const char *getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName,
|
||||
bool usePreset);
|
||||
};
|
||||
|
@ -843,9 +843,6 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
|
||||
setPowerPMU(true); // Power (PMU): on
|
||||
writePinStandby(false); // Standby (pin): awake (not standby)
|
||||
setPowerUBLOX(true); // Standby (UBLOX): awake
|
||||
#ifdef GNSS_AIROHA
|
||||
lastFixStartMsec = 0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case GPS_SOFTSLEEP:
|
||||
@ -863,9 +860,7 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
|
||||
writePinStandby(true); // Standby (pin): asleep (not awake)
|
||||
setPowerUBLOX(false, sleepTime); // Standby (UBLOX): asleep, timed
|
||||
#ifdef GNSS_AIROHA
|
||||
if (config.position.gps_update_interval * 1000 >= GPS_FIX_HOLD_TIME * 2) {
|
||||
digitalWrite(PIN_GPS_EN, LOW);
|
||||
}
|
||||
digitalWrite(PIN_GPS_EN, LOW);
|
||||
#endif
|
||||
break;
|
||||
|
||||
@ -877,9 +872,7 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
|
||||
writePinStandby(true); // Standby (pin): asleep
|
||||
setPowerUBLOX(false, 0); // Standby (UBLOX): asleep, indefinitely
|
||||
#ifdef GNSS_AIROHA
|
||||
if (config.position.gps_update_interval * 1000 >= GPS_FIX_HOLD_TIME * 2) {
|
||||
digitalWrite(PIN_GPS_EN, LOW);
|
||||
}
|
||||
digitalWrite(PIN_GPS_EN, LOW);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@ -1062,6 +1055,8 @@ void GPS::down()
|
||||
}
|
||||
// If update interval long enough (or softsleep unsupported): hardsleep instead
|
||||
setPowerState(GPS_HARDSLEEP, sleepTime);
|
||||
// Reset the fix quality to 0, since we're off.
|
||||
fixQual = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1121,11 +1116,19 @@ int32_t GPS::runOnce()
|
||||
shouldPublish = true;
|
||||
}
|
||||
|
||||
uint8_t prev_fixQual = fixQual;
|
||||
bool gotLoc = lookForLocation();
|
||||
if (gotLoc && !hasValidLocation) { // declare that we have location ASAP
|
||||
LOG_DEBUG("hasValidLocation RISING EDGE");
|
||||
hasValidLocation = true;
|
||||
shouldPublish = true;
|
||||
// Hold for 20secs after getting a lock to download ephemeris etc
|
||||
fixHoldEnds = millis() + 20000;
|
||||
}
|
||||
|
||||
if (gotLoc && prev_fixQual == 0) { // just got a lock after turning back on.
|
||||
fixHoldEnds = millis() + 20000;
|
||||
shouldPublish = true; // Publish immediately, since next publish is at end of hold
|
||||
}
|
||||
|
||||
bool tooLong = scheduling.searchedTooLong();
|
||||
@ -1134,8 +1137,7 @@ int32_t GPS::runOnce()
|
||||
|
||||
// Once we get a location we no longer desperately want an update
|
||||
if ((gotLoc && gotTime) || tooLong) {
|
||||
|
||||
if (tooLong) {
|
||||
if (tooLong && !gotLoc) {
|
||||
// we didn't get a location during this ack window, therefore declare loss of lock
|
||||
if (hasValidLocation) {
|
||||
LOG_DEBUG("hasValidLocation FALLING EDGE");
|
||||
@ -1143,9 +1145,15 @@ int32_t GPS::runOnce()
|
||||
p = meshtastic_Position_init_default;
|
||||
hasValidLocation = false;
|
||||
}
|
||||
|
||||
down();
|
||||
shouldPublish = true; // publish our update for this just finished acquisition window
|
||||
if (millis() > fixHoldEnds) {
|
||||
shouldPublish = true; // publish our update at the end of the lock hold
|
||||
publishUpdate();
|
||||
down();
|
||||
#ifdef GPS_DEBUG
|
||||
} else {
|
||||
LOG_DEBUG("Holding for GPS data download: %d ms (numSats=%d)", fixHoldEnds - millis(), p.sats_in_view);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// If state has changed do a publish
|
||||
@ -1508,24 +1516,6 @@ static int32_t toDegInt(RawDegrees d)
|
||||
*/
|
||||
bool GPS::lookForTime()
|
||||
{
|
||||
|
||||
#ifdef GNSS_AIROHA
|
||||
uint8_t fix = reader.fixQuality();
|
||||
if (fix >= 1 && fix <= 5) {
|
||||
if (lastFixStartMsec > 0) {
|
||||
if (Throttle::isWithinTimespanMs(lastFixStartMsec, GPS_FIX_HOLD_TIME)) {
|
||||
return false;
|
||||
} else {
|
||||
clearBuffer();
|
||||
}
|
||||
} else {
|
||||
lastFixStartMsec = millis();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
auto ti = reader.time;
|
||||
auto d = reader.date;
|
||||
if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed
|
||||
@ -1564,25 +1554,6 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
||||
*/
|
||||
bool GPS::lookForLocation()
|
||||
{
|
||||
#ifdef GNSS_AIROHA
|
||||
if ((config.position.gps_update_interval * 1000) >= (GPS_FIX_HOLD_TIME * 2)) {
|
||||
uint8_t fix = reader.fixQuality();
|
||||
if (fix >= 1 && fix <= 5) {
|
||||
if (lastFixStartMsec > 0) {
|
||||
if (Throttle::isWithinTimespanMs(lastFixStartMsec, GPS_FIX_HOLD_TIME)) {
|
||||
return false;
|
||||
} else {
|
||||
clearBuffer();
|
||||
}
|
||||
} else {
|
||||
lastFixStartMsec = millis();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// By default, TinyGPS++ does not parse GPGSA lines, which give us
|
||||
// the 2D/3D fixType (see NMEAGPS.h)
|
||||
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)
|
||||
|
@ -159,7 +159,7 @@ class GPS : private concurrency::OSThread
|
||||
uint8_t fixType = 0; // fix type from GPGSA
|
||||
#endif
|
||||
|
||||
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastFixStartMsec = 0;
|
||||
uint32_t fixHoldEnds = 0;
|
||||
uint32_t rx_gpio = 0;
|
||||
uint32_t tx_gpio = 0;
|
||||
|
||||
|
@ -132,6 +132,10 @@ RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpd
|
||||
if (tv->tv_sec < BUILD_EPOCH) {
|
||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||
return RTCSetResultInvalidTime;
|
||||
} else if (tv->tv_sec > (BUILD_EPOCH + FORTY_YEARS)) {
|
||||
LOG_WARN("Ignore time (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch, BUILD_EPOCH,
|
||||
BUILD_EPOCH + FORTY_YEARS);
|
||||
return RTCSetResultInvalidTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -250,6 +254,10 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
if (tv.tv_sec < BUILD_EPOCH) {
|
||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||
return RTCSetResultInvalidTime;
|
||||
} else if (tv.tv_sec > (BUILD_EPOCH + FORTY_YEARS)) {
|
||||
LOG_WARN("Ignore time (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch, BUILD_EPOCH,
|
||||
BUILD_EPOCH + FORTY_YEARS);
|
||||
return RTCSetResultInvalidTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -55,3 +55,6 @@ time_t gm_mktime(struct tm *tm);
|
||||
#define SEC_PER_DAY 86400
|
||||
#define SEC_PER_HOUR 3600
|
||||
#define SEC_PER_MIN 60
|
||||
#ifdef BUILD_EPOCH
|
||||
#define FORTY_YEARS (40UL * 365 * SEC_PER_DAY) // probably time to update your firmware
|
||||
#endif
|
||||
|
@ -263,12 +263,6 @@ void drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
display->drawString(x + 1, y, "USB");
|
||||
}
|
||||
|
||||
// auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, true);
|
||||
|
||||
// display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
|
||||
// if (config.display.heading_bold)
|
||||
// display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode) - 1, y, mode);
|
||||
|
||||
uint32_t currentMillis = millis();
|
||||
uint32_t seconds = currentMillis / 1000;
|
||||
uint32_t minutes = seconds / 60;
|
||||
@ -398,7 +392,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
|
||||
|
||||
// === Second Row: Radio Preset ===
|
||||
auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
|
||||
auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset);
|
||||
char regionradiopreset[25];
|
||||
const char *region = myRegion ? myRegion->name : NULL;
|
||||
if (region != nullptr) {
|
||||
|
@ -1525,7 +1525,7 @@ extern meshtastic_DeviceMetadata getDeviceMetadata()
|
||||
#if ((!HAS_SCREEN || NO_EXT_GPIO) || MESHTASTIC_EXCLUDE_CANNEDMESSAGES) && !defined(MESHTASTIC_INCLUDE_NICHE_GRAPHICS)
|
||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_CANNEDMSG_CONFIG;
|
||||
#endif
|
||||
#if NO_EXT_GPIO
|
||||
#if NO_EXT_GPIO || MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
|
||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_EXTNOTIF_CONFIG;
|
||||
#endif
|
||||
// Only edge case here is if we apply this a device with built in Accelerometer and want to detect interrupts
|
||||
|
@ -368,7 +368,7 @@ const char *Channels::getName(size_t chIndex)
|
||||
// Per mesh.proto spec, if bandwidth is specified we must ignore modemPreset enum, we assume that in that case
|
||||
// the app effed up and forgot to set channelSettings.name
|
||||
if (config.lora.use_preset) {
|
||||
channelName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
|
||||
channelName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset);
|
||||
} else {
|
||||
channelName = "Custom";
|
||||
}
|
||||
@ -382,7 +382,8 @@ bool Channels::isDefaultChannel(ChannelIndex chIndex)
|
||||
const auto &ch = getByIndex(chIndex);
|
||||
if (ch.settings.psk.size == 1 && ch.settings.psk.bytes[0] == 1) {
|
||||
const char *name = getName(chIndex);
|
||||
const char *presetName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
|
||||
const char *presetName =
|
||||
DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset);
|
||||
// Check if the name is the default derived from the modem preset
|
||||
if (strcmp(name, presetName) == 0)
|
||||
return true;
|
||||
|
@ -586,7 +586,8 @@ void RadioInterface::applyModemConfig()
|
||||
|
||||
// Check if we use the default frequency slot
|
||||
RadioInterface::uses_default_frequency_slot =
|
||||
channel_num == hash(DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false)) % numChannels;
|
||||
channel_num ==
|
||||
hash(DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset)) % numChannels;
|
||||
|
||||
// Old frequency selection formula
|
||||
// float freq = myRegion->freqStart + ((((myRegion->freqEnd - myRegion->freqStart) / numChannels) / 2) * channel_num);
|
||||
|
@ -364,9 +364,10 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
// moduleConfig.external_notification.alert_message_buzzer = true;
|
||||
|
||||
if (moduleConfig.external_notification.enabled) {
|
||||
#if !defined(MESHTASTIC_EXCLUDE_INPUTBROKER)
|
||||
if (inputBroker) // put our callback in the inputObserver list
|
||||
inputObserver.observe(inputBroker);
|
||||
|
||||
#endif
|
||||
if (nodeDB->loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig),
|
||||
&meshtastic_RTTTLConfig_msg, &rtttlConfig) != LoadFileResult::LOAD_SUCCESS) {
|
||||
memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone));
|
||||
|
@ -88,7 +88,7 @@
|
||||
#include "modules/StoreForwardModule.h"
|
||||
#endif
|
||||
#endif
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#endif
|
||||
@ -98,12 +98,15 @@
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !MESHTASTIC_EXCLUDE_SERIAL
|
||||
#include "modules/SerialModule.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_DROPZONE
|
||||
#include "modules/DropzoneModule.h"
|
||||
#endif
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ZPS
|
||||
#include "modules/esp32/ZPSModule.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else)
|
||||
*/
|
||||
@ -150,6 +153,9 @@ void setupModules()
|
||||
#if !MESHTASTIC_EXCLUDE_DROPZONE
|
||||
dropzoneModule = new DropzoneModule();
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_ZPS
|
||||
zpsModule = new ZPSModule();
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE
|
||||
new GenericThreadModule();
|
||||
#endif
|
||||
@ -246,8 +252,8 @@ void setupModules()
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
new PowerTelemetryModule();
|
||||
#endif
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#if !MESHTASTIC_EXCLUDE_SERIAL
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
new SerialModule();
|
||||
@ -268,13 +274,11 @@ void setupModules()
|
||||
storeForwardModule = new StoreForwardModule();
|
||||
#endif
|
||||
#endif
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)
|
||||
#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
|
||||
externalNotificationModule = new ExternalNotificationModule();
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_RANGETEST && !MESHTASTIC_EXCLUDE_GPS
|
||||
new RangeTestModule();
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
#if !MESHTASTIC_EXCLUDE_ADMIN
|
||||
|
@ -31,7 +31,7 @@ uint32_t packetSequence = 0;
|
||||
|
||||
int32_t RangeTestModule::runOnce()
|
||||
{
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_PORTDUINO)
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_STM32WL) || defined(ARCH_PORTDUINO)
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the module
|
||||
@ -130,7 +130,7 @@ void RangeTestModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
|
||||
ProcessMessage RangeTestModuleRadio::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_PORTDUINO)
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_STM32WL) || defined(ARCH_PORTDUINO)
|
||||
|
||||
if (moduleConfig.range_test.enabled) {
|
||||
|
||||
|
@ -49,8 +49,8 @@
|
||||
#include "meshSolarApp.h"
|
||||
#endif
|
||||
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
#define RX_BUFFER 256
|
||||
#define TIMEOUT 250
|
||||
@ -67,7 +67,7 @@ SerialModuleRadio *serialModuleRadio;
|
||||
defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE)
|
||||
SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial") {}
|
||||
static Print *serialPrint = &Serial;
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(RAK3172)
|
||||
SerialModule::SerialModule() : StreamAPI(&Serial1), concurrency::OSThread("Serial") {}
|
||||
static Print *serialPrint = &Serial1;
|
||||
#else
|
||||
@ -173,7 +173,18 @@ int32_t SerialModule::runOnce()
|
||||
Serial.begin(baud);
|
||||
Serial.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
|
||||
}
|
||||
|
||||
#elif defined(ARCH_STM32WL)
|
||||
#ifndef RAK3172
|
||||
HardwareSerial *serialInstance = &Serial2;
|
||||
#else
|
||||
HardwareSerial *serialInstance = &Serial1;
|
||||
#endif
|
||||
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
|
||||
serialInstance->setTx(moduleConfig.serial.txd);
|
||||
serialInstance->setRx(moduleConfig.serial.rxd);
|
||||
}
|
||||
serialInstance->begin(baud);
|
||||
serialInstance->setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
|
||||
#elif defined(ARCH_ESP32)
|
||||
|
||||
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
|
||||
@ -260,8 +271,13 @@ int32_t SerialModule::runOnce()
|
||||
while (Serial1.available()) {
|
||||
serialPayloadSize = Serial1.readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
||||
#else
|
||||
while (Serial2.available()) {
|
||||
serialPayloadSize = Serial2.readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
||||
#ifndef RAK3172
|
||||
HardwareSerial *serialInstance = &Serial2;
|
||||
#else
|
||||
HardwareSerial *serialInstance = &Serial1;
|
||||
#endif
|
||||
while (serialInstance->available()) {
|
||||
serialPayloadSize = serialInstance->readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
||||
#endif
|
||||
serialModuleRadio->sendPayload();
|
||||
}
|
||||
@ -511,7 +527,7 @@ ParsedLine parseLine(const char *line)
|
||||
void SerialModule::processWXSerial()
|
||||
{
|
||||
#if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \
|
||||
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M5)
|
||||
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M5) && !defined(ARCH_STM32WL)
|
||||
static unsigned int lastAveraged = 0;
|
||||
static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded.
|
||||
static double dir_sum_sin = 0;
|
||||
|
@ -8,8 +8,8 @@
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
class SerialModule : public StreamAPI, private concurrency::OSThread
|
||||
{
|
||||
|
419
src/modules/esp32/ZPSModule.cpp
Normal file
419
src/modules/esp32/ZPSModule.cpp
Normal file
@ -0,0 +1,419 @@
|
||||
/*
|
||||
* ZPS - Zero-GPS Positioning System for standalone Meshtastic devices
|
||||
* - experimental tools for estimating own position without a GPS -
|
||||
*
|
||||
* Copyright 2021 all rights reserved by https://github.com/a-f-G-U-C
|
||||
* Released under GPL v3 (see LICENSE file for details)
|
||||
*/
|
||||
|
||||
#include "ZPSModule.h"
|
||||
#include "Default.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "NodeStatus.h"
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include "gps/RTC.h"
|
||||
#include <WiFi.h>
|
||||
|
||||
#if !defined(MESHTASTIC_EXCLUDE_BLUETOOTH)
|
||||
|
||||
#include "NimBLEDevice.h"
|
||||
|
||||
#define BLE_MAX_REC 15
|
||||
#define BLE_NO_RESULTS -1 // Indicates a BLE scan is in progress
|
||||
|
||||
uint8_t bleCounter = 0; // used internally by the ble scanner
|
||||
uint64_t bleResult[BLE_MAX_REC + 1];
|
||||
int bleResSize = BLE_NO_RESULTS;
|
||||
|
||||
uint64_t scanStart = 0;
|
||||
|
||||
ZPSModule *zpsModule;
|
||||
|
||||
// Mini BLE scanner, NIMBLE based and modelled loosely after the Wifi scanner
|
||||
static int ble_scan(uint32_t duration, bool passive = true, bool dedup = true);
|
||||
|
||||
// ZPSModule::ZPSModule()
|
||||
// : ProtobufModule("ZPS", ZPS_PORTNUM, Position_fields), concurrency::OSThread("ZPSModule")
|
||||
ZPSModule::ZPSModule() : SinglePortModule("ZPS", ZPS_PORTNUM), concurrency::OSThread("ZPSModule")
|
||||
{
|
||||
setIntervalFromNow(ZPS_STARTUP_DELAY); // Delay startup by 10 seconds, no need to race :)
|
||||
|
||||
wantBSS = true;
|
||||
wantBLE = true;
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.disconnect();
|
||||
WiFi.scanNetworks(true, true); // nonblock, showhidden
|
||||
scanState = SCAN_BSS_RUN;
|
||||
}
|
||||
|
||||
ProcessMessage ZPSModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
meshtastic_Position pos = meshtastic_Position_init_default;
|
||||
|
||||
auto &pd = mp.decoded;
|
||||
uint8_t nRecs = pd.payload.size >> 3;
|
||||
|
||||
LOG_DEBUG("handleReceived %s 0x%0x->0x%0x, id=0x%x, port=%d, len=%d, rec=%d\n", name, mp.from, mp.to, mp.id, pd.portnum,
|
||||
pd.payload.size, nRecs);
|
||||
if (nRecs > ZPS_DATAPKT_MAXITEMS)
|
||||
nRecs = ZPS_DATAPKT_MAXITEMS;
|
||||
memcpy(&netData, pd.payload.bytes, nRecs << 3);
|
||||
|
||||
// Currently we are unable to act as a position server, so we're
|
||||
// not interested in broadcasts (this will change later)
|
||||
if (mp.to != nodeDB->getNodeNum()) {
|
||||
// Message is not for us, won't process
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
|
||||
#ifdef ZPS_EXTRAVERBOSE
|
||||
for (int i = 0; i < nRecs; i++) {
|
||||
LOG_DEBUG("ZPS[%d]: %08x"
|
||||
"%08x\n",
|
||||
i, (uint32_t)(netData[i] >> 32), (uint32_t)netData[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((netData[0] & 0x800000000000) && (nRecs >= 2)) {
|
||||
// message contains a position
|
||||
pos.PDOP = (netData[0] >> 40) & 0x7f;
|
||||
pos.timestamp = netData[0] & 0xffffffff;
|
||||
// second int64 encodes lat and lon
|
||||
pos.longitude_i = (int32_t)(netData[1] & 0xffffffff);
|
||||
pos.latitude_i = (int32_t)((netData[1] >> 32) & 0xffffffff);
|
||||
|
||||
// FIXME should be conditional, to ensure we don't overwrite a good GPS fix!
|
||||
LOG_DEBUG("ZPS lat/lon/dop/pts %d/%d/%d/%d\n", pos.latitude_i, pos.longitude_i, pos.PDOP, pos.timestamp);
|
||||
|
||||
// Some required fields
|
||||
pos.time = getTime();
|
||||
pos.location_source = meshtastic_Position_LocSource_LOC_EXTERNAL;
|
||||
|
||||
// don't update position if my gps fix is valid
|
||||
if (nodeDB->hasValidPosition(nodeDB->getMeshNode(nodeDB->getNodeNum()))) {
|
||||
LOG_DEBUG("ZPSModule::handleReceived: ignoring position update, GPS is valid\n");
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
nodeDB->updatePosition(nodeDB->getNodeNum(), pos);
|
||||
} else {
|
||||
// nothing we can do - for now
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
meshtastic_MeshPacket *ZPSModule::allocReply()
|
||||
{
|
||||
meshtastic_MeshPacket *p = allocDataPacket();
|
||||
p->decoded.payload.size = (netRecs + 2) << 3; // actually can be only +1 if no GPS data
|
||||
|
||||
LOG_DEBUG("Allocating dataPacket for %d items, %d bytes\n", netRecs, p->decoded.payload.size);
|
||||
memcpy(p->decoded.payload.bytes, &netData, p->decoded.payload.size);
|
||||
|
||||
return (p);
|
||||
}
|
||||
|
||||
void ZPSModule::sendDataPacket(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
// cancel any not yet sent (now stale) position packets
|
||||
if (prevPacketId)
|
||||
service->cancelSending(prevPacketId);
|
||||
|
||||
meshtastic_MeshPacket *p = allocReply();
|
||||
p->to = dest;
|
||||
p->decoded.portnum = meshtastic_PortNum_ZPS_APP;
|
||||
p->decoded.want_response = wantReplies;
|
||||
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
prevPacketId = p->id;
|
||||
|
||||
service->sendToMesh(p, RX_SRC_LOCAL);
|
||||
}
|
||||
|
||||
int32_t ZPSModule::runOnce()
|
||||
{
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
assert(node);
|
||||
|
||||
// LOG_DEBUG("ZPSModule::runOnce() START, scanState: %d\n", (int) scanState);
|
||||
|
||||
int numWifi = 0;
|
||||
|
||||
if (scanState == SCAN_BSS_RUN) {
|
||||
// check completion status of any running Wifi scan
|
||||
numWifi = WiFi.scanComplete();
|
||||
|
||||
if (numWifi >= 0) {
|
||||
// scan is complete
|
||||
LOG_DEBUG("%d BSS found\n", numWifi);
|
||||
LOG_DEBUG("BSS scan done in %d millis\n", millis() - scanStart);
|
||||
|
||||
if (wantBSS && haveBSS) {
|
||||
// old data exists, overwrite it
|
||||
netRecs = 0;
|
||||
haveBSS = haveBLE = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numWifi; i++) {
|
||||
// pack each Wifi network record into a 64-bit int
|
||||
uint64_t netBytes = encodeBSS(WiFi.BSSID(i), WiFi.channel(i), abs(WiFi.RSSI(i)));
|
||||
|
||||
if (wantBSS) {
|
||||
// load into outbound array if needed
|
||||
outBufAdd(netBytes);
|
||||
haveBSS = true;
|
||||
}
|
||||
#ifdef ZPS_EXTRAVERBOSE
|
||||
LOG_DEBUG("BSS[%02d]: %08x"
|
||||
"%08x\n",
|
||||
i, (uint32_t)(netBytes >> 32), (uint32_t)netBytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
WiFi.scanDelete();
|
||||
scanState = SCAN_BSS_DONE;
|
||||
|
||||
#ifdef ZPS_EXTRAVERBOSE
|
||||
} else if (numWifi == -1) {
|
||||
// LOG_DEBUG("BSS scan in-progress\n");
|
||||
} else {
|
||||
LOG_DEBUG("BSS scan state=%d\n", numWifi);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if ((scanState == SCAN_BLE_RUN) && (bleResSize >= 0)) {
|
||||
// completion status checked above (bleResSize >= 0)
|
||||
LOG_DEBUG("BLE scan done in %d millis\n", millis() - scanStart);
|
||||
scanState = SCAN_BLE_DONE;
|
||||
|
||||
if (wantBLE && haveBLE) {
|
||||
// old data exists, overwrite it
|
||||
netRecs = 0;
|
||||
haveBSS = haveBLE = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < bleResSize; i++) {
|
||||
// load data into output array if needed
|
||||
if (wantBLE) {
|
||||
outBufAdd(bleResult[i]);
|
||||
haveBLE = true;
|
||||
}
|
||||
#ifdef ZPS_EXTRAVERBOSE
|
||||
LOG_DEBUG("BLE[%d]: %08x"
|
||||
"%08x\n",
|
||||
i, (uint32_t)(bleResult[i] >> 32), (uint32_t)bleResult[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Reset the counter once we're done with the dataset
|
||||
bleResSize = BLE_NO_RESULTS;
|
||||
}
|
||||
|
||||
// Are we finished assembling that packet? Then send it out
|
||||
if ((wantBSS == haveBSS) && (wantBLE == haveBLE) &&
|
||||
airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
|
||||
airTime->isTxAllowedAirUtil() &&
|
||||
(lastSend == 0 || millis() - lastSend >= Default::getConfiguredOrDefaultMsScaled(config.position.position_broadcast_secs,
|
||||
default_broadcast_interval_secs,
|
||||
nodeStatus->getNumOnline()))) {
|
||||
|
||||
haveBSS = haveBLE = false;
|
||||
sendDataPacket(NODENUM_BROADCAST, false); // no replies
|
||||
lastSend = millis();
|
||||
netRecs = 0; // reset packet
|
||||
}
|
||||
|
||||
/*
|
||||
* State machine transitions
|
||||
*
|
||||
* FIXME could be managed better, for example: check if we require
|
||||
* each type of scan (wantBSS/wantBLE), and if not, don't start it!
|
||||
*/
|
||||
if (scanState == SCAN_BLE_DONE) {
|
||||
// BLE done, transition to BSS scanning
|
||||
scanStart = millis();
|
||||
LOG_DEBUG("BSS scan start t=%d\n", scanStart);
|
||||
if (WiFi.scanNetworks(true, true) == WIFI_SCAN_RUNNING) // nonblock, showhidden
|
||||
scanState = SCAN_BSS_RUN;
|
||||
|
||||
} else if (scanState == SCAN_BSS_DONE) {
|
||||
// BSS done, transition to BLE scanning
|
||||
scanStart = millis();
|
||||
LOG_DEBUG("BLE scan start t=%d\n", scanStart);
|
||||
if (ble_scan(ZPS_BLE_SCANTIME) == 0)
|
||||
scanState = SCAN_BLE_RUN;
|
||||
}
|
||||
|
||||
// LOG_DEBUG("ZPSModule::runOnce() DONE, scanState=%d\n", scanState);
|
||||
if ((scanState == SCAN_BSS_RUN) || (scanState == SCAN_BLE_RUN)) {
|
||||
return 1000; // scan in progress, re-check soon
|
||||
}
|
||||
|
||||
return 5000;
|
||||
}
|
||||
|
||||
uint64_t encodeBSS(uint8_t *bssid, uint8_t chan, uint8_t absRSSI)
|
||||
{
|
||||
uint64_t netBytes = absRSSI & 0xff;
|
||||
netBytes <<= 8;
|
||||
netBytes |= (chan & 0xff);
|
||||
|
||||
for (uint8_t b = 0; b < 6; b++) {
|
||||
netBytes <<= 8;
|
||||
netBytes |= bssid[b];
|
||||
}
|
||||
|
||||
return netBytes;
|
||||
}
|
||||
|
||||
uint64_t encodeBLE(uint8_t *addr, uint8_t absRSSI)
|
||||
{
|
||||
uint64_t netBytes = absRSSI & 0xff;
|
||||
netBytes <<= 8;
|
||||
netBytes |= 0xff; // "channel" byte reserved in BLE records
|
||||
|
||||
for (uint8_t b = 0; b < 6; b++) {
|
||||
netBytes <<= 8;
|
||||
netBytes |= addr[5 - b] & 0xff;
|
||||
}
|
||||
|
||||
return netBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler
|
||||
*/
|
||||
static int ble_gap_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
// Adverts matching certain patterns are useless for positioning purposes
|
||||
// (ephemeral MAC etc), so try excluding them if possible
|
||||
//
|
||||
// TODO: Expand the list of reject patterns for BLE adverts.
|
||||
// There are likely more than 10 patterns to test and reject, including most Apple devices and others.
|
||||
//
|
||||
// TODO: Implement full packet search for reject patterns (use memmem() or similar),
|
||||
// not just at the beginning (currently uses memcmp()).
|
||||
|
||||
const uint8_t rejPat[] = {0x1e, 0xff, 0x06, 0x00, 0x01}; // one of many
|
||||
|
||||
struct ble_hs_adv_fields fields;
|
||||
int rc;
|
||||
int i = 0;
|
||||
|
||||
uint64_t netBytes = 0;
|
||||
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_DISC:
|
||||
// called once for every BLE advert received
|
||||
rc = ble_hs_adv_parse_fields(&fields, event->disc.data, event->disc.length_data);
|
||||
if (rc != 0)
|
||||
return 0;
|
||||
|
||||
if (bleResSize != BLE_NO_RESULTS)
|
||||
// as far as we know, we're not in the middle of a BLE scan!
|
||||
LOG_DEBUG("Unexpected BLE_GAP_EVENT_DISC!\n");
|
||||
|
||||
#ifdef ZPS_EXTRAVERBOSE
|
||||
// Dump the advertisement packet
|
||||
DEBUG_PORT.hexDump("DEBUG", (unsigned char *)event->disc.data, event->disc.length_data);
|
||||
#endif
|
||||
// Reject beacons known to be unreliable (ephemeral etc)
|
||||
if (memcmp(event->disc.data, rejPat, sizeof(rejPat)) == 0) {
|
||||
LOG_DEBUG("(BLE item filtered by pattern)\n");
|
||||
return 0; // Processing-wise, it's still a success
|
||||
}
|
||||
|
||||
//
|
||||
// STORE THE RESULTS IN A SORTED LIST
|
||||
//
|
||||
|
||||
// first, pack each BLE item reading into a 64-bit int
|
||||
netBytes = encodeBLE(event->disc.addr.val, abs(event->disc.rssi));
|
||||
|
||||
// SOME DUPLICATES SURVIVE through filter_duplicates = 1, catch them here
|
||||
// Duplicate filtering is now handled in the sorting loop below,
|
||||
// but right now we write for clarity not optimization
|
||||
for (i = 0; i < bleCounter; i++) {
|
||||
if ((bleResult[i] & 0xffffffffffff) == (netBytes & 0xffffffffffff)) {
|
||||
LOG_DEBUG("(BLE duplicate filtered)\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ZPS_EXTRAVERBOSE
|
||||
// redundant extraverbosity, but I need it for duplicate hunting
|
||||
LOG_DEBUG("BL_[%02d]: %08x"
|
||||
"%08x\n",
|
||||
bleCounter, (uint32_t)(netBytes >> 32), (uint32_t)netBytes);
|
||||
#endif
|
||||
// then insert item into a list (up to BLE_MAX_REC records), sorted by RSSI
|
||||
for (i = 0; i < bleCounter; i++) {
|
||||
// find first element greater than ours, that will be our insertion point
|
||||
if (bleResult[i] > netBytes)
|
||||
break;
|
||||
}
|
||||
// any other records move down one position to vacate res[i]
|
||||
for (int j = bleCounter; j > i; j--)
|
||||
bleResult[j] = bleResult[j - 1];
|
||||
// write new element at insertion point
|
||||
bleResult[i] = netBytes;
|
||||
|
||||
// advance tail of list, but not beyond limit
|
||||
if (bleCounter < BLE_MAX_REC)
|
||||
bleCounter++;
|
||||
|
||||
return 0; // SUCCESS
|
||||
|
||||
case BLE_GAP_EVENT_DISC_COMPLETE:
|
||||
LOG_DEBUG("EVENT_DISC_COMPLETE in %d millis\n", (millis() - scanStart));
|
||||
LOG_DEBUG("%d BLE found\n", bleCounter);
|
||||
bleResSize = bleCounter;
|
||||
|
||||
bleCounter = 0; // reset counter
|
||||
return 0; // SUCCESS
|
||||
|
||||
default:
|
||||
return 0; // SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the GAP general discovery procedure (non-blocking)
|
||||
*/
|
||||
static int ble_scan(uint32_t duration, bool passive, bool dedup)
|
||||
{
|
||||
uint8_t own_addr_type;
|
||||
struct ble_gap_disc_params disc_params;
|
||||
int rc;
|
||||
|
||||
// Figure out address type to use
|
||||
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (rc != 0) {
|
||||
LOG_DEBUG("error determining address type; rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Scanning parameters, these are mostly default
|
||||
disc_params.itvl = 0;
|
||||
disc_params.window = 0;
|
||||
disc_params.filter_policy = 0;
|
||||
disc_params.limited = 0;
|
||||
|
||||
// These two params are the more interesting ones
|
||||
disc_params.filter_duplicates = dedup; // self-explanatory
|
||||
disc_params.passive = passive; // passive uses less power
|
||||
|
||||
// Start scanning process (non-blocking) and return
|
||||
rc = ble_gap_disc(own_addr_type, duration, &disc_params, ble_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
LOG_DEBUG("error initiating GAP discovery; rc=%d\n", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif // MESHTASTIC_EXCLUDE_BLUETOOTH
|
86
src/modules/esp32/ZPSModule.h
Normal file
86
src/modules/esp32/ZPSModule.h
Normal file
@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
#include "SinglePortModule.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "gps/RTC.h"
|
||||
|
||||
#define ZPS_PORTNUM meshtastic_PortNum_ZPS_APP
|
||||
|
||||
#define ZPS_DATAPKT_MAXITEMS 20 // max number of records to pack in an outbound packet (~10)
|
||||
#define ZPS_STARTUP_DELAY 10000 // Module startup delay in millis
|
||||
|
||||
// Duration of a BLE scan in millis.
|
||||
// We want this number to be SLIGHTLY UNDER an integer number of seconds,
|
||||
// to be able to catch the result as fresh as possible on a 1-second polling loop
|
||||
#define ZPS_BLE_SCANTIME 2900 // millis
|
||||
|
||||
enum SCANSTATE { SCAN_NONE, SCAN_BSS_RUN, SCAN_BSS_DONE, SCAN_BLE_RUN, SCAN_BLE_DONE };
|
||||
|
||||
/*
|
||||
* Data packing "compression" functions
|
||||
* Ingest a WiFi BSSID, channel and RSSI (or BLE address and RSSI)
|
||||
* and encode them into a packed uint64
|
||||
*/
|
||||
uint64_t encodeBSS(uint8_t *bssid, uint8_t chan, uint8_t absRSSI);
|
||||
uint64_t encodeBLE(uint8_t *addr, uint8_t absRSSI);
|
||||
|
||||
class ZPSModule : public SinglePortModule, private concurrency::OSThread
|
||||
{
|
||||
/// The id of the last packet we sent, to allow us to cancel it if we make something fresher
|
||||
PacketId prevPacketId = 0;
|
||||
|
||||
/// We limit our broadcasts to a max rate
|
||||
uint32_t lastSend = 0;
|
||||
|
||||
bool wantBSS = true;
|
||||
bool haveBSS = false;
|
||||
|
||||
bool wantBLE = true;
|
||||
bool haveBLE = false;
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
ZPSModule();
|
||||
|
||||
/**
|
||||
* Send our radio environment data into the mesh
|
||||
*/
|
||||
void sendDataPacket(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
|
||||
protected:
|
||||
/** Called to handle a particular incoming message
|
||||
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp);
|
||||
|
||||
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||
* so that subclasses can (optionally) send a response back to the original sender. */
|
||||
virtual meshtastic_MeshPacket *allocReply();
|
||||
|
||||
/** Does our periodic broadcast */
|
||||
virtual int32_t runOnce();
|
||||
|
||||
private:
|
||||
// outbound data packet staging buffer and record counter
|
||||
uint64_t netData[ZPS_DATAPKT_MAXITEMS + 2] = {0};
|
||||
uint8_t netRecs = 0;
|
||||
|
||||
// mini state machine to alternate between BSS(Wifi) and BLE scanning
|
||||
SCANSTATE scanState = SCAN_NONE;
|
||||
|
||||
inline void outBufAdd(uint64_t netBytes)
|
||||
{
|
||||
// If this is the first record, initialize the header with the current time and reset the record count.
|
||||
if (!netRecs) {
|
||||
netData[0] = getTime();
|
||||
netData[1] = 0;
|
||||
}
|
||||
|
||||
// push to buffer and update counter
|
||||
if (netRecs < ZPS_DATAPKT_MAXITEMS)
|
||||
netData[2 + (netRecs++)] = netBytes;
|
||||
}
|
||||
};
|
||||
|
||||
extern ZPSModule *zpsModule;
|
@ -124,8 +124,7 @@ extern "C" {
|
||||
#define GPS_RTC_INT (0 + 15) // P0.15, normal is LOW, wake by HIGH
|
||||
#define GPS_RESETB_OUT (32 + 14) // P1.14, always input pull_up
|
||||
|
||||
#define GPS_FIX_HOLD_TIME 15000 // ms
|
||||
#define BATTERY_PIN 2 // P0.02/AIN0, BAT_ADC
|
||||
#define BATTERY_PIN 2 // P0.02/AIN0, BAT_ADC
|
||||
#define BATTERY_IMMUTABLE
|
||||
#define ADC_MULTIPLIER (2.0F)
|
||||
// P0.04/AIN2 is VCC_ADC, P0.05/AIN3 is CHARGER_DET, P1.03 is CHARGE_STA, P1.04 is CHARGE_DONE
|
||||
|
@ -123,7 +123,6 @@ extern "C" {
|
||||
#define GPS_RESETB_OUT (32 + 14) // P1.14, awlays input pull_up
|
||||
|
||||
// #define GPS_THREAD_INTERVAL 50
|
||||
#define GPS_FIX_HOLD_TIME 15000 // ms
|
||||
|
||||
#define BATTERY_PIN 2
|
||||
// #define ADC_CHANNEL ADC1_GPIO2_CHANNEL
|
||||
@ -157,4 +156,4 @@ extern "C" {
|
||||
* Arduino objects - C++ only
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#endif // _VARIANT_WIO_SDK_WM1110_
|
||||
#endif // _VARIANT_WIO_SDK_WM1110_
|
||||
|
@ -6,6 +6,10 @@ board_upload.maximum_size = 233472 ; reserve the last 28KB for filesystem
|
||||
build_flags =
|
||||
${stm32_base.build_flags}
|
||||
-Ivariants/stm32/rak3172
|
||||
-DRAK3172
|
||||
-DENABLE_HWSERIAL1
|
||||
-DPIN_SERIAL1_RX=PB7
|
||||
-DPIN_SERIAL1_TX=PB6
|
||||
-DPIN_WIRE_SDA=PA11
|
||||
-DPIN_WIRE_SCL=PA12
|
||||
-DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR=1
|
||||
|
Loading…
Reference in New Issue
Block a user