Merge pull request #87 from geeksville/cleanupblue

Refactoring to cleanup the relationship between bluetooth and everything else
1.2-legacy
Kevin Hester 2020-04-15 14:19:38 -07:00 zatwierdzone przez GitHub
commit a8f5ff1fbd
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
23 zmienionych plików z 343 dodań i 171 usunięć

Wyświetl plik

@ -3,4 +3,4 @@ set -e
source bin/version.sh
esptool.py --baud 921600 write_flash 0x10000 release/latest/firmware-HELTEC-US-$VERSION.bin
esptool.py --baud 921600 write_flash 0x10000 release/latest/bins/firmware-heltec-US-$VERSION.bin

Wyświetl plik

@ -3,4 +3,4 @@ set -e
source bin/version.sh
esptool.py --baud 921600 write_flash 0x10000 release/latest/firmware-TBEAM-US-$VERSION.bin
esptool.py --baud 921600 write_flash 0x10000 release/latest/bins/firmware-tbeam-US-$VERSION.bin

Wyświetl plik

@ -15,6 +15,11 @@ default_envs = tbeam
; default to a US frequency range, change it as needed for your region and hardware (CN, JP, EU433, EU865)
hw_version = US
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
src_filter =
${env.src_filter} -<bare/>
[env]
platform = espressif32
framework = arduino
@ -70,7 +75,8 @@ lib_deps =
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git
; The 1.0 release of the TBEAM board
[env:tbeam]
[env:tbeam]
extends = esp32_base
board = ttgo-t-beam
lib_deps =
${env.lib_deps}
@ -79,22 +85,26 @@ build_flags =
${env.build_flags} -D TBEAM_V10
; The original TBEAM board without the AXP power chip and a few other changes
[env:tbeam0.7]
[env:tbeam0.7]
extends = esp32_base
board = ttgo-t-beam
build_flags =
${env.build_flags} -D TBEAM_V07
[env:heltec]
;build_type = debug ; to make it possible to step through our jtag debugger
extends = esp32_base
board = heltec_wifi_lora_32_V2
[env:ttgo-lora32-v1]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${env.build_flags} -D TTGO_LORA_V1
; note: the platformio definition for lora32-v2 seems stale, it is missing a pins_arduino.h file, therefore I don't think it works
[env:ttgo-lora32-v2]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${env.build_flags} -D TTGO_LORA_V2
@ -104,4 +114,8 @@ build_flags =
[env:bare]
board = ttgo-lora32-v1
build_flags =
${env.build_flags} -D BARE_BOARD
${env.build_flags} -D BARE_BOARD
src_filter =
${env.src_filter} -<esp32/>
lib_ignore =
BluetoothOTA

Wyświetl plik

@ -192,7 +192,7 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
hasValidLocation = (latitude != 0) || (longitude != 0); // bogus lat lon is reported as 0,0
if (hasValidLocation) {
wantNewLocation = false;
notifyObservers();
notifyObservers(NULL);
// ublox.powerOff();
}
} else // we didn't get a location update, go back to sleep and hope the characters show up

Wyświetl plik

