From e2fb8b38228fc9407c151bf75f9008bb8bc7a631 Mon Sep 17 00:00:00 2001 From: anschrammh Date: Thu, 13 Apr 2023 13:41:42 +0200 Subject: [PATCH] Reworked the watch's sleep feature and internal workings, added a new sleep mode when BLE is enabled, now sending the watch's battery level, voltage and state to the GadgetBridge app when it connects to the watch --- src/W800_SDK_v1.00.10/app/gfx/gfx_task.c | 218 +++++++++++++++-------- 1 file changed, 142 insertions(+), 76 deletions(-) diff --git a/src/W800_SDK_v1.00.10/app/gfx/gfx_task.c b/src/W800_SDK_v1.00.10/app/gfx/gfx_task.c index eadf328..5726781 100644 --- a/src/W800_SDK_v1.00.10/app/gfx/gfx_task.c +++ b/src/W800_SDK_v1.00.10/app/gfx/gfx_task.c @@ -1,7 +1,9 @@ #include "app_common.h" +#include "app_utils.h" #include "lvgl.h" #include "lv_port_disp.h" #include "lv_port_indev.h" +#include "lv_port_tick.h" #include "FreeRTOS.h" #include "wm_include.h" #include "lcd.h" @@ -9,9 +11,9 @@ #include "menu_screen.h" #include "compass_screen.h" #include "settings_screen.h" -#include "CST816D.h" #include "watch_peripherals.h" #include "watch_settings.h" +#include "firmware_version.h" #include "ble_modem.h" #include "ble_service.h" @@ -23,6 +25,7 @@ static void date_time_cb(struct tm * const dateTime) tls_get_rtc(dateTime); } +bool _is_in_ble_sleep_mode = false; static void _perform_deferred_display_wake_up_set_timestamp(void); static void _perform_deferred_display_wake_up(uint8_t deferred_time_in_ms); @@ -358,6 +361,12 @@ static void ble_service_state_change_cb(ble_service_state_e ble_service_state) case BLE_SERVICE_MODE_ADVERTISING: watch_face_set_bluetooth_indicator(&watchFace, BLUETOOTH_STATE_ON); break; + case BLE_SERVICE_MODE_SUBSCRIBED: + /* We also set the current watch firmware version */ + gadget_bridge_send_firmware_version(FIRMWARE_VERSION, NULL); + /* We send the current battery level and battery state (charging or not)*/ + gadget_bridge_send_battery_status(_battery_stats.battery_percentage, _battery_stats.battery_voltage/1000.0, watch_peripherals_get_battery_controller_status() != BATTERY_CONTROLLER_STATUS_DISCHARGING); + break; default: break; } @@ -449,6 +458,9 @@ void gfx_task(void *param) lv_port_disp_init(); lv_port_indev_init(); + lv_port_tick_init(); + + lv_port_tick_start(); /* Initialize lvgl screens */ watch_face_init(&watchFace); @@ -484,99 +496,133 @@ void gfx_task(void *param) for(;;) { - lv_timer_handler(); - tls_os_time_delay(5); - - if(compass_screen_is_in_use(&compassScreen)) + /* Actions to perform when the watch is active only */ + if(!_is_in_ble_sleep_mode) { - bool is_data_available = false; - uint16_t azimuth = watch_peripherals_magnetometer_azimuth_read(&is_data_available); + lv_timer_handler(); + tls_os_time_delay(5); - if(is_data_available) + if(compass_screen_is_in_use(&compassScreen)) { - /* - QMC5883L_MData_t MDataRaw = watch_peripherals_magnetometer_raw_data_read(); - APP_LOG_TRACE("X %d Y %d Z %d", MDataRaw.MFieldX, MDataRaw.MFieldY, MDataRaw.MFieldZ); - */ + bool is_data_available = false; + uint16_t azimuth = watch_peripherals_magnetometer_azimuth_read(&is_data_available); - compass_screen_set_azimuth(&compassScreen, angle_with_offset(azimuth, 180)); + if(is_data_available) + { + /* + QMC5883L_MData_t MDataRaw = watch_peripherals_magnetometer_raw_data_read(); + APP_LOG_TRACE("X %d Y %d Z %d", MDataRaw.MFieldX, MDataRaw.MFieldY, MDataRaw.MFieldZ); + */ + + compass_screen_set_azimuth(&compassScreen, angle_with_offset(azimuth, 180)); + } + + compass_screen_set_temperature(&compassScreen, temperature); } - compass_screen_set_temperature(&compassScreen, temperature); - } + /* To rework */ + if(lv_tick_elaps(update_tick) > 5000) + { + pressure = watch_peripherals_pressure_sensor_get_pressure(&temperature); - if(watch_peripherals_accelerometer_wrist_wakeup_interrupt()) + _battery_stats.battery_voltage = watch_peripherals_get_battery_voltage(battery_unit_mv); + _battery_stats.battery_percentage = battery_voltage_to_percentage(_battery_stats.battery_voltage); + APP_LOG_DEBUG("GFX thread, temp : %0.2f °C, press : %0.2f hPa, battery(%s) : %u mV <-> %u %%", + temperature, + pressure/100, + battery_controller_status_2_str(watch_peripherals_get_battery_controller_status()), + _battery_stats.battery_voltage, + _battery_stats.battery_percentage); + + update_tick = lv_tick_get(); + } + + /* Throttle CPU freq down when inactive to save power or to increase responsiveness */ + tls_sys_clk clk; + tls_sys_clk_get(&clk); + if(lv_disp_get_inactive_time(NULL) > 5000) + { + if(clk.cpuclk != 40) + { + tls_sys_clk_set(CPU_CLK_40M); + APP_LOG_DEBUG("CPU 40Mhz"); + } + } + else + { + if(clk.cpuclk != 160) + { + tls_sys_clk_set(CPU_CLK_160M); + APP_LOG_DEBUG("CPU 160Mhz"); + } + } + + /* Will wake the display up after some ms to avoid seeing the second hand jumping */ + _perform_deferred_display_wake_up(30); + } + else { - APP_LOG_DEBUG("Wrist tilt"); + /* Increase task IDLE time */ + tls_os_time_delay(50); } - if(lv_tick_elaps(update_tick) > 5000) - { - pressure = watch_peripherals_pressure_sensor_get_pressure(&temperature); - - _battery_stats.battery_voltage = watch_peripherals_get_battery_voltage(battery_unit_mv); - _battery_stats.battery_percentage = battery_voltage_to_percentage(_battery_stats.battery_voltage); - APP_LOG_DEBUG("GFX thread, temp : %0.2f °C, press : %0.2f hPa, battery(%s) : %u mV <-> %u %%", - temperature, - pressure/100, - battery_controller_status_2_str(watch_peripherals_get_battery_controller_status()), - _battery_stats.battery_voltage, - _battery_stats.battery_percentage); - - //APP_LOG_DEBUG("Scanning WiFi : %d", tls_wifi_scan()); - update_tick = lv_tick_get(); - } /* Handle inactivity periods : */ if( persistency_get_settings()->display.display_delay_before_sleep != 0 && lv_disp_get_inactive_time(NULL) > (persistency_get_settings()->display.display_delay_before_sleep * 5 * 1000)) { - // First, we disable the display backlight and we set all the peripherals in their low power mode - watch_peripherals_set_brightness(0); - //lcd_on(&LCDConfig, false); - lcd_sleep(&LCDConfig, true); - watch_peripherals_magnetometer_power_mode_set(QMC5883L_Mode_Control_Standby); - if(CST816D_sleep()) - APP_LOG_DEBUG("CST816D Sleep cmd ok"); - else - APP_LOG_DEBUG("CST816D Sleep cmd fail"); - // Let's sleep - tls_pmu_sleep_start(); - // On wake up, we force the watch face to sync up with the rtc /!\ RTC update delay WTF ? - tls_os_time_delay(1); - watch_face_force_sync(&watchFace); - lv_disp_trig_activity(NULL); - watch_peripherals_magnetometer_power_mode_set(QMC5883L_Mode_Control_Continuous); - //lcd_on(&LCDConfig, true); - lcd_sleep(&LCDConfig, false); - //watch_peripherals_set_brightness(persistency_get_settings()->display.display_brightness); - //lcd_on(&LCDConfig, false); - _perform_deferred_display_wake_up_set_timestamp(); - } + /* Turns off the backlight, sets the display in sleep mode as well as some sensors. */ + watch_peripherals_watch_sleep(); - /* Will wake the display up after some ms to avoid seeing the second hand jumping */ - _perform_deferred_display_wake_up(30); - - /* Throttle CPU freq down when inactive to save power or to increase responsiveness */ - tls_sys_clk clk; - tls_sys_clk_get(&clk); - if(lv_disp_get_inactive_time(NULL) > 5000) - { - if(clk.cpuclk != 40) + /* We need to keep the BLE stack running so we can't juste put the MCU in sleep mode :-( */ + if(is_ble_modem_on()) { - tls_sys_clk_set(CPU_CLK_40M); - APP_LOG_DEBUG("CPU 40Mhz"); - } - } - else - { - if(clk.cpuclk != 160) - { - tls_sys_clk_set(CPU_CLK_160M); - APP_LOG_DEBUG("CPU 160Mhz"); + APP_LOG_DEBUG("Entering BLE sleep mode"); + /* We can stop the lvgl timer */ + APP_LOG_TRACE("Stopping LVGL tick timer"); + lv_port_tick_stop(); + _is_in_ble_sleep_mode = true; } + else + { + do + { + /* We set the pmu timer 0 to wake up every now and then to perform some background tasks before we go back to sleep again */ + tls_pmu_timer0_start(5); + + /* We clear any potentiential user wakeup source */ + watch_peripherals_wakeup_source_is_user(); + + /* Let's sleep for real */ + tls_pmu_sleep_start(); + + if(watch_peripherals_wakeup_source_is_user()) + { + /* Just to clear it off */ + tls_pmu_timer0_stop(); + watch_peripherals_wakeup_source_is_timer(); + break; + } + + /* Perform the periodic background tasks */ + ms_delay(5); + APP_LOG_INFO("Periodic timer wakeup !"); + + } while (watch_peripherals_wakeup_source_is_timer()); + + /* On wake up, we force the watch face to sync up with the rtc /!\ RTC update delay WTF ? */ + tls_os_time_delay(1); + watch_face_force_sync(&watchFace); + watch_peripherals_magnetometer_power_mode_set(QMC5883L_Mode_Control_Continuous); + + lcd_sleep(&LCDConfig, false); + lcd_on(&LCDConfig, false); + _perform_deferred_display_wake_up_set_timestamp(); + } + lv_disp_trig_activity(NULL); } + /* Handle any interrupts status */ if(_interrupts_statuses.battery_controller_status) { @@ -586,11 +632,31 @@ void gfx_task(void *param) _battery_stats.battery_percentage = battery_voltage_to_percentage(_battery_stats.battery_voltage); watch_face_set_battery_indicator(&watchFace, _battery_stats.battery_percentage, watch_peripherals_get_battery_controller_status()); } + + bool wrist_tilt = false , touch_screen_touch = false; + if((wrist_tilt = watch_peripherals_accelerometer_wrist_wakeup_interrupt()) || ((touch_screen_touch = lv_port_indev_touched()) && _is_in_ble_sleep_mode)) + { + if(wrist_tilt) + APP_LOG_DEBUG("Wrist tilt"); + if(touch_screen_touch) + APP_LOG_DEBUG("Touch screen touch"); + + if(_is_in_ble_sleep_mode) + { + _is_in_ble_sleep_mode = false; + lv_port_tick_start(); + + watch_face_force_sync(&watchFace); + watch_peripherals_magnetometer_power_mode_set(QMC5883L_Mode_Control_Continuous); + + lcd_sleep(&LCDConfig, false); + lcd_on(&LCDConfig, false); + _perform_deferred_display_wake_up_set_timestamp(); + } + } } } - - /* This handling logic should be moved somewhere ! I just don't know where yet ... */ static uint32_t _ticks = 0; static bool _was_sleeping = false;