mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-10-08 18:56:40 +00:00
Merge pull request #3122 from Hacuchino-hash/x1-notifications
Add RGB LED and haptic notifications for SenseCAP MeshTracker X1
This commit is contained in:
@@ -28,6 +28,7 @@ public:
|
|||||||
uint32_t ble_pin = 0;
|
uint32_t ble_pin = 0;
|
||||||
uint8_t advert_loc_policy = 0;
|
uint8_t advert_loc_policy = 0;
|
||||||
uint8_t buzzer_quiet = 0;
|
uint8_t buzzer_quiet = 0;
|
||||||
|
uint8_t vibe_quiet = 0;
|
||||||
uint8_t gps_enabled = 0; // GPS enabled flag (0=disabled, 1=enabled)
|
uint8_t gps_enabled = 0; // GPS enabled flag (0=disabled, 1=enabled)
|
||||||
uint32_t gps_interval = 0; // GPS read interval in seconds
|
uint32_t gps_interval = 0; // GPS read interval in seconds
|
||||||
uint8_t autoadd_config = 0; // bitmask for auto-add contacts config
|
uint8_t autoadd_config = 0; // bitmask for auto-add contacts config
|
||||||
@@ -101,6 +102,7 @@ private:
|
|||||||
def("defs_key", (void *) _parent->default_scope_key, sizeof(_parent->default_scope_key));
|
def("defs_key", (void *) _parent->default_scope_key, sizeof(_parent->default_scope_key));
|
||||||
def("pin", _parent->ble_pin);
|
def("pin", _parent->ble_pin);
|
||||||
def("buzz_q", _parent->buzzer_quiet);
|
def("buzz_q", _parent->buzzer_quiet);
|
||||||
|
def("vibe_q", _parent->vibe_quiet);
|
||||||
def("auto_add", _parent->autoadd_config); // bitmask for auto-add contacts config
|
def("auto_add", _parent->autoadd_config); // bitmask for auto-add contacts config
|
||||||
def("man_add", _parent->manual_add_contacts);
|
def("man_add", _parent->manual_add_contacts);
|
||||||
def("tel_base", _parent->telemetry_mode_base);
|
def("tel_base", _parent->telemetry_mode_base);
|
||||||
|
|||||||
@@ -6,12 +6,19 @@
|
|||||||
#define AUTO_OFF_MILLIS 15000 // 15 seconds
|
#define AUTO_OFF_MILLIS 15000 // 15 seconds
|
||||||
#define BOOT_SCREEN_MILLIS 3000 // 3 seconds
|
#define BOOT_SCREEN_MILLIS 3000 // 3 seconds
|
||||||
|
|
||||||
#ifdef PIN_STATUS_LED
|
#if defined(PIN_STATUS_LED) || defined(PIN_STATUS_LED_R)
|
||||||
#define LED_ON_MILLIS 20
|
#define LED_ON_MILLIS 20
|
||||||
#define LED_ON_MSG_MILLIS 200
|
#define LED_ON_MSG_MILLIS 200
|
||||||
#define LED_CYCLE_MILLIS 4000
|
#define LED_CYCLE_MILLIS 4000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(PIN_STATUS_LED_R) && defined(PIN_STATUS_LED_G) && defined(PIN_STATUS_LED_B)
|
||||||
|
#define STATUS_LED_RGB 1
|
||||||
|
#ifndef LOW_BATT_MILLIVOLTS
|
||||||
|
#define LOW_BATT_MILLIVOLTS 3500
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef USER_BTN_PRESSED
|
#ifndef USER_BTN_PRESSED
|
||||||
#define USER_BTN_PRESSED LOW
|
#define USER_BTN_PRESSED LOW
|
||||||
#endif
|
#endif
|
||||||
@@ -60,6 +67,11 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
|
|||||||
buzzer.startup();
|
buzzer.startup();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_DRV2605
|
||||||
|
vibration.begin();
|
||||||
|
vibration.quiet(_node_prefs->vibe_quiet);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Initialize digital button if available
|
// Initialize digital button if available
|
||||||
#ifdef PIN_USER_BTN
|
#ifdef PIN_USER_BTN
|
||||||
_userButton = new Button(PIN_USER_BTN, USER_BTN_PRESSED);
|
_userButton = new Button(PIN_USER_BTN, USER_BTN_PRESSED);
|
||||||
@@ -130,6 +142,10 @@ void UITask::clearMsgPreview() {
|
|||||||
void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) {
|
void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) {
|
||||||
_msgcount = msgcount;
|
_msgcount = msgcount;
|
||||||
|
|
||||||
|
#ifdef HAS_DRV2605
|
||||||
|
vibration.trigger(); // vibrate even while the app is connected (honors quiet + cooldown)
|
||||||
|
#endif
|
||||||
|
|
||||||
if (path_len == 0xFF) {
|
if (path_len == 0xFF) {
|
||||||
sprintf(_origin, "(F) %s", from_name);
|
sprintf(_origin, "(F) %s", from_name);
|
||||||
} else {
|
} else {
|
||||||
@@ -260,8 +276,118 @@ void UITask::renderCurrScreen() {
|
|||||||
_need_refresh = false;
|
_need_refresh = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef STATUS_LED_RGB
|
||||||
|
static void statusLedWrite(uint8_t r, uint8_t g, uint8_t b) {
|
||||||
|
analogWrite(PIN_STATUS_LED_R, r);
|
||||||
|
analogWrite(PIN_STATUS_LED_G, g);
|
||||||
|
analogWrite(PIN_STATUS_LED_B, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void statusLedWheel(uint8_t pos) { // smooth hue sweep, 0..255
|
||||||
|
if (pos < 85) {
|
||||||
|
statusLedWrite(255 - pos * 3, pos * 3, 0);
|
||||||
|
} else if (pos < 170) {
|
||||||
|
pos -= 85;
|
||||||
|
statusLedWrite(0, 255 - pos * 3, pos * 3);
|
||||||
|
} else {
|
||||||
|
pos -= 170;
|
||||||
|
statusLedWrite(pos * 3, 0, 255 - pos * 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void UITask::userLedHandler() {
|
void UITask::userLedHandler() {
|
||||||
#ifdef PIN_STATUS_LED
|
#ifdef STATUS_LED_RGB
|
||||||
|
static bool booted = false;
|
||||||
|
static bool flourish_active = false;
|
||||||
|
static unsigned long flourish_until = 0;
|
||||||
|
static int prev_msgcount = 0;
|
||||||
|
static int state = 0;
|
||||||
|
static unsigned long next_change = 0;
|
||||||
|
static int last_increment = 0;
|
||||||
|
static unsigned long next_batt_check = 0;
|
||||||
|
static bool low_batt = false;
|
||||||
|
|
||||||
|
unsigned long cur_time = millis();
|
||||||
|
|
||||||
|
if (!booted) { // color sweep on boot
|
||||||
|
booted = true;
|
||||||
|
flourish_until = cur_time + 1200;
|
||||||
|
flourish_active = true;
|
||||||
|
}
|
||||||
|
if (_msgcount > prev_msgcount) { // color sweep when a new message arrives
|
||||||
|
flourish_until = cur_time + 800;
|
||||||
|
flourish_active = true;
|
||||||
|
}
|
||||||
|
prev_msgcount = _msgcount;
|
||||||
|
|
||||||
|
if (flourish_active) {
|
||||||
|
if (cur_time < flourish_until) {
|
||||||
|
statusLedWheel((cur_time % 1200) * 255 / 1200);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
statusLedWrite(0, 0, 0);
|
||||||
|
flourish_active = false;
|
||||||
|
state = 0;
|
||||||
|
next_change = cur_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur_time > next_batt_check) { // battery reads are not free, keep them rare
|
||||||
|
low_batt = _board->getBattMilliVolts() < LOW_BATT_MILLIVOLTS;
|
||||||
|
next_batt_check = cur_time + 60000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef EXT_CHRG_DETECT
|
||||||
|
// charge status display while docked (skipped when messages are waiting,
|
||||||
|
// so the unread indication is never masked)
|
||||||
|
static unsigned long next_pwr_check = 0;
|
||||||
|
static bool ext_powered = false, ext_charging = false;
|
||||||
|
if (cur_time > next_pwr_check) {
|
||||||
|
ext_powered = _board->isExternalPowered();
|
||||||
|
bool chrg = digitalRead(EXT_CHRG_DETECT) == LOW;
|
||||||
|
#ifdef EXT_CHRG_DONE
|
||||||
|
if (digitalRead(EXT_CHRG_DONE) == LOW) chrg = false; // charge-done wins
|
||||||
|
#endif
|
||||||
|
ext_charging = ext_powered && chrg;
|
||||||
|
next_pwr_check = cur_time + 1000;
|
||||||
|
}
|
||||||
|
if (ext_powered && _msgcount == 0) {
|
||||||
|
if (ext_charging) {
|
||||||
|
// amber breathing while charging
|
||||||
|
int ph = cur_time % 2000;
|
||||||
|
int v = ph < 1000 ? ph : 2000 - ph;
|
||||||
|
uint8_t lvl = (uint8_t)(v * 255 / 1000);
|
||||||
|
statusLedWrite(lvl, (uint8_t)(lvl * 35 / 100), 0);
|
||||||
|
} else {
|
||||||
|
statusLedWrite(0, 40, 0); // dim solid green: charge complete
|
||||||
|
}
|
||||||
|
state = 0;
|
||||||
|
next_change = cur_time;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (cur_time > next_change) {
|
||||||
|
if (state == 0) {
|
||||||
|
state = 1;
|
||||||
|
last_increment = (_msgcount > 0) ? LED_ON_MSG_MILLIS : LED_ON_MILLIS;
|
||||||
|
next_change = cur_time + last_increment;
|
||||||
|
if (low_batt) {
|
||||||
|
statusLedWrite(255, 0, 0); // red: battery low
|
||||||
|
} else if (_msgcount > 0) {
|
||||||
|
statusLedWrite(255, 90, 0); // amber: unread messages
|
||||||
|
} else if (_connected) {
|
||||||
|
statusLedWrite(0, 0, 255); // blue: app connected
|
||||||
|
} else {
|
||||||
|
statusLedWrite(0, 255, 0); // green: heartbeat
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state = 0;
|
||||||
|
next_change = cur_time + LED_CYCLE_MILLIS - last_increment;
|
||||||
|
statusLedWrite(0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(PIN_STATUS_LED)
|
||||||
static int state = 0;
|
static int state = 0;
|
||||||
static int next_change = 0;
|
static int next_change = 0;
|
||||||
static int last_increment = 0;
|
static int last_increment = 0;
|
||||||
@@ -406,8 +532,26 @@ void UITask::handleButtonDoublePress() {
|
|||||||
|
|
||||||
void UITask::handleButtonTriplePress() {
|
void UITask::handleButtonTriplePress() {
|
||||||
MESH_DEBUG_PRINTLN("UITask: triple press triggered");
|
MESH_DEBUG_PRINTLN("UITask: triple press triggered");
|
||||||
// Toggle buzzer quiet mode
|
#if defined(PIN_BUZZER) && defined(HAS_DRV2605)
|
||||||
#ifdef PIN_BUZZER
|
// cycle alert modes: Buzz+Vibe -> Buzz only -> Vibe only -> Silent
|
||||||
|
int mode = (_node_prefs->buzzer_quiet ? 2 : 0) | (_node_prefs->vibe_quiet ? 1 : 0);
|
||||||
|
mode = (mode + 1) & 3;
|
||||||
|
_node_prefs->buzzer_quiet = (mode & 2) ? 1 : 0;
|
||||||
|
_node_prefs->vibe_quiet = (mode & 1) ? 1 : 0;
|
||||||
|
buzzer.quiet(_node_prefs->buzzer_quiet);
|
||||||
|
vibration.quiet(_node_prefs->vibe_quiet);
|
||||||
|
// audible/tactile confirmation of the new mode (no screen on some boards)
|
||||||
|
if (!_node_prefs->buzzer_quiet) notify(UIEventType::ack);
|
||||||
|
if (!_node_prefs->vibe_quiet) vibration.trigger(true);
|
||||||
|
switch (mode) {
|
||||||
|
case 0: sprintf(_alert, "Alerts: Buzz+Vibe"); break;
|
||||||
|
case 1: sprintf(_alert, "Alerts: Buzz only"); break;
|
||||||
|
case 2: sprintf(_alert, "Alerts: Vibe only"); break;
|
||||||
|
default: sprintf(_alert, "Alerts: Silent"); break;
|
||||||
|
}
|
||||||
|
the_mesh.savePrefs();
|
||||||
|
_need_refresh = true;
|
||||||
|
#elif defined(PIN_BUZZER)
|
||||||
if (buzzer.isQuiet()) {
|
if (buzzer.isQuiet()) {
|
||||||
buzzer.quiet(false);
|
buzzer.quiet(false);
|
||||||
notify(UIEventType::ack);
|
notify(UIEventType::ack);
|
||||||
@@ -419,7 +563,7 @@ void UITask::handleButtonTriplePress() {
|
|||||||
_node_prefs->buzzer_quiet = buzzer.isQuiet();
|
_node_prefs->buzzer_quiet = buzzer.isQuiet();
|
||||||
the_mesh.savePrefs();
|
the_mesh.savePrefs();
|
||||||
_need_refresh = true;
|
_need_refresh = true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void UITask::handleButtonQuadruplePress() {
|
void UITask::handleButtonQuadruplePress() {
|
||||||
|
|||||||
@@ -14,11 +14,18 @@
|
|||||||
|
|
||||||
#include "Button.h"
|
#include "Button.h"
|
||||||
|
|
||||||
|
#ifdef HAS_DRV2605
|
||||||
|
#include <helpers/ui/DRV2605Vibration.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
class UITask : public AbstractUITask {
|
class UITask : public AbstractUITask {
|
||||||
DisplayDriver* _display;
|
DisplayDriver* _display;
|
||||||
SensorManager* _sensors;
|
SensorManager* _sensors;
|
||||||
#ifdef PIN_BUZZER
|
#ifdef PIN_BUZZER
|
||||||
genericBuzzer buzzer;
|
genericBuzzer buzzer;
|
||||||
|
#endif
|
||||||
|
#ifdef HAS_DRV2605
|
||||||
|
DRV2605Vibration vibration;
|
||||||
#endif
|
#endif
|
||||||
unsigned long _next_refresh, _auto_off;
|
unsigned long _next_refresh, _auto_off;
|
||||||
NodePrefs* _node_prefs;
|
NodePrefs* _node_prefs;
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#ifdef HAS_DRV2605
|
||||||
|
|
||||||
|
#include "DRV2605Vibration.h"
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
void DRV2605Vibration::begin() {
|
||||||
|
#ifdef PIN_DRV_EN
|
||||||
|
pinMode(PIN_DRV_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_DRV_EN, HIGH); // power up the haptic driver
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
if (!drv.begin(&Wire)) {
|
||||||
|
return; // no haptic driver found, stay silent
|
||||||
|
}
|
||||||
|
#ifdef DRV2605_USE_LRA
|
||||||
|
// LRA mode: 4x brake factor, medium loop gain, back-EMF gain 2
|
||||||
|
drv.writeRegister8(DRV2605_REG_FEEDBACK, 0xB6);
|
||||||
|
#endif
|
||||||
|
drv.selectLibrary(1);
|
||||||
|
drv.setMode(DRV2605_MODE_INTTRIG);
|
||||||
|
_ready = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRV2605Vibration::trigger(bool force) {
|
||||||
|
if (!_ready || _quiet) return;
|
||||||
|
unsigned long now = millis();
|
||||||
|
if (!force && _last_trigger != 0 && now - _last_trigger < VIBRATION_TIMEOUT) return;
|
||||||
|
_last_trigger = now;
|
||||||
|
drv.setWaveform(0, DRV2605_EFFECT);
|
||||||
|
drv.setWaveform(1, 0); // pause
|
||||||
|
drv.setWaveform(2, DRV2605_EFFECT);
|
||||||
|
drv.setWaveform(3, 0); // end of sequence
|
||||||
|
drv.go();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRV2605Vibration::loop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DRV2605Vibration::isVibrating() {
|
||||||
|
return false; // effects are short, treat as instantaneous
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRV2605Vibration::stop() {
|
||||||
|
if (_ready) drv.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ifdef HAS_DRV2605
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef HAS_DRV2605
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <Adafruit_DRV2605.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vibration control class for boards where the motor is behind a
|
||||||
|
* DRV2605 haptic driver on I2C (e.g. Seeed SenseCAP MeshTracker X1).
|
||||||
|
* Same interface as GenericVibration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VIBRATION_TIMEOUT
|
||||||
|
#define VIBRATION_TIMEOUT 5000 // cooldown between vibrations
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DRV2605_EFFECT
|
||||||
|
#define DRV2605_EFFECT 16 // "1000 ms alert" from the DRV2605 effect library
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class DRV2605Vibration {
|
||||||
|
public:
|
||||||
|
void begin(); // power up and init the DRV2605
|
||||||
|
void trigger(bool force = false); // trigger vibration; force skips the cooldown
|
||||||
|
void loop(); // no-op, the DRV2605 plays effects autonomously
|
||||||
|
bool isVibrating();
|
||||||
|
void stop(); // stop vibration immediately
|
||||||
|
void quiet(bool q) { _quiet = q; }
|
||||||
|
bool isQuiet() const { return _quiet; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Adafruit_DRV2605 drv;
|
||||||
|
bool _ready = false;
|
||||||
|
bool _quiet = false;
|
||||||
|
unsigned long _last_trigger = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ifdef HAS_DRV2605
|
||||||
@@ -12,6 +12,9 @@ build_flags = ${nrf52_base.build_flags}
|
|||||||
-D PIN_USER_BTN=6
|
-D PIN_USER_BTN=6
|
||||||
-D USER_BTN_PRESSED=HIGH
|
-D USER_BTN_PRESSED=HIGH
|
||||||
-D PIN_STATUS_LED=24
|
-D PIN_STATUS_LED=24
|
||||||
|
-D PIN_STATUS_LED_R=3 ; P0.3 red
|
||||||
|
-D PIN_STATUS_LED_G=24 ; P0.24 green
|
||||||
|
-D PIN_STATUS_LED_B=28 ; P0.28 blue
|
||||||
-D RADIO_CLASS=CustomLR2021
|
-D RADIO_CLASS=CustomLR2021
|
||||||
-D USE_LR2021
|
-D USE_LR2021
|
||||||
-D WRAPPER_CLASS=CustomLR2021Wrapper
|
-D WRAPPER_CLASS=CustomLR2021Wrapper
|
||||||
@@ -29,6 +32,8 @@ build_flags = ${nrf52_base.build_flags}
|
|||||||
build_src_filter = ${nrf52_base.build_src_filter}
|
build_src_filter = ${nrf52_base.build_src_filter}
|
||||||
+<helpers/*.cpp>
|
+<helpers/*.cpp>
|
||||||
+<../variants/meshtracker_x1>
|
+<../variants/meshtracker_x1>
|
||||||
|
lib_deps = ${nrf52_base.lib_deps}
|
||||||
|
https://github.com/adafruit/Adafruit_SPA06_003/archive/refs/tags/1.0.2.zip
|
||||||
debug_tool = jlink
|
debug_tool = jlink
|
||||||
upload_protocol = nrfutil
|
upload_protocol = nrfutil
|
||||||
|
|
||||||
@@ -77,16 +82,20 @@ build_flags = ${MeshTracker_X1.build_flags}
|
|||||||
-D OFFLINE_QUEUE_SIZE=256
|
-D OFFLINE_QUEUE_SIZE=256
|
||||||
-D DISPLAY_CLASS=NullDisplayDriver
|
-D DISPLAY_CLASS=NullDisplayDriver
|
||||||
-D PIN_BUZZER=25
|
-D PIN_BUZZER=25
|
||||||
|
-D HAS_DRV2605=1
|
||||||
|
-D DRV2605_USE_LRA=1
|
||||||
-D ENABLE_USB_INTERFACE
|
-D ENABLE_USB_INTERFACE
|
||||||
build_src_filter = ${MeshTracker_X1.build_src_filter}
|
build_src_filter = ${MeshTracker_X1.build_src_filter}
|
||||||
+<helpers/ui/buzzer.cpp>
|
+<helpers/ui/buzzer.cpp>
|
||||||
+<helpers/ui/NullDisplayDriver.cpp>
|
+<helpers/ui/NullDisplayDriver.cpp>
|
||||||
|
+<helpers/ui/DRV2605Vibration.cpp>
|
||||||
+<../examples/companion_radio/*.cpp>
|
+<../examples/companion_radio/*.cpp>
|
||||||
+<../examples/companion_radio/ui-orig/*.cpp>
|
+<../examples/companion_radio/ui-orig/*.cpp>
|
||||||
lib_deps = ${MeshTracker_X1.lib_deps}
|
lib_deps = ${MeshTracker_X1.lib_deps}
|
||||||
densaugeo/base64 @ ~1.4.0
|
densaugeo/base64 @ ~1.4.0
|
||||||
stevemarple/MicroNMEA @ ^2.0.6
|
stevemarple/MicroNMEA @ ^2.0.6
|
||||||
end2endzone/NonBlockingRTTTL@^1.3.0
|
end2endzone/NonBlockingRTTTL@^1.3.0
|
||||||
|
adafruit/Adafruit DRV2605 Library @ ^1.2.4
|
||||||
|
|
||||||
[env:MeshTracker_X1_companion_radio_ble]
|
[env:MeshTracker_X1_companion_radio_ble]
|
||||||
extends = MeshTracker_X1
|
extends = MeshTracker_X1
|
||||||
@@ -104,14 +113,18 @@ build_flags = ${MeshTracker_X1.build_flags}
|
|||||||
-D OFFLINE_QUEUE_SIZE=256
|
-D OFFLINE_QUEUE_SIZE=256
|
||||||
-D DISPLAY_CLASS=NullDisplayDriver
|
-D DISPLAY_CLASS=NullDisplayDriver
|
||||||
-D PIN_BUZZER=25
|
-D PIN_BUZZER=25
|
||||||
|
-D HAS_DRV2605=1
|
||||||
|
-D DRV2605_USE_LRA=1
|
||||||
-D ADVERT_NAME='"@@MAC"'
|
-D ADVERT_NAME='"@@MAC"'
|
||||||
build_src_filter = ${MeshTracker_X1.build_src_filter}
|
build_src_filter = ${MeshTracker_X1.build_src_filter}
|
||||||
+<helpers/nrf52/SerialBLEInterface.cpp>
|
+<helpers/nrf52/SerialBLEInterface.cpp>
|
||||||
+<helpers/ui/buzzer.cpp>
|
+<helpers/ui/buzzer.cpp>
|
||||||
+<helpers/ui/NullDisplayDriver.cpp>
|
+<helpers/ui/NullDisplayDriver.cpp>
|
||||||
|
+<helpers/ui/DRV2605Vibration.cpp>
|
||||||
+<../examples/companion_radio/*.cpp>
|
+<../examples/companion_radio/*.cpp>
|
||||||
+<../examples/companion_radio/ui-orig/*.cpp>
|
+<../examples/companion_radio/ui-orig/*.cpp>
|
||||||
lib_deps = ${MeshTracker_X1.lib_deps}
|
lib_deps = ${MeshTracker_X1.lib_deps}
|
||||||
densaugeo/base64 @ ~1.4.0
|
densaugeo/base64 @ ~1.4.0
|
||||||
stevemarple/MicroNMEA @ ^2.0.6
|
stevemarple/MicroNMEA @ ^2.0.6
|
||||||
end2endzone/NonBlockingRTTTL@^1.3.0
|
end2endzone/NonBlockingRTTTL@^1.3.0
|
||||||
|
adafruit/Adafruit DRV2605 Library @ ^1.2.4
|
||||||
|
|||||||
@@ -67,6 +67,17 @@ void MeshTrackerX1SensorManager::stop_gps() {
|
|||||||
bool MeshTrackerX1SensorManager::begin() {
|
bool MeshTrackerX1SensorManager::begin() {
|
||||||
// init GPS
|
// init GPS
|
||||||
Serial1.begin(GPS_BAUD_RATE);
|
Serial1.begin(GPS_BAUD_RATE);
|
||||||
|
|
||||||
|
// init SPA06-003 barometer
|
||||||
|
baro_ok = spa06.begin(SPA06_003_DEFAULT_ADDR, &Wire) || spa06.begin(0x76, &Wire);
|
||||||
|
if (baro_ok) {
|
||||||
|
spa06.setPressureOversampling(SPA06_003_OVERSAMPLE_8);
|
||||||
|
spa06.setTemperatureOversampling(SPA06_003_OVERSAMPLE_8);
|
||||||
|
// 1 Hz continuous keeps reads non-blocking at minimal power cost
|
||||||
|
spa06.setPressureMeasureRate(SPA06_003_RATE_1);
|
||||||
|
spa06.setTemperatureMeasureRate(SPA06_003_RATE_1);
|
||||||
|
spa06.setMeasurementMode(SPA06_003_MEAS_CONTINUOUS_BOTH);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,12 +85,17 @@ bool MeshTrackerX1SensorManager::querySensors(uint8_t requester_permissions, Cay
|
|||||||
if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission?
|
if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission?
|
||||||
telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude);
|
telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude);
|
||||||
}
|
}
|
||||||
|
if (requester_permissions & TELEM_PERM_ENVIRONMENT && baro_ok) {
|
||||||
|
telemetry.addTemperature(TELEM_CHANNEL_SELF, spa06.readTemperature());
|
||||||
|
telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, spa06.readPressure());
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshTrackerX1SensorManager::loop() {
|
void MeshTrackerX1SensorManager::loop() {
|
||||||
static long next_gps_update = 0;
|
static long next_gps_update = 0;
|
||||||
|
|
||||||
|
|
||||||
_nmea->loop();
|
_nmea->loop();
|
||||||
|
|
||||||
if (millis() > next_gps_update) {
|
if (millis() > next_gps_update) {
|
||||||
|
|||||||
@@ -8,12 +8,15 @@
|
|||||||
#include <helpers/ArduinoHelpers.h>
|
#include <helpers/ArduinoHelpers.h>
|
||||||
#include <helpers/SensorManager.h>
|
#include <helpers/SensorManager.h>
|
||||||
#include <helpers/sensors/LocationProvider.h>
|
#include <helpers/sensors/LocationProvider.h>
|
||||||
|
#include <Adafruit_SPA06_003.h>
|
||||||
#ifdef DISPLAY_CLASS
|
#ifdef DISPLAY_CLASS
|
||||||
#include "NullDisplayDriver.h"
|
#include "NullDisplayDriver.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class MeshTrackerX1SensorManager: public SensorManager {
|
class MeshTrackerX1SensorManager: public SensorManager {
|
||||||
bool gps_active = false;
|
bool gps_active = false;
|
||||||
|
bool baro_ok = false;
|
||||||
|
Adafruit_SPA06_003 spa06;
|
||||||
LocationProvider * _nmea;
|
LocationProvider * _nmea;
|
||||||
|
|
||||||
void start_gps();
|
void start_gps();
|
||||||
|
|||||||
@@ -62,7 +62,8 @@ const uint32_t g_ADigitalPinMap[PINS_COUNT + 1] =
|
|||||||
void initVariant()
|
void initVariant()
|
||||||
{
|
{
|
||||||
pinMode(BATTERY_PIN, INPUT);
|
pinMode(BATTERY_PIN, INPUT);
|
||||||
pinMode(EXT_CHRG_DETECT, INPUT);
|
pinMode(EXT_CHRG_DETECT, INPUT_PULLUP);
|
||||||
|
pinMode(EXT_CHRG_DONE, INPUT_PULLUP);
|
||||||
pinMode(EXT_PWR_DETECT, INPUT);
|
pinMode(EXT_PWR_DETECT, INPUT);
|
||||||
pinMode(PIN_BUTTON1, INPUT_PULLDOWN);
|
pinMode(PIN_BUTTON1, INPUT_PULLDOWN);
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#define ADC_MULTIPLIER (2.0F)
|
#define ADC_MULTIPLIER (2.0F)
|
||||||
|
|
||||||
#define EXT_CHRG_DETECT (35) // P1.3, LOW while charging
|
#define EXT_CHRG_DETECT (35) // P1.3, LOW while charging
|
||||||
|
#define EXT_CHRG_DONE (36) // P1.4, LOW when charge complete
|
||||||
#define EXT_PWR_DETECT (5) // P0.5
|
#define EXT_PWR_DETECT (5) // P0.5
|
||||||
|
|
||||||
#define ADC_RESOLUTION (14)
|
#define ADC_RESOLUTION (14)
|
||||||
|
|||||||
Reference in New Issue
Block a user