@ -10,7 +10,7 @@
*
* When new data is available it will notify observers.
*/
class GPS : public PeriodicTask, public Observable
class GPS : public PeriodicTask, public Observable<void *>
{
SFE_UBLOX_GPS ublox;

Wyświetl plik

@ -5,8 +5,10 @@
#include <assert.h>
#include "MeshRadio.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "configuration.h"
#include "sleep.h"
#include <pb_decode.h>
#include <pb_encode.h>
@ -25,7 +27,7 @@ separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts
bool useHardware = true;
MeshRadio::MeshRadio(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest)
: radioIf(_pool, _rxDest) // , manager(radioIf)
: radioIf(_pool, _rxDest), sendPacketObserver(this, &MeshRadio::send) // , manager(radioIf)
{
myNodeInfo.num_channels = NUM_CHANNELS;
@ -40,6 +42,11 @@ bool MeshRadio::init()
DEBUG_MSG("Starting meshradio init...\n");
configChangedObserver.observe(&service.configChanged);
sendPacketObserver.observe(&service.sendViaRadio);
preflightSleepObserver.observe(&preflightSleep);
notifyDeepSleepObserver.observe(&notifyDeepSleep);
#ifdef RESET_GPIO
pinMode(RESET_GPIO, OUTPUT); // Deassert reset
digitalWrite(RESET_GPIO, HIGH);
@ -84,7 +91,7 @@ unsigned long hash(char *str)
return hash;
}
void MeshRadio::reloadConfig()
int MeshRadio::reloadConfig(void *unused)
{
radioIf.setModeIdle(); // Need to be idle before doing init
@ -116,17 +123,21 @@ void MeshRadio::reloadConfig()
// Done with init tell radio to start receiving
radioIf.setModeRx();
return 0;
}
ErrorCode MeshRadio::send(MeshPacket *p)
int MeshRadio::send(MeshPacket *p)
{
lastTxStart = millis();
if (useHardware)
return radioIf.send(p);
else {
radioIf.pool.release(p);
return ERRNO_OK;
if (useHardware) {
radioIf.send(p);
// Note: we ignore the error code, because no matter what the interface has already freed the packet.
return 1; // Indicate success - stop offering this packet to radios
} else {
// fail
return 0;
}
}

Wyświetl plik

@ -3,6 +3,7 @@
#include "CustomRF95.h"
#include "MemoryPool.h"
#include "MeshTypes.h"
#include "Observer.h"
#include "PointerQueue.h"
#include "configuration.h"
#include "mesh.pb.h"
@ -80,22 +81,42 @@ class MeshRadio
bool init();
/// Send a packet (possibly by enquing in a private fifo). This routine will
/// later free() the packet to pool. This routine is not allowed to stall because it is called from
/// bluetooth comms code. If the txmit queue is empty it might return an error
ErrorCode send(MeshPacket *p);
/// Do loop callback operations (we currently FIXME poll the receive mailbox here)
/// for received packets it will call the rx handler
void loop();
/// The radioConfig object just changed, call this to force the hw to change to the new settings
void reloadConfig();
private:
// RHReliableDatagram manager; // don't use mesh yet
// RHMesh manager;
/// Used for the tx timer watchdog, to check for bugs in our transmit code, msec of last time we did a send
uint32_t lastTxStart = 0;
CallbackObserver<MeshRadio, void *> configChangedObserver =
CallbackObserver<MeshRadio, void *>(this, &MeshRadio::reloadConfig);
CallbackObserver<MeshRadio, void *> preflightSleepObserver =
CallbackObserver<MeshRadio, void *>(this, &MeshRadio::preflightSleepCb);
CallbackObserver<MeshRadio, void *> notifyDeepSleepObserver =
CallbackObserver<MeshRadio, void *>(this, &MeshRadio::notifyDeepSleepDb);
CallbackObserver<MeshRadio, MeshPacket *> sendPacketObserver; /* =
CallbackObserver<MeshRadio, MeshPacket *>(this, &MeshRadio::send); */
/// Send a packet (possibly by enquing in a private fifo). This routine will
/// later free() the packet to pool. This routine is not allowed to stall because it is called from
/// bluetooth comms code. If the txmit queue is empty it might return an error.
///
/// Returns 1 for success or 0 for failure (and if we fail it is the _callers_ responsibility to free the packet)
int send(MeshPacket *p);
/// The radioConfig object just changed, call this to force the hw to change to the new settings
int reloadConfig(void *unused = NULL);
/// Return 0 if sleep is okay
int preflightSleepCb(void *unused = NULL) { return radioIf.canSleep() ? 0 : 1; }
int notifyDeepSleepDb(void *unused = NULL)
{
radioIf.sleep();
return 0;
}
};

Wyświetl plik

@ -3,7 +3,7 @@
#include <assert.h>
#include "GPS.h"
#include "MeshBluetoothService.h"
//#include "MeshBluetoothService.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "Periodic.h"
@ -51,9 +51,7 @@ MeshService service;
#define MAX_RX_FROMRADIO \
4 // max number of packets destined to our queue, we dispatch packets quickly so it doesn't need to be big
MeshService::MeshService()
: packetPool(MAX_PACKETS), toPhoneQueue(MAX_RX_TOPHONE), fromRadioQueue(MAX_RX_FROMRADIO), fromNum(0),
radio(packetPool, fromRadioQueue)
MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE), packetPool(MAX_PACKETS), fromRadioQueue(MAX_RX_FROMRADIO)
{
// assert(MAX_RX_TOPHONE == 32); // FIXME, delete this, just checking my clever macro
}
@ -62,10 +60,7 @@ void MeshService::init()
{
nodeDB.init();
if (!radio.init())
DEBUG_MSG("radio init failed\n");
gps.addObserver(this);
gpsObserver.observe(&gps);
// No need to call this here, our periodic task will fire quite soon
// sendOwnerPeriod();
@ -191,7 +186,7 @@ void MeshService::handleFromRadio()
handleFromRadio(mp);
}
if (oldFromNum != fromNum) // We don't want to generate extra notifies for multiple new packets
bluetoothNotifyFromNum(fromNum);
fromNumChanged.notifyObservers(fromNum);
}
uint32_t sendOwnerCb()
@ -206,8 +201,6 @@ Periodic sendOwnerPeriod(sendOwnerCb);
/// Do idle processing (mostly processing messages which have been queued from the radio)
void MeshService::loop()
{
radio.loop(); // FIXME, possibly move radio interaction to own thread
handleFromRadio();
// occasionally send our owner info
@ -219,7 +212,7 @@ void MeshService::reloadConfig()
{
// If we can successfully set this radio to these settings, save them to disk
nodeDB.resetRadioConfig(); // Don't let the phone send us fatally bad settings
radio.reloadConfig();
configChanged.notifyObservers(NULL);
nodeDB.saveToDisk();
}
@ -244,7 +237,7 @@ void MeshService::handleToRadio(std::string s)
if (loopback) {
MeshPacket *mp = packetPool.allocCopy(r.variant.packet);
handleFromRadio(mp);
bluetoothNotifyFromNum(fromNum); // tell the phone a new packet arrived
// handleFromRadio will tell the phone a new packet arrived
}
break;
}
@ -277,8 +270,11 @@ void MeshService::sendToMesh(MeshPacket *p)
DEBUG_MSG("Dropping locally processed message\n");
else {
// Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it
if (radio.send(p) != ERRNO_OK)
DEBUG_MSG("Dropped packet because send queue was full!\n");
int didSend = sendViaRadio.notifyObservers(p);
if (!didSend) {
DEBUG_MSG("No radio was able to send packet, discarding...\n");
releaseToPool(p);
}
}
}
@ -323,8 +319,10 @@ void MeshService::sendOurPosition(NodeNum dest, bool wantReplies)
sendToMesh(p);
}
void MeshService::onGPSChanged()
int MeshService::onGPSChanged(void *unused)
{
DEBUG_MSG("got gps notify\n");
// Update our local node info with our position (even if we don't decide to update anyone else)
MeshPacket *p = allocForSending();
p->payload.which_variant = SubPacket_position_tag;
@ -353,10 +351,6 @@ void MeshService::onGPSChanged()
releaseToPool(p);
}
}
void MeshService::onNotify(Observable *o)
{
DEBUG_MSG("got gps notify\n");
onGPSChanged();
return 0;
}

