Merge branch 'develop' into gps-toggle-final

raspi-portduino
Thomas Göttgens 2022-12-16 20:58:53 +01:00 zatwierdzone przez GitHub
commit c577e09183
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
38 zmienionych plików z 967 dodań i 464 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -1,6 +1,6 @@
{
"build": {
"arduino":{
"arduino": {
"ldscript": "esp32s3_out.ld"
},
"core": "esp32",
@ -8,9 +8,7 @@
"-DBOARD_HAS_PSRAM",
"-DLILYGO_TBEAM_S3_CORE",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_DFU_ON_BOOT=1",
"-DARDUINO_USB_MSC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],

@ -1 +1 @@
Subproject commit 0a59599589bc77763e76302e533a4c4bfa5ec80e
Subproject commit 737d1fc01bd7f57e48e9b8cd53b780b314b09c5b

Wyświetl plik

@ -4,6 +4,7 @@
#include "concurrency/OSThread.h"
#include "configuration.h"
#include "graphics/Screen.h"
#include "modules/ExternalNotificationModule.h"
#include "power.h"
#include <OneButton.h>
@ -115,6 +116,10 @@ class ButtonThread : public concurrency::OSThread
{
// DEBUG_MSG("press!\n");
#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) ||
!moduleConfig.canned_message.enabled) {
powerFSM.trigger(EVENT_PRESS);

Wyświetl plik

@ -182,6 +182,9 @@ Power::Power() : OSThread("Power")
{
statusHandler = {};
low_voltage_counter = 0;
#ifdef DEBUG_HEAP
lastheap = ESP.getFreeHeap();
#endif
}
bool Power::analogInit()
@ -284,7 +287,10 @@ void Power::readPowerStatus()
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
newStatus.notifyObservers(&powerStatus2);
#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
// 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
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) {
// t-beam s3 core
@ -510,6 +519,8 @@ bool Power::axpChipInit()
//Set the constant current charging current of AXP2101, temporarily use 500mA by default
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");
//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
PMU->setSysPowerDownVoltage(2600);

Wyświetl plik

@ -329,11 +329,8 @@ static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, i
display->drawString(64 + x, y, "Updating");
display->setFont(FONT_SMALL);
if ((millis() / 1000) % 2) {
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . .");
} else {
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . ");
}
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawStringMaxWidth(0 + x, 2 + y + FONT_HEIGHT_SMALL *2, x + display->getWidth(), "Please be patient and do not power off.");
}
/// 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
// the max length of this buffer is much longer than we can possibly print
static char tempBuf[237];
MeshPacket &mp = devicestate.rx_text_message;
NodeInfo *node = nodeDB.getNode(getFrom(&mp));
// 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
// be wrapped. Currently only spaces and "-" are allowed for wrapping
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);
// the max length of this buffer is much longer than we can possibly print
static char tempBuf[96];
snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.payload.bytes);
display->drawStringMaxWidth(4 + x, 10 + y, SCREEN_WIDTH - (6 + x), tempBuf);
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK);
display->drawStringf(0 + x, 0 + y, tempBuf, "From: %s", (node && node->has_user) ? node->user.short_name : "???");
display->drawStringf(1 + x, 0 + y, tempBuf, "From: %s", (node && node->has_user) ? node->user.short_name : "???");
display->setColor(WHITE);
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
@ -395,6 +393,10 @@ static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char *
int xo = x, yo = y;
while (*f) {
display->drawString(xo, yo, *f);
if (display->getColor() == BLACK)
display->drawString(xo + 1, yo, *f);
display->setColor(WHITE);
yo += FONT_HEIGHT_SMALL;
if (yo > SCREEN_HEIGHT - FONT_HEIGHT_SMALL) {
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());
display->drawFastImage(x, y, 8, 8, imgUser);
display->drawString(x + 10, y - 2, usersString);
display->drawString(x + 11, y - 2, usersString);
}
// 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) {
// GPS coordinates are currently fixed
display->drawString(x - 1, y - 2, "Fixed GPS");
display->drawString(x, y - 2, "Fixed GPS");
return;
}
if (!gps->getIsConnected()) {
display->drawString(x, y - 2, "No GPS");
display->drawString(x + 1, y - 2, "No GPS");
return;
}
display->drawFastImage(x, y, 6, 8, gps->getHasLock() ? imgPositionSolid : imgPositionEmpty);
if (!gps->getHasLock()) {
display->drawString(x + 8, y - 2, "No sats");
display->drawString(x + 9, y - 2, "No sats");
return;
} else {
char satsString[3];
@ -685,16 +691,16 @@ static uint16_t getCompassDiam(OLEDDisplay *display)
{
uint16_t diam = 0;
// get the smaller of the 2 dimensions and subtract 20
if(display->getWidth() > display->getHeight()) {
diam = display->getHeight();
if(display->getWidth() > (display->getHeight() - FONT_HEIGHT_SMALL)) {
diam = display->getHeight() - FONT_HEIGHT_SMALL;
// if 2/3 of the other size would be smaller, use that
if (diam > (display->getWidth() * 2 / 3)) {
diam = display->getWidth() * 2 / 3;
}
} else {
diam = display->getWidth();
if (diam > (display->getHeight() * 2 / 3)) {
diam = display->getHeight() * 2 / 3;
if (diam > ((display->getHeight() - FONT_HEIGHT_SMALL) * 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
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";
static char signalStr[20];
@ -804,7 +812,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
// 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;
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->drawCircle(compassX, compassY, getCompassDiam(display) / 2);
display->setColor(BLACK);
// Must be after distStr is populated
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
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK);
char channelStr[20];
{
concurrency::LockGuard guard(&lock);
@ -1382,22 +1394,24 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// Display power status
if (powerStatus->getHasBattery())
drawBattery(display, x, y + 2, imgBattery, powerStatus);
drawBattery(display, x + 1, y + 3, imgBattery, powerStatus);
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
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus);
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 3, nodeStatus);
// Display GPS status
if (!config.position.gps_enabled){
int16_t yPos = y + 2;
#ifdef GPS_POWER_TOGGLE
int16_t yPos = y + 2;
#ifdef GPS_POWER_TOGGLE
yPos = (y + 10 + FONT_HEIGHT_SMALL);
#endif
drawGPSpowerstat(display, x, yPos, gpsStatus);
#endif
drawGPSpowerstat(display, x, yPos, gpsStatus);
} else {
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 3, gpsStatus);
}
display->setColor(WHITE);
// Draw the channel name
display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr);
// 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
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) {
display->drawString(x, y, String("WiFi: Not Connected"));
display->drawString(x + 1, y, String("WiFi: Not Connected"));
} else {
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,
"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_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
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK);
char batStr[20];
if (powerStatus->getHasBattery()) {
int batV = powerStatus->getBatteryVoltageMv() / 1000;
@ -1555,9 +1581,11 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
// Line 1
display->drawString(x, y, batStr);
display->drawString(x + 1, y, batStr);
} else {
// Line 1
display->drawString(x, y, String("USB"));
display->drawString(x + 1, y, String("USB"));
}
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) - 1, y, mode);
// Line 2
uint32_t currentMillis = millis();
@ -1602,6 +1631,8 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
// minutes %= 60;
// hours %= 24;
display->setColor(WHITE);
// Show uptime as days, hours, minutes OR seconds
String uptime;
if (days >= 2)

