diff --git a/bin/program-release-heltec.sh b/bin/program-release-heltec.sh
index d16f6c360..90506473b 100755
--- a/bin/program-release-heltec.sh
+++ b/bin/program-release-heltec.sh
@@ -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
diff --git a/bin/program-release-tbeam.sh b/bin/program-release-tbeam.sh
index 2c5f030c6..d83b35622 100755
--- a/bin/program-release-tbeam.sh
+++ b/bin/program-release-tbeam.sh
@@ -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
diff --git a/platformio.ini b/platformio.ini
index 093a8d477..cd1755adf 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -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} -
+
[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
\ No newline at end of file
+ ${env.build_flags} -D BARE_BOARD
+src_filter =
+ ${env.src_filter} -
+lib_ignore =
+ BluetoothOTA
\ No newline at end of file
diff --git a/src/GPS.cpp b/src/GPS.cpp
index 8ca8dd36b..ea04b09f9 100644
--- a/src/GPS.cpp
+++ b/src/GPS.cpp
@@ -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
diff --git a/src/GPS.h b/src/GPS.h
index 5d0d4b876..caf3fc249 100644
--- a/src/GPS.h
+++ b/src/GPS.h
@@ -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
{
SFE_UBLOX_GPS ublox;
diff --git a/src/MeshRadio.cpp b/src/MeshRadio.cpp
index 1f7d20d43..7950760bf 100644
--- a/src/MeshRadio.cpp
+++ b/src/MeshRadio.cpp
@@ -5,8 +5,10 @@
#include
#include "MeshRadio.h"
+#include "MeshService.h"
#include "NodeDB.h"
#include "configuration.h"
+#include "sleep.h"
#include
#include
@@ -25,7 +27,7 @@ separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts
bool useHardware = true;
MeshRadio::MeshRadio(MemoryPool &_pool, PointerQueue &_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(¬ifyDeepSleep);
+
#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;
}
}
diff --git a/src/MeshRadio.h b/src/MeshRadio.h
index efb9e4faa..4b4d3c7b6 100644
--- a/src/MeshRadio.h
+++ b/src/MeshRadio.h
@@ -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 configChangedObserver =
+ CallbackObserver(this, &MeshRadio::reloadConfig);
+
+ CallbackObserver preflightSleepObserver =
+ CallbackObserver(this, &MeshRadio::preflightSleepCb);
+
+ CallbackObserver notifyDeepSleepObserver =
+ CallbackObserver(this, &MeshRadio::notifyDeepSleepDb);
+
+ CallbackObserver sendPacketObserver; /* =
+ CallbackObserver(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;
+ }
};
diff --git a/src/MeshService.cpp b/src/MeshService.cpp
index 85f4856d2..c8e947acf 100644
--- a/src/MeshService.cpp
+++ b/src/MeshService.cpp
@@ -3,7 +3,7 @@
#include
#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;
}
diff --git a/src/MeshService.h b/src/MeshService.h
index 884529237..e9d4fe488 100644
--- a/src/MeshService.h
+++ b/src/MeshService.h
@@ -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 packetPool;
+ CallbackObserver gpsObserver = CallbackObserver(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 toPhoneQueue;
+ /// The current nonce for the newest packet which has been queued for the phone
+ uint32_t fromNum = 0;
+
+ public:
+ MemoryPool packetPool;
+
/// Packets which have just arrived from the radio, ready to be processed by this service and possibly
/// forwarded to the phone.
PointerQueue 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 fromNumChanged;
- public:
- MeshRadio radio;
+ /// Called when radio config has changed (radios should observe this and set their hardware as required)
+ Observable 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 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
diff --git a/src/Observer.cpp b/src/Observer.cpp
index 468f5ade9..1025f8bc0 100644
--- a/src/Observer.cpp
+++ b/src/Observer.cpp
@@ -1,13 +1,2 @@
#include "Observer.h"
-Observer::~Observer()
-{
- if (observed)
- observed->removeObserver(this);
- observed = NULL;
-}
-
-void Observer::observe(Observable *o)
-{
- o->addObserver(this);
-}
\ No newline at end of file
diff --git a/src/Observer.h b/src/Observer.h
index b4de9d83b..eab1a4a30 100644
--- a/src/Observer.h
+++ b/src/Observer.h
@@ -4,38 +4,93 @@
#include
-class Observable;
+template class Observable;
-class Observer
+/**
+ * An observer which can be mixed in as a baseclass. Implement onNotify as a method in your class.
+ */
+template class Observer
{
- Observable *observed;
+ Observable *observed;
public:
Observer() : observed(NULL) {}
virtual ~Observer();
- void observe(Observable *o);
+ void observe(Observable *o);
private:
- friend class Observable;
+ friend class Observable;
- 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 CallbackObserver : public Observer
{
- std::list 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 Observable
+{
+ std::list *> 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::const_iterator iterator = observers.begin(); iterator != observers.end(); ++iterator) {
- (*iterator)->onNotify(this);
+ for (typename std::list *>::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;
- void removeObserver(Observer *o) { observers.remove(o); }
+ // Not called directly, instead call observer.observe
+ void addObserver(Observer *o) { observers.push_back(o); }
+
+ void removeObserver(Observer *o) { observers.remove(o); }
};
+
+template Observer::~Observer()
+{
+ if (observed)
+ observed->removeObserver(this);
+ observed = NULL;
+}
+
+template void Observer::observe(Observable *o)
+{
+ o->addObserver(this);
+}
\ No newline at end of file
diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp
index ce7005ffa..716e4e2c3 100644
--- a/src/PowerFSM.cpp
+++ b/src/PowerFSM.cpp
@@ -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");
}
diff --git a/src/bare/main-bare.cpp b/src/bare/main-bare.cpp
new file mode 100644
index 000000000..29532a639
--- /dev/null
+++ b/src/bare/main-bare.cpp
@@ -0,0 +1,6 @@
+#include "target_specific.h"
+
+void setBluetoothEnable(bool on)
+{
+ // Do nothing
+}
\ No newline at end of file
diff --git a/src/configuration.h b/src/configuration.h
index 86bdd231b..9d6ca47d3 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -202,6 +202,8 @@ along with this program. If not, see .
// 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
// -----------------------------------------------------------------------------
diff --git a/src/error.h b/src/error.h
index cc3328c3b..3fa3f4709 100644
--- a/src/error.h
+++ b/src/error.h
@@ -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);
diff --git a/src/MeshBluetoothService.cpp b/src/esp32/MeshBluetoothService.cpp
similarity index 96%
rename from src/MeshBluetoothService.cpp
rename to src/esp32/MeshBluetoothService.cpp
index 16af14921..086f0afe6 100644
--- a/src/MeshBluetoothService.cpp
+++ b/src/esp32/MeshBluetoothService.cpp
@@ -204,7 +204,7 @@ class FromRadioCharacteristic : public CallbackCharacteristic
}
};
-class FromNumCharacteristic : public CallbackCharacteristic
+class FromNumCharacteristic : public CallbackCharacteristic, public Observer
{
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;
/*
diff --git a/src/MeshBluetoothService.h b/src/esp32/MeshBluetoothService.h
similarity index 100%
rename from src/MeshBluetoothService.h
rename to src/esp32/MeshBluetoothService.h
diff --git a/src/esp32/main-esp32.cpp b/src/esp32/main-esp32.cpp
new file mode 100644
index 000000000..baf0d85b7
--- /dev/null
+++ b/src/esp32/main-esp32.cpp
@@ -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();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index 910d45cfe..a10de160b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -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
#include
+#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) {
diff --git a/src/main.h b/src/main.h
index 9842ea96f..c8c379715 100644
--- a/src/main.h
+++ b/src/main.h
@@ -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();
diff --git a/src/sleep.cpp b/src/sleep.cpp
index e204ea5f5..0ae911b04 100644
--- a/src/sleep.cpp
+++ b/src/sleep.cpp
@@ -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
#include
+#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 preflightSleep;
+
+/// Called to tell observers we are now entering sleep and you should prepare. Must return 0
+Observable 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
diff --git a/src/sleep.h b/src/sleep.h
index 49976516b..e63fa70a6 100644
--- a/src/sleep.h
+++ b/src/sleep.h
@@ -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;
\ No newline at end of file
+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 preflightSleep;
+
+/// Called to tell observers we are now entering (light or deep) sleep and you should prepare. Must return 0
+extern Observable notifySleep;
+
+/// Called to tell observers we are now entering (deep) sleep and you should prepare. Must return 0
+extern Observable notifyDeepSleep;
\ No newline at end of file
diff --git a/src/target_specific.h b/src/target_specific.h
new file mode 100644
index 000000000..6acca364a
--- /dev/null
+++ b/src/target_specific.h
@@ -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);
\ No newline at end of file