mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-10 07:02:11 +00:00
move bluetooth code into something that is architecture specific...
because the ESP32 implementation will be different from NRF52 to make this possible I needed to decouple knowlege about bluetooth from our mesh service. Instead mesh service now uses the Obserable pattern to let any interested consumer get notified of important mesh changes (currently that is only bluetooth, but really we should do the same thing for decoupling the GUI 'app' from the mesh service) @girtsf would you mind reviewing my Observer changes? I haven't written C++ code in a long time ;-)
This commit is contained in:
parent
93a06906cb
commit
6ad451eb5f
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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"
|
||||
@ -52,8 +52,7 @@ MeshService service;
|
||||
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)
|
||||
: packetPool(MAX_PACKETS), toPhoneQueue(MAX_RX_TOPHONE), fromRadioQueue(MAX_RX_FROMRADIO), radio(packetPool, fromRadioQueue)
|
||||
{
|
||||
// assert(MAX_RX_TOPHONE == 32); // FIXME, delete this, just checking my clever macro
|
||||
}
|
||||
@ -65,7 +64,7 @@ void MeshService::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 +190,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()
|
||||
@ -244,7 +243,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;
|
||||
}
|
||||
@ -323,8 +322,10 @@ void MeshService::sendOurPosition(NodeNum dest, bool wantReplies)
|
||||
sendToMesh(p);
|
||||
}
|
||||
|
||||
void MeshService::onGPSChanged()
|
||||
void 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;
|
||||
@ -354,9 +355,3 @@ void MeshService::onGPSChanged()
|
||||
releaseToPool(p);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshService::onNotify(Observable *o)
|
||||
{
|
||||
DEBUG_MSG("got gps notify\n");
|
||||
onGPSChanged();
|
||||
}
|
||||
|
@ -13,8 +13,10 @@
|
||||
* Top level app for this service. keeps the mesh, the radio config and the queue of received packets.
|
||||
*
|
||||
*/
|
||||
class MeshService : private Observer
|
||||
class MeshService
|
||||
{
|
||||
CallbackObserver<MeshService, void *> gpsObserver = CallbackObserver<MeshService, void *>(this, &MeshService::onGPSChanged);
|
||||
|
||||
MemoryPool<MeshPacket> packetPool;
|
||||
|
||||
/// received packets waiting for the phone to process them
|
||||
@ -28,11 +30,13 @@ class MeshService : private Observer
|
||||
PointerQueue<MeshPacket> fromRadioQueue;
|
||||
|
||||
/// The current nonce for the newest packet which has been queued for the phone
|
||||
uint32_t fromNum;
|
||||
uint32_t fromNum = 0;
|
||||
|
||||
public:
|
||||
MeshRadio radio;
|
||||
|
||||
Observable<uint32_t> fromNumChanged;
|
||||
|
||||
MeshService();
|
||||
|
||||
void init();
|
||||
@ -76,14 +80,13 @@ 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);
|
||||
void 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
|
||||
|
@ -1,13 +1,2 @@
|
||||
#include "Observer.h"
|
||||
|
||||
Observer::~Observer()
|
||||
{
|
||||
if (observed)
|
||||
observed->removeObserver(this);
|
||||
observed = NULL;
|
||||
}
|
||||
|
||||
void Observer::observe(Observable *o)
|
||||
{
|
||||
o->addObserver(this);
|
||||
}
|
@ -4,38 +4,83 @@
|
||||
|
||||
#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:
|
||||
virtual void 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 void (Callback::*ObserverCallback)(T arg);
|
||||
|
||||
Callback *objPtr;
|
||||
ObserverCallback method;
|
||||
|
||||
public:
|
||||
void notifyObservers()
|
||||
CallbackObserver(Callback *_objPtr, ObserverCallback _method) : objPtr(_objPtr), method(_method) {}
|
||||
|
||||
protected:
|
||||
virtual void onNotify(T arg) { (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
|
||||
*/
|
||||
void 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) {
|
||||
(*iterator)->onNotify(arg);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
#include "main.h"
|
||||
#include "screen.h"
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
|
||||
static void sdsEnter()
|
||||
{
|
||||
|
@ -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,13 @@ 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 void onNotify(uint32_t newValue)
|
||||
{
|
||||
setValue(newValue);
|
||||
notify();
|
||||
}
|
||||
};
|
||||
|
||||
class MyNodeInfoCharacteristic : public ProtobufCharacteristic
|
||||
@ -244,18 +252,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;
|
||||
|
||||
/*
|
54
src/main.cpp
54
src/main.cpp
@ -21,9 +21,7 @@
|
||||
|
||||
*/
|
||||
|
||||
#include "BluetoothUtil.h"
|
||||
#include "GPS.h"
|
||||
#include "MeshBluetoothService.h"
|
||||
#include "MeshRadio.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
@ -39,6 +37,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 +61,6 @@ static meshtastic::PowerStatus powerStatus;
|
||||
bool ssd1306_found;
|
||||
bool axp192_found;
|
||||
|
||||
bool bluetoothOn;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Application
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -266,49 +266,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;
|
||||
@ -352,7 +309,10 @@ void loop()
|
||||
|
||||
ledPeriodic.loop();
|
||||
// axpDebugOutput.loop();
|
||||
|
||||
#ifndef NO_ESP32
|
||||
loopBLE();
|
||||
#endif
|
||||
|
||||
// for debug printing
|
||||
// service.radio.radioIf.canSleep();
|
||||
|
@ -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();
|
||||
|
@ -1,7 +1,5 @@
|
||||
#include "sleep.h"
|
||||
#include "BluetoothUtil.h"
|
||||
#include "GPS.h"
|
||||
#include "MeshBluetoothService.h"
|
||||
#include "MeshRadio.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
@ -11,9 +9,14 @@
|
||||
#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;
|
||||
@ -105,7 +108,9 @@ void doDeepSleep(uint64_t msecToWake)
|
||||
// not using wifi yet, but once we are this is needed to shutoff the radio hw
|
||||
// esp_wifi_stop();
|
||||
|
||||
#ifndef NO_ESP32
|
||||
BLEDevice::deinit(false); // We are required to shutdown bluetooth before deep or light sleep
|
||||
#endif
|
||||
|
||||
screen.setOn(false); // datasheet says this will draw only 10ua
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user