Merge branch 'master' into upstream-heltec

This commit is contained in:
Ben Meadors
2022-12-21 07:45:18 -06:00
committed by GitHub
co-authored by GitHub
59 changed files with 1065 additions and 633 deletions
+3 -3
View File
@@ -17,9 +17,9 @@ jobs:
- name: Download nanopb - name: Download nanopb
run: | run: |
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.6-linux-x86.tar.gz wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.7-linux-x86.tar.gz
tar xvzf nanopb-0.4.6-linux-x86.tar.gz tar xvzf nanopb-0.4.7-linux-x86.tar.gz
mv nanopb-0.4.6-linux-x86 nanopb-0.4.6 mv nanopb-0.4.7-linux-x86 nanopb-0.4.7
- name: Re-generate protocol buffers - name: Re-generate protocol buffers
run: | run: |
+3 -1
View File
@@ -26,6 +26,7 @@ build_flags =
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2 -DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20 -DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
-DDEBUG_HEAP
lib_deps = lib_deps =
${arduino_base.lib_deps} ${arduino_base.lib_deps}
@@ -33,7 +34,8 @@ lib_deps =
${environmental_base.lib_deps} ${environmental_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2 https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.0 h2zero/NimBLE-Arduino@^1.4.0
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6 https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
caveman99/ESP32 Codec2@^1.0.1
lib_ignore = lib_ignore =
segger_rtt segger_rtt
+47
View File
@@ -0,0 +1,47 @@
[esp32s2_base]
extends = arduino_base
platform = platformio/espressif32@^5.2.0
build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> -<nimble/>
upload_speed = 961200
monitor_speed = 115200
debug_init_break = tbreak setup
monitor_filters = esp32_exception_decoder
board_build.filesystem = littlefs
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
# See library directory for BLE logging possible values: .pio/libdeps/tbeam/NimBLE-Arduino/src/log_common/log_common.h
# This overrides the BLE logging default of LOG_LEVEL_INFO (1) from: .pio/libdeps/tbeam/NimBLE-Arduino/src/esp_nimble_cfg.h
build_flags =
${arduino_base.build_flags}
-Wall
-Wextra
-Isrc/platform/esp32
-std=c++11
-DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
-DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL
-DAXP_DEBUG_PORT=Serial
-DCONFIG_BT_NIMBLE_ENABLED
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
-DHAS_BLUETOOTH=0
-DDEBUG_HEAP
lib_deps =
${arduino_base.lib_deps}
${networking_base.lib_deps}
${environmental_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
caveman99/ESP32 Codec2@^1.0.1
lib_ignore =
segger_rtt
ESP32 BLE Arduino
; customize the partition table
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
board_build.partitions = partition-table.csv
+4 -2
View File
@@ -23,9 +23,10 @@ build_flags =
-DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL
-DAXP_DEBUG_PORT=Serial -DAXP_DEBUG_PORT=Serial
-DCONFIG_BT_NIMBLE_ENABLED -DCONFIG_BT_NIMBLE_ENABLED
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2 -DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20 -DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
-DDEBUG_HEAP
lib_deps = lib_deps =
${arduino_base.lib_deps} ${arduino_base.lib_deps}
@@ -34,6 +35,7 @@ lib_deps =
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2 https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.0 h2zero/NimBLE-Arduino@^1.4.0
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6 https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
caveman99/ESP32 Codec2@^1.0.1
lib_ignore = lib_ignore =
segger_rtt segger_rtt
+1 -1
View File
@@ -1 +1 @@
cd protobufs && ..\nanopb-0.4.6\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs *.proto cd protobufs && ..\nanopb-0.4.7\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs *.proto
+3 -3
View File
@@ -2,13 +2,13 @@
set -e set -e
echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.6 to be located in the" echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.7 to be located in the"
echo "firmware root directory if the following step fails, you should download the correct" echo "firmware root directory if the following step fails, you should download the correct"
echo "prebuilt binaries for your computer into nanopb-0.4.6" echo "prebuilt binaries for your computer into nanopb-0.4.7"
# the nanopb tool seems to require that the .options file be in the current directory! # the nanopb tool seems to require that the .options file be in the current directory!
cd protobufs cd protobufs
../nanopb-0.4.6/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated -I=../protobufs *.proto ../nanopb-0.4.7/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated -I=../protobufs *.proto
#echo "Regenerating protobuf documentation - if you see an error message" #echo "Regenerating protobuf documentation - if you see an error message"
#echo "you can ignore it unless doing a new protobuf release to github." #echo "you can ignore it unless doing a new protobuf release to github."
+15 -2
View File
@@ -51,6 +51,7 @@ class ButtonThread : public concurrency::OSThread
pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE); pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE);
#endif #endif
userButton.attachClick(userButtonPressed); userButton.attachClick(userButtonPressed);
userButton.setClickTicks(300);
userButton.attachDuringLongPress(userButtonPressedLong); userButton.attachDuringLongPress(userButtonPressedLong);
userButton.attachDoubleClick(userButtonDoublePressed); userButton.attachDoubleClick(userButtonDoublePressed);
userButton.attachMultiClick(userButtonMultiPressed); userButton.attachMultiClick(userButtonMultiPressed);
@@ -159,9 +160,21 @@ class ButtonThread : public concurrency::OSThread
static void userButtonDoublePressed() static void userButtonDoublePressed()
{ {
#if defined(USE_EINK) && defined(PIN_EINK_EN) #if defined(USE_EINK) && defined(PIN_EINK_EN)
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW); digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
#endif #endif
#if defined(GPS_POWER_TOGGLE)
if(config.position.gps_enabled)
{
DEBUG_MSG("Flag set to false for gps power\n");
}
else
{
DEBUG_MSG("Flag set to true to restore power\n");
}
config.position.gps_enabled = !(config.position.gps_enabled);
doGPSpowersave(config.position.gps_enabled);
#endif
} }
static void userButtonMultiPressed() static void userButtonMultiPressed()
+7 -2
View File
@@ -20,16 +20,19 @@ class GPSStatus : public Status
bool hasLock = false; // default to false, until we complete our first read bool hasLock = false; // default to false, until we complete our first read
bool isConnected = false; // Do we have a GPS we are talking to bool isConnected = false; // Do we have a GPS we are talking to
bool isPowerSaving = false; //Are we in power saving state
Position p = Position_init_default; Position p = Position_init_default;
public: public:
GPSStatus() { statusType = STATUS_TYPE_GPS; } GPSStatus() { statusType = STATUS_TYPE_GPS; }
// preferred method // preferred method
GPSStatus(bool hasLock, bool isConnected, const Position &pos) : Status() GPSStatus(bool hasLock, bool isConnected, bool isPowerSaving, const Position &pos) : Status()
{ {
this->hasLock = hasLock; this->hasLock = hasLock;
this->isConnected = isConnected; this->isConnected = isConnected;
this->isPowerSaving = isPowerSaving;
// all-in-one struct copy // all-in-one struct copy
this->p = pos; this->p = pos;
@@ -44,6 +47,8 @@ class GPSStatus : public Status
bool getIsConnected() const { return isConnected; } bool getIsConnected() const { return isConnected; }
bool getIsPowerSaving() const { return isPowerSaving;}
int32_t getLatitude() const int32_t getLatitude() const
{ {
if (config.position.fixed_position) { if (config.position.fixed_position) {
@@ -94,7 +99,7 @@ class GPSStatus : public Status
#ifdef GPS_EXTRAVERBOSE #ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.pos_timestamp, p.pos_timestamp); DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.pos_timestamp, p.pos_timestamp);
#endif #endif
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected || return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected || newStatus->isPowerSaving !=isPowerSaving ||
newStatus->p.latitude_i != p.latitude_i || newStatus->p.longitude_i != p.longitude_i || newStatus->p.latitude_i != p.latitude_i || newStatus->p.longitude_i != p.longitude_i ||
newStatus->p.altitude != p.altitude || newStatus->p.altitude_hae != p.altitude_hae || newStatus->p.altitude != p.altitude || newStatus->p.altitude_hae != p.altitude_hae ||
newStatus->p.PDOP != p.PDOP || newStatus->p.ground_track != p.ground_track || newStatus->p.PDOP != p.PDOP || newStatus->p.ground_track != p.ground_track ||
+9
View File
@@ -182,6 +182,9 @@ Power::Power() : OSThread("Power")
{ {
statusHandler = {}; statusHandler = {};
low_voltage_counter = 0; low_voltage_counter = 0;
#ifdef DEBUG_HEAP
lastheap = ESP.getFreeHeap();
#endif
} }
bool Power::analogInit() bool Power::analogInit()
@@ -283,6 +286,12 @@ void Power::readPowerStatus()
DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(), DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(),
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent()); powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
newStatus.notifyObservers(&powerStatus2); newStatus.notifyObservers(&powerStatus2);
#ifdef DEBUG_HEAP
if (lastheap != ESP.getFreeHeap()){
DEBUG_MSG("Heap status: %d/%d bytes free (%d), running %d threads\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreeHeap() - lastheap , concurrency::mainController.size(false));
lastheap = ESP.getFreeHeap();
}
#endif
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 3 low readings in a row // If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 3 low readings in a row
// Supect fluctuating voltage on the RAK4631 to force it to deep sleep even if battery is at 85% after only a few days // Supect fluctuating voltage on the RAK4631 to force it to deep sleep even if battery is at 85% after only a few days
+1 -4
View File
@@ -326,10 +326,10 @@ void PowerFSM_setup()
powerFSM.add_timed_transition(&stateON, &stateDARK, getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout"); powerFSM.add_timed_transition(&stateON, &stateDARK, getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout");
#ifdef ARCH_ESP32
// On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK // On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK
State *lowPowerState = &stateLS; State *lowPowerState = &stateLS;
#ifdef ARCH_ESP32
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally) // We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
// See: https://github.com/meshtastic/firmware/issues/1071 // See: https://github.com/meshtastic/firmware/issues/1071
@@ -340,9 +340,6 @@ void PowerFSM_setup()
if (config.power.sds_secs != UINT32_MAX) if (config.power.sds_secs != UINT32_MAX)
powerFSM.add_timed_transition(lowPowerState, &stateSDS, getConfiguredOrDefaultMs(config.power.sds_secs), NULL, "mesh timeout"); powerFSM.add_timed_transition(lowPowerState, &stateSDS, getConfiguredOrDefaultMs(config.power.sds_secs), NULL, "mesh timeout");
#elif defined (ARCH_NRF52)
lowPowerState = &stateDARK;
#endif #endif
+14
View File
@@ -117,6 +117,20 @@ float AirTime::utilizationTXPercent()
return (float(sum) / float(MS_IN_HOUR)) * 100; return (float(sum) / float(MS_IN_HOUR)) * 100;
} }
// Get the amount of minutes we have to be silent before we can send again
uint8_t AirTime::getSilentMinutes(float txPercent, float dutyCycle)
{
float newTxPercent = txPercent;
for (int8_t i = MINUTES_IN_HOUR-1; i >= 0; --i) {
newTxPercent -= ((float)this->utilizationTX[i] / (MS_IN_MINUTE * MINUTES_IN_HOUR / 100));
if (newTxPercent < dutyCycle)
return MINUTES_IN_HOUR-1-i;
}
return MINUTES_IN_HOUR;
}
AirTime::AirTime() : concurrency::OSThread("AirTime"),airtimes({}) { AirTime::AirTime() : concurrency::OSThread("AirTime"),airtimes({}) {
} }
+2
View File
@@ -29,6 +29,7 @@
#define PERIODS_TO_LOG 8 #define PERIODS_TO_LOG 8
#define MINUTES_IN_HOUR 60 #define MINUTES_IN_HOUR 60
#define SECONDS_IN_MINUTE 60 #define SECONDS_IN_MINUTE 60
#define MS_IN_MINUTE (SECONDS_IN_MINUTE * 1000)
#define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000) #define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000)
@@ -57,6 +58,7 @@ class AirTime : private concurrency::OSThread
uint32_t getSecondsPerPeriod(); uint32_t getSecondsPerPeriod();
uint32_t getSecondsSinceBoot(); uint32_t getSecondsSinceBoot();
uint32_t *airtimeReport(reportTypes reportType); uint32_t *airtimeReport(reportTypes reportType);
uint8_t getSilentMinutes(float txPercent, float dutyCycle);
private: private:
bool firstTime = true; bool firstTime = true;
+20 -4
View File
@@ -270,21 +270,30 @@ bool GPS::setup()
pinMode(PIN_GPS_EN, OUTPUT); pinMode(PIN_GPS_EN, OUTPUT);
#endif #endif
#ifdef HAS_PMU
if(config.position.gps_enabled){
setGPSPower(true);
}
#endif
#ifdef PIN_GPS_RESET #ifdef PIN_GPS_RESET
digitalWrite(PIN_GPS_RESET, 1); // assert for 10ms digitalWrite(PIN_GPS_RESET, 1); // assert for 10ms
pinMode(PIN_GPS_RESET, OUTPUT); pinMode(PIN_GPS_RESET, OUTPUT);
delay(10); delay(10);
digitalWrite(PIN_GPS_RESET, 0); digitalWrite(PIN_GPS_RESET, 0);
#endif #endif
setAwake(true); // Wake GPS power before doing any init setAwake(true); // Wake GPS power before doing any init
bool ok = setupGPS(); bool ok = setupGPS();
if (ok) { if (ok) {
notifySleepObserver.observe(&notifySleep); notifySleepObserver.observe(&notifySleep);
notifyDeepSleepObserver.observe(&notifyDeepSleep); notifyDeepSleepObserver.observe(&notifyDeepSleep);
notifyGPSSleepObserver.observe(&notifyGPSSleep);
}
if (config.position.gps_enabled==false) {
setAwake(false);
doGPSpowersave(false);
} }
return ok; return ok;
} }
@@ -293,6 +302,7 @@ GPS::~GPS()
// we really should unregister our sleep observer // we really should unregister our sleep observer
notifySleepObserver.unobserve(&notifySleep); notifySleepObserver.unobserve(&notifySleep);
notifyDeepSleepObserver.unobserve(&notifyDeepSleep); notifyDeepSleepObserver.unobserve(&notifyDeepSleep);
notifyGPSSleepObserver.observe(&notifyGPSSleep);
} }
bool GPS::hasLock() bool GPS::hasLock()
@@ -405,7 +415,7 @@ void GPS::publishUpdate()
DEBUG_MSG("publishing pos@%x:2, hasVal=%d, GPSlock=%d\n", p.timestamp, hasValidLocation, hasLock()); DEBUG_MSG("publishing pos@%x:2, hasVal=%d, GPSlock=%d\n", p.timestamp, hasValidLocation, hasLock());
// Notify any status instances that are observing us // Notify any status instances that are observing us
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasValidLocation, isConnected(), p); const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasValidLocation, isConnected(), isPowerSaving(), p);
newStatus.notifyObservers(&status); newStatus.notifyObservers(&status);
} }
} }
@@ -416,7 +426,7 @@ int32_t GPS::runOnce()
// if we have received valid NMEA claim we are connected // if we have received valid NMEA claim we are connected
setConnected(); setConnected();
} else { } else {
if(gnssModel == GNSS_MODEL_UBLOX){ if((config.position.gps_enabled == 1) && (gnssModel == GNSS_MODEL_UBLOX)){
// reset the GPS on next bootup // reset the GPS on next bootup
if(devicestate.did_gps_reset && (millis() > 60000) && !hasFlow()) { if(devicestate.did_gps_reset && (millis() > 60000) && !hasFlow()) {
DEBUG_MSG("GPS is not communicating, trying factory reset on next bootup.\n"); DEBUG_MSG("GPS is not communicating, trying factory reset on next bootup.\n");
@@ -518,6 +528,7 @@ int GPS::prepareDeepSleep(void *unused)
DEBUG_MSG("GPS deep sleep!\n"); DEBUG_MSG("GPS deep sleep!\n");
// For deep sleep we also want abandon any lock attempts (because we want minimum power) // For deep sleep we also want abandon any lock attempts (because we want minimum power)
getSleepTime();
setAwake(false); setAwake(false);
return 0; return 0;
@@ -653,6 +664,11 @@ GPS *createGps()
return new_gps; return new_gps;
} }
} }
else{
GPS *new_gps = new NMEAGPS();
new_gps->setup();
return new_gps;
}
return nullptr; return nullptr;
#endif #endif
} }
+3
View File
@@ -49,6 +49,7 @@ class GPS : private concurrency::OSThread
CallbackObserver<GPS, void *> notifySleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareSleep); CallbackObserver<GPS, void *> notifySleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareSleep);
CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep); CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
CallbackObserver<GPS, void *> notifyGPSSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
public: public:
/** If !NULL we will use this serial port to construct our GPS */ /** If !NULL we will use this serial port to construct our GPS */
@@ -77,6 +78,8 @@ class GPS : private concurrency::OSThread
/// Return true if we are connected to a GPS /// Return true if we are connected to a GPS
bool isConnected() const { return hasGPS; } bool isConnected() const { return hasGPS; }
bool isPowerSaving() const { return !config.position.gps_enabled;}
/** /**
* Restart our lock attempt - try to get and broadcast a GPS reading ASAP * Restart our lock attempt - try to get and broadcast a GPS reading ASAP
* called after the CPU wakes from light-sleep state * called after the CPU wakes from light-sleep state
+123 -56
View File
@@ -35,6 +35,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "mesh/Channels.h" #include "mesh/Channels.h"
#include "mesh/generated/deviceonly.pb.h" #include "mesh/generated/deviceonly.pb.h"
#include "modules/TextMessageModule.h" #include "modules/TextMessageModule.h"
#include "sleep.h" #include "sleep.h"
#include "target_specific.h" #include "target_specific.h"
#include "utils.h" #include "utils.h"
@@ -42,6 +43,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
#include "mesh/http/WiFiAPClient.h" #include "mesh/http/WiFiAPClient.h"
#include "modules/esp32/StoreForwardModule.h"
#endif #endif
#ifdef OLED_RU #ifdef OLED_RU
@@ -95,17 +97,17 @@ static uint16_t displayWidth, displayHeight;
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) #if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
// The screen is bigger so use bigger fonts // The screen is bigger so use bigger fonts
#define FONT_SMALL ArialMT_Plain_16 #define FONT_SMALL ArialMT_Plain_16 // Height: 19
#define FONT_MEDIUM ArialMT_Plain_24 #define FONT_MEDIUM ArialMT_Plain_24 // Height: 28
#define FONT_LARGE ArialMT_Plain_24 #define FONT_LARGE ArialMT_Plain_24 // Height: 28
#else #else
#ifdef OLED_RU #ifdef OLED_RU
#define FONT_SMALL ArialMT_Plain_10_RU #define FONT_SMALL ArialMT_Plain_10_RU
#else #else
#define FONT_SMALL ArialMT_Plain_10 #define FONT_SMALL ArialMT_Plain_10 // Height: 13
#endif #endif
#define FONT_MEDIUM ArialMT_Plain_16 #define FONT_MEDIUM ArialMT_Plain_16 // Height: 19
#define FONT_LARGE ArialMT_Plain_24 #define FONT_LARGE ArialMT_Plain_24 // Height: 28
#endif #endif
#define fontHeight(font) ((font)[1] + 1) // height is position 1 #define fontHeight(font) ((font)[1] + 1) // height is position 1
@@ -329,11 +331,8 @@ static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, i
display->drawString(64 + x, y, "Updating"); display->drawString(64 + x, y, "Updating");
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
if ((millis() / 1000) % 2) { display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . ."); display->drawStringMaxWidth(0 + x, 2 + y + FONT_HEIGHT_SMALL *2, x + display->getWidth(), "Please be patient and do not power off.");
} else {
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . ");
}
} }
/// Draw the last text message we received /// Draw the last text message we received
@@ -364,6 +363,9 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
{ {
displayedNodeNum = 0; // Not currently showing a node pane displayedNodeNum = 0; // Not currently showing a node pane
// the max length of this buffer is much longer than we can possibly print
static char tempBuf[237];
MeshPacket &mp = devicestate.rx_text_message; MeshPacket &mp = devicestate.rx_text_message;
NodeInfo *node = nodeDB.getNode(getFrom(&mp)); NodeInfo *node = nodeDB.getNode(getFrom(&mp));
// DEBUG_MSG("drawing text message from 0x%x: %s\n", mp.from, // DEBUG_MSG("drawing text message from 0x%x: %s\n", mp.from,
@@ -373,16 +375,14 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
// with the third parameter you can define the width after which words will // with the third parameter you can define the width after which words will
// be wrapped. Currently only spaces and "-" are allowed for wrapping // be wrapped. Currently only spaces and "-" are allowed for wrapping
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_MEDIUM);
String sender = (node && node->has_user) ? node->user.short_name : "???";
display->drawString(0 + x, 0 + y, sender);
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
// the max length of this buffer is much longer than we can possibly print display->setColor(BLACK);
static char tempBuf[96]; display->drawStringf(0 + x, 0 + y, tempBuf, "From: %s", (node && node->has_user) ? node->user.short_name : "???");
snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.payload.bytes); display->drawStringf(1 + x, 0 + y, tempBuf, "From: %s", (node && node->has_user) ? node->user.short_name : "???");
display->setColor(WHITE);
display->drawStringMaxWidth(4 + x, 10 + y, SCREEN_WIDTH - (6 + x), tempBuf); snprintf(tempBuf, sizeof(tempBuf), "%s", mp.decoded.payload.bytes);
display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf);
} }
/// Draw a series of fields in a column, wrapping to multiple colums if needed /// Draw a series of fields in a column, wrapping to multiple colums if needed
@@ -395,6 +395,10 @@ static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char *
int xo = x, yo = y; int xo = x, yo = y;
while (*f) { while (*f) {
display->drawString(xo, yo, *f); display->drawString(xo, yo, *f);
if (display->getColor() == BLACK)
display->drawString(xo + 1, yo, *f);
display->setColor(WHITE);
yo += FONT_HEIGHT_SMALL; yo += FONT_HEIGHT_SMALL;
if (yo > SCREEN_HEIGHT - FONT_HEIGHT_SMALL) { if (yo > SCREEN_HEIGHT - FONT_HEIGHT_SMALL) {
xo += SCREEN_WIDTH / 2; xo += SCREEN_WIDTH / 2;
@@ -463,8 +467,13 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *no
{ {
char usersString[20]; char usersString[20];
sprintf(usersString, "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal()); sprintf(usersString, "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
display->drawFastImage(x, y + 3, 8, 8, imgUser);
#else
display->drawFastImage(x, y, 8, 8, imgUser); display->drawFastImage(x, y, 8, 8, imgUser);
#endif
display->drawString(x + 10, y - 2, usersString); display->drawString(x + 10, y - 2, usersString);
display->drawString(x + 11, y - 2, usersString);
} }
// Draw GPS status summary // Draw GPS status summary
@@ -473,15 +482,18 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
if (config.position.fixed_position) { if (config.position.fixed_position) {
// GPS coordinates are currently fixed // GPS coordinates are currently fixed
display->drawString(x - 1, y - 2, "Fixed GPS"); display->drawString(x - 1, y - 2, "Fixed GPS");
display->drawString(x, y - 2, "Fixed GPS");
return; return;
} }
if (!gps->getIsConnected()) { if (!gps->getIsConnected()) {
display->drawString(x, y - 2, "No GPS"); display->drawString(x, y - 2, "No GPS");
display->drawString(x + 1, y - 2, "No GPS");
return; return;
} }
display->drawFastImage(x, y, 6, 8, gps->getHasLock() ? imgPositionSolid : imgPositionEmpty); display->drawFastImage(x, y, 6, 8, gps->getHasLock() ? imgPositionSolid : imgPositionEmpty);
if (!gps->getHasLock()) { if (!gps->getHasLock()) {
display->drawString(x + 8, y - 2, "No sats"); display->drawString(x + 8, y - 2, "No sats");
display->drawString(x + 9, y - 2, "No sats");
return; return;
} else { } else {
char satsString[3]; char satsString[3];
@@ -506,6 +518,23 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
} }
} }
//Draw status when gps is disabled by PMU
static void drawGPSpowerstat(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
{
#ifdef HAS_PMU
String displayLine = "GPS disabled";
int16_t xPos = display->getStringWidth(displayLine);
if (!config.position.gps_enabled){
display->drawString(x + xPos, y, displayLine);
#ifdef GPS_POWER_TOGGLE
display->drawString(x + xPos, y - 2 + FONT_HEIGHT_SMALL, " by button");
#endif
//display->drawString(x + xPos, y + 2, displayLine);
}
#endif
}
static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps) static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
{ {
String displayLine = ""; String displayLine = "";
@@ -669,16 +698,16 @@ static uint16_t getCompassDiam(OLEDDisplay *display)
{ {
uint16_t diam = 0; uint16_t diam = 0;
// get the smaller of the 2 dimensions and subtract 20 // get the smaller of the 2 dimensions and subtract 20
if(display->getWidth() > display->getHeight()) { if(display->getWidth() > (display->getHeight() - FONT_HEIGHT_SMALL)) {
diam = display->getHeight(); diam = display->getHeight() - FONT_HEIGHT_SMALL;
// if 2/3 of the other size would be smaller, use that // if 2/3 of the other size would be smaller, use that
if (diam > (display->getWidth() * 2 / 3)) { if (diam > (display->getWidth() * 2 / 3)) {
diam = display->getWidth() * 2 / 3; diam = display->getWidth() * 2 / 3;
} }
} else { } else {
diam = display->getWidth(); diam = display->getWidth();
if (diam > (display->getHeight() * 2 / 3)) { if (diam > ((display->getHeight() - FONT_HEIGHT_SMALL) * 2 / 3)) {
diam = display->getHeight() * 2 / 3; diam = (display->getHeight() - FONT_HEIGHT_SMALL) * 2 / 3;
} }
} }
@@ -758,6 +787,8 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
const char *username = node->has_user ? node->user.long_name : "Unknown Name"; const char *username = node->has_user ? node->user.long_name : "Unknown Name";
static char signalStr[20]; static char signalStr[20];
@@ -788,7 +819,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
const char *fields[] = {username, distStr, signalStr, lastStr, NULL}; const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
// coordinates for the center of the compass/circle // coordinates for the center of the compass/circle
int16_t compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5, compassY = y + SCREEN_HEIGHT / 2; int16_t compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5, compassY = y + FONT_HEIGHT_SMALL + (SCREEN_HEIGHT - FONT_HEIGHT_SMALL) / 2;
bool hasNodeHeading = false; bool hasNodeHeading = false;
if (ourNode && hasPosition(ourNode)) { if (ourNode && hasPosition(ourNode)) {
@@ -831,33 +862,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?"); display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?");
display->drawCircle(compassX, compassY, getCompassDiam(display) / 2); display->drawCircle(compassX, compassY, getCompassDiam(display) / 2);
display->setColor(BLACK);
// Must be after distStr is populated // Must be after distStr is populated
drawColumns(display, x, y, fields); drawColumns(display, x, y, fields);
} }
#if 0
void _screen_header()
{
if (!disp)
return;
// Message count
//snprintf(buffer, sizeof(buffer), "#%03d", ttn_get_count() % 1000);
//display->setTextAlignment(TEXT_ALIGN_LEFT);
//display->drawString(0, 2, buffer);
// Datetime
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(display->getWidth()/2, 2, gps.getTimeStr());
// Satellite count
display->setTextAlignment(TEXT_ALIGN_RIGHT);
char buffer[10];
display->drawString(display->getWidth() - SATELLITE_IMAGE_WIDTH - 4, 2, itoa(gps.satellites.value(), buffer, 10));
display->drawXbm(display->getWidth() - SATELLITE_IMAGE_WIDTH, 0, SATELLITE_IMAGE_WIDTH, SATELLITE_IMAGE_HEIGHT, SATELLITE_IMAGE);
}
#endif
// #ifdef RAK4630 // #ifdef RAK4630
// Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), // Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl),
// dispdev_oled(address, sda, scl), ui(&dispdev) // dispdev_oled(address, sda, scl), ui(&dispdev)
@@ -1357,6 +1366,9 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK);
char channelStr[20]; char channelStr[20];
{ {
concurrency::LockGuard guard(&lock); concurrency::LockGuard guard(&lock);
@@ -1366,18 +1378,54 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// Display power status // Display power status
if (powerStatus->getHasBattery()) if (powerStatus->getHasBattery())
drawBattery(display, x, y + 2, imgBattery, powerStatus); drawBattery(display, x + 1, y + 3, imgBattery, powerStatus);
else if (powerStatus->knowsUSB()) else if (powerStatus->knowsUSB())
display->drawFastImage(x, y + 2, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower); display->drawFastImage(x + 1, y + 3, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower);
// Display nodes status // Display nodes status
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus); drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 3, nodeStatus);
// Display GPS status // Display GPS status
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus); if (!config.position.gps_enabled){
int16_t yPos = y + 2;
#ifdef GPS_POWER_TOGGLE
yPos = (y + 10 + FONT_HEIGHT_SMALL);
#endif
drawGPSpowerstat(display, x, yPos, gpsStatus);
} else {
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 3, gpsStatus);
}
display->setColor(WHITE);
// Draw the channel name // Draw the channel name
display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr); display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr);
// Draw our hardware ID to assist with bluetooth pairing // Draw our hardware ID to assist with bluetooth pairing. Either prefix with Info or S&F Logo
display->drawFastImage(x + SCREEN_WIDTH - (10) - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgInfo); if (moduleConfig.store_forward.enabled) {
#if 0
if (millis() - storeForwardModule->lastHeartbeat > (storeForwardModule->heartbeatInterval * 1200)) { //no heartbeat, overlap a bit
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, imgQuestionL1);
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8, imgQuestionL2);
#else
display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgQuestion);
#endif
} else {
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 16, 8, imgSFL1);
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 16, 8, imgSFL2);
#else
display->drawFastImage(x + SCREEN_WIDTH - 13 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 11, 8, imgSF);
#endif
}
#endif
} else {
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, imgInfoL1);
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8, imgInfoL2);
#else
display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgInfo);
#endif
}
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT_SMALL, ourId); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT_SMALL, ourId);
// Draw any log messages // Draw any log messages
@@ -1404,15 +1452,24 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK);
if (WiFi.status() != WL_CONNECTED) { if (WiFi.status() != WL_CONNECTED) {
display->drawString(x, y, String("WiFi: Not Connected")); display->drawString(x, y, String("WiFi: Not Connected"));
display->drawString(x + 1, y, String("WiFi: Not Connected"));
} else { } else {
display->drawString(x, y, String("WiFi: Connected")); display->drawString(x, y, String("WiFi: Connected"));
display->drawString(x + 1, y, String("WiFi: Connected"));
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("RSSI " + String(WiFi.RSSI())), y, display->drawString(x + SCREEN_WIDTH - display->getStringWidth("RSSI " + String(WiFi.RSSI())), y,
"RSSI " + String(WiFi.RSSI())); "RSSI " + String(WiFi.RSSI()));
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("RSSI " + String(WiFi.RSSI())) - 1, y,
"RSSI " + String(WiFi.RSSI()));
} }
display->setColor(WHITE);
/* /*
- WL_CONNECTED: assigned when connected to a WiFi network; - WL_CONNECTED: assigned when connected to a WiFi network;
- WL_NO_SSID_AVAIL: assigned when no SSID are available; - WL_NO_SSID_AVAIL: assigned when no SSID are available;
@@ -1521,6 +1578,9 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK);
char batStr[20]; char batStr[20];
if (powerStatus->getHasBattery()) { if (powerStatus->getHasBattery()) {
int batV = powerStatus->getBatteryVoltageMv() / 1000; int batV = powerStatus->getBatteryVoltageMv() / 1000;
@@ -1531,9 +1591,11 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
// Line 1 // Line 1
display->drawString(x, y, batStr); display->drawString(x, y, batStr);
display->drawString(x + 1, y, batStr);
} else { } else {
// Line 1 // Line 1
display->drawString(x, y, String("USB")); display->drawString(x, y, String("USB"));
display->drawString(x + 1, y, String("USB"));
} }
auto mode = ""; auto mode = "";
@@ -1566,6 +1628,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
} }
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode) - 1, y, mode);
// Line 2 // Line 2
uint32_t currentMillis = millis(); uint32_t currentMillis = millis();
@@ -1578,6 +1641,8 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
// minutes %= 60; // minutes %= 60;
// hours %= 24; // hours %= 24;
display->setColor(WHITE);
// Show uptime as days, hours, minutes OR seconds // Show uptime as days, hours, minutes OR seconds
String uptime; String uptime;
if (days >= 2) if (days >= 2)
@@ -1613,7 +1678,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
char chUtil[13]; char chUtil[13];
sprintf(chUtil, "ChUtil %2.0f%%", airTime->channelUtilizationPercent()); sprintf(chUtil, "ChUtil %2.0f%%", airTime->channelUtilizationPercent());
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil);
if (config.position.gps_enabled) {
// Line 3 // Line 3
if (config.display.gps_format != if (config.display.gps_format !=
Config_DisplayConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude Config_DisplayConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude
@@ -1621,7 +1686,9 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
// Line 4 // Line 4
drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus); drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus);
} else {
drawGPSpowerstat(display, x - (SCREEN_WIDTH / 4), y + FONT_HEIGHT_SMALL * 2, gpsStatus);
}
/* Display a heartbeat pixel that blinks every time the frame is redrawn */ /* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS #ifdef SHOW_REDRAWS
if (heartbeat) if (heartbeat)
+1
View File
@@ -21,6 +21,7 @@ class Screen
void startBluetoothPinScreen(uint32_t pin) {} void startBluetoothPinScreen(uint32_t pin) {}
void stopBluetoothPinScreen() {} void stopBluetoothPinScreen() {}
void startRebootScreen() {} void startRebootScreen() {}
void startFirmwareUpdateScreen() {}
}; };
} }
+12 -30
View File
@@ -12,36 +12,18 @@ const uint8_t imgPower[] PROGMEM = { 0x40, 0x40, 0x40, 0x58, 0x48, 0x08,
const uint8_t imgUser[] PROGMEM = { 0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C }; const uint8_t imgUser[] PROGMEM = { 0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C };
const uint8_t imgPositionEmpty[] PROGMEM = { 0x20, 0x30, 0x28, 0x24, 0x42, 0xFF }; const uint8_t imgPositionEmpty[] PROGMEM = { 0x20, 0x30, 0x28, 0x24, 0x42, 0xFF };
const uint8_t imgPositionSolid[] PROGMEM = { 0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF }; const uint8_t imgPositionSolid[] PROGMEM = { 0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF };
const uint8_t imgInfo[] PROGMEM = { 0xFF, 0x81, 0x81, 0xB5, 0xB5, 0x81, 0x81, 0xFF };
#include "img/icon.xbm" #if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
const uint8_t imgQuestionL1[] PROGMEM = { 0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff };
// We now programmatically draw our compass const uint8_t imgQuestionL2[] PROGMEM = { 0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f };
#if 0 const uint8_t imgInfoL1[] PROGMEM = { 0xff, 0x01, 0x01, 0x01, 0x1e, 0x7f, 0x1e, 0x01, 0x01, 0x01, 0x01, 0xff };
const const uint8_t imgInfoL2[] PROGMEM = { 0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f };
#include "img/compass.xbm" const uint8_t imgSFL1[] PROGMEM = { 0xb6, 0x8f, 0x19, 0x11, 0x31, 0xe3, 0xc2, 0x01, 0x01, 0xf9, 0xf9, 0x89, 0x89, 0x89, 0x09, 0xeb};
const uint8_t imgSFL2[] PROGMEM = { 0x0e, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x00, 0x0f, 0x0f, 0x00, 0x08, 0x08, 0x08, 0x0f};
#else
const uint8_t imgInfo[] PROGMEM = { 0xff, 0x81, 0x00, 0xfb, 0xfb, 0x00, 0x81, 0xff };
const uint8_t imgQuestion[] PROGMEM = { 0xbf, 0x41, 0xc0, 0x8b, 0xdb, 0x70, 0xa1, 0xdf };
const uint8_t imgSF[] PROGMEM = { 0xd2, 0xb7, 0xad, 0xbb, 0x92, 0x01, 0xfd, 0xfd, 0x15, 0x85, 0xf5};
#endif #endif
#if 0 #include "img/icon.xbm"
const uint8_t activeSymbol[] PROGMEM = {
B00000000,
B00000000,
B00011000,
B00100100,
B01000010,
B01000010,
B00100100,
B00011000
};
const uint8_t inactiveSymbol[] PROGMEM = {
B00000000,
B00000000,
B00000000,
B00000000,
B00011000,
B00011000,
B00000000,
B00000000
};
#endif
-28
View File
@@ -1,28 +0,0 @@
#define compass_width 48
#define compass_height 48
static char compass_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x01, 0x00,
0x00, 0xC0, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00,
0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xFC, 0x07, 0xE0, 0x3F, 0x00,
0x00, 0xFE, 0x01, 0x80, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00,
0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xFC, 0x01,
0x80, 0x1F, 0x00, 0x00, 0xF8, 0x01, 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x01,
0xC0, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03,
0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03,
0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F, 0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F,
0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F, 0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F,
0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03,
0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x0F, 0x00, 0x00, 0xF0, 0x03,
0x80, 0x0F, 0x00, 0x00, 0xF0, 0x01, 0x80, 0x1F, 0x00, 0x00, 0xF8, 0x01,
0x80, 0x3F, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00,
0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x01, 0x80, 0x7F, 0x00,
0x00, 0xFC, 0x07, 0xE0, 0x3F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00,
0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x03, 0x00,
0x00, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00,
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
-6
View File
@@ -1,6 +0,0 @@
#define pin_width 13
#define pin_height 13
static char pin_bits[] = {
0x00, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0xFC, 0x07, 0xBC, 0x07, 0xBC, 0x07,
0xFC, 0x07, 0xF8, 0x03, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0xE0, 0x00,
0x00, 0x00, };
+25 -4
View File
@@ -8,8 +8,6 @@
#include "configuration.h" #include "configuration.h"
#include "error.h" #include "error.h"
#include "power.h" #include "power.h"
// #include "rom/rtc.h"
//#include "DSRRouter.h"
#include "ReliableRouter.h" #include "ReliableRouter.h"
// #include "debug.h" // #include "debug.h"
#include "FSCommon.h" #include "FSCommon.h"
@@ -217,7 +215,6 @@ void setup()
fsInit(); fsInit();
// router = new DSRRouter();
router = new ReliableRouter(); router = new ReliableRouter();
#ifdef I2C_SDA1 #ifdef I2C_SDA1
@@ -387,7 +384,7 @@ void setup()
} }
#endif #endif
#if defined(USE_SX1280) && !defined(ARCH_PORTDUINO) #if defined(USE_SX1280)
if (!rIf) { if (!rIf) {
rIf = new SX1280Interface(SX128X_CS, SX128X_DIO1, SX128X_RESET, SX128X_BUSY, SPI); rIf = new SX1280Interface(SX128X_CS, SX128X_DIO1, SX128X_RESET, SX128X_BUSY, SPI);
if (!rIf->init()) { if (!rIf->init()) {
@@ -452,6 +449,30 @@ void setup()
} }
#endif #endif
// check if the radio chip matches the selected region
if((config.lora.region == Config_LoRaConfig_RegionCode_LORA_24) && (!rIf->wideLora())){
DEBUG_MSG("Warning: Radio chip does not support 2.4GHz LoRa. Reverting to unset.\n");
config.lora.region = Config_LoRaConfig_RegionCode_UNSET;
nodeDB.saveToDisk(SEGMENT_CONFIG);
if(!rIf->reconfigure()) {
DEBUG_MSG("Reconfigure failed, rebooting\n");
screen->startRebootScreen();
rebootAtMsec = millis() + 5000;
}
}
if((config.lora.region != Config_LoRaConfig_RegionCode_LORA_24) && (rIf->wideLora())){
DEBUG_MSG("Warning: Radio chip only supports 2.4GHz LoRa. Adjusting Region.\n");
config.lora.region = Config_LoRaConfig_RegionCode_LORA_24;
nodeDB.saveToDisk(SEGMENT_CONFIG);
if(!rIf->reconfigure()) {
DEBUG_MSG("Reconfigure failed, rebooting\n");
screen->startRebootScreen();
rebootAtMsec = millis() + 5000;
}
}
#if HAS_WIFI || HAS_ETHERNET #if HAS_WIFI || HAS_ETHERNET
mqttInit(); mqttInit();
#endif #endif
+5
View File
@@ -41,6 +41,11 @@ void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c)
tosend->hop_limit--; // bump down the hop count tosend->hop_limit--; // bump down the hop count
// If it is a traceRoute request, update the route that it went via me
if (p->which_payload_variant == MeshPacket_decoded_tag && traceRouteModule->wantPacket(p)) {
traceRouteModule->updateRoute(tosend);
}
printPacket("Rebroadcasting received floodmsg to neighbors", p); printPacket("Rebroadcasting received floodmsg to neighbors", p);
// Note: we are careful to resend using the original senders node id // Note: we are careful to resend using the original senders node id
// We are careful not to call our hooked version of send() - because we don't want to check this again // We are careful not to call our hooked version of send() - because we don't want to check this again
+1
View File
@@ -2,6 +2,7 @@
#include "PacketHistory.h" #include "PacketHistory.h"
#include "Router.h" #include "Router.h"
#include "modules/TraceRouteModule.h"
/** /**
* This is a mixin that extends Router with the ability to do Naive Flooding (in the standard mesh protocol sense) * This is a mixin that extends Router with the ability to do Naive Flooding (in the standard mesh protocol sense)
-3
View File
@@ -7,7 +7,4 @@
template class SX126xInterface<SX1262>; template class SX126xInterface<SX1262>;
template class SX126xInterface<SX1268>; template class SX126xInterface<SX1268>;
template class SX126xInterface<LLCC68>; template class SX126xInterface<LLCC68>;
#if defined(RADIOLIB_GODMODE)
template class SX128xInterface<SX1280>; template class SX128xInterface<SX1280>;
#endif
+4 -3
View File
@@ -162,6 +162,7 @@ void NodeDB::installDefaultConfig()
config.has_network = true; config.has_network = true;
config.has_bluetooth = true; config.has_bluetooth = true;
config.lora.tx_enabled = true; // FIXME: maybe false in the future, and setting region to enable it. (unset region forces it off) config.lora.tx_enabled = true; // FIXME: maybe false in the future, and setting region to enable it. (unset region forces it off)
config.lora.override_duty_cycle = false;
config.lora.region = Config_LoRaConfig_RegionCode_UNSET; config.lora.region = Config_LoRaConfig_RegionCode_UNSET;
config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LONG_FAST; config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LONG_FAST;
config.lora.hop_limit = HOP_RELIABLE; config.lora.hop_limit = HOP_RELIABLE;
@@ -214,9 +215,9 @@ void NodeDB::installDefaultModuleConfig()
moduleConfig.has_external_notification = true; moduleConfig.has_external_notification = true;
moduleConfig.has_canned_message = true; moduleConfig.has_canned_message = true;
strncpy(moduleConfig.mqtt.address, default_mqtt_address, sizeof(default_mqtt_address)); strncpy(moduleConfig.mqtt.address, default_mqtt_address, sizeof(moduleConfig.mqtt.address));
strncpy(moduleConfig.mqtt.username, default_mqtt_username, sizeof(default_mqtt_username)); strncpy(moduleConfig.mqtt.username, default_mqtt_username, sizeof(moduleConfig.mqtt.username));
strncpy(moduleConfig.mqtt.password, default_mqtt_password, sizeof(default_mqtt_password)); strncpy(moduleConfig.mqtt.password, default_mqtt_password, sizeof(moduleConfig.mqtt.password));
initModuleConfigIntervals(); initModuleConfigIntervals();
} }
+2 -1
View File
@@ -1,6 +1,5 @@
#pragma once #pragma once
#include "../concurrency/NotifiedWorkerThread.h"
#include "MemoryPool.h" #include "MemoryPool.h"
#include "MeshTypes.h" #include "MeshTypes.h"
#include "Observer.h" #include "Observer.h"
@@ -97,6 +96,8 @@ class RadioInterface
*/ */
virtual bool canSleep() { return true; } virtual bool canSleep() { return true; }
virtual bool wideLora() { return false; }
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep. /// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
virtual bool sleep() { return true; } virtual bool sleep() { return true; }
+1 -2
View File
@@ -1,10 +1,9 @@
#pragma once #pragma once
#include "../concurrency/OSThread.h" #include "concurrency/NotifiedWorkerThread.h"
#include "RadioInterface.h" #include "RadioInterface.h"
#include "MeshPacketQueue.h" #include "MeshPacketQueue.h"
#define RADIOLIB_EXCLUDE_HTTP
#include <RadioLib.h> #include <RadioLib.h>
// ESP32 has special rules about ISR code // ESP32 has special rules about ISR code
+2 -4
View File
@@ -90,8 +90,7 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c)
{ {
NodeNum ourNode = getNodeNum(); NodeNum ourNode = getNodeNum();
if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability)
// - not DSR routing)
if (p->want_ack) { if (p->want_ack) {
if (MeshModule::currentReply) if (MeshModule::currentReply)
DEBUG_MSG("Some other module has replied to this message, no need for a 2nd ack\n"); DEBUG_MSG("Some other module has replied to this message, no need for a 2nd ack\n");
@@ -200,8 +199,7 @@ int32_t ReliableRouter::doRetransmissions()
DEBUG_MSG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to, DEBUG_MSG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to,
p.packet->id); p.packet->id);
sendAckNak(Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel); sendAckNak(Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel);
// Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived
// allows the DSR version to still be able to look at the PendingPacket
stopRetransmission(it->first); stopRetransmission(it->first);
stillValid = false; // just deleted it stillValid = false; // just deleted it
} else { } else {
-6
View File
@@ -38,12 +38,6 @@ struct PendingPacket {
/** Starts at NUM_RETRANSMISSIONS -1(normally 3) and counts down. Once zero it will be removed from the list */ /** Starts at NUM_RETRANSMISSIONS -1(normally 3) and counts down. Once zero it will be removed from the list */
uint8_t numRetransmissions = 0; uint8_t numRetransmissions = 0;
/** True if we have started trying to find a route - for DSR usage
* While trying to find a route we don't actually send the data packet. We just leave it here pending until
* we have a route or we've failed to find one.
*/
bool wantRoute = false;
PendingPacket() {} PendingPacket() {}
explicit PendingPacket(MeshPacket *p); explicit PendingPacket(MeshPacket *p);
}; };
+13 -1
View File
@@ -2,6 +2,7 @@
#include "Channels.h" #include "Channels.h"
#include "CryptoEngine.h" #include "CryptoEngine.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "MeshRadio.h"
#include "RTC.h" #include "RTC.h"
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
@@ -21,7 +22,6 @@ extern "C" {
* DONE: Implement basic interface and use it elsewhere in app * DONE: Implement basic interface and use it elsewhere in app
* Add naive flooding mixin (& drop duplicate rx broadcasts), add tools for sending broadcasts with incrementing sequence #s * Add naive flooding mixin (& drop duplicate rx broadcasts), add tools for sending broadcasts with incrementing sequence #s
* Add an optional adjacent node only 'send with ack' mixin. If we timeout waiting for the ack, call handleAckTimeout(packet) * Add an optional adjacent node only 'send with ack' mixin. If we timeout waiting for the ack, call handleAckTimeout(packet)
* Add DSR mixin
* *
**/ **/
@@ -188,6 +188,18 @@ ErrorCode Router::send(MeshPacket *p)
{ {
assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal
// Abort sending if we are violating the duty cycle
if (!config.lora.override_duty_cycle && myRegion->dutyCycle != 100) {
float hourlyTxPercent = airTime->utilizationTXPercent();
if (hourlyTxPercent > myRegion->dutyCycle) {
uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle);
DEBUG_MSG("WARNING: Duty cycle limit exceeded. Aborting send for now, you can send again in %d minutes.\n", silentMinutes);
Routing_Error err = Routing_Error_DUTY_CYCLE_LIMIT;
abortSendAndNak(err, p);
return err;
}
}
// PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0; // PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0;
// assert(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with // assert(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with
// assert // assert
-4
View File
@@ -2,12 +2,8 @@
#include "SX1280Interface.h" #include "SX1280Interface.h"
#include "error.h" #include "error.h"
#if defined(RADIOLIB_GODMODE)
SX1280Interface::SX1280Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SX1280Interface::SX1280Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
SPIClass &spi) SPIClass &spi)
: SX128xInterface(cs, irq, rst, busy, spi) : SX128xInterface(cs, irq, rst, busy, spi)
{ {
} }
#endif
-3
View File
@@ -6,12 +6,9 @@
* Our adapter for SX1280 radios * Our adapter for SX1280 radios
*/ */
#if defined(RADIOLIB_GODMODE)
class SX1280Interface : public SX128xInterface<SX1280> class SX1280Interface : public SX128xInterface<SX1280>
{ {
public: public:
SX1280Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi); SX1280Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi);
}; };
#endif
+24 -20
View File
@@ -2,8 +2,6 @@
#include "SX128xInterface.h" #include "SX128xInterface.h"
#include "error.h" #include "error.h"
#if defined(RADIOLIB_GODMODE)
// Particular boards might define a different max power based on what their hardware can do // Particular boards might define a different max power based on what their hardware can do
#ifndef SX128X_MAX_POWER #ifndef SX128X_MAX_POWER
#define SX128X_MAX_POWER 13 #define SX128X_MAX_POWER 13
@@ -27,11 +25,11 @@ bool SX128xInterface<T>::init()
pinMode(SX128X_POWER_EN, OUTPUT); pinMode(SX128X_POWER_EN, OUTPUT);
#endif #endif
#ifdef SX128X_RXEN // set not rx or tx mode #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // set not rx or tx mode
digitalWrite(SX128X_RXEN, LOW); // Set low before becoming an output digitalWrite(SX128X_RXEN, LOW); // Set low before becoming an output
pinMode(SX128X_RXEN, OUTPUT); pinMode(SX128X_RXEN, OUTPUT);
#endif #endif
#ifdef SX128X_TXEN #if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC)
digitalWrite(SX128X_TXEN, LOW); digitalWrite(SX128X_TXEN, LOW);
pinMode(SX128X_TXEN, OUTPUT); pinMode(SX128X_TXEN, OUTPUT);
#endif #endif
@@ -46,6 +44,8 @@ bool SX128xInterface<T>::init()
limitPower(); limitPower();
preambleLength = 12; // 12 is the default for this chip, 32 does not RX at all
int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength); int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength);
// \todo Display actual typename of the adapter, not just `SX128x` // \todo Display actual typename of the adapter, not just `SX128x`
DEBUG_MSG("SX128x init result %d\n", res); DEBUG_MSG("SX128x init result %d\n", res);
@@ -54,12 +54,6 @@ bool SX128xInterface<T>::init()
DEBUG_MSG("Bandwidth set to %f\n", bw); DEBUG_MSG("Bandwidth set to %f\n", bw);
DEBUG_MSG("Power output set to %d\n", power); DEBUG_MSG("Power output set to %d\n", power);
#ifdef SX128X_TXEN
// lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX
if (res == RADIOLIB_ERR_NONE)
res = lora.setDio2AsRfSwitch(true);
#endif
if (res == RADIOLIB_ERR_NONE) if (res == RADIOLIB_ERR_NONE)
res = lora.setCRC(2); res = lora.setCRC(2);
@@ -122,18 +116,28 @@ void INTERRUPT_ATTR SX128xInterface<T>::disableInterrupt()
lora.clearDio1Action(); lora.clearDio1Action();
} }
template<typename T>
bool SX128xInterface<T>::wideLora()
{
return true;
}
template<typename T> template<typename T>
void SX128xInterface<T>::setStandby() void SX128xInterface<T>::setStandby()
{ {
checkNotification(); // handle any pending interrupts before we force standby checkNotification(); // handle any pending interrupts before we force standby
int err = lora.standby(); int err = lora.standby();
if (err != RADIOLIB_ERR_NONE)
DEBUG_MSG("SX128x standby failed with error %d\n", err);
assert(err == RADIOLIB_ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
#ifdef SX128X_RXEN // we have RXEN/TXEN control - turn off RX and TX power #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn off RX and TX power
digitalWrite(SX128X_RXEN, LOW); digitalWrite(SX128X_RXEN, LOW);
#endif #endif
#ifdef SX128X_TXEN #if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC)
digitalWrite(SX128X_TXEN, LOW); digitalWrite(SX128X_TXEN, LOW);
#endif #endif
@@ -158,10 +162,10 @@ void SX128xInterface<T>::addReceiveMetadata(MeshPacket *mp)
template<typename T> template<typename T>
void SX128xInterface<T>::configHardwareForSend() void SX128xInterface<T>::configHardwareForSend()
{ {
#ifdef SX128X_TXEN // we have RXEN/TXEN control - turn on TX power / off RX power #if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn on TX power / off RX power
digitalWrite(SX128X_TXEN, HIGH); digitalWrite(SX128X_TXEN, HIGH);
#endif #endif
#ifdef SX128X_RXEN #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC)
digitalWrite(SX128X_RXEN, LOW); digitalWrite(SX128X_RXEN, LOW);
#endif #endif
@@ -180,10 +184,10 @@ void SX128xInterface<T>::startReceive()
setStandby(); setStandby();
#ifdef SX128X_RXEN // we have RXEN/TXEN control - turn on RX power / off TX power #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn on RX power / off TX power
digitalWrite(SX128X_RXEN, HIGH); digitalWrite(SX128X_RXEN, HIGH);
#endif #endif
#ifdef SX128X_TXEN #if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC)
digitalWrite(SX128X_TXEN, LOW); digitalWrite(SX128X_TXEN, LOW);
#endif #endif
@@ -219,11 +223,13 @@ bool SX128xInterface<T>::isChannelActive()
template<typename T> template<typename T>
bool SX128xInterface<T>::isActivelyReceiving() bool SX128xInterface<T>::isActivelyReceiving()
{ {
// return isChannelActive(); #ifdef RADIOLIB_GODMODE
uint16_t irq = lora.getIrqStatus(); uint16_t irq = lora.getIrqStatus();
bool hasPreamble = (irq & RADIOLIB_SX128X_IRQ_HEADER_VALID); bool hasPreamble = (irq & RADIOLIB_SX128X_IRQ_HEADER_VALID);
return hasPreamble; return hasPreamble;
#else
return isChannelActive();
#endif
} }
template<typename T> template<typename T>
@@ -248,5 +254,3 @@ bool SX128xInterface<T>::sleep()
return true; return true;
} }
#endif
+6 -6
View File
@@ -1,7 +1,5 @@
#pragma once #pragma once
#if defined(RADIOLIB_GODMODE)
#include "RadioLibInterface.h" #include "RadioLibInterface.h"
/** /**
@@ -19,6 +17,8 @@ class SX128xInterface : public RadioLibInterface
/// \return true if initialisation succeeded. /// \return true if initialisation succeeded.
virtual bool init() override; virtual bool init() override;
virtual bool wideLora() override;
/// Apply any radio provisioning changes /// Apply any radio provisioning changes
/// Make sure the Driver is properly configured before calling init(). /// Make sure the Driver is properly configured before calling init().
/// \return true if initialisation succeeded. /// \return true if initialisation succeeded.
@@ -27,9 +27,11 @@ class SX128xInterface : public RadioLibInterface
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep. /// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
virtual bool sleep() override; virtual bool sleep() override;
protected: #ifdef RADIOLIB_GODMODE
bool isIRQPending() override { return lora.getIrqStatus() != 0; }
#endif
float currentLimit = 140; // Higher OCP limit for SX128x PA protected:
/** /**
* Specific module instance * Specific module instance
@@ -71,5 +73,3 @@ class SX128xInterface : public RadioLibInterface
private: private:
}; };
#endif
+1 -1
View File
@@ -151,7 +151,7 @@ extern const pb_msgdesc_t LocalModuleConfig_msg;
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define LocalConfig_size 387 #define LocalConfig_size 387
#define LocalModuleConfig_size 376 #define LocalModuleConfig_size 358
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
+4 -25
View File
@@ -93,13 +93,6 @@ typedef struct _ModuleConfig_ExternalNotificationConfig {
bool alert_message; bool alert_message;
bool alert_bell; bool alert_bell;
bool use_pwm; bool use_pwm;
uint8_t output_vibra;
uint8_t output_buzzer;
bool alert_message_vibra;
bool alert_message_buzzer;
bool alert_bell_vibra;
bool alert_bell_buzzer;
uint16_t nag_timeout;
} ModuleConfig_ExternalNotificationConfig; } ModuleConfig_ExternalNotificationConfig;
typedef struct _ModuleConfig_MQTTConfig { typedef struct _ModuleConfig_MQTTConfig {
@@ -194,7 +187,7 @@ extern "C" {
#define ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0} #define ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0}
#define ModuleConfig_AudioConfig_init_default {0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0} #define ModuleConfig_AudioConfig_init_default {0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
#define ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN} #define ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN}
#define ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0}
#define ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0} #define ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0}
#define ModuleConfig_RangeTestConfig_init_default {0, 0, 0} #define ModuleConfig_RangeTestConfig_init_default {0, 0, 0}
#define ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0} #define ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0}
@@ -203,7 +196,7 @@ extern "C" {
#define ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0} #define ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0}
#define ModuleConfig_AudioConfig_init_zero {0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0} #define ModuleConfig_AudioConfig_init_zero {0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
#define ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN} #define ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN}
#define ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0}
#define ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0} #define ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0}
#define ModuleConfig_RangeTestConfig_init_zero {0, 0, 0} #define ModuleConfig_RangeTestConfig_init_zero {0, 0, 0}
#define ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0} #define ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0}
@@ -235,13 +228,6 @@ extern "C" {
#define ModuleConfig_ExternalNotificationConfig_alert_message_tag 5 #define ModuleConfig_ExternalNotificationConfig_alert_message_tag 5
#define ModuleConfig_ExternalNotificationConfig_alert_bell_tag 6 #define ModuleConfig_ExternalNotificationConfig_alert_bell_tag 6
#define ModuleConfig_ExternalNotificationConfig_use_pwm_tag 7 #define ModuleConfig_ExternalNotificationConfig_use_pwm_tag 7
#define ModuleConfig_ExternalNotificationConfig_output_vibra_tag 8
#define ModuleConfig_ExternalNotificationConfig_output_buzzer_tag 9
#define ModuleConfig_ExternalNotificationConfig_alert_message_vibra_tag 10
#define ModuleConfig_ExternalNotificationConfig_alert_message_buzzer_tag 11
#define ModuleConfig_ExternalNotificationConfig_alert_bell_vibra_tag 12
#define ModuleConfig_ExternalNotificationConfig_alert_bell_buzzer_tag 13
#define ModuleConfig_ExternalNotificationConfig_nag_timeout_tag 14
#define ModuleConfig_MQTTConfig_enabled_tag 1 #define ModuleConfig_MQTTConfig_enabled_tag 1
#define ModuleConfig_MQTTConfig_address_tag 2 #define ModuleConfig_MQTTConfig_address_tag 2
#define ModuleConfig_MQTTConfig_username_tag 3 #define ModuleConfig_MQTTConfig_username_tag 3
@@ -337,14 +323,7 @@ X(a, STATIC, SINGULAR, UINT32, output, 3) \
X(a, STATIC, SINGULAR, BOOL, active, 4) \ X(a, STATIC, SINGULAR, BOOL, active, 4) \
X(a, STATIC, SINGULAR, BOOL, alert_message, 5) \ X(a, STATIC, SINGULAR, BOOL, alert_message, 5) \
X(a, STATIC, SINGULAR, BOOL, alert_bell, 6) \ X(a, STATIC, SINGULAR, BOOL, alert_bell, 6) \
X(a, STATIC, SINGULAR, BOOL, use_pwm, 7) \ X(a, STATIC, SINGULAR, BOOL, use_pwm, 7)
X(a, STATIC, SINGULAR, UINT32, output_vibra, 8) \
X(a, STATIC, SINGULAR, UINT32, output_buzzer, 9) \
X(a, STATIC, SINGULAR, BOOL, alert_message_vibra, 10) \
X(a, STATIC, SINGULAR, BOOL, alert_message_buzzer, 11) \
X(a, STATIC, SINGULAR, BOOL, alert_bell_vibra, 12) \
X(a, STATIC, SINGULAR, BOOL, alert_bell_buzzer, 13) \
X(a, STATIC, SINGULAR, UINT32, nag_timeout, 14)
#define ModuleConfig_ExternalNotificationConfig_CALLBACK NULL #define ModuleConfig_ExternalNotificationConfig_CALLBACK NULL
#define ModuleConfig_ExternalNotificationConfig_DEFAULT NULL #define ModuleConfig_ExternalNotificationConfig_DEFAULT NULL
@@ -412,7 +391,7 @@ extern const pb_msgdesc_t ModuleConfig_CannedMessageConfig_msg;
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define ModuleConfig_AudioConfig_size 19 #define ModuleConfig_AudioConfig_size 19
#define ModuleConfig_CannedMessageConfig_size 49 #define ModuleConfig_CannedMessageConfig_size 49
#define ModuleConfig_ExternalNotificationConfig_size 40 #define ModuleConfig_ExternalNotificationConfig_size 22
#define ModuleConfig_MQTTConfig_size 169 #define ModuleConfig_MQTTConfig_size 169
#define ModuleConfig_RangeTestConfig_size 10 #define ModuleConfig_RangeTestConfig_size 10
#define ModuleConfig_SerialConfig_size 26 #define ModuleConfig_SerialConfig_size 26
+84 -50
View File
@@ -1,7 +1,7 @@
#include "mesh/http/WiFiAPClient.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "RTC.h" #include "RTC.h"
#include "concurrency/Periodic.h" #include "concurrency/Periodic.h"
#include "mesh/http/WiFiAPClient.h"
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
#include "mesh/http/WebServer.h" #include "mesh/http/WebServer.h"
@@ -37,9 +37,9 @@ bool APStartupComplete = 0;
unsigned long lastrun_ntp = 0; unsigned long lastrun_ntp = 0;
static bool needReconnect = true; // If we create our reconnector, run it once at the beginning bool needReconnect = true; // If we create our reconnector, run it once at the beginning
static Periodic *wifiReconnect; Periodic *wifiReconnect;
static int32_t reconnectWiFi() static int32_t reconnectWiFi()
{ {
@@ -56,29 +56,15 @@ static int32_t reconnectWiFi()
// Make sure we clear old connection credentials // Make sure we clear old connection credentials
WiFi.disconnect(false, true); WiFi.disconnect(false, true);
DEBUG_MSG("... Reconnecting to WiFi access point %s\n",wifiName); DEBUG_MSG("Reconnecting to WiFi access point %s\n",wifiName);
int n = WiFi.scanNetworks();
if (n > 0) {
for (int i = 0; i < n; ++i) {
DEBUG_MSG("Found WiFi network %s, signal strength %d\n", WiFi.SSID(i).c_str(), WiFi.RSSI(i));
yield();
}
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(wifiName, wifiPsw);
} else {
DEBUG_MSG("No networks found during site survey. Rebooting MCU...\n");
screen->startRebootScreen();
rebootAtMsec = millis() + 5000;
}
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(wifiName, wifiPsw);
} }
#ifndef DISABLE_NTP #ifndef DISABLE_NTP
if (WiFi.isConnected() && (((millis() - lastrun_ntp) > 43200000) || (lastrun_ntp == 0))) { // every 12 hours if (WiFi.isConnected() && (((millis() - lastrun_ntp) > 43200000) || (lastrun_ntp == 0))) { // every 12 hours
DEBUG_MSG("Updating NTP time\n"); DEBUG_MSG("Updating NTP time from %s\n",config.network.ntp_server);
if (timeClient.update()) { if (timeClient.update()) {
DEBUG_MSG("NTP Request Success - Setting RTCQualityNTP if needed\n"); DEBUG_MSG("NTP Request Success - Setting RTCQualityNTP if needed\n");
@@ -129,7 +115,7 @@ static void onNetworkConnected()
{ {
if (!APStartupComplete) { if (!APStartupComplete) {
// Start web server // Start web server
DEBUG_MSG("... Starting network services\n"); DEBUG_MSG("Starting network services\n");
// start mdns // start mdns
if (!MDNS.begin("Meshtastic")) { if (!MDNS.begin("Meshtastic")) {
@@ -168,6 +154,8 @@ bool initWifi()
createSSLCert(); createSSLCert();
esp_wifi_set_storage(WIFI_STORAGE_RAM); // Disable flash storage for WiFi credentials
if (!*wifiPsw) // Treat empty password as no password if (!*wifiPsw) // Treat empty password as no password
wifiPsw = NULL; wifiPsw = NULL;
@@ -194,7 +182,7 @@ bool initWifi()
WiFi.onEvent( WiFi.onEvent(
[](WiFiEvent_t event, WiFiEventInfo_t info) { [](WiFiEvent_t event, WiFiEventInfo_t info) {
Serial.print("\nWiFi lost connection. Reason: "); Serial.print("WiFi lost connection. Reason: ");
Serial.println(info.wifi_sta_disconnected.reason); Serial.println(info.wifi_sta_disconnected.reason);
/* /*
@@ -221,91 +209,137 @@ bool initWifi()
// Called by the Espressif SDK to // Called by the Espressif SDK to
static void WiFiEvent(WiFiEvent_t event) static void WiFiEvent(WiFiEvent_t event)
{ {
DEBUG_MSG("************ [WiFi-event] event: %d ************\n", event); DEBUG_MSG("WiFi-Event %d: ", event);
switch (event) { switch (event) {
case SYSTEM_EVENT_WIFI_READY: case ARDUINO_EVENT_WIFI_READY:
DEBUG_MSG("WiFi interface ready\n"); DEBUG_MSG("WiFi interface ready\n");
break; break;
case SYSTEM_EVENT_SCAN_DONE: case ARDUINO_EVENT_WIFI_SCAN_DONE:
DEBUG_MSG("Completed scan for access points\n"); DEBUG_MSG("Completed scan for access points\n");
break; break;
case SYSTEM_EVENT_STA_START: case ARDUINO_EVENT_WIFI_STA_START:
DEBUG_MSG("WiFi station started\n"); DEBUG_MSG("WiFi station started\n");
break; break;
case SYSTEM_EVENT_STA_STOP: case ARDUINO_EVENT_WIFI_STA_STOP:
DEBUG_MSG("WiFi station stopped\n"); DEBUG_MSG("WiFi station stopped\n");
break; break;
case SYSTEM_EVENT_STA_CONNECTED: case ARDUINO_EVENT_WIFI_STA_CONNECTED:
DEBUG_MSG("Connected to access point\n"); DEBUG_MSG("Connected to access point\n");
break; break;
case SYSTEM_EVENT_STA_DISCONNECTED: case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
DEBUG_MSG("Disconnected from WiFi access point\n"); DEBUG_MSG("Disconnected from WiFi access point\n");
WiFi.disconnect(false, true); WiFi.disconnect(false, true);
needReconnect = true; needReconnect = true;
wifiReconnect->setIntervalFromNow(1000); wifiReconnect->setIntervalFromNow(1000);
break; break;
case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE:
DEBUG_MSG("Authentication mode of access point has changed\n"); DEBUG_MSG("Authentication mode of access point has changed\n");
break; break;
case SYSTEM_EVENT_STA_GOT_IP: case ARDUINO_EVENT_WIFI_STA_GOT_IP:
DEBUG_MSG("Obtained IP address: "); DEBUG_MSG("Obtained IP address: ");
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
onNetworkConnected(); onNetworkConnected();
break; break;
case SYSTEM_EVENT_STA_LOST_IP: case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
DEBUG_MSG("Obtained IP6 address: ");
Serial.println(WiFi.localIPv6());
break;
case ARDUINO_EVENT_WIFI_STA_LOST_IP:
DEBUG_MSG("Lost IP address and IP address is reset to 0\n"); DEBUG_MSG("Lost IP address and IP address is reset to 0\n");
WiFi.disconnect(false, true); WiFi.disconnect(false, true);
needReconnect = true; needReconnect = true;
wifiReconnect->setIntervalFromNow(1000); wifiReconnect->setIntervalFromNow(1000);
break; break;
case SYSTEM_EVENT_STA_WPS_ER_SUCCESS: case ARDUINO_EVENT_WPS_ER_SUCCESS:
DEBUG_MSG("WiFi Protected Setup (WPS): succeeded in enrollee mode\n"); DEBUG_MSG("WiFi Protected Setup (WPS): succeeded in enrollee mode\n");
break; break;
case SYSTEM_EVENT_STA_WPS_ER_FAILED: case ARDUINO_EVENT_WPS_ER_FAILED:
DEBUG_MSG("WiFi Protected Setup (WPS): failed in enrollee mode\n"); DEBUG_MSG("WiFi Protected Setup (WPS): failed in enrollee mode\n");
break; break;
case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT: case ARDUINO_EVENT_WPS_ER_TIMEOUT:
DEBUG_MSG("WiFi Protected Setup (WPS): timeout in enrollee mode\n"); DEBUG_MSG("WiFi Protected Setup (WPS): timeout in enrollee mode\n");
break; break;
case SYSTEM_EVENT_STA_WPS_ER_PIN: case ARDUINO_EVENT_WPS_ER_PIN:
DEBUG_MSG("WiFi Protected Setup (WPS): pin code in enrollee mode\n"); DEBUG_MSG("WiFi Protected Setup (WPS): pin code in enrollee mode\n");
break; break;
case SYSTEM_EVENT_AP_START: case ARDUINO_EVENT_WPS_ER_PBC_OVERLAP:
DEBUG_MSG("WiFi Protected Setup (WPS): push button overlap in enrollee mode\n");
break;
case ARDUINO_EVENT_WIFI_AP_START:
DEBUG_MSG("WiFi access point started\n"); DEBUG_MSG("WiFi access point started\n");
break; break;
case SYSTEM_EVENT_AP_STOP: case ARDUINO_EVENT_WIFI_AP_STOP:
DEBUG_MSG("WiFi access point stopped\n"); DEBUG_MSG("WiFi access point stopped\n");
break; break;
case SYSTEM_EVENT_AP_STACONNECTED: case ARDUINO_EVENT_WIFI_AP_STACONNECTED:
DEBUG_MSG("Client connected\n"); DEBUG_MSG("Client connected\n");
break; break;
case SYSTEM_EVENT_AP_STADISCONNECTED: case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED:
DEBUG_MSG("Client disconnected\n"); DEBUG_MSG("Client disconnected\n");
break; break;
case SYSTEM_EVENT_AP_STAIPASSIGNED: case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED:
DEBUG_MSG("Assigned IP address to client\n"); DEBUG_MSG("Assigned IP address to client\n");
break; break;
case SYSTEM_EVENT_AP_PROBEREQRECVED: case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED:
DEBUG_MSG("Received probe request\n"); DEBUG_MSG("Received probe request\n");
break; break;
case SYSTEM_EVENT_GOT_IP6: case ARDUINO_EVENT_WIFI_AP_GOT_IP6:
DEBUG_MSG("IPv6 is preferred\n"); DEBUG_MSG("IPv6 is preferred\n");
break; break;
case SYSTEM_EVENT_ETH_START: case ARDUINO_EVENT_WIFI_FTM_REPORT:
DEBUG_MSG("Fast Transition Management report\n");
break;
case ARDUINO_EVENT_ETH_START:
DEBUG_MSG("Ethernet started\n"); DEBUG_MSG("Ethernet started\n");
break; break;
case SYSTEM_EVENT_ETH_STOP: case ARDUINO_EVENT_ETH_STOP:
DEBUG_MSG("Ethernet stopped\n"); DEBUG_MSG("Ethernet stopped\n");
break; break;
case SYSTEM_EVENT_ETH_CONNECTED: case ARDUINO_EVENT_ETH_CONNECTED:
DEBUG_MSG("Ethernet connected\n"); DEBUG_MSG("Ethernet connected\n");
break; break;
case SYSTEM_EVENT_ETH_DISCONNECTED: case ARDUINO_EVENT_ETH_DISCONNECTED:
DEBUG_MSG("Ethernet disconnected\n"); DEBUG_MSG("Ethernet disconnected\n");
break; break;
case SYSTEM_EVENT_ETH_GOT_IP: case ARDUINO_EVENT_ETH_GOT_IP:
DEBUG_MSG("Obtained IP address (SYSTEM_EVENT_ETH_GOT_IP)\n"); DEBUG_MSG("Obtained IP address (ARDUINO_EVENT_ETH_GOT_IP)\n");
break;
case ARDUINO_EVENT_ETH_GOT_IP6:
DEBUG_MSG("Obtained IP6 address (ARDUINO_EVENT_ETH_GOT_IP6)\n");
break;
case ARDUINO_EVENT_SC_SCAN_DONE:
DEBUG_MSG("SmartConfig: Scan done\n");
break;
case ARDUINO_EVENT_SC_FOUND_CHANNEL:
DEBUG_MSG("SmartConfig: Found channel\n");
break;
case ARDUINO_EVENT_SC_GOT_SSID_PSWD:
DEBUG_MSG("SmartConfig: Got SSID and password\n");
break;
case ARDUINO_EVENT_SC_SEND_ACK_DONE:
DEBUG_MSG("SmartConfig: Send ACK done\n");
break;
case ARDUINO_EVENT_PROV_INIT:
DEBUG_MSG("Provisioning: Init\n");
break;
case ARDUINO_EVENT_PROV_DEINIT:
DEBUG_MSG("Provisioning: Stopped\n");
break;
case ARDUINO_EVENT_PROV_START:
DEBUG_MSG("Provisioning: Started\n");
break;
case ARDUINO_EVENT_PROV_END:
DEBUG_MSG("Provisioning: End\n");
break;
case ARDUINO_EVENT_PROV_CRED_RECV:
DEBUG_MSG("Provisioning: Credentials received\n");
break;
case ARDUINO_EVENT_PROV_CRED_FAIL:
DEBUG_MSG("Provisioning: Credentials failed\n");
break;
case ARDUINO_EVENT_PROV_CRED_SUCCESS:
DEBUG_MSG("Provisioning: Credentials success\n");
break; break;
default: default:
break; break;
+4
View File
@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "configuration.h" #include "configuration.h"
#include "concurrency/Periodic.h"
#include <Arduino.h> #include <Arduino.h>
#include <functional> #include <functional>
@@ -8,6 +9,9 @@
#include <WiFi.h> #include <WiFi.h>
#endif #endif
extern bool needReconnect;
extern concurrency::Periodic *wifiReconnect;
/// @return true if wifi is now in use /// @return true if wifi is now in use
bool initWifi(); bool initWifi();
+7 -1
View File
@@ -112,12 +112,15 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
if (BleOta::getOtaAppVersion().isEmpty()) { if (BleOta::getOtaAppVersion().isEmpty()) {
DEBUG_MSG("No OTA firmware available, scheduling regular reboot in %d seconds\n", s); DEBUG_MSG("No OTA firmware available, scheduling regular reboot in %d seconds\n", s);
screen->startRebootScreen();
}else{ }else{
screen->startFirmwareUpdateScreen();
BleOta::switchToOtaApp(); BleOta::switchToOtaApp();
DEBUG_MSG("Rebooting to OTA in %d seconds\n", s); DEBUG_MSG("Rebooting to OTA in %d seconds\n", s);
} }
#else #else
DEBUG_MSG("Not on ESP32, scheduling regular reboot in %d seconds\n", s); DEBUG_MSG("Not on ESP32, scheduling regular reboot in %d seconds\n", s);
screen->startRebootScreen();
#endif #endif
rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000); rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000);
break; break;
@@ -192,6 +195,7 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
void AdminModule::handleSetOwner(const User &o) void AdminModule::handleSetOwner(const User &o)
{ {
int changed = 0; int changed = 0;
bool licensed_changed = false;
if (*o.long_name) { if (*o.long_name) {
changed |= strcmp(owner.long_name, o.long_name); changed |= strcmp(owner.long_name, o.long_name);
@@ -207,12 +211,14 @@ void AdminModule::handleSetOwner(const User &o)
} }
if (owner.is_licensed != o.is_licensed) { if (owner.is_licensed != o.is_licensed) {
changed = 1; changed = 1;
licensed_changed = true;
owner.is_licensed = o.is_licensed; owner.is_licensed = o.is_licensed;
config.lora.override_duty_cycle = owner.is_licensed; // override duty cycle for licensed operators
} }
if (changed) { // If nothing really changed, don't broadcast on the network or write to flash if (changed) { // If nothing really changed, don't broadcast on the network or write to flash
service.reloadOwner(!hasOpenEditTransaction); service.reloadOwner(!hasOpenEditTransaction);
saveChanges(SEGMENT_DEVICESTATE); licensed_changed ? saveChanges(SEGMENT_CONFIG | SEGMENT_DEVICESTATE) : saveChanges(SEGMENT_DEVICESTATE);
} }
} }
+4
View File
@@ -451,11 +451,15 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
if (this->destSelect) { if (this->destSelect) {
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK); display->setColor(BLACK);
display->drawStringf(1 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
} }
display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest)); display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
// used chars right aligned // used chars right aligned
sprintf(buffer, "%d left", Constants_DATA_PAYLOAD_LEN - this->freetext.length()); sprintf(buffer, "%d left", Constants_DATA_PAYLOAD_LEN - this->freetext.length());
display->drawString(x + display->getWidth() - display->getStringWidth(buffer), y + 0, buffer); display->drawString(x + display->getWidth() - display->getStringWidth(buffer), y + 0, buffer);
if (this->destSelect) {
display->drawString(x + display->getWidth() - display->getStringWidth(buffer) - 1, y + 0, buffer);
}
display->setColor(WHITE); display->setColor(WHITE);
display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), cannedMessageModule->drawWithCursor(cannedMessageModule->freetext, cannedMessageModule->cursor)); display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), cannedMessageModule->drawWithCursor(cannedMessageModule->freetext, cannedMessageModule->cursor));
} else { } else {
+3 -5
View File
@@ -11,6 +11,7 @@
#include "modules/ReplyModule.h" #include "modules/ReplyModule.h"
#include "modules/RoutingModule.h" #include "modules/RoutingModule.h"
#include "modules/TextMessageModule.h" #include "modules/TextMessageModule.h"
#include "modules/TraceRouteModule.h"
#include "modules/WaypointModule.h" #include "modules/WaypointModule.h"
#if HAS_TELEMETRY #if HAS_TELEMETRY
#include "modules/Telemetry/DeviceTelemetry.h" #include "modules/Telemetry/DeviceTelemetry.h"
@@ -19,10 +20,8 @@
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#include "modules/esp32/RangeTestModule.h" #include "modules/esp32/RangeTestModule.h"
#include "modules/esp32/StoreForwardModule.h" #include "modules/esp32/StoreForwardModule.h"
#ifdef USE_SX1280
#include "modules/esp32/AudioModule.h" #include "modules/esp32/AudioModule.h"
#endif #endif
#endif
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) #if defined(ARCH_ESP32) || defined(ARCH_NRF52)
#include "modules/ExternalNotificationModule.h" #include "modules/ExternalNotificationModule.h"
#if !defined(TTGO_T_ECHO) #if !defined(TTGO_T_ECHO)
@@ -42,6 +41,7 @@ void setupModules()
positionModule = new PositionModule(); positionModule = new PositionModule();
waypointModule = new WaypointModule(); waypointModule = new WaypointModule();
textMessageModule = new TextMessageModule(); textMessageModule = new TextMessageModule();
traceRouteModule = new TraceRouteModule();
// Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance // Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance
// to a global variable. // to a global variable.
@@ -68,9 +68,7 @@ void setupModules()
#endif #endif
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
// Only run on an esp32 based device. // Only run on an esp32 based device.
#ifdef USE_SX1280 audioModule = new AudioModule();
new AudioModule();
#endif
new ExternalNotificationModule(); new ExternalNotificationModule();
storeForwardModule = new StoreForwardModule(); storeForwardModule = new StoreForwardModule();
+2 -2
View File
@@ -82,7 +82,7 @@ SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio")
int32_t SerialModule::runOnce() int32_t SerialModule::runOnce()
{ {
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) #if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
/* /*
Uncomment the preferences below if you want to use the module Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI. without having to configure it from the PythonAPI or WebUI.
@@ -239,7 +239,7 @@ void SerialModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp) ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
{ {
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) #if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
if (moduleConfig.serial.enabled) { if (moduleConfig.serial.enabled) {
auto &p = mp.decoded; auto &p = mp.decoded;
+86
View File
@@ -0,0 +1,86 @@
#include "TraceRouteModule.h"
#include "MeshService.h"
#include "FloodingRouter.h"
TraceRouteModule *traceRouteModule;
bool TraceRouteModule::handleReceivedProtobuf(const MeshPacket &mp, RouteDiscovery *r)
{
// Only handle a response
if (mp.decoded.request_id) {
printRoute(r, mp.to, mp.from);
}
return false; // let it be handled by RoutingModule
}
void TraceRouteModule::updateRoute(MeshPacket* p)
{
auto &incoming = p->decoded;
// Only append an ID for the request (one way)
if (!incoming.request_id) {
RouteDiscovery scratch;
RouteDiscovery *updated = NULL;
memset(&scratch, 0, sizeof(scratch));
pb_decode_from_bytes(incoming.payload.bytes, incoming.payload.size, RouteDiscovery_fields, &scratch);
updated = &scratch;
appendMyID(updated);
printRoute(updated, p->from, NODENUM_BROADCAST);
// Set updated route to the payload of the to be flooded packet
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), RouteDiscovery_fields, updated);
}
}
void TraceRouteModule::appendMyID(RouteDiscovery* updated)
{
// Length of route array can normally not be exceeded due to the max. hop_limit of 7
if (updated->route_count < sizeof(updated->route)/sizeof(updated->route[0])) {
updated->route[updated->route_count] = myNodeInfo.my_node_num;
updated->route_count += 1;
} else {
DEBUG_MSG("WARNING: Route exceeded maximum hop limit, are you bridging networks?\n");
}
}
void TraceRouteModule::printRoute(RouteDiscovery* r, uint32_t origin, uint32_t dest)
{
DEBUG_MSG("Route traced:\n");
DEBUG_MSG("0x%x --> ", origin);
for (uint8_t i=0; i<r->route_count; i++) {
DEBUG_MSG("0x%x --> ", r->route[i]);
}
if (dest != NODENUM_BROADCAST) DEBUG_MSG("0x%x\n", dest); else DEBUG_MSG("...\n");
}
MeshPacket* TraceRouteModule::allocReply()
{
assert(currentRequest);
// Copy the payload of the current request
auto req = *currentRequest;
auto &p = req.decoded;
RouteDiscovery scratch;
RouteDiscovery *updated = NULL;
memset(&scratch, 0, sizeof(scratch));
pb_decode_from_bytes(p.payload.bytes, p.payload.size, RouteDiscovery_fields, &scratch);
updated = &scratch;
printRoute(updated, req.from, req.to);
// Create a MeshPacket with this payload and set it as the reply
MeshPacket* reply = allocDataProtobuf(*updated);
return reply;
}
TraceRouteModule::TraceRouteModule() : ProtobufModule("traceroute", PortNum_TRACEROUTE_APP, RouteDiscovery_fields) {
ourPortNum = PortNum_TRACEROUTE_APP;
}
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include "ProtobufModule.h"
/**
* A module that traces the route to a certain destination node
*/
class TraceRouteModule : public ProtobufModule<RouteDiscovery>
{
public:
TraceRouteModule();
// Let FloodingRouter call updateRoute upon rebroadcasting a TraceRoute request
friend class FloodingRouter;
protected:
bool handleReceivedProtobuf(const MeshPacket &mp, RouteDiscovery *r) override;
virtual MeshPacket *allocReply() override;
/* Call before rebroadcasting a RouteDiscovery payload in order to update
the route array containing the IDs of nodes this packet went through */
void updateRoute(MeshPacket* p);
private:
// Call to add your ID to the route array of a RouteDiscovery message
void appendMyID(RouteDiscovery *r);
/* Call to print the route array of a RouteDiscovery message.
Set origin to where the request came from.
Set dest to the ID of its destination, or NODENUM_BROADCAST if it has not yet arrived there. */
void printRoute(RouteDiscovery* r, uint32_t origin, uint32_t dest);
};
extern TraceRouteModule *traceRouteModule;
+223 -149
View File
@@ -1,4 +1,6 @@
#include "configuration.h" #include "configuration.h"
#if defined(ARCH_ESP32)
#include "AudioModule.h" #include "AudioModule.h"
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
@@ -8,6 +10,10 @@
#include <assert.h> #include <assert.h>
#ifdef OLED_RU
#include "graphics/fonts/OLEDDisplayFontsRU.h"
#endif
/* /*
AudioModule AudioModule
A interface to send raw codec2 audio data over the mesh network. Based on the example code from the ESP32_codec2 project. A interface to send raw codec2 audio data over the mesh network. Based on the example code from the ESP32_codec2 project.
@@ -19,201 +25,269 @@
Basic Usage: Basic Usage:
1) Enable the module by setting audio.codec2_enabled to 1. 1) Enable the module by setting audio.codec2_enabled to 1.
2) Set the pins (audio.mic_pin / audio.amp_pin) for your preferred microphone and amplifier GPIO pins. 2) Set the pins for the I2S interface. Recommended on TLora is I2S_WS 13/I2S_SD 15/I2S_SIN 2/I2S_SCK 14
On tbeam, recommend to use: 3) Set audio.bitrate to the desired codec2 rate (CODEC2_3200, CODEC2_2400, CODEC2_1600, CODEC2_1400, CODEC2_1300, CODEC2_1200, CODEC2_700, CODEC2_700B)
audio.mic_chan 6 (GPIO 34)
audio.amp_pin 14
audio.ptt_pin 39
3) Set audio.timeout to the amount of time to wait before we consider
your voice stream as "done".
4) Set audio.bitrate to the desired codec2 rate (CODEC2_3200, CODEC2_2400, CODEC2_1600, CODEC2_1400, CODEC2_1300, CODEC2_1200, CODEC2_700, CODEC2_700B)
KNOWN PROBLEMS KNOWN PROBLEMS
* Until the module is initilized by the startup sequence, the amp_pin pin is in a floating * Half Duplex
state. This may produce a bit of "noise". * Will not work on NRF and the Linux device targets (yet?).
* Will not work on NRF and the Linux device targets.
*/ */
#define AMIC 6
#define AAMP 14
#define PTT_PIN 39
#define AUDIO_MODULE_RX_BUFFER 128
#define AUDIO_MODULE_DATA_MAX Constants_DATA_PAYLOAD_LEN
#define AUDIO_MODULE_MODE 7 // 700B
#define AUDIO_MODULE_ACK 1
#if defined(ARCH_ESP32) && defined(USE_SX1280)
AudioModule *audioModule;
ButterworthFilter hp_filter(240, 8000, ButterworthFilter::ButterworthFilter::Highpass, 1); ButterworthFilter hp_filter(240, 8000, ButterworthFilter::ButterworthFilter::Highpass, 1);
//int16_t 1KHz sine test tone TaskHandle_t codec2HandlerTask;
int16_t Sine1KHz[8] = { -21210 , -30000, -21210, 0 , 21210 , 30000 , 21210, 0 }; AudioModule *audioModule;
int Sine1KHz_index = 0;
uint8_t rx_raw_audio_value = 127; #ifdef ARCH_ESP32
// ESP32 doesn't use that flag
#define YIELD_FROM_ISR(x) portYIELD_FROM_ISR()
#else
#define YIELD_FROM_ISR(x) portYIELD_FROM_ISR(x)
#endif
AudioModule::AudioModule() : SinglePortModule("AudioModule", PortNum_AUDIO_APP), concurrency::OSThread("AudioModule") { #if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
audio_fifo.init(); // The screen is bigger so use bigger fonts
} #define FONT_SMALL ArialMT_Plain_16
#define FONT_MEDIUM ArialMT_Plain_24
#define FONT_LARGE ArialMT_Plain_24
#else
#ifdef OLED_RU
#define FONT_SMALL ArialMT_Plain_10_RU
#else
#define FONT_SMALL ArialMT_Plain_10
#endif
#define FONT_MEDIUM ArialMT_Plain_16
#define FONT_LARGE ArialMT_Plain_24
#endif
void AudioModule::run_codec2() #define fontHeight(font) ((font)[1] + 1) // height is position 1
#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL)
#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM)
#define FONT_HEIGHT_LARGE fontHeight(FONT_LARGE)
void run_codec2(void* parameter)
{ {
if (state == State::tx) // 4 bytes of header in each frame hex c0 de c2 plus the bitrate
{ memcpy(audioModule->tx_encode_frame,&audioModule->tx_header,sizeof(audioModule->tx_header));
for (int i = 0; i < ADC_BUFFER_SIZE; i++)
speech[i] = (int16_t)hp_filter.Update((float)speech[i]);
codec2_encode(codec2_state, tx_encode_frame + tx_encode_frame_index, speech); DEBUG_MSG("Starting codec2 task\n");
//increment the pointer where the encoded frame must be saved while (true) {
tx_encode_frame_index += 8; uint32_t tcount = ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(10000));
//If it is the 5th time then we have a ready trasnmission frame if (tcount != 0) {
if (tx_encode_frame_index == ENCODE_FRAME_SIZE) if (audioModule->radio_state == RadioState::tx) {
{ for (int i = 0; i < audioModule->adc_buffer_size; i++)
tx_encode_frame_index = 0; audioModule->speech[i] = (int16_t)hp_filter.Update((float)audioModule->speech[i]);
//Transmit it
sendPayload(); codec2_encode(audioModule->codec2, audioModule->tx_encode_frame + audioModule->tx_encode_frame_index, audioModule->speech);
audioModule->tx_encode_frame_index += audioModule->encode_codec_size;
if (audioModule->tx_encode_frame_index == (audioModule->encode_frame_size + sizeof(audioModule->tx_header)))
{
DEBUG_MSG("Sending %d codec2 bytes\n", audioModule->encode_frame_size);
audioModule->sendPayload();
audioModule->tx_encode_frame_index = sizeof(audioModule->tx_header);
}
}
if (audioModule->radio_state == RadioState::rx) {
size_t bytesOut = 0;
if (memcmp(audioModule->rx_encode_frame, &audioModule->tx_header, sizeof(audioModule->tx_header)) == 0) {
for (int i = 4; i < audioModule->rx_encode_frame_index; i += audioModule->encode_codec_size)
{
codec2_decode(audioModule->codec2, audioModule->output_buffer, audioModule->rx_encode_frame + i);
i2s_write(I2S_PORT, &audioModule->output_buffer, audioModule->adc_buffer_size, &bytesOut, pdMS_TO_TICKS(500));
}
} else {
// if the buffer header does not match our own codec, make a temp decoding setup.
CODEC2* tmp_codec2 = codec2_create(audioModule->rx_encode_frame[3]);
codec2_set_lpc_post_filter(tmp_codec2, 1, 0, 0.8, 0.2);
int tmp_encode_codec_size = (codec2_bits_per_frame(tmp_codec2) + 7) / 8;
int tmp_adc_buffer_size = codec2_samples_per_frame(tmp_codec2);
for (int i = 4; i < audioModule->rx_encode_frame_index; i += tmp_encode_codec_size)
{
codec2_decode(tmp_codec2, audioModule->output_buffer, audioModule->rx_encode_frame + i);
i2s_write(I2S_PORT, &audioModule->output_buffer, tmp_adc_buffer_size, &bytesOut, pdMS_TO_TICKS(500));
}
codec2_destroy(tmp_codec2);
}
}
} }
} }
if (state == State::rx) //Receiving }
{
//Make a cycle to get each codec2 frame from the received frame AudioModule::AudioModule() : SinglePortModule("AudioModule", PortNum_AUDIO_APP), concurrency::OSThread("AudioModule")
for (int i = 0; i < ENCODE_FRAME_SIZE; i += 8) {
{ // moduleConfig.audio.codec2_enabled = true;
//Decode the codec2 frame // moduleConfig.audio.i2s_ws = 13;
codec2_decode(codec2_state, output_buffer, rx_encode_frame + i); // moduleConfig.audio.i2s_sd = 15;
// moduleConfig.audio.i2s_din = 22;
// Add to the audio buffer the 320 samples resulting of the decode of the codec2 frame. // moduleConfig.audio.i2s_sck = 14;
for (int g = 0; g < ADC_BUFFER_SIZE; g++) // moduleConfig.audio.ptt_pin = 39;
audio_fifo.put(output_buffer[g]);
} if ((moduleConfig.audio.codec2_enabled) && (myRegion->audioPermitted)) {
DEBUG_MSG("Setting up codec2 in mode %u", (moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1);
codec2 = codec2_create((moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1);
memcpy(tx_header.magic,c2_magic,sizeof(c2_magic));
tx_header.mode = (moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1;
codec2_set_lpc_post_filter(codec2, 1, 0, 0.8, 0.2);
encode_codec_size = (codec2_bits_per_frame(codec2) + 7) / 8;
encode_frame_num = (Constants_DATA_PAYLOAD_LEN - sizeof(tx_header)) / encode_codec_size;
encode_frame_size = encode_frame_num * encode_codec_size; // max 233 bytes + 4 header bytes
adc_buffer_size = codec2_samples_per_frame(codec2);
DEBUG_MSG(" using %d frames of %d bytes for a total payload length of %d bytes\n", encode_frame_num, encode_codec_size, encode_frame_size);
xTaskCreate(&run_codec2, "codec2_task", 30000, NULL, 5, &codec2HandlerTask);
} else {
DEBUG_MSG("Codec2 disabled (AudioModule %d, Region %s, permitted %d)\n", moduleConfig.audio.codec2_enabled, myRegion->name, myRegion->audioPermitted);
} }
state = State::standby;
} }
void AudioModule::handleInterrupt() void AudioModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
audioModule->onTimer(); displayedNodeNum = 0; // Not currently showing a node pane
}
void AudioModule::onTimer() char buffer[50];
{
if (state == State::tx) {
adc_buffer[adc_buffer_index++] = (16 * adc1_get_raw(mic_chan)) - 32768;
//If you want to test with a 1KHz tone, comment the line above and descomment the three lines below display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_SMALL);
// adc_buffer[adc_buffer_index++] = Sine1KHz[Sine1KHz_index++]; display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
// if (Sine1KHz_index >= 8) display->setColor(BLACK);
// Sine1KHz_index = 0; display->drawStringf(0 + x, 0 + y, buffer, "Codec2 Mode %d Audio", (moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1);
display->setColor(WHITE);
if (adc_buffer_index == ADC_BUFFER_SIZE) { display->setFont(FONT_LARGE);
adc_buffer_index = 0; display->setTextAlignment(TEXT_ALIGN_CENTER);
memcpy((void*)speech, (void*)adc_buffer, 2 * ADC_BUFFER_SIZE); switch (radio_state) {
audioModule->setIntervalFromNow(0); // process buffer immediately case RadioState::tx:
} display->drawString(display->getWidth() / 2 + x, (display->getHeight() - FONT_HEIGHT_SMALL) / 2 + y, "PTT");
} else if (state == State::rx) { break;
default:
int16_t v; display->drawString(display->getWidth() / 2 + x, (display->getHeight() - FONT_HEIGHT_SMALL) / 2 + y, "Receive");
break;
//Get a value from audio_fifo and convert it to 0 - 255 to play it in the ADC
//If none value is available the DAC will play the last one that was read, that's
//why the rx_raw_audio_value variable is a global one.
if (audio_fifo.get(&v))
rx_raw_audio_value = (uint8_t)((v + 32768) / 256);
//Play
dacWrite(moduleConfig.audio.amp_pin ? moduleConfig.audio.amp_pin : AAMP, rx_raw_audio_value);
} }
} }
int32_t AudioModule::runOnce() int32_t AudioModule::runOnce()
{ {
if (moduleConfig.audio.codec2_enabled) { if ((moduleConfig.audio.codec2_enabled) && (myRegion->audioPermitted)) {
esp_err_t res;
if (firstTime) { if (firstTime) {
// Set up I2S Processor configuration. This will produce 16bit samples at 8 kHz instead of 12 from the ADC
DEBUG_MSG("Initializing I2S SD: %d DIN: %d WS: %d SCK: %d\n", moduleConfig.audio.i2s_sd, moduleConfig.audio.i2s_din, moduleConfig.audio.i2s_ws, moduleConfig.audio.i2s_sck);
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | (moduleConfig.audio.i2s_sd ? I2S_MODE_RX : 0) | (moduleConfig.audio.i2s_din ? I2S_MODE_TX : 0)),
.sample_rate = 8000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S),
.intr_alloc_flags = 0,
.dma_buf_count = 8,
.dma_buf_len = adc_buffer_size, // 320 * 2 bytes
.use_apll = false,
.tx_desc_auto_clear = true,
.fixed_mclk = 0
};
res = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
if(res != ESP_OK)
DEBUG_MSG("Failed to install I2S driver: %d\n", res);
DEBUG_MSG("Initializing ADC on Channel %u\n", moduleConfig.audio.mic_chan ? moduleConfig.audio.mic_chan : AMIC); const i2s_pin_config_t pin_config = {
.bck_io_num = moduleConfig.audio.i2s_sck,
.ws_io_num = moduleConfig.audio.i2s_ws,
.data_out_num = moduleConfig.audio.i2s_din ? moduleConfig.audio.i2s_din : I2S_PIN_NO_CHANGE,
.data_in_num = moduleConfig.audio.i2s_sd ? moduleConfig.audio.i2s_sd : I2S_PIN_NO_CHANGE
};
res = i2s_set_pin(I2S_PORT, &pin_config);
if(res != ESP_OK)
DEBUG_MSG("Failed to set I2S pin config: %d\n", res);
mic_chan = moduleConfig.audio.mic_chan ? (adc1_channel_t)(int)moduleConfig.audio.mic_chan : (adc1_channel_t)AMIC; res = i2s_start(I2S_PORT);
adc1_config_width(ADC_WIDTH_12Bit); if(res != ESP_OK)
adc1_config_channel_atten(mic_chan, ADC_ATTEN_DB_6); DEBUG_MSG("Failed to start I2S: %d\n", res);
// Start a timer at 8kHz to sample the ADC and play the audio on the DAC. radio_state = RadioState::rx;
uint32_t cpufreq = getCpuFrequencyMhz();
switch (cpufreq){
case 160:
adcTimer = timerBegin(3, 1000, true); // 160 MHz / 1000 = 160KHz
break;
case 240:
adcTimer = timerBegin(3, 1500, true); // 240 MHz / 1500 = 160KHz
break;
case 320:
adcTimer = timerBegin(3, 2000, true); // 320 MHz / 2000 = 160KHz
break;
case 80:
default:
adcTimer = timerBegin(3, 500, true); // 80 MHz / 500 = 160KHz
break;
}
timerAttachInterrupt(adcTimer, &AudioModule::handleInterrupt, true);
timerAlarmWrite(adcTimer, 20, true); // Interrupts when counter == 20, 8.000 times a second
timerAlarmEnable(adcTimer);
DEBUG_MSG("Initializing DAC on Pin %u\n", moduleConfig.audio.amp_pin ? moduleConfig.audio.amp_pin : AAMP);
DEBUG_MSG("Initializing PTT on Pin %u\n", moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN);
// Configure PTT input // Configure PTT input
pinMode(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN, INPUT_PULLUP); DEBUG_MSG("Initializing PTT on Pin %u\n", moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN);
pinMode(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN, INPUT);
state = State::rx; firstTime = false;
DEBUG_MSG("Setting up codec2 in mode %u\n", moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE);
codec2_state = codec2_create(moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE);
codec2_set_lpc_post_filter(codec2_state, 1, 0, 0.8, 0.2);
firstTime = 0;
} else { } else {
// Check if we have a PTT press UIFrameEvent e = {false, true};
if (digitalRead(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN) == LOW) { // Check if PTT is pressed. TODO hook that into Onebutton/Interrupt drive.
// PTT pressed, recording if (digitalRead(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN) == HIGH) {
state = State::tx; if (radio_state == RadioState::rx) {
DEBUG_MSG("PTT pressed, switching to TX\n");
radio_state = RadioState::tx;
e.frameChanged = true;
this->notifyObservers(&e);
}
} else {
if (radio_state == RadioState::tx) {
DEBUG_MSG("PTT released, switching to RX\n");
if (tx_encode_frame_index > sizeof(tx_header)) {
// Send the incomplete frame
DEBUG_MSG("Sending %d codec2 bytes (incomplete)\n", tx_encode_frame_index);
sendPayload();
}
tx_encode_frame_index = sizeof(tx_header);
radio_state = RadioState::rx;
e.frameChanged = true;
this->notifyObservers(&e);
}
} }
if (state != State::standby) { if (radio_state == RadioState::tx) {
run_codec2(); // Get I2S data from the microphone and place in data buffer
size_t bytesIn = 0;
res = i2s_read(I2S_PORT, adc_buffer + adc_buffer_index, adc_buffer_size - adc_buffer_index, &bytesIn, pdMS_TO_TICKS(40)); // wait 40ms for audio to arrive.
if (res == ESP_OK) {
adc_buffer_index += bytesIn;
if (adc_buffer_index == adc_buffer_size) {
adc_buffer_index = 0;
memcpy((void*)speech, (void*)adc_buffer, 2 * adc_buffer_size);
// Notify run_codec2 task that the buffer is ready.
radio_state = RadioState::tx;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(codec2HandlerTask, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken == pdTRUE)
YIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
} }
} }
return 100; return 100;
} else { } else {
DEBUG_MSG("Audio Module Disabled\n"); DEBUG_MSG("Audio Module Disabled\n");
return INT32_MAX; return INT32_MAX;
} }
} }
MeshPacket *AudioModule::allocReply() MeshPacket *AudioModule::allocReply()
{ {
auto reply = allocDataPacket();
auto reply = allocDataPacket(); // Allocate a packet for sending
return reply; return reply;
} }
bool AudioModule::shouldDraw()
{
if (!moduleConfig.audio.codec2_enabled) {
return false;
}
return (radio_state == RadioState::tx);
}
void AudioModule::sendPayload(NodeNum dest, bool wantReplies) void AudioModule::sendPayload(NodeNum dest, bool wantReplies)
{ {
MeshPacket *p = allocReply(); MeshPacket *p = allocReply();
p->to = dest; p->to = dest;
p->decoded.want_response = wantReplies; p->decoded.want_response = wantReplies;
p->want_ack = AUDIO_MODULE_ACK; p->want_ack = false; // Audio is shoot&forget. No need to wait for ACKs.
p->priority = MeshPacket_Priority_MAX; // Audio is important, because realtime
p->decoded.payload.size = ENCODE_FRAME_SIZE; p->decoded.payload.size = tx_encode_frame_index;
memcpy(p->decoded.payload.bytes, tx_encode_frame, p->decoded.payload.size); memcpy(p->decoded.payload.bytes, tx_encode_frame, p->decoded.payload.size);
service.sendToMesh(p); service.sendToMesh(p);
@@ -221,17 +295,17 @@ void AudioModule::sendPayload(NodeNum dest, bool wantReplies)
ProcessMessage AudioModule::handleReceived(const MeshPacket &mp) ProcessMessage AudioModule::handleReceived(const MeshPacket &mp)
{ {
if (moduleConfig.audio.codec2_enabled) { if ((moduleConfig.audio.codec2_enabled) && (myRegion->audioPermitted)) {
auto &p = mp.decoded; auto &p = mp.decoded;
if (getFrom(&mp) != nodeDB.getNodeNum()) { if (getFrom(&mp) != nodeDB.getNodeNum()) {
if (p.payload.size == ENCODE_FRAME_SIZE) { memcpy(rx_encode_frame, p.payload.bytes, p.payload.size);
memcpy(rx_encode_frame, p.payload.bytes, p.payload.size); radio_state = RadioState::rx;
state = State::rx; rx_encode_frame_index = p.payload.size;
audioModule->setIntervalFromNow(0); // Notify run_codec2 task that the buffer is ready.
run_codec2(); BaseType_t xHigherPriorityTaskWoken = pdFALSE;
} else { vTaskNotifyGiveFromISR(codec2HandlerTask, &xHigherPriorityTaskWoken);
DEBUG_MSG("Invalid payload size %u != %u\n", p.payload.size, ENCODE_FRAME_SIZE); if (xHigherPriorityTaskWoken == pdTRUE)
} YIELD_FROM_ISR(xHigherPriorityTaskWoken);
} }
} }
+54 -35
View File
@@ -1,68 +1,87 @@
#pragma once #pragma once
#include "SinglePortModule.h" #include "SinglePortModule.h"
#include "concurrency/OSThread.h" #include "concurrency/NotifiedWorkerThread.h"
#include "configuration.h" #include "configuration.h"
#if defined(ARCH_ESP32)
#include "NodeDB.h" #include "NodeDB.h"
#include <Arduino.h> #include <Arduino.h>
#include <driver/adc.h> #include <driver/i2s.h>
#include <functional> #include <functional>
#if defined(ARCH_ESP32) && defined(USE_SX1280)
#include <codec2.h> #include <codec2.h>
#include <ButterworthFilter.h> #include <ButterworthFilter.h>
#include <FastAudioFIFO.h> #include <OLEDDisplay.h>
#endif #include <OLEDDisplayUi.h>
#define ADC_BUFFER_SIZE 320 // 40ms of voice in 8KHz sampling frequency enum RadioState { standby, rx, tx };
#define ENCODE_FRAME_SIZE 40 // 5 codec2 frames of 8 bytes each
class AudioModule : public SinglePortModule, private concurrency::OSThread const char c2_magic[3] = {0xc0, 0xde, 0xc2}; // Magic number for codec2 header
struct c2_header {
char magic[3];
char mode;
};
#define ADC_BUFFER_SIZE_MAX 320
#define PTT_PIN 39
#define I2S_PORT I2S_NUM_0
#define AUDIO_MODULE_RX_BUFFER 128
#define AUDIO_MODULE_MODE ModuleConfig_AudioConfig_Audio_Baud_CODEC2_700
class AudioModule : public SinglePortModule, public Observable<const UIFrameEvent *>, private concurrency::OSThread
{ {
#if defined(ARCH_ESP32) && defined(USE_SX1280)
bool firstTime = 1;
hw_timer_t* adcTimer = NULL;
uint16_t adc_buffer[ADC_BUFFER_SIZE] = {};
int16_t speech[ADC_BUFFER_SIZE] = {};
int16_t output_buffer[ADC_BUFFER_SIZE] = {};
unsigned char rx_encode_frame[ENCODE_FRAME_SIZE] = {};
unsigned char tx_encode_frame[ENCODE_FRAME_SIZE] = {};
int tx_encode_frame_index = 0;
FastAudioFIFO audio_fifo;
uint16_t adc_buffer_index = 0;
adc1_channel_t mic_chan = (adc1_channel_t)0;
struct CODEC2* codec2_state = NULL;
enum State
{
standby, rx, tx
};
volatile State state = State::tx;
public: public:
unsigned char rx_encode_frame[Constants_DATA_PAYLOAD_LEN] = {};
unsigned char tx_encode_frame[Constants_DATA_PAYLOAD_LEN] = {};
c2_header tx_header = {};
int16_t speech[ADC_BUFFER_SIZE_MAX] = {};
int16_t output_buffer[ADC_BUFFER_SIZE_MAX] = {};
uint16_t adc_buffer[ADC_BUFFER_SIZE_MAX] = {};
int adc_buffer_size = 0;
uint16_t adc_buffer_index = 0;
int tx_encode_frame_index = sizeof(c2_header); // leave room for header
int rx_encode_frame_index = 0;
int encode_codec_size = 0;
int encode_frame_size = 0;
volatile RadioState radio_state = RadioState::rx;
struct CODEC2* codec2 = NULL;
// int16_t sample;
AudioModule(); AudioModule();
bool shouldDraw();
/** /**
* Send our payload into the mesh * Send our payload into the mesh
*/ */
void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
protected: protected:
int encode_frame_num = 0;
bool firstTime = true;
virtual int32_t runOnce() override; virtual int32_t runOnce() override;
static void handleInterrupt();
void onTimer();
void run_codec2();
virtual MeshPacket *allocReply() override; virtual MeshPacket *allocReply() override;
virtual bool wantUIFrame() override { return this->shouldDraw(); }
virtual Observable<const UIFrameEvent *>* getUIFrameObservable() override { return this; }
#if !HAS_SCREEN
void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
#else
virtual void drawFrame(
OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override;
#endif
/** Called to handle a particular incoming message /** Called to handle a particular incoming message
* @return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it * @return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
*/ */
virtual ProcessMessage handleReceived(const MeshPacket &mp) override; virtual ProcessMessage handleReceived(const MeshPacket &mp) override;
#endif
}; };
extern AudioModule *audioModule; extern AudioModule *audioModule;
#endif
+137 -136
View File
@@ -16,52 +16,50 @@ StoreForwardModule *storeForwardModule;
int32_t StoreForwardModule::runOnce() int32_t StoreForwardModule::runOnce()
{ {
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
if (moduleConfig.store_forward.enabled && is_server) {
// Send out the message queue.
if (this->busy) {
// Only send packets if the channel is less than 25% utilized.
if (airTime->channelUtilizationPercent() < polite_channel_util_percent) {
if (moduleConfig.store_forward.enabled) { // DEBUG_MSG("--- --- --- In busy loop 1 %d\n", this->packetHistoryTXQueue_index);
storeForwardModule->sendPayload(this->busyTo, this->packetHistoryTXQueue_index);
if (config.device.role == Config_DeviceConfig_Role_ROUTER) { if (this->packetHistoryTXQueue_index == packetHistoryTXQueue_size) {
strcpy(this->routerMessage, "** S&F - Done");
// Send out the message queue. storeForwardModule->sendMessage(this->busyTo, this->routerMessage);
if (this->busy) {
// Only send packets if the channel is less than 25% utilized.
if (airTime->channelUtilizationPercent() < polite_channel_util_percent) {
// DEBUG_MSG("--- --- --- In busy loop 1 %d\n", this->packetHistoryTXQueue_index);
storeForwardModule->sendPayload(this->busyTo, this->packetHistoryTXQueue_index);
if (this->packetHistoryTXQueue_index == packetHistoryTXQueue_size) {
strcpy(this->routerMessage, "** S&F - Done");
storeForwardModule->sendMessage(this->busyTo, this->routerMessage);
// DEBUG_MSG("--- --- --- In busy loop - Done \n");
this->packetHistoryTXQueue_index = 0;
this->busy = false;
} else {
this->packetHistoryTXQueue_index++;
}
// DEBUG_MSG("--- --- --- In busy loop - Done \n");
this->packetHistoryTXQueue_index = 0;
this->busy = false;
} else { } else {
DEBUG_MSG("Channel utilization is too high. Skipping this opportunity to send and will retry later.\n"); this->packetHistoryTXQueue_index++;
} }
} else {
DEBUG_MSG("Channel utilization is too high. Retrying later.\n");
} }
DEBUG_MSG("SF myNodeInfo.bitrate = %f bytes / sec\n", myNodeInfo.bitrate); DEBUG_MSG("SF bitrate = %f bytes / sec\n", myNodeInfo.bitrate);
return (this->packetTimeMax); } else if (millis() - lastHeartbeat > 300000) {
} else { lastHeartbeat = millis();
DEBUG_MSG("Store & Forward Module - Disabled (is_router = false)\n"); DEBUG_MSG("Sending heartbeat\n");
StoreAndForward sf;
sf.rr = StoreAndForward_RequestResponse_ROUTER_HEARTBEAT;
sf.has_heartbeat = true;
sf.heartbeat.period = 300;
sf.heartbeat.secondary = 0; // TODO we always have one primary router for now
return (INT32_MAX); MeshPacket *p = allocDataProtobuf(sf);
p->to = NODENUM_BROADCAST;
p->decoded.want_response = false;
p->priority = MeshPacket_Priority_MIN;
service.sendToMesh(p);
} }
return (this->packetTimeMax);
} else {
DEBUG_MSG("Store & Forward Module - Disabled\n");
return (INT32_MAX);
} }
#endif #endif
return (INT32_MAX); return (INT32_MAX);
} }
@@ -76,12 +74,7 @@ void StoreForwardModule::populatePSRAM()
https://learn.upesy.com/en/programmation/psram.html#psram-tab https://learn.upesy.com/en/programmation/psram.html#psram-tab
*/ */
DEBUG_MSG("Before PSRAM initilization:\n"); DEBUG_MSG("Before PSRAM initilization: heap %d/%d PSRAM %d/%d\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreePsram(), ESP.getPsramSize());
DEBUG_MSG(" Total heap: %d\n", ESP.getHeapSize());
DEBUG_MSG(" Free heap: %d\n", ESP.getFreeHeap());
DEBUG_MSG(" Total PSRAM: %d\n", ESP.getPsramSize());
DEBUG_MSG(" Free PSRAM: %d\n", ESP.getFreePsram());
this->packetHistoryTXQueue = this->packetHistoryTXQueue =
static_cast<PacketHistoryStruct *>(ps_calloc(this->historyReturnMax, sizeof(PacketHistoryStruct))); static_cast<PacketHistoryStruct *>(ps_calloc(this->historyReturnMax, sizeof(PacketHistoryStruct)));
@@ -93,19 +86,12 @@ void StoreForwardModule::populatePSRAM()
this->packetHistory = static_cast<PacketHistoryStruct *>(ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct))); this->packetHistory = static_cast<PacketHistoryStruct *>(ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct)));
DEBUG_MSG("After PSRAM initilization:\n"); DEBUG_MSG("After PSRAM initilization: heap %d/%d PSRAM %d/%d\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreePsram(), ESP.getPsramSize());
DEBUG_MSG("numberOfPackets for packetHistory - %u\n", numberOfPackets);
DEBUG_MSG(" Total heap: %d\n", ESP.getHeapSize());
DEBUG_MSG(" Free heap: %d\n", ESP.getFreeHeap());
DEBUG_MSG(" Total PSRAM: %d\n", ESP.getPsramSize());
DEBUG_MSG(" Free PSRAM: %d\n", ESP.getFreePsram());
DEBUG_MSG("Store and Forward Stats:\n");
DEBUG_MSG(" numberOfPackets for packetHistory - %u\n", numberOfPackets);
} }
void StoreForwardModule::historyReport() void StoreForwardModule::historyReport()
{ {
DEBUG_MSG("Iterating through the message history...\n");
DEBUG_MSG("Message history contains %u records\n", this->packetHistoryCurrent); DEBUG_MSG("Message history contains %u records\n", this->packetHistoryCurrent);
} }
@@ -246,8 +232,8 @@ ProcessMessage StoreForwardModule::handleReceived(const MeshPacket &mp)
DEBUG_MSG("--- S&F Received something\n"); DEBUG_MSG("--- S&F Received something\n");
// The router node should not be sending messages as a client. // The router node should not be sending messages as a client. Unless he is a ROUTER_CLIENT
if (getFrom(&mp) != nodeDB.getNodeNum()) { if ((getFrom(&mp) != nodeDB.getNodeNum()) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) {
if (mp.decoded.portnum == PortNum_TEXT_MESSAGE_APP) { if (mp.decoded.portnum == PortNum_TEXT_MESSAGE_APP) {
DEBUG_MSG("Packet came from - PortNum_TEXT_MESSAGE_APP\n"); DEBUG_MSG("Packet came from - PortNum_TEXT_MESSAGE_APP\n");
@@ -264,6 +250,7 @@ ProcessMessage StoreForwardModule::handleReceived(const MeshPacket &mp)
} else { } else {
storeForwardModule->historySend(1000 * 60, getFrom(&mp)); storeForwardModule->historySend(1000 * 60, getFrom(&mp));
} }
} else if ((p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') && (p.payload.bytes[2] == 'm') && } else if ((p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') && (p.payload.bytes[2] == 'm') &&
(p.payload.bytes[3] == 0x00)) { (p.payload.bytes[3] == 0x00)) {
strlcpy(this->routerMessage, strlcpy(this->routerMessage,
@@ -278,14 +265,12 @@ ProcessMessage StoreForwardModule::handleReceived(const MeshPacket &mp)
} }
} else if (mp.decoded.portnum == PortNum_STORE_FORWARD_APP) { } else if (mp.decoded.portnum == PortNum_STORE_FORWARD_APP) {
DEBUG_MSG("Packet came from an PortNum_STORE_FORWARD_APP port %u\n", mp.decoded.portnum);
} else { } else {
DEBUG_MSG("Packet came from an unknown port %u\n", mp.decoded.portnum); DEBUG_MSG("Packet came from an unknown port %u\n", mp.decoded.portnum);
} }
} }
} else {
DEBUG_MSG("Store & Forward Module - Disabled\n");
} }
#endif #endif
@@ -293,92 +278,107 @@ ProcessMessage StoreForwardModule::handleReceived(const MeshPacket &mp)
return ProcessMessage::CONTINUE; // Let others look at this message also if they want return ProcessMessage::CONTINUE; // Let others look at this message also if they want
} }
ProcessMessage StoreForwardModule::handleReceivedProtobuf(const MeshPacket &mp, StoreAndForward *p) bool StoreForwardModule::handleReceivedProtobuf(const MeshPacket &mp, StoreAndForward *p)
{ {
if (!moduleConfig.store_forward.enabled) { if (!moduleConfig.store_forward.enabled) {
// If this module is not enabled in any capacity, don't handle the packet, and allow other modules to consume // If this module is not enabled in any capacity, don't handle the packet, and allow other modules to consume
return ProcessMessage::CONTINUE; return false;
} }
if (mp.decoded.portnum == PortNum_TEXT_MESSAGE_APP) { if (mp.decoded.portnum != PortNum_STORE_FORWARD_APP) {
DEBUG_MSG("Packet came from an PortNum_TEXT_MESSAGE_APP port %u\n", mp.decoded.portnum); DEBUG_MSG("Packet came from port %u\n", mp.decoded.portnum);
return ProcessMessage::CONTINUE; return false;
} else if (mp.decoded.portnum == PortNum_STORE_FORWARD_APP) {
DEBUG_MSG("Packet came from an PortNum_STORE_FORWARD_APP port %u\n", mp.decoded.portnum);
} else { } else {
DEBUG_MSG("Packet came from an UNKNOWN port %u\n", mp.decoded.portnum); DEBUG_MSG("Packet came from PortNum_STORE_FORWARD_APP port %u\n", mp.decoded.portnum);
return ProcessMessage::CONTINUE;
}
switch (p->rr) { switch (p->rr) {
case StoreAndForward_RequestResponse_CLIENT_ERROR: case StoreAndForward_RequestResponse_CLIENT_ERROR:
// Do nothing if(is_server) {
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_ERROR\n"); // Do nothing
break; DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_ERROR\n");
}
break;
case StoreAndForward_RequestResponse_CLIENT_HISTORY: case StoreAndForward_RequestResponse_CLIENT_HISTORY:
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_HISTORY\n"); if(is_server) {
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_HISTORY\n");
// Send the last 60 minutes of messages.
if (this->busy) {
strcpy(this->routerMessage, "** S&F - Busy. Try again shortly.");
storeForwardModule->sendMessage(getFrom(&mp), this->routerMessage);
} else {
storeForwardModule->historySend(1000 * 60, getFrom(&mp));
}
}
break;
// Send the last 60 minutes of messages. case StoreAndForward_RequestResponse_CLIENT_PING:
if (this->busy) { if(is_server) {
strcpy(this->routerMessage, "** S&F - Busy. Try again shortly."); // Do nothing
storeForwardModule->sendMessage(getFrom(&mp), this->routerMessage); DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_PING\n");
} else { }
storeForwardModule->historySend(1000 * 60, getFrom(&mp)); break;
case StoreAndForward_RequestResponse_CLIENT_PONG:
if(is_server) {
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_PONG\n");
}
break;
case StoreAndForward_RequestResponse_CLIENT_STATS:
if(is_server) {
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_STATS\n");
}
break;
case StoreAndForward_RequestResponse_ROUTER_BUSY:
if(is_client) {
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_BUSY\n");
}
break;
case StoreAndForward_RequestResponse_ROUTER_ERROR:
if(is_client) {
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_ERROR\n");
}
break;
case StoreAndForward_RequestResponse_ROUTER_HEARTBEAT:
if(is_client) {
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_HEARTBEAT\n");
}
break;
case StoreAndForward_RequestResponse_ROUTER_PING:
if(is_client) {
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_PING\n");
}
break;
case StoreAndForward_RequestResponse_ROUTER_PONG:
if(is_client) {
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_PONG\n");
}
break;
default:
assert(0); // unexpected state - FIXME, make an error code and reboot
} }
break;
case StoreAndForward_RequestResponse_CLIENT_PING:
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_PING\n");
break;
case StoreAndForward_RequestResponse_CLIENT_PONG:
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_PONG\n");
break;
case StoreAndForward_RequestResponse_CLIENT_STATS:
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_STATS\n");
break;
case StoreAndForward_RequestResponse_ROUTER_BUSY:
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_BUSY\n");
break;
case StoreAndForward_RequestResponse_ROUTER_ERROR:
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_ERROR\n");
break;
case StoreAndForward_RequestResponse_ROUTER_HEARTBEAT:
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_HEARTBEAT\n");
break;
case StoreAndForward_RequestResponse_ROUTER_PING:
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_PING\n");
break;
case StoreAndForward_RequestResponse_ROUTER_PONG:
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_PONG\n");
break;
default:
assert(0); // unexpected state - FIXME, make an error code and reboot
} }
return ProcessMessage::STOP; // There's no need for others to look at this message. return true; // There's no need for others to look at this message.
} }
StoreForwardModule::StoreForwardModule() StoreForwardModule::StoreForwardModule()
: SinglePortModule("StoreForwardModule", PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("StoreForwardModule") : concurrency::OSThread("StoreForwardModule"), ProtobufModule("StoreForward", PortNum_STORE_FORWARD_APP, &StoreAndForward_msg)
{ {
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
@@ -397,9 +397,9 @@ StoreForwardModule::StoreForwardModule()
if (moduleConfig.store_forward.enabled) { if (moduleConfig.store_forward.enabled) {
// Router // Router
if (config.device.role == Config_DeviceConfig_Role_ROUTER) { if ((config.device.role == Config_DeviceConfig_Role_ROUTER) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) {
DEBUG_MSG("Initializing Store & Forward Module - Enabled as Router\n"); DEBUG_MSG("Initializing Store & Forward Module in Router mode\n");
if (ESP.getPsramSize()) { if (ESP.getPsramSize() > 0) {
if (ESP.getFreePsram() >= 1024 * 1024) { if (ESP.getFreePsram() >= 1024 * 1024) {
// Do the startup here // Do the startup here
@@ -416,26 +416,27 @@ StoreForwardModule::StoreForwardModule()
if (moduleConfig.store_forward.records) if (moduleConfig.store_forward.records)
this->records = moduleConfig.store_forward.records; this->records = moduleConfig.store_forward.records;
// Maximum number of records to store in memory // send heartbeat advertising?
if (moduleConfig.store_forward.heartbeat) if (moduleConfig.store_forward.heartbeat)
this->heartbeat = moduleConfig.store_forward.heartbeat; this->heartbeat = moduleConfig.store_forward.heartbeat;
// Popupate PSRAM with our data structures. // Popupate PSRAM with our data structures.
this->populatePSRAM(); this->populatePSRAM();
is_server = true;
} else { } else {
DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n"); DEBUG_MSG("Device has less than 1M of PSRAM free.\n");
DEBUG_MSG("Store & Forward Module - Aborting Startup.\n"); DEBUG_MSG("Store & Forward Module - disabling server.\n");
} }
} else { } else {
DEBUG_MSG("Device doesn't have PSRAM.\n"); DEBUG_MSG("Device doesn't have PSRAM.\n");
DEBUG_MSG("Store & Forward Module - Aborting Startup.\n"); DEBUG_MSG("Store & Forward Module - disabling server.\n");
} }
// Client // Client
} else { }
DEBUG_MSG("Initializing Store & Forward Module - Enabled as Client\n"); if ((config.device.role == Config_DeviceConfig_Role_CLIENT) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) {
is_client = true;
DEBUG_MSG("Initializing Store & Forward Module in Client mode\n");
} }
} }
#endif #endif
+9 -5
View File
@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "SinglePortModule.h" #include "ProtobufModule.h"
#include "concurrency/OSThread.h" #include "concurrency/OSThread.h"
#include "mesh/generated/storeforward.pb.h" #include "mesh/generated/storeforward.pb.h"
@@ -18,9 +18,8 @@ struct PacketHistoryStruct {
pb_size_t payload_size; pb_size_t payload_size;
}; };
class StoreForwardModule : public SinglePortModule, private concurrency::OSThread class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<StoreAndForward>
{ {
// bool firstTime = 1;
bool busy = 0; bool busy = 0;
uint32_t busyTo = 0; uint32_t busyTo = 0;
char routerMessage[Constants_DATA_PAYLOAD_LEN] = {0}; char routerMessage[Constants_DATA_PAYLOAD_LEN] = {0};
@@ -34,7 +33,12 @@ class StoreForwardModule : public SinglePortModule, private concurrency::OSThrea
uint32_t packetHistoryTXQueue_size = 0; uint32_t packetHistoryTXQueue_size = 0;
uint32_t packetHistoryTXQueue_index = 0; uint32_t packetHistoryTXQueue_index = 0;
uint32_t packetTimeMax = 2000; uint32_t packetTimeMax = 5000;
unsigned long lastHeartbeat = 0;
bool is_client = false;
bool is_server = false;
public: public:
StoreForwardModule(); StoreForwardModule();
@@ -78,7 +82,7 @@ class StoreForwardModule : public SinglePortModule, private concurrency::OSThrea
it it
*/ */
virtual ProcessMessage handleReceived(const MeshPacket &mp) override; virtual ProcessMessage handleReceived(const MeshPacket &mp) override;
virtual ProcessMessage handleReceivedProtobuf(const MeshPacket &mp, StoreAndForward *p); virtual bool handleReceivedProtobuf(const MeshPacket &mp, StoreAndForward *p);
}; };
+12 -5
View File
@@ -3,7 +3,9 @@
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
#include "main.h" #include "main.h"
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
#include "nimble/NimbleBluetooth.h" #include "nimble/NimbleBluetooth.h"
#endif
#include "BleOta.h" #include "BleOta.h"
#include "mesh/http/WiFiAPClient.h" #include "mesh/http/WiFiAPClient.h"
@@ -16,13 +18,9 @@
#include <nvs_flash.h> #include <nvs_flash.h>
#include "soc/rtc.h" #include "soc/rtc.h"
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
NimbleBluetooth *nimbleBluetooth; NimbleBluetooth *nimbleBluetooth;
void getMacAddr(uint8_t *dmac)
{
assert(esp_efuse_mac_get_default(dmac) == ESP_OK);
}
void setBluetoothEnable(bool on) { void setBluetoothEnable(bool on) {
if (!isWifiAvailable() && config.bluetooth.enabled == true) { if (!isWifiAvailable() && config.bluetooth.enabled == true) {
@@ -36,6 +34,15 @@ void setBluetoothEnable(bool on) {
} }
} }
} }
#else
void setBluetoothEnable(bool on) { }
void updateBatteryLevel(uint8_t level) { }
#endif
void getMacAddr(uint8_t *dmac)
{
assert(esp_efuse_mac_get_default(dmac) == ESP_OK);
}
#ifdef HAS_32768HZ #ifdef HAS_32768HZ
#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk) #define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)
-1
View File
@@ -4,7 +4,6 @@
#include "MeshPacketQueue.h" #include "MeshPacketQueue.h"
#include "wifi/WiFiServerAPI.h" #include "wifi/WiFiServerAPI.h"
#define RADIOLIB_EXCLUDE_HTTP
#include <RadioLib.h> #include <RadioLib.h>
class SimRadio : public RadioInterface class SimRadio : public RadioInterface
+3
View File
@@ -40,6 +40,9 @@ class Power : private concurrency::OSThread
private: private:
uint8_t low_voltage_counter; uint8_t low_voltage_counter;
#ifdef DEBUG_HEAP
uint32_t lastheap;
#endif
}; };
extern Power *power; extern Power *power;
+35 -1
View File
@@ -29,7 +29,9 @@ Observable<void *> preflightSleep;
/// Called to tell observers we are now entering sleep and you should prepare. Must return 0 /// Called to tell observers we are now entering sleep and you should prepare. Must return 0
/// notifySleep will be called for light or deep sleep, notifyDeepSleep is only called for deep sleep /// notifySleep will be called for light or deep sleep, notifyDeepSleep is only called for deep sleep
/// notifyGPSSleep will be called when config.position.gps_enabled is set to 0 or from buttonthread when GPS_POWER_TOGGLE is enabled.
Observable<void *> notifySleep, notifyDeepSleep; Observable<void *> notifySleep, notifyDeepSleep;
Observable<void *> notifyGPSSleep;
// deep sleep support // deep sleep support
RTC_DATA_ATTR int bootCount = 0; RTC_DATA_ATTR int bootCount = 0;
@@ -167,6 +169,36 @@ static void waitEnterSleep()
notifySleep.notifyObservers(NULL); notifySleep.notifyObservers(NULL);
} }
void doGPSpowersave(bool on)
{
#ifdef HAS_PMU
if (on)
{
DEBUG_MSG("Turning GPS back on\n");
gps->forceWake(1);
setGPSPower(1);
}
else
{
DEBUG_MSG("Turning off GPS chip\n");
notifyGPSSleep.notifyObservers(NULL);
setGPSPower(0);
}
#endif
#ifdef PIN_GPS_WAKE
if (on)
{
DEBUG_MSG("Waking GPS");
gps->forceWake(1);
}
else
{
DEBUG_MSG("GPS entering sleep");
notifyGPSSleep.notifyObservers(NULL);
}
#endif
}
void doDeepSleep(uint64_t msecToWake) void doDeepSleep(uint64_t msecToWake)
{ {
DEBUG_MSG("Entering deep sleep for %lu seconds\n", msecToWake / 1000); DEBUG_MSG("Entering deep sleep for %lu seconds\n", msecToWake / 1000);
@@ -237,7 +269,7 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
// We want RTC peripherals to stay on // We want RTC peripherals to stay on
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
#ifdef BUTTON_NEED_PULLUP #if defined(BUTTON_PIN) && defined(BUTTON_NEED_PULLUP)
gpio_pullup_en((gpio_num_t)BUTTON_PIN); gpio_pullup_en((gpio_num_t)BUTTON_PIN);
#endif #endif
@@ -300,6 +332,8 @@ void enableModemSleep()
#if CONFIG_IDF_TARGET_ESP32S3 #if CONFIG_IDF_TARGET_ESP32S3
esp32_config.max_freq_mhz = CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ; esp32_config.max_freq_mhz = CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ;
#elif CONFIG_IDF_TARGET_ESP32S2
esp32_config.max_freq_mhz = CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ;
#else #else
esp32_config.max_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; esp32_config.max_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
#endif #endif
+3 -1
View File
@@ -13,7 +13,7 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t msecToWake);
extern esp_sleep_source_t wakeCause; extern esp_sleep_source_t wakeCause;
#endif #endif
void setGPSPower(bool on); void setGPSPower(bool on);
void doGPSpowersave(bool on);
// Perform power on init that we do on each wake from deep sleep // Perform power on init that we do on each wake from deep sleep
void initDeepSleep(); void initDeepSleep();
@@ -37,4 +37,6 @@ extern Observable<void *> notifySleep;
/// Called to tell observers we are now entering (deep) sleep and you should prepare. Must return 0 /// Called to tell observers we are now entering (deep) sleep and you should prepare. Must return 0
extern Observable<void *> notifyDeepSleep; extern Observable<void *> notifyDeepSleep;
/// Called to tell GPS thread to enter deep sleep independently of LoRa/MCU sleep, prior to full poweroff. Must return 0
extern Observable<void *> notifyGPSSleep;
void enableModemSleep(); void enableModemSleep();
+1 -1
View File
@@ -1,6 +1,6 @@
[env:heltec-v3] [env:heltec-v3]
platform = https://github.com/Baptou88/platform-espressif32.git platform = https://github.com/Baptou88/platform-espressif32.git
extends = esp32_base extends = esp32s3_base
board = heltec_wifi_lora_32_V3 board = heltec_wifi_lora_32_V3
# Temporary until espressif creates a release with this new target # Temporary until espressif creates a release with this new target
platform_packages = platform_packages =
+1 -1
View File
@@ -1,6 +1,6 @@
[env:heltec-wsl-v3] [env:heltec-wsl-v3]
platform = https://github.com/Baptou88/platform-espressif32.git platform = https://github.com/Baptou88/platform-espressif32.git
extends = esp32_base extends = esp32s3_base
board = heltec_wifi_lora_32_V3 board = heltec_wifi_lora_32_V3
# Temporary until espressif creates a release with this new target # Temporary until espressif creates a release with this new target
platform_packages = platform_packages =
+1
View File
@@ -169,6 +169,7 @@ static const uint8_t SCK = PIN_SPI_SCK;
IO4 <-> P0.04 (Arduino GPIO number 4) IO4 <-> P0.04 (Arduino GPIO number 4)
IO5 <-> P0.09 (Arduino GPIO number 9) IO5 <-> P0.09 (Arduino GPIO number 9)
IO6 <-> P0.10 (Arduino GPIO number 10) IO6 <-> P0.10 (Arduino GPIO number 10)
IO7 <-> P0.28 (Arduino GPIO number 28)
SW1 <-> P0.01 (Arduino GPIO number 1) SW1 <-> P0.01 (Arduino GPIO number 1)
A0 <-> P0.04/AIN2 (Arduino Analog A2 A0 <-> P0.04/AIN2 (Arduino Analog A2
A1 <-> P0.31/AIN7 (Arduino Analog A7 A1 <-> P0.31/AIN7 (Arduino Analog A7
+1
View File
@@ -169,6 +169,7 @@ static const uint8_t SCK = PIN_SPI_SCK;
IO4 <-> P0.04 (Arduino GPIO number 4) IO4 <-> P0.04 (Arduino GPIO number 4)
IO5 <-> P0.09 (Arduino GPIO number 9) IO5 <-> P0.09 (Arduino GPIO number 9)
IO6 <-> P0.10 (Arduino GPIO number 10) IO6 <-> P0.10 (Arduino GPIO number 10)
IO7 <-> P0.28 (Arduino GPIO number 28)
SW1 <-> P0.01 (Arduino GPIO number 1) SW1 <-> P0.01 (Arduino GPIO number 1)
A0 <-> P0.04/AIN2 (Arduino Analog A2 A0 <-> P0.04/AIN2 (Arduino Analog A2
A1 <-> P0.31/AIN7 (Arduino Analog A7 A1 <-> P0.31/AIN7 (Arduino Analog A7
+1
View File
@@ -6,4 +6,5 @@ lib_deps =
${esp32_base.lib_deps} ${esp32_base.lib_deps}
build_flags = build_flags =
${esp32_base.build_flags} -D TBEAM_V10 -I variants/tbeam ${esp32_base.build_flags} -D TBEAM_V10 -I variants/tbeam
-DGPS_POWER_TOGGLE ; comment this line to disable double press function on the user button to turn off gps entirely.
upload_speed = 921600 upload_speed = 921600
-5
View File
@@ -3,8 +3,6 @@
#define GPS_RX_PIN 15 // per @der_bear on the forum, 36 is incorrect for this board type and 15 is a better pick #define GPS_RX_PIN 15 // per @der_bear on the forum, 36 is incorrect for this board type and 15 is a better pick
#define GPS_TX_PIN 13 #define GPS_TX_PIN 13
#define EXT_NOTIFY_OUT 2 // Default pin to use for Ext Notify Module.
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage #define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
// ratio of voltage divider = 2.0 (R42=100k, R43=100k) // ratio of voltage divider = 2.0 (R42=100k, R43=100k)
#define ADC_MULTIPLIER 2.11 // 2.0 + 10% for correction of display undervoltage. #define ADC_MULTIPLIER 2.11 // 2.0 + 10% for correction of display undervoltage.
@@ -12,9 +10,6 @@
#define I2C_SDA 21 // I2C pins for this board #define I2C_SDA 21 // I2C pins for this board
#define I2C_SCL 22 #define I2C_SCL 22
// #define RESET_OLED 16 // If defined, this pin will be used to reset the display controller. Crashes on newer ESP-IDF and not needed per schematic
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED #define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN 12 // If defined, this will be used for user button presses, #define BUTTON_PIN 12 // If defined, this will be used for user button presses,
+2 -10
View File
@@ -1,9 +1,5 @@
#undef GPS_RX_PIN #undef GPS_RX_PIN
#undef GPS_TX_PIN #undef GPS_TX_PIN
#define GPS_RX_PIN 15 // per @der_bear on the forum, 36 is incorrect for this board type and 15 is a better pick
#define GPS_TX_PIN 13
#define EXT_NOTIFY_OUT 2 // Default pin to use for Ext Notify Module.
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage #define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
// ratio of voltage divider = 2.0 (R42=100k, R43=100k) // ratio of voltage divider = 2.0 (R42=100k, R43=100k)
@@ -20,11 +16,7 @@
#define USE_SX1280 #define USE_SX1280
#define LORA_RESET 23 #define LORA_RESET 23
#define SX128X_CS 18 // FIXME - we really should define LORA_CS instead #define SX128X_CS 18
#define SX128X_DIO1 26 #define SX128X_DIO1 26
#define SX128X_DIO2 33
#define SX128X_BUSY 32 #define SX128X_BUSY 32
#define SX128X_RESET LORA_RESET #define SX128X_RESET LORA_RESET
#define SX128X_E22 // Not really an E22 but TTGO seems to be trying to clone that
// Internally the TTGO module hooks the SX1280-DIO2 in to control the TX/RX switch (which is the default for the sx1280interface
// code)