Wyświetl plik

@ -21,6 +21,7 @@ class Screen
void startBluetoothPinScreen(uint32_t pin) {}
void stopBluetoothPinScreen() {}
void startRebootScreen() {}
void startFirmwareUpdateScreen() {}
};
}

Wyświetl plik

@ -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 };
#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

Wyświetl plik

@ -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,
};

Wyświetl plik

@ -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, };

Wyświetl plik

@ -41,6 +41,11 @@ void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c)
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);
// 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

Wyświetl plik

@ -2,6 +2,7 @@
#include "PacketHistory.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)

Wyświetl plik

@ -215,9 +215,9 @@ void NodeDB::installDefaultModuleConfig()
moduleConfig.has_external_notification = true;
moduleConfig.has_canned_message = true;
strncpy(moduleConfig.mqtt.address, default_mqtt_address, sizeof(default_mqtt_address));
strncpy(moduleConfig.mqtt.username, default_mqtt_username, sizeof(default_mqtt_username));
strncpy(moduleConfig.mqtt.password, default_mqtt_password, sizeof(default_mqtt_password));
strncpy(moduleConfig.mqtt.address, default_mqtt_address, sizeof(moduleConfig.mqtt.address));
strncpy(moduleConfig.mqtt.username, default_mqtt_username, sizeof(moduleConfig.mqtt.username));
strncpy(moduleConfig.mqtt.password, default_mqtt_password, sizeof(moduleConfig.mqtt.password));
initModuleConfigIntervals();
}

Wyświetl plik

@ -3,6 +3,7 @@
#include "NodeDB.h"
#include "SPILock.h"
#include "configuration.h"
#include "main.h"
#include "error.h"
#include "mesh-pb-constants.h"
#include <pb_decode.h>
@ -87,10 +88,8 @@ bool RadioLibInterface::canSendImmediately()
if (busyTx && (millis() - lastTxStart > 60000)) {
DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n");
RECORD_CRITICALERROR(CriticalErrorCode_TRANSMIT_FAILED);
#ifdef ARCH_ESP32
if (busyTx && (millis() - lastTxStart > 65000)) // After 5s more, reboot
ESP.restart();
#endif
// reboot in 5 seconds when this condition occurs.
rebootAtMsec = lastTxStart + 65000;
}
if (busyRx)
DEBUG_MSG("Can not send yet, busyRx\n");
@ -386,6 +385,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
int res = iface->startTransmit(radiobuf, numbytes);
if (res != RADIOLIB_ERR_NONE) {
DEBUG_MSG("startTransmit failed, error=%d\n", res);
RECORD_CRITICALERROR(CriticalErrorCode_RADIO_SPI_BUG);
// This send failed, but make sure to 'complete' it properly

Wyświetl plik

@ -151,7 +151,7 @@ extern const pb_msgdesc_t LocalModuleConfig_msg;
/* Maximum encoded size of messages (where known) */
#define LocalConfig_size 387
#define LocalModuleConfig_size 358
#define LocalModuleConfig_size 376
#ifdef __cplusplus
} /* extern "C" */

Wyświetl plik

