diff --git a/platformio.ini b/platformio.ini index b54274a46..aaebceedc 100644 --- a/platformio.ini +++ b/platformio.ini @@ -111,3 +111,5 @@ lib_deps = adafruit/Adafruit LPS2X@^2.0.4 adafruit/Adafruit SHT31 Library@^2.2.0 adafruit/Adafruit PM25 AQI Sensor@^1.0.6 + adafruit/Adafruit MPU6050@^2.2.4 + adafruit/Adafruit LIS3DH@^1.2.4 diff --git a/protobufs b/protobufs index e3e22cdee..9c9fe890c 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit e3e22cdee6024663031fa2d87afd98a88adc2685 +Subproject commit 9c9fe890ce55ad9f3f5f6dae28fda629a5cc25bb diff --git a/src/AccelerometerThread.h b/src/AccelerometerThread.h new file mode 100644 index 000000000..94129630d --- /dev/null +++ b/src/AccelerometerThread.h @@ -0,0 +1,67 @@ +#include "PowerFSM.h" +#include "concurrency/OSThread.h" +#include "configuration.h" +#include "main.h" +#include "power.h" + +#include +#include + +namespace concurrency +{ +class AccelerometerThread : public concurrency::OSThread +{ + public: + AccelerometerThread(ScanI2C::DeviceType type = ScanI2C::DeviceType::NONE) : OSThread("AccelerometerThread") + { + if (accelerometer_found.port == ScanI2C::I2CPort::NO_I2C || !config.display.wake_on_tap_or_motion) { + disable(); + return; + } + accleremoter_type = type; + LOG_DEBUG("AccelerometerThread initializing\n"); + + if (accleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.begin(accelerometer_found.address)) { + LOG_DEBUG("MPU6050 initializing\n"); + // setup motion detection + mpu.setHighPassFilter(MPU6050_HIGHPASS_0_63_HZ); + mpu.setMotionDetectionThreshold(1); + mpu.setMotionDetectionDuration(20); + mpu.setInterruptPinLatch(true); // Keep it latched. Will turn off when reinitialized. + mpu.setInterruptPinPolarity(true); + } else if (accleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.begin(accelerometer_found.address)) { + LOG_DEBUG("LIS3DH initializing\n"); + lis.setRange(LIS3DH_RANGE_2_G); + + // Adjust threshhold, higher numbers are less sensitive + lis.setClick(1, 80); + } + } + + protected: + int32_t runOnce() override + { + canSleep = true; // Assume we should not keep the board awake + + if (accleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.getMotionInterruptStatus()) { + wakeScreen(); + } else if (accleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.getClick() > 0) { + wakeScreen(); + } + return 100; + } + + private: + void wakeScreen() + { + LOG_DEBUG("Tap or motion detected. Turning on screen\n"); + if (powerFSM.getState() == &stateDARK) { + powerFSM.trigger(EVENT_INPUT); + } + } + ScanI2C::DeviceType accleremoter_type; + Adafruit_MPU6050 mpu; + Adafruit_LIS3DH lis; +}; + +} // namespace concurrency diff --git a/src/PowerFSM.h b/src/PowerFSM.h index 6692172f4..116468121 100644 --- a/src/PowerFSM.h +++ b/src/PowerFSM.h @@ -23,6 +23,6 @@ #define EVENT_INPUT 17 // input broker wants something, we need to wake up and enable screen extern Fsm powerFSM; -extern State statePOWER, stateSERIAL; +extern State stateON, statePOWER, stateSERIAL, stateDARK; void PowerFSM_setup(); diff --git a/src/configuration.h b/src/configuration.h index f35fff4e0..58e41877d 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -82,7 +82,7 @@ along with this program. If not, see . // #define DISABLE_NTP // Disable the welcome screen and allow -//#define DISABLE_WELCOME_UNSET +// #define DISABLE_WELCOME_UNSET // ----------------------------------------------------------------------------- // OLED & Input @@ -93,7 +93,7 @@ along with this program. If not, see . // The SH1106 controller is almost, but not quite, the same as SSD1306 // Define this if you know you have that controller or your "SSD1306" misbehaves. -//#define USE_SH1106 +// #define USE_SH1106 // Define if screen should be mirrored left to right // #define SCREEN_MIRROR @@ -118,6 +118,12 @@ along with this program. If not, see . #define SHT31_ADDR 0x44 #define PMSA0031_ADDR 0x12 +// ----------------------------------------------------------------------------- +// ACCELEROMETER +// ----------------------------------------------------------------------------- +#define MPU6050_ADDR 0x68 +#define LIS3DH_ADR 0x18 + // ----------------------------------------------------------------------------- // Security // ----------------------------------------------------------------------------- diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index e72478c17..4ce848612 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -34,6 +34,12 @@ ScanI2C::FoundDevice ScanI2C::firstKeyboard() const return firstOfOrNONE(2, types); } +ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const +{ + ScanI2C::DeviceType types[] = {MPU6050, LIS3DH}; + return firstOfOrNONE(2, types); +} + ScanI2C::FoundDevice ScanI2C::find(ScanI2C::DeviceType) const { return DEVICE_NONE; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 0e7e442b1..01b300c10 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -31,6 +31,8 @@ class ScanI2C QMI8658, QMC5883L, PMSA0031, + MPU6050, + LIS3DH, } DeviceType; // typedef uint8_t DeviceAddress; @@ -79,6 +81,8 @@ class ScanI2C FoundDevice firstKeyboard() const; + FoundDevice firstAccelerometer() const; + virtual FoundDevice find(DeviceType) const; virtual bool exists(DeviceType) const; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 53e4dca5b..fb568b552 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -248,7 +248,17 @@ void ScanI2CTwoWire::scanPort(I2CPort port) } break; - SCAN_SIMPLE_CASE(MCP9808_ADDR, MCP9808, "MCP9808 sensor found\n") + case MCP9808_ADDR: + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2); + if (registerValue == 0x0400) { + type = MCP9808; + LOG_INFO("MCP9808 sensor found\n"); + } else { + type = LIS3DH; + LOG_INFO("LIS3DH accelerometer found\n"); + } + + break; SCAN_SIMPLE_CASE(SHT31_ADDR, SHT31, "SHT31 sensor found\n") SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3 sensor found\n") @@ -261,11 +271,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port) SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L Highrate 3-Axis magnetic sensor found\n") SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031 air quality sensor found\n") + SCAN_SIMPLE_CASE(MPU6050_ADDR, MPU6050, "MPU6050 accelerometer found\n"); default: LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address); } - } else if (err == 4) { LOG_ERROR("Unknown error at address 0x%x\n", addr); } diff --git a/src/main.cpp b/src/main.cpp index aca540323..9e657e7ee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -68,6 +68,10 @@ NRF52Bluetooth *nrf52Bluetooth; #endif #include "PowerFSMThread.h" +#if !defined(ARCH_PORTDUINO) +#include "AccelerometerThread.h" +#endif + using namespace concurrency; // We always create a screen object, but we only init it if we find the hardware @@ -94,6 +98,8 @@ uint8_t kb_model; // The I2C address of the RTC Module (if found) ScanI2C::DeviceAddress rtc_found = ScanI2C::ADDRESS_NONE; +// The I2C address of the Accelerometer (if found) +ScanI2C::DeviceAddress accelerometer_found = ScanI2C::ADDRESS_NONE; #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) ATECCX08A atecc; @@ -163,6 +169,7 @@ static OSThread *powerFSMthread; static OSThread *buttonThread; uint32_t ButtonThread::longPressTime = 0; #endif +static OSThread *accelerometerThread; RadioInterface *rIf = NULL; @@ -350,6 +357,15 @@ void setup() * nodeTelemetrySensorsMap singleton. This wraps that logic in a temporary scope to declare the temporary field * "found". */ +#if !defined(ARCH_PORTDUINO) + auto acc_info = i2cScanner->firstAccelerometer(); + accelerometer_found = acc_info.type != ScanI2C::DeviceType::NONE ? acc_info.address : accelerometer_found; + + LOG_DEBUG("acc_info = %i\n", acc_info.type); + if (acc_info.type != ScanI2C::DeviceType::NONE) { + accelerometerThread = new AccelerometerThread(acc_info.type); + } +#endif #define STRING(S) #S @@ -459,14 +475,14 @@ void setup() // Now that the mesh service is created, create any modules setupModules(); - // Do this after service.init (because that clears error_code) +// Do this after service.init (because that clears error_code) #ifdef HAS_PMU if (!pmu_found) RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_NO_AXP192); // Record a hardware fault for missing hardware #endif - // Don't call screen setup until after nodedb is setup (because we need - // the current region name) +// Don't call screen setup until after nodedb is setup (because we need +// the current region name) #if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) screen->setup(); #else diff --git a/src/main.h b/src/main.h index 29fe34f7f..db5fc26d8 100644 --- a/src/main.h +++ b/src/main.h @@ -24,6 +24,7 @@ extern ScanI2C::DeviceAddress screen_found; extern ScanI2C::DeviceAddress cardkb_found; extern uint8_t kb_model; extern ScanI2C::DeviceAddress rtc_found; +extern ScanI2C::DeviceAddress accelerometer_found; extern bool eink_found; extern bool pmu_found; diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 0b2aff4d8..fd949cde9 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -360,6 +360,8 @@ typedef struct _meshtastic_Config_DisplayConfig { meshtastic_Config_DisplayConfig_DisplayMode displaymode; /* Print first line in pseudo-bold? FALSE is original style, TRUE is bold */ bool heading_bold; + /* Should we wake the screen up on accelerometer detected motion or tap */ + bool wake_on_tap_or_motion; } meshtastic_Config_DisplayConfig; /* Lora Config */ @@ -526,7 +528,7 @@ extern "C" { #define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0} -#define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0} +#define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0} #define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}} #define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} #define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}} @@ -535,7 +537,7 @@ extern "C" { #define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0} -#define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0} +#define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0} #define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}} #define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} @@ -585,6 +587,7 @@ extern "C" { #define meshtastic_Config_DisplayConfig_oled_tag 7 #define meshtastic_Config_DisplayConfig_displaymode_tag 8 #define meshtastic_Config_DisplayConfig_heading_bold_tag 9 +#define meshtastic_Config_DisplayConfig_wake_on_tap_or_motion_tag 10 #define meshtastic_Config_LoRaConfig_use_preset_tag 1 #define meshtastic_Config_LoRaConfig_modem_preset_tag 2 #define meshtastic_Config_LoRaConfig_bandwidth_tag 3 @@ -696,7 +699,8 @@ X(a, STATIC, SINGULAR, BOOL, flip_screen, 5) \ X(a, STATIC, SINGULAR, UENUM, units, 6) \ X(a, STATIC, SINGULAR, UENUM, oled, 7) \ X(a, STATIC, SINGULAR, UENUM, displaymode, 8) \ -X(a, STATIC, SINGULAR, BOOL, heading_bold, 9) +X(a, STATIC, SINGULAR, BOOL, heading_bold, 9) \ +X(a, STATIC, SINGULAR, BOOL, wake_on_tap_or_motion, 10) #define meshtastic_Config_DisplayConfig_CALLBACK NULL #define meshtastic_Config_DisplayConfig_DEFAULT NULL @@ -750,7 +754,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg; /* Maximum encoded size of messages (where known) */ #define meshtastic_Config_BluetoothConfig_size 10 #define meshtastic_Config_DeviceConfig_size 26 -#define meshtastic_Config_DisplayConfig_size 26 +#define meshtastic_Config_DisplayConfig_size 28 #define meshtastic_Config_LoRaConfig_size 77 #define meshtastic_Config_NetworkConfig_IpV4Config_size 20 #define meshtastic_Config_NetworkConfig_size 195 diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 043c1b8a0..e0d708400 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -188,7 +188,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg; /* Maximum encoded size of messages (where known) */ #define meshtastic_ChannelFile_size 638 #define meshtastic_DeviceState_size 21800 -#define meshtastic_OEMStore_size 3006 +#define meshtastic_OEMStore_size 3008 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index 6aa0fdbeb..41d6d70aa 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -156,7 +156,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; #define meshtastic_LocalModuleConfig_fields &meshtastic_LocalModuleConfig_msg /* Maximum encoded size of messages (where known) */ -#define meshtastic_LocalConfig_size 440 +#define meshtastic_LocalConfig_size 442 #define meshtastic_LocalModuleConfig_size 420 #ifdef __cplusplus