mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-17 08:12:32 +00:00
Merge branch 'develop' into gps-toggle-final
This commit is contained in:
47
arch/esp32/esp32s2.ini
Normal file
47
arch/esp32/esp32s2.ini
Normal 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
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"build": {
|
"build": {
|
||||||
"arduino":{
|
"arduino": {
|
||||||
"ldscript": "esp32s3_out.ld"
|
"ldscript": "esp32s3_out.ld"
|
||||||
},
|
},
|
||||||
"core": "esp32",
|
"core": "esp32",
|
||||||
@@ -8,9 +8,7 @@
|
|||||||
"-DBOARD_HAS_PSRAM",
|
"-DBOARD_HAS_PSRAM",
|
||||||
"-DLILYGO_TBEAM_S3_CORE",
|
"-DLILYGO_TBEAM_S3_CORE",
|
||||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||||
"-DARDUINO_USB_DFU_ON_BOOT=1",
|
"-DARDUINO_USB_MODE=0",
|
||||||
"-DARDUINO_USB_MSC_ON_BOOT=1",
|
|
||||||
"-DARDUINO_USB_MODE=1",
|
|
||||||
"-DARDUINO_RUNNING_CORE=1",
|
"-DARDUINO_RUNNING_CORE=1",
|
||||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||||
],
|
],
|
||||||
|
|||||||
Submodule protobufs updated: 0a59599589...737d1fc01b
@@ -4,6 +4,7 @@
|
|||||||
#include "concurrency/OSThread.h"
|
#include "concurrency/OSThread.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "graphics/Screen.h"
|
#include "graphics/Screen.h"
|
||||||
|
#include "modules/ExternalNotificationModule.h"
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
#include <OneButton.h>
|
#include <OneButton.h>
|
||||||
|
|
||||||
@@ -115,6 +116,10 @@ class ButtonThread : public concurrency::OSThread
|
|||||||
{
|
{
|
||||||
// DEBUG_MSG("press!\n");
|
// DEBUG_MSG("press!\n");
|
||||||
#ifdef BUTTON_PIN
|
#ifdef BUTTON_PIN
|
||||||
|
// If a nag notification is running, stop it
|
||||||
|
if (externalNotificationModule->nagCycleCutoff != UINT32_MAX) {
|
||||||
|
externalNotificationModule->nagCycleCutoff = 0;
|
||||||
|
}
|
||||||
if ((BUTTON_PIN != moduleConfig.canned_message.inputbroker_pin_press) ||
|
if ((BUTTON_PIN != moduleConfig.canned_message.inputbroker_pin_press) ||
|
||||||
!moduleConfig.canned_message.enabled) {
|
!moduleConfig.canned_message.enabled) {
|
||||||
powerFSM.trigger(EVENT_PRESS);
|
powerFSM.trigger(EVENT_PRESS);
|
||||||
|
|||||||
@@ -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()
|
||||||
@@ -284,7 +287,10 @@ void Power::readPowerStatus()
|
|||||||
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
|
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
|
||||||
newStatus.notifyObservers(&powerStatus2);
|
newStatus.notifyObservers(&powerStatus2);
|
||||||
#ifdef DEBUG_HEAP
|
#ifdef DEBUG_HEAP
|
||||||
DEBUG_MSG("Heap status: %d/%d bytes free, running %d threads\n", ESP.getFreeHeap(), ESP.getHeapSize(), concurrency::mainController.size(false));
|
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
|
#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
|
||||||
@@ -458,6 +464,9 @@ bool Power::axpChipInit()
|
|||||||
// Set constant current charging current
|
// Set constant current charging current
|
||||||
PMU->setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_450MA);
|
PMU->setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_450MA);
|
||||||
|
|
||||||
|
//Set up the charging voltage
|
||||||
|
PMU->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
|
||||||
|
|
||||||
} else if (PMU->getChipModel() == XPOWERS_AXP2101) {
|
} else if (PMU->getChipModel() == XPOWERS_AXP2101) {
|
||||||
|
|
||||||
// t-beam s3 core
|
// t-beam s3 core
|
||||||
@@ -510,6 +519,8 @@ bool Power::axpChipInit()
|
|||||||
//Set the constant current charging current of AXP2101, temporarily use 500mA by default
|
//Set the constant current charging current of AXP2101, temporarily use 500mA by default
|
||||||
PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
|
PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
|
||||||
|
|
||||||
|
//Set up the charging voltage
|
||||||
|
PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -563,9 +574,6 @@ bool Power::axpChipInit()
|
|||||||
DEBUG_MSG("=======================================================================\n");
|
DEBUG_MSG("=======================================================================\n");
|
||||||
|
|
||||||
|
|
||||||
//Set up the charging voltage, AXP2101/AXP192 4.2V gear is the same
|
|
||||||
// XPOWERS_AXP192_CHG_VOL_4V2 = XPOWERS_AXP2101_CHG_VOL_4V2
|
|
||||||
PMU->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
|
|
||||||
|
|
||||||
// Set PMU shutdown voltage at 2.6V to maximize battery utilization
|
// Set PMU shutdown voltage at 2.6V to maximize battery utilization
|
||||||
PMU->setSysPowerDownVoltage(2600);
|
PMU->setSysPowerDownVoltage(2600);
|
||||||
|
|||||||
@@ -329,11 +329,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 +361,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 +373,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 +393,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;
|
||||||
@@ -465,6 +467,7 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *no
|
|||||||
sprintf(usersString, "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
|
sprintf(usersString, "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
|
||||||
display->drawFastImage(x, y, 8, 8, imgUser);
|
display->drawFastImage(x, y, 8, 8, imgUser);
|
||||||
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 +476,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];
|
||||||
@@ -685,16 +691,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -774,6 +780,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];
|
||||||
@@ -804,7 +812,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)) {
|
||||||
@@ -847,6 +855,7 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -1373,6 +1382,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);
|
||||||
@@ -1382,22 +1394,24 @@ 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
|
||||||
if (!config.position.gps_enabled){
|
if (!config.position.gps_enabled){
|
||||||
int16_t yPos = y + 2;
|
int16_t yPos = y + 2;
|
||||||
#ifdef GPS_POWER_TOGGLE
|
#ifdef GPS_POWER_TOGGLE
|
||||||
yPos = (y + 10 + FONT_HEIGHT_SMALL);
|
yPos = (y + 10 + FONT_HEIGHT_SMALL);
|
||||||
#endif
|
#endif
|
||||||
drawGPSpowerstat(display, x, yPos, gpsStatus);
|
drawGPSpowerstat(display, x, yPos, gpsStatus);
|
||||||
} else {
|
} else {
|
||||||
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
|
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
|
||||||
@@ -1428,15 +1442,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;
|
||||||
@@ -1545,6 +1568,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;
|
||||||
@@ -1555,9 +1581,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 = "";
|
||||||
@@ -1590,6 +1618,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();
|
||||||
@@ -1602,6 +1631,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)
|
||||||
|
|||||||
@@ -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() {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,33 +15,3 @@ const uint8_t imgPositionSolid[] PROGMEM = { 0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF
|
|||||||
const uint8_t imgInfo[] PROGMEM = { 0xFF, 0x81, 0x81, 0xB5, 0xB5, 0x81, 0x81, 0xFF };
|
const uint8_t imgInfo[] PROGMEM = { 0xFF, 0x81, 0x81, 0xB5, 0xB5, 0x81, 0x81, 0xFF };
|
||||||
|
|
||||||
#include "img/icon.xbm"
|
#include "img/icon.xbm"
|
||||||
|
|
||||||
// We now programmatically draw our compass
|
|
||||||
#if 0
|
|
||||||
const
|
|
||||||
#include "img/compass.xbm"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
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
|
|
||||||
@@ -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,
|
|
||||||
};
|
|
||||||
@@ -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, };
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -215,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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "SPILock.h"
|
#include "SPILock.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "main.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include <pb_decode.h>
|
#include <pb_decode.h>
|
||||||
@@ -87,10 +88,8 @@ bool RadioLibInterface::canSendImmediately()
|
|||||||
if (busyTx && (millis() - lastTxStart > 60000)) {
|
if (busyTx && (millis() - lastTxStart > 60000)) {
|
||||||
DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n");
|
DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n");
|
||||||
RECORD_CRITICALERROR(CriticalErrorCode_TRANSMIT_FAILED);
|
RECORD_CRITICALERROR(CriticalErrorCode_TRANSMIT_FAILED);
|
||||||
#ifdef ARCH_ESP32
|
// reboot in 5 seconds when this condition occurs.
|
||||||
if (busyTx && (millis() - lastTxStart > 65000)) // After 5s more, reboot
|
rebootAtMsec = lastTxStart + 65000;
|
||||||
ESP.restart();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (busyRx)
|
if (busyRx)
|
||||||
DEBUG_MSG("Can not send yet, busyRx\n");
|
DEBUG_MSG("Can not send yet, busyRx\n");
|
||||||
@@ -386,6 +385,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
|||||||
|
|
||||||
int res = iface->startTransmit(radiobuf, numbytes);
|
int res = iface->startTransmit(radiobuf, numbytes);
|
||||||
if (res != RADIOLIB_ERR_NONE) {
|
if (res != RADIOLIB_ERR_NONE) {
|
||||||
|
DEBUG_MSG("startTransmit failed, error=%d\n", res);
|
||||||
RECORD_CRITICALERROR(CriticalErrorCode_RADIO_SPI_BUG);
|
RECORD_CRITICALERROR(CriticalErrorCode_RADIO_SPI_BUG);
|
||||||
|
|
||||||
// This send failed, but make sure to 'complete' it properly
|
// This send failed, but make sure to 'complete' it properly
|
||||||
|
|||||||
@@ -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 358
|
#define LocalModuleConfig_size 376
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|||||||
@@ -93,6 +93,13 @@ 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 {
|
||||||
@@ -187,7 +194,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}
|
#define ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 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}
|
||||||
@@ -196,7 +203,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}
|
#define ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 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}
|
||||||
@@ -228,6 +235,13 @@ 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
|
||||||
@@ -323,7 +337,14 @@ 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
|
||||||
|
|
||||||
@@ -391,7 +412,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 22
|
#define ModuleConfig_ExternalNotificationConfig_size 40
|
||||||
#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
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ typedef enum _PortNum {
|
|||||||
Maintained by GitHub user GUVWAF.
|
Maintained by GitHub user GUVWAF.
|
||||||
Project files at https://github.com/GUVWAF/Meshtasticator */
|
Project files at https://github.com/GUVWAF/Meshtasticator */
|
||||||
PortNum_SIMULATOR_APP = 69,
|
PortNum_SIMULATOR_APP = 69,
|
||||||
|
/* Provides a traceroute functionality to show the route a packet towards
|
||||||
|
a certain destination would take on the mesh. */
|
||||||
|
PortNum_TRACEROUTE_APP = 70,
|
||||||
/* Private applications should use portnums >= 256.
|
/* Private applications should use portnums >= 256.
|
||||||
To simplify initial development and testing you can use "PRIVATE_APP"
|
To simplify initial development and testing you can use "PRIVATE_APP"
|
||||||
in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) */
|
in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) */
|
||||||
|
|||||||
@@ -69,10 +69,10 @@ typedef struct _EnvironmentMetrics {
|
|||||||
|
|
||||||
/* Types of Measurements the telemetry module is equipped to handle */
|
/* Types of Measurements the telemetry module is equipped to handle */
|
||||||
typedef struct _Telemetry {
|
typedef struct _Telemetry {
|
||||||
/* This is usually not sent over the mesh (to save space), but it is sent
|
/* This is usually not sent over the mesh (to save space), but it is sent
|
||||||
from the phone so that the local device can set its RTC If it is sent over
|
from the phone so that the local device can set its RTC If it is sent over
|
||||||
the mesh (because there are devices on the mesh without GPS), it will only
|
the mesh (because there are devices on the mesh without GPS), it will only
|
||||||
be sent by devices which has a hardware GPS clock (IE Mobile Phone).
|
be sent by devices which has a hardware GPS clock (IE Mobile Phone).
|
||||||
seconds since 1970 */
|
seconds since 1970 */
|
||||||
uint32_t time;
|
uint32_t time;
|
||||||
pb_size_t which_variant;
|
pb_size_t which_variant;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -11,41 +11,9 @@
|
|||||||
#define PIN_BUZZER false
|
#define PIN_BUZZER false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//#include <assert.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Documentation:
|
Documentation:
|
||||||
https://github.com/meshtastic/firmware/blob/master/docs/software/modules/ExternalNotificationModule.md
|
https://meshtastic.org/docs/settings/moduleconfig/external-notification
|
||||||
|
|
||||||
This module supports:
|
|
||||||
https://github.com/meshtastic/firmware/issues/654
|
|
||||||
|
|
||||||
|
|
||||||
Quick reference:
|
|
||||||
|
|
||||||
moduleConfig.external_notification.enabled
|
|
||||||
0 = Disabled (Default)
|
|
||||||
1 = Enabled
|
|
||||||
|
|
||||||
moduleConfig.external_notification.active
|
|
||||||
0 = Active Low (Default)
|
|
||||||
1 = Active High
|
|
||||||
|
|
||||||
moduleConfig.external_notification.alert_message
|
|
||||||
0 = Disabled (Default)
|
|
||||||
1 = Alert when a text message comes
|
|
||||||
|
|
||||||
moduleConfig.external_notification.alert_bell
|
|
||||||
0 = Disabled (Default)
|
|
||||||
1 = Alert when the bell character is received
|
|
||||||
|
|
||||||
moduleConfig.external_notification.output
|
|
||||||
GPIO of the output. (Default = 13)
|
|
||||||
|
|
||||||
moduleConfig.external_notification.output_ms
|
|
||||||
Amount of time in ms for the alert. Default is 1000.
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Default configurations
|
// Default configurations
|
||||||
@@ -58,56 +26,97 @@
|
|||||||
|
|
||||||
#define ASCII_BELL 0x07
|
#define ASCII_BELL 0x07
|
||||||
|
|
||||||
bool externalCurrentState = 0;
|
ExternalNotificationModule *externalNotificationModule;
|
||||||
uint32_t externalTurnedOn = 0;
|
|
||||||
|
bool externalCurrentState[3] = {};
|
||||||
|
|
||||||
|
uint32_t externalTurnedOn[3] = {};
|
||||||
|
|
||||||
int32_t ExternalNotificationModule::runOnce()
|
int32_t ExternalNotificationModule::runOnce()
|
||||||
{
|
{
|
||||||
/*
|
if (moduleConfig.external_notification.use_pwm || !moduleConfig.external_notification.enabled) {
|
||||||
Uncomment the preferences below if you want to use the module
|
return INT32_MAX; // we don't need this thread here...
|
||||||
without having to configure it from the PythonAPI or WebUI.
|
} else {
|
||||||
*/
|
|
||||||
|
|
||||||
// moduleConfig.external_notification.enabled = 1;
|
|
||||||
// moduleConfig.external_notification.alert_message = 1;
|
|
||||||
|
|
||||||
// moduleConfig.external_notification.active = 1;
|
|
||||||
// moduleConfig.external_notification.alert_bell = 1;
|
|
||||||
// moduleConfig.external_notification.output_ms = 1000;
|
|
||||||
// moduleConfig.external_notification.output = 13;
|
|
||||||
|
|
||||||
if (externalCurrentState && !moduleConfig.external_notification.use_pwm) {
|
|
||||||
|
|
||||||
// If the output is turned on, turn it back off after the given period of time.
|
// If the output is turned on, turn it back off after the given period of time.
|
||||||
if (externalTurnedOn + (moduleConfig.external_notification.output_ms
|
if (nagCycleCutoff != UINT32_MAX) {
|
||||||
|
if (externalTurnedOn[0] + (moduleConfig.external_notification.output_ms
|
||||||
? moduleConfig.external_notification.output_ms
|
? moduleConfig.external_notification.output_ms
|
||||||
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
|
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) {
|
||||||
millis()) {
|
getExternal(0) ? setExternalOff(0) : setExternalOn(0);
|
||||||
DEBUG_MSG("Turning off external notification\n");
|
}
|
||||||
setExternalOff();
|
if (externalTurnedOn[1] + (moduleConfig.external_notification.output_ms
|
||||||
|
? moduleConfig.external_notification.output_ms
|
||||||
|
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) {
|
||||||
|
getExternal(1) ? setExternalOff(1) : setExternalOn(1);
|
||||||
|
}
|
||||||
|
if (externalTurnedOn[2] + (moduleConfig.external_notification.output_ms
|
||||||
|
? moduleConfig.external_notification.output_ms
|
||||||
|
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) {
|
||||||
|
getExternal(2) ? setExternalOff(2) : setExternalOn(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nagCycleCutoff < millis()) {
|
||||||
|
nagCycleCutoff = UINT32_MAX;
|
||||||
|
DEBUG_MSG("Turning off external notification: ");
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
if (getExternal(i)) {
|
||||||
|
setExternalOff(i);
|
||||||
|
externalTurnedOn[i] = 0;
|
||||||
|
DEBUG_MSG("%d ", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DEBUG_MSG("\n");
|
||||||
|
return INT32_MAX; // save cycles till we're needed again
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (moduleConfig.external_notification.use_pwm)
|
|
||||||
return INT32_MAX; // we don't need this thread here...
|
|
||||||
else
|
|
||||||
return 25;
|
return 25;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExternalNotificationModule::setExternalOn()
|
void ExternalNotificationModule::setExternalOn(uint8_t index)
|
||||||
{
|
{
|
||||||
externalCurrentState = 1;
|
externalCurrentState[index] = 1;
|
||||||
externalTurnedOn = millis();
|
externalTurnedOn[index] = millis();
|
||||||
|
|
||||||
digitalWrite(output,
|
switch(index) {
|
||||||
(moduleConfig.external_notification.active ? true : false));
|
case 1:
|
||||||
|
if(moduleConfig.external_notification.output_vibra)
|
||||||
|
digitalWrite(moduleConfig.external_notification.output_vibra, true);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if(moduleConfig.external_notification.output_buzzer)
|
||||||
|
digitalWrite(moduleConfig.external_notification.output_buzzer, true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
digitalWrite(output, (moduleConfig.external_notification.active ? true : false));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExternalNotificationModule::setExternalOff()
|
void ExternalNotificationModule::setExternalOff(uint8_t index)
|
||||||
{
|
{
|
||||||
externalCurrentState = 0;
|
externalCurrentState[index] = 0;
|
||||||
|
externalTurnedOn[index] = millis();
|
||||||
|
|
||||||
digitalWrite(output,
|
switch(index) {
|
||||||
(moduleConfig.external_notification.active ? false : true));
|
case 1:
|
||||||
|
if(moduleConfig.external_notification.output_vibra)
|
||||||
|
digitalWrite(moduleConfig.external_notification.output_vibra, false);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if(moduleConfig.external_notification.output_buzzer)
|
||||||
|
digitalWrite(moduleConfig.external_notification.output_buzzer, false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
digitalWrite(output, (moduleConfig.external_notification.active ? false : true));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExternalNotificationModule::getExternal(uint8_t index)
|
||||||
|
{
|
||||||
|
return externalCurrentState[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------
|
// --------
|
||||||
@@ -121,13 +130,18 @@ ExternalNotificationModule::ExternalNotificationModule()
|
|||||||
without having to configure it from the PythonAPI or WebUI.
|
without having to configure it from the PythonAPI or WebUI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// moduleConfig.external_notification.enabled = 1;
|
// moduleConfig.external_notification.enabled = true;
|
||||||
// moduleConfig.external_notification.alert_message = 1;
|
// moduleConfig.external_notification.alert_message = true;
|
||||||
|
// moduleConfig.external_notification.alert_message_buzzer = true;
|
||||||
|
// moduleConfig.external_notification.alert_message_vibra = true;
|
||||||
|
|
||||||
// moduleConfig.external_notification.active = 1;
|
// moduleConfig.external_notification.active = true;
|
||||||
// moduleConfig.external_notification.alert_bell = 1;
|
// moduleConfig.external_notification.alert_bell = 1;
|
||||||
// moduleConfig.external_notification.output_ms = 1000;
|
// moduleConfig.external_notification.output_ms = 1000;
|
||||||
// moduleConfig.external_notification.output = 13;
|
// moduleConfig.external_notification.output = 4; // RAK4631 IO4
|
||||||
|
// moduleConfig.external_notification.output_buzzer = 10; // RAK4631 IO6
|
||||||
|
// moduleConfig.external_notification.output_vibra = 28; // RAK4631 IO7
|
||||||
|
// moduleConfig.external_notification.nag_timeout = 300;
|
||||||
|
|
||||||
if (moduleConfig.external_notification.enabled) {
|
if (moduleConfig.external_notification.enabled) {
|
||||||
|
|
||||||
@@ -141,8 +155,20 @@ ExternalNotificationModule::ExternalNotificationModule()
|
|||||||
// Set the direction of a pin
|
// Set the direction of a pin
|
||||||
DEBUG_MSG("Using Pin %i in digital mode\n", output);
|
DEBUG_MSG("Using Pin %i in digital mode\n", output);
|
||||||
pinMode(output, OUTPUT);
|
pinMode(output, OUTPUT);
|
||||||
// Turn off the pin
|
setExternalOff(0);
|
||||||
setExternalOff();
|
externalTurnedOn[0] = 0;
|
||||||
|
if(moduleConfig.external_notification.output_vibra) {
|
||||||
|
DEBUG_MSG("Using Pin %i for vibra motor\n", moduleConfig.external_notification.output_vibra);
|
||||||
|
pinMode(moduleConfig.external_notification.output_vibra, OUTPUT);
|
||||||
|
setExternalOff(1);
|
||||||
|
externalTurnedOn[1] = 0;
|
||||||
|
}
|
||||||
|
if(moduleConfig.external_notification.output_buzzer) {
|
||||||
|
DEBUG_MSG("Using Pin %i for buzzer\n", moduleConfig.external_notification.output_buzzer);
|
||||||
|
pinMode(moduleConfig.external_notification.output_buzzer, OUTPUT);
|
||||||
|
setExternalOff(2);
|
||||||
|
externalTurnedOn[2] = 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
config.device.buzzer_gpio = config.device.buzzer_gpio
|
config.device.buzzer_gpio = config.device.buzzer_gpio
|
||||||
? config.device.buzzer_gpio
|
? config.device.buzzer_gpio
|
||||||
@@ -163,17 +189,53 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
|
|||||||
|
|
||||||
if (getFrom(&mp) != nodeDB.getNodeNum()) {
|
if (getFrom(&mp) != nodeDB.getNodeNum()) {
|
||||||
|
|
||||||
// TODO: This may be a problem if messages are sent in unicide, but I'm not sure if it will.
|
// Check if the message contains a bell character. Don't do this loop for every pin, just once.
|
||||||
// Need to know if and how this could be a problem.
|
auto &p = mp.decoded;
|
||||||
|
bool containsBell = false;
|
||||||
|
for (int i = 0; i < p.payload.size; i++) {
|
||||||
|
if (p.payload.bytes[i] == ASCII_BELL) {
|
||||||
|
containsBell = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (moduleConfig.external_notification.alert_bell) {
|
if (moduleConfig.external_notification.alert_bell) {
|
||||||
auto &p = mp.decoded;
|
if (containsBell) {
|
||||||
DEBUG_MSG("externalNotificationModule - Notification Bell\n");
|
DEBUG_MSG("externalNotificationModule - Notification Bell\n");
|
||||||
for (int i = 0; i < p.payload.size; i++) {
|
if (!moduleConfig.external_notification.use_pwm) {
|
||||||
if (p.payload.bytes[i] == ASCII_BELL) {
|
setExternalOn(0);
|
||||||
if (!moduleConfig.external_notification.use_pwm) {
|
if (moduleConfig.external_notification.nag_timeout) {
|
||||||
setExternalOn();
|
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||||
} else {
|
} else {
|
||||||
playBeep();
|
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||||
|
}
|
||||||
|
// run_once now
|
||||||
|
} else {
|
||||||
|
playBeep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!moduleConfig.external_notification.use_pwm) {
|
||||||
|
if (moduleConfig.external_notification.alert_bell_vibra) {
|
||||||
|
if (containsBell) {
|
||||||
|
DEBUG_MSG("externalNotificationModule - Notification Bell (Vibra)\n");
|
||||||
|
setExternalOn(1);
|
||||||
|
if (moduleConfig.external_notification.nag_timeout) {
|
||||||
|
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||||
|
} else {
|
||||||
|
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleConfig.external_notification.alert_bell_buzzer) {
|
||||||
|
if (containsBell) {
|
||||||
|
DEBUG_MSG("externalNotificationModule - Notification Bell (Buzzer)\n");
|
||||||
|
setExternalOn(2);
|
||||||
|
if (moduleConfig.external_notification.nag_timeout) {
|
||||||
|
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||||
|
} else {
|
||||||
|
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,11 +244,39 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
|
|||||||
if (moduleConfig.external_notification.alert_message) {
|
if (moduleConfig.external_notification.alert_message) {
|
||||||
DEBUG_MSG("externalNotificationModule - Notification Module\n");
|
DEBUG_MSG("externalNotificationModule - Notification Module\n");
|
||||||
if (!moduleConfig.external_notification.use_pwm) {
|
if (!moduleConfig.external_notification.use_pwm) {
|
||||||
setExternalOn();
|
setExternalOn(0);
|
||||||
|
if (moduleConfig.external_notification.nag_timeout) {
|
||||||
|
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||||
|
} else {
|
||||||
|
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
playBeep();
|
playBeep();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!moduleConfig.external_notification.use_pwm) {
|
||||||
|
if (moduleConfig.external_notification.alert_message_vibra) {
|
||||||
|
DEBUG_MSG("externalNotificationModule - Notification Module (Vibra)\n");
|
||||||
|
setExternalOn(1);
|
||||||
|
if (moduleConfig.external_notification.nag_timeout) {
|
||||||
|
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||||
|
} else {
|
||||||
|
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleConfig.external_notification.alert_message_buzzer) {
|
||||||
|
DEBUG_MSG("externalNotificationModule - Notification Module (Buzzer)\n");
|
||||||
|
setExternalOn(2);
|
||||||
|
if (moduleConfig.external_notification.nag_timeout) {
|
||||||
|
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||||
|
} else {
|
||||||
|
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setIntervalFromNow(0); // run once so we know if we should do something
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -17,18 +17,19 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
|
|||||||
public:
|
public:
|
||||||
ExternalNotificationModule();
|
ExternalNotificationModule();
|
||||||
|
|
||||||
void setExternalOn();
|
uint32_t nagCycleCutoff = UINT32_MAX;
|
||||||
void setExternalOff();
|
|
||||||
void getExternal();
|
void setExternalOn(uint8_t index = 0);
|
||||||
|
void setExternalOff(uint8_t index = 0);
|
||||||
|
bool getExternal(uint8_t index = 0);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// virtual MeshPacket *allocReply();
|
|
||||||
|
|
||||||
/** 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;
|
||||||
|
|
||||||
virtual int32_t runOnce() override;
|
virtual int32_t runOnce() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern ExternalNotificationModule *externalNotificationModule;
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -40,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.
|
||||||
@@ -67,7 +69,7 @@ void setupModules()
|
|||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
// Only run on an esp32 based device.
|
// Only run on an esp32 based device.
|
||||||
audioModule = new AudioModule();
|
audioModule = new AudioModule();
|
||||||
new ExternalNotificationModule();
|
externalNotificationModule = new ExternalNotificationModule();
|
||||||
|
|
||||||
storeForwardModule = new StoreForwardModule();
|
storeForwardModule = new StoreForwardModule();
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -214,7 +214,6 @@ int32_t SerialModule::runOnce()
|
|||||||
|
|
||||||
MeshPacket *SerialModuleRadio::allocReply()
|
MeshPacket *SerialModuleRadio::allocReply()
|
||||||
{
|
{
|
||||||
|
|
||||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||||
|
|
||||||
return reply;
|
return reply;
|
||||||
@@ -236,7 +235,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;
|
||||||
@@ -266,7 +265,12 @@ ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
|
|||||||
if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_DEFAULT ||
|
if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_DEFAULT ||
|
||||||
moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_SIMPLE) {
|
moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_SIMPLE) {
|
||||||
Serial2.printf("%s", p.payload.bytes);
|
Serial2.printf("%s", p.payload.bytes);
|
||||||
|
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG) {
|
||||||
|
NodeInfo *node = nodeDB.getNode(getFrom(&mp));
|
||||||
|
String sender = (node && node->has_user) ? node->user.short_name : "???";
|
||||||
|
Serial2.println();
|
||||||
|
Serial2.printf("%s: %s", sender, p.payload.bytes);
|
||||||
|
Serial2.println();
|
||||||
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
|
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
|
||||||
// TODO this needs to be implemented
|
// TODO this needs to be implemented
|
||||||
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) {
|
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) {
|
||||||
|
|||||||
86
src/modules/TraceRouteModule.cpp
Normal file
86
src/modules/TraceRouteModule.cpp
Normal 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
src/modules/TraceRouteModule.h
Normal file
36
src/modules/TraceRouteModule.h
Normal 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;
|
||||||
@@ -10,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.
|
||||||
@@ -41,48 +45,72 @@ AudioModule *audioModule;
|
|||||||
#define YIELD_FROM_ISR(x) portYIELD_FROM_ISR(x)
|
#define YIELD_FROM_ISR(x) portYIELD_FROM_ISR(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//int16_t 1KHz sine test tone
|
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||||
int16_t Sine1KHz[8] = { -21210 , -30000, -21210, 0 , 21210 , 30000 , 21210, 0 };
|
// The screen is bigger so use bigger fonts
|
||||||
int Sine1KHz_index = 0;
|
#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
|
||||||
|
|
||||||
|
#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)
|
void run_codec2(void* parameter)
|
||||||
{
|
{
|
||||||
// 4 bytes of header in each frame Kennung hex c0 de c2 plus the bitrate
|
// 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));
|
memcpy(audioModule->tx_encode_frame,&audioModule->tx_header,sizeof(audioModule->tx_header));
|
||||||
|
|
||||||
|
DEBUG_MSG("Starting codec2 task\n");
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
uint32_t tcount = ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(10000));
|
uint32_t tcount = ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(10000));
|
||||||
|
|
||||||
if (tcount != 0) {
|
if (tcount != 0) {
|
||||||
if (audioModule->radio_state == RadioState::tx) {
|
if (audioModule->radio_state == RadioState::tx) {
|
||||||
|
|
||||||
// Apply the TX filter
|
|
||||||
for (int i = 0; i < audioModule->adc_buffer_size; i++)
|
for (int i = 0; i < audioModule->adc_buffer_size; i++)
|
||||||
audioModule->speech[i] = (int16_t)hp_filter.Update((float)audioModule->speech[i]);
|
audioModule->speech[i] = (int16_t)hp_filter.Update((float)audioModule->speech[i]);
|
||||||
|
|
||||||
// Encode the audio
|
|
||||||
codec2_encode(audioModule->codec2, audioModule->tx_encode_frame + audioModule->tx_encode_frame_index, audioModule->speech);
|
codec2_encode(audioModule->codec2, audioModule->tx_encode_frame + audioModule->tx_encode_frame_index, audioModule->speech);
|
||||||
|
|
||||||
//increment the pointer where the encoded frame must be saved
|
|
||||||
audioModule->tx_encode_frame_index += audioModule->encode_codec_size;
|
audioModule->tx_encode_frame_index += audioModule->encode_codec_size;
|
||||||
|
|
||||||
//If it this is reached we have a ready trasnmission frame
|
|
||||||
if (audioModule->tx_encode_frame_index == (audioModule->encode_frame_size + sizeof(audioModule->tx_header)))
|
if (audioModule->tx_encode_frame_index == (audioModule->encode_frame_size + sizeof(audioModule->tx_header)))
|
||||||
{
|
{
|
||||||
//Transmit it
|
DEBUG_MSG("Sending %d codec2 bytes\n", audioModule->encode_frame_size);
|
||||||
DEBUG_MSG("♪♫♪ Sending %d codec2 bytes\n", audioModule->encode_frame_size);
|
|
||||||
audioModule->sendPayload();
|
audioModule->sendPayload();
|
||||||
audioModule->tx_encode_frame_index = sizeof(audioModule->tx_header);
|
audioModule->tx_encode_frame_index = sizeof(audioModule->tx_header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (audioModule->radio_state == RadioState::rx) {
|
if (audioModule->radio_state == RadioState::rx) {
|
||||||
//Make a cycle to get each codec2 frame from the received frame
|
size_t bytesOut = 0;
|
||||||
for (int i = 0; i < audioModule->rx_encode_frame_index; i += audioModule->encode_codec_size)
|
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)
|
||||||
//Decode the codec2 frame
|
{
|
||||||
codec2_decode(audioModule->codec2, audioModule->output_buffer, audioModule->rx_encode_frame + i);
|
codec2_decode(audioModule->codec2, audioModule->output_buffer, audioModule->rx_encode_frame + i);
|
||||||
size_t bytesOut = 0;
|
i2s_write(I2S_PORT, &audioModule->output_buffer, audioModule->adc_buffer_size, &bytesOut, pdMS_TO_TICKS(500));
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,8 +119,15 @@ void run_codec2(void* parameter)
|
|||||||
|
|
||||||
AudioModule::AudioModule() : SinglePortModule("AudioModule", PortNum_AUDIO_APP), concurrency::OSThread("AudioModule")
|
AudioModule::AudioModule() : SinglePortModule("AudioModule", PortNum_AUDIO_APP), concurrency::OSThread("AudioModule")
|
||||||
{
|
{
|
||||||
|
// moduleConfig.audio.codec2_enabled = true;
|
||||||
|
// moduleConfig.audio.i2s_ws = 13;
|
||||||
|
// moduleConfig.audio.i2s_sd = 15;
|
||||||
|
// moduleConfig.audio.i2s_din = 22;
|
||||||
|
// moduleConfig.audio.i2s_sck = 14;
|
||||||
|
// moduleConfig.audio.ptt_pin = 39;
|
||||||
|
|
||||||
if ((moduleConfig.audio.codec2_enabled) && (myRegion->audioPermitted)) {
|
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);
|
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);
|
codec2 = codec2_create((moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1);
|
||||||
memcpy(tx_header.magic,c2_magic,sizeof(c2_magic));
|
memcpy(tx_header.magic,c2_magic,sizeof(c2_magic));
|
||||||
tx_header.mode = (moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1;
|
tx_header.mode = (moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1;
|
||||||
@@ -104,7 +139,31 @@ AudioModule::AudioModule() : SinglePortModule("AudioModule", PortNum_AUDIO_APP),
|
|||||||
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);
|
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);
|
xTaskCreate(&run_codec2, "codec2_task", 30000, NULL, 5, &codec2HandlerTask);
|
||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("♪♫♪ Codec2 disabled (AudioModule %d, Region %s, permitted %d)\n", moduleConfig.audio.codec2_enabled, myRegion->name, myRegion->audioPermitted);
|
DEBUG_MSG("Codec2 disabled (AudioModule %d, Region %s, permitted %d)\n", moduleConfig.audio.codec2_enabled, myRegion->name, myRegion->audioPermitted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
|
{
|
||||||
|
displayedNodeNum = 0; // Not currently showing a node pane
|
||||||
|
|
||||||
|
char buffer[50];
|
||||||
|
|
||||||
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
|
display->setFont(FONT_SMALL);
|
||||||
|
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||||
|
display->setColor(BLACK);
|
||||||
|
display->drawStringf(0 + x, 0 + y, buffer, "Codec2 Mode %d Audio", (moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1);
|
||||||
|
display->setColor(WHITE);
|
||||||
|
display->setFont(FONT_LARGE);
|
||||||
|
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
|
switch (radio_state) {
|
||||||
|
case RadioState::tx:
|
||||||
|
display->drawString(display->getWidth() / 2 + x, (display->getHeight() - FONT_HEIGHT_SMALL) / 2 + y, "PTT");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
display->drawString(display->getWidth() / 2 + x, (display->getHeight() - FONT_HEIGHT_SMALL) / 2 + y, "Receive");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +173,7 @@ int32_t AudioModule::runOnce()
|
|||||||
esp_err_t res;
|
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
|
// 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);
|
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 = {
|
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)),
|
.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,
|
.sample_rate = 8000,
|
||||||
@@ -130,7 +189,7 @@ int32_t AudioModule::runOnce()
|
|||||||
};
|
};
|
||||||
res = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
|
res = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
|
||||||
if(res != ESP_OK)
|
if(res != ESP_OK)
|
||||||
DEBUG_MSG("♪♫♪ Failed to install I2S driver: %d\n", res);
|
DEBUG_MSG("Failed to install I2S driver: %d\n", res);
|
||||||
|
|
||||||
const i2s_pin_config_t pin_config = {
|
const i2s_pin_config_t pin_config = {
|
||||||
.bck_io_num = moduleConfig.audio.i2s_sck,
|
.bck_io_num = moduleConfig.audio.i2s_sck,
|
||||||
@@ -140,36 +199,41 @@ int32_t AudioModule::runOnce()
|
|||||||
};
|
};
|
||||||
res = i2s_set_pin(I2S_PORT, &pin_config);
|
res = i2s_set_pin(I2S_PORT, &pin_config);
|
||||||
if(res != ESP_OK)
|
if(res != ESP_OK)
|
||||||
DEBUG_MSG("♪♫♪ Failed to set I2S pin config: %d\n", res);
|
DEBUG_MSG("Failed to set I2S pin config: %d\n", res);
|
||||||
|
|
||||||
res = i2s_start(I2S_PORT);
|
res = i2s_start(I2S_PORT);
|
||||||
if(res != ESP_OK)
|
if(res != ESP_OK)
|
||||||
DEBUG_MSG("♪♫♪ Failed to start I2S: %d\n", res);
|
DEBUG_MSG("Failed to start I2S: %d\n", res);
|
||||||
|
|
||||||
radio_state = RadioState::rx;
|
radio_state = RadioState::rx;
|
||||||
|
|
||||||
// Configure PTT input
|
// Configure PTT input
|
||||||
DEBUG_MSG("♪♫♪ Initializing PTT on Pin %u\n", moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN);
|
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);
|
pinMode(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN, INPUT);
|
||||||
|
|
||||||
firstTime = false;
|
firstTime = false;
|
||||||
} else {
|
} else {
|
||||||
|
UIFrameEvent e = {false, true};
|
||||||
// Check if PTT is pressed. TODO hook that into Onebutton/Interrupt drive.
|
// Check if PTT is pressed. TODO hook that into Onebutton/Interrupt drive.
|
||||||
if (digitalRead(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN) == HIGH) {
|
if (digitalRead(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN) == HIGH) {
|
||||||
if (radio_state == RadioState::rx) {
|
if (radio_state == RadioState::rx) {
|
||||||
DEBUG_MSG("♪♫♪ PTT pressed, switching to TX\n");
|
DEBUG_MSG("PTT pressed, switching to TX\n");
|
||||||
radio_state = RadioState::tx;
|
radio_state = RadioState::tx;
|
||||||
|
e.frameChanged = true;
|
||||||
|
this->notifyObservers(&e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (radio_state == RadioState::tx) {
|
if (radio_state == RadioState::tx) {
|
||||||
|
DEBUG_MSG("PTT released, switching to RX\n");
|
||||||
if (tx_encode_frame_index > sizeof(tx_header)) {
|
if (tx_encode_frame_index > sizeof(tx_header)) {
|
||||||
// Send the incomplete frame
|
// Send the incomplete frame
|
||||||
DEBUG_MSG("♪♫♪ Sending %d codec2 bytes (incomplete)\n", tx_encode_frame_index);
|
DEBUG_MSG("Sending %d codec2 bytes (incomplete)\n", tx_encode_frame_index);
|
||||||
sendPayload();
|
sendPayload();
|
||||||
}
|
}
|
||||||
DEBUG_MSG("♪♫♪ PTT released, switching to RX\n");
|
|
||||||
tx_encode_frame_index = sizeof(tx_header);
|
tx_encode_frame_index = sizeof(tx_header);
|
||||||
radio_state = RadioState::rx;
|
radio_state = RadioState::rx;
|
||||||
|
e.frameChanged = true;
|
||||||
|
this->notifyObservers(&e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (radio_state == RadioState::tx) {
|
if (radio_state == RadioState::tx) {
|
||||||
@@ -194,7 +258,7 @@ int32_t AudioModule::runOnce()
|
|||||||
}
|
}
|
||||||
return 100;
|
return 100;
|
||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("♪♫♪ Audio Module Disabled\n");
|
DEBUG_MSG("Audio Module Disabled\n");
|
||||||
return INT32_MAX;
|
return INT32_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,17 +266,25 @@ int32_t AudioModule::runOnce()
|
|||||||
|
|
||||||
MeshPacket *AudioModule::allocReply()
|
MeshPacket *AudioModule::allocReply()
|
||||||
{
|
{
|
||||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
auto reply = allocDataPacket();
|
||||||
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 = false; // Audio is shoot&forget. TODO: Is this really suppressing retransmissions?
|
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->priority = MeshPacket_Priority_MAX; // Audio is important, because realtime
|
||||||
|
|
||||||
p->decoded.payload.size = tx_encode_frame_index;
|
p->decoded.payload.size = tx_encode_frame_index;
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <codec2.h>
|
#include <codec2.h>
|
||||||
#include <ButterworthFilter.h>
|
#include <ButterworthFilter.h>
|
||||||
|
#include <OLEDDisplay.h>
|
||||||
|
#include <OLEDDisplayUi.h>
|
||||||
|
|
||||||
enum RadioState { standby, rx, tx };
|
enum RadioState { standby, rx, tx };
|
||||||
|
|
||||||
@@ -28,7 +30,7 @@ struct c2_header {
|
|||||||
#define AUDIO_MODULE_RX_BUFFER 128
|
#define AUDIO_MODULE_RX_BUFFER 128
|
||||||
#define AUDIO_MODULE_MODE ModuleConfig_AudioConfig_Audio_Baud_CODEC2_700
|
#define AUDIO_MODULE_MODE ModuleConfig_AudioConfig_Audio_Baud_CODEC2_700
|
||||||
|
|
||||||
class AudioModule : public SinglePortModule, private concurrency::OSThread
|
class AudioModule : public SinglePortModule, public Observable<const UIFrameEvent *>, private concurrency::OSThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
unsigned char rx_encode_frame[Constants_DATA_PAYLOAD_LEN] = {};
|
unsigned char rx_encode_frame[Constants_DATA_PAYLOAD_LEN] = {};
|
||||||
@@ -50,6 +52,8 @@ class AudioModule : public SinglePortModule, private concurrency::OSThread
|
|||||||
|
|
||||||
AudioModule();
|
AudioModule();
|
||||||
|
|
||||||
|
bool shouldDraw();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send our payload into the mesh
|
* Send our payload into the mesh
|
||||||
*/
|
*/
|
||||||
@@ -63,6 +67,15 @@ class AudioModule : public SinglePortModule, private concurrency::OSThread
|
|||||||
|
|
||||||
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
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "mesh/Router.h"
|
#include "mesh/Router.h"
|
||||||
#include "mesh/generated/mqtt.pb.h"
|
#include "mesh/generated/mqtt.pb.h"
|
||||||
#include "mesh/generated/telemetry.pb.h"
|
#include "mesh/generated/telemetry.pb.h"
|
||||||
|
#include "mesh/http/WiFiAPClient.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
#if HAS_WIFI
|
#if HAS_WIFI
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
@@ -20,6 +21,10 @@ String statusTopic = "msh/2/stat/";
|
|||||||
String cryptTopic = "msh/2/c/"; // msh/2/c/CHANNELID/NODEID
|
String cryptTopic = "msh/2/c/"; // msh/2/c/CHANNELID/NODEID
|
||||||
String jsonTopic = "msh/2/json/"; // msh/2/json/CHANNELID/NODEID
|
String jsonTopic = "msh/2/json/"; // msh/2/json/CHANNELID/NODEID
|
||||||
|
|
||||||
|
static MemoryDynamic<ServiceEnvelope> staticMqttPool;
|
||||||
|
|
||||||
|
Allocator<ServiceEnvelope> &mqttPool = staticMqttPool;
|
||||||
|
|
||||||
void MQTT::mqttCallback(char *topic, byte *payload, unsigned int length)
|
void MQTT::mqttCallback(char *topic, byte *payload, unsigned int length)
|
||||||
{
|
{
|
||||||
mqtt->onPublish(topic, payload, length);
|
mqtt->onPublish(topic, payload, length);
|
||||||
@@ -61,7 +66,27 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length)
|
|||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("JSON Ignoring downlink message we originally sent.\n");
|
DEBUG_MSG("JSON Ignoring downlink message we originally sent.\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else if ((json.find("sender") != json.end()) && (json.find("payload") != json.end()) && (json.find("type") != json.end()) && json["type"]->IsString() && (json["type"]->AsString().compare("sendposition") == 0)) {
|
||||||
|
//invent the "sendposition" type for a valid envelope
|
||||||
|
if (json["payload"]->IsObject() && json["type"]->IsString() && (json["sender"]->AsString().compare(owner.id) != 0)) {
|
||||||
|
JSONObject posit;
|
||||||
|
posit=json["payload"]->AsObject(); //get nested JSON Position
|
||||||
|
Position pos =Position_init_default;
|
||||||
|
pos.latitude_i=posit["latitude_i"]->AsNumber();
|
||||||
|
pos.longitude_i=posit["longitude_i"]->AsNumber();
|
||||||
|
pos.altitude=posit["altitude"]->AsNumber();
|
||||||
|
pos.time=posit["time"]->AsNumber();
|
||||||
|
|
||||||
|
// construct protobuf data packet using POSITION, send it to the mesh
|
||||||
|
MeshPacket *p = router->allocForSending();
|
||||||
|
p->decoded.portnum = PortNum_POSITION_APP;
|
||||||
|
p->decoded.payload.size=pb_encode_to_bytes(p->decoded.payload.bytes,sizeof(p->decoded.payload.bytes),Position_fields, &pos); //make the Data protobuf from position
|
||||||
|
service.sendToMesh(p, RX_SRC_LOCAL);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("JSON Ignoring downlink message we originally sent.\n");
|
||||||
|
}
|
||||||
|
} else{
|
||||||
DEBUG_MSG("JSON Received payload on MQTT but not a valid envelope\n");
|
DEBUG_MSG("JSON Received payload on MQTT but not a valid envelope\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -101,7 +126,7 @@ void mqttInit()
|
|||||||
new MQTT();
|
new MQTT();
|
||||||
}
|
}
|
||||||
|
|
||||||
MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient)
|
MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient), mqttQueue(MAX_MQTT_QUEUE)
|
||||||
{
|
{
|
||||||
assert(!mqtt);
|
assert(!mqtt);
|
||||||
mqtt = this;
|
mqtt = this;
|
||||||
@@ -148,14 +173,23 @@ void MQTT::reconnect()
|
|||||||
DEBUG_MSG("MQTT connected\n");
|
DEBUG_MSG("MQTT connected\n");
|
||||||
enabled = true; // Start running background process again
|
enabled = true; // Start running background process again
|
||||||
runASAP = true;
|
runASAP = true;
|
||||||
|
reconnectCount = 0;
|
||||||
|
|
||||||
/// FIXME, include more information in the status text
|
/// FIXME, include more information in the status text
|
||||||
bool ok = pubSub.publish(myStatus.c_str(), "online", true);
|
bool ok = pubSub.publish(myStatus.c_str(), "online", true);
|
||||||
DEBUG_MSG("published %d\n", ok);
|
DEBUG_MSG("published %d\n", ok);
|
||||||
|
|
||||||
sendSubscriptions();
|
sendSubscriptions();
|
||||||
} else
|
} else {
|
||||||
DEBUG_MSG("Failed to contact MQTT server...\n");
|
DEBUG_MSG("Failed to contact MQTT server (%d/10)...\n",reconnectCount);
|
||||||
|
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
||||||
|
if (reconnectCount > 9) {
|
||||||
|
needReconnect = true;
|
||||||
|
wifiReconnect->setIntervalFromNow(1000);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
reconnectCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,8 +245,35 @@ int32_t MQTT::runOnce()
|
|||||||
if (wantConnection) {
|
if (wantConnection) {
|
||||||
reconnect();
|
reconnect();
|
||||||
|
|
||||||
// If we succeeded, start reading rapidly, else try again in 30 seconds (TCP connections are EXPENSIVE so try rarely)
|
// If we succeeded, empty the queue one by one and start reading rapidly, else try again in 30 seconds (TCP connections are EXPENSIVE so try rarely)
|
||||||
return pubSub.connected() ? 20 : 30000;
|
if (pubSub.connected()) {
|
||||||
|
if (!mqttQueue.isEmpty()) {
|
||||||
|
// FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets
|
||||||
|
ServiceEnvelope *env = mqttQueue.dequeuePtr(0);
|
||||||
|
static uint8_t bytes[MeshPacket_size + 64];
|
||||||
|
size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), ServiceEnvelope_fields, env);
|
||||||
|
|
||||||
|
String topic = cryptTopic + env->channel_id + "/" + owner.id;
|
||||||
|
DEBUG_MSG("publish %s, %u bytes from queue\n", topic.c_str(), numBytes);
|
||||||
|
|
||||||
|
|
||||||
|
pubSub.publish(topic.c_str(), bytes, numBytes, false);
|
||||||
|
|
||||||
|
if (moduleConfig.mqtt.json_enabled) {
|
||||||
|
// handle json topic
|
||||||
|
auto jsonString = this->downstreamPacketToJson(env->packet);
|
||||||
|
if (jsonString.length() != 0) {
|
||||||
|
String topicJson = jsonTopic + env->channel_id + "/" + owner.id;
|
||||||
|
DEBUG_MSG("JSON publish message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(), jsonString.c_str());
|
||||||
|
pubSub.publish(topicJson.c_str(), jsonString.c_str(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mqttPool.release(env);
|
||||||
|
}
|
||||||
|
return 20;
|
||||||
|
} else {
|
||||||
|
return 30000;
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
return 5000; // If we don't want connection now, check again in 5 secs
|
return 5000; // If we don't want connection now, check again in 5 secs
|
||||||
} else {
|
} else {
|
||||||
@@ -231,33 +292,48 @@ void MQTT::onSend(const MeshPacket &mp, ChannelIndex chIndex)
|
|||||||
{
|
{
|
||||||
auto &ch = channels.getByIndex(chIndex);
|
auto &ch = channels.getByIndex(chIndex);
|
||||||
|
|
||||||
// don't bother sending if not connected...
|
if (ch.settings.uplink_enabled) {
|
||||||
if (pubSub.connected() && ch.settings.uplink_enabled) {
|
|
||||||
const char *channelId = channels.getGlobalId(chIndex); // FIXME, for now we just use the human name for the channel
|
const char *channelId = channels.getGlobalId(chIndex); // FIXME, for now we just use the human name for the channel
|
||||||
|
|
||||||
ServiceEnvelope env = ServiceEnvelope_init_default;
|
ServiceEnvelope *env = mqttPool.allocZeroed();
|
||||||
env.channel_id = (char *)channelId;
|
env->channel_id = (char *)channelId;
|
||||||
env.gateway_id = owner.id;
|
env->gateway_id = owner.id;
|
||||||
env.packet = (MeshPacket *)∓
|
env->packet = (MeshPacket *)∓
|
||||||
|
|
||||||
// FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets
|
// don't bother sending if not connected...
|
||||||
static uint8_t bytes[MeshPacket_size + 64];
|
if (pubSub.connected()) {
|
||||||
size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), ServiceEnvelope_fields, &env);
|
|
||||||
|
|
||||||
String topic = cryptTopic + channelId + "/" + owner.id;
|
// FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets
|
||||||
DEBUG_MSG("publish %s, %u bytes\n", topic.c_str(), numBytes);
|
static uint8_t bytes[MeshPacket_size + 64];
|
||||||
|
size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), ServiceEnvelope_fields, env);
|
||||||
|
|
||||||
pubSub.publish(topic.c_str(), bytes, numBytes, false);
|
String topic = cryptTopic + channelId + "/" + owner.id;
|
||||||
|
DEBUG_MSG("publish %s, %u bytes\n", topic.c_str(), numBytes);
|
||||||
|
|
||||||
if (moduleConfig.mqtt.json_enabled) {
|
pubSub.publish(topic.c_str(), bytes, numBytes, false);
|
||||||
// handle json topic
|
|
||||||
auto jsonString = this->downstreamPacketToJson((MeshPacket *)&mp);
|
if (moduleConfig.mqtt.json_enabled) {
|
||||||
if (jsonString.length() != 0) {
|
// handle json topic
|
||||||
String topicJson = jsonTopic + channelId + "/" + owner.id;
|
auto jsonString = this->downstreamPacketToJson((MeshPacket *)&mp);
|
||||||
DEBUG_MSG("JSON publish message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(), jsonString.c_str());
|
if (jsonString.length() != 0) {
|
||||||
pubSub.publish(topicJson.c_str(), jsonString.c_str(), false);
|
String topicJson = jsonTopic + channelId + "/" + owner.id;
|
||||||
|
DEBUG_MSG("JSON publish message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(), jsonString.c_str());
|
||||||
|
pubSub.publish(topicJson.c_str(), jsonString.c_str(), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("MQTT not connected, queueing packet\n");
|
||||||
|
if (mqttQueue.numFree() == 0) {
|
||||||
|
DEBUG_MSG("NOTE: MQTT queue is full, discarding oldest\n");
|
||||||
|
ServiceEnvelope *d = mqttQueue.dequeuePtr(0);
|
||||||
|
if (d)
|
||||||
|
mqttPool.release(d);
|
||||||
|
}
|
||||||
|
// make a copy of serviceEnvelope and queue it
|
||||||
|
ServiceEnvelope *copied = mqttPool.allocCopy(*env);
|
||||||
|
assert(mqttQueue.enqueue(copied, 0));
|
||||||
}
|
}
|
||||||
|
mqttPool.release(env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "concurrency/OSThread.h"
|
#include "concurrency/OSThread.h"
|
||||||
#include "mesh/Channels.h"
|
#include "mesh/Channels.h"
|
||||||
|
#include "mesh/generated/mqtt.pb.h"
|
||||||
#include <PubSubClient.h>
|
#include <PubSubClient.h>
|
||||||
#if HAS_WIFI
|
#if HAS_WIFI
|
||||||
#include <WiFiClient.h>
|
#include <WiFiClient.h>
|
||||||
@@ -12,6 +13,8 @@
|
|||||||
#include <EthernetClient.h>
|
#include <EthernetClient.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MAX_MQTT_QUEUE 32
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Our wrapper/singleton for sending/receiving MQTT "udp" packets. This object isolates the MQTT protocol implementation from
|
* Our wrapper/singleton for sending/receiving MQTT "udp" packets. This object isolates the MQTT protocol implementation from
|
||||||
* the two components that use it: MQTTPlugin and MQTTSimInterface.
|
* the two components that use it: MQTTPlugin and MQTTSimInterface.
|
||||||
@@ -52,6 +55,10 @@ class MQTT : private concurrency::OSThread
|
|||||||
bool connected();
|
bool connected();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
PointerQueue<ServiceEnvelope> mqttQueue;
|
||||||
|
|
||||||
|
int reconnectCount = 0;
|
||||||
|
|
||||||
virtual int32_t runOnce() override;
|
virtual int32_t runOnce() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -332,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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user