Seeed Tracker X1 Support (#10834)
* Seeed Tracker X1 Support * silence CPPCheck * fix macro order regression and adapt stm32hal for new radiolib * STM32 is a radiolib upstream fix ( https://github.com/jgromes/RadioLib/issues/1825 ) * fix STM32 regression * Seeed Tracker X1 Support * silence CPPCheck * fix macro order regression and adapt stm32hal for new radiolib * STM32 is a radiolib upstream fix ( https://github.com/jgromes/RadioLib/issues/1825 ) * fix STM32 regression * address copilot OCD * Split behavior only when the two LEDs are on distinct pins. * bring naming in line with the other seeed devices * update env name to fit convention too * guarantee evaluation order * Guard sensor readings against null values, make sensor use less power
This commit is contained in:
co-authored by
GitHub
parent
3becaf2d95
commit
7509c1a6dd
@@ -101,6 +101,7 @@ class ScanI2C
|
||||
ADS1115,
|
||||
IIS2MDCTR,
|
||||
ISM330DHCX,
|
||||
SPA06,
|
||||
} DeviceType;
|
||||
|
||||
// typedef uint8_t DeviceAddress;
|
||||
|
||||
@@ -441,8 +441,12 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
logFoundDevice("DPS310", (uint8_t)addr.address);
|
||||
type = DPS310;
|
||||
break;
|
||||
case 0x11:
|
||||
logFoundDevice("SPA06-003", (uint8_t)addr.address);
|
||||
type = SPA06;
|
||||
break;
|
||||
}
|
||||
if (type == DPS310) {
|
||||
if (type == DPS310 || type == SPA06) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -874,6 +874,17 @@ void setup()
|
||||
delay(10);
|
||||
#endif
|
||||
drv.begin();
|
||||
|
||||
// Bits Field Value Meaning
|
||||
// 7 N_ERM_LRA 1 LRA mode (vs 0 = ERM)
|
||||
// 6:4 FB_BRAKE_FACTOR 3 4× brake factor
|
||||
// 3:2 LOOP_GAIN 1 medium loop gain
|
||||
// 1:0 BEMF_GAIN 2 back-EMF gain
|
||||
|
||||
#if defined(DRV2605_USE_LRA)
|
||||
drv.writeRegister8(DRV2605_REG_FEEDBACK, 0xB6);
|
||||
#endif
|
||||
|
||||
drv.selectLibrary(1);
|
||||
// I2C trigger by sending 'go' command
|
||||
drv.setMode(DRV2605_MODE_INTTRIG);
|
||||
|
||||
@@ -127,7 +127,10 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
#endif
|
||||
|
||||
#ifdef HAS_DRV2605
|
||||
drv.go();
|
||||
// Only trigger DRV2605 if vibration alerts are enabled
|
||||
if (moduleConfig.external_notification.alert_message_vibra || moduleConfig.external_notification.alert_bell_vibra) {
|
||||
drv.go();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -144,7 +147,7 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
}
|
||||
#endif
|
||||
// now let the PWM buzzer play
|
||||
if (moduleConfig.external_notification.use_pwm && config.device.buzzer_gpio && canBuzz()) {
|
||||
if (moduleConfig.external_notification.use_pwm && config.device.buzzer_gpio && canBuzz() && buzzerShouldAlert) {
|
||||
if (rtttl::isPlaying()) {
|
||||
rtttl::play();
|
||||
} else if (isNagging && (nagCycleCutoff >= millis())) {
|
||||
@@ -225,9 +228,18 @@ void ExternalNotificationModule::setExternalState(uint8_t index, bool on)
|
||||
#endif
|
||||
|
||||
#ifdef HAS_DRV2605
|
||||
// Only trigger DRV2605 when setting vibration motor
|
||||
bool shouldTriggerDRV = false;
|
||||
if (on) {
|
||||
if (index == 1 &&
|
||||
(moduleConfig.external_notification.alert_message_vibra || moduleConfig.external_notification.alert_bell_vibra)) {
|
||||
shouldTriggerDRV = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldTriggerDRV) {
|
||||
drv.go();
|
||||
} else {
|
||||
} else if (!on && index == 1) {
|
||||
drv.stop();
|
||||
}
|
||||
#endif
|
||||
@@ -266,6 +278,7 @@ void ExternalNotificationModule::stopNow()
|
||||
|
||||
// Prevent the state machine from immediately re-triggering outputs after a manual stop.
|
||||
isNagging = false;
|
||||
buzzerShouldAlert = false;
|
||||
nagCycleCutoff = UINT32_MAX;
|
||||
|
||||
#ifdef HAS_I2S
|
||||
@@ -404,8 +417,10 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
||||
|
||||
// Alert GPIO Buzzer when receiving a bell = alertBellBuzzer: true
|
||||
// Alert GPIO Buzzer when receiving a message = alertMessageBuzzer: true
|
||||
const bool buzzerShouldAlert = canBuzz() && ((moduleConfig.external_notification.alert_bell_buzzer && containsBell) ||
|
||||
(moduleConfig.external_notification.alert_message_buzzer && !is_muted));
|
||||
// If you are already buzzing, keep going
|
||||
buzzerShouldAlert =
|
||||
buzzerShouldAlert || (canBuzz() && ((moduleConfig.external_notification.alert_bell_buzzer && containsBell) ||
|
||||
(moduleConfig.external_notification.alert_message_buzzer && !is_muted)));
|
||||
|
||||
if (genericShouldAlert || vibraShouldAlert || buzzerShouldAlert) {
|
||||
nagCycleCutoff = millis() + (moduleConfig.external_notification.nag_timeout
|
||||
@@ -422,6 +437,18 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
||||
|
||||
if (vibraShouldAlert) {
|
||||
LOG_INFO("externalNotificationModule - Vibra alert");
|
||||
#ifdef HAS_DRV2605
|
||||
// Set DRV2605 waveform when vibration alert is triggered
|
||||
drv.setWaveform(0, 16); // Long buzzer 100%
|
||||
drv.setWaveform(1, 0); // Pause
|
||||
drv.setWaveform(2, 16);
|
||||
drv.setWaveform(3, 0);
|
||||
drv.setWaveform(4, 16);
|
||||
drv.setWaveform(5, 0);
|
||||
drv.setWaveform(6, 16);
|
||||
drv.setWaveform(7, 0);
|
||||
drv.go();
|
||||
#endif
|
||||
setExternalState(1, true);
|
||||
}
|
||||
|
||||
@@ -431,18 +458,6 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
||||
LOG_INFO("Message buzzer was suppressed because buzzer mode DIRECT_MSG_ONLY");
|
||||
} else {
|
||||
// Buzz if buzzer mode is not in DIRECT_MSG_ONLY or is DM to us
|
||||
#ifdef HAS_DRV2605
|
||||
drv.setWaveform(0, 16); // Long buzzer 100%
|
||||
drv.setWaveform(1, 0); // Pause
|
||||
drv.setWaveform(2, 16);
|
||||
drv.setWaveform(3, 0);
|
||||
drv.setWaveform(4, 16);
|
||||
drv.setWaveform(5, 0);
|
||||
drv.setWaveform(6, 16);
|
||||
drv.setWaveform(7, 0);
|
||||
drv.go();
|
||||
#endif
|
||||
|
||||
if (moduleConfig.external_notification.use_i2s_as_buzzer) {
|
||||
#ifdef HAS_I2S
|
||||
audioThread->beginRttl(rtttlConfig.ringtone, strlen_P(rtttlConfig.ringtone));
|
||||
|
||||
@@ -90,6 +90,7 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
|
||||
bool isNagging = false;
|
||||
|
||||
bool isSilenced = false;
|
||||
bool buzzerShouldAlert = false;
|
||||
|
||||
virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
|
||||
meshtastic_AdminMessage *request,
|
||||
|
||||
@@ -215,9 +215,25 @@ int32_t StatusLEDModule::runOnce()
|
||||
#ifdef PCA_LED_ENABLE
|
||||
io.digitalWrite(PCA_LED_ENABLE, CHARGE_LED_state);
|
||||
#endif
|
||||
|
||||
#ifdef LED_POWER
|
||||
#ifdef LED_POWER_CRITICAL
|
||||
if (LED_POWER != LED_POWER_CRITICAL) {
|
||||
if (power_state == critical) {
|
||||
digitalWrite(LED_POWER, 0);
|
||||
digitalWrite(LED_POWER_CRITICAL, CHARGE_LED_state);
|
||||
} else {
|
||||
digitalWrite(LED_POWER, CHARGE_LED_state);
|
||||
digitalWrite(LED_POWER_CRITICAL, 0);
|
||||
}
|
||||
} else {
|
||||
digitalWrite(LED_POWER, CHARGE_LED_state);
|
||||
}
|
||||
#else
|
||||
digitalWrite(LED_POWER, CHARGE_LED_state);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef LED_PAIRING
|
||||
digitalWrite(LED_PAIRING, PAIRING_LED_state);
|
||||
#endif
|
||||
|
||||
@@ -119,6 +119,10 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c
|
||||
#include "Sensor/T1000xSensor.h"
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_SPA06_003.h>)
|
||||
#include "Sensor/SPA06Sensor.h"
|
||||
#endif
|
||||
|
||||
#ifdef SENSECAP_INDICATOR
|
||||
#include "Sensor/IndicatorSensor.h"
|
||||
#endif
|
||||
@@ -167,12 +171,15 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
|
||||
// Not a real I2C device, uses UART
|
||||
addSensor<IndicatorSensor>(i2cScanner, ScanI2C::DeviceType::NONE);
|
||||
#endif
|
||||
addSensor<RCWL9620Sensor>(i2cScanner, ScanI2C::DeviceType::RCWL9620);
|
||||
addSensor<CGRadSensSensor>(i2cScanner, ScanI2C::DeviceType::CGRADSENS);
|
||||
#if HAS_SPA06 && __has_include(<Adafruit_SPA06_003.h>)
|
||||
addSensor<SPA06Sensor>(i2cScanner, ScanI2C::DeviceType::SPA06);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
|
||||
addSensor<RCWL9620Sensor>(i2cScanner, ScanI2C::DeviceType::RCWL9620);
|
||||
addSensor<CGRadSensSensor>(i2cScanner, ScanI2C::DeviceType::CGRADSENS);
|
||||
#if __has_include(<DFRobot_LarkWeatherStation.h>)
|
||||
addSensor<DFRobotLarkSensor>(i2cScanner, ScanI2C::DeviceType::DFROBOT_LARK);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_SPA06_003.h>)
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "SPA06Sensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_SPA06_003.h>
|
||||
|
||||
SPA06Sensor::SPA06Sensor()
|
||||
: TelemetrySensor(meshtastic_TelemetrySensorType_SPA06, "SPA06"), spa_temp(nullptr), spa_pressure(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
bool SPA06Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
status = spa06.begin(dev->address.address, bus);
|
||||
if (!status) {
|
||||
return status;
|
||||
}
|
||||
// Set moderate precision for faster sampling
|
||||
spa06.setPressureOversampling(SPA06_003_OVERSAMPLE_8); // 8x oversampling
|
||||
spa06.setTemperatureOversampling(SPA06_003_OVERSAMPLE_8); // 8x oversampling
|
||||
|
||||
// Set measurement rate. 1 Hz is ample for telemetry (polled every tens of seconds)
|
||||
// and draws far less power than 32 Hz, while staying in continuous mode so getMetrics()
|
||||
// remains non-blocking (fresh data always available).
|
||||
spa06.setPressureMeasureRate(SPA06_003_RATE_1); // 1 Hz
|
||||
spa06.setTemperatureMeasureRate(SPA06_003_RATE_1); // 1 Hz
|
||||
spa06.setMeasurementMode(SPA06_003_MEAS_CONTINUOUS_BOTH);
|
||||
|
||||
spa_temp = spa06.getTemperatureSensor();
|
||||
spa_pressure = spa06.getPressureSensor();
|
||||
|
||||
initI2CSensor();
|
||||
return status;
|
||||
}
|
||||
|
||||
bool SPA06Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
if (!spa_temp || !spa_pressure) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sensors_event_t temp, press;
|
||||
|
||||
if (!spa_temp->getEvent(&temp) || !spa_pressure->getEvent(&press)) {
|
||||
LOG_DEBUG("SPA06 getEvents no data");
|
||||
return false;
|
||||
}
|
||||
|
||||
measurement->variant.environment_metrics.has_temperature = true;
|
||||
measurement->variant.environment_metrics.has_barometric_pressure = true;
|
||||
measurement->variant.environment_metrics.temperature = temp.temperature;
|
||||
measurement->variant.environment_metrics.barometric_pressure = press.pressure;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_SPA06_003.h>)
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_SPA06_003.h>
|
||||
|
||||
class SPA06Sensor : public TelemetrySensor
|
||||
{
|
||||
private:
|
||||
Adafruit_SPA06_003 spa06;
|
||||
Adafruit_Sensor *spa_temp;
|
||||
Adafruit_Sensor *spa_pressure;
|
||||
|
||||
public:
|
||||
SPA06Sensor();
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -113,6 +113,8 @@
|
||||
#define HW_VENDOR meshtastic_HardwareModel_WIO_WM1110
|
||||
#elif defined(TRACKER_T1000_E)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_TRACKER_T1000_E
|
||||
#elif defined(MESH_TRACKER_X1)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_MESH_TRACKER_X1
|
||||
#elif defined(ME25LS01_4Y10TD)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_ME25LS01_4Y10TD
|
||||
#elif defined(MS24SF1)
|
||||
|
||||
+7
-1
@@ -266,20 +266,26 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false, bool skipSaveN
|
||||
digitalWrite(SDCARD_CS, LOW);
|
||||
#endif
|
||||
|
||||
#ifdef TRACKER_T1000_E
|
||||
#if defined(TRACKER_T1000_E) || defined(MESH_TRACKER_X1)
|
||||
#ifdef GNSS_AIROHA
|
||||
digitalWrite(GPS_VRTC_EN, LOW);
|
||||
digitalWrite(PIN_GPS_RESET, LOW);
|
||||
digitalWrite(GPS_SLEEP_INT, LOW);
|
||||
digitalWrite(GPS_RTC_INT, LOW);
|
||||
#ifdef GPS_RESETB_OUT
|
||||
pinMode(GPS_RESETB_OUT, OUTPUT);
|
||||
digitalWrite(GPS_RESETB_OUT, LOW);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BUZZER_EN_PIN
|
||||
digitalWrite(BUZZER_EN_PIN, LOW);
|
||||
#endif
|
||||
|
||||
#ifdef PIN_DRV_EN
|
||||
digitalWrite(PIN_DRV_EN, LOW);
|
||||
#endif
|
||||
|
||||
#ifdef PIN_3V3_EN
|
||||
digitalWrite(PIN_3V3_EN, LOW);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user