mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-19 18:01:30 +10:00
feat: Support Elecrow ThinkNode M9 (#10908)
* thinknode-m9 variant * move lora to SPI1 device * enable SDcard * use HSPI * BaseUI tft -> HSPI * buzzer, webdav lib * fix build issues * M9 default to MUI, no BT, short ringtone * add keyboard long-press config * update variant * add ThingNode-M9 GPS string * GPS 115200 baud * Basic BaseUI support * Fixup power detection * Compass and KB fixes for M9 * add timed Lock::lock() * add SD card * point device-ui to thinknode m9 draft branch * trunk fmt * fix FusionCompass * Fix t-deck-tft linker arg list overflow in CI * SDcard/lora fix: SPI1 must not be declared twice in arduino 3.x -> reuse SPI1 defined in FSCommon.cpp * update battery parameters * reinit SD card when updating; fix PSRAM size * update lib versions * fix wakeup on key press (KB_INT) * fix default nag_timeout for TFT/MUI devices with buzzer * increase PSRAM and SD freq * trunk fmt * update lovyanGFX 1.2.26 * update device-ui commit reference * fix screen definition * remove DONE; maybe a keyword or other used identifier * fixed CI error nag_timeout * fix prepareSleep initialization * trunk fmt * reduce SD SPI frequency * update device-ui * fix SDcard issue * stage * fix device-ui commit reference * fix device-ui commit * update device-ui commit (fixed keyboard lag) * fix QMI8658 * trunk fmt * update .ini meta information, align SD freq * fix device-ui reference to target (ready to merge) * device-ui for all other targets * make the rabbit happy * trunk fmt * fixed lock screen * fix compile error * SPI lock timeout * apply device-ui fix * revert bad RadioLib commit hash in platformio.ini Co-authored-by: mverch67 <71137295+mverch67@users.noreply.github.com> * fix wrong commit hash change * fix fix commit fix * I love changing random numbers in random files --------- Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz> Co-authored-by: Ben Meadors <benmmeadors@gmail.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
Jonathan Bennett
Ben Meadors
copilot-swe-agent[bot]
parent
ef2be877a5
commit
c308d0aca4
@@ -21,6 +21,7 @@
|
||||
#include "LSM6DS3Sensor.h"
|
||||
#include "MPU6050Sensor.h"
|
||||
#include "MotionSensor.h"
|
||||
#include "QMI8658Sensor.h"
|
||||
|
||||
#include <memory>
|
||||
#ifdef HAS_QMA6100P
|
||||
@@ -146,6 +147,11 @@ class AccelerometerThread : public concurrency::OSThread
|
||||
case ScanI2C::DeviceType::QMA6100P:
|
||||
sensor.reset(new QMA6100PSensor(device));
|
||||
break;
|
||||
#endif
|
||||
#if __has_include(<SensorQMI8658.hpp>)
|
||||
case ScanI2C::DeviceType::QMI8658:
|
||||
sensor.reset(new QMI8658Sensor(device));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
disable();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "../concurrency/OSThread.h"
|
||||
#include "MMC5983MASensor.h"
|
||||
#include "MotionSensor.h"
|
||||
#include "QMC6309Sensor.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -73,6 +74,11 @@ class MagnetometerThread : public concurrency::OSThread
|
||||
case ScanI2C::DeviceType::MMC5983MA:
|
||||
sensor.reset(new MMC5983MASensor(device));
|
||||
break;
|
||||
#endif
|
||||
#if __has_include(<SensorQMC6309.hpp>)
|
||||
case ScanI2C::DeviceType::QMC6309:
|
||||
sensor.reset(new QMC6309Sensor(device));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
disable();
|
||||
|
||||
@@ -42,6 +42,9 @@ struct CompassAccelSample {
|
||||
|
||||
concurrency::Lock latestCompassAccelLock;
|
||||
CompassAccelSample latestCompassAccelSample;
|
||||
|
||||
concurrency::Lock latestCompassMagLock;
|
||||
CompassAccelSample latestCompassMagSample;
|
||||
} // namespace
|
||||
|
||||
// screen is defined in main.cpp
|
||||
@@ -245,6 +248,35 @@ bool MotionSensor::getLatestCompassAccelSample(float &x, float &y, float &z, uin
|
||||
return true;
|
||||
}
|
||||
|
||||
void MotionSensor::publishCompassMagSample(float x, float y, float z)
|
||||
{
|
||||
concurrency::LockGuard guard(&latestCompassMagLock);
|
||||
latestCompassMagSample.x = x;
|
||||
latestCompassMagSample.y = y;
|
||||
latestCompassMagSample.z = z;
|
||||
latestCompassMagSample.sampledAtMs = millis();
|
||||
latestCompassMagSample.valid = true;
|
||||
}
|
||||
|
||||
bool MotionSensor::getLatestCompassMagSample(float &x, float &y, float &z, uint32_t &ageMs)
|
||||
{
|
||||
uint32_t sampledAtMs = 0;
|
||||
{
|
||||
concurrency::LockGuard guard(&latestCompassMagLock);
|
||||
if (!latestCompassMagSample.valid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
x = latestCompassMagSample.x;
|
||||
y = latestCompassMagSample.y;
|
||||
z = latestCompassMagSample.z;
|
||||
sampledAtMs = latestCompassMagSample.sampledAtMs;
|
||||
}
|
||||
|
||||
ageMs = millis() - sampledAtMs;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !defined(MESHTASTIC_EXCLUDE_SCREEN) && HAS_SCREEN
|
||||
void MotionSensor::drawFrameCalibration(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
|
||||
@@ -42,6 +42,11 @@ class MotionSensor
|
||||
|
||||
virtual void calibrate(uint16_t forSeconds){};
|
||||
|
||||
// Latest samples published by the compass-fusion drivers (accel from the IMU, mag from the magnetometer).
|
||||
// Public so an optional on-screen sensor debug readout can read them. Return false if nothing published yet.
|
||||
static bool getLatestCompassAccelSample(float &x, float &y, float &z, uint32_t &ageMs);
|
||||
static bool getLatestCompassMagSample(float &x, float &y, float &z, uint32_t &ageMs);
|
||||
|
||||
// True if this sensor produces the compass heading (screen->setHeading()) in runOnce().
|
||||
// Combined accel+magnetometer parts (e.g. BMX160, ICM20948) and standalone magnetometers
|
||||
// handled by the accelerometer thread (e.g. BMM150) override this. Used to avoid halting
|
||||
@@ -74,7 +79,7 @@ class MotionSensor
|
||||
float &lowestY, float &highestZ, float &lowestZ);
|
||||
static float applyCompassOrientation(float heading);
|
||||
static void publishCompassAccelSample(float x, float y, float z);
|
||||
static bool getLatestCompassAccelSample(float &x, float &y, float &z, uint32_t &ageMs);
|
||||
static void publishCompassMagSample(float x, float y, float z);
|
||||
|
||||
ScanI2C::FoundDevice device;
|
||||
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
#include "QMC6309Sensor.h"
|
||||
|
||||
#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && __has_include(<SensorQMC6309.hpp>)
|
||||
|
||||
#include "Fusion/Fusion.h"
|
||||
#include "detect/ScanI2CTwoWire.h"
|
||||
#include <math.h>
|
||||
|
||||
#if !defined(MESHTASTIC_EXCLUDE_SCREEN)
|
||||
extern std::unique_ptr<graphics::Screen> screen;
|
||||
#endif
|
||||
|
||||
static constexpr int32_t QMC6309_UPDATE_INTERVAL_MS = 20;
|
||||
// Heading offset/flip below is a starting point copied from the MMC5983MA path; it is orientation-specific
|
||||
// and must be verified/tuned against known North on real M9 hardware (see plan).
|
||||
static constexpr float QMC6309_HEADING_OFFSET_DEG = 180.0f;
|
||||
static constexpr uint32_t QMC6309_ACCEL_STALE_MS = 300;
|
||||
static constexpr float QMC6309_MIN_AXIS_RADIUS = 1e-4f;
|
||||
|
||||
QMC6309Sensor::QMC6309Sensor(ScanI2C::FoundDevice foundDevice) : MotionSensor::MotionSensor(foundDevice) {}
|
||||
|
||||
bool QMC6309Sensor::init()
|
||||
{
|
||||
LOG_DEBUG("QMC6309 begin on addr 0x%02X (port=%d)", device.address.address, device.address.port);
|
||||
TwoWire *wire = ScanI2CTwoWire::fetchI2CBus(device.address);
|
||||
|
||||
if (!sensor.begin(*wire, deviceAddress())) {
|
||||
LOG_DEBUG("QMC6309 init error");
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor.reset();
|
||||
|
||||
// 8 Gauss full-scale easily covers Earth's ~0.5 G field; OSR_8 for low noise. Tunable.
|
||||
if (!sensor.configMagnetometer(OperationMode::CONTINUOUS_MEASUREMENT, MagFullScaleRange::FS_8G, 100.0f,
|
||||
MagOverSampleRatio::OSR_8)) {
|
||||
LOG_DEBUG("QMC6309 config failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
loadMagnetometerCalibration(compassCalibrationFileName, highestX, lowestX, highestY, lowestY, highestZ, lowestZ);
|
||||
LOG_DEBUG("QMC6309 init ok");
|
||||
LOG_DEBUG("QMC6309 calibration extrema: X=(%.3f, %.3f), Y=(%.3f, %.3f), Z=(%.3f, %.3f)", lowestX, highestX, lowestY, highestY,
|
||||
lowestZ, highestZ);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QMC6309Sensor::readMagnetometer(float &xGauss, float &yGauss, float &zGauss)
|
||||
{
|
||||
MagnetometerData data;
|
||||
if (!sensor.readData(data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// magnetic_field is already scaled to Gauss by the driver.
|
||||
xGauss = data.magnetic_field.x;
|
||||
yGauss = data.magnetic_field.y;
|
||||
zGauss = data.magnetic_field.z;
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t QMC6309Sensor::runOnce()
|
||||
{
|
||||
float magX = 0, magY = 0, magZ = 0;
|
||||
if (!readMagnetometer(magX, magY, magZ)) {
|
||||
return QMC6309_UPDATE_INTERVAL_MS;
|
||||
}
|
||||
|
||||
#if !defined(MESHTASTIC_EXCLUDE_SCREEN)
|
||||
if (doCalibration) {
|
||||
beginCalibrationDisplay(showingScreen);
|
||||
updateCalibrationExtrema(magX, magY, magZ, highestX, lowestX, highestY, lowestY, highestZ, lowestZ);
|
||||
finishCalibrationIfExpired(showingScreen, compassCalibrationFileName, highestX, lowestX, highestY, lowestY, highestZ,
|
||||
lowestZ);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Hard-iron bias removal.
|
||||
magX -= (highestX + lowestX) * 0.5f;
|
||||
magY -= (highestY + lowestY) * 0.5f;
|
||||
magZ -= (highestZ + lowestZ) * 0.5f;
|
||||
// LOG_WARN("QMC6309 extrema=(%.3f, %.3f, %.3f) to (%.3f, %.3f, %.3f)",
|
||||
// lowestX, lowestY, lowestZ, highestX, highestY, highestZ);
|
||||
|
||||
// Soft-iron diagonal scaling from calibration extrema.
|
||||
const float radiusX = (highestX - lowestX) * 0.5f;
|
||||
const float radiusY = (highestY - lowestY) * 0.5f;
|
||||
const float radiusZ = (highestZ - lowestZ) * 0.5f;
|
||||
const float avgRadius = (radiusX + radiusY + radiusZ) / 3.0f;
|
||||
// magX *= (radiusX > QMC6309_MIN_AXIS_RADIUS) ? (avgRadius / radiusX) : 1.0f;
|
||||
// magY *= (radiusY > QMC6309_MIN_AXIS_RADIUS) ? (avgRadius / radiusY) : 1.0f;
|
||||
// magZ *= (radiusZ > QMC6309_MIN_AXIS_RADIUS) ? (avgRadius / radiusZ) : 1.0f;
|
||||
|
||||
// Publish the calibrated magnetometer values (hard/soft-iron applied) for the optional on-screen debug readout.
|
||||
publishCompassMagSample(magX, magY, magZ);
|
||||
|
||||
#if !defined(MESHTASTIC_EXCLUDE_SCREEN) && HAS_SCREEN
|
||||
float heading;
|
||||
float accelX = 0.0f;
|
||||
float accelY = 0.0f;
|
||||
float accelZ = 0.0f;
|
||||
uint32_t accelAgeMs = 0;
|
||||
|
||||
// Fuse with the latest accelerometer sample (published by the QMI8658 driver) for tilt compensation.
|
||||
if (getLatestCompassAccelSample(accelX, accelY, accelZ, accelAgeMs) && accelAgeMs <= QMC6309_ACCEL_STALE_MS) {
|
||||
FusionVector ga = {.axis = {accelX, accelY, accelZ}};
|
||||
FusionVector ma = {.axis = {magX, magY, magZ}};
|
||||
// if (config.display.compass_orientation > meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270) {
|
||||
// ma = FusionAxesSwap(ma, FusionAxesAlignmentNXNYPZ);
|
||||
// ga = FusionAxesSwap(ga, FusionAxesAlignmentNXNYPZ);
|
||||
//}
|
||||
// LOG_WARN("QMC6309 accel age %ums, ga=(%.3f, %.3f, %.3f), ma=(%.3f, %.3f, %.3f)", accelAgeMs, ga.axis.x, ga.axis.y,
|
||||
// ga.axis.z, ma.axis.x, ma.axis.y, ma.axis.z);
|
||||
heading = FusionCompass(ga, ma, FusionConventionNed);
|
||||
if (ga.axis.z > 0.0f)
|
||||
heading = 360.0f - heading;
|
||||
|
||||
} else {
|
||||
heading = atan2f(-magY, magX) * RAD_TO_DEG;
|
||||
}
|
||||
|
||||
if (heading >= 360.0f)
|
||||
heading -= 360.0f;
|
||||
else if (heading < 0.0f)
|
||||
heading += 360.0f;
|
||||
|
||||
heading = applyCompassOrientation(heading);
|
||||
if (screen)
|
||||
screen->setHeading(heading);
|
||||
#endif
|
||||
|
||||
return QMC6309_UPDATE_INTERVAL_MS;
|
||||
}
|
||||
|
||||
void QMC6309Sensor::calibrate(uint16_t forSeconds)
|
||||
{
|
||||
#if !defined(MESHTASTIC_EXCLUDE_SCREEN)
|
||||
float xGauss = 0.0f;
|
||||
float yGauss = 0.0f;
|
||||
float zGauss = 0.0f;
|
||||
|
||||
LOG_DEBUG("QMC6309 calibration started for %is", forSeconds);
|
||||
if (readMagnetometer(xGauss, yGauss, zGauss)) {
|
||||
seedCalibrationExtrema(xGauss, yGauss, zGauss, highestX, lowestX, highestY, lowestY, highestZ, lowestZ);
|
||||
} else {
|
||||
seedCalibrationExtrema(0.0f, 0.0f, 0.0f, highestX, lowestX, highestY, lowestY, highestZ, lowestZ);
|
||||
}
|
||||
startCalibrationWindow(forSeconds);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
#ifndef _QMC6309_SENSOR_H_
|
||||
#define _QMC6309_SENSOR_H_
|
||||
|
||||
#include "MotionSensor.h"
|
||||
|
||||
#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && __has_include(<SensorQMC6309.hpp>)
|
||||
|
||||
// SensorQMC6309.hpp (SensorLib 0.4.1) references the isBitSet() macro in an inline method but never includes
|
||||
// SensorLib.h where it is defined. Define it here (guarded) so the header compiles regardless of include order
|
||||
// (pulling in SensorLib.h is unreliable - its #pragma once can already be tripped by an in-progress include).
|
||||
#ifndef isBitSet
|
||||
#define isBitSet(value, bit) (((value) & (1UL << (bit))) == (1UL << (bit)))
|
||||
#endif
|
||||
#include <SensorQMC6309.hpp>
|
||||
|
||||
class QMC6309Sensor : public MotionSensor
|
||||
{
|
||||
private:
|
||||
SensorQMC6309 sensor;
|
||||
bool showingScreen = false;
|
||||
static constexpr const char *compassCalibrationFileName = "/prefs/compass_qmc6309.dat";
|
||||
#ifdef ELECROW_ThinkNode_M9
|
||||
float highestX = -5.548, lowestX = -6.530, highestY = -6.638, lowestY = -7.637, highestZ = -6.676, lowestZ = -7.633;
|
||||
#else
|
||||
float highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0;
|
||||
#endif
|
||||
|
||||
bool readMagnetometer(float &xGauss, float &yGauss, float &zGauss);
|
||||
|
||||
public:
|
||||
explicit QMC6309Sensor(ScanI2C::FoundDevice foundDevice);
|
||||
virtual bool init() override;
|
||||
virtual int32_t runOnce() override;
|
||||
virtual void calibrate(uint16_t forSeconds) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "QMI8658Sensor.h"
|
||||
|
||||
#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && __has_include(<SensorQMI8658.hpp>)
|
||||
|
||||
#include "NodeDB.h"
|
||||
#include "detect/ScanI2CTwoWire.h"
|
||||
#include <math.h>
|
||||
|
||||
// Accelerometer configuration. 2G full-scale gives the best gravity resolution for the tilt
|
||||
// compensation that the (future) separate compass module will apply to these samples.
|
||||
static constexpr SensorQMI8658::AccelRange QMI8658_ACCEL_RANGE = SensorQMI8658::ACC_RANGE_2G;
|
||||
static constexpr SensorQMI8658::AccelODR QMI8658_ACCEL_ODR = SensorQMI8658::ACC_ODR_125Hz;
|
||||
|
||||
// Any-motion slope threshold (in mg) used to wake the screen. Tunable: raise to reduce false wakes,
|
||||
// lower to make it more sensitive. 200mg (~0.2g) requires a deliberate movement.
|
||||
static constexpr float QMI8658_ANY_MOTION_THRESHOLD_MG = 200.0f;
|
||||
static constexpr uint8_t QMI8658_ANY_MOTION_WINDOW = 1;
|
||||
|
||||
// Optional board-defined rotation (degrees) applied to the accel X/Y before publishing to the compass
|
||||
// fusion path, mirroring the ICM42607P driver. Defaults to no rotation.
|
||||
static constexpr float QMI8658_ACCEL_TO_COMPASS_ROTATION_DEG_VALUE =
|
||||
#ifdef QMI8658_ACCEL_TO_COMPASS_ROTATION_DEG
|
||||
QMI8658_ACCEL_TO_COMPASS_ROTATION_DEG;
|
||||
#else
|
||||
0.0f;
|
||||
#endif
|
||||
|
||||
QMI8658Sensor::QMI8658Sensor(ScanI2C::FoundDevice foundDevice) : MotionSensor::MotionSensor(foundDevice) {}
|
||||
|
||||
bool QMI8658Sensor::init()
|
||||
{
|
||||
LOG_DEBUG("QMI8658 begin on addr 0x%02X (port=%d)", deviceAddress(), devicePort());
|
||||
TwoWire *wire = ScanI2CTwoWire::fetchI2CBus(device.address);
|
||||
|
||||
if (!sensor.begin(*wire, deviceAddress())) {
|
||||
LOG_DEBUG("QMI8658 init failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor.configAccelerometer(QMI8658_ACCEL_RANGE, QMI8658_ACCEL_ODR, SensorQMI8658::LPF_MODE_0);
|
||||
sensor.enableAccelerometer();
|
||||
|
||||
// Configure the on-chip any-motion engine so we can wake the screen without a dedicated interrupt pin.
|
||||
// configMotion() runs alongside normal accel data output (unlike Wake-on-Motion, which halts data), so
|
||||
// we keep publishing samples for compass fusion while still detecting motion.
|
||||
wakeOnMotion = config.display.wake_on_tap_or_motion;
|
||||
if (wakeOnMotion) {
|
||||
const uint8_t modeCtrl = SensorQMI8658::ANY_MOTION_EN_X | SensorQMI8658::ANY_MOTION_EN_Y | SensorQMI8658::ANY_MOTION_EN_Z;
|
||||
// No-motion detection is left disabled (unreliable per the SensorLib example); its thresholds/windows
|
||||
// are still required arguments but are ignored when the mode bits above are clear.
|
||||
sensor.configMotion(modeCtrl, QMI8658_ANY_MOTION_THRESHOLD_MG, QMI8658_ANY_MOTION_THRESHOLD_MG,
|
||||
QMI8658_ANY_MOTION_THRESHOLD_MG, QMI8658_ANY_MOTION_WINDOW, /*NoMotion X/Y/Z*/ 0.1f, 0.1f, 0.1f,
|
||||
/*NoMotionWindow*/ 1, /*SigMotionWaitWindow*/ 1, /*SigMotionConfirmWindow*/ 1);
|
||||
sensor.enableMotionDetect();
|
||||
}
|
||||
|
||||
LOG_DEBUG("QMI8658 init ok");
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t QMI8658Sensor::runOnce()
|
||||
{
|
||||
float ax, ay, az;
|
||||
if (sensor.getAccelerometer(ax, ay, az)) {
|
||||
if (QMI8658_ACCEL_TO_COMPASS_ROTATION_DEG_VALUE != 0.0f) {
|
||||
static const float rotRad = QMI8658_ACCEL_TO_COMPASS_ROTATION_DEG_VALUE * DEG_TO_RAD;
|
||||
static const float cosTheta = cosf(rotRad);
|
||||
static const float sinTheta = sinf(rotRad);
|
||||
const float rotatedX = (ax * cosTheta) - (ay * sinTheta);
|
||||
const float rotatedY = (ax * sinTheta) + (ay * cosTheta);
|
||||
ax = rotatedX;
|
||||
ay = rotatedY;
|
||||
}
|
||||
|
||||
// Match the accel sign convention used by the other FusionCompass sensor paths (e.g. ICM42607P).
|
||||
// The final handedness must be verified against the QMI8658 datasheet and real calibration once the
|
||||
// separate compass module is wired up; do not hand-tune the signs before then.
|
||||
publishCompassAccelSample(ax, ay, az);
|
||||
}
|
||||
|
||||
if (wakeOnMotion && (sensor.getStatusRegister() & SensorQMI8658::EVENT_ANY_MOTION)) {
|
||||
wakeScreen();
|
||||
}
|
||||
|
||||
return MOTION_SENSOR_CHECK_INTERVAL_MS;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#ifndef _QMI8658_SENSOR_H_
|
||||
#define _QMI8658_SENSOR_H_
|
||||
|
||||
#include "MotionSensor.h"
|
||||
|
||||
#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && __has_include(<SensorQMI8658.hpp>)
|
||||
|
||||
#include <SensorQMI8658.hpp>
|
||||
|
||||
class QMI8658Sensor : public MotionSensor
|
||||
{
|
||||
private:
|
||||
SensorQMI8658 sensor;
|
||||
bool wakeOnMotion = false;
|
||||
|
||||
public:
|
||||
explicit QMI8658Sensor(ScanI2C::FoundDevice foundDevice);
|
||||
virtual bool init() override;
|
||||
virtual int32_t runOnce() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user