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

This commit is contained in:
anschrammh 2023-04-13 13:41:42 +02:00
parent 9f241454c6
commit e2fb8b3822

View File

@ -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;