diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini index 3b0f5ab64..6af3a7717 100644 --- a/arch/portduino/portduino.ini +++ b/arch/portduino/portduino.ini @@ -24,7 +24,6 @@ lib_deps = ${networking_base.lib_deps} ${radiolib_base.lib_deps} ${environmental_base.lib_deps} - ${environmental_base.lib_deps} # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto rweather/Crypto@^0.4.0 # renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX @@ -49,4 +48,4 @@ build_flags = -std=gnu17 -std=c++17 -lib_ignore = Adafruit NeoPixel \ No newline at end of file +lib_ignore = Adafruit NeoPixel diff --git a/src/motion/ICM20948Sensor.cpp b/src/motion/ICM20948Sensor.cpp index 946390ddb..293e06648 100755 --- a/src/motion/ICM20948Sensor.cpp +++ b/src/motion/ICM20948Sensor.cpp @@ -1,6 +1,11 @@ #include "ICM20948Sensor.h" #if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && __has_include() +#if !defined(MESHTASTIC_EXCLUDE_SCREEN) + +// screen is defined in main.cpp +extern graphics::Screen *screen; +#endif // Flag when an interrupt has been detected volatile static bool ICM20948_IRQ = false; @@ -41,6 +46,90 @@ int32_t ICM20948Sensor::runOnce() int32_t ICM20948Sensor::runOnce() { +#if !defined(MESHTASTIC_EXCLUDE_SCREEN) + float magX = 0, magY = 0, magZ = 0; + if (sensor->dataReady()) { + sensor->getAGMT(); + magX = sensor->agmt.mag.axes.x; + magY = sensor->agmt.mag.axes.y; + magZ = sensor->agmt.mag.axes.z; + } + + if (doCalibration) { + + if (!showingScreen) { + powerFSM.trigger(EVENT_PRESS); // keep screen alive during calibration + showingScreen = true; + screen->startAlert((FrameCallback)drawFrameCalibration); + } + + if (magX > highestX) + highestX = magX; + if (magX < lowestX) + lowestX = magX; + if (magY > highestY) + highestY = magY; + if (magY < lowestY) + lowestY = magY; + if (magZ > highestZ) + highestZ = magZ; + if (magZ < lowestZ) + lowestZ = magZ; + + uint32_t now = millis(); + if (now > endCalibrationAt) { + doCalibration = false; + endCalibrationAt = 0; + showingScreen = false; + screen->endAlert(); + } + + // LOG_DEBUG("ICM20948 min_x: %.4f, max_X: %.4f, min_Y: %.4f, max_Y: %.4f, min_Z: %.4f, max_Z: %.4f", lowestX, highestX, + // lowestY, highestY, lowestZ, highestZ); + } + + int highestRealX = highestX - (highestX + lowestX) / 2; + + magX -= (highestX + lowestX) / 2; + magY -= (highestY + lowestY) / 2; + magZ -= (highestZ + lowestZ) / 2; + FusionVector ga, ma; + ga.axis.x = -(sensor->agmt.acc.axes.x); // default location for the BMX160 is on the rear of the board + ga.axis.y = -(sensor->agmt.acc.axes.y); + ga.axis.z = (sensor->agmt.acc.axes.z); + ma.axis.x = -magX; + ma.axis.y = -magY; + ma.axis.z = magZ * 3; + + // If we're set to one of the inverted positions + if (config.display.compass_orientation > meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270) { + ma = FusionAxesSwap(ma, FusionAxesAlignmentNXNYPZ); + ga = FusionAxesSwap(ga, FusionAxesAlignmentNXNYPZ); + } + + float heading = FusionCompassCalculateHeading(FusionConventionNed, ga, ma); + + switch (config.display.compass_orientation) { + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0_INVERTED: + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0: + break; + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_90: + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_90_INVERTED: + heading += 90; + break; + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_180: + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_180_INVERTED: + heading += 180; + break; + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270: + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED: + heading += 270; + break; + } + + screen->setHeading(heading); +#endif + // Wake on motion using polling - this is not as efficient as using hardware interrupt pin (see above) auto status = sensor->setBank(0); if (sensor->status != ICM_20948_Stat_Ok) { @@ -64,6 +153,17 @@ int32_t ICM20948Sensor::runOnce() #endif +void ICM20948Sensor::calibrate(uint16_t forSeconds) +{ +#if !defined(MESHTASTIC_EXCLUDE_SCREEN) + LOG_DEBUG("BMX160 calibration started for %is", forSeconds); + + doCalibration = true; + uint16_t calibrateFor = forSeconds * 1000; // calibrate for seconds provided + endCalibrationAt = millis() + calibrateFor; + screen->setEndCalibration(endCalibrationAt); +#endif +} // ---------------------------------------------------------------------- // ICM20948Singleton // ---------------------------------------------------------------------- @@ -121,6 +221,11 @@ bool ICM20948Singleton::init(ScanI2C::FoundDevice device) return false; } + if (startupMagnetometer(false) != ICM_20948_Stat_Ok) { + LOG_DEBUG("ICM20948 init magnetometer - %s", statusString()); + return false; + } + #ifdef ICM_20948_INT_PIN // Active low diff --git a/src/motion/ICM20948Sensor.h b/src/motion/ICM20948Sensor.h index 8344b0703..27ce4f451 100755 --- a/src/motion/ICM20948Sensor.h +++ b/src/motion/ICM20948Sensor.h @@ -6,6 +6,7 @@ #if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && __has_include() +#include "Fusion/Fusion.h" #include // Set the default gyro scale - dps250, dps500, dps1000, dps2000 @@ -80,6 +81,8 @@ class ICM20948Sensor : public MotionSensor { private: ICM20948Singleton *sensor = nullptr; + bool showingScreen = false; + float highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0; public: explicit ICM20948Sensor(ScanI2C::FoundDevice foundDevice); @@ -89,6 +92,7 @@ class ICM20948Sensor : public MotionSensor // Called each time our sensor gets a chance to run virtual int32_t runOnce() override; + virtual void calibrate(uint16_t forSeconds) override; }; #endif