Wyświetl plik

@ -13,9 +13,9 @@
* Top level app for this service. keeps the mesh, the radio config and the queue of received packets.
*
*/
class MeshService : private Observer
class MeshService
{
MemoryPool<MeshPacket> packetPool;
CallbackObserver<MeshService, void *> gpsObserver = CallbackObserver<MeshService, void *>(this, &MeshService::onGPSChanged);
/// received packets waiting for the phone to process them
/// FIXME, change to a DropOldestQueue and keep a count of the number of dropped packets to ensure
@ -23,15 +23,25 @@ class MeshService : private Observer
/// FIXME - save this to flash on deep sleep
PointerQueue<MeshPacket> toPhoneQueue;
/// The current nonce for the newest packet which has been queued for the phone
uint32_t fromNum = 0;
public:
MemoryPool<MeshPacket> packetPool;
/// Packets which have just arrived from the radio, ready to be processed by this service and possibly
/// forwarded to the phone.
PointerQueue<MeshPacket> fromRadioQueue;
/// The current nonce for the newest packet which has been queued for the phone
uint32_t fromNum;
/// Called when some new packets have arrived from one of the radios
Observable<uint32_t> fromNumChanged;
public:
MeshRadio radio;
/// Called when radio config has changed (radios should observe this and set their hardware as required)
Observable<void *> configChanged;
/// Radios should observe this and return 0 if they were unable to process the packet or 1 if they were (and therefore it
/// should not be offered to other radios)
Observable<MeshPacket *> sendViaRadio;
MeshService();
@ -76,14 +86,14 @@ class MeshService : private Observer
void sendToMesh(MeshPacket *p);
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
void onGPSChanged();
virtual void onNotify(Observable *o);
/// returns 0 to allow futher processing
int onGPSChanged(void *arg);
/// handle all the packets that just arrived from the mesh radio
void handleFromRadio();
/// Handle a packet that just arrived from the radio. We will either eventually enqueue the message to the phone or return it to the free pool
/// Handle a packet that just arrived from the radio. We will either eventually enqueue the message to the phone or return it
/// to the free pool
void handleFromRadio(MeshPacket *p);
/// handle a user packet that just arrived on the radio, return NULL if we should not process this packet at all

Wyświetl plik

@ -1,13 +1,2 @@
#include "Observer.h"
Observer::~Observer()
{
if (observed)
observed->removeObserver(this);
observed = NULL;
}
void Observer::observe(Observable *o)
{
o->addObserver(this);
}

Wyświetl plik

@ -4,38 +4,93 @@
#include <list>
class Observable;
template <class T> class Observable;
class Observer
/**
* An observer which can be mixed in as a baseclass. Implement onNotify as a method in your class.
*/
template <class T> class Observer
{
Observable *observed;
Observable<T> *observed;
public:
Observer() : observed(NULL) {}
virtual ~Observer();
void observe(Observable *o);
void observe(Observable<T> *o);
private:
friend class Observable;
friend class Observable<T>;
virtual void onNotify(Observable *o) = 0;
protected:
/**
* returns 0 if other observers should continue to be called
* returns !0 if the observe calls should be aborted and this result code returned for notifyObservers
**/
virtual int onNotify(T arg) = 0;
};
class Observable
/**
* An observer that calls an arbitrary method
*/
template <class Callback, class T> class CallbackObserver : public Observer<T>
{
std::list<Observer *> observers;
typedef int (Callback::*ObserverCallback)(T arg);
Callback *objPtr;
ObserverCallback method;
public:
void notifyObservers()
CallbackObserver(Callback *_objPtr, ObserverCallback _method) : objPtr(_objPtr), method(_method) {}
protected:
virtual int onNotify(T arg) { return (objPtr->*method)(arg); }
};
/**
* An observable class that will notify observers anytime notifyObservers is called. Argument type T can be any type, but for
* performance reasons a pointer or word sized object is recommended.
*/
template <class T> class Observable
{
std::list<Observer<T> *> observers;
public:
/**
* Tell all observers about a change, observers can process arg as they wish
*
* returns !0 if an observer chose to abort processing by returning this code
*/
int notifyObservers(T arg)
{
for (std::list<Observer *>::const_iterator iterator = observers.begin(); iterator != observers.end(); ++iterator) {
(*iterator)->onNotify(this);
for (typename std::list<Observer<T> *>::const_iterator iterator = observers.begin(); iterator != observers.end();
++iterator) {
int result = (*iterator)->onNotify(arg);
if (result != 0)
return result;
}
return 0;
}
void addObserver(Observer *o) { observers.push_back(o); }
private:
friend class Observer<T>;
void removeObserver(Observer *o) { observers.remove(o); }
// Not called directly, instead call observer.observe
void addObserver(Observer<T> *o) { observers.push_back(o); }
void removeObserver(Observer<T> *o) { observers.remove(o); }
};
template <class T> Observer<T>::~Observer()
{
if (observed)
observed->removeObserver(this);
observed = NULL;
}
template <class T> void Observer<T>::observe(Observable<T> *o)
{
o->addObserver(this);
}

Wyświetl plik

@ -7,6 +7,7 @@
#include "main.h"
#include "screen.h"
#include "sleep.h"
#include "target_specific.h"
static void sdsEnter()
{
@ -30,22 +31,6 @@ static void lsEnter()
DEBUG_MSG("lsEnter begin, ls_secs=%u\n", radioConfig.preferences.ls_secs);
screen.setOn(false);
uint32_t now = millis();
while (!service.radio.radioIf.canSleep()) {
delay(10); // Kinda yucky - wait until radio says say we can shutdown (finished in process sends/receives)
if (millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep
recordCriticalError(ErrSleepEnterWait);
break;
}
}
gps.prepareSleep(); // abandon in-process parsing
// if (!isUSBPowered) // FIXME - temp hack until we can put gps in sleep mode, if we have AC when we go to sleep then
// leave GPS on
// setGPSPower(false); // kill GPS power
DEBUG_MSG("lsEnter end\n");
}

Wyświetl plik

@ -0,0 +1,6 @@
#include "target_specific.h"
void setBluetoothEnable(bool on)
{
// Do nothing
}

Wyświetl plik

@ -202,6 +202,8 @@ 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 "bare"
#define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth)
#endif
// -----------------------------------------------------------------------------

Wyświetl plik

@ -1,7 +1,7 @@
#pragma once
/// Error codes for critical error
enum CriticalErrorCode { NoError, ErrTxWatchdog, ErrSleepEnterWait };
enum CriticalErrorCode { NoError, ErrTxWatchdog, ErrSleepEnterWait, ErrNoRadio };
/// Record an error that should be reported via analytics
void recordCriticalError(CriticalErrorCode code, uint32_t address = 0);

Wyświetl plik

@ -204,7 +204,7 @@ class FromRadioCharacteristic : public CallbackCharacteristic
}
};
class FromNumCharacteristic : public CallbackCharacteristic
class FromNumCharacteristic : public CallbackCharacteristic, public Observer<uint32_t>
{
public:
FromNumCharacteristic()
@ -212,6 +212,7 @@ class FromNumCharacteristic : public CallbackCharacteristic
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_NOTIFY)
{
observe(&service.fromNumChanged);
}
void onRead(BLECharacteristic *c)
@ -219,6 +220,14 @@ class FromNumCharacteristic : public CallbackCharacteristic
BLEKeepAliveCallbacks::onRead(c);
DEBUG_MSG("FIXME implement fromnum read\n");
}
/// If the mesh service tells us fromNum has changed, tell the phone
virtual int onNotify(uint32_t newValue)
{
setValue(newValue);
notify();
return 0;
}
};
class MyNodeInfoCharacteristic : public ProtobufCharacteristic
@ -244,18 +253,6 @@ class MyNodeInfoCharacteristic : public ProtobufCharacteristic
FromNumCharacteristic *meshFromNumCharacteristic;
/**
* Tell any bluetooth clients that the number of rx packets has changed
*/
void bluetoothNotifyFromNum(uint32_t newValue)
{
if (meshFromNumCharacteristic) {
// if bt not running ignore
meshFromNumCharacteristic->setValue(newValue);
meshFromNumCharacteristic->notify();
}
}
BLEService *meshService;
/*

Wyświetl plik

@ -0,0 +1,53 @@
#include "BluetoothUtil.h"
#include "MeshBluetoothService.h"
#include "PowerFSM.h"
#include "configuration.h"
#include "main.h"
#include "target_specific.h"
bool bluetoothOn;
// This routine is called multiple times, once each time we come back from sleep
void reinitBluetooth()
{
DEBUG_MSG("Starting bluetooth\n");
// FIXME - we are leaking like crazy
// AllocatorScope scope(btPool);
// Note: these callbacks might be coming in from a different thread.
BLEServer *serve = initBLE(
[](uint32_t pin) {
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
screen.startBluetoothPinScreen(pin);
},
[]() { screen.stopBluetoothPinScreen(); }, getDeviceName(), HW_VENDOR, xstr(APP_VERSION),
xstr(HW_VERSION)); // FIXME, use a real name based on the macaddr
createMeshBluetoothService(serve);
// Start advertising - this must be done _after_ creating all services
serve->getAdvertising()->start();
}
// Enable/disable bluetooth.
void setBluetoothEnable(bool on)
{
if (on != bluetoothOn) {
DEBUG_MSG("Setting bluetooth enable=%d\n", on);
bluetoothOn = on;
if (on) {
Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap());
// ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
reinitBluetooth();
} else {
// We have to totally teardown our bluetooth objects to prevent leaks
stopMeshBluetoothService(); // Must do before shutting down bluetooth
deinitBLE();
destroyMeshBluetoothService(); // must do after deinit, because it frees our service
Serial.printf("Shutdown BT: %u heap size\n", ESP.getFreeHeap());
// ESP_ERROR_CHECK( heap_trace_stop() );
// heap_trace_dump();
}
}
}

Wyświetl plik

@ -21,15 +21,14 @@
*/
#include "BluetoothUtil.h"
#include "GPS.h"
#include "MeshBluetoothService.h"
#include "MeshRadio.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "Periodic.h"
#include "PowerFSM.h"
#include "configuration.h"
#include "error.h"
#include "esp32/pm.h"
#include "esp_pm.h"
#include "power.h"
@ -39,6 +38,10 @@
#include <Wire.h>
#include <driver/rtc_io.h>
#ifndef NO_ESP32
#include "BluetoothUtil.h"
#endif
#ifdef TBEAM_V10
#include "axp20x.h"
AXP20X_Class axp;
@ -59,8 +62,6 @@ static meshtastic::PowerStatus powerStatus;
bool ssd1306_found;
bool axp192_found;
bool bluetoothOn;
// -----------------------------------------------------------------------------
// Application
// -----------------------------------------------------------------------------
@ -205,6 +206,8 @@ const char *getDeviceName()
return name;
}
static MeshRadio *radio = NULL;
void setup()
{
// Debug
@ -259,6 +262,14 @@ void setup()
service.init();
#ifndef NO_ESP32
// MUST BE AFTER service.init, so we have our radio config settings (from nodedb init)
radio = new MeshRadio(service.packetPool, service.fromRadioQueue);
#endif
if (radio && !radio->init())
recordCriticalError(ErrNoRadio);
// This must be _after_ service.init because we need our preferences loaded from flash to have proper timeout values
PowerFSM_setup(); // we will transition to ON in a couple of seconds, FIXME, only do this for cold boots, not waking from SDS
@ -266,49 +277,6 @@ void setup()
setCPUFast(false); // 80MHz is fine for our slow peripherals
}
void initBluetooth()
{
DEBUG_MSG("Starting bluetooth\n");
// FIXME - we are leaking like crazy
// AllocatorScope scope(btPool);
// Note: these callbacks might be coming in from a different thread.
BLEServer *serve = initBLE(
[](uint32_t pin) {
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
screen.startBluetoothPinScreen(pin);
},
[]() { screen.stopBluetoothPinScreen(); }, getDeviceName(), HW_VENDOR, xstr(APP_VERSION),
xstr(HW_VERSION)); // FIXME, use a real name based on the macaddr
createMeshBluetoothService(serve);
// Start advertising - this must be done _after_ creating all services
serve->getAdvertising()->start();
}
void setBluetoothEnable(bool on)
{
if (on != bluetoothOn) {
DEBUG_MSG("Setting bluetooth enable=%d\n", on);
bluetoothOn = on;
if (on) {
Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap());
// ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
initBluetooth();
} else {
// We have to totally teardown our bluetooth objects to prevent leaks
stopMeshBluetoothService(); // Must do before shutting down bluetooth
deinitBLE();
destroyMeshBluetoothService(); // must do after deinit, because it frees our service
Serial.printf("Shutdown BT: %u heap size\n", ESP.getFreeHeap());
// ESP_ERROR_CHECK( heap_trace_stop() );
// heap_trace_dump();
}
}
}
uint32_t ledBlinker()
{
static bool ledOn;
@ -350,12 +318,18 @@ void loop()
gps.loop();
service.loop();
if (radio)
radio->loop();
ledPeriodic.loop();
// axpDebugOutput.loop();
#ifndef NO_ESP32
loopBLE();
#endif
// for debug printing
// service.radio.radioIf.canSleep();
// radio.radioIf.canSleep();
#ifdef PMU_IRQ
if (pmu_irq) {

Wyświetl plik

@ -9,3 +9,6 @@ extern bool isUSBPowered;
// Global Screen singleton.
extern meshtastic::Screen screen;
// Return a human readable string of the form "Meshtastic_ab13"
const char *getDeviceName();

Wyświetl plik

@ -1,24 +1,34 @@
#include "sleep.h"
#include "BluetoothUtil.h"
#include "GPS.h"
#include "MeshBluetoothService.h"
#include "MeshRadio.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "Periodic.h"
#include "configuration.h"
#include "error.h"
#include "esp32/pm.h"
#include "esp_pm.h"
#include "main.h"
#include "rom/rtc.h"
#include "target_specific.h"
#include <Wire.h>
#include <driver/rtc_io.h>
#ifndef NO_ESP32
#include "BluetoothUtil.h"
#endif
#ifdef TBEAM_V10
#include "axp20x.h"
extern AXP20X_Class axp;
#endif
/// Called to ask any observers if they want to veto sleep. Return 1 to veto or 0 to allow sleep to happen
Observable<void *> preflightSleep;
/// Called to tell observers we are now entering sleep and you should prepare. Must return 0
Observable<void *> notifySleep, notifyDeepSleep;
// deep sleep support
RTC_DATA_ATTR int bootCount = 0;
esp_sleep_source_t wakeCause; // the reason we booted this time
@ -98,20 +108,53 @@ void initDeepSleep()
DEBUG_MSG("booted, wake cause %d (boot count %d), reset_reason=%s\n", wakeCause, bootCount, reason);
}
/// return true if sleep is allowed
static bool doPreflightSleep()
{
if (preflightSleep.notifyObservers(NULL) != 0)
return false; // vetoed
else
return true;
}
/// Tell devices we are going to sleep and wait for them to handle things
static void waitEnterSleep()
{
/*
former hardwired code - now moved into notifySleep callbacks:
// Put radio in sleep mode (will still draw power but only 0.2uA)
service.radio.radioIf.sleep();
*/
uint32_t now = millis();
while (!doPreflightSleep()) {
delay(10); // Kinda yucky - wait until radio says say we can shutdown (finished in process sends/receives)
if (millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep
recordCriticalError(ErrSleepEnterWait);
break;
}
}
// Code that still needs to be moved into notifyObservers
Serial.flush(); // send all our characters before we stop cpu clock
setBluetoothEnable(false); // has to be off before calling light sleep
gps.prepareSleep(); // abandon in-process parsing
notifySleep.notifyObservers(NULL);
}
void doDeepSleep(uint64_t msecToWake)
{
DEBUG_MSG("Entering deep sleep for %llu seconds\n", msecToWake / 1000);
// not using wifi yet, but once we are this is needed to shutoff the radio hw
// esp_wifi_stop();
BLEDevice::deinit(false); // We are required to shutdown bluetooth before deep or light sleep
waitEnterSleep();
notifyDeepSleep.notifyObservers(NULL);
screen.setOn(false); // datasheet says this will draw only 10ua
// Put radio in sleep mode (will still draw power but only 0.2uA)
service.radio.radioIf.sleep();
nodeDB.saveToDisk();
#ifdef RESET_OLED
@ -199,10 +242,10 @@ void doDeepSleep(uint64_t msecToWake)
esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more reasonable default
{
// DEBUG_MSG("Enter light sleep\n");
uint64_t sleepUsec = sleepMsec * 1000LL;
Serial.flush(); // send all our characters before we stop cpu clock
setBluetoothEnable(false); // has to be off before calling light sleep
waitEnterSleep();
uint64_t sleepUsec = sleepMsec * 1000LL;
// NOTE! ESP docs say we must disable bluetooth and wifi before light sleep

Wyświetl plik

@ -1,11 +1,11 @@
#pragma once
#include "Arduino.h"
#include "Observer.h"
#include "esp_sleep.h"
void doDeepSleep(uint64_t msecToWake);
esp_sleep_wakeup_cause_t doLightSleep(uint64_t msecToWake);
void setBluetoothEnable(bool on);
void setGPSPower(bool on);
// Perform power on init that we do on each wake from deep sleep
@ -18,4 +18,13 @@ extern int bootCount;
extern esp_sleep_source_t wakeCause;
// is bluetooth sw currently running?
extern bool bluetoothOn;
extern bool bluetoothOn;
/// Called to ask any observers if they want to veto sleep. Return 1 to veto or 0 to allow sleep to happen
extern Observable<void *> preflightSleep;
/// Called to tell observers we are now entering (light or deep) sleep and you should prepare. Must return 0
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;

Wyświetl plik

@ -0,0 +1,6 @@
#pragma once
// Functions that are unique to particular target types (esp32, bare, nrf52 etc...)
// Enable/disable bluetooth.
void setBluetoothEnable(bool on);