Cherry Picking Stuff from develop...

This commit is contained in:
Thomas Göttgens 2022-12-21 13:36:38 +01:00
parent 220859d0aa
commit 7396d0f241
15 changed files with 220 additions and 122 deletions

View File

@ -1 +1 @@
cd protobufs && ..\nanopb-0.4.6\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs *.proto cd protobufs && ..\nanopb-0.4.7\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs *.proto

View File

@ -2,13 +2,13 @@
set -e set -e
echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.6 to be located in the" echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.7 to be located in the"
echo "firmware root directory if the following step fails, you should download the correct" echo "firmware root directory if the following step fails, you should download the correct"
echo "prebuilt binaries for your computer into nanopb-0.4.6" echo "prebuilt binaries for your computer into nanopb-0.4.7"
# the nanopb tool seems to require that the .options file be in the current directory! # the nanopb tool seems to require that the .options file be in the current directory!
cd protobufs cd protobufs
../nanopb-0.4.6/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated -I=../protobufs *.proto ../nanopb-0.4.7/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated -I=../protobufs *.proto
#echo "Regenerating protobuf documentation - if you see an error message" #echo "Regenerating protobuf documentation - if you see an error message"
#echo "you can ignore it unless doing a new protobuf release to github." #echo "you can ignore it unless doing a new protobuf release to github."

View File

@ -182,6 +182,9 @@ Power::Power() : OSThread("Power")
{ {
statusHandler = {}; statusHandler = {};
low_voltage_counter = 0; low_voltage_counter = 0;
#ifdef DEBUG_HEAP
lastheap = ESP.getFreeHeap();
#endif
} }
bool Power::analogInit() bool Power::analogInit()

View File

@ -117,6 +117,20 @@ float AirTime::utilizationTXPercent()
return (float(sum) / float(MS_IN_HOUR)) * 100; return (float(sum) / float(MS_IN_HOUR)) * 100;
} }
// Get the amount of minutes we have to be silent before we can send again
uint8_t AirTime::getSilentMinutes(float txPercent, float dutyCycle)
{
float newTxPercent = txPercent;
for (int8_t i = MINUTES_IN_HOUR-1; i >= 0; --i) {
newTxPercent -= ((float)this->utilizationTX[i] / (MS_IN_MINUTE * MINUTES_IN_HOUR / 100));
if (newTxPercent < dutyCycle)
return MINUTES_IN_HOUR-1-i;
}
return MINUTES_IN_HOUR;
}
AirTime::AirTime() : concurrency::OSThread("AirTime"),airtimes({}) { AirTime::AirTime() : concurrency::OSThread("AirTime"),airtimes({}) {
} }

View File

@ -29,6 +29,7 @@
#define PERIODS_TO_LOG 8 #define PERIODS_TO_LOG 8
#define MINUTES_IN_HOUR 60 #define MINUTES_IN_HOUR 60
#define SECONDS_IN_MINUTE 60 #define SECONDS_IN_MINUTE 60
#define MS_IN_MINUTE (SECONDS_IN_MINUTE * 1000)
#define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000) #define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000)
@ -57,6 +58,7 @@ class AirTime : private concurrency::OSThread
uint32_t getSecondsPerPeriod(); uint32_t getSecondsPerPeriod();
uint32_t getSecondsSinceBoot(); uint32_t getSecondsSinceBoot();
uint32_t *airtimeReport(reportTypes reportType); uint32_t *airtimeReport(reportTypes reportType);
uint8_t getSilentMinutes(float txPercent, float dutyCycle);
private: private:
bool firstTime = true; bool firstTime = true;

View File

@ -35,6 +35,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "mesh/Channels.h" #include "mesh/Channels.h"
#include "mesh/generated/deviceonly.pb.h" #include "mesh/generated/deviceonly.pb.h"
#include "modules/TextMessageModule.h" #include "modules/TextMessageModule.h"
#include "modules/esp32/StoreForwardModule.h"
#include "sleep.h" #include "sleep.h"
#include "target_specific.h" #include "target_specific.h"
#include "utils.h" #include "utils.h"
@ -95,17 +96,17 @@ static uint16_t displayWidth, displayHeight;
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) #if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
// The screen is bigger so use bigger fonts // The screen is bigger so use bigger fonts
#define FONT_SMALL ArialMT_Plain_16 #define FONT_SMALL ArialMT_Plain_16 // Height: 19
#define FONT_MEDIUM ArialMT_Plain_24 #define FONT_MEDIUM ArialMT_Plain_24 // Height: 28
#define FONT_LARGE ArialMT_Plain_24 #define FONT_LARGE ArialMT_Plain_24 // Height: 28
#else #else
#ifdef OLED_RU #ifdef OLED_RU
#define FONT_SMALL ArialMT_Plain_10_RU #define FONT_SMALL ArialMT_Plain_10_RU
#else #else
#define FONT_SMALL ArialMT_Plain_10 #define FONT_SMALL ArialMT_Plain_10 // Height: 13
#endif #endif
#define FONT_MEDIUM ArialMT_Plain_16 #define FONT_MEDIUM ArialMT_Plain_16 // Height: 19
#define FONT_LARGE ArialMT_Plain_24 #define FONT_LARGE ArialMT_Plain_24 // Height: 28
#endif #endif
#define fontHeight(font) ((font)[1] + 1) // height is position 1 #define fontHeight(font) ((font)[1] + 1) // height is position 1
@ -465,7 +466,11 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *no
{ {
char usersString[20]; char usersString[20];
sprintf(usersString, "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal()); sprintf(usersString, "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
display->drawFastImage(x, y + 3, 8, 8, imgUser);
#else
display->drawFastImage(x, y, 8, 8, imgUser); display->drawFastImage(x, y, 8, 8, imgUser);
#endif
display->drawString(x + 10, y - 2, usersString); display->drawString(x + 10, y - 2, usersString);
display->drawString(x + 11, y - 2, usersString); display->drawString(x + 11, y - 2, usersString);
} }
@ -513,19 +518,20 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
} }
//Draw status when gps is disabled by PMU //Draw status when gps is disabled by PMU
static void drawGPSpowerstat(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps){ static void drawGPSpowerstat(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
String displayLine = ""; {
displayLine = "GPS disabled"; #ifdef HAS_PMU
int16_t xPos = display->getStringWidth(displayLine); String displayLine = "GPS disabled";
#ifdef HAS_PMU int16_t xPos = display->getStringWidth(displayLine);
if (!config.position.gps_enabled){ if (!config.position.gps_enabled){
display->drawString(x + xPos, y, displayLine); display->drawString(x + xPos, y, displayLine);
#ifdef GPS_POWER_TOGGLE #ifdef GPS_POWER_TOGGLE
display->drawString(x + xPos, y - 2 + FONT_HEIGHT_SMALL, " by button"); display->drawString(x + xPos, y - 2 + FONT_HEIGHT_SMALL, " by button");
#endif #endif
//display->drawString(x + xPos, y + 2, displayLine); //display->drawString(x + xPos, y + 2, displayLine);
} }
#endif #endif
} }
static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps) static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
@ -860,29 +866,6 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
drawColumns(display, x, y, fields); drawColumns(display, x, y, fields);
} }
#if 0
void _screen_header()
{
if (!disp)
return;
// Message count
//snprintf(buffer, sizeof(buffer), "#%03d", ttn_get_count() % 1000);
//display->setTextAlignment(TEXT_ALIGN_LEFT);
//display->drawString(0, 2, buffer);
// Datetime
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(display->getWidth()/2, 2, gps.getTimeStr());
// Satellite count
display->setTextAlignment(TEXT_ALIGN_RIGHT);
char buffer[10];
display->drawString(display->getWidth() - SATELLITE_IMAGE_WIDTH - 4, 2, itoa(gps.satellites.value(), buffer, 10));
display->drawXbm(display->getWidth() - SATELLITE_IMAGE_WIDTH, 0, SATELLITE_IMAGE_WIDTH, SATELLITE_IMAGE_HEIGHT, SATELLITE_IMAGE);
}
#endif
// #ifdef RAK4630 // #ifdef RAK4630
// Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), // Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl),
// dispdev_oled(address, sda, scl), ui(&dispdev) // dispdev_oled(address, sda, scl), ui(&dispdev)
@ -1414,8 +1397,32 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
display->setColor(WHITE); display->setColor(WHITE);
// Draw the channel name // Draw the channel name
display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr); display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr);
// Draw our hardware ID to assist with bluetooth pairing // Draw our hardware ID to assist with bluetooth pairing. Either prefix with Info or S&F Logo
display->drawFastImage(x + SCREEN_WIDTH - (10) - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgInfo); if (moduleConfig.store_forward.enabled) {
if (millis() - storeForwardModule->lastHeartbeat > (storeForwardModule->heartbeatInterval * 1200)) { //no heartbeat, overlap a bit
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, imgQuestionL1);
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8, imgQuestionL2);
#else
display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgQuestion);
#endif
} else {
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 16, 8, imgSFL1);
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 16, 8, imgSFL2);
#else
display->drawFastImage(x + SCREEN_WIDTH - 13 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 11, 8, imgSF);
#endif
}
} else {
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, imgInfoL1);
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8, imgInfoL2);
#else
display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgInfo);
#endif
}
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT_SMALL, ourId); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT_SMALL, ourId);
// Draw any log messages // Draw any log messages

View File

@ -12,6 +12,18 @@ const uint8_t imgPower[] PROGMEM = { 0x40, 0x40, 0x40, 0x58, 0x48, 0x08,
const uint8_t imgUser[] PROGMEM = { 0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C }; const uint8_t imgUser[] PROGMEM = { 0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C };
const uint8_t imgPositionEmpty[] PROGMEM = { 0x20, 0x30, 0x28, 0x24, 0x42, 0xFF }; const uint8_t imgPositionEmpty[] PROGMEM = { 0x20, 0x30, 0x28, 0x24, 0x42, 0xFF };
const uint8_t imgPositionSolid[] PROGMEM = { 0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF }; const uint8_t imgPositionSolid[] PROGMEM = { 0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF };
const uint8_t imgInfo[] PROGMEM = { 0xFF, 0x81, 0x81, 0xB5, 0xB5, 0x81, 0x81, 0xFF };
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
const uint8_t imgQuestionL1[] PROGMEM = { 0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff };
const uint8_t imgQuestionL2[] PROGMEM = { 0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f };
const uint8_t imgInfoL1[] PROGMEM = { 0xff, 0x01, 0x01, 0x01, 0x1e, 0x7f, 0x1e, 0x01, 0x01, 0x01, 0x01, 0xff };
const uint8_t imgInfoL2[] PROGMEM = { 0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f };
const uint8_t imgSFL1[] PROGMEM = { 0xb6, 0x8f, 0x19, 0x11, 0x31, 0xe3, 0xc2, 0x01, 0x01, 0xf9, 0xf9, 0x89, 0x89, 0x89, 0x09, 0xeb};
const uint8_t imgSFL2[] PROGMEM = { 0x0e, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x00, 0x0f, 0x0f, 0x00, 0x08, 0x08, 0x08, 0x0f};
#else
const uint8_t imgInfo[] PROGMEM = { 0xff, 0x81, 0x00, 0xfb, 0xfb, 0x00, 0x81, 0xff };
const uint8_t imgQuestion[] PROGMEM = { 0xbf, 0x41, 0xc0, 0x8b, 0xdb, 0x70, 0xa1, 0xdf };
const uint8_t imgSF[] PROGMEM = { 0xd2, 0xb7, 0xad, 0xbb, 0x92, 0x01, 0xfd, 0xfd, 0x15, 0x85, 0xf5};
#endif
#include "img/icon.xbm" #include "img/icon.xbm"

View File

@ -162,6 +162,7 @@ void NodeDB::installDefaultConfig()
config.has_network = true; config.has_network = true;
config.has_bluetooth = true; config.has_bluetooth = true;
config.lora.tx_enabled = true; // FIXME: maybe false in the future, and setting region to enable it. (unset region forces it off) config.lora.tx_enabled = true; // FIXME: maybe false in the future, and setting region to enable it. (unset region forces it off)
config.lora.override_duty_cycle = false;
config.lora.region = Config_LoRaConfig_RegionCode_UNSET; config.lora.region = Config_LoRaConfig_RegionCode_UNSET;
config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LONG_FAST; config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LONG_FAST;
config.lora.hop_limit = HOP_RELIABLE; config.lora.hop_limit = HOP_RELIABLE;

View File

@ -2,6 +2,7 @@
#include "Channels.h" #include "Channels.h"
#include "CryptoEngine.h" #include "CryptoEngine.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "MeshRadio.h"
#include "RTC.h" #include "RTC.h"
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
@ -187,6 +188,18 @@ ErrorCode Router::send(MeshPacket *p)
{ {
assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal
// Abort sending if we are violating the duty cycle
if (!config.lora.override_duty_cycle && myRegion->dutyCycle != 100) {
float hourlyTxPercent = airTime->utilizationTXPercent();
if (hourlyTxPercent > myRegion->dutyCycle) {
uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle);
DEBUG_MSG("WARNING: Duty cycle limit exceeded. Aborting send for now, you can send again in %d minutes.\n", silentMinutes);
Routing_Error err = Routing_Error_DUTY_CYCLE_LIMIT;
abortSendAndNak(err, p);
return err;
}
}
// PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0; // PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0;
// assert(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with // assert(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with
// assert // assert

View File

@ -1,7 +1,7 @@
#include "mesh/http/WiFiAPClient.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "RTC.h" #include "RTC.h"
#include "concurrency/Periodic.h" #include "concurrency/Periodic.h"
#include "mesh/http/WiFiAPClient.h"
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
#include "mesh/http/WebServer.h" #include "mesh/http/WebServer.h"
@ -37,9 +37,9 @@ bool APStartupComplete = 0;
unsigned long lastrun_ntp = 0; unsigned long lastrun_ntp = 0;
static bool needReconnect = true; // If we create our reconnector, run it once at the beginning bool needReconnect = true; // If we create our reconnector, run it once at the beginning
static Periodic *wifiReconnect; Periodic *wifiReconnect;
static int32_t reconnectWiFi() static int32_t reconnectWiFi()
{ {
@ -56,29 +56,15 @@ static int32_t reconnectWiFi()
// Make sure we clear old connection credentials // Make sure we clear old connection credentials
WiFi.disconnect(false, true); WiFi.disconnect(false, true);
DEBUG_MSG("... Reconnecting to WiFi access point %s\n",wifiName); DEBUG_MSG("Reconnecting to WiFi access point %s\n",wifiName);
int n = WiFi.scanNetworks();
if (n > 0) {
for (int i = 0; i < n; ++i) {
DEBUG_MSG("Found WiFi network %s, signal strength %d\n", WiFi.SSID(i).c_str(), WiFi.RSSI(i));
yield();
}
WiFi.mode(WIFI_MODE_STA); WiFi.mode(WIFI_MODE_STA);
WiFi.begin(wifiName, wifiPsw); WiFi.begin(wifiName, wifiPsw);
} else {
DEBUG_MSG("No networks found during site survey. Rebooting MCU...\n");
screen->startRebootScreen();
rebootAtMsec = millis() + 5000;
}
} }
#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;

View File

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

View File

@ -195,6 +195,7 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
void AdminModule::handleSetOwner(const User &o) void AdminModule::handleSetOwner(const User &o)
{ {
int changed = 0; int changed = 0;
bool licensed_changed = false;
if (*o.long_name) { if (*o.long_name) {
changed |= strcmp(owner.long_name, o.long_name); changed |= strcmp(owner.long_name, o.long_name);
@ -210,12 +211,14 @@ void AdminModule::handleSetOwner(const User &o)
} }
if (owner.is_licensed != o.is_licensed) { if (owner.is_licensed != o.is_licensed) {
changed = 1; changed = 1;
licensed_changed = true;
owner.is_licensed = o.is_licensed; owner.is_licensed = o.is_licensed;
config.lora.override_duty_cycle = owner.is_licensed; // override duty cycle for licensed operators
} }
if (changed) { // If nothing really changed, don't broadcast on the network or write to flash if (changed) { // If nothing really changed, don't broadcast on the network or write to flash
service.reloadOwner(!hasOpenEditTransaction); service.reloadOwner(!hasOpenEditTransaction);
saveChanges(SEGMENT_DEVICESTATE); licensed_changed ? saveChanges(SEGMENT_CONFIG | SEGMENT_DEVICESTATE) : saveChanges(SEGMENT_DEVICESTATE);
} }
} }

View File

@ -451,11 +451,15 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
if (this->destSelect) { if (this->destSelect) {
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK); display->setColor(BLACK);
display->drawStringf(1 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
} }
display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest)); display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
// used chars right aligned // used chars right aligned
sprintf(buffer, "%d left", Constants_DATA_PAYLOAD_LEN - this->freetext.length()); sprintf(buffer, "%d left", Constants_DATA_PAYLOAD_LEN - this->freetext.length());
display->drawString(x + display->getWidth() - display->getStringWidth(buffer), y + 0, buffer); display->drawString(x + display->getWidth() - display->getStringWidth(buffer), y + 0, buffer);
if (this->destSelect) {
display->drawString(x + display->getWidth() - display->getStringWidth(buffer) - 1, y + 0, buffer);
}
display->setColor(WHITE); display->setColor(WHITE);
display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), cannedMessageModule->drawWithCursor(cannedMessageModule->freetext, cannedMessageModule->cursor)); display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), cannedMessageModule->drawWithCursor(cannedMessageModule->freetext, cannedMessageModule->cursor));
} else { } else {

View File

@ -71,27 +71,22 @@ void run_codec2(void* parameter)
// 4 bytes of header in each frame 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);
} }
@ -99,10 +94,8 @@ void run_codec2(void* parameter)
if (audioModule->radio_state == RadioState::rx) { if (audioModule->radio_state == RadioState::rx) {
size_t bytesOut = 0; size_t bytesOut = 0;
if (memcmp(audioModule->rx_encode_frame, &audioModule->tx_header, sizeof(audioModule->tx_header)) == 0) { if (memcmp(audioModule->rx_encode_frame, &audioModule->tx_header, sizeof(audioModule->tx_header)) == 0) {
// Make a cycle to get each codec2 frame from the received frame
for (int i = 4; i < audioModule->rx_encode_frame_index; i += audioModule->encode_codec_size) 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);
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));
} }
@ -112,10 +105,8 @@ void run_codec2(void* parameter)
codec2_set_lpc_post_filter(tmp_codec2, 1, 0, 0.8, 0.2); 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_encode_codec_size = (codec2_bits_per_frame(tmp_codec2) + 7) / 8;
int tmp_adc_buffer_size = codec2_samples_per_frame(tmp_codec2); int tmp_adc_buffer_size = codec2_samples_per_frame(tmp_codec2);
// Make a cycle to get each codec2 frame from the received frame
for (int i = 4; i < audioModule->rx_encode_frame_index; i += tmp_encode_codec_size) for (int i = 4; i < audioModule->rx_encode_frame_index; i += tmp_encode_codec_size)
{ {
//Decode the codec2 frame
codec2_decode(tmp_codec2, audioModule->output_buffer, audioModule->rx_encode_frame + i); 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)); i2s_write(I2S_PORT, &audioModule->output_buffer, tmp_adc_buffer_size, &bytesOut, pdMS_TO_TICKS(500));
} }
@ -128,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;
@ -141,7 +139,7 @@ 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);
} }
} }
@ -175,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,
@ -191,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,
@ -201,16 +199,16 @@ 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;
@ -219,19 +217,19 @@ int32_t AudioModule::runOnce()
// 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; e.frameChanged = true;
this->notifyObservers(&e); 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; e.frameChanged = true;
@ -260,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;
} }
@ -268,7 +266,7 @@ 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;
} }
@ -286,7 +284,7 @@ void AudioModule::sendPayload(NodeNum dest, bool wantReplies)
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;

View File

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