mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-02 08:00:38 +00:00
Merge branch 'master' into cubecell
This commit is contained in:
@@ -26,60 +26,73 @@ static void sdsEnter()
|
||||
|
||||
#include "error.h"
|
||||
|
||||
static uint32_t secsSlept;
|
||||
|
||||
static void lsEnter()
|
||||
{
|
||||
DEBUG_MSG("lsEnter begin, ls_secs=%u\n", radioConfig.preferences.ls_secs);
|
||||
screen.setOn(false);
|
||||
secsSlept = 0; // How long have we been sleeping this time
|
||||
|
||||
DEBUG_MSG("lsEnter end\n");
|
||||
}
|
||||
|
||||
static void lsIdle()
|
||||
{
|
||||
DEBUG_MSG("lsIdle begin ls_secs=%u\n", radioConfig.preferences.ls_secs);
|
||||
// DEBUG_MSG("lsIdle begin ls_secs=%u\n", radioConfig.preferences.ls_secs);
|
||||
|
||||
#ifndef NO_ESP32
|
||||
uint32_t secsSlept = 0;
|
||||
esp_sleep_source_t wakeCause = ESP_SLEEP_WAKEUP_UNDEFINED;
|
||||
bool reached_ls_secs = false;
|
||||
|
||||
while (!reached_ls_secs) {
|
||||
// Do we have more sleeping to do?
|
||||
if (secsSlept < radioConfig.preferences.ls_secs) {
|
||||
// Briefly come out of sleep long enough to blink the led once every few seconds
|
||||
uint32_t sleepTime = 5;
|
||||
uint32_t sleepTime = 30;
|
||||
|
||||
setLed(false); // Never leave led on while in light sleep
|
||||
wakeCause = doLightSleep(sleepTime * 1000LL);
|
||||
if (wakeCause != ESP_SLEEP_WAKEUP_TIMER)
|
||||
break;
|
||||
// If some other service would stall sleep, don't let sleep happen yet
|
||||
if (doPreflightSleep()) {
|
||||
setLed(false); // Never leave led on while in light sleep
|
||||
wakeCause = doLightSleep(sleepTime * 1000LL);
|
||||
|
||||
setLed(true); // briefly turn on led
|
||||
doLightSleep(1);
|
||||
if (wakeCause != ESP_SLEEP_WAKEUP_TIMER)
|
||||
break;
|
||||
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) {
|
||||
// Normal case: timer expired, we should just go back to sleep ASAP
|
||||
|
||||
secsSlept += sleepTime;
|
||||
reached_ls_secs = secsSlept >= radioConfig.preferences.ls_secs;
|
||||
}
|
||||
setLed(false);
|
||||
setLed(true); // briefly turn on led
|
||||
wakeCause = doLightSleep(1); // leave led on for 1ms
|
||||
|
||||
if (reached_ls_secs) {
|
||||
// stay in LS mode but let loop check whatever it wants
|
||||
DEBUG_MSG("reached ls_secs, servicing loop()\n");
|
||||
} else {
|
||||
DEBUG_MSG("wakeCause %d\n", wakeCause);
|
||||
secsSlept += sleepTime;
|
||||
// DEBUG_MSG("sleeping, flash led!\n");
|
||||
}
|
||||
if (wakeCause == ESP_SLEEP_WAKEUP_UART) {
|
||||
// Not currently used (because uart triggers in hw have problems)
|
||||
powerFSM.trigger(EVENT_SERIAL_CONNECTED);
|
||||
} else {
|
||||
// We woke for some other reason (button press, uart, device interrupt)
|
||||
// uint64_t status = esp_sleep_get_ext1_wakeup_status();
|
||||
DEBUG_MSG("wakeCause %d\n", wakeCause);
|
||||
|
||||
#ifdef BUTTON_PIN
|
||||
bool pressed = !digitalRead(BUTTON_PIN);
|
||||
bool pressed = !digitalRead(BUTTON_PIN);
|
||||
#else
|
||||
bool pressed = false;
|
||||
bool pressed = false;
|
||||
#endif
|
||||
if (pressed) // If we woke because of press, instead generate a PRESS event.
|
||||
{
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
if (pressed) // If we woke because of press, instead generate a PRESS event.
|
||||
{
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
} else {
|
||||
// Otherwise let the NB state handle the IRQ (and that state will handle stuff like IRQs etc)
|
||||
powerFSM.trigger(EVENT_WAKE_TIMER);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Otherwise let the NB state handle the IRQ (and that state will handle stuff like IRQs etc)
|
||||
powerFSM.trigger(EVENT_WAKE_TIMER);
|
||||
// Someone says we can't sleep now, so just save some power by sleeping the CPU for 100ms or so
|
||||
delay(100);
|
||||
}
|
||||
} else {
|
||||
// Time to stop sleeping!
|
||||
setLed(false);
|
||||
DEBUG_MSG("reached ls_secs, servicing loop()\n");
|
||||
powerFSM.trigger(EVENT_WAKE_TIMER);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -104,6 +117,12 @@ static void darkEnter()
|
||||
screen.setOn(false);
|
||||
}
|
||||
|
||||
static void serialEnter()
|
||||
{
|
||||
setBluetoothEnable(false);
|
||||
screen.setOn(true);
|
||||
}
|
||||
|
||||
static void onEnter()
|
||||
{
|
||||
screen.setOn(true);
|
||||
@@ -133,6 +152,7 @@ State stateSDS(sdsEnter, NULL, NULL, "SDS");
|
||||
State stateLS(lsEnter, lsIdle, lsExit, "LS");
|
||||
State stateNB(nbEnter, NULL, NULL, "NB");
|
||||
State stateDARK(darkEnter, NULL, NULL, "DARK");
|
||||
State stateSERIAL(serialEnter, NULL, NULL, "SERIAL");
|
||||
State stateBOOT(bootEnter, NULL, NULL, "BOOT");
|
||||
State stateON(onEnter, NULL, NULL, "ON");
|
||||
Fsm powerFSM(&stateBOOT);
|
||||
@@ -148,7 +168,7 @@ void PowerFSM_setup()
|
||||
|
||||
powerFSM.add_transition(&stateNB, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet, resetting win wake");
|
||||
|
||||
// Handle press events
|
||||
// Handle press events - note: we ignore button presses when in API mode
|
||||
powerFSM.add_transition(&stateLS, &stateON, EVENT_PRESS, NULL, "Press");
|
||||
powerFSM.add_transition(&stateNB, &stateON, EVENT_PRESS, NULL, "Press");
|
||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "Press");
|
||||
@@ -160,6 +180,7 @@ void PowerFSM_setup()
|
||||
powerFSM.add_transition(&stateNB, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
|
||||
powerFSM.add_transition(&stateDARK, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
|
||||
powerFSM.add_transition(&stateON, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
|
||||
powerFSM.add_transition(&stateSERIAL, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
|
||||
|
||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
|
||||
powerFSM.add_transition(&stateON, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
|
||||
@@ -173,6 +194,13 @@ void PowerFSM_setup()
|
||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
|
||||
powerFSM.add_transition(&stateON, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text"); // restarts the sleep timer
|
||||
|
||||
powerFSM.add_transition(&stateLS, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
||||
powerFSM.add_transition(&stateNB, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
||||
powerFSM.add_transition(&stateDARK, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
||||
powerFSM.add_transition(&stateON, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
|
||||
|
||||
powerFSM.add_transition(&stateSERIAL, &stateNB, EVENT_SERIAL_DISCONNECTED, NULL, "serial disconnect");
|
||||
|
||||
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
|
||||
|
||||
powerFSM.add_transition(&stateNB, &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Packet for phone");
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#define EVENT_NODEDB_UPDATED 8 // NodeDB has a big enough change that we think you should turn on the screen
|
||||
#define EVENT_CONTACT_FROM_PHONE 9 // the phone just talked to us over bluetooth
|
||||
#define EVENT_LOW_BATTERY 10 // Battery is critically low, go to sleep
|
||||
#define EVENT_SERIAL_CONNECTED 11
|
||||
#define EVENT_SERIAL_DISCONNECTED 12
|
||||
|
||||
extern Fsm powerFSM;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "SerialConsole.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
@@ -26,12 +27,19 @@ void SerialConsole::init()
|
||||
*/
|
||||
void SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
|
||||
{
|
||||
// Note: for the time being we could _allow_ debug printing to keep going out the console
|
||||
// I _think_ this is okay because we currently only print debug msgs from loop() and we are only
|
||||
// dispatching serial protobuf msgs from loop() as well. When things are more threaded in the future this
|
||||
// will need to change.
|
||||
// setDestination(&noopPrint);
|
||||
// Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets
|
||||
setDestination(&noopPrint);
|
||||
canWrite = true;
|
||||
|
||||
StreamAPI::handleToRadio(buf, len);
|
||||
}
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
void SerialConsole::onConnectionChanged(bool connected)
|
||||
{
|
||||
if (connected) { // To prevent user confusion, turn off bluetooth while using the serial port api
|
||||
powerFSM.trigger(EVENT_SERIAL_CONNECTED);
|
||||
} else {
|
||||
powerFSM.trigger(EVENT_SERIAL_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,10 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
|
||||
RedirectablePrint::write('\r');
|
||||
return RedirectablePrint::write(c);
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Hookable to find out when connection changes
|
||||
virtual void onConnectionChanged(bool connected);
|
||||
};
|
||||
|
||||
extern SerialConsole console;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "WorkerThread.h"
|
||||
#include "debug.h"
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef configUSE_PREEMPTION
|
||||
@@ -18,6 +19,15 @@ void WorkerThread::doRun()
|
||||
{
|
||||
while (!wantExit) {
|
||||
block();
|
||||
|
||||
#ifdef DEBUG_STACK
|
||||
static uint32_t lastPrint = 0;
|
||||
if (millis() - lastPrint > 10 * 1000L) {
|
||||
lastPrint = millis();
|
||||
meshtastic::printThreadInfo("net");
|
||||
}
|
||||
#endif
|
||||
|
||||
loop();
|
||||
}
|
||||
}
|
||||
@@ -30,8 +40,6 @@ void NotifiedWorkerThread::notify(uint32_t v, eNotifyAction action)
|
||||
xTaskNotify(taskHandle, v, action);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void NotifiedWorkerThread::block()
|
||||
{
|
||||
xTaskNotifyWait(0, // don't clear notification on entry
|
||||
|
||||
@@ -18,6 +18,8 @@ class Thread
|
||||
|
||||
virtual ~Thread() { vTaskDelete(taskHandle); }
|
||||
|
||||
uint32_t getStackHighwaterMark() { return uxTaskGetStackHighWaterMark(taskHandle); }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The method that will be called when start is called.
|
||||
|
||||
@@ -120,6 +120,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#define SSD1306_ADDRESS 0x3C
|
||||
|
||||
// The SH1106 controller is almost, but not quite, the same as SSD1306
|
||||
// Define this if you know you have that controller or your "SSD1306" misbehaves.
|
||||
//#define USE_SH1106
|
||||
|
||||
// Flip the screen upside down by default as it makes more sense on T-BEAM
|
||||
// devices. Comment this out to not rotate screen 180 degrees.
|
||||
#define FLIP_SCREEN_VERTICALLY
|
||||
@@ -184,6 +188,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR "heltec"
|
||||
|
||||
// the default ESP32 Pin of 15 is the Oled SCL, set to 36 and 37 and works fine.
|
||||
//Tested on Neo6m module.
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
#define GPS_RX_PIN 36
|
||||
#define GPS_TX_PIN 37
|
||||
|
||||
#ifndef USE_JTAG // gpio15 is TDO for JTAG, so no I2C on this board while doing jtag
|
||||
#define I2C_SDA 4 // I2C pins for this board
|
||||
#define I2C_SCL 15
|
||||
@@ -275,6 +286,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// What platforms should use SEGGER?
|
||||
#ifdef NRF52_SERIES
|
||||
#define USE_SEGGER
|
||||
#else
|
||||
#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32
|
||||
#endif
|
||||
|
||||
#ifdef USE_SEGGER
|
||||
|
||||
@@ -30,8 +30,6 @@ class TotalSizeCharacteristic : public CallbackCharacteristic
|
||||
|
||||
void onWrite(BLECharacteristic *c)
|
||||
{
|
||||
BLEKeepAliveCallbacks::onWrite(c);
|
||||
|
||||
LockGuard g(updateLock);
|
||||
// Check if there is enough to OTA Update
|
||||
uint32_t len = getValue32(c, 0);
|
||||
@@ -67,8 +65,6 @@ class DataCharacteristic : public CallbackCharacteristic
|
||||
|
||||
void onWrite(BLECharacteristic *c)
|
||||
{
|
||||
BLEKeepAliveCallbacks::onWrite(c);
|
||||
|
||||
LockGuard g(updateLock);
|
||||
std::string value = c->getValue();
|
||||
uint32_t len = value.length();
|
||||
@@ -92,8 +88,6 @@ class CRC32Characteristic : public CallbackCharacteristic
|
||||
|
||||
void onWrite(BLECharacteristic *c)
|
||||
{
|
||||
BLEKeepAliveCallbacks::onWrite(c);
|
||||
|
||||
LockGuard g(updateLock);
|
||||
uint32_t expectedCRC = getValue32(c, 0);
|
||||
uint32_t actualCRC = crc.finalize();
|
||||
|
||||
@@ -8,54 +8,6 @@
|
||||
|
||||
SimpleAllocator btPool;
|
||||
|
||||
/**
|
||||
* Create standard device info service
|
||||
**/
|
||||
BLEService *createDeviceInfomationService(BLEServer *server, std::string hwVendor, std::string swVersion,
|
||||
std::string hwVersion = "")
|
||||
{
|
||||
BLEService *deviceInfoService = server->createService(BLEUUID((uint16_t)ESP_GATT_UUID_DEVICE_INFO_SVC));
|
||||
|
||||
BLECharacteristic *swC =
|
||||
new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_SW_VERSION_STR), BLECharacteristic::PROPERTY_READ);
|
||||
BLECharacteristic *mfC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_MANU_NAME), BLECharacteristic::PROPERTY_READ);
|
||||
// BLECharacteristic SerialNumberCharacteristic(BLEUUID((uint16_t) ESP_GATT_UUID_SERIAL_NUMBER_STR),
|
||||
// BLECharacteristic::PROPERTY_READ);
|
||||
|
||||
/*
|
||||
* Mandatory characteristic for device info service?
|
||||
|
||||
BLECharacteristic *m_pnpCharacteristic = m_deviceInfoService->createCharacteristic(ESP_GATT_UUID_PNP_ID,
|
||||
BLECharacteristic::PROPERTY_READ);
|
||||
|
||||
uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version;
|
||||
uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >>
|
||||
8), (uint8_t) version }; m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
|
||||
*/
|
||||
swC->setValue(swVersion);
|
||||
deviceInfoService->addCharacteristic(addBLECharacteristic(swC));
|
||||
mfC->setValue(hwVendor);
|
||||
deviceInfoService->addCharacteristic(addBLECharacteristic(mfC));
|
||||
if (!hwVersion.empty()) {
|
||||
BLECharacteristic *hwvC =
|
||||
new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_HW_VERSION_STR), BLECharacteristic::PROPERTY_READ);
|
||||
hwvC->setValue(hwVersion);
|
||||
deviceInfoService->addCharacteristic(addBLECharacteristic(hwvC));
|
||||
}
|
||||
// SerialNumberCharacteristic.setValue("FIXME");
|
||||
// deviceInfoService->addCharacteristic(&SerialNumberCharacteristic);
|
||||
|
||||
// m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29,
|
||||
// BLECharacteristic::PROPERTY_READ); m_manufacturerCharacteristic->setValue(name);
|
||||
|
||||
/* add these later?
|
||||
ESP_GATT_UUID_SYSTEM_ID
|
||||
*/
|
||||
|
||||
// caller must call service->start();
|
||||
return deviceInfoService;
|
||||
}
|
||||
|
||||
bool _BLEClientConnected = false;
|
||||
|
||||
class MyServerCallbacks : public BLEServerCallbacks
|
||||
@@ -106,6 +58,54 @@ void addWithDesc(BLEService *service, BLECharacteristic *c, const char *descript
|
||||
addBLEDescriptor(desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create standard device info service
|
||||
**/
|
||||
BLEService *createDeviceInfomationService(BLEServer *server, std::string hwVendor, std::string swVersion,
|
||||
std::string hwVersion = "")
|
||||
{
|
||||
BLEService *deviceInfoService = server->createService(BLEUUID((uint16_t)ESP_GATT_UUID_DEVICE_INFO_SVC));
|
||||
|
||||
BLECharacteristic *swC =
|
||||
new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_SW_VERSION_STR), BLECharacteristic::PROPERTY_READ);
|
||||
BLECharacteristic *mfC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_MANU_NAME), BLECharacteristic::PROPERTY_READ);
|
||||
// BLECharacteristic SerialNumberCharacteristic(BLEUUID((uint16_t) ESP_GATT_UUID_SERIAL_NUMBER_STR),
|
||||
// BLECharacteristic::PROPERTY_READ);
|
||||
|
||||
/*
|
||||
* Mandatory characteristic for device info service?
|
||||
|
||||
BLECharacteristic *m_pnpCharacteristic = m_deviceInfoService->createCharacteristic(ESP_GATT_UUID_PNP_ID,
|
||||
BLECharacteristic::PROPERTY_READ);
|
||||
|
||||
uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version;
|
||||
uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >>
|
||||
8), (uint8_t) version }; m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
|
||||
*/
|
||||
swC->setValue(swVersion);
|
||||
deviceInfoService->addCharacteristic(addBLECharacteristic(swC));
|
||||
mfC->setValue(hwVendor);
|
||||
deviceInfoService->addCharacteristic(addBLECharacteristic(mfC));
|
||||
if (!hwVersion.empty()) {
|
||||
BLECharacteristic *hwvC =
|
||||
new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_HW_VERSION_STR), BLECharacteristic::PROPERTY_READ);
|
||||
hwvC->setValue(hwVersion);
|
||||
deviceInfoService->addCharacteristic(addBLECharacteristic(hwvC));
|
||||
}
|
||||
// SerialNumberCharacteristic.setValue("FIXME");
|
||||
// deviceInfoService->addCharacteristic(&SerialNumberCharacteristic);
|
||||
|
||||
// m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29,
|
||||
// BLECharacteristic::PROPERTY_READ); m_manufacturerCharacteristic->setValue(name);
|
||||
|
||||
/* add these later?
|
||||
ESP_GATT_UUID_SYSTEM_ID
|
||||
*/
|
||||
|
||||
// caller must call service->start();
|
||||
return deviceInfoService;
|
||||
}
|
||||
|
||||
static BLECharacteristic *batteryLevelC;
|
||||
|
||||
/**
|
||||
@@ -223,11 +223,15 @@ void deinitBLE()
|
||||
|
||||
pServer->getAdvertising()->stop();
|
||||
|
||||
destroyUpdateService();
|
||||
if (pUpdate != NULL) {
|
||||
destroyUpdateService();
|
||||
|
||||
pUpdate->stop(); // we delete them below
|
||||
pUpdate->executeDelete();
|
||||
}
|
||||
|
||||
pUpdate->stop();
|
||||
pDevInfo->stop();
|
||||
pUpdate->stop(); // we delete them below
|
||||
pDevInfo->executeDelete();
|
||||
|
||||
// First shutdown bluetooth
|
||||
BLEDevice::deinit(false);
|
||||
@@ -235,14 +239,16 @@ void deinitBLE()
|
||||
// do not delete this - it is dynamically allocated, but only once - statically in BLEDevice
|
||||
// delete pServer->getAdvertising();
|
||||
|
||||
delete pUpdate;
|
||||
if (pUpdate != NULL)
|
||||
delete pUpdate;
|
||||
delete pDevInfo;
|
||||
delete pServer;
|
||||
|
||||
batteryLevelC = NULL; // Don't let anyone generate bogus notifies
|
||||
|
||||
for (int i = 0; i < numChars; i++)
|
||||
for (int i = 0; i < numChars; i++) {
|
||||
delete chars[i];
|
||||
}
|
||||
numChars = 0;
|
||||
|
||||
for (int i = 0; i < numDescs; i++)
|
||||
@@ -276,15 +282,19 @@ BLEServer *initBLE(StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoo
|
||||
// We now let users create the battery service only if they really want (not all devices have a battery)
|
||||
// BLEService *pBattery = createBatteryService(pServer);
|
||||
|
||||
// #define BLE_SOFTWARE_UPDATE
|
||||
#ifdef BLE_SOFTWARE_UPDATE
|
||||
pUpdate = createUpdateService(pServer, hwVendor, swVersion,
|
||||
hwVersion); // We need to advertise this so our android ble scan operation can see it
|
||||
|
||||
pUpdate->start();
|
||||
#endif
|
||||
|
||||
// It seems only one service can be advertised - so for now don't advertise our updater
|
||||
// pServer->getAdvertising()->addServiceUUID(pUpdate->getUUID());
|
||||
|
||||
// start all our services (do this after creating all of them)
|
||||
pDevInfo->start();
|
||||
pUpdate->start();
|
||||
|
||||
// FIXME turn on this restriction only after the device is paired with a phone
|
||||
// advert->setScanFilter(false, true); // We let anyone scan for us (FIXME, perhaps only allow that until we are paired with a
|
||||
@@ -293,7 +303,11 @@ BLEServer *initBLE(StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoo
|
||||
static BLESecurity security; // static to avoid allocs
|
||||
BLESecurity *pSecurity = &security;
|
||||
pSecurity->setCapability(ESP_IO_CAP_OUT);
|
||||
|
||||
// FIXME - really should be ESP_LE_AUTH_REQ_SC_BOND but it seems there is a bug right now causing that bonding info to be lost
|
||||
// occasionally?
|
||||
pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND);
|
||||
|
||||
pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
|
||||
|
||||
return pServer;
|
||||
|
||||
@@ -1,33 +1,12 @@
|
||||
#pragma once
|
||||
#include "PowerFSM.h" // FIXME - someday I want to make this OTA thing a separate lb at at that point it can't touch this
|
||||
#include "BLECharacteristic.h"
|
||||
|
||||
/**
|
||||
* This mixin just lets the power management state machine know the phone is still talking to us
|
||||
*/
|
||||
class BLEKeepAliveCallbacks : public BLECharacteristicCallbacks
|
||||
{
|
||||
public:
|
||||
void onRead(BLECharacteristic *c)
|
||||
{
|
||||
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
|
||||
}
|
||||
|
||||
void onWrite(BLECharacteristic *c)
|
||||
{
|
||||
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
|
||||
}
|
||||
};
|
||||
#include "PowerFSM.h" // FIXME - someday I want to make this OTA thing a separate lb at at that point it can't touch this
|
||||
|
||||
/**
|
||||
* A characterstic with a set of overridable callbacks
|
||||
*/
|
||||
class CallbackCharacteristic : public BLECharacteristic, public BLEKeepAliveCallbacks
|
||||
class CallbackCharacteristic : public BLECharacteristic, public BLECharacteristicCallbacks
|
||||
{
|
||||
public:
|
||||
CallbackCharacteristic(const char *uuid, uint32_t btprops)
|
||||
: BLECharacteristic(uuid, btprops)
|
||||
{
|
||||
setCallbacks(this);
|
||||
}
|
||||
public:
|
||||
CallbackCharacteristic(const char *uuid, uint32_t btprops) : BLECharacteristic(uuid, btprops) { setCallbacks(this); }
|
||||
};
|
||||
|
||||
@@ -23,9 +23,6 @@ static CallbackCharacteristic *meshFromNumCharacteristic;
|
||||
|
||||
BLEService *meshService;
|
||||
|
||||
// If defined we will also support the old API
|
||||
#define SUPPORT_OLD_BLE_API
|
||||
|
||||
class BluetoothPhoneAPI : public PhoneAPI
|
||||
{
|
||||
/**
|
||||
@@ -44,150 +41,6 @@ class BluetoothPhoneAPI : public PhoneAPI
|
||||
|
||||
BluetoothPhoneAPI *bluetoothPhoneAPI;
|
||||
|
||||
class ProtobufCharacteristic : public CallbackCharacteristic
|
||||
{
|
||||
const pb_msgdesc_t *fields;
|
||||
void *my_struct;
|
||||
|
||||
public:
|
||||
ProtobufCharacteristic(const char *uuid, uint32_t btprops, const pb_msgdesc_t *_fields, void *_my_struct)
|
||||
: CallbackCharacteristic(uuid, btprops), fields(_fields), my_struct(_my_struct)
|
||||
{
|
||||
setCallbacks(this);
|
||||
}
|
||||
|
||||
void onRead(BLECharacteristic *c)
|
||||
{
|
||||
BLEKeepAliveCallbacks::onRead(c);
|
||||
size_t numbytes = pb_encode_to_bytes(trBytes, sizeof(trBytes), fields, my_struct);
|
||||
DEBUG_MSG("pbread from %s returns %d bytes\n", c->getUUID().toString().c_str(), numbytes);
|
||||
c->setValue(trBytes, numbytes);
|
||||
}
|
||||
|
||||
void onWrite(BLECharacteristic *c)
|
||||
{
|
||||
BLEKeepAliveCallbacks::onWrite(c);
|
||||
writeToDest(c, my_struct);
|
||||
}
|
||||
|
||||
protected:
|
||||
/// like onWrite, but we provide an different destination to write to, for use by subclasses that
|
||||
/// want to optionally ignore parts of writes.
|
||||
/// returns true for success
|
||||
bool writeToDest(BLECharacteristic *c, void *dest)
|
||||
{
|
||||
// dumpCharacteristic(pCharacteristic);
|
||||
std::string src = c->getValue();
|
||||
DEBUG_MSG("pbwrite to %s of %d bytes\n", c->getUUID().toString().c_str(), src.length());
|
||||
return pb_decode_from_bytes((const uint8_t *)src.c_str(), src.length(), fields, dest);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef SUPPORT_OLD_BLE_API
|
||||
class NodeInfoCharacteristic : public BLECharacteristic, public BLEKeepAliveCallbacks
|
||||
{
|
||||
public:
|
||||
NodeInfoCharacteristic()
|
||||
: BLECharacteristic("d31e02e0-c8ab-4d3f-9cc9-0b8466bdabe8",
|
||||
BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ)
|
||||
{
|
||||
setCallbacks(this);
|
||||
}
|
||||
|
||||
void onRead(BLECharacteristic *c)
|
||||
{
|
||||
BLEKeepAliveCallbacks::onRead(c);
|
||||
|
||||
const NodeInfo *info = nodeDB.readNextInfo();
|
||||
|
||||
if (info) {
|
||||
DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->position.time, info->user.id,
|
||||
info->user.long_name);
|
||||
size_t numbytes = pb_encode_to_bytes(trBytes, sizeof(trBytes), NodeInfo_fields, info);
|
||||
c->setValue(trBytes, numbytes);
|
||||
} else {
|
||||
c->setValue(trBytes, 0); // Send an empty response
|
||||
DEBUG_MSG("Done sending nodeinfos\n");
|
||||
}
|
||||
}
|
||||
|
||||
void onWrite(BLECharacteristic *c)
|
||||
{
|
||||
BLEKeepAliveCallbacks::onWrite(c);
|
||||
DEBUG_MSG("Reset nodeinfo read pointer\n");
|
||||
nodeDB.resetReadPointer();
|
||||
}
|
||||
};
|
||||
|
||||
// wrap our protobuf version with something that forces the service to reload the config
|
||||
class RadioCharacteristic : public ProtobufCharacteristic
|
||||
{
|
||||
public:
|
||||
RadioCharacteristic()
|
||||
: ProtobufCharacteristic("b56786c8-839a-44a1-b98e-a1724c4a0262",
|
||||
BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ, RadioConfig_fields,
|
||||
&radioConfig)
|
||||
{
|
||||
}
|
||||
|
||||
void onRead(BLECharacteristic *c)
|
||||
{
|
||||
DEBUG_MSG("Reading radio config, sdsecs %u\n", radioConfig.preferences.sds_secs);
|
||||
ProtobufCharacteristic::onRead(c);
|
||||
}
|
||||
|
||||
void onWrite(BLECharacteristic *c)
|
||||
{
|
||||
DEBUG_MSG("Writing radio config\n");
|
||||
ProtobufCharacteristic::onWrite(c);
|
||||
bluetoothPhoneAPI->handleSetRadio(radioConfig);
|
||||
}
|
||||
};
|
||||
|
||||
// wrap our protobuf version with something that forces the service to reload the owner
|
||||
class OwnerCharacteristic : public ProtobufCharacteristic
|
||||
{
|
||||
public:
|
||||
OwnerCharacteristic()
|
||||
: ProtobufCharacteristic("6ff1d8b6-e2de-41e3-8c0b-8fa384f64eb6",
|
||||
BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ, User_fields, &owner)
|
||||
{
|
||||
}
|
||||
|
||||
void onWrite(BLECharacteristic *c)
|
||||
{
|
||||
BLEKeepAliveCallbacks::onWrite(
|
||||
c); // NOTE: We do not call the standard ProtobufCharacteristic superclass, because we want custom write behavior
|
||||
|
||||
static User o; // if the phone doesn't set ID we are careful to keep ours, we also always keep our macaddr
|
||||
if (writeToDest(c, &o)) {
|
||||
bluetoothPhoneAPI->handleSetOwner(o);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MyNodeInfoCharacteristic : public ProtobufCharacteristic
|
||||
{
|
||||
public:
|
||||
MyNodeInfoCharacteristic()
|
||||
: ProtobufCharacteristic("ea9f3f82-8dc4-4733-9452-1f6da28892a2", BLECharacteristic::PROPERTY_READ, MyNodeInfo_fields,
|
||||
&myNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
void onRead(BLECharacteristic *c)
|
||||
{
|
||||
// update gps connection state
|
||||
myNodeInfo.has_gps = gps->isConnected;
|
||||
|
||||
ProtobufCharacteristic::onRead(c);
|
||||
|
||||
myNodeInfo.error_code = 0; // The phone just read us, so throw it away
|
||||
myNodeInfo.error_address = 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class ToRadioCharacteristic : public CallbackCharacteristic
|
||||
{
|
||||
@@ -196,9 +49,6 @@ class ToRadioCharacteristic : public CallbackCharacteristic
|
||||
|
||||
void onWrite(BLECharacteristic *c)
|
||||
{
|
||||
BLEKeepAliveCallbacks::onWrite(c);
|
||||
DEBUG_MSG("Got on write\n");
|
||||
|
||||
bluetoothPhoneAPI->handleToRadio(c->getData(), c->getValue().length());
|
||||
}
|
||||
};
|
||||
@@ -212,7 +62,6 @@ class FromRadioCharacteristic : public CallbackCharacteristic
|
||||
|
||||
void onRead(BLECharacteristic *c)
|
||||
{
|
||||
BLEKeepAliveCallbacks::onRead(c);
|
||||
size_t numBytes = bluetoothPhoneAPI->getFromRadio(trBytes);
|
||||
|
||||
// Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue
|
||||
@@ -236,11 +85,7 @@ class FromNumCharacteristic : public CallbackCharacteristic
|
||||
// observe(&service.fromNumChanged);
|
||||
}
|
||||
|
||||
void onRead(BLECharacteristic *c)
|
||||
{
|
||||
BLEKeepAliveCallbacks::onRead(c);
|
||||
DEBUG_MSG("FIXME implement fromnum read\n");
|
||||
}
|
||||
void onRead(BLECharacteristic *c) { DEBUG_MSG("FIXME implement fromnum read\n"); }
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -263,12 +108,6 @@ BLEService *createMeshBluetoothService(BLEServer *server)
|
||||
addWithDesc(service, meshFromNumCharacteristic, "fromRadio");
|
||||
addWithDesc(service, new ToRadioCharacteristic, "toRadio");
|
||||
addWithDesc(service, new FromRadioCharacteristic, "fromNum");
|
||||
#ifdef SUPPORT_OLD_BLE_API
|
||||
addWithDesc(service, new MyNodeInfoCharacteristic, "myNode");
|
||||
addWithDesc(service, new RadioCharacteristic, "radio");
|
||||
addWithDesc(service, new OwnerCharacteristic, "owner");
|
||||
addWithDesc(service, new NodeInfoCharacteristic, "nodeinfo");
|
||||
#endif
|
||||
|
||||
meshFromNumCharacteristic->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification
|
||||
|
||||
@@ -292,6 +131,7 @@ void stopMeshBluetoothService()
|
||||
{
|
||||
assert(meshService);
|
||||
meshService->stop();
|
||||
meshService->executeDelete();
|
||||
}
|
||||
|
||||
void destroyMeshBluetoothService()
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "power.h"
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
|
||||
bool bluetoothOn;
|
||||
@@ -154,12 +155,31 @@ void axp192Init()
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
static void printBLEinfo() {
|
||||
int dev_num = esp_ble_get_bond_device_num();
|
||||
|
||||
esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num);
|
||||
esp_ble_get_bond_device_list(&dev_num, dev_list);
|
||||
for (int i = 0; i < dev_num; i++) {
|
||||
// esp_ble_remove_bond_device(dev_list[i].bd_addr);
|
||||
}
|
||||
|
||||
} */
|
||||
|
||||
void esp32Setup()
|
||||
{
|
||||
uint32_t seed = esp_random();
|
||||
DEBUG_MSG("Setting random seed %u\n", seed);
|
||||
randomSeed(seed); // ESP docs say this is fairly random
|
||||
|
||||
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());
|
||||
|
||||
// enableModemSleep();
|
||||
|
||||
#ifdef AXP192_SLAVE_ADDRESS
|
||||
axp192Init();
|
||||
#endif
|
||||
|
||||
11
src/main.cpp
11
src/main.cpp
@@ -33,6 +33,7 @@
|
||||
#include "power.h"
|
||||
// #include "rom/rtc.h"
|
||||
#include "DSRRouter.h"
|
||||
#include "debug.h"
|
||||
#include "main.h"
|
||||
#include "screen.h"
|
||||
#include "sleep.h"
|
||||
@@ -282,6 +283,8 @@ void loop()
|
||||
DEBUG_PORT.loop(); // Send/receive protobufs over the serial port
|
||||
#endif
|
||||
|
||||
// heap_caps_check_integrity_all(true); // FIXME - disable this expensive check
|
||||
|
||||
#ifndef NO_ESP32
|
||||
esp32Loop();
|
||||
#endif
|
||||
@@ -314,6 +317,14 @@ void loop()
|
||||
showingBootScreen = false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_STACK
|
||||
static uint32_t lastPrint = 0;
|
||||
if (millis() - lastPrint > 10 * 1000L) {
|
||||
lastPrint = millis();
|
||||
meshtastic::printThreadInfo("main");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Update the screen last, after we've figured out what to show.
|
||||
screen.debug()->setNodeNumbersStatus(nodeDB.getNumOnlineNodes(), nodeDB.getNumNodes());
|
||||
screen.debug()->setChannelNameStatus(channelSettings.name);
|
||||
|
||||
@@ -5,12 +5,80 @@
|
||||
|
||||
#include "PointerQueue.h"
|
||||
|
||||
template <class T> class Allocator
|
||||
{
|
||||
|
||||
public:
|
||||
virtual ~Allocator() {}
|
||||
|
||||
/// Return a queable object which has been prefilled with zeros. Panic if no buffer is available
|
||||
/// Note: this method is safe to call from regular OR ISR code
|
||||
T *allocZeroed()
|
||||
{
|
||||
T *p = allocZeroed(0);
|
||||
|
||||
assert(p); // FIXME panic instead
|
||||
return p;
|
||||
}
|
||||
|
||||
/// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you probably
|
||||
/// don't want this version).
|
||||
T *allocZeroed(TickType_t maxWait)
|
||||
{
|
||||
T *p = alloc(maxWait);
|
||||
|
||||
if (p)
|
||||
memset(p, 0, sizeof(T));
|
||||
return p;
|
||||
}
|
||||
|
||||
/// Return a queable object which is a copy of some other object
|
||||
T *allocCopy(const T &src, TickType_t maxWait = portMAX_DELAY)
|
||||
{
|
||||
T *p = alloc(maxWait);
|
||||
assert(p);
|
||||
|
||||
if (p)
|
||||
*p = src;
|
||||
return p;
|
||||
}
|
||||
|
||||
/// Return a buffer for use by others
|
||||
virtual void release(T *p) = 0;
|
||||
|
||||
protected:
|
||||
// Alloc some storage
|
||||
virtual T *alloc(TickType_t maxWait) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* An allocator that just uses regular free/malloc
|
||||
*/
|
||||
template <class T> class MemoryDynamic : public Allocator<T>
|
||||
{
|
||||
public:
|
||||
/// Return a buffer for use by others
|
||||
virtual void release(T *p)
|
||||
{
|
||||
assert(p);
|
||||
free(p);
|
||||
}
|
||||
|
||||
protected:
|
||||
// Alloc some storage
|
||||
virtual T *alloc(TickType_t maxWait)
|
||||
{
|
||||
T *p = (T *)malloc(sizeof(T));
|
||||
assert(p);
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A pool based allocator
|
||||
*
|
||||
* Eventually this routine will even be safe for ISR use...
|
||||
*/
|
||||
template <class T> class MemoryPool
|
||||
template <class T> class MemoryPool : public Allocator<T>
|
||||
{
|
||||
PointerQueue<T> dead;
|
||||
|
||||
@@ -30,39 +98,8 @@ template <class T> class MemoryPool
|
||||
|
||||
~MemoryPool() { delete[] buf; }
|
||||
|
||||
/// Return a queable object which has been prefilled with zeros. Panic if no buffer is available
|
||||
/// Note: this method is safe to call from regular OR ISR code
|
||||
T *allocZeroed()
|
||||
{
|
||||
T *p = allocZeroed(0);
|
||||
|
||||
assert(p); // FIXME panic instead
|
||||
return p;
|
||||
}
|
||||
|
||||
/// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you probably
|
||||
/// don't want this version).
|
||||
T *allocZeroed(TickType_t maxWait)
|
||||
{
|
||||
T *p = dead.dequeuePtr(maxWait);
|
||||
|
||||
if (p)
|
||||
memset(p, 0, sizeof(T));
|
||||
return p;
|
||||
}
|
||||
|
||||
/// Return a queable object which is a copy of some other object
|
||||
T *allocCopy(const T &src, TickType_t maxWait = portMAX_DELAY)
|
||||
{
|
||||
T *p = dead.dequeuePtr(maxWait);
|
||||
|
||||
if (p)
|
||||
*p = src;
|
||||
return p;
|
||||
}
|
||||
|
||||
/// Return a buffer for use by others
|
||||
void release(T *p)
|
||||
virtual void release(T *p)
|
||||
{
|
||||
assert(dead.enqueue(p, 0));
|
||||
assert(p >= buf &&
|
||||
@@ -78,4 +115,9 @@ template <class T> class MemoryPool
|
||||
(size_t)(p - buf) <
|
||||
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you
|
||||
/// probably don't want this version).
|
||||
virtual T *alloc(TickType_t maxWait) { return dead.dequeuePtr(maxWait); }
|
||||
};
|
||||
|
||||
@@ -86,12 +86,14 @@ void MeshService::sendOurOwner(NodeNum dest, bool wantReplies)
|
||||
const MeshPacket *MeshService::handleFromRadioUser(const MeshPacket *mp)
|
||||
{
|
||||
bool wasBroadcast = mp->to == NODENUM_BROADCAST;
|
||||
bool isCollision = mp->from == myNodeInfo.my_node_num;
|
||||
|
||||
// we win if we have a lower macaddr
|
||||
bool weWin = memcmp(&owner.macaddr, &mp->decoded.user.macaddr, sizeof(owner.macaddr)) < 0;
|
||||
// Disable this collision testing if we use 32 bit nodenums
|
||||
bool isCollision = (sizeof(NodeNum) == 1) && (mp->from == myNodeInfo.my_node_num);
|
||||
|
||||
if (isCollision) {
|
||||
// we win if we have a lower macaddr
|
||||
bool weWin = memcmp(&owner.macaddr, &mp->decoded.user.macaddr, sizeof(owner.macaddr)) < 0;
|
||||
|
||||
if (weWin) {
|
||||
DEBUG_MSG("NOTE! Received a nodenum collision and we are vetoing\n");
|
||||
|
||||
@@ -158,7 +160,7 @@ int MeshService::handleFromRadio(const MeshPacket *mp)
|
||||
|
||||
// If we veto a received User packet, we don't put it into the DB or forward it to the phone (to prevent confusing it)
|
||||
if (mp) {
|
||||
DEBUG_MSG("Forwarding to phone, from=0x%x, rx_time=%u\n", mp->from, mp->rx_time);
|
||||
printPacket("Forwarding to phone", mp);
|
||||
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
|
||||
|
||||
fromNum++;
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#include "mesh.pb.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
typedef uint8_t NodeNum;
|
||||
typedef uint8_t PacketId; // A packet sequence number
|
||||
typedef uint32_t NodeNum;
|
||||
typedef uint32_t PacketId; // A packet sequence number
|
||||
|
||||
#define NODENUM_BROADCAST (sizeof(NodeNum) == 4 ? UINT32_MAX : UINT8_MAX)
|
||||
#define ERRNO_OK 0
|
||||
@@ -29,4 +29,4 @@ typedef uint8_t PacketId; // A packet sequence number
|
||||
typedef int ErrorCode;
|
||||
|
||||
/// Alloc and free packets to our global, ISR safe pool
|
||||
extern MemoryPool<MeshPacket> packetPool;
|
||||
extern Allocator<MeshPacket> &packetPool;
|
||||
@@ -30,7 +30,7 @@ DeviceState versions used to be defined in the .proto file but really only this
|
||||
#define here.
|
||||
*/
|
||||
|
||||
#define DEVICESTATE_CUR_VER 8
|
||||
#define DEVICESTATE_CUR_VER 10
|
||||
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
|
||||
|
||||
#ifndef NO_ESP32
|
||||
@@ -101,10 +101,12 @@ void NodeDB::resetRadioConfig()
|
||||
crypto->setKey(channelSettings.psk.size, channelSettings.psk.bytes);
|
||||
|
||||
// temp hack for quicker testing
|
||||
|
||||
/*
|
||||
radioConfig.preferences.screen_on_secs = 30;
|
||||
radioConfig.preferences.wait_bluetooth_secs = 30;
|
||||
radioConfig.preferences.position_broadcast_secs = 15;
|
||||
radioConfig.preferences.position_broadcast_secs = 6 * 60;
|
||||
radioConfig.preferences.ls_secs = 60;
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -114,7 +116,6 @@ void NodeDB::init()
|
||||
devicestate.has_my_node = true;
|
||||
devicestate.has_radio = true;
|
||||
devicestate.has_owner = true;
|
||||
devicestate.has_radio = false;
|
||||
devicestate.radio.has_channel_settings = true;
|
||||
devicestate.radio.has_preferences = true;
|
||||
devicestate.node_db_count = 0;
|
||||
@@ -124,10 +125,8 @@ void NodeDB::init()
|
||||
|
||||
// default to no GPS, until one has been found by probing
|
||||
myNodeInfo.has_gps = false;
|
||||
myNodeInfo.node_num_bits = sizeof(NodeNum) * 8;
|
||||
myNodeInfo.packet_id_bits = sizeof(PacketId) * 8;
|
||||
myNodeInfo.message_timeout_msec = FLOOD_EXPIRE_TIME;
|
||||
myNodeInfo.min_app_version = 167;
|
||||
myNodeInfo.min_app_version = 172;
|
||||
generatePacketId(); // FIXME - ugly way to init current_packet_id;
|
||||
|
||||
// Init our blank owner info to reasonable defaults
|
||||
@@ -135,18 +134,13 @@ void NodeDB::init()
|
||||
sprintf(owner.id, "!%02x%02x%02x%02x%02x%02x", ourMacAddr[0], ourMacAddr[1], ourMacAddr[2], ourMacAddr[3], ourMacAddr[4],
|
||||
ourMacAddr[5]);
|
||||
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
|
||||
|
||||
// Set default owner name
|
||||
pickNewNodeNum(); // Note: we will repick later, just in case the settings are corrupted, but we need a valid
|
||||
// owner.short_name now
|
||||
sprintf(owner.long_name, "Unknown %02x%02x", ourMacAddr[4], ourMacAddr[5]);
|
||||
|
||||
// Crummy guess at our nodenum
|
||||
pickNewNodeNum();
|
||||
|
||||
sprintf(owner.short_name, "?%02X", myNodeInfo.my_node_num & 0xff);
|
||||
|
||||
// Include our owner in the node db under our nodenum
|
||||
NodeInfo *info = getOrCreateNode(getNodeNum());
|
||||
info->user = owner;
|
||||
info->has_user = true;
|
||||
|
||||
if (!FSBegin()) // FIXME - do this in main?
|
||||
{
|
||||
DEBUG_MSG("ERROR filesystem mount Failed\n");
|
||||
@@ -157,6 +151,20 @@ void NodeDB::init()
|
||||
loadFromDisk();
|
||||
// saveToDisk();
|
||||
|
||||
// We set node_num and packet_id _after_ loading from disk, because we always want to use the values this
|
||||
// rom was compiled for, not what happens to be in the save file.
|
||||
myNodeInfo.node_num_bits = sizeof(NodeNum) * 8;
|
||||
myNodeInfo.packet_id_bits = sizeof(PacketId) * 8;
|
||||
|
||||
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
|
||||
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
|
||||
pickNewNodeNum();
|
||||
|
||||
// Include our owner in the node db under our nodenum
|
||||
NodeInfo *info = getOrCreateNode(getNodeNum());
|
||||
info->user = owner;
|
||||
info->has_user = true;
|
||||
|
||||
// We set these _after_ loading from disk - because they come from the build and are more trusted than
|
||||
// what is stored in flash
|
||||
strncpy(myNodeInfo.region, optstr(HW_VERSION), sizeof(myNodeInfo.region));
|
||||
@@ -176,9 +184,12 @@ void NodeDB::init()
|
||||
*/
|
||||
void NodeDB::pickNewNodeNum()
|
||||
{
|
||||
// Pick an initial nodenum based on the macaddr
|
||||
NodeNum r = sizeof(NodeNum) == 1 ? ourMacAddr[5]
|
||||
: ((ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5]);
|
||||
NodeNum r = myNodeInfo.my_node_num;
|
||||
|
||||
// If we don't have a nodenum at app - pick an initial nodenum based on the macaddr
|
||||
if (r == 0)
|
||||
r = sizeof(NodeNum) == 1 ? ourMacAddr[5]
|
||||
: ((ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5]);
|
||||
|
||||
if (r == NODENUM_BROADCAST || r < NUM_RESERVED)
|
||||
r = NUM_RESERVED; // don't pick a reserved node number
|
||||
@@ -247,15 +258,18 @@ void NodeDB::saveToDisk()
|
||||
if (!pb_encode(&stream, DeviceState_fields, &devicestate)) {
|
||||
DEBUG_MSG("Error: can't write protobuf %s\n", PB_GET_ERROR(&stream));
|
||||
// FIXME - report failure to phone
|
||||
|
||||
f.close();
|
||||
} else {
|
||||
// Success - replace the old file
|
||||
f.close();
|
||||
|
||||
// brief window of risk here ;-)
|
||||
if (!FS.remove(preffile))
|
||||
DEBUG_MSG("Warning: Can't remove old pref file\n");
|
||||
if (!FS.rename(preftmp, preffile))
|
||||
DEBUG_MSG("Error: can't rename new pref file\n");
|
||||
}
|
||||
|
||||
f.close();
|
||||
|
||||
// brief window of risk here ;-)
|
||||
if (!FS.remove(preffile))
|
||||
DEBUG_MSG("Warning: Can't remove old pref file\n");
|
||||
if (!FS.rename(preftmp, preffile))
|
||||
DEBUG_MSG("Error: can't rename new pref file\n");
|
||||
} else {
|
||||
DEBUG_MSG("ERROR: can't write prefs\n"); // FIXME report to app
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
#include "configuration.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
|
||||
|
||||
|
||||
PacketHistory::PacketHistory()
|
||||
{
|
||||
recentPackets.reserve(MAX_NUM_NODES); // Prealloc the worst case # of records - to prevent heap fragmentation
|
||||
@@ -48,7 +46,7 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate)
|
||||
r.sender = p->from;
|
||||
r.rxTimeMsec = now;
|
||||
recentPackets.push_back(r);
|
||||
DEBUG_MSG("Adding packet record for fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
|
||||
printPacket("Adding packet record", p);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "PhoneAPI.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RadioInterface.h"
|
||||
#include <assert.h>
|
||||
|
||||
PhoneAPI::PhoneAPI()
|
||||
@@ -14,16 +16,35 @@ void PhoneAPI::init()
|
||||
observe(&service.fromNumChanged);
|
||||
}
|
||||
|
||||
void PhoneAPI::checkConnectionTimeout()
|
||||
{
|
||||
if (isConnected) {
|
||||
bool newConnected = (millis() - lastContactMsec < radioConfig.preferences.phone_timeout_secs * 1000L);
|
||||
if (!newConnected) {
|
||||
isConnected = false;
|
||||
onConnectionChanged(isConnected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a ToRadio protobuf
|
||||
*/
|
||||
void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
{
|
||||
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE); // As long as the phone keeps talking to us, don't let the radio go to sleep
|
||||
lastContactMsec = millis();
|
||||
if (!isConnected) {
|
||||
isConnected = true;
|
||||
onConnectionChanged(isConnected);
|
||||
}
|
||||
// return (lastContactMsec != 0) &&
|
||||
|
||||
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
|
||||
switch (toRadioScratch.which_variant) {
|
||||
case ToRadio_packet_tag: {
|
||||
// If our phone is sending a position, see if we can use it to set our RTC
|
||||
MeshPacket &p = toRadioScratch.variant.packet;
|
||||
printPacket("PACKET FROM PHONE", &p);
|
||||
service.handleToRadio(p);
|
||||
break;
|
||||
}
|
||||
@@ -71,8 +92,12 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
*/
|
||||
size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
{
|
||||
if (!available())
|
||||
if (!available()) {
|
||||
DEBUG_MSG("getFromRadio, !available\n");
|
||||
return false;
|
||||
} else {
|
||||
DEBUG_MSG("getFromRadio, state=%d\n", state);
|
||||
}
|
||||
|
||||
// In case we send a FromRadio packet
|
||||
memset(&fromRadioScratch, 0, sizeof(fromRadioScratch));
|
||||
@@ -227,6 +252,9 @@ void PhoneAPI::handleToRadioPacket(MeshPacket *p) {}
|
||||
/// If the mesh service tells us fromNum has changed, tell the phone
|
||||
int PhoneAPI::onNotify(uint32_t newValue)
|
||||
{
|
||||
checkConnectionTimeout(); // a handy place to check if we've heard from the phone (since the BLE version doesn't call this
|
||||
// from idle)
|
||||
|
||||
if (state == STATE_SEND_PACKETS || state == STATE_LEGACY) {
|
||||
DEBUG_MSG("Telling client we have new packets %u\n", newValue);
|
||||
onNowHasData(newValue);
|
||||
|
||||
@@ -50,6 +50,11 @@ class PhoneAPI
|
||||
/// Use to ensure that clients don't get confused about old messages from the radio
|
||||
uint32_t config_nonce = 0;
|
||||
|
||||
/** the last msec we heard from the client on the other side of this link */
|
||||
uint32_t lastContactMsec = 0;
|
||||
|
||||
bool isConnected = false;
|
||||
|
||||
public:
|
||||
PhoneAPI();
|
||||
|
||||
@@ -85,6 +90,12 @@ class PhoneAPI
|
||||
/// Our fromradio packet while it is being assembled
|
||||
FromRadio fromRadioScratch;
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
virtual void onConnectionChanged(bool connected) {}
|
||||
|
||||
/// If we haven't heard from the other side in a while then say not connected
|
||||
void checkConnectionTimeout();
|
||||
|
||||
/**
|
||||
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
||||
*/
|
||||
|
||||
@@ -24,7 +24,53 @@ separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts
|
||||
// 1kb was too small
|
||||
#define RADIO_STACK_SIZE 4096
|
||||
|
||||
RadioInterface::RadioInterface() : txQueue(MAX_TX_QUEUE)
|
||||
void printPacket(const char *prefix, const MeshPacket *p)
|
||||
{
|
||||
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack,
|
||||
p->hop_limit);
|
||||
if (p->which_payload == MeshPacket_decoded_tag) {
|
||||
auto &s = p->decoded;
|
||||
switch (s.which_payload) {
|
||||
case SubPacket_data_tag:
|
||||
DEBUG_MSG(" Payload:Data");
|
||||
break;
|
||||
case SubPacket_position_tag:
|
||||
DEBUG_MSG(" Payload:Position");
|
||||
break;
|
||||
case SubPacket_user_tag:
|
||||
DEBUG_MSG(" Payload:User");
|
||||
break;
|
||||
case 0:
|
||||
DEBUG_MSG(" Payload:None");
|
||||
break;
|
||||
default:
|
||||
DEBUG_MSG(" Payload:%d", s.which_payload);
|
||||
break;
|
||||
}
|
||||
if (s.want_response)
|
||||
DEBUG_MSG(" WANTRESP");
|
||||
|
||||
if (s.source != 0)
|
||||
DEBUG_MSG(" source=%08x", s.source);
|
||||
|
||||
if (s.dest != 0)
|
||||
DEBUG_MSG(" dest=%08x", s.dest);
|
||||
|
||||
if (s.which_ack == SubPacket_success_id_tag)
|
||||
DEBUG_MSG(" successId=%08x", s.ack.success_id);
|
||||
else if (s.which_ack == SubPacket_fail_id_tag)
|
||||
DEBUG_MSG(" failId=%08x", s.ack.fail_id);
|
||||
} else {
|
||||
DEBUG_MSG(" encrypted");
|
||||
}
|
||||
|
||||
if (p->rx_time != 0) {
|
||||
DEBUG_MSG(" rxtime=%u", p->rx_time);
|
||||
}
|
||||
DEBUG_MSG(")\n");
|
||||
}
|
||||
|
||||
RadioInterface::RadioInterface()
|
||||
{
|
||||
assert(sizeof(PacketHeader) == 4 || sizeof(PacketHeader) == 16); // make sure the compiler did what we expected
|
||||
|
||||
|
||||
@@ -59,7 +59,6 @@ class RadioInterface : protected NotifiedWorkerThread
|
||||
|
||||
protected:
|
||||
MeshPacket *sendingPacket = NULL; // The packet we are currently sending
|
||||
PointerQueue<MeshPacket> txQueue;
|
||||
uint32_t lastTxStart = 0L;
|
||||
|
||||
/**
|
||||
@@ -163,3 +162,6 @@ class SimRadio : public RadioInterface
|
||||
/// \return true if initialisation succeeded.
|
||||
virtual bool init() { return true; }
|
||||
};
|
||||
|
||||
/// Debug printing for packets
|
||||
void printPacket(const char *prefix, const MeshPacket *p);
|
||||
@@ -114,8 +114,8 @@ bool RadioLibInterface::canSendImmediately()
|
||||
/// bluetooth comms code. If the txmit queue is empty it might return an error
|
||||
ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
{
|
||||
DEBUG_MSG("enqueuing for send on mesh fr=0x%x,to=0x%x,id=%d (txGood=%d,rxGood=%d,rxBad=%d)\n", p->from, p->to, p->id, txGood,
|
||||
rxGood, rxBad);
|
||||
printPacket("enqueuing for send", p);
|
||||
DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad);
|
||||
ErrorCode res = txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN;
|
||||
|
||||
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
|
||||
@@ -134,7 +134,7 @@ bool RadioLibInterface::canSleep()
|
||||
{
|
||||
bool res = txQueue.isEmpty();
|
||||
if (!res) // only print debug messages if we are vetoing sleep
|
||||
DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", txQueue.isEmpty());
|
||||
DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", res);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -173,11 +173,13 @@ void RadioLibInterface::loop()
|
||||
case ISR_TX:
|
||||
handleTransmitInterrupt();
|
||||
startReceive();
|
||||
// DEBUG_MSG("tx complete - starting timer\n");
|
||||
startTransmitTimer();
|
||||
break;
|
||||
case ISR_RX:
|
||||
handleReceiveInterrupt();
|
||||
startReceive();
|
||||
// DEBUG_MSG("rx complete - starting timer\n");
|
||||
startTransmitTimer();
|
||||
break;
|
||||
case TRANSMIT_DELAY_COMPLETED:
|
||||
@@ -192,6 +194,8 @@ void RadioLibInterface::loop()
|
||||
assert(txp);
|
||||
startSend(txp);
|
||||
}
|
||||
} else {
|
||||
// DEBUG_MSG("done with txqueue\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -216,7 +220,7 @@ void RadioLibInterface::startTransmitTimer(bool withDelay)
|
||||
uint32_t delay =
|
||||
!withDelay ? 1 : random(MIN_TX_WAIT_MSEC, MAX_TX_WAIT_MSEC); // See documentation for loop() wrt these values
|
||||
// DEBUG_MSG("xmit timer %d\n", delay);
|
||||
|
||||
// DEBUG_MSG("delaying %u\n", delay);
|
||||
setPeriod(delay);
|
||||
}
|
||||
}
|
||||
@@ -233,7 +237,7 @@ void RadioLibInterface::completeSending()
|
||||
{
|
||||
if (sendingPacket) {
|
||||
txGood++;
|
||||
DEBUG_MSG("Completed sending to=0x%x, id=%u\n", sendingPacket->to, sendingPacket->id);
|
||||
printPacket("Completed sending", sendingPacket);
|
||||
|
||||
// We are done sending that packet, release it
|
||||
packetPool.release(sendingPacket);
|
||||
@@ -287,7 +291,7 @@ void RadioLibInterface::handleReceiveInterrupt()
|
||||
memcpy(mp->encrypted.bytes, payload, payloadLen);
|
||||
mp->encrypted.size = payloadLen;
|
||||
|
||||
DEBUG_MSG("Lora RX interrupt from=0x%x, id=%u\n", mp->from, mp->id);
|
||||
printPacket("Lora RX", mp);
|
||||
|
||||
deliverToReceiver(mp);
|
||||
}
|
||||
@@ -297,7 +301,7 @@ void RadioLibInterface::handleReceiveInterrupt()
|
||||
/** start an immediate transmit */
|
||||
void RadioLibInterface::startSend(MeshPacket *txp)
|
||||
{
|
||||
DEBUG_MSG("Starting low level send from=0x%x, to=0x%x, id=%u, want_ack=%d\n", txp->from, txp->to, txp->id, txp->want_ack);
|
||||
printPacket("Starting low level send", txp);
|
||||
setStandby(); // Cancel any already in process receives
|
||||
|
||||
size_t numbytes = beginSending(txp);
|
||||
|
||||
@@ -29,6 +29,8 @@ class RadioLibInterface : public RadioInterface, private PeriodicTask
|
||||
*/
|
||||
uint32_t rxBad = 0, rxGood = 0, txGood = 0;
|
||||
|
||||
PointerQueue<MeshPacket> txQueue = PointerQueue<MeshPacket>(MAX_TX_QUEUE);
|
||||
|
||||
protected:
|
||||
float bw = 125;
|
||||
uint8_t sf = 9;
|
||||
|
||||
@@ -27,7 +27,7 @@ ErrorCode ReliableRouter::send(MeshPacket *p)
|
||||
bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
|
||||
{
|
||||
if (p->to == NODENUM_BROADCAST && p->from == getNodeNum()) {
|
||||
DEBUG_MSG("Received someone rebroadcasting for us fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
|
||||
printPacket("Rx someone rebroadcasting for us", p);
|
||||
|
||||
// We are seeing someone rebroadcast one of our broadcast attempts.
|
||||
// If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for
|
||||
|
||||
@@ -19,11 +19,15 @@
|
||||
4 // max number of packets destined to our queue, we dispatch packets quickly so it doesn't need to be big
|
||||
|
||||
// I think this is right, one packet for each of the three fifos + one packet being currently assembled for TX or RX
|
||||
// And every TX packet might have a retransmission packet or an ack alive at any moment
|
||||
#define MAX_PACKETS \
|
||||
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + MAX_TX_QUEUE + \
|
||||
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \
|
||||
2) // max number of packets which can be in flight (either queued from reception or queued for sending)
|
||||
|
||||
MemoryPool<MeshPacket> packetPool(MAX_PACKETS);
|
||||
static MemoryPool<MeshPacket> staticPool(MAX_PACKETS);
|
||||
// static MemoryDynamic<MeshPacket> staticPool;
|
||||
|
||||
Allocator<MeshPacket> &packetPool = staticPool;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -56,8 +60,11 @@ PacketId generatePacketId()
|
||||
|
||||
if (!didInit) {
|
||||
didInit = true;
|
||||
i = random(0, numPacketId +
|
||||
1); // pick a random initial sequence number at boot (to prevent repeated reboots always starting at 0)
|
||||
|
||||
// pick a random initial sequence number at boot (to prevent repeated reboots always starting at 0)
|
||||
// Note: we mask the high order bit to ensure that we never pass a 'negative' number to random
|
||||
i = random(numPacketId & 0x7fffffff);
|
||||
DEBUG_MSG("Initial packet id %u, numPacketId %u\n", i, numPacketId);
|
||||
}
|
||||
|
||||
i++;
|
||||
@@ -143,8 +150,8 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
*/
|
||||
void Router::sniffReceived(const MeshPacket *p)
|
||||
{
|
||||
DEBUG_MSG("FIXME-update-db Sniffing packet fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
|
||||
// FIXME, update nodedb
|
||||
DEBUG_MSG("FIXME-update-db Sniffing packet\n");
|
||||
// FIXME, update nodedb here for any packet that passes through us
|
||||
}
|
||||
|
||||
bool Router::perhapsDecode(MeshPacket *p)
|
||||
@@ -195,7 +202,7 @@ void Router::handleReceived(MeshPacket *p)
|
||||
sniffReceived(p);
|
||||
|
||||
if (p->to == NODENUM_BROADCAST || p->to == getNodeNum()) {
|
||||
DEBUG_MSG("Notifying observers of received packet fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
|
||||
printPacket("Delivering rx packet", p);
|
||||
notifyPacketReceived.notifyObservers(p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ void StreamAPI::loop()
|
||||
{
|
||||
writeStream();
|
||||
readStream();
|
||||
checkConnectionTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
PB_BIND(Position, Position, AUTO)
|
||||
|
||||
|
||||
PB_BIND(Data, Data, 2)
|
||||
PB_BIND(Data, Data, AUTO)
|
||||
|
||||
|
||||
PB_BIND(User, User, AUTO)
|
||||
|
||||
@@ -47,7 +47,7 @@ typedef struct _ChannelSettings {
|
||||
char name[12];
|
||||
} ChannelSettings;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(251) Data_payload_t;
|
||||
typedef PB_BYTES_ARRAY_T(240) Data_payload_t;
|
||||
typedef struct _Data {
|
||||
Data_Type typ;
|
||||
Data_payload_t payload;
|
||||
@@ -586,20 +586,20 @@ extern const pb_msgdesc_t ManufacturingData_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define Position_size 39
|
||||
#define Data_size 256
|
||||
#define Data_size 245
|
||||
#define User_size 72
|
||||
#define RouteDiscovery_size 88
|
||||
#define SubPacket_size 285
|
||||
#define MeshPacket_size 324
|
||||
#define SubPacket_size 274
|
||||
#define MeshPacket_size 313
|
||||
#define ChannelSettings_size 60
|
||||
#define RadioConfig_size 157
|
||||
#define RadioConfig_UserPreferences_size 93
|
||||
#define NodeInfo_size 132
|
||||
#define MyNodeInfo_size 110
|
||||
#define DeviceState_size 15463
|
||||
#define DeviceState_size 15100
|
||||
#define DebugString_size 258
|
||||
#define FromRadio_size 333
|
||||
#define ToRadio_size 327
|
||||
#define FromRadio_size 322
|
||||
#define ToRadio_size 316
|
||||
/* ManufacturingData_size depends on runtime parameters */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -34,7 +34,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#define FONT_HEIGHT 14 // actually 13 for "ariel 10" but want a little extra space
|
||||
#define FONT_HEIGHT_16 (ArialMT_Plain_16[1] + 1)
|
||||
#ifdef USE_SH1106
|
||||
#define SCREEN_WIDTH 132
|
||||
#else
|
||||
#define SCREEN_WIDTH 128
|
||||
#endif
|
||||
#define SCREEN_HEIGHT 64
|
||||
#define TRANSITION_FRAMERATE 30 // fps
|
||||
#define IDLE_FRAMERATE 10 // in fps
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
#include <cstring>
|
||||
|
||||
#include <OLEDDisplayUi.h>
|
||||
|
||||
#ifdef USE_SH1106
|
||||
#include <SH1106Wire.h>
|
||||
#else
|
||||
#include <SSD1306Wire.h>
|
||||
#endif
|
||||
|
||||
#include "PeriodicTask.h"
|
||||
#include "TypedQueue.h"
|
||||
@@ -211,7 +216,11 @@ class Screen : public PeriodicTask
|
||||
/// Holds state for debug information
|
||||
DebugInfo debugInfo;
|
||||
/// Display device
|
||||
#ifdef USE_SH1106
|
||||
SH1106Wire dispdev;
|
||||
#else
|
||||
SSD1306Wire dispdev;
|
||||
#endif
|
||||
/// UI helper for rendering to frames and switching between them
|
||||
OLEDDisplayUi ui;
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "esp_pm.h"
|
||||
#include "rom/rtc.h"
|
||||
#include <driver/rtc_io.h>
|
||||
#include <driver/uart.h>
|
||||
|
||||
#include "BluetoothUtil.h"
|
||||
|
||||
@@ -111,8 +112,7 @@ void initDeepSleep()
|
||||
#endif
|
||||
}
|
||||
|
||||
/// return true if sleep is allowed
|
||||
static bool doPreflightSleep()
|
||||
bool doPreflightSleep()
|
||||
{
|
||||
if (preflightSleep.notifyObservers(NULL) != 0)
|
||||
return false; // vetoed
|
||||
@@ -129,6 +129,7 @@ static void waitEnterSleep()
|
||||
|
||||
if (millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep
|
||||
recordCriticalError(ErrSleepEnterWait);
|
||||
ESP.restart(); // FIXME - for now we just restart, need to fix bug #167
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -256,6 +257,17 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
|
||||
gpio_pullup_en((gpio_num_t)BUTTON_PIN);
|
||||
#endif
|
||||
|
||||
#ifdef SERIAL0_RX_GPIO
|
||||
// We treat the serial port as a GPIO for a fast/low power way of waking, if we see a rising edge that means
|
||||
// someone started to send something
|
||||
|
||||
// Alas - doesn't work reliably, instead need to use the uart specific version (which burns a little power)
|
||||
// FIXME: gpio 3 is RXD for serialport 0 on ESP32
|
||||
// Send a few Z characters to wake the port
|
||||
gpio_wakeup_enable((gpio_num_t)SERIAL0_RX_GPIO, GPIO_INTR_LOW_LEVEL);
|
||||
// uart_set_wakeup_threshold(UART_NUM_0, 3);
|
||||
// esp_sleep_enable_uart_wakeup(0);
|
||||
#endif
|
||||
#ifdef BUTTON_PIN
|
||||
gpio_wakeup_enable((gpio_num_t)BUTTON_PIN, GPIO_INTR_LOW_LEVEL); // when user presses, this button goes low
|
||||
#endif
|
||||
@@ -279,7 +291,7 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
|
||||
// not legal on the stock android ESP build
|
||||
|
||||
/**
|
||||
@@ -294,8 +306,8 @@ void enableModemSleep()
|
||||
static esp_pm_config_esp32_t config; // filled with zeros because bss
|
||||
|
||||
config.max_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
|
||||
config.min_freq_mhz = 10; // 10Mhz is minimum recommended
|
||||
config.min_freq_mhz = 20; // 10Mhz is minimum recommended
|
||||
config.light_sleep_enable = false;
|
||||
DEBUG_MSG("Sleep request result %x\n", esp_pm_configure(&config));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ void initDeepSleep();
|
||||
void setCPUFast(bool on);
|
||||
void setLed(bool ledOn);
|
||||
|
||||
/** return true if sleep is allowed right now */
|
||||
bool doPreflightSleep();
|
||||
|
||||
extern int bootCount;
|
||||
|
||||
// is bluetooth sw currently running?
|
||||
@@ -31,4 +34,6 @@ extern Observable<void *> preflightSleep;
|
||||
extern Observable<void *> notifySleep;
|
||||
|
||||
/// Called to tell observers we are now entering (deep) sleep and you should prepare. Must return 0
|
||||
extern Observable<void *> notifyDeepSleep;
|
||||
extern Observable<void *> notifyDeepSleep;
|
||||
|
||||
void enableModemSleep();
|
||||
Reference in New Issue
Block a user