Merge branch 'post1' into nimble
# Conflicts: # docs/software/TODO.md # docs/software/nrf52-TODO.md # platformio.ini # src/esp32/MeshBluetoothService.cpp
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
/**
|
||||
* Common lib functions for all platforms that have bluetooth
|
||||
*/
|
||||
|
||||
#define MESH_SERVICE_UUID "6ba1b218-15a8-461f-9fa8-5dcae273eafd"
|
||||
|
||||
#define TORADIO_UUID "f75c76d2-129e-4dad-a1dd-7866124401e7"
|
||||
#define FROMRADIO_UUID "8ba2bcc2-ee02-4a55-a531-c525c5e454d5"
|
||||
#define FROMNUM_UUID "ed9da18c-a800-4f66-a670-aa7547e34453"
|
||||
|
||||
/// Given a level between 0-100, update the BLE attribute
|
||||
void updateBatteryLevel(uint8_t level);
|
||||
@@ -1,7 +1,13 @@
|
||||
#include "Thread.h"
|
||||
#include "timing.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace concurrency {
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "esp_task_wdt.h"
|
||||
#endif
|
||||
|
||||
namespace concurrency
|
||||
{
|
||||
|
||||
void Thread::start(const char *name, size_t stackSize, uint32_t priority)
|
||||
{
|
||||
@@ -14,4 +20,27 @@ void Thread::callRun(void *_this)
|
||||
((Thread *)_this)->doRun();
|
||||
}
|
||||
|
||||
void Thread::serviceWatchdog()
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
esp_task_wdt_reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Thread::startWatchdog()
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
auto r = esp_task_wdt_add(taskHandle);
|
||||
assert(r == ESP_OK);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Thread::stopWatchdog()
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
auto r = esp_task_wdt_delete(taskHandle);
|
||||
assert(r == ESP_OK);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace concurrency
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "freertosinc.h"
|
||||
#include "esp_task_wdt.h"
|
||||
|
||||
namespace concurrency {
|
||||
|
||||
@@ -36,17 +35,9 @@ class Thread
|
||||
*
|
||||
* this only applies after startWatchdog() has been called. If you need to sleep for a long time call stopWatchdog()
|
||||
*/
|
||||
void serviceWatchdog() { esp_task_wdt_reset(); }
|
||||
void startWatchdog()
|
||||
{
|
||||
auto r = esp_task_wdt_add(taskHandle);
|
||||
assert(r == ESP_OK);
|
||||
}
|
||||
void stopWatchdog()
|
||||
{
|
||||
auto r = esp_task_wdt_delete(taskHandle);
|
||||
assert(r == ESP_OK);
|
||||
}
|
||||
void serviceWatchdog();
|
||||
void startWatchdog();
|
||||
void stopWatchdog();
|
||||
|
||||
private:
|
||||
static void callRun(void *_this);
|
||||
|
||||
+65
-38
@@ -55,13 +55,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
/// Convert a preprocessor name into a quoted string and if that string is empty use "unset"
|
||||
#define optstr(s) (xstr(s)[0] ? xstr(s) : "unset")
|
||||
|
||||
#ifdef NRF52840_XXAA // All of the NRF52 targets are configured using variant.h, so this section shouldn't need to be
|
||||
// board specific
|
||||
#ifdef NRF52_SERIES // All of the NRF52 targets are configured using variant.h, so this section shouldn't need to be
|
||||
// board specific
|
||||
|
||||
//
|
||||
// Standard definitions for NRF52 targets
|
||||
//
|
||||
|
||||
// Nop definition for these attributes - not used on NRF52
|
||||
#define EXT_RAM_ATTR
|
||||
#define IRAM_ATTR
|
||||
|
||||
#define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth)
|
||||
|
||||
// We bind to the GPS using variant.h instead for this platform (Serial1)
|
||||
@@ -70,7 +74,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define RTC_DATA_ATTR
|
||||
|
||||
#define LED_PIN PIN_LED1 // LED1 on nrf52840-DK
|
||||
|
||||
// If the variant filed defines as standard button
|
||||
#ifdef PIN_BUTTON1
|
||||
#define BUTTON_PIN PIN_BUTTON1
|
||||
#endif
|
||||
|
||||
// FIXME, use variant.h defs for all of this!!! (even on the ESP32 targets)
|
||||
#elif defined(CubeCell_BoardPlus)
|
||||
@@ -105,10 +113,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// LoRa SPI
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define SCK_GPIO 5
|
||||
#define MISO_GPIO 19
|
||||
#define MOSI_GPIO 27
|
||||
#define NSS_GPIO 18
|
||||
// NRF52 boards will define this in variant.h
|
||||
#ifndef RF95_SCK
|
||||
#define RF95_SCK 5
|
||||
#define RF95_MISO 19
|
||||
#define RF95_MOSI 27
|
||||
#define RF95_NSS 18
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -148,11 +159,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define BUTTON_PIN_ALT 13 // Alternate GPIO for an external button if needed
|
||||
|
||||
#ifndef USE_JTAG
|
||||
#define RESET_GPIO 14
|
||||
#define RF95_RESET 14
|
||||
#endif
|
||||
#define RF95_IRQ_GPIO 26
|
||||
#define DIO1_GPIO 33 // Note: not really used on this board
|
||||
#define DIO2_GPIO 32 // Note: not really used on this board
|
||||
#define RF95_IRQ 26
|
||||
#define RF95_DIO1 33 // Note: not really used on this board
|
||||
#define RF95_DIO2 32 // Note: not really used on this board
|
||||
|
||||
// Leave undefined to disable our PMU IRQ handler
|
||||
#define PMU_IRQ 35
|
||||
@@ -171,11 +182,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define BUTTON_PIN 39
|
||||
|
||||
#ifndef USE_JTAG
|
||||
#define RESET_GPIO 23
|
||||
#define RF95_RESET 23
|
||||
#endif
|
||||
#define RF95_IRQ_GPIO 26
|
||||
#define DIO1_GPIO 33 // Note: not really used on this board
|
||||
#define DIO2_GPIO 32 // Note: not really used on this board
|
||||
#define RF95_IRQ 26
|
||||
#define RF95_DIO1 33 // Note: not really used on this board
|
||||
#define RF95_DIO2 32 // Note: not really used on this board
|
||||
|
||||
// This board has different GPS pins than all other boards
|
||||
#undef GPS_RX_PIN
|
||||
@@ -206,11 +217,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
|
||||
|
||||
#ifndef USE_JTAG
|
||||
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
|
||||
#define RF95_RESET 14 // If defined, this pin will be used to reset the LORA radio
|
||||
#endif
|
||||
#define RF95_IRQ_GPIO 26
|
||||
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
||||
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
||||
#define RF95_IRQ 26
|
||||
#define RF95_DIO1 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
||||
#define RF95_DIO2 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
||||
#elif defined(TLORA_V1)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR "tlora-v1"
|
||||
@@ -228,10 +239,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define LED_PIN 2 // If defined we will blink this LED
|
||||
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
|
||||
|
||||
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
|
||||
#define RF95_IRQ_GPIO 26 // IRQ line for the LORA radio
|
||||
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
||||
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
||||
#define RF95_RESET 14 // If defined, this pin will be used to reset the LORA radio
|
||||
#define RF95_IRQ 26 // IRQ line for the LORA radio
|
||||
#define RF95_DIO1 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
||||
#define RF95_DIO2 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
||||
|
||||
#elif defined(TLORA_V2)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR "tlora-v2"
|
||||
@@ -248,7 +260,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
|
||||
#define LED_PIN 25 // If defined we will blink this LED
|
||||
#define BUTTON_PIN 0 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one between this pin and ground
|
||||
#define BUTTON_PIN \
|
||||
0 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one
|
||||
// between this pin and ground
|
||||
|
||||
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
|
||||
#define RF95_IRQ_GPIO 26 // IRQ line for the LORA radio
|
||||
@@ -262,7 +276,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
#define GPS_RX_PIN 36
|
||||
#define GPS_TX_PIN 39
|
||||
#define GPS_TX_PIN 39
|
||||
|
||||
#define I2C_SDA 21 // I2C pins for this board
|
||||
#define I2C_SCL 22
|
||||
@@ -271,12 +285,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
|
||||
#define LED_PIN 25 // If defined we will blink this LED
|
||||
#define BUTTON_PIN 12 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one between this pin and ground
|
||||
#define BUTTON_PIN \
|
||||
12 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one
|
||||
// between this pin and ground
|
||||
|
||||
#define RESET_GPIO 23 // If defined, this pin will be used to reset the LORA radio
|
||||
#define RF95_IRQ_GPIO 26 // IRQ line for the LORA radio
|
||||
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
||||
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
||||
#define RF95_RESET 14 // If defined, this pin will be used to reset the LORA radio
|
||||
#define RF95_IRQ 26 // IRQ line for the LORA radio
|
||||
#define RF95_DIO1 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
||||
#define RF95_DIO2 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_NRF52840_PCA10056
|
||||
@@ -288,25 +304,25 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#undef LED_INVERTED
|
||||
#define LED_INVERTED 1
|
||||
|
||||
// Uncomment to confirm if we can build the RF95 driver for NRF52
|
||||
#if 0
|
||||
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
|
||||
#define RF95_IRQ_GPIO 26 // IRQ line for the LORA radio
|
||||
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
||||
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
||||
#endif
|
||||
|
||||
#elif defined(ARDUINO_NRF52840_PPR)
|
||||
|
||||
#define HW_VENDOR "ppr"
|
||||
|
||||
#elif NRF52_SERIES
|
||||
|
||||
#define HW_VENDOR "nrf52unknown" // FIXME - unknown nrf52 board
|
||||
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// DEBUG
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#ifdef CONSOLE_MAX_BAUD
|
||||
#define SERIAL_BAUD CONSOLE_MAX_BAUD
|
||||
#else
|
||||
#define SERIAL_BAUD 921600 // Serial debug baud rate
|
||||
#endif
|
||||
|
||||
#include "SerialConsole.h"
|
||||
|
||||
@@ -314,13 +330,24 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// What platforms should use SEGGER?
|
||||
#ifdef NRF52_SERIES
|
||||
|
||||
// Always include the SEGGER code on NRF52 - because useful for debugging
|
||||
#include "SEGGER_RTT.h"
|
||||
|
||||
// Debug printing to segger console
|
||||
#define SEGGER_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
|
||||
// nrf52 gets its settings via variant files
|
||||
#ifndef PIN_SERIAL_RX
|
||||
// No serial ports on this board - ONLY use segger in memory console
|
||||
#define USE_SEGGER
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32
|
||||
#endif
|
||||
|
||||
#ifdef USE_SEGGER
|
||||
#include "SEGGER_RTT.h"
|
||||
#define DEBUG_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
#else
|
||||
#ifdef DEBUG_PORT
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <Arduino.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "BluetoothCommon.h"
|
||||
#include "GPS.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
@@ -43,26 +44,20 @@ class BluetoothPhoneAPI : public PhoneAPI
|
||||
}
|
||||
};
|
||||
|
||||
BluetoothPhoneAPI *bluetoothPhoneAPI;
|
||||
|
||||
static BluetoothPhoneAPI *bluetoothPhoneAPI;
|
||||
|
||||
class ToRadioCharacteristic : public CallbackCharacteristic
|
||||
{
|
||||
public:
|
||||
ToRadioCharacteristic() : CallbackCharacteristic("f75c76d2-129e-4dad-a1dd-7866124401e7", BLECharacteristic::PROPERTY_WRITE) {}
|
||||
ToRadioCharacteristic() : CallbackCharacteristic(TORADIO_UUID, BLECharacteristic::PROPERTY_WRITE) {}
|
||||
|
||||
void onWrite(BLECharacteristic *c)
|
||||
{
|
||||
bluetoothPhoneAPI->handleToRadio(c->getData(), c->getValue().length());
|
||||
}
|
||||
void onWrite(BLECharacteristic *c) { bluetoothPhoneAPI->handleToRadio(c->getData(), c->getValue().length()); }
|
||||
};
|
||||
|
||||
class FromRadioCharacteristic : public CallbackCharacteristic
|
||||
{
|
||||
public:
|
||||
FromRadioCharacteristic() : CallbackCharacteristic("8ba2bcc2-ee02-4a55-a531-c525c5e454d5", BLECharacteristic::PROPERTY_READ)
|
||||
{
|
||||
}
|
||||
FromRadioCharacteristic() : CallbackCharacteristic(FROMRADIO_UUID, BLECharacteristic::PROPERTY_READ) {}
|
||||
|
||||
void onRead(BLECharacteristic *c)
|
||||
{
|
||||
@@ -82,9 +77,8 @@ class FromNumCharacteristic : public CallbackCharacteristic
|
||||
{
|
||||
public:
|
||||
FromNumCharacteristic()
|
||||
: CallbackCharacteristic("ed9da18c-a800-4f66-a670-aa7547e34453", BLECharacteristic::PROPERTY_WRITE |
|
||||
BLECharacteristic::PROPERTY_READ |
|
||||
BLECharacteristic::PROPERTY_NOTIFY)
|
||||
: CallbackCharacteristic(FROMNUM_UUID, BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ |
|
||||
BLECharacteristic::PROPERTY_NOTIFY)
|
||||
{
|
||||
// observe(&service.fromNumChanged);
|
||||
}
|
||||
@@ -104,7 +98,7 @@ BLEService *createMeshBluetoothService(BLEServer *server)
|
||||
}
|
||||
|
||||
// Create the BLE Service, we need more than the default of 15 handles
|
||||
BLEService *service = server->createService(BLEUUID("6ba1b218-15a8-461f-9fa8-5dcae273eafd"), 30, 0);
|
||||
BLEService *service = server->createService(BLEUUID(MESH_SERVICE_UUID), 30, 0);
|
||||
|
||||
assert(!meshFromNumCharacteristic);
|
||||
meshFromNumCharacteristic = new FromNumCharacteristic;
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#include "WiFiServerAPI.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), client(_client)
|
||||
{
|
||||
DEBUG_MSG("Incoming connection from %s\n", client.remoteIP().toString().c_str());
|
||||
}
|
||||
|
||||
WiFiServerAPI::~WiFiServerAPI()
|
||||
{
|
||||
client.stop();
|
||||
|
||||
// FIXME - delete this if the client dropps the connection!
|
||||
}
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
void WiFiServerAPI::onConnectionChanged(bool connected)
|
||||
{
|
||||
// FIXME - we really should be doing global reference counting to see if anyone is currently using serial or wifi and if so,
|
||||
// block sleep
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void WiFiServerAPI::loop()
|
||||
{
|
||||
if (client.connected()) {
|
||||
StreamAPI::loop();
|
||||
} else {
|
||||
DEBUG_MSG("Client dropped connection, closing UDP server\n");
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
#define MESHTASTIC_PORTNUM 4403
|
||||
|
||||
WiFiServerPort::WiFiServerPort() : WiFiServer(MESHTASTIC_PORTNUM) {}
|
||||
|
||||
void WiFiServerPort::init()
|
||||
{
|
||||
DEBUG_MSG("Listening on TCP port %d\n", MESHTASTIC_PORTNUM);
|
||||
begin();
|
||||
}
|
||||
|
||||
void WiFiServerPort::loop()
|
||||
{
|
||||
auto client = available();
|
||||
if (client) {
|
||||
new WiFiServerAPI(client);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "StreamAPI.h"
|
||||
#include <WiFi.h>
|
||||
|
||||
/**
|
||||
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs
|
||||
* (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs).
|
||||
*/
|
||||
class WiFiServerAPI : public StreamAPI
|
||||
{
|
||||
private:
|
||||
WiFiClient client;
|
||||
|
||||
public:
|
||||
WiFiServerAPI(WiFiClient &_client);
|
||||
|
||||
virtual ~WiFiServerAPI();
|
||||
|
||||
virtual void loop(); // Check for dropped client connections
|
||||
|
||||
protected:
|
||||
/// Hookable to find out when connection changes
|
||||
virtual void onConnectionChanged(bool connected);
|
||||
};
|
||||
|
||||
/**
|
||||
* Listens for incoming connections and does accepts and creates instances of WiFiServerAPI as needed
|
||||
*/
|
||||
class WiFiServerPort : public WiFiServer
|
||||
{
|
||||
public:
|
||||
WiFiServerPort();
|
||||
|
||||
void init();
|
||||
|
||||
void loop();
|
||||
};
|
||||
+13
-4
@@ -5,12 +5,21 @@
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
|
||||
// If we have a serial GPS port it will not be null
|
||||
#ifdef GPS_RX_PIN
|
||||
HardwareSerial _serial_gps_real(GPS_SERIAL_NUM);
|
||||
HardwareSerial &GPS::_serial_gps = _serial_gps_real;
|
||||
HardwareSerial *GPS::_serial_gps = &_serial_gps_real;
|
||||
#elif defined(NRF52840_XXAA)
|
||||
// Assume NRF52840
|
||||
HardwareSerial *GPS::_serial_gps = &Serial1;
|
||||
#else
|
||||
// Assume NRF52
|
||||
HardwareSerial &GPS::_serial_gps = Serial1;
|
||||
HardwareSerial *GPS::_serial_gps = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef GPS_I2C_ADDRESS
|
||||
uint8_t GPS::i2cAddress = GPS_I2C_ADDRESS;
|
||||
#else
|
||||
uint8_t GPS::i2cAddress = 0;
|
||||
#endif
|
||||
|
||||
bool timeSetFromGPS; // We try to set our time from GPS each time we wake from sleep
|
||||
@@ -63,7 +72,7 @@ void perhapsSetRTC(struct tm &t)
|
||||
|
||||
// DEBUG_MSG("Got time from GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
|
||||
if (t.tm_year < 0 || t.tm_year >= 300)
|
||||
DEBUG_MSG("Ignoring invalid GPS time\n");
|
||||
DEBUG_MSG("Ignoring invalid GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
|
||||
else
|
||||
perhapsSetRTC(&tv);
|
||||
}
|
||||
|
||||
+10
-5
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "Observer.h"
|
||||
#include "GPSStatus.h"
|
||||
#include "../concurrency/PeriodicTask.h"
|
||||
#include "GPSStatus.h"
|
||||
#include "Observer.h"
|
||||
#include "sys/time.h"
|
||||
|
||||
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
|
||||
@@ -30,12 +30,17 @@ class GPS : public Observable<void *>
|
||||
protected:
|
||||
bool hasValidLocation = false; // default to false, until we complete our first read
|
||||
|
||||
static HardwareSerial &_serial_gps;
|
||||
|
||||
public:
|
||||
/** If !NULL we will use this serial port to construct our GPS */
|
||||
static HardwareSerial *_serial_gps;
|
||||
|
||||
/** If !0 we will attempt to connect to the GPS over I2C */
|
||||
static uint8_t i2cAddress;
|
||||
|
||||
int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double
|
||||
int32_t altitude = 0;
|
||||
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs scaling before use)
|
||||
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs
|
||||
// scaling before use)
|
||||
uint32_t heading = 0; // Heading of motion, in degrees * 10^-5
|
||||
uint32_t numSatellites = 0;
|
||||
|
||||
|
||||
+2
-3
@@ -13,9 +13,8 @@ static int32_t toDegInt(RawDegrees d)
|
||||
|
||||
void NEMAGPS::loop()
|
||||
{
|
||||
|
||||
while (_serial_gps.available() > 0) {
|
||||
int c = _serial_gps.read();
|
||||
while (_serial_gps->available() > 0) {
|
||||
int c = _serial_gps->read();
|
||||
// Serial.write(c);
|
||||
reader.encode(c);
|
||||
}
|
||||
|
||||
+62
-28
@@ -7,23 +7,46 @@ UBloxGPS::UBloxGPS() : concurrency::PeriodicTask()
|
||||
notifySleepObserver.observe(¬ifySleep);
|
||||
}
|
||||
|
||||
bool UBloxGPS::tryConnect()
|
||||
{
|
||||
isConnected = false;
|
||||
|
||||
if (_serial_gps)
|
||||
isConnected = ublox.begin(*_serial_gps);
|
||||
|
||||
if (!isConnected && i2cAddress) {
|
||||
extern bool neo6M; // Super skanky - if we are talking to the device i2c we assume it is a neo7 on a RAK815, which
|
||||
// supports the newer API
|
||||
neo6M = true;
|
||||
|
||||
isConnected = ublox.begin(Wire, i2cAddress);
|
||||
}
|
||||
|
||||
return isConnected;
|
||||
}
|
||||
|
||||
bool UBloxGPS::setup()
|
||||
{
|
||||
if (_serial_gps) {
|
||||
#ifdef GPS_RX_PIN
|
||||
_serial_gps.begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
|
||||
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
|
||||
#else
|
||||
_serial_gps.begin(GPS_BAUDRATE);
|
||||
_serial_gps->begin(GPS_BAUDRATE);
|
||||
#endif
|
||||
// _serial_gps.setRxBufferSize(1024); // the default is 256
|
||||
// _serial_gps.setRxBufferSize(1024); // the default is 256
|
||||
}
|
||||
|
||||
#ifdef GPS_POWER_EN
|
||||
pinMode(GPS_POWER_EN, OUTPUT);
|
||||
digitalWrite(GPS_POWER_EN, 1);
|
||||
delay(200); // Give time for the GPS to startup after we gave power
|
||||
#endif
|
||||
|
||||
// ublox.enableDebugging(Serial);
|
||||
|
||||
// note: the lib's implementation has the wrong docs for what the return val is
|
||||
// it is not a bool, it returns zero for success
|
||||
isConnected = ublox.begin(_serial_gps);
|
||||
|
||||
// try a second time, the ublox lib serial parsing is buggy?
|
||||
if (!isConnected)
|
||||
isConnected = ublox.begin(_serial_gps);
|
||||
if (!tryConnect())
|
||||
tryConnect();
|
||||
|
||||
if (isConnected) {
|
||||
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
|
||||
@@ -35,14 +58,21 @@ bool UBloxGPS::setup()
|
||||
// GPS_TX connected)
|
||||
ublox.factoryReset();
|
||||
delay(3000);
|
||||
isConnected = ublox.begin(_serial_gps);
|
||||
tryConnect();
|
||||
DEBUG_MSG("Factory reset success=%d\n", isConnected);
|
||||
ok = ublox.saveConfiguration(3000);
|
||||
assert(ok);
|
||||
return false;
|
||||
} else {
|
||||
ok = ublox.setUART1Output(COM_TYPE_UBX, 500); // Use native API
|
||||
assert(ok);
|
||||
if (_serial_gps) {
|
||||
ok = ublox.setUART1Output(COM_TYPE_UBX, 500); // Use native API
|
||||
assert(ok);
|
||||
}
|
||||
if (i2cAddress) {
|
||||
ok = ublox.setI2COutput(COM_TYPE_UBX, 500);
|
||||
assert(ok);
|
||||
}
|
||||
|
||||
ok = ublox.setNavigationFrequency(1, 500); // Produce 4x/sec to keep the amount of time we stall in getPVT low
|
||||
assert(ok);
|
||||
// ok = ublox.setAutoPVT(false); // Not implemented on NEO-6M
|
||||
@@ -80,20 +110,22 @@ void UBloxGPS::doTask()
|
||||
|
||||
// Consume all characters that have arrived
|
||||
|
||||
// getPVT automatically calls checkUblox
|
||||
// if using i2c or serial look too see if any chars are ready
|
||||
ublox.checkUblox(); // See if new data is available. Process bytes as they come in.
|
||||
|
||||
// If we don't have a fix (a quick check), don't try waiting for a solution)
|
||||
// Hmmm my fix type reading returns zeros for fix, which doesn't seem correct, because it is still sptting out positions
|
||||
// turn off for now
|
||||
fixtype = ublox.getFixType(0);
|
||||
uint16_t maxWait = i2cAddress ? 300 : 0; // If using i2c we must poll with wait
|
||||
fixtype = ublox.getFixType(maxWait);
|
||||
DEBUG_MSG("GPS fix type %d\n", fixtype);
|
||||
|
||||
// DEBUG_MSG("sec %d\n", ublox.getSecond());
|
||||
// DEBUG_MSG("lat %d\n", ublox.getLatitude());
|
||||
|
||||
// any fix that has time
|
||||
if (ublox.getT(0)) {
|
||||
|
||||
if (ublox.getT(maxWait)) {
|
||||
/* Convert to unix time
|
||||
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970
|
||||
(midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
|
||||
@@ -109,19 +141,20 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
||||
perhapsSetRTC(t);
|
||||
}
|
||||
|
||||
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(0)) // rd fixes only
|
||||
{
|
||||
// we only notify if position has changed
|
||||
latitude = ublox.getLatitude(0);
|
||||
longitude = ublox.getLongitude(0);
|
||||
altitude = ublox.getAltitude(0) / 1000; // in mm convert to meters
|
||||
dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
|
||||
heading = ublox.getHeading(0);
|
||||
numSatellites = ublox.getSIV(0);
|
||||
latitude = ublox.getLatitude(0);
|
||||
longitude = ublox.getLongitude(0);
|
||||
altitude = ublox.getAltitude(0) / 1000; // in mm convert to meters
|
||||
dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
|
||||
heading = ublox.getHeading(0);
|
||||
numSatellites = ublox.getSIV(0);
|
||||
|
||||
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
|
||||
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
|
||||
hasValidLocation = (latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000);
|
||||
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
|
||||
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
|
||||
hasValidLocation = (latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000) && (numSatellites > 0);
|
||||
|
||||
// we only notify if position has changed due to a new fix
|
||||
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only
|
||||
{
|
||||
if (hasValidLocation) {
|
||||
wantNewLocation = false;
|
||||
notifyObservers(NULL);
|
||||
@@ -131,7 +164,8 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
||||
wantNewLocation = true;
|
||||
|
||||
// Notify any status instances that are observing us
|
||||
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
|
||||
const meshtastic::GPSStatus status =
|
||||
meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
|
||||
newStatus.notifyObservers(&status);
|
||||
|
||||
// Once we have sent a location once we only poll the GPS rarely, otherwise check back every 1s until we have something over
|
||||
|
||||
@@ -38,4 +38,7 @@ class UBloxGPS : public GPS, public concurrency::PeriodicTask
|
||||
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
|
||||
/// always returns 0 to indicate okay to sleep
|
||||
int prepareSleep(void *unused);
|
||||
|
||||
/// Attempt to connect to our GPS, returns false if no gps is present
|
||||
bool tryConnect();
|
||||
};
|
||||
|
||||
+30
-18
@@ -25,17 +25,17 @@
|
||||
#include "MeshService.h"
|
||||
#include "NEMAGPS.h"
|
||||
#include "NodeDB.h"
|
||||
#include "concurrency/Periodic.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "UBloxGPS.h"
|
||||
#include "concurrency/Periodic.h"
|
||||
#include "configuration.h"
|
||||
#include "error.h"
|
||||
#include "power.h"
|
||||
// #include "rom/rtc.h"
|
||||
#include "DSRRouter.h"
|
||||
#include "debug.h"
|
||||
#include "main.h"
|
||||
// #include "debug.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "main.h"
|
||||
#include "sleep.h"
|
||||
#include "timing.h"
|
||||
#include <OneButton.h>
|
||||
@@ -152,23 +152,29 @@ void userButtonPressedLong()
|
||||
#ifndef NO_ESP32
|
||||
void initWifi()
|
||||
{
|
||||
strcpy(radioConfig.preferences.wifi_ssid, "geeksville");
|
||||
strcpy(radioConfig.preferences.wifi_password, "xxx");
|
||||
#if 0
|
||||
// strcpy(radioConfig.preferences.wifi_ssid, "xxx");
|
||||
// strcpy(radioConfig.preferences.wifi_password, "xxx");
|
||||
if (radioConfig.has_preferences) {
|
||||
const char *wifiName = radioConfig.preferences.wifi_ssid;
|
||||
|
||||
if (*wifiName) {
|
||||
const char *wifiPsw = radioConfig.preferences.wifi_password;
|
||||
if (radioConfig.preferences.wifi_ap_mode) {
|
||||
// DEBUG_MSG("STARTING WIFI AP: ssid=%s, ok=%d\n", wifiName, WiFi.softAP(wifiName, wifiPsw));
|
||||
DEBUG_MSG("STARTING WIFI AP: ssid=%s, ok=%d\n", wifiName, WiFi.softAP(wifiName, wifiPsw));
|
||||
} else {
|
||||
// WiFi.mode(WIFI_MODE_STA);
|
||||
WiFi.mode(WIFI_MODE_STA);
|
||||
DEBUG_MSG("JOINING WIFI: ssid=%s\n", wifiName);
|
||||
// WiFi.begin(wifiName, wifiPsw);
|
||||
if (WiFi.begin(wifiName, wifiPsw) == WL_CONNECTED) {
|
||||
DEBUG_MSG("MY IP ADDRESS: %s\n", WiFi.localIP().toString().c_str());
|
||||
} else {
|
||||
DEBUG_MSG("FAILED JOINING WIFI\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
} else
|
||||
DEBUG_MSG("Not using WIFI\n");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -259,12 +265,18 @@ void setup()
|
||||
// Init GPS - first try ublox
|
||||
gps = new UBloxGPS();
|
||||
if (!gps->setup()) {
|
||||
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
|
||||
// assume NEMA at 9600 baud.
|
||||
DEBUG_MSG("ERROR: No UBLOX GPS found, hoping that NEMA might work\n");
|
||||
delete gps;
|
||||
gps = new NEMAGPS();
|
||||
gps->setup();
|
||||
DEBUG_MSG("ERROR: No UBLOX GPS found\n");
|
||||
|
||||
if (GPS::_serial_gps) {
|
||||
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
|
||||
// assume NEMA at 9600 baud.
|
||||
DEBUG_MSG("Hoping that NEMA might work\n");
|
||||
delete gps;
|
||||
|
||||
// dumb NEMA access only work for serial GPSes)
|
||||
gps = new NEMAGPS();
|
||||
gps->setup();
|
||||
}
|
||||
}
|
||||
#else
|
||||
gps = new NEMAGPS();
|
||||
@@ -290,15 +302,15 @@ void setup()
|
||||
SPI.begin();
|
||||
#else
|
||||
// ESP32
|
||||
SPI.begin(SCK_GPIO, MISO_GPIO, MOSI_GPIO, NSS_GPIO);
|
||||
SPI.begin(RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS);
|
||||
SPI.setFrequency(4000000);
|
||||
#endif
|
||||
|
||||
// MUST BE AFTER service.init, so we have our radio config settings (from nodedb init)
|
||||
RadioInterface *rIf =
|
||||
#if defined(RF95_IRQ_GPIO)
|
||||
#if defined(RF95_IRQ)
|
||||
// new CustomRF95(); old Radiohead based driver
|
||||
new RF95Interface(NSS_GPIO, RF95_IRQ_GPIO, RESET_GPIO, SPI);
|
||||
new RF95Interface(RF95_NSS, RF95_IRQ, RF95_RESET, SPI);
|
||||
#elif defined(SX1262_CS)
|
||||
new SX1262Interface(SX1262_CS, SX1262_DIO1, SX1262_RESET, SX1262_BUSY, SPI);
|
||||
#else
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
#include "GPS.h"
|
||||
//#include "MeshBluetoothService.h"
|
||||
#include "../concurrency/Periodic.h"
|
||||
#include "BluetoothCommon.h" // needed for updateBatteryLevel, FIXME, eventually when we pull mesh out into a lib we shouldn't be whacking bluetooth from here
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "../concurrency/Periodic.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "power.h"
|
||||
#include "BluetoothUtil.h" // needed for updateBatteryLevel, FIXME, eventually when we pull mesh out into a lib we shouldn't be whacking bluetooth from here
|
||||
#include "timing.h"
|
||||
|
||||
/*
|
||||
@@ -283,8 +283,6 @@ void MeshService::sendOurPosition(NodeNum dest, bool wantReplies)
|
||||
sendToMesh(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int MeshService::onGPSChanged(void *unused)
|
||||
{
|
||||
// DEBUG_MSG("got gps notify\n");
|
||||
|
||||
@@ -12,6 +12,18 @@ RF95Interface::RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOL
|
||||
// FIXME - we assume devices never get destroyed
|
||||
}
|
||||
|
||||
/** Some boards require GPIO control of tx vs rx paths */
|
||||
void RF95Interface::setTransmitEnable(bool txon)
|
||||
{
|
||||
#ifdef RF95_TXEN
|
||||
digitalWrite(RF95_TXEN, txon ? 1 : 0);
|
||||
#endif
|
||||
|
||||
#ifdef RF95_RXEN
|
||||
digitalWrite(RF95_RXEN, txon ? 0 : 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Initialise the Driver transport hardware and software.
|
||||
/// Make sure the Driver is properly configured before calling init().
|
||||
/// \return true if initialisation succeeded.
|
||||
@@ -24,8 +36,30 @@ bool RF95Interface::init()
|
||||
power = MAX_POWER;
|
||||
|
||||
iface = lora = new RadioLibRF95(&module);
|
||||
|
||||
#ifdef RF95_TCXO
|
||||
pinMode(RF95_TCXO, OUTPUT);
|
||||
digitalWrite(RF95_TCXO, 1);
|
||||
#endif
|
||||
|
||||
/*
|
||||
#define RF95_TXEN (22) // If defined, this pin should be set high prior to transmit (controls an external analog switch)
|
||||
#define RF95_RXEN (23) // If defined, this pin should be set high prior to receive (controls an external analog switch)
|
||||
*/
|
||||
|
||||
#ifdef RF95_TXEN
|
||||
pinMode(RF95_TXEN, OUTPUT);
|
||||
digitalWrite(RF95_TXEN, 0);
|
||||
#endif
|
||||
|
||||
#ifdef RF95_RXEN
|
||||
pinMode(RF95_RXEN, OUTPUT);
|
||||
digitalWrite(RF95_RXEN, 1);
|
||||
#endif
|
||||
setTransmitEnable(false);
|
||||
|
||||
int res = lora->begin(freq, bw, sf, cr, syncWord, power, currentLimit, preambleLength);
|
||||
DEBUG_MSG("LORA init result %d\n", res);
|
||||
DEBUG_MSG("RF95 init result %d\n", res);
|
||||
|
||||
if (res == ERR_NONE)
|
||||
res = lora->setCRC(SX126X_LORA_CRC_ON);
|
||||
@@ -98,8 +132,18 @@ void RF95Interface::setStandby()
|
||||
completeSending(); // If we were sending, not anymore
|
||||
}
|
||||
|
||||
/** We override to turn on transmitter power as needed.
|
||||
*/
|
||||
void RF95Interface::configHardwareForSend()
|
||||
{
|
||||
setTransmitEnable(true);
|
||||
|
||||
RadioLibInterface::configHardwareForSend();
|
||||
}
|
||||
|
||||
void RF95Interface::startReceive()
|
||||
{
|
||||
setTransmitEnable(false);
|
||||
setStandby();
|
||||
int err = lora->startReceive();
|
||||
assert(err == ERR_NONE);
|
||||
|
||||
@@ -52,4 +52,13 @@ class RF95Interface : public RadioLibInterface
|
||||
virtual void addReceiveMetadata(MeshPacket *mp);
|
||||
|
||||
virtual void setStandby();
|
||||
|
||||
/**
|
||||
* We override to turn on transmitter power as needed.
|
||||
*/
|
||||
virtual void configHardwareForSend();
|
||||
|
||||
private:
|
||||
/** Some boards require GPIO control of tx vs rx paths */
|
||||
void setTransmitEnable(bool txon);
|
||||
};
|
||||
@@ -161,6 +161,11 @@ class SimRadio : public RadioInterface
|
||||
/// Make sure the Driver is properly configured before calling init().
|
||||
/// \return true if initialisation succeeded.
|
||||
virtual bool init() { return true; }
|
||||
|
||||
/// Apply any radio provisioning changes
|
||||
/// Make sure the Driver is properly configured before calling init().
|
||||
/// \return true if initialisation succeeded.
|
||||
virtual bool reconfigure() { return true; }
|
||||
};
|
||||
|
||||
/// Debug printing for packets
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
#define RF95_CHIP_VERSION 0x12
|
||||
#define RF95_ALT_VERSION 0x11 // Supposedly some versions of the chip have id 0x11
|
||||
|
||||
// From datasheet but radiolib doesn't know anything about this
|
||||
#define SX127X_REG_TCXO 0x4B
|
||||
|
||||
|
||||
RadioLibRF95::RadioLibRF95(Module *mod) : SX1278(mod) {}
|
||||
|
||||
int16_t RadioLibRF95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit,
|
||||
@@ -18,6 +22,11 @@ int16_t RadioLibRF95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_
|
||||
state = config();
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
#ifdef RF95_TCXO
|
||||
state = _mod->SPIsetRegValue(SX127X_REG_TCXO, 0x10 | _mod->SPIgetRegValue(SX127X_REG_TCXO));
|
||||
RADIOLIB_ASSERT(state);
|
||||
#endif
|
||||
|
||||
// configure publicly accessible settings
|
||||
state = setFrequency(freq);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
+3
-3
@@ -24,8 +24,8 @@
|
||||
(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)
|
||||
|
||||
static MemoryPool<MeshPacket> staticPool(MAX_PACKETS);
|
||||
// static MemoryDynamic<MeshPacket> staticPool;
|
||||
// static MemoryPool<MeshPacket> staticPool(MAX_PACKETS);
|
||||
static MemoryDynamic<MeshPacket> staticPool;
|
||||
|
||||
Allocator<MeshPacket> &packetPool = staticPool;
|
||||
|
||||
@@ -36,7 +36,7 @@ Allocator<MeshPacket> &packetPool = staticPool;
|
||||
*/
|
||||
Router::Router() : fromRadioQueue(MAX_RX_FROMRADIO)
|
||||
{
|
||||
// This is called pre main(), don't touch anything here, the following code is not safe
|
||||
// This is called pre main(), don't touch anything here, the following code is not safe
|
||||
|
||||
/* DEBUG_MSG("Size of NodeInfo %d\n", sizeof(NodeInfo));
|
||||
DEBUG_MSG("Size of SubPacket %d\n", sizeof(SubPacket));
|
||||
|
||||
@@ -33,7 +33,7 @@ bool SX1262Interface::init()
|
||||
if (power > 22) // This chip has lower power limits than some
|
||||
power = 22;
|
||||
int res = lora.begin(freq, bw, sf, cr, syncWord, power, currentLimit, preambleLength, tcxoVoltage, useRegulatorLDO);
|
||||
DEBUG_MSG("LORA init result %d\n", res);
|
||||
DEBUG_MSG("SX1262 init result %d\n", res);
|
||||
|
||||
#ifdef SX1262_TXEN
|
||||
// lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX
|
||||
@@ -119,8 +119,7 @@ void SX1262Interface::addReceiveMetadata(MeshPacket *mp)
|
||||
mp->rx_snr = lora.getSNR();
|
||||
}
|
||||
|
||||
/** start an immediate transmit
|
||||
* We override to turn on transmitter power as needed.
|
||||
/** We override to turn on transmitter power as needed.
|
||||
*/
|
||||
void SX1262Interface::configHardwareForSend()
|
||||
{
|
||||
|
||||
+148
-135
@@ -1,22 +1,50 @@
|
||||
#include "NRF52Bluetooth.h"
|
||||
#include "BluetoothCommon.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include <bluefruit.h>
|
||||
|
||||
/* HRM Service Definitions
|
||||
* Heart Rate Monitor Service: 0x180D
|
||||
* Heart Rate Measurement Char: 0x2A37
|
||||
* Body Sensor Location Char: 0x2A38
|
||||
*/
|
||||
BLEService hrms = BLEService(UUID16_SVC_HEART_RATE);
|
||||
BLECharacteristic hrmc = BLECharacteristic(UUID16_CHR_HEART_RATE_MEASUREMENT);
|
||||
BLECharacteristic bslc = BLECharacteristic(UUID16_CHR_BODY_SENSOR_LOCATION);
|
||||
// NRF52 wants these constants as byte arrays
|
||||
// Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER
|
||||
const uint8_t MESH_SERVICE_UUID_16[16u] = {0xfd, 0xea, 0x73, 0xe2, 0xca, 0x5d, 0xa8, 0x9f,
|
||||
0x1f, 0x46, 0xa8, 0x15, 0x18, 0xb2, 0xa1, 0x6b};
|
||||
const uint8_t TORADIO_UUID_16[16u] = {0xe7, 0x01, 0x44, 0x12, 0x66, 0x78, 0xdd, 0xa1,
|
||||
0xad, 0x4d, 0x9e, 0x12, 0xd2, 0x76, 0x5c, 0xf7};
|
||||
const uint8_t FROMRADIO_UUID_16[16u] = {0xd5, 0x54, 0xe4, 0xc5, 0x25, 0xc5, 0x31, 0xa5,
|
||||
0x55, 0x4a, 0x02, 0xee, 0xc2, 0xbc, 0xa2, 0x8b};
|
||||
const uint8_t FROMNUM_UUID_16[16u] = {0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6,
|
||||
0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed};
|
||||
|
||||
BLEDis bledis; // DIS (Device Information Service) helper class instance
|
||||
BLEBas blebas; // BAS (Battery Service) helper class instance
|
||||
BLEDfu bledfu; // DFU software update helper service
|
||||
static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16));
|
||||
static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16));
|
||||
static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16));
|
||||
static BLECharacteristic toRadio = BLECharacteristic(BLEUuid(TORADIO_UUID_16));
|
||||
|
||||
uint8_t bps = 0;
|
||||
static BLEDis bledis; // DIS (Device Information Service) helper class instance
|
||||
static BLEBas blebas; // BAS (Battery Service) helper class instance
|
||||
static BLEDfu bledfu; // DFU software update helper service
|
||||
|
||||
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in
|
||||
// proccess at once
|
||||
// static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)];
|
||||
static uint8_t fromRadioBytes[FromRadio_size];
|
||||
static uint8_t toRadioBytes[ToRadio_size];
|
||||
|
||||
class BluetoothPhoneAPI : public PhoneAPI
|
||||
{
|
||||
/**
|
||||
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
||||
*/
|
||||
virtual void onNowHasData(uint32_t fromRadioNum)
|
||||
{
|
||||
PhoneAPI::onNowHasData(fromRadioNum);
|
||||
|
||||
DEBUG_MSG("BLE notify fromNum\n");
|
||||
fromNum.notify32(fromRadioNum);
|
||||
}
|
||||
};
|
||||
|
||||
static BluetoothPhoneAPI *bluetoothPhoneAPI;
|
||||
|
||||
void connect_callback(uint16_t conn_handle)
|
||||
{
|
||||
@@ -26,7 +54,7 @@ void connect_callback(uint16_t conn_handle)
|
||||
char central_name[32] = {0};
|
||||
connection->getPeerName(central_name, sizeof(central_name));
|
||||
|
||||
DEBUG_MSG("Connected to %s\n", central_name);
|
||||
DEBUG_MSG("BLE Connected to %s\n", central_name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,9 +65,8 @@ void connect_callback(uint16_t conn_handle)
|
||||
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
|
||||
{
|
||||
(void)conn_handle;
|
||||
(void)reason;
|
||||
|
||||
DEBUG_MSG("Disconnected, reason = 0x%x\n", reason);
|
||||
DEBUG_MSG("BLE Disconnected, reason = 0x%x\n", reason);
|
||||
}
|
||||
|
||||
void cccd_callback(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value)
|
||||
@@ -49,11 +76,11 @@ void cccd_callback(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_valu
|
||||
|
||||
// Check the characteristic this CCCD update is associated with in case
|
||||
// this handler is used for multiple CCCD records.
|
||||
if (chr->uuid == hrmc.uuid) {
|
||||
if (chr->uuid == fromNum.uuid) {
|
||||
if (chr->notifyEnabled(conn_hdl)) {
|
||||
DEBUG_MSG("Heart Rate Measurement 'Notify' enabled\n");
|
||||
DEBUG_MSG("fromNum 'Notify' enabled\n");
|
||||
} else {
|
||||
DEBUG_MSG("Heart Rate Measurement 'Notify' disabled\n");
|
||||
DEBUG_MSG("fromNum 'Notify' disabled\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,13 +89,15 @@ void startAdv(void)
|
||||
{
|
||||
// Advertising packet
|
||||
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
|
||||
Bluefruit.Advertising.addTxPower();
|
||||
|
||||
// Include HRM Service UUID
|
||||
Bluefruit.Advertising.addService(hrms);
|
||||
// IncludeService UUID
|
||||
// Bluefruit.ScanResponse.addService(meshBleService);
|
||||
Bluefruit.ScanResponse.addTxPower();
|
||||
Bluefruit.ScanResponse.addName();
|
||||
|
||||
// Include Name
|
||||
Bluefruit.Advertising.addName();
|
||||
// Bluefruit.Advertising.addName();
|
||||
Bluefruit.Advertising.addService(meshBleService);
|
||||
|
||||
/* Start Advertising
|
||||
* - Enable auto advertising if disconnected
|
||||
@@ -82,74 +111,105 @@ void startAdv(void)
|
||||
Bluefruit.Advertising.restartOnDisconnect(true);
|
||||
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
|
||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
|
||||
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds. FIXME, we should stop advertising after X
|
||||
}
|
||||
|
||||
void setupHRM(void)
|
||||
// Just ack that the caller is allowed to read
|
||||
static void authorizeRead(uint16_t conn_hdl)
|
||||
{
|
||||
// Configure the Heart Rate Monitor service
|
||||
// See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml
|
||||
// Supported Characteristics:
|
||||
// Name UUID Requirement Properties
|
||||
// ---------------------------- ------ ----------- ----------
|
||||
// Heart Rate Measurement 0x2A37 Mandatory Notify
|
||||
// Body Sensor Location 0x2A38 Optional Read
|
||||
// Heart Rate Control Point 0x2A39 Conditional Write <-- Not used here
|
||||
hrms.begin();
|
||||
ble_gatts_rw_authorize_reply_params_t reply = {.type = BLE_GATTS_AUTHORIZE_TYPE_READ};
|
||||
reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply);
|
||||
}
|
||||
|
||||
/**
|
||||
* client is starting read, pull the bytes from our API class
|
||||
*/
|
||||
void fromRadioAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request)
|
||||
{
|
||||
if (request->offset == 0) {
|
||||
// If the read is long, we will get multiple authorize invocations - we only populate data on the first
|
||||
|
||||
size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes);
|
||||
|
||||
// DEBUG_MSG("fromRadioAuthorizeCb numBytes=%u\n", numBytes);
|
||||
// if (numBytes >= 2) DEBUG_MSG("fromRadio bytes %x %x\n", fromRadioBytes[0], fromRadioBytes[1]);
|
||||
|
||||
// Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue
|
||||
// or make empty if the queue is empty
|
||||
fromRadio.write(fromRadioBytes, numBytes);
|
||||
} else {
|
||||
// DEBUG_MSG("Ignoring successor read\n");
|
||||
}
|
||||
authorizeRead(conn_hdl);
|
||||
}
|
||||
|
||||
void toRadioWriteCb(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len)
|
||||
{
|
||||
DEBUG_MSG("toRadioWriteCb data %p, len %u\n", data, len);
|
||||
|
||||
bluetoothPhoneAPI->handleToRadio(data, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* client is starting read, pull the bytes from our API class
|
||||
*/
|
||||
void fromNumAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request)
|
||||
{
|
||||
DEBUG_MSG("fromNumAuthorizeCb\n");
|
||||
|
||||
authorizeRead(conn_hdl);
|
||||
}
|
||||
|
||||
void setupMeshService(void)
|
||||
{
|
||||
bluetoothPhoneAPI = new BluetoothPhoneAPI();
|
||||
bluetoothPhoneAPI->init();
|
||||
|
||||
meshBleService.begin();
|
||||
|
||||
// Note: You must call .begin() on the BLEService before calling .begin() on
|
||||
// any characteristic(s) within that service definition.. Calling .begin() on
|
||||
// a BLECharacteristic will cause it to be added to the last BLEService that
|
||||
// was 'begin()'ed!
|
||||
|
||||
// Configure the Heart Rate Measurement characteristic
|
||||
// See:
|
||||
// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml
|
||||
// Properties = Notify
|
||||
// Min Len = 1
|
||||
// Max Len = 8
|
||||
// B0 = UINT8 - Flag (MANDATORY)
|
||||
// b5:7 = Reserved
|
||||
// b4 = RR-Internal (0 = Not present, 1 = Present)
|
||||
// b3 = Energy expended status (0 = Not present, 1 = Present)
|
||||
// b1:2 = Sensor contact status (0+1 = Not supported, 2 = Supported but contact not detected, 3 = Supported and
|
||||
// detected) b0 = Value format (0 = UINT8, 1 = UINT16)
|
||||
// B1 = UINT8 - 8-bit heart rate measurement value in BPM
|
||||
// B2:3 = UINT16 - 16-bit heart rate measurement value in BPM
|
||||
// B4:5 = UINT16 - Energy expended in joules
|
||||
// B6:7 = UINT16 - RR Internal (1/1024 second resolution)
|
||||
hrmc.setProperties(CHR_PROPS_NOTIFY);
|
||||
hrmc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
|
||||
hrmc.setFixedLen(2);
|
||||
hrmc.setCccdWriteCallback(cccd_callback); // Optionally capture CCCD updates
|
||||
hrmc.begin();
|
||||
uint8_t hrmdata[2] = {0b00000110, 0x40}; // Set the characteristic to use 8-bit values, with the sensor connected and detected
|
||||
hrmc.write(hrmdata, 2);
|
||||
fromNum.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ);
|
||||
fromNum.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME, secure this!!!
|
||||
fromNum.setFixedLen(
|
||||
0); // Variable len (either 0 or 4) FIXME consider changing protocol so it is fixed 4 byte len, where 0 means empty
|
||||
fromNum.setMaxLen(4);
|
||||
fromNum.setCccdWriteCallback(cccd_callback); // Optionally capture CCCD updates
|
||||
// We don't yet need to hook the fromNum auth callback
|
||||
// fromNum.setReadAuthorizeCallback(fromNumAuthorizeCb);
|
||||
fromNum.write32(0); // Provide default fromNum of 0
|
||||
fromNum.begin();
|
||||
// uint8_t hrmdata[2] = {0b00000110, 0x40}; // Set the characteristic to use 8-bit values, with the sensor connected and
|
||||
// detected
|
||||
// hrmc.write(hrmdata, 2);
|
||||
|
||||
// Configure the Body Sensor Location characteristic
|
||||
// See:
|
||||
// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.body_sensor_location.xml
|
||||
// Properties = Read
|
||||
// Min Len = 1
|
||||
// Max Len = 1
|
||||
// B0 = UINT8 - Body Sensor Location
|
||||
// 0 = Other
|
||||
// 1 = Chest
|
||||
// 2 = Wrist
|
||||
// 3 = Finger
|
||||
// 4 = Hand
|
||||
// 5 = Ear Lobe
|
||||
// 6 = Foot
|
||||
// 7:255 = Reserved
|
||||
bslc.setProperties(CHR_PROPS_READ);
|
||||
bslc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
|
||||
bslc.setFixedLen(1);
|
||||
bslc.begin();
|
||||
bslc.write8(2); // Set the characteristic to 'Wrist' (2)
|
||||
fromRadio.setProperties(CHR_PROPS_READ);
|
||||
fromRadio.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME secure this!
|
||||
fromRadio.setMaxLen(sizeof(fromRadioBytes));
|
||||
fromRadio.setReadAuthorizeCallback(
|
||||
fromRadioAuthorizeCb,
|
||||
false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
|
||||
fromRadio.setBuffer(fromRadioBytes, sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space
|
||||
// for two copies
|
||||
fromRadio.begin();
|
||||
|
||||
toRadio.setProperties(CHR_PROPS_WRITE);
|
||||
toRadio.setPermission(SECMODE_OPEN, SECMODE_OPEN); // FIXME secure this!
|
||||
toRadio.setFixedLen(0);
|
||||
toRadio.setMaxLen(512);
|
||||
toRadio.setBuffer(toRadioBytes, sizeof(toRadioBytes));
|
||||
toRadio.setWriteCallback(
|
||||
toRadioWriteCb,
|
||||
false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
|
||||
toRadio.begin();
|
||||
}
|
||||
|
||||
// FIXME, turn off soft device access for debugging
|
||||
static bool isSoftDeviceAllowed = false;
|
||||
static bool isSoftDeviceAllowed = true;
|
||||
|
||||
void NRF52Bluetooth::setup()
|
||||
{
|
||||
@@ -158,7 +218,7 @@ void NRF52Bluetooth::setup()
|
||||
Bluefruit.begin();
|
||||
|
||||
// Set the advertised device name (keep it short!)
|
||||
Bluefruit.setName(getDeviceName()); // FIXME
|
||||
Bluefruit.setName(getDeviceName());
|
||||
|
||||
// Set the connect/disconnect callback handlers
|
||||
Bluefruit.Periph.setConnectCallback(connect_callback);
|
||||
@@ -166,21 +226,22 @@ void NRF52Bluetooth::setup()
|
||||
|
||||
// Configure and Start the Device Information Service
|
||||
DEBUG_MSG("Configuring the Device Information Service\n");
|
||||
bledis.setManufacturer("meshtastic.org");
|
||||
bledis.setModel("NRF52-meshtastic"); // FIXME
|
||||
bledis.setManufacturer(HW_VENDOR);
|
||||
bledis.setModel(optstr(HW_VERSION));
|
||||
bledis.setFirmwareRev(optstr(APP_VERSION));
|
||||
bledis.begin();
|
||||
|
||||
// Start the BLE Battery Service and set it to 100%
|
||||
DEBUG_MSG("Configuring the Battery Service\n");
|
||||
blebas.begin();
|
||||
blebas.write(42); // FIXME, report real power levels
|
||||
blebas.write(0); // Unknown battery level for now
|
||||
|
||||
bledfu.begin(); // Install the DFU helper
|
||||
|
||||
// Setup the Heart Rate Monitor service using
|
||||
// BLEService and BLECharacteristic classes
|
||||
DEBUG_MSG("Configuring the Heart Rate Monitor Service\n");
|
||||
setupHRM();
|
||||
DEBUG_MSG("Configuring the Mesh bluetooth service\n");
|
||||
setupMeshService();
|
||||
|
||||
// Supposedly debugging works with soft device if you disable advertising
|
||||
if (isSoftDeviceAllowed) {
|
||||
@@ -192,56 +253,8 @@ void NRF52Bluetooth::setup()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void loop()
|
||||
/// Given a level between 0-100, update the BLE attribute
|
||||
void updateBatteryLevel(uint8_t level)
|
||||
{
|
||||
digitalToggle(LED_RED);
|
||||
|
||||
if ( Bluefruit.connected() ) {
|
||||
uint8_t hrmdata[2] = { 0b00000110, bps++ }; // Sensor connected, increment BPS value
|
||||
|
||||
// Note: We use .notify instead of .write!
|
||||
// If it is connected but CCCD is not enabled
|
||||
// The characteristic's value is still updated although notification is not sent
|
||||
if ( hrmc.notify(hrmdata, sizeof(hrmdata)) ){
|
||||
Serial.print("Heart Rate Measurement updated to: "); Serial.println(bps);
|
||||
}else{
|
||||
Serial.println("ERROR: Notify not set in the CCCD or not connected!");
|
||||
}
|
||||
}
|
||||
|
||||
// Only send update once per second
|
||||
delay(1000);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
examples of advanced characteristics. use setReadAuthorizeCallback to prepare data for reads by others
|
||||
|
||||
err_t BLEDfu::begin(void)
|
||||
{
|
||||
// Invoke base class begin()
|
||||
VERIFY_STATUS( BLEService::begin() );
|
||||
|
||||
// No need to keep packet & revision characteristics
|
||||
BLECharacteristic chr_packet(UUID128_CHR_DFU_PACKET);
|
||||
chr_packet.setTempMemory();
|
||||
chr_packet.setProperties(CHR_PROPS_WRITE_WO_RESP);
|
||||
chr_packet.setMaxLen(20);
|
||||
VERIFY_STATUS( chr_packet.begin() );
|
||||
|
||||
_chr_control.setProperties(CHR_PROPS_WRITE | CHR_PROPS_NOTIFY);
|
||||
_chr_control.setMaxLen(23);
|
||||
_chr_control.setWriteAuthorizeCallback(bledfu_control_wr_authorize_cb);
|
||||
VERIFY_STATUS( _chr_control.begin() );
|
||||
|
||||
BLECharacteristic chr_revision(UUID128_CHR_DFU_REVISON);
|
||||
chr_revision.setTempMemory();
|
||||
chr_revision.setProperties(CHR_PROPS_READ);
|
||||
chr_revision.setFixedLen(2);
|
||||
VERIFY_STATUS( chr_revision.begin());
|
||||
chr_revision.write16(DFU_REV_APPMODE);
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
*/
|
||||
blebas.write(level);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "rtos.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Custom new/delete to panic if out out memory
|
||||
*/
|
||||
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
auto p = rtos_malloc(size);
|
||||
assert(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *operator new[](size_t size)
|
||||
{
|
||||
auto p = rtos_malloc(size);
|
||||
assert(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void operator delete(void *ptr)
|
||||
{
|
||||
rtos_free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void *ptr)
|
||||
{
|
||||
rtos_free(ptr);
|
||||
}
|
||||
+31
-27
@@ -5,47 +5,49 @@
|
||||
|
||||
enum { r0, r1, r2, r3, r12, lr, pc, psr };
|
||||
|
||||
// we can't use the regular DEBUG_MSG for these crash dumps because it depends on threading still being running. Instead use the
|
||||
// segger in memory tool
|
||||
#define FAULT_MSG(...) SEGGER_MSG(__VA_ARGS__)
|
||||
|
||||
// Per http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Cihcfefj.html
|
||||
static void printUsageErrorMsg(uint32_t cfsr)
|
||||
{
|
||||
DEBUG_MSG("Usage fault: ");
|
||||
FAULT_MSG("Usage fault: ");
|
||||
cfsr >>= SCB_CFSR_USGFAULTSR_Pos; // right shift to lsb
|
||||
if ((cfsr & (1 << 9)) != 0)
|
||||
DEBUG_MSG("Divide by zero\n");
|
||||
FAULT_MSG("Divide by zero\n");
|
||||
if ((cfsr & (1 << 8)) != 0)
|
||||
DEBUG_MSG("Unaligned\n");
|
||||
FAULT_MSG("Unaligned\n");
|
||||
}
|
||||
|
||||
static void printBusErrorMsg(uint32_t cfsr)
|
||||
{
|
||||
DEBUG_MSG("Usage fault: ");
|
||||
FAULT_MSG("Bus fault: ");
|
||||
cfsr >>= SCB_CFSR_BUSFAULTSR_Pos; // right shift to lsb
|
||||
if ((cfsr & (1 << 0)) != 0)
|
||||
DEBUG_MSG("Instruction bus error\n");
|
||||
FAULT_MSG("Instruction bus error\n");
|
||||
if ((cfsr & (1 << 1)) != 0)
|
||||
DEBUG_MSG("Precise data bus error\n");
|
||||
FAULT_MSG("Precise data bus error\n");
|
||||
if ((cfsr & (1 << 2)) != 0)
|
||||
DEBUG_MSG("Imprecise data bus error\n");
|
||||
FAULT_MSG("Imprecise data bus error\n");
|
||||
}
|
||||
|
||||
static void printMemErrorMsg(uint32_t cfsr)
|
||||
{
|
||||
DEBUG_MSG("Usage fault: ");
|
||||
FAULT_MSG("Memory fault: ");
|
||||
cfsr >>= SCB_CFSR_MEMFAULTSR_Pos; // right shift to lsb
|
||||
if ((cfsr & (1 << 0)) != 0)
|
||||
DEBUG_MSG("Instruction access violation\n");
|
||||
FAULT_MSG("Instruction access violation\n");
|
||||
if ((cfsr & (1 << 1)) != 0)
|
||||
DEBUG_MSG("Data access violation\n");
|
||||
FAULT_MSG("Data access violation\n");
|
||||
}
|
||||
|
||||
static void HardFault_Impl(uint32_t stack[])
|
||||
extern "C" void HardFault_Impl(uint32_t stack[])
|
||||
{
|
||||
DEBUG_MSG("In Hard Fault Handler\n");
|
||||
DEBUG_MSG("SCB->HFSR = 0x%08lx\n", SCB->HFSR);
|
||||
FAULT_MSG("Hard Fault occurred! SCB->HFSR = 0x%08lx\n", SCB->HFSR);
|
||||
|
||||
if ((SCB->HFSR & SCB_HFSR_FORCED_Msk) != 0) {
|
||||
DEBUG_MSG("Forced Hard Fault\n");
|
||||
DEBUG_MSG("SCB->CFSR = 0x%08lx\n", SCB->CFSR);
|
||||
FAULT_MSG("Forced Hard Fault: SCB->CFSR = 0x%08lx\n", SCB->CFSR);
|
||||
|
||||
if ((SCB->CFSR & SCB_CFSR_USGFAULTSR_Msk) != 0) {
|
||||
printUsageErrorMsg(SCB->CFSR);
|
||||
@@ -57,21 +59,23 @@ static void HardFault_Impl(uint32_t stack[])
|
||||
printMemErrorMsg(SCB->CFSR);
|
||||
}
|
||||
|
||||
DEBUG_MSG("r0 = 0x%08lx\n", stack[r0]);
|
||||
DEBUG_MSG("r1 = 0x%08lx\n", stack[r1]);
|
||||
DEBUG_MSG("r2 = 0x%08lx\n", stack[r2]);
|
||||
DEBUG_MSG("r3 = 0x%08lx\n", stack[r3]);
|
||||
DEBUG_MSG("r12 = 0x%08lx\n", stack[r12]);
|
||||
DEBUG_MSG("lr = 0x%08lx\n", stack[lr]);
|
||||
DEBUG_MSG("pc = 0x%08lx\n", stack[pc]);
|
||||
DEBUG_MSG("psr = 0x%08lx\n", stack[psr]);
|
||||
asm volatile("bkpt #01");
|
||||
while (1)
|
||||
;
|
||||
FAULT_MSG("r0 = 0x%08lx\n", stack[r0]);
|
||||
FAULT_MSG("r1 = 0x%08lx\n", stack[r1]);
|
||||
FAULT_MSG("r2 = 0x%08lx\n", stack[r2]);
|
||||
FAULT_MSG("r3 = 0x%08lx\n", stack[r3]);
|
||||
FAULT_MSG("r12 = 0x%08lx\n", stack[r12]);
|
||||
FAULT_MSG("lr = 0x%08lx\n", stack[lr]);
|
||||
FAULT_MSG("pc = 0x%08lx\n", stack[pc]);
|
||||
FAULT_MSG("psr = 0x%08lx\n", stack[psr]);
|
||||
}
|
||||
|
||||
FAULT_MSG("Done with fault report - Waiting to reboot\n");
|
||||
asm volatile("bkpt #01"); // Enter the debugger if one is connected
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void HardFault_Handler(void)
|
||||
extern "C" void HardFault_Handler(void)
|
||||
{
|
||||
asm volatile(" mrs r0,msp\n"
|
||||
" b HardFault_Impl \n");
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
#include <assert.h>
|
||||
#include <ble_gap.h>
|
||||
#include <memory.h>
|
||||
#include <nrf52840.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef NRF52840_XXAA
|
||||
// #include <nrf52840.h>
|
||||
#endif
|
||||
|
||||
// #define USE_SOFTDEVICE
|
||||
|
||||
@@ -49,6 +53,7 @@ void setBluetoothEnable(bool on)
|
||||
if (on != bleOn) {
|
||||
if (on) {
|
||||
if (!nrf52Bluetooth) {
|
||||
// DEBUG_MSG("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n");
|
||||
nrf52Bluetooth = new NRF52Bluetooth();
|
||||
nrf52Bluetooth->setup();
|
||||
}
|
||||
@@ -59,6 +64,18 @@ void setBluetoothEnable(bool on)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override printf to use the SEGGER output library
|
||||
*/
|
||||
int printf(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
auto res = SEGGER_RTT_vprintf(0, fmt, &args);
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
void nrf52Setup()
|
||||
{
|
||||
|
||||
@@ -80,4 +97,5 @@ void nrf52Setup()
|
||||
// ble_controller_rand_vector_get_blocking(&r, sizeof(r));
|
||||
// randomSeed(r);
|
||||
DEBUG_MSG("FIXME, call randomSeed\n");
|
||||
// ::printf("TESTING PRINTF\n");
|
||||
}
|
||||
Reference in New Issue
Block a user