@ -93,6 +93,13 @@ typedef struct _ModuleConfig_ExternalNotificationConfig {
bool alert_message;
bool alert_bell;
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;
typedef struct _ModuleConfig_MQTTConfig {
@ -187,7 +194,7 @@ extern "C" {
#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_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_RangeTestConfig_init_default {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_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_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_RangeTestConfig_init_zero {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_bell_tag 6
#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_address_tag 2
#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, alert_message, 5) \
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_DEFAULT NULL
@ -391,7 +412,7 @@ extern const pb_msgdesc_t ModuleConfig_CannedMessageConfig_msg;
/* Maximum encoded size of messages (where known) */
#define ModuleConfig_AudioConfig_size 19
#define ModuleConfig_CannedMessageConfig_size 49
#define ModuleConfig_ExternalNotificationConfig_size 22
#define ModuleConfig_ExternalNotificationConfig_size 40
#define ModuleConfig_MQTTConfig_size 169
#define ModuleConfig_RangeTestConfig_size 10
#define ModuleConfig_SerialConfig_size 26

Wyświetl plik

@ -82,6 +82,9 @@ typedef enum _PortNum {
Maintained by GitHub user GUVWAF.
Project files at https://github.com/GUVWAF/Meshtasticator */
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.
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)) */

Wyświetl plik

@ -69,10 +69,10 @@ typedef struct _EnvironmentMetrics {
/* Types of Measurements the telemetry module is equipped to handle */
typedef struct _Telemetry {
/* 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
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).
/* 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
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).
seconds since 1970 */
uint32_t time;
pb_size_t which_variant;

Wyświetl plik

@ -1,7 +1,7 @@
#include "mesh/http/WiFiAPClient.h"
#include "NodeDB.h"
#include "RTC.h"
#include "concurrency/Periodic.h"
#include "mesh/http/WiFiAPClient.h"
#include "configuration.h"
#include "main.h"
#include "mesh/http/WebServer.h"
@ -37,9 +37,9 @@ bool APStartupComplete = 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()
{
@ -56,29 +56,15 @@ static int32_t reconnectWiFi()
// Make sure we clear old connection credentials
WiFi.disconnect(false, true);
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;
}
DEBUG_MSG("Reconnecting to WiFi access point %s\n",wifiName);
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(wifiName, wifiPsw);
}
#ifndef DISABLE_NTP
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()) {
DEBUG_MSG("NTP Request Success - Setting RTCQualityNTP if needed\n");
@ -129,7 +115,7 @@ static void onNetworkConnected()
{
if (!APStartupComplete) {
// Start web server
DEBUG_MSG("... Starting network services\n");
DEBUG_MSG("Starting network services\n");
// start mdns
if (!MDNS.begin("Meshtastic")) {
@ -168,6 +154,8 @@ bool initWifi()
createSSLCert();
esp_wifi_set_storage(WIFI_STORAGE_RAM); // Disable flash storage for WiFi credentials
if (!*wifiPsw) // Treat empty password as no password
wifiPsw = NULL;
@ -194,7 +182,7 @@ bool initWifi()
WiFi.onEvent(
[](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);
/*
@ -221,91 +209,137 @@ bool initWifi()
// Called by the Espressif SDK to
static void WiFiEvent(WiFiEvent_t event)
{
DEBUG_MSG("************ [WiFi-event] event: %d ************\n", event);
DEBUG_MSG("WiFi-Event %d: ", event);
switch (event) {
case SYSTEM_EVENT_WIFI_READY:
case ARDUINO_EVENT_WIFI_READY:
DEBUG_MSG("WiFi interface ready\n");
break;
case SYSTEM_EVENT_SCAN_DONE:
case ARDUINO_EVENT_WIFI_SCAN_DONE:
DEBUG_MSG("Completed scan for access points\n");
break;
case SYSTEM_EVENT_STA_START:
case ARDUINO_EVENT_WIFI_STA_START:
DEBUG_MSG("WiFi station started\n");
break;
case SYSTEM_EVENT_STA_STOP:
case ARDUINO_EVENT_WIFI_STA_STOP:
DEBUG_MSG("WiFi station stopped\n");
break;
case SYSTEM_EVENT_STA_CONNECTED:
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
DEBUG_MSG("Connected to access point\n");
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
DEBUG_MSG("Disconnected from WiFi access point\n");
WiFi.disconnect(false, true);
needReconnect = true;
wifiReconnect->setIntervalFromNow(1000);
break;
case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE:
DEBUG_MSG("Authentication mode of access point has changed\n");
break;
case SYSTEM_EVENT_STA_GOT_IP:
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
DEBUG_MSG("Obtained IP address: ");
Serial.println(WiFi.localIP());
onNetworkConnected();
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");
WiFi.disconnect(false, true);
needReconnect = true;
wifiReconnect->setIntervalFromNow(1000);
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");
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");
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");
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");
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");
break;
case SYSTEM_EVENT_AP_STOP:
case ARDUINO_EVENT_WIFI_AP_STOP:
DEBUG_MSG("WiFi access point stopped\n");
break;
case SYSTEM_EVENT_AP_STACONNECTED:
case ARDUINO_EVENT_WIFI_AP_STACONNECTED:
DEBUG_MSG("Client connected\n");
break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED:
DEBUG_MSG("Client disconnected\n");
break;
case SYSTEM_EVENT_AP_STAIPASSIGNED:
case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED:
DEBUG_MSG("Assigned IP address to client\n");
break;
case SYSTEM_EVENT_AP_PROBEREQRECVED:
case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED:
DEBUG_MSG("Received probe request\n");
break;
case SYSTEM_EVENT_GOT_IP6:
case ARDUINO_EVENT_WIFI_AP_GOT_IP6:
DEBUG_MSG("IPv6 is preferred\n");
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");
break;
case SYSTEM_EVENT_ETH_STOP:
case ARDUINO_EVENT_ETH_STOP:
DEBUG_MSG("Ethernet stopped\n");
break;
case SYSTEM_EVENT_ETH_CONNECTED:
case ARDUINO_EVENT_ETH_CONNECTED:
DEBUG_MSG("Ethernet connected\n");
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
case ARDUINO_EVENT_ETH_DISCONNECTED:
DEBUG_MSG("Ethernet disconnected\n");
break;
case SYSTEM_EVENT_ETH_GOT_IP:
DEBUG_MSG("Obtained IP address (SYSTEM_EVENT_ETH_GOT_IP)\n");
case ARDUINO_EVENT_ETH_GOT_IP:
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;
default:
break;

Wyświetl plik

@ -1,6 +1,7 @@
#pragma once
#include "configuration.h"
#include "concurrency/Periodic.h"
#include <Arduino.h>
#include <functional>
@ -8,6 +9,9 @@
#include <WiFi.h>
#endif
extern bool needReconnect;
extern concurrency::Periodic *wifiReconnect;
/// @return true if wifi is now in use
bool initWifi();

Wyświetl plik

@ -112,12 +112,15 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
#ifdef ARCH_ESP32
if (BleOta::getOtaAppVersion().isEmpty()) {
DEBUG_MSG("No OTA firmware available, scheduling regular reboot in %d seconds\n", s);
screen->startRebootScreen();
}else{
screen->startFirmwareUpdateScreen();
BleOta::switchToOtaApp();
DEBUG_MSG("Rebooting to OTA in %d seconds\n", s);
}
#else
DEBUG_MSG("Not on ESP32, scheduling regular reboot in %d seconds\n", s);
screen->startRebootScreen();
#endif
rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000);
break;

Wyświetl plik

@ -11,41 +11,9 @@
#define PIN_BUZZER false
#endif
//#include <assert.h>
/*
Documentation:
https://github.com/meshtastic/firmware/blob/master/docs/software/modules/ExternalNotificationModule.md
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.
https://meshtastic.org/docs/settings/moduleconfig/external-notification
*/
// Default configurations
@ -58,56 +26,97 @@
#define ASCII_BELL 0x07
bool externalCurrentState = 0;
uint32_t externalTurnedOn = 0;
ExternalNotificationModule *externalNotificationModule;
bool externalCurrentState[3] = {};
uint32_t externalTurnedOn[3] = {};
int32_t ExternalNotificationModule::runOnce()
{
/*
Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI.
*/
// 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 (moduleConfig.external_notification.use_pwm || !moduleConfig.external_notification.enabled) {
return INT32_MAX; // we don't need this thread here...
} else {
// 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
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
millis()) {
DEBUG_MSG("Turning off external notification\n");
setExternalOff();
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) {
getExternal(0) ? setExternalOff(0) : setExternalOn(0);
}
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;
}
}
void ExternalNotificationModule::setExternalOn()
void ExternalNotificationModule::setExternalOn(uint8_t index)
{
externalCurrentState = 1;
externalTurnedOn = millis();
externalCurrentState[index] = 1;
externalTurnedOn[index] = millis();
digitalWrite(output,
(moduleConfig.external_notification.active ? true : false));
switch(index) {
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,
(moduleConfig.external_notification.active ? false : true));
switch(index) {
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.
*/
// moduleConfig.external_notification.enabled = 1;
// moduleConfig.external_notification.alert_message = 1;
// moduleConfig.external_notification.enabled = true;
// 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.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) {
@ -141,8 +155,20 @@ ExternalNotificationModule::ExternalNotificationModule()
// Set the direction of a pin
DEBUG_MSG("Using Pin %i in digital mode\n", output);
pinMode(output, OUTPUT);
// Turn off the pin
setExternalOff();
setExternalOff(0);
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 {
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()) {
// TODO: This may be a problem if messages are sent in unicide, but I'm not sure if it will.
// Need to know if and how this could be a problem.
// Check if the message contains a bell character. Don't do this loop for every pin, just once.
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) {
auto &p = mp.decoded;
DEBUG_MSG("externalNotificationModule - Notification Bell\n");
for (int i = 0; i < p.payload.size; i++) {
if (p.payload.bytes[i] == ASCII_BELL) {
if (!moduleConfig.external_notification.use_pwm) {
setExternalOn();
if (containsBell) {
DEBUG_MSG("externalNotificationModule - Notification Bell\n");
if (!moduleConfig.external_notification.use_pwm) {
setExternalOn(0);
if (moduleConfig.external_notification.nag_timeout) {
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
} 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) {
DEBUG_MSG("externalNotificationModule - Notification Module\n");
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 {
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 {

Wyświetl plik

@ -17,18 +17,19 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
public:
ExternalNotificationModule();
void setExternalOn();
void setExternalOff();
void getExternal();
uint32_t nagCycleCutoff = UINT32_MAX;
void setExternalOn(uint8_t index = 0);
void setExternalOff(uint8_t index = 0);
bool getExternal(uint8_t index = 0);
protected:
// virtual MeshPacket *allocReply();
/** 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
*/
virtual ProcessMessage handleReceived(const MeshPacket &mp) override;
virtual int32_t runOnce() override;
};
extern ExternalNotificationModule *externalNotificationModule;

Wyświetl plik

@ -11,6 +11,7 @@
#include "modules/ReplyModule.h"
#include "modules/RoutingModule.h"
#include "modules/TextMessageModule.h"
#include "modules/TraceRouteModule.h"
#include "modules/WaypointModule.h"
#if HAS_TELEMETRY
#include "modules/Telemetry/DeviceTelemetry.h"
@ -40,6 +41,7 @@ void setupModules()
positionModule = new PositionModule();
waypointModule = new WaypointModule();
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
// to a global variable.
@ -67,7 +69,7 @@ void setupModules()
#ifdef ARCH_ESP32
// Only run on an esp32 based device.
audioModule = new AudioModule();
new ExternalNotificationModule();
externalNotificationModule = new ExternalNotificationModule();
storeForwardModule = new StoreForwardModule();

Wyświetl plik

@ -82,7 +82,7 @@ SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio")
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
without having to configure it from the PythonAPI or WebUI.
@ -214,7 +214,6 @@ int32_t SerialModule::runOnce()
MeshPacket *SerialModuleRadio::allocReply()
{
auto reply = allocDataPacket(); // Allocate a packet for sending
return reply;
@ -236,7 +235,7 @@ void SerialModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
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) {
auto &p = mp.decoded;
@ -266,7 +265,12 @@ ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_DEFAULT ||
moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_SIMPLE) {
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) {
// TODO this needs to be implemented
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) {

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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;

Wyświetl plik

@ -10,6 +10,10 @@
#include <assert.h>
#ifdef OLED_RU
#include "graphics/fonts/OLEDDisplayFontsRU.h"
#endif
/*
AudioModule
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)
#endif
//int16_t 1KHz sine test tone
int16_t Sine1KHz[8] = { -21210 , -30000, -21210, 0 , 21210 , 30000 , 21210, 0 };
int Sine1KHz_index = 0;
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
// The screen is bigger so use bigger fonts
#define FONT_SMALL ArialMT_Plain_16
#define FONT_MEDIUM ArialMT_Plain_24
#define FONT_LARGE ArialMT_Plain_24
#else
#ifdef OLED_RU
#define FONT_SMALL ArialMT_Plain_10_RU
#else
#define FONT_SMALL ArialMT_Plain_10
#endif
#define FONT_MEDIUM ArialMT_Plain_16
#define FONT_LARGE ArialMT_Plain_24
#endif
#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)
{
// 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));
DEBUG_MSG("Starting codec2 task\n");
while (true) {
uint32_t tcount = ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(10000));
if (tcount != 0) {
if (audioModule->radio_state == RadioState::tx) {
// Apply the TX filter
for (int i = 0; i < audioModule->adc_buffer_size; 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);
//increment the pointer where the encoded frame must be saved
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)))
{
//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->tx_encode_frame_index = sizeof(audioModule->tx_header);
}
}
if (audioModule->radio_state == RadioState::rx) {
//Make a cycle to get each codec2 frame from the received frame
for (int i = 0; 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);
size_t bytesOut = 0;
i2s_write(I2S_PORT, &audioModule->output_buffer, audioModule->adc_buffer_size, &bytesOut, pdMS_TO_TICKS(500));
size_t bytesOut = 0;
if (memcmp(audioModule->rx_encode_frame, &audioModule->tx_header, sizeof(audioModule->tx_header)) == 0) {
for (int i = 4; i < audioModule->rx_encode_frame_index; i += audioModule->encode_codec_size)
{
codec2_decode(audioModule->codec2, audioModule->output_buffer, audioModule->rx_encode_frame + i);
i2s_write(I2S_PORT, &audioModule->output_buffer, audioModule->adc_buffer_size, &bytesOut, pdMS_TO_TICKS(500));
}
} else {
// if the buffer header does not match our own codec, make a temp decoding setup.
CODEC2* tmp_codec2 = codec2_create(audioModule->rx_encode_frame[3]);
codec2_set_lpc_post_filter(tmp_codec2, 1, 0, 0.8, 0.2);
int tmp_encode_codec_size = (codec2_bits_per_frame(tmp_codec2) + 7) / 8;
int tmp_adc_buffer_size = codec2_samples_per_frame(tmp_codec2);
for (int i = 4; i < audioModule->rx_encode_frame_index; i += tmp_encode_codec_size)
{
codec2_decode(tmp_codec2, audioModule->output_buffer, audioModule->rx_encode_frame + i);
i2s_write(I2S_PORT, &audioModule->output_buffer, tmp_adc_buffer_size, &bytesOut, pdMS_TO_TICKS(500));
}
codec2_destroy(tmp_codec2);
}
}
}
@ -91,8 +119,15 @@ void run_codec2(void* parameter)
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)) {
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);
memcpy(tx_header.magic,c2_magic,sizeof(c2_magic));
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);
xTaskCreate(&run_codec2, "codec2_task", 30000, NULL, 5, &codec2HandlerTask);
} else {
DEBUG_MSG("♪♫♪ Codec2 disabled (AudioModule %d, Region %s, permitted %d)\n", moduleConfig.audio.codec2_enabled, myRegion->name, myRegion->audioPermitted);
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;
if (firstTime) {
// Set up I2S Processor configuration. This will produce 16bit samples at 8 kHz instead of 12 from the ADC
DEBUG_MSG("♪♫♪ Initializing I2S SD: %d DIN: %d WS: %d SCK:%d\n", moduleConfig.audio.i2s_sd, moduleConfig.audio.i2s_din, moduleConfig.audio.i2s_ws, moduleConfig.audio.i2s_sck);
DEBUG_MSG("Initializing I2S SD: %d DIN: %d WS: %d SCK: %d\n", moduleConfig.audio.i2s_sd, moduleConfig.audio.i2s_din, moduleConfig.audio.i2s_ws, moduleConfig.audio.i2s_sck);
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | (moduleConfig.audio.i2s_sd ? I2S_MODE_RX : 0) | (moduleConfig.audio.i2s_din ? I2S_MODE_TX : 0)),
.sample_rate = 8000,
@ -130,7 +189,7 @@ int32_t AudioModule::runOnce()
};
res = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
if(res != ESP_OK)
DEBUG_MSG("♪♫♪ Failed to install I2S driver: %d\n", res);
DEBUG_MSG("Failed to install I2S driver: %d\n", res);
const i2s_pin_config_t pin_config = {
.bck_io_num = moduleConfig.audio.i2s_sck,
@ -140,36 +199,41 @@ int32_t AudioModule::runOnce()
};
res = i2s_set_pin(I2S_PORT, &pin_config);
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);
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;
// 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);
firstTime = false;
} else {
UIFrameEvent e = {false, true};
// 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 (radio_state == RadioState::rx) {
DEBUG_MSG("♪♫♪ PTT pressed, switching to TX\n");
DEBUG_MSG("PTT pressed, switching to TX\n");
radio_state = RadioState::tx;
e.frameChanged = true;
this->notifyObservers(&e);
}
} else {
if (radio_state == RadioState::tx) {
DEBUG_MSG("PTT released, switching to RX\n");
if (tx_encode_frame_index > sizeof(tx_header)) {
// Send the incomplete frame
DEBUG_MSG("♪♫♪ Sending %d codec2 bytes (incomplete)\n", tx_encode_frame_index);
DEBUG_MSG("Sending %d codec2 bytes (incomplete)\n", tx_encode_frame_index);
sendPayload();
}
DEBUG_MSG("♪♫♪ PTT released, switching to RX\n");
tx_encode_frame_index = sizeof(tx_header);
radio_state = RadioState::rx;
e.frameChanged = true;
this->notifyObservers(&e);
}
}
if (radio_state == RadioState::tx) {
@ -194,7 +258,7 @@ int32_t AudioModule::runOnce()
}
return 100;
} else {
DEBUG_MSG("♪♫♪ Audio Module Disabled\n");
DEBUG_MSG("Audio Module Disabled\n");
return INT32_MAX;
}
@ -202,17 +266,25 @@ int32_t AudioModule::runOnce()
MeshPacket *AudioModule::allocReply()
{
auto reply = allocDataPacket(); // Allocate a packet for sending
auto reply = allocDataPacket();
return reply;
}
bool AudioModule::shouldDraw()
{
if (!moduleConfig.audio.codec2_enabled) {
return false;
}
return (radio_state == RadioState::tx);
}
void AudioModule::sendPayload(NodeNum dest, bool wantReplies)
{
MeshPacket *p = allocReply();
p->to = dest;
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->decoded.payload.size = tx_encode_frame_index;

Wyświetl plik

@ -10,6 +10,8 @@
#include <functional>
#include <codec2.h>
#include <ButterworthFilter.h>
#include <OLEDDisplay.h>
#include <OLEDDisplayUi.h>
enum RadioState { standby, rx, tx };
@ -28,7 +30,7 @@ struct c2_header {
#define AUDIO_MODULE_RX_BUFFER 128
#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:
unsigned char rx_encode_frame[Constants_DATA_PAYLOAD_LEN] = {};
@ -50,6 +52,8 @@ class AudioModule : public SinglePortModule, private concurrency::OSThread
AudioModule();
bool shouldDraw();
/**
* Send our payload into the mesh
*/
@ -63,6 +67,15 @@ class AudioModule : public SinglePortModule, private concurrency::OSThread
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
* @return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
*/

Wyświetl plik

@ -16,52 +16,50 @@ StoreForwardModule *storeForwardModule;
int32_t StoreForwardModule::runOnce()
{
#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) {
// 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) {
// 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++;
}
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 {
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 {
DEBUG_MSG("Store & Forward Module - Disabled (is_router = false)\n");
} else if (millis() - lastHeartbeat > 300000) {
lastHeartbeat = millis();
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);
}
} else {
DEBUG_MSG("Store & Forward Module - Disabled\n");
return (INT32_MAX);
return (this->packetTimeMax);
}
#endif
return (INT32_MAX);
}
@ -76,12 +74,7 @@ void StoreForwardModule::populatePSRAM()
https://learn.upesy.com/en/programmation/psram.html#psram-tab
*/
DEBUG_MSG("Before PSRAM initilization:\n");
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("Before PSRAM initilization: heap %d/%d PSRAM %d/%d\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreePsram(), ESP.getPsramSize());
this->packetHistoryTXQueue =
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)));
DEBUG_MSG("After PSRAM initilization:\n");
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);
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);
}
void StoreForwardModule::historyReport()
{
DEBUG_MSG("Iterating through the message history...\n");
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");
// The router node should not be sending messages as a client.
if (getFrom(&mp) != nodeDB.getNodeNum()) {
// The router node should not be sending messages as a client. Unless he is a ROUTER_CLIENT
if ((getFrom(&mp) != nodeDB.getNodeNum()) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) {
if (mp.decoded.portnum == PortNum_TEXT_MESSAGE_APP) {
DEBUG_MSG("Packet came from - PortNum_TEXT_MESSAGE_APP\n");
@ -264,6 +250,7 @@ ProcessMessage StoreForwardModule::handleReceived(const MeshPacket &mp)
} else {
storeForwardModule->historySend(1000 * 60, getFrom(&mp));
}
} else if ((p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') && (p.payload.bytes[2] == 'm') &&
(p.payload.bytes[3] == 0x00)) {
strlcpy(this->routerMessage,
@ -278,14 +265,12 @@ ProcessMessage StoreForwardModule::handleReceived(const MeshPacket &mp)
}
} 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 {
DEBUG_MSG("Packet came from an unknown port %u\n", mp.decoded.portnum);
}
}
} else {
DEBUG_MSG("Store & Forward Module - Disabled\n");
}
#endif
@ -293,92 +278,107 @@ ProcessMessage StoreForwardModule::handleReceived(const MeshPacket &mp)
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 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) {
DEBUG_MSG("Packet came from an PortNum_TEXT_MESSAGE_APP port %u\n", mp.decoded.portnum);
return ProcessMessage::CONTINUE;
} 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);
if (mp.decoded.portnum != PortNum_STORE_FORWARD_APP) {
DEBUG_MSG("Packet came from port %u\n", mp.decoded.portnum);
return false;
} else {
DEBUG_MSG("Packet came from an UNKNOWN port %u\n", mp.decoded.portnum);
return ProcessMessage::CONTINUE;
}
DEBUG_MSG("Packet came from PortNum_STORE_FORWARD_APP port %u\n", mp.decoded.portnum);
switch (p->rr) {
case StoreAndForward_RequestResponse_CLIENT_ERROR:
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_ERROR\n");
break;
case StoreAndForward_RequestResponse_CLIENT_ERROR:
if(is_server) {
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_ERROR\n");
}
break;
case StoreAndForward_RequestResponse_CLIENT_HISTORY:
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_HISTORY\n");
case StoreAndForward_RequestResponse_CLIENT_HISTORY:
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.
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));
case StoreAndForward_RequestResponse_CLIENT_PING:
if(is_server) {
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_PING\n");
}
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()
: SinglePortModule("StoreForwardModule", PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("StoreForwardModule")
: concurrency::OSThread("StoreForwardModule"), ProtobufModule("StoreForward", PortNum_STORE_FORWARD_APP, &StoreAndForward_msg)
{
#ifdef ARCH_ESP32
@ -397,9 +397,9 @@ StoreForwardModule::StoreForwardModule()
if (moduleConfig.store_forward.enabled) {
// Router
if (config.device.role == Config_DeviceConfig_Role_ROUTER) {
DEBUG_MSG("Initializing Store & Forward Module - Enabled as Router\n");
if (ESP.getPsramSize()) {
if ((config.device.role == Config_DeviceConfig_Role_ROUTER) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) {
DEBUG_MSG("Initializing Store & Forward Module in Router mode\n");
if (ESP.getPsramSize() > 0) {
if (ESP.getFreePsram() >= 1024 * 1024) {
// Do the startup here
@ -416,26 +416,27 @@ StoreForwardModule::StoreForwardModule()
if (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)
this->heartbeat = moduleConfig.store_forward.heartbeat;
// Popupate PSRAM with our data structures.
this->populatePSRAM();
is_server = true;
} else {
DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n");
DEBUG_MSG("Store & Forward Module - Aborting Startup.\n");
DEBUG_MSG("Device has less than 1M of PSRAM free.\n");
DEBUG_MSG("Store & Forward Module - disabling server.\n");
}
} else {
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
} 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

Wyświetl plik

@ -1,6 +1,6 @@
#pragma once
#include "SinglePortModule.h"
#include "ProtobufModule.h"
#include "concurrency/OSThread.h"
#include "mesh/generated/storeforward.pb.h"
@ -18,9 +18,8 @@ struct PacketHistoryStruct {
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;
uint32_t busyTo = 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_index = 0;
uint32_t packetTimeMax = 2000;
uint32_t packetTimeMax = 5000;
unsigned long lastHeartbeat = 0;
bool is_client = false;
bool is_server = false;
public:
StoreForwardModule();
@ -78,7 +82,7 @@ class StoreForwardModule : public SinglePortModule, private concurrency::OSThrea
it
*/
virtual ProcessMessage handleReceived(const MeshPacket &mp) override;
virtual ProcessMessage handleReceivedProtobuf(const MeshPacket &mp, StoreAndForward *p);
virtual bool handleReceivedProtobuf(const MeshPacket &mp, StoreAndForward *p);
};

Wyświetl plik

@ -7,6 +7,7 @@
#include "mesh/Router.h"
#include "mesh/generated/mqtt.pb.h"
#include "mesh/generated/telemetry.pb.h"
#include "mesh/http/WiFiAPClient.h"
#include "sleep.h"
#if HAS_WIFI
#include <WiFi.h>
@ -20,6 +21,10 @@ String statusTopic = "msh/2/stat/";
String cryptTopic = "msh/2/c/"; // msh/2/c/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)
{
mqtt->onPublish(topic, payload, length);
@ -61,7 +66,27 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length)
} else {
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");
}
} else {
@ -101,7 +126,7 @@ void mqttInit()
new MQTT();
}
MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient)
MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient), mqttQueue(MAX_MQTT_QUEUE)
{
assert(!mqtt);
mqtt = this;
@ -148,14 +173,23 @@ void MQTT::reconnect()
DEBUG_MSG("MQTT connected\n");
enabled = true; // Start running background process again
runASAP = true;
reconnectCount = 0;
/// FIXME, include more information in the status text
bool ok = pubSub.publish(myStatus.c_str(), "online", true);
DEBUG_MSG("published %d\n", ok);
sendSubscriptions();
} else
DEBUG_MSG("Failed to contact MQTT server...\n");
} else {
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) {
reconnect();
// If we succeeded, start reading rapidly, else try again in 30 seconds (TCP connections are EXPENSIVE so try rarely)
return pubSub.connected() ? 20 : 30000;
// 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)
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
return 5000; // If we don't want connection now, check again in 5 secs
} else {
@ -231,33 +292,48 @@ void MQTT::onSend(const MeshPacket &mp, ChannelIndex chIndex)
{
auto &ch = channels.getByIndex(chIndex);
// don't bother sending if not connected...
if (pubSub.connected() && ch.settings.uplink_enabled) {
if (ch.settings.uplink_enabled) {
const char *channelId = channels.getGlobalId(chIndex); // FIXME, for now we just use the human name for the channel
ServiceEnvelope env = ServiceEnvelope_init_default;
env.channel_id = (char *)channelId;
env.gateway_id = owner.id;
env.packet = (MeshPacket *)&mp;
ServiceEnvelope *env = mqttPool.allocZeroed();
env->channel_id = (char *)channelId;
env->gateway_id = owner.id;
env->packet = (MeshPacket *)&mp;
// FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets
static uint8_t bytes[MeshPacket_size + 64];
size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), ServiceEnvelope_fields, &env);
// don't bother sending if not connected...
if (pubSub.connected()) {
String topic = cryptTopic + channelId + "/" + owner.id;
DEBUG_MSG("publish %s, %u bytes\n", topic.c_str(), numBytes);
// FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets
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) {
// handle json topic
auto jsonString = this->downstreamPacketToJson((MeshPacket *)&mp);
if (jsonString.length() != 0) {
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);
pubSub.publish(topic.c_str(), bytes, numBytes, false);
if (moduleConfig.mqtt.json_enabled) {
// handle json topic
auto jsonString = this->downstreamPacketToJson((MeshPacket *)&mp);
if (jsonString.length() != 0) {
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);
}
}

Wyświetl plik

@ -4,6 +4,7 @@
#include "concurrency/OSThread.h"
#include "mesh/Channels.h"
#include "mesh/generated/mqtt.pb.h"
#include <PubSubClient.h>
#if HAS_WIFI
#include <WiFiClient.h>
@ -12,6 +13,8 @@
#include <EthernetClient.h>
#endif
#define MAX_MQTT_QUEUE 32
/**
* 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.
@ -52,6 +55,10 @@ class MQTT : private concurrency::OSThread
bool connected();
protected:
PointerQueue<ServiceEnvelope> mqttQueue;
int reconnectCount = 0;
virtual int32_t runOnce() override;
private:

Wyświetl plik

@ -3,7 +3,9 @@
#include "esp_task_wdt.h"
#include "main.h"
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
#include "nimble/NimbleBluetooth.h"
#endif
#include "BleOta.h"
#include "mesh/http/WiFiAPClient.h"
@ -16,13 +18,9 @@
#include <nvs_flash.h>
#include "soc/rtc.h"
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
NimbleBluetooth *nimbleBluetooth;
void getMacAddr(uint8_t *dmac)
{
assert(esp_efuse_mac_get_default(dmac) == ESP_OK);
}
void setBluetoothEnable(bool on) {
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
#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)

Wyświetl plik

@ -40,6 +40,9 @@ class Power : private concurrency::OSThread
private:
uint8_t low_voltage_counter;
#ifdef DEBUG_HEAP
uint32_t lastheap;
#endif
};
extern Power *power;

Wyświetl plik

@ -332,6 +332,8 @@ void enableModemSleep()
#if CONFIG_IDF_TARGET_ESP32S3
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
esp32_config.max_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
#endif

Wyświetl plik

@ -169,6 +169,7 @@ static const uint8_t SCK = PIN_SPI_SCK;
IO4 <-> P0.04 (Arduino GPIO number 4)
IO5 <-> P0.09 (Arduino GPIO number 9)
IO6 <-> P0.10 (Arduino GPIO number 10)
IO7 <-> P0.28 (Arduino GPIO number 28)
SW1 <-> P0.01 (Arduino GPIO number 1)
A0 <-> P0.04/AIN2 (Arduino Analog A2
A1 <-> P0.31/AIN7 (Arduino Analog A7

Wyświetl plik

@ -169,6 +169,7 @@ static const uint8_t SCK = PIN_SPI_SCK;
IO4 <-> P0.04 (Arduino GPIO number 4)
IO5 <-> P0.09 (Arduino GPIO number 9)
IO6 <-> P0.10 (Arduino GPIO number 10)
IO7 <-> P0.28 (Arduino GPIO number 28)
SW1 <-> P0.01 (Arduino GPIO number 1)
A0 <-> P0.04/AIN2 (Arduino Analog A2
A1 <-> P0.31/AIN7 (Arduino Analog A7