diff --git a/Platform-io-source/platformio.ini b/Platform-io-source/platformio.ini index 33cbb00..363f087 100644 --- a/Platform-io-source/platformio.ini +++ b/Platform-io-source/platformio.ini @@ -13,7 +13,7 @@ lib_deps = Wire bodmer/TFT_eSPI adafruit/Adafruit MMC56x3 - sparkfun/SparkFun BMI270 Arduino Library + https://github.com/disq/SparkFun_BMI270_Arduino_Library.git#94fe8d0f0a871630f4a5c7327b1a894314ff5819 sparkfun/SparkFun MAX1704x Fuel Gauge Arduino Library@^1.0.4 me-no-dev/ESP Async WebServer@^1.2.3 knolleary/PubSubClient@^2.8 diff --git a/Platform-io-source/src/peripherals/imu.cpp b/Platform-io-source/src/peripherals/imu.cpp index 78038ff..f914600 100644 --- a/Platform-io-source/src/peripherals/imu.cpp +++ b/Platform-io-source/src/peripherals/imu.cpp @@ -6,20 +6,27 @@ extern Activity activity; extern RTC rtc; -void IMU::init() +void IMU::preinit(bool woke_from_sleep) { - imu_ready = true; - mag_ready = true; - - if (imu.beginI2C(i2cAddress) != BMI2_OK) + imu_preinit_ok = true; + if (imu.beginI2C(i2cAddress, Wire, woke_from_sleep) != BMI2_OK) { // Not connected, inform user info_println("Error: BMI270 not connected, check wiring and I2C address!"); - imu_ready = false; + imu_preinit_ok = false; + return; } - else + info_println(F("Found BMI270")); +} + +void IMU::init() +{ + imu_ready = imu_preinit_ok; + mag_ready = true; + + if (imu_ready) { - info_println(F("Found BMI270")); + info_println(F("Setting up BMI270")); imu.setAccelPowerMode(BMI2_POWER_OPT_MODE); imu.setGyroPowerMode(BMI2_POWER_OPT_MODE, BMI2_POWER_OPT_MODE); @@ -144,59 +151,81 @@ void IMU::set_hibernate(bool state) void IMU::process_steps() { - if (!imu_ready) + process_steps(false); +} + +void IMU::process_steps(bool force) +{ + if (!imu_preinit_ok) { - info_println("IMU not ready"); + info_println("process_steps: IMU not ready"); return; } // Wait for interrupt to occur + if (!interrupt_happened && !force) + { + return; + } + + uint16_t interrupt_status = 0; + + // Serial.println("interrupt caught!"); Serial.flush(); + // Reset flag for next interrupt if (interrupt_happened) { - // Reset flag for next interrupt interrupt_happened = false; - // Get the interrupt status to know which condition triggered - uint16_t interrupt_status = 0; imu.getInterruptStatus(&interrupt_status); + if (force) + interrupt_status |= BMI270_STEP_CNT_STATUS_MASK; // force in effect + } + else + { + // no interrupt but we're forced to process + interrupt_status = BMI270_STEP_CNT_STATUS_MASK; + } - // Check if this is the correct interrupt condition - if (interrupt_status & BMI270_STEP_CNT_STATUS_MASK) - { - // Get the step count - uint32_t _step_count = 0; - imu.getStepCount(&_step_count); + bool processed = false; - if (_step_count > 0) - step_count = _step_count; + // Check if this is the correct interrupt condition + if (interrupt_status & BMI270_STEP_CNT_STATUS_MASK) + { + // Get the step count + uint32_t _step_count = 0; + imu.getStepCount(&_step_count); - info_println("Step count: " + step_count); - } - if (interrupt_status & BMI270_STEP_ACT_STATUS_MASK) + if (_step_count > 0) { - // Get the step activity - movement_activity = 0; - imu.getStepActivity(&movement_activity); - - if (movement_activity == BMI2_STEP_ACTIVITY_STILL) - { - // Track steps for day, month, year in settings with date rollover - if (step_count > 0) - { - uint16_t day, month, year; - rtc.get_step_date(day, month, year); - activity.track_steps(step_count, day, month, year); - activity.save(true); - step_count = 0; - } - imu.resetStepCount(); - } + step_count = _step_count; + imu.resetStepCount(); } - if (!(interrupt_status & (BMI270_STEP_CNT_STATUS_MASK | BMI270_STEP_ACT_STATUS_MASK))) + + processed = true; + info_println("Step count: " + String(step_count)); + } + + if (interrupt_status & BMI270_STEP_ACT_STATUS_MASK) + { + // Get the step activity + movement_activity = 0; + imu.getStepActivity(&movement_activity); + + if (movement_activity == BMI2_STEP_ACTIVITY_STILL && !processed) { - // info_println("Unkown IInterrupt condition!"); + process_steps(true); + return; } } + if (!(interrupt_status & (BMI270_STEP_CNT_STATUS_MASK | BMI270_STEP_ACT_STATUS_MASK))) + { + // info_println("Unknown Interrupt condition! " + String(interrupt_status)); + } + + if (force) + { + persist_step_count(); + } } uint32_t IMU::get_steps(uint8_t day, uint8_t month, uint16_t year) @@ -392,4 +421,18 @@ bool IMU::is_looking_at_face() return (p >= 30 && p <= 50 && r > -10 && r < 10); } -IMU imu; \ No newline at end of file +bool IMU::persist_step_count() +{ + if (step_count == 0) + return false; + + // Track steps for day, month, year in settings with date rollover + uint16_t day, month, year; + rtc.get_step_date(day, month, year); + activity.track_steps(step_count, day, month, year); + auto saved = activity.save(false); + step_count = 0; + return saved; +} + +IMU imu; diff --git a/Platform-io-source/src/peripherals/imu.h b/Platform-io-source/src/peripherals/imu.h index 7ffc10a..77aa836 100644 --- a/Platform-io-source/src/peripherals/imu.h +++ b/Platform-io-source/src/peripherals/imu.h @@ -9,6 +9,7 @@ class IMU { public: + void preinit(bool woke_from_sleep); void init(); void update(); float get_accel_x(); @@ -27,6 +28,7 @@ class IMU // BMI270 Step Counter void setup_step_counter(); void process_steps(); + void process_steps(bool force); uint32_t get_steps(uint8_t day, uint8_t month, uint16_t year); uint8_t get_movement_activity_id(); String get_movement_activity(); @@ -38,7 +40,8 @@ class IMU void process_wrist_gestures(); // Ready states - bool imu_ready = true; + bool imu_preinit_ok = false; + bool imu_ready = false; bool mag_ready = true; private: @@ -62,6 +65,8 @@ class IMU const float soft_iron[3][3] = {{1.003, 0.008, -0.001}, {0.008, 1.004, 0.000}, {-0.001, -0.000, 0.994}}; const float mag_decl = -1.233; + + bool persist_step_count(); }; extern IMU imu; diff --git a/Platform-io-source/src/peripherals/rtc.cpp b/Platform-io-source/src/peripherals/rtc.cpp index 4b0fe66..9afdcc2 100644 --- a/Platform-io-source/src/peripherals/rtc.cpp +++ b/Platform-io-source/src/peripherals/rtc.cpp @@ -27,8 +27,6 @@ bool RTC::init() requiresNTP = rtc.getCurrentDateTimeComponent(DATETIME_YEAR) < 23; - next_rtc_read = millis(); - return true; } @@ -70,11 +68,11 @@ bool RTC::set_time_from_NTP(int16_t utc_offset) return !time_error; } -void RTC::set_hourly_alarm(uint minuets) +void RTC::set_hourly_alarm(uint minutes) { setup_interrupt(); - rtc.setHourlyAlarm(/*minute=*/minuets); + rtc.setHourlyAlarm(/*minute=*/minutes); rtc.enableInterrupt(INTERRUPT_ALARM); } @@ -129,7 +127,7 @@ uint16_t RTC::get_year() { return ((uint16_t)rtc.getCurrentDateTimeComponent(DAT void RTC::get_step_date(uint16_t &day, uint16_t &month, uint16_t &year) { - if (millis() - next_rtc_read > 5000) + if (next_rtc_read == 0 || millis() - next_rtc_read > 5000) { next_rtc_read = millis(); cached_day = get_day(); diff --git a/Platform-io-source/src/peripherals/rtc.h b/Platform-io-source/src/peripherals/rtc.h index 28ef029..a8e8f35 100644 --- a/Platform-io-source/src/peripherals/rtc.h +++ b/Platform-io-source/src/peripherals/rtc.h @@ -17,7 +17,7 @@ class RTC void setup_interrupt(); bool check_interrupt(); bool set_time_from_NTP(int16_t utc_offset); - void set_hourly_alarm(uint minuets); + void set_hourly_alarm(uint minutes); // String getTime(); String get_hours_string(bool padded, bool is24hour); String get_mins_string(bool padded); @@ -47,7 +47,7 @@ class RTC uint8_t interruptPin = 33; unsigned long next_rtc_read = 0; uint16_t cached_day = 0; - uint cached_month = 0; + uint16_t cached_month = 0; uint16_t cached_year = 0; }; diff --git a/Platform-io-source/src/tinywatch.cpp b/Platform-io-source/src/tinywatch.cpp index 87ed009..07840aa 100644 --- a/Platform-io-source/src/tinywatch.cpp +++ b/Platform-io-source/src/tinywatch.cpp @@ -101,6 +101,7 @@ void setup() // Start the RTC & Battery early as they are needed for wake fom sleep battery.init(); rtc.init(); + imu.preinit(was_asleep); if (was_asleep) { @@ -120,7 +121,6 @@ void setup() if (was_asleep) { // Wake up the peripherals because we were sleeping! - imu.set_hibernate(false); // work out why we were woken up and do something about it // 0: Touched Screen @@ -219,6 +219,16 @@ void setup() // load the activity data activity.load(); + if (was_asleep) + { + // Do the steps last, after activity is loaded + imu.set_hibernate(false); + if (settings.config.imu_process_steps) + { + imu.process_steps(true); + } + } + // Start the rest of the peripherals imu.init(); } @@ -387,9 +397,16 @@ void TinyWATCH::go_to_sleep() digitalWrite(TFT_LED, 0); deinit_buzzer(BUZZER); battery.set_hibernate(true); + + if (settings.config.imu_process_steps) + { + imu.process_steps(true); + } + imu.set_hibernate(false); settings.save(true); activity.save(true); + delay(500); // no delay and it sometimes wakes up immediately LittleFS.end();