Compare commits

...

13 Commits

Author SHA1 Message Date
anschrammh
e8f8f694f0 Updated CodeBlocks LVGL simulator main.c file 2023-10-19 08:32:30 +02:00
anschrammh
9e63ebd529 Updated the notification screen in the CodeBlocks LVGL simulator as work is in progress 2023-10-19 08:32:28 +02:00
anschrammh
a89e0db18a increased the available memory to lvgl from 30k to 35k of RAM 2023-10-19 08:32:27 +02:00
anschrammh
d796c4c0fa Fixed a bug where on watch screen creation, depending on the current battery state, I paused a timer which was not yet created... 2023-10-19 08:32:26 +02:00
anschrammh
b19c7defc7 Added an event callback to know what setting category is opened and closed, reworked the way the side screen is cleaned (refactoring), added a background color on the selected item of the list 2023-10-19 08:32:25 +02:00
anschrammh
bf9816457b Added the GadgetBridge notification popup (Work In Progress), removed the compass app update code from the loop, plus other ongoing code cleanup/rework of this file 2023-10-19 08:32:24 +02:00
anschrammh
af71c44af4 The compass app now updates it's azimuth and temperature by itself with a timer and doesn't rely on the main loop to do so. It also, through a callback, put the magnetometer in active or standby mode to save power when leaving the app 2023-10-19 08:32:20 +02:00
anschrammh
2fc99479c5 Updated the GadgetBridge parser to fix an issue where a double quote was added in the parsed data if we received a notification text with 35 characters, removed the const attribute of the parameter passed in the event callback 2023-10-19 08:07:26 +02:00
anschrammh
59a42c7309 Changed battery_unit_e enumeration values names to capital letters for consistency sake 2023-10-19 08:03:02 +02:00
anschrammh
73b0a6f2f3 Minor change trying to make the mmc_sdio driver more robust 2023-10-19 08:00:25 +02:00
anschrammh
43dc3ce89e Cosmetic change 2023-10-19 07:58:42 +02:00
anschrammh
8f53359cb8 Added the folder for a new module which work is still in progress : the power management block 2023-10-19 07:57:48 +02:00
anschrammh
57fe2a423e Replaced Mhz with the correct spelling MHz 2023-10-19 07:54:03 +02:00
35 changed files with 1816 additions and 634 deletions

View File

@ -10,7 +10,7 @@ So let's go !
The W800 is a pretty interesting chip with impressive characteristics for its price (around 1$) :
### Core :
* 32bit XT804 CPU
* 240 Mhz max clock
* 240 MHz max clock
### Memory :
* 2 MB on chip flash
@ -237,8 +237,8 @@ to save power
(Need to work on sleep current :-( )
| Mode | Current draw | Estimated battery life (600 mAh lipo) |
|--------------------------|--------------|---------------------------------------|
|Active (40Mhz clk)<br>(No BLE / No WiFi) |~52 mA | ~11 hour |
|Active (240Mhz clk)<br>(No BLE / No WiFi)|~72 mA | ~8 hour |
|Active (40MHz clk)<br>(No BLE / No WiFi) |~52 mA | ~11 hour |
|Active (240MHz clk)<br>(No BLE / No WiFi)|~72 mA | ~8 hour |
|Sleep |~4.5 mA |~5 days and 12 hours |
|Standby |~1.8 mA |~13 days and 15 hours |

View File

@ -6,7 +6,8 @@ GEN_LIBS = libappdrivers$(LIB_EXT)
COMPONENTS_libappdrivers = lcd/libappdriverslcd$(LIB_EXT) \
mmc_sdio/libappdriversmmc_sdio$(LIB_EXT) \
i2c/libappdriversi2c$(LIB_EXT) \
watch_peripherals/libappdriverswatch_peripherals$(LIB_EXT)
watch_peripherals/libappdriverswatch_peripherals$(LIB_EXT) \
watch_power_management/libappdriverswatch_power_management$(LIB_EXT)
endif
#DEFINES +=

View File

@ -8,6 +8,7 @@
* @copyright MIT
*
*/
#include "wm_type_def.h"
#include "wm_io.h"
#include "wm_gpio_afsel.h"

View File

@ -7,6 +7,7 @@
*
* @copyright MIT
*/
#ifndef I2C_H
#define I2C_H

View File

@ -64,6 +64,11 @@ void mmc_sdio_driver_write_dma_async(uint32_t *data, uint32_t dataLengthInBytes)
if (dataLengthInBytes < 4)
{
APP_LOG_ERROR("send err, data length < 4");
/* Let's call the user DMATransferDoneFuncCb function if any to not stay stuck */
if(DMATransferDoneFuncCb)
{
DMATransferDoneFuncCb(DMATransferDoneArg);
}
return;
}

View File

@ -299,10 +299,10 @@ uint16_t watch_peripherals_get_battery_voltage(battery_unit_e unit)
switch (unit)
{
case battery_unit_mv:
case BATTERY_UNIT_MV:
return batteryVoltage < 0 ? 0 : batteryVoltage;
break;
case battery_unit_percent:
case BATTERY_UNIT_PERCENT:
return battery_voltage_to_percentage(batteryVoltage < 0 ? 0 : batteryVoltage);
break;
default:
@ -450,7 +450,7 @@ bool watch_peripherals_magnetometer_init(void)
/* Needed but UGLY */
tls_os_time_delay(2);
if(!QMC5883L_set_power_mode(QMC5883L_Mode_Control_Continuous))
if(!QMC5883L_set_power_mode(QMC5883L_Mode_Control_Standby))
{
APP_LOG_ERROR("Failed to set QMC5883L mode");
return false;

View File

@ -4,6 +4,7 @@
*/
#ifndef WATCH_PERIPHERALS_H
#define WATCH_PERIPHERALS_H
#include "lcd.h"
#include "wm_type_def.h"
#include "QMC5883L.h"
@ -12,8 +13,8 @@
typedef enum battery_unit
{
battery_unit_mv = 0,
battery_unit_percent
BATTERY_UNIT_MV = 0,
BATTERY_UNIT_PERCENT
} battery_unit_e;
typedef enum battery_controller_status

View File

@ -0,0 +1,15 @@
TOP_DIR = ../../..
sinclude $(TOP_DIR)/tools/w800/conf.mk
ifndef PDIR
GEN_LIBS = libappdriverswatch_power_management$(LIB_EXT)
endif
#DEFINES +=
sinclude $(TOP_DIR)/tools/w800/rules.mk
INCLUDES := $(INCLUDES) -I $(PDIR)include
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

View File

@ -0,0 +1,10 @@
/**
* @file watch_power_management.h
* @author Anatole SCHRAMM-HENRY
* @brief Watch power management functions API header file
* @version 0.1
* @date 2023-10-12
*
* @copyright MIT
*
*/

View File

@ -0,0 +1,55 @@
/**
* @file watch_power_management.h
* @author Anatole SCHRAMM-HENRY
* @brief Watch power management functions API header file
* @version 0.1
* @date 2023-10-12
*
* @copyright MIT
*
*/
#ifndef WATCH_POWER_MANAGEMENT_H
#define WATCH_POWER_MANAGEMENT_H
typedef enum watch_power_state
{
/**
* @brief WATCH_POWER_STATE_IDLE : the watch has the display on and the screen is showing something,
* to save power, the MCU is running at a low clock speed (40 MHz), animations, transitions and other graphical effects might not be smooth.
*/
WATCH_POWER_STATE_IDLE,
/**
* @brief WATCH_POWER_STATE_FULL_SPEED : the watch has the display on and the screen is showing something,
* to have the best graphical user experience, the MCU is running at a higher clock speed giving better animations,
* transitions and other graphical effects at the expense of a higher power consumption.
*/
WATCH_POWER_STATE_FULL_SPEED,
/**
* @brief WATCH_POWER_STATE_SLEEP : the watch is put in sleep state this means that the MCU stops, data in RAM is kept,
* the display is completely switched off and the wake up is fast.
* The watch will wakeup after user interaction is detected : tilt of the wrist, screen touched.
* The watch will continue executing the firmware where it last was.
* This mode allows for a low power consumption of around 4 mA.
*/
WATCH_POWER_STATE_SLEEP,
/**
* @brief WATCH_POWER_STATE_BLE_SLEEP : the watch will enter this mode instead of the WATCH_POWER_STATE_SLEEP state
* if the BLE modem is running. This is because the MCU can not be put to sleep to keep the Bluetooth Low Energy stack running.
* The min clock speed should be set to 40MHz and NOT lower.
*/
WATCH_POWER_STATE_BLE_SLEEP,
/**
* @brief WACTH_POWER_STATE_STANDBY : in this state, the watch should achieve it's the lowest power consumption,
* data in RAM is lost and on user events (tilt of the wrist, screen touched), the watch reboots.
* This mode allows for a low power consumption of around 2 mA.
*/
WACTH_POWER_STATE_STANDBY,
} watch_power_state_e;
typedef struct watch_power_management
{
watch_power_state_e current_power_state;
} watch_power_management_t;
#endif //WATCH_POWER_MANAGEMENT_H

View File

@ -6,6 +6,7 @@
* @version 0.1
* @date 2023-04-05
* Updated : 2023-10-15, fixed potential memory leak.
* Updated : 2023-10-17, fixed potential issue where a double quote is added at the start of a parsed string.
*
* @copyright MIT
*
@ -256,7 +257,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
{
case GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE:
// To prevent a potential memory leak if the parser is fed with bad data
// To prevent a potential memory leak if the parser is fed with ill formed data
_free_event_data();
if((start = strstr(_gadget_bridge_internals.buffer, "setTime("))
@ -435,7 +436,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
else to_return = GADGET_BRIDGE_PARSER_CODE_OK;
break;
case GADGET_BRIDGE_PARSER_FSM_FOUND_ID_SRC:
if((start = strstr(_gadget_bridge_internals.buffer, "src:")) &&
if((start = strstr(_gadget_bridge_internals.buffer, "src:\"")) &&
((end = strstr(_gadget_bridge_internals.buffer, ",title")) || (end2 = strstr(_gadget_bridge_internals.buffer, ",subject"))))
{
if((end && !end2) || (end != NULL && end < end2))
@ -465,7 +466,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
else to_return = GADGET_BRIDGE_PARSER_CODE_OK;
break;
case GADGET_BRIDGE_PARSER_FSM_FOUND_TITLE:
if((start = strstr(_gadget_bridge_internals.buffer, "title:")))
if((start = strstr(_gadget_bridge_internals.buffer, "title:\"")))
{
//printf("###Parsing TITLE content\n");
@ -488,7 +489,6 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
if(end)
{
//printf("###Found BODY\n");
_parser_extract_char_str(_gadget_bridge_internals.buffer, end - 1, &_gadget_bridge_internals.event_data.notification.title);
// We remove the parsed part from the buffer
@ -519,7 +519,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
}
break;
case GADGET_BRIDGE_PARSER_FSM_FOUND_SRC_BODY:
if((start = strstr(_gadget_bridge_internals.buffer, "body:")))
if((start = strstr(_gadget_bridge_internals.buffer, "body:\"")))
{
//printf("###Parsing BODY content\n");
@ -603,7 +603,6 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
{
// We don't care about the sender nor the tel tag
//printf("###TEST NOTIFICATION Type done\n");
_parser_extract_char_str(_gadget_bridge_internals.buffer, end - 1, &_gadget_bridge_internals.event_data.notification.body);
// We remove the parsed part from the buffer
@ -711,7 +710,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
_gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE;
break;*/
case GADGET_BRIDGE_PARSER_FSM_FOUND_SUBJECT:
if((start = strstr(_gadget_bridge_internals.buffer, "subject:")))
if((start = strstr(_gadget_bridge_internals.buffer, "subject:\"")))
{
//printf("###Parsing SUBJECT content\n");

View File

@ -201,7 +201,7 @@ typedef struct gadget_bridge_event_data
};
} gadget_bridge_event_data_t;
typedef void (*parser_event_callback_t)(const gadget_bridge_event_data_t *gadget_bridge_event_data);
typedef void (*parser_event_callback_t)(gadget_bridge_event_data_t *gadget_bridge_event_data);
/**
* @brief Sends an Android toast to GadgetBridge to be displayed on the phone.

View File

@ -20,7 +20,6 @@ static const char *cardinals[] =
static void gesture_event_cb(lv_event_t * e)
{
CompassScreen_t *compassScreen = e->user_data;
(void)compassScreen;
lv_dir_t gesture;
switch(gesture = lv_indev_get_gesture_dir(lv_indev_get_act()))
@ -30,6 +29,8 @@ static void gesture_event_cb(lv_event_t * e)
break;
case LV_DIR_RIGHT:
LV_LOG_USER("GESTURE : RIGHT");
// We delete the refresh timer
lv_timer_del(compassScreen->refreshTimer);
// We create the menu screen and switch to it
extern MenuScreen_t menuScreen;
menu_screen_create(&menuScreen);
@ -53,6 +54,23 @@ static void cleanup_event_cb(lv_event_t * e)
LV_LOG_USER("cleanup");
}
static void _compass_screen_refresh_timer_cb(lv_timer_t *timer)
{
CompassScreen_t *compassScreen = timer->user_data;
if(compassScreen->compassScreenAzimuthAndTemperatureCb)
{
uint16_t azimuth = 0;
float temperature = 0.0f;
bool refreshAzimuth = true, refreshTemperature = true;
compassScreen->compassScreenAzimuthAndTemperatureCb(&azimuth, &refreshAzimuth, &temperature, &refreshTemperature);
if(refreshAzimuth)compass_screen_set_azimuth(compassScreen, azimuth);
if(refreshTemperature)compass_screen_set_temperature(compassScreen, temperature);
}
}
static void create_cardinal(CompassCardinal_t *cardidanl, const char *cardinalText, lv_color_t textColor, lv_coord_t x, lv_coord_t y, lv_obj_t *parent)
{
cardidanl->label = lv_label_create(parent);
@ -93,6 +111,29 @@ void compass_screen_init(CompassScreen_t * const compassScreen)
memset(compassScreen, 0, sizeof(CompassScreen_t));
strcpy(compassScreen->compassAzimuth.text, "0° N");
strcpy(compassScreen->compassTemperature.text, "0.00°C");
}
void compass_screen_register_on_state_change_cb(CompassScreen_t * const compassScreen, CompassScreenOnStateChangeCb_t compassScreenOnStateChangeCb)
{
if(!compassScreen)
{
LV_LOG_ERROR("NULL pointer given !");
return;
}
compassScreen->compassScreenOnStateChangeCb = compassScreenOnStateChangeCb;
}
void compass_screen_register_azimuth_and_temperature_cb(CompassScreen_t * const compassScreen, CompassScreenAzimuthAndTemperatureCb_t compassScreenAzimuthAndTemperatureCb)
{
if(!compassScreen)
{
LV_LOG_ERROR("NULL pointer given !");
return;
}
compassScreen->compassScreenAzimuthAndTemperatureCb = compassScreenAzimuthAndTemperatureCb;
}
void compass_screen_set_azimuth(CompassScreen_t * const compassScreen, uint16_t azimuth)
@ -317,6 +358,18 @@ void compass_screen_create(CompassScreen_t * const compassScreen)
lv_obj_add_event_cb(compassScreen->display, &(gesture_event_cb), LV_EVENT_GESTURE, compassScreen);
//We register the event callback to handle the cleanup
lv_obj_add_event_cb(compassScreen->display, &(cleanup_event_cb), LV_EVENT_DELETE, compassScreen);
//We create the refresh timer
if(compassScreen->refreshTimer)
{
LV_LOG_ERROR("refreshTimer should be NULL here !");
lv_timer_del(compassScreen->refreshTimer);
compassScreen->refreshTimer = NULL;
}
if(compassScreen->compassScreenOnStateChangeCb) compassScreen->compassScreenOnStateChangeCb(COMPASS_SCREEN_STATE_OPENED);
compassScreen->refreshTimer = lv_timer_create(&(_compass_screen_refresh_timer_cb), 20, compassScreen);
}
void compass_screen_destroy(CompassScreen_t * const compassScreen)
@ -337,4 +390,7 @@ void compass_screen_destroy(CompassScreen_t * const compassScreen)
compassScreen->northMarker = NULL;
//compassScreen->compassGraduation.meter = NULL;
//compassScreen->compassGraduation.scale = NULL;
compassScreen->refreshTimer = NULL;
if(compassScreen->compassScreenOnStateChangeCb) compassScreen->compassScreenOnStateChangeCb(COMPASS_SCREEN_STATE_CLOSED);
}

View File

@ -22,6 +22,15 @@ typedef struct CompassCardinal
lv_meter_scale_t *scale;
} CompassGraduation_t;*/
typedef enum CompassScreenState
{
COMPASS_SCREEN_STATE_OPENED = 0,
COMPASS_SCREEN_STATE_CLOSED
} CompassScreenState_e;
typedef void (*CompassScreenOnStateChangeCb_t)(CompassScreenState_e compassScreenState);
typedef void (*CompassScreenAzimuthAndTemperatureCb_t)(uint16_t *azimuth, bool *refreshAzimuth, float *temperature, bool *refreshTemperature);
/* Compass screen context object */
typedef struct CompassScreen
{
@ -37,6 +46,11 @@ typedef struct CompassScreen
CompassLabel_t compassAzimuth;
CompassLabel_t compassTemperature;
CompassScreenOnStateChangeCb_t compassScreenOnStateChangeCb;
CompassScreenAzimuthAndTemperatureCb_t compassScreenAzimuthAndTemperatureCb;
lv_timer_t *refreshTimer;
} CompassScreen_t;
/**
@ -47,6 +61,26 @@ typedef struct CompassScreen
*/
void compass_screen_init(CompassScreen_t * const compassScreen);
/**
* @brief Registers a callback function which will be called every time the state of the application changes ie : is opened or closed.
* This callback should be used to initialize and deinitialize needed devices drivers like the magnetometer or the temperature sensor.
* @note The state of the application is passed as a parameter or the callback function.
*
* @param compassScreen a pointer to the compass screen object structure.
* @param compassScreenOnStateChangeCb the callback of type @ref CompassScreenOnStateChangeCb_t to register.
*/
void compass_screen_register_on_state_change_cb(CompassScreen_t * const compassScreen, CompassScreenOnStateChangeCb_t compassScreenOnStateChangeCb);
/**
* @brief Registers a callback function which will be executed every time the compass refreshes.
* This callback should retrieve the azimuth and temperature and pass it through the provided pointers.
* @note If no new magnetometer or temperature data is available upon the function call, set the associated refresh parameter to false;
*
* @param compassScreen a pointer to the compass screen object structure.
* @param compassScreenOnStateChangeCb the callback of type CompassScreenAzimuthAndTemperatureCb_t to register.
*/
void compass_screen_register_azimuth_and_temperature_cb(CompassScreen_t * const compassScreen, CompassScreenAzimuthAndTemperatureCb_t compassScreenAzimuthAndTemperatureCb);
/**
* @brief Sets the azimuth in degrees (relative to the north) to show on the compass UI.
*

View File

@ -13,6 +13,7 @@
#include "find_my_phone_screen.h"
#include "music_player_screen.h"
#include "settings_screen.h"
#include "notification_screen.h"
#include "watch_peripherals.h"
#include "watch_settings.h"
#include "firmware_version.h"
@ -38,6 +39,7 @@ MenuScreen_t menuScreen;
CompassScreen_t compassScreen;
FindMyPhoneScreen_t findMyPhoneScreen;
MusicPlayerScreen_t musicPlayerScreen;
NotificationScreen_t notificationScreen;
SettingsScreen_t settingsScreen;
@ -362,7 +364,7 @@ static uint16_t angle_with_offset(uint16_t angle, uint16_t offset)
return (angle + offset) >= 360 ? angle + offset - 360 : angle + offset;
}
static void parser_event_cb(const gadget_bridge_event_data_t *gadget_bridge_event_data)
static void parser_event_cb(gadget_bridge_event_data_t *gadget_bridge_event_data)
{
APP_LOG_INFO("[GB]Event of type : %s\n", gadget_bridge_event_type_2_str(gadget_bridge_event_data->event_type));
@ -396,6 +398,23 @@ static void parser_event_cb(const gadget_bridge_event_data_t *gadget_bridge_even
}
music_player_screen_set_music_position(&musicPlayerScreen, gadget_bridge_event_data->music_state.position_in_seconds);
break;
case GADGET_BRIDGE_EVENT_TYPE_NOTIFY:
{
// Let's retrieve the time from the watch :
struct tm date_time;
tls_get_rtc(&date_time);
notification_screen_notify(&notificationScreen, gadget_bridge_event_data->notification.handle,
mktime(&date_time),
gadget_bridge_event_data->notification.notification_type,
gadget_bridge_event_data->notification.title,
gadget_bridge_event_data->notification.body);
//As we don't want the title and the body strings to be freed after the callback returns, let's set them to NULL
gadget_bridge_event_data->notification.title = NULL;
gadget_bridge_event_data->notification.body = NULL;
}
break;
default:
APP_LOG_INFO("Not yet handled\n");
}
@ -481,6 +500,50 @@ static void scan_result_cb(void)
tls_mem_free(buffer);
}
static void compass_screen_on_state_change_cb(CompassScreenState_e compassScreenState)
{
switch(compassScreenState)
{
case COMPASS_SCREEN_STATE_OPENED:
watch_peripherals_magnetometer_power_mode_set(QMC5883L_Mode_Control_Continuous);
break;
case COMPASS_SCREEN_STATE_CLOSED:
default:
watch_peripherals_magnetometer_power_mode_set(QMC5883L_Mode_Control_Standby);
break;
}
}
static void settings_screen_on_state_change_cb(SettingsScreenState_e settingsScreenState, SettingsScreenCategory_e settingsScreenCategory)
{
switch(settingsScreenState)
{
case SETTINGS_SCREEN_STATE_OPENED:
if(settingsScreenCategory == SETTINGS_SCREEN_CATEGORY_ABOUT)
{
watch_peripherals_magnetometer_power_mode_set(QMC5883L_Mode_Control_Continuous);
}
break;
case SETTINGS_SCREEN_STATE_CLOSED:
if(settingsScreenCategory == SETTINGS_SCREEN_CATEGORY_ABOUT)
{
watch_peripherals_magnetometer_power_mode_set(QMC5883L_Mode_Control_Standby);
}
break;
default:
break;
}
}
static float bmp_temperature = 0;
static void compass_screen_azimuth_and_temperature_cb(uint16_t *azimuth, bool *refreshAzimuth, float *temperature, bool *refreshTemperature)
{
uint16_t sensor_azimuth = watch_peripherals_magnetometer_azimuth_read(refreshAzimuth);
*azimuth = angle_with_offset(sensor_azimuth, 270);
*temperature = bmp_temperature;
}
static void sendFindMyPhoneBLECommandCb(bool findMyPhone)
{
gadget_bridge_send_find_phone(findMyPhone);
@ -514,7 +577,7 @@ void gfx_task(void *param)
/* Let's init all the watch's sensors */
watch_peripherals_pressure_sensor_init();
watch_peripherals_magnetometer_init();
watch_peripherals_magnetometer_calibration_data_set(-3120, 1050, 1140, 5200, 1200, 3200, 30.0);
watch_peripherals_magnetometer_calibration_data_set(-7200, -2700, -1300, 3300, 1200, 3200, 30.0);
watch_peripherals_accelerometer_init();
watch_peripherals_accelerometer_wrist_wakeup_enable(persistency_get_settings()->display.display_wrist_wakeup);
watch_peripherals_accelerometer_step_counter_enable(true);
@ -524,7 +587,7 @@ void gfx_task(void *param)
APP_LOG_DEBUG("MAX3010X enable temp int %d", MAX3010X_enable_die_temperature_int(true));*/
/* Make the first battery voltage reading here */
_battery_stats.battery_voltage = watch_peripherals_get_battery_voltage(battery_unit_mv);
_battery_stats.battery_voltage = watch_peripherals_get_battery_voltage(BATTERY_UNIT_MV);
_battery_stats.battery_percentage = battery_voltage_to_percentage(_battery_stats.battery_voltage);
ble_service_set_battery_value(_battery_stats.battery_percentage);
@ -553,6 +616,8 @@ void gfx_task(void *param)
watch_face_init(&watchFace);
menu_screen_init(&menuScreen);
compass_screen_init(&compassScreen);
compass_screen_register_on_state_change_cb(&compassScreen, &(compass_screen_on_state_change_cb));
compass_screen_register_azimuth_and_temperature_cb(&compassScreen, &(compass_screen_azimuth_and_temperature_cb));
find_my_phone_screen_init(&findMyPhoneScreen);
find_my_phone_screen_register_BLE_command_send_cb(&findMyPhoneScreen, &(sendFindMyPhoneBLECommandCb));
@ -561,7 +626,10 @@ void gfx_task(void *param)
music_player_screen_register_music_playback_control_cb(&musicPlayerScreen, &(sendMusicPlaybackBLECommandCb));
music_player_screen_register_music_player_time_ref_ms_cb(&musicPlayerScreen, &(elapsed_ms));
notification_screen_init(&notificationScreen);
settings_screen_init(&settingsScreen);
settings_screen_register_on_state_change_cb(&settingsScreen, &(settings_screen_on_state_change_cb));
settings_screen_register_API_interface(&settingsScreen, &settingsScreenAPIInterface);
watch_face_register_date_time_cb(&watchFace, &(date_time_cb));
@ -584,8 +652,6 @@ void gfx_task(void *param)
/* Enable WiFi hotspot scanning for antenna performance test purposes */
//tls_wifi_scan_result_cb_register(&(scan_result_cb));
float temperature = 0;
float pressure = 0;
uint32_t ble_info_update_ms = 0;
@ -593,29 +659,12 @@ void gfx_task(void *param)
for(;;)
{
/* Actions to perform when the watch is active only */
if(!_is_in_ble_sleep_mode)
{
lv_timer_handler();
if(compass_screen_is_in_use(&compassScreen))
{
bool is_data_available = false;
uint16_t azimuth = watch_peripherals_magnetometer_azimuth_read(&is_data_available);
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, 270));
}
compass_screen_set_temperature(&compassScreen, temperature);
}
/* Throttle CPU freq down when inactive to save power or to increase responsiveness */
tls_sys_clk clk;
tls_sys_clk_get(&clk);
@ -624,7 +673,7 @@ void gfx_task(void *param)
if(clk.cpuclk != 40)
{
tls_sys_clk_set(CPU_CLK_40M);
APP_LOG_DEBUG("CPU 40Mhz");
APP_LOG_DEBUG("CPU 40MHz");
}
}
else
@ -632,7 +681,7 @@ void gfx_task(void *param)
if(clk.cpuclk != 160)
{
tls_sys_clk_set(CPU_CLK_160M);
APP_LOG_DEBUG("CPU 160Mhz");
APP_LOG_DEBUG("CPU 160MHz");
}
}
@ -692,7 +741,6 @@ void gfx_task(void *param)
/* 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);
@ -707,12 +755,12 @@ void gfx_task(void *param)
{
main_data_update = elapsed_ms();
pressure = watch_peripherals_pressure_sensor_get_pressure(&temperature);
pressure = watch_peripherals_pressure_sensor_get_pressure(&bmp_temperature);
_battery_stats.battery_voltage = watch_peripherals_get_battery_voltage(battery_unit_mv);
_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,
bmp_temperature,
pressure/100,
battery_controller_status_2_str(watch_peripherals_get_battery_controller_status()),
_battery_stats.battery_voltage,
@ -726,7 +774,7 @@ void gfx_task(void *param)
{
_interrupts_statuses.battery_controller_status = false;
//Let's refresh the battery percentage as well:
_battery_stats.battery_voltage = watch_peripherals_get_battery_voltage(battery_unit_mv);
_battery_stats.battery_voltage = watch_peripherals_get_battery_voltage(BATTERY_UNIT_MV);
_battery_stats.battery_percentage = battery_voltage_to_percentage(_battery_stats.battery_voltage);
ble_service_set_battery_value(_battery_stats.battery_percentage);
watch_face_set_battery_indicator(&watchFace, _battery_stats.battery_percentage, watch_peripherals_get_battery_controller_status());
@ -762,7 +810,6 @@ void gfx_task(void *param)
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);

View File

@ -0,0 +1,331 @@
#include "notification_screen.h"
#include <stdio.h>
#include <stdlib.h>
#include "wm_mem.h"
/* Internal API to manage notification objects */
bool _notification_list_is_empty(NotificationDataList_t notificationList);
void _notification_list_add_head(NotificationDataList_t *notificationList, NotificationData_t *notification);
NotificationData_t *_notification_list_remove_tail(NotificationDataList_t *notificationList);
uint8_t _notification_list_count(NotificationDataList_t notificationList);
void _notification_list_debug(NotificationDataList_t notificationList);
/* Internal UI API */
void _display_message_notification(NotificationScreen_t * const notificationScreen, const NotificationData_t *notification);
void _notification_popup_destroy(NotificationScreen_t * const notificationScreen);
const char *_notification_type_to_char(NotificationType_e notificationType);
const char *_notification_timestamp_to_date(time_t timestamp);
static void notification_scrolled_event_cb(lv_event_t *e)
{
NotificationScreen_t *notificationScreen = lv_event_get_user_data(e);
//If we didn't scroll down enough, make the notif pop again
if(lv_obj_get_scroll_y(e->target) >= 83)
{
lv_obj_scroll_to_y(e->target, 166, LV_ANIM_ON);
}
//Else we know that the user wants to close the notification, so we do it with an animation to reach 0
else if(lv_obj_get_scroll_y(e->target) != 0)
{
lv_obj_scroll_to_y(e->target, 0, LV_ANIM_ON);
}
else //We scrolled enough to tell that we saw the notification and that we want to close it
{
LV_LOG_USER("Notification closed");
_notification_popup_destroy(notificationScreen);
if(notificationScreen->notificationOnStateChangeCb) notificationScreen->notificationOnStateChangeCb(NOTIFICATION_STATE_CLEARED);
}
}
void notification_screen_init(NotificationScreen_t * const notificationScreen)
{
if(!notificationScreen)
{
LV_LOG_ERROR("NULL pointer given !");
return;
}
memset(notificationScreen, 0, sizeof(NotificationScreen_t));
//Let's initialize the list of free notifications from the pool
for(uint8_t i = 0; i < MAX_NOTIFICATIONS_COUNT; i++)
_notification_list_add_head(&notificationScreen->freeNotificationList, notificationScreen->notificationPool + i);
}
void notification_screen_register_on_state_change_cb(NotificationScreen_t * const notificationScreen, NotificationOnStateChangeCb_t notificationOnStateChangeCb)
{
if(!notificationScreen)
{
LV_LOG_ERROR("NULL pointer given !");
return;
}
notificationScreen->notificationOnStateChangeCb = notificationOnStateChangeCb;
}
void notification_screen_notify(NotificationScreen_t * const notificationScreen, uint32_t handle, time_t dateOfArrival, NotificationType_e notificationType, char * title, char * body)
{
if(!notificationScreen)
{
LV_LOG_ERROR("NULL pointer given !");
return;
}
NotificationData_t *notification = NULL;
//We try to get a notification from the free list.
if((notification = _notification_list_remove_tail(&notificationScreen->freeNotificationList)) == NULL)
{
//If that fails, we reuse the oldest notification from the used list.
if((notification = _notification_list_remove_tail(&notificationScreen->notificationList)) == NULL)
{
//That's bad
LV_LOG_ERROR("Unable to find a notification to reuse !");
return;
}
//Don't forget to free the allocated strings if not already done
tls_mem_free(notification->title);
tls_mem_free(notification->body);
}
notification->handle = handle;
notification->dateOfArrival = dateOfArrival;
notification->type = notificationType;
notification->title = title;
notification->body = body;
notification->read = false;
_notification_list_add_head(&notificationScreen->notificationList, notification);
switch(notificationType)
{
case NOTIFICATION_TYPE_CALL:
break;
default:
_display_message_notification(notificationScreen, notification);
if(notificationScreen->notificationOnStateChangeCb) notificationScreen->notificationOnStateChangeCb(NOTIFICATION_STATE_DISPLAYED);
}
}
void notification_screen_destroy(NotificationScreen_t * const notificationScreen)
{
if(!notificationScreen)
{
LV_LOG_ERROR("NULL pointer given !");
return;
}
}
bool _notification_list_is_empty(NotificationDataList_t notificationList)
{
return notificationList == NULL;
}
void _notification_list_add_head(NotificationDataList_t *notificationList, NotificationData_t *notification)
{
if(!notificationList || !notification) return;
if(_notification_list_is_empty(*notificationList))
*notificationList = notification;
else
{
notification->next = *notificationList;
*notificationList = notification;
}
}
NotificationData_t *_notification_list_remove_tail(NotificationDataList_t *notificationList)
{
if(!notificationList) return NULL;
if(_notification_list_is_empty(*notificationList)) return NULL;
NotificationData_t *toReturn = NULL;
//There is only one item in the list
if((*notificationList)->next == NULL)
{
toReturn = *notificationList;
*notificationList = NULL;
return toReturn;
}
NotificationDataList_t cursor = *notificationList;
while(!_notification_list_is_empty(cursor->next->next))
{
cursor = cursor->next;
}
toReturn = cursor->next;
cursor->next = NULL;
return toReturn;
}
uint8_t _notification_list_count(NotificationDataList_t notificationList)
{
uint8_t count = 0;
while(!_notification_list_is_empty(notificationList))
{
notificationList = notificationList->next;
count++;
}
return count;
}
void _display_message_notification(NotificationScreen_t * const notificationScreen, const NotificationData_t *notification)
{
//Create and display a graphical widget containing the notification
lv_obj_t *notification_display = lv_layer_top();
if(!notification_display)
{
LV_LOG_ERROR("Could not retrieve sys layer !");
return;
}
/*We can have two cases :
1) No notification is currently being displayed, so we create the needed UI objects
2) A notification is currently being shown and all UI elements were already created / allocated
*/
if(lv_obj_get_child_cnt(notification_display) == 0)
{
//Only allow to scroll down and not up (LV_DIR_TOP makes it, is it a bug ?)
lv_obj_set_scroll_dir(notification_display, LV_DIR_TOP);
lv_obj_add_event_cb(notification_display, &(notification_scrolled_event_cb), LV_EVENT_SCROLL_END, notificationScreen);
lv_obj_t *main_notification = lv_obj_create(notification_display);
lv_obj_set_size(main_notification, 202, 166);
lv_obj_set_style_pad_all(main_notification, 0, LV_PART_MAIN);
lv_obj_set_style_pad_top(main_notification, 10, LV_PART_MAIN);
lv_obj_set_style_border_width(main_notification, 0, LV_PART_MAIN);
lv_obj_set_style_radius(main_notification, 30, LV_PART_MAIN);
lv_obj_align(main_notification, LV_ALIGN_BOTTOM_MID,0,166);
lv_obj_set_style_bg_color(main_notification, lv_color_make(52, 93, 106), LV_PART_MAIN);
//lv_obj_set_style_opa(main_notification, 240, LV_PART_MAIN); //Opacity is too heavy on ram :-(
//Create the title, type and date labels
if(notificationScreen->type_label)
{
LV_LOG_ERROR("type_label should be NULL here !");
lv_obj_del(notificationScreen->type_label);
notificationScreen->type_label = NULL;
}
notificationScreen->type_label = lv_label_create(main_notification);
lv_obj_set_style_text_color(notificationScreen->type_label, lv_color_white(), LV_PART_MAIN);
lv_obj_set_style_pad_left(notificationScreen->type_label, 10, LV_PART_MAIN);
lv_label_set_long_mode(notificationScreen->type_label, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_obj_set_style_anim_speed(notificationScreen->type_label, 10, LV_PART_MAIN);
lv_obj_set_width(notificationScreen->type_label, lv_pct(27));
lv_label_set_text(notificationScreen->type_label, _notification_type_to_char(notification->type));
if(notificationScreen->title_label)
{
LV_LOG_ERROR("title_label should be NULL here !");
lv_obj_del(notificationScreen->title_label);
notificationScreen->title_label = NULL;
}
notificationScreen->title_label = lv_label_create(main_notification);
lv_obj_set_style_text_color(notificationScreen->title_label, lv_color_white(), LV_PART_MAIN);
lv_obj_align(notificationScreen->title_label, LV_ALIGN_TOP_MID, 0, 0);
lv_obj_set_style_anim_speed(notificationScreen->title_label, 10, LV_PART_MAIN);
lv_label_set_long_mode(notificationScreen->title_label, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_obj_set_width(notificationScreen->title_label, lv_pct(40));
lv_label_set_text_static(notificationScreen->title_label, notification->title);
if(notificationScreen->date_label)
{
LV_LOG_ERROR("date_label should be NULL here !");
lv_obj_del(notificationScreen->date_label);
notificationScreen->date_label = NULL;
}
notificationScreen->date_label = lv_label_create(main_notification);
lv_obj_set_style_pad_right(notificationScreen->date_label, 10, LV_PART_MAIN);
lv_obj_set_style_text_color(notificationScreen->date_label, lv_color_white(), LV_PART_MAIN);
lv_obj_align(notificationScreen->date_label, LV_ALIGN_TOP_RIGHT, 0, 0);
lv_label_set_text(notificationScreen->date_label, _notification_timestamp_to_date(notification->dateOfArrival));
//Create the sub-area in the notification
lv_obj_t *sub_area = lv_obj_create(main_notification);
lv_obj_set_style_pad_all(sub_area, 10, LV_PART_MAIN);
lv_obj_set_style_border_width(sub_area, 0, LV_PART_MAIN);
lv_obj_set_style_radius(sub_area, 0, LV_PART_MAIN);
lv_obj_set_width(sub_area, 202);
lv_obj_set_height(sub_area, 136);
lv_obj_align(sub_area, LV_ALIGN_BOTTOM_MID, 0, 0);
lv_obj_set_style_bg_color(sub_area, lv_color_make(22, 52, 62), LV_PART_MAIN);
//Create the main text
if(notificationScreen->body_label)
{
LV_LOG_ERROR("body_label should be NULL here !");
lv_obj_del(notificationScreen->body_label);
notificationScreen->body_label = NULL;
}
notificationScreen->body_label = lv_label_create(sub_area);
lv_obj_set_width(notificationScreen->body_label, 182);
lv_obj_set_style_text_color(notificationScreen->body_label, lv_color_white(), LV_PART_MAIN);
lv_obj_set_style_pad_all(notificationScreen->body_label, 0, LV_PART_MAIN);
lv_obj_set_style_pad_bottom(notificationScreen->body_label, 40, LV_PART_MAIN);
lv_label_set_long_mode(notificationScreen->body_label, LV_LABEL_LONG_WRAP);
lv_label_set_text_static(notificationScreen->body_label, notification->body);
lv_obj_scroll_to_y(notification_display, 166, LV_ANIM_ON);
}
else
{
LV_LOG_USER("A notification is already being displayed, updating it's content !");
//We just have to update the notification content
lv_label_set_text_static(notificationScreen->type_label, _notification_type_to_char(notification->type));
lv_label_set_text_static(notificationScreen->title_label, notification->title);
lv_label_set_text_static(notificationScreen->date_label, _notification_timestamp_to_date(notification->dateOfArrival));
lv_label_set_text_static(notificationScreen->body_label, notification->body);
}
}
void _notification_popup_destroy(NotificationScreen_t * const notificationScreen)
{
lv_obj_clean(lv_layer_top());
notificationScreen->type_label = NULL;
notificationScreen->title_label = NULL;
notificationScreen->date_label = NULL;
notificationScreen->body_label = NULL;
}
const char *_notification_type_to_char(NotificationType_e notificationType)
{
switch(notificationType)
{
case NOTIFICATION_TYPE_SMS:
return "Sms";
case NOTIFICATION_TYPE_EMAIL:
return "Email";
case NOTIFICATION_TYPE_WHATSAPP:
return "WhatsApp";
case NOTIFICATION_TYPE_GADGET_BRIDGE:
return "GadgetBridge";
case NOTIFICATION_TYPE_UNKNOWN:
default:
return "Unknown";
}
}
const char *_notification_timestamp_to_date(time_t timestamp)
{
static char date[9]; //Ex 7:23PM
struct tm *time = gmtime(&timestamp);
sprintf(date, "%s%d:%s%d", time->tm_hour > 10 ? "" : "0", time->tm_hour, time->tm_min > 10 ? "" : "0", time->tm_min);
return date;
}
void _notification_list_debug(NotificationDataList_t notificationList)
{
while(!_notification_list_is_empty(notificationList))
{
LV_LOG_USER("Notification handle :%u", notificationList->handle);
notificationList = notificationList->next;
}
}

View File

@ -0,0 +1,71 @@
#ifndef NOTIFICATION_SCREEN_H
#define NOTIFICATION_SCREEN_H
#include "lvgl.h"
#include <time.h>
/* The maximum number of notifications which will be stored before the oldest one gets discarded
to make room for the new one.
*/
#define MAX_NOTIFICATIONS_COUNT (10)
typedef enum NotificationType
{
NOTIFICATION_TYPE_SMS = 0,
NOTIFICATION_TYPE_EMAIL,
NOTIFICATION_TYPE_WHATSAPP,
NOTIFICATION_TYPE_GADGET_BRIDGE,
NOTIFICATION_TYPE_UNKNOWN,
/* This enum value has no match in GadgetBridge's enum */
NOTIFICATION_TYPE_CALL,
} NotificationType_e;
typedef enum NotificationState
{
NOTIFICATION_STATE_CLEARED = 0,
NOTIFICATION_STATE_DISPLAYED = 1,
} NotificationState_e;
typedef struct NotificationData
{
struct NotificationData *next;
uint32_t handle;
time_t dateOfArrival;
char *title;
char *body;
NotificationType_e type;
bool read; // Has the notification been read (aka closed by the user)
} NotificationData_t, *NotificationDataList_t;
typedef void (*NotificationOnStateChangeCb_t)(NotificationState_e notificationState);
typedef struct NotificationScreen
{
//Can be erased attributes
lv_obj_t *display;
//Should not be erased attributes
//Notification UI object
lv_obj_t *type_label;
lv_obj_t *title_label;
lv_obj_t *date_label;
lv_obj_t *body_label;
NotificationOnStateChangeCb_t notificationOnStateChangeCb;
//Notification history data structure
NotificationData_t notificationPool[MAX_NOTIFICATIONS_COUNT];
NotificationDataList_t notificationList; //Actual notifications
NotificationDataList_t freeNotificationList; //Free notification object pool
} NotificationScreen_t;
void notification_screen_init(NotificationScreen_t * const notificationScreen);
void notification_screen_register_on_state_change_cb(NotificationScreen_t * const notificationScreen, NotificationOnStateChangeCb_t notificationOnStateChangeCb);
void notification_screen_notify(NotificationScreen_t * const notificationScreen, uint32_t handle, time_t dateOfArrival, NotificationType_e notificationType, char * title, char * body);
void notification_screen_create(NotificationScreen_t * const notificationScreen);
void notification_screen_destroy(NotificationScreen_t * const notificationScreen);
#endif // NOTIFICATION_SCREEN_H

View File

@ -20,7 +20,7 @@ static const char* vibration_force = "1\n2\n3\n4\n5\n6\n7\n8";
static const char* language_options = "Francais\nDeutsch\nEnglish";
static lv_obj_t *add_menu_list_item(lv_obj_t *list, const char *text, lv_event_cb_t event_cb, void *user_data);
static lv_obj_t *add_menu_list_item(lv_obj_t *list, const char *text, lv_event_cb_t event_cb, void *user_data, SettingsScreenCategory_e category);
static void update_menu_list_item_text(lv_obj_t *menu_list_item, const char *text);
static void _simulate_side_screen_item_click(SettingsScreen_t * const settingsScreen, lv_obj_t *item);
@ -261,6 +261,8 @@ static void factory_reset_cb(lv_event_t *e)
static void about_refresh_timer_cb(lv_timer_t *timer)
{
SettingsScreen_t *settingsScreen = timer->user_data;
if(!settingsScreen->about_refresh_timer) return;
static uint8_t timer_divider = 6;
if(timer_divider++ == 6)
@ -275,9 +277,6 @@ static void about_refresh_timer_cb(lv_timer_t *timer)
static void load_time_and_date_side_screen(SettingsScreen_t *settingsScreen)
{
lv_obj_clean(settingsScreen->side_screen);
_reset_switch_pointers(settingsScreen);
uint8_t hour = 0, minute = 0, second = 0, day = 0, month = 0, year = 0;
if(settingsScreen->settingsScreenAPIInterface.setTimeSettingsCb)
settingsScreen->settingsScreenAPIInterface.setTimeSettingsCb(&hour, &minute, &second, &day, &month, &year, SETTING_MODE_GET);
@ -393,9 +392,6 @@ static void load_time_and_date_side_screen(SettingsScreen_t *settingsScreen)
static void load_display_side_screen(SettingsScreen_t *settingsScreen)
{
lv_obj_clean(settingsScreen->side_screen);
_reset_switch_pointers(settingsScreen);
lv_obj_t *label = lv_label_create(settingsScreen->side_screen);
lv_label_set_text_static(label, "Brightness :");
@ -483,9 +479,6 @@ static void load_display_side_screen(SettingsScreen_t *settingsScreen)
static void load_notifications_side_screen(SettingsScreen_t *settingsScreen)
{
lv_obj_clean(settingsScreen->side_screen);
_reset_switch_pointers(settingsScreen);
lv_obj_t *label = lv_label_create(settingsScreen->side_screen);
lv_label_set_text_static(label, "Vibrate on\nnotifications :");
@ -512,9 +505,6 @@ static void load_notifications_side_screen(SettingsScreen_t *settingsScreen)
static void load_connectivity_side_screen(SettingsScreen_t *settingsScreen)
{
lv_obj_clean(settingsScreen->side_screen);
_reset_switch_pointers(settingsScreen);
lv_obj_t *label = lv_label_create(settingsScreen->side_screen);
lv_label_set_text_static(label, "Connectivity :");
@ -588,9 +578,6 @@ static void load_connectivity_side_screen(SettingsScreen_t *settingsScreen)
static void load_language_side_screen(SettingsScreen_t *settingsScreen)
{
lv_obj_clean(settingsScreen->side_screen);
_reset_switch_pointers(settingsScreen);
lv_obj_t *label = lv_label_create(settingsScreen->side_screen);
lv_label_set_text_static(label, "Language :");
@ -605,9 +592,6 @@ static void load_language_side_screen(SettingsScreen_t *settingsScreen)
static void load_about_side_screen(SettingsScreen_t *settingsScreen)
{
lv_obj_clean(settingsScreen->side_screen);
_reset_switch_pointers(settingsScreen);
lv_obj_t *label = lv_label_create(settingsScreen->side_screen);
lv_label_set_text_static(label, "System Info :");
@ -723,6 +707,17 @@ void settings_screen_init(SettingsScreen_t * const settingsScreen)
memset(settingsScreen, 0, sizeof(SettingsScreen_t));
}
void settings_screen_register_on_state_change_cb(SettingsScreen_t * const settingsScreen, SettingsScreenOnStateChangeCb_t settingsScreenOnStateChangeCb)
{
if(!settingsScreen)
{
LV_LOG_ERROR("NULL pointer given !");
return;
}
settingsScreen->settingsScreenOnStateChangeCb = settingsScreenOnStateChangeCb;
}
void settings_screen_register_API_interface(SettingsScreen_t * const settingsScreen, SettingsScreenAPIInterface_t * const settingsScreenAPIInterface)
{
if(!settingsScreen)
@ -745,7 +740,7 @@ void settings_screen_create(SettingsScreen_t * const settingsScreen)
return;
}
//We create our parent screen :
// We create our parent screen :
if(settingsScreen->display)
{
LV_LOG_ERROR("display should be NULL here !");
@ -754,10 +749,10 @@ void settings_screen_create(SettingsScreen_t * const settingsScreen)
}
settingsScreen->display = lv_obj_create(NULL);
//We add the screen header
// We add the screen header
common_screen_header_component(settingsScreen->display, translation_get_word(TRANSLATION_SETTINGS), 50);
//We create the menu list on the left hand side
// We create the menu list on the left hand side
lv_obj_t *menu_list = lv_list_create(settingsScreen->display);
lv_obj_set_size(menu_list, 75,190);
lv_obj_set_pos(menu_list, 0, 50);
@ -767,7 +762,7 @@ void settings_screen_create(SettingsScreen_t * const settingsScreen)
lv_obj_set_style_pad_left(menu_list, 0, LV_PART_MAIN);
lv_obj_set_style_pad_bottom(menu_list, 50, LV_PART_MAIN);
//We add the side screen containing the settings
// We add the side screen containing the settings
settingsScreen->side_screen = lv_obj_create(settingsScreen->display);
lv_obj_set_size(settingsScreen->side_screen, 165,190);
lv_obj_set_pos(settingsScreen->side_screen, 75, 50);
@ -777,20 +772,20 @@ void settings_screen_create(SettingsScreen_t * const settingsScreen)
lv_obj_set_style_pad_bottom(settingsScreen->side_screen, 70, LV_PART_MAIN);
lv_obj_set_scroll_dir(settingsScreen->side_screen, LV_DIR_VER);
//We add all the menu list items
settingsScreen->time_and_date_item = add_menu_list_item(menu_list, translation_get_word(TRANSLATION_TIME_AND_DATE), &(menu_list_item_event_handler), settingsScreen);
settingsScreen->display_item = add_menu_list_item(menu_list, translation_get_word(TRANSLATION_DISPLAY), &(menu_list_item_event_handler), settingsScreen);
settingsScreen->notifications_item = add_menu_list_item(menu_list, translation_get_word(TRANSLATION_NOTIFICATIONS), &(menu_list_item_event_handler), settingsScreen);
settingsScreen->connectivity_item = add_menu_list_item(menu_list, translation_get_word(TRANSLATION_CONNECTIVITY), &(menu_list_item_event_handler), settingsScreen);
settingsScreen->language_item = add_menu_list_item(menu_list, translation_get_word(TRANSLATION_LANGUAGE), &(menu_list_item_event_handler), settingsScreen);
settingsScreen->about_item = add_menu_list_item(menu_list, translation_get_word(TRANSLATION_ABOUT), &(menu_list_item_event_handler), settingsScreen);
// We add all the menu list items
settingsScreen->time_and_date_item = add_menu_list_item(menu_list, translation_get_word(TRANSLATION_TIME_AND_DATE), &(menu_list_item_event_handler), settingsScreen, SETTINGS_SCREEN_CATEGORY_TIME_AND_DATE);
settingsScreen->display_item = add_menu_list_item(menu_list, translation_get_word(TRANSLATION_DISPLAY), &(menu_list_item_event_handler), settingsScreen, SETTINGS_SCREEN_CATEGORY_DISPLAY);
settingsScreen->notifications_item = add_menu_list_item(menu_list, translation_get_word(TRANSLATION_NOTIFICATIONS), &(menu_list_item_event_handler), settingsScreen, SETTINGS_SCREEN_CATEGORY_NOTIFICATION);
settingsScreen->connectivity_item = add_menu_list_item(menu_list, translation_get_word(TRANSLATION_CONNECTIVITY), &(menu_list_item_event_handler), settingsScreen, SETTINGS_SCREEN_CATEGORY_CONNECTIVITY);
settingsScreen->language_item = add_menu_list_item(menu_list, translation_get_word(TRANSLATION_LANGUAGE), &(menu_list_item_event_handler), settingsScreen, SETTINGS_SCREEN_CATEGORY_LANGUAGE);
settingsScreen->about_item = add_menu_list_item(menu_list, translation_get_word(TRANSLATION_ABOUT), &(menu_list_item_event_handler), settingsScreen, SETTINGS_SCREEN_CATEGORY_ABOUT);
//We register the event callback to handle gesture
// We register the event callback to handle gesture
lv_obj_add_event_cb(settingsScreen->display, &(gesture_event_cb), LV_EVENT_GESTURE, settingsScreen);
//We register the event callback to handle the cleanup
// We register the event callback to handle the cleanup
lv_obj_add_event_cb(settingsScreen->display, &(cleanup_event_cb), LV_EVENT_DELETE, settingsScreen);
//We load the default side screen content (time and date)
// We load the default side screen content (time and date)
_simulate_side_screen_item_click(settingsScreen, settingsScreen->time_and_date_item);
}
@ -802,6 +797,12 @@ void settings_screen_destroy(SettingsScreen_t * const settingsScreen)
return;
}
if (settingsScreen->last_selected_item)
{
if (settingsScreen->settingsScreenOnStateChangeCb)
settingsScreen->settingsScreenOnStateChangeCb(SETTINGS_SCREEN_STATE_CLOSED, (SettingsScreenCategory_e)lv_obj_get_user_data(settingsScreen->last_selected_item));
}
settingsScreen->hour_roller = NULL;
settingsScreen->minute_roller = NULL;
settingsScreen->second_roller = NULL;
@ -823,13 +824,26 @@ static void _simulate_side_screen_item_click(SettingsScreen_t * const settingsSc
settingsScreen->about_refresh_timer = NULL;
}
//Updating the background of the selected category
// Updating the background of the selected category
lv_obj_set_style_bg_color(item, lv_color_make(178, 223, 219), LV_PART_MAIN);
if(settingsScreen->last_selected_item)
lv_obj_set_style_bg_color(settingsScreen->last_selected_item, lv_color_white(), LV_PART_MAIN);
// Let's call the settings screen on state change callback if registered
if(settingsScreen->settingsScreenOnStateChangeCb)
settingsScreen->settingsScreenOnStateChangeCb(SETTINGS_SCREEN_STATE_OPENED, (SettingsScreenCategory_e)lv_obj_get_user_data(item));
if(settingsScreen->last_selected_item)
{
if(settingsScreen->settingsScreenOnStateChangeCb)
settingsScreen->settingsScreenOnStateChangeCb(SETTINGS_SCREEN_STATE_CLOSED, (SettingsScreenCategory_e)lv_obj_get_user_data(settingsScreen->last_selected_item));
}
settingsScreen->last_selected_item = item;
lv_obj_clean(settingsScreen->side_screen);
_reset_switch_pointers(settingsScreen);
if(item == settingsScreen->time_and_date_item)
{
load_time_and_date_side_screen(settingsScreen);
@ -861,7 +875,10 @@ static void _set_rtc_time_to_label(SettingsScreen_t * const settingsScreen)
uint8_t hour = 0, minute = 0, second = 0, day = 0, month = 0, year = 0;
if(settingsScreen->settingsScreenAPIInterface.setTimeSettingsCb)
settingsScreen->settingsScreenAPIInterface.setTimeSettingsCb(&hour, &minute, &second, &day, &month, &year, SETTING_MODE_GET);
sprintf(settingsScreen->currentTime.current_time_text, "%u:%u:%u %s%u/%s%u/%u", hour, minute, second,
sprintf(settingsScreen->currentTime.current_time_text, "%s%u:%s%u:%s%u %s%u/%s%u/%u",
hour < 10 ? "0":"", hour,
minute < 10 ? "0":"", minute,
second < 10 ? "0":"", second,
day < 10 ? "0":"", day,
month + 1 < 10 ? "0":"", month + 1,
year+1900);
@ -951,7 +968,7 @@ static void _enable_time_and_date_rollers(bool enabled, SettingsScreen_t * const
}
}
static lv_obj_t *add_menu_list_item(lv_obj_t *list, const char *text, lv_event_cb_t event_cb, void *user_data)
static lv_obj_t *add_menu_list_item(lv_obj_t *list, const char *text, lv_event_cb_t event_cb, void *user_data, SettingsScreenCategory_e category)
{
lv_obj_t *btn = lv_list_add_btn(list, NULL, text);
lv_obj_t *label = lv_obj_get_child(btn, 0);
@ -962,6 +979,7 @@ static lv_obj_t *add_menu_list_item(lv_obj_t *list, const char *text, lv_event_c
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
}
lv_obj_set_user_data(btn, (void *)category);
lv_obj_add_event_cb(btn, event_cb, LV_EVENT_CLICKED, user_data);
return btn;
}

View File

@ -33,6 +33,24 @@ typedef struct SettingsScreenAPIInterface
void (*factoryResetCb)(void);
} SettingsScreenAPIInterface_t;
typedef enum SettingsScreenState
{
SETTINGS_SCREEN_STATE_OPENED = 0,
SETTINGS_SCREEN_STATE_CLOSED
} SettingsScreenState_e;
typedef enum SettingsScreenCategory
{
SETTINGS_SCREEN_CATEGORY_TIME_AND_DATE = 0,
SETTINGS_SCREEN_CATEGORY_DISPLAY,
SETTINGS_SCREEN_CATEGORY_NOTIFICATION,
SETTINGS_SCREEN_CATEGORY_CONNECTIVITY,
SETTINGS_SCREEN_CATEGORY_LANGUAGE,
SETTINGS_SCREEN_CATEGORY_ABOUT,
} SettingsScreenCategory_e;
typedef void (*SettingsScreenOnStateChangeCb_t)(SettingsScreenState_e settingsScreenState, SettingsScreenCategory_e settingsScreenCategory);
typedef struct SettingsScreen
{
SettingsScreenAPIInterface_t settingsScreenAPIInterface;
@ -108,10 +126,21 @@ typedef struct SettingsScreen
/* Other */
lv_timer_t *about_refresh_timer;
SettingsScreenOnStateChangeCb_t settingsScreenOnStateChangeCb;
} SettingsScreen_t;
void settings_screen_init(SettingsScreen_t * const settingsScreen);
/**
* @brief Registers a callback function which will be called every time the state of the application changes ie : is opened or closed.
* This callback should be used to initialize and deinitialize needed devices drivers like the magnetometer or the temperature sensor.
* @note The state of the application is passed as a parameter or the callback function.
*
* @param settingsScreen a pointer to the settings screen object structure.
* @param SettingsScreenOnStateChangeCb the callback of type @ref SettingsScreenOnStateChangeCb_t to register.
*/
void settings_screen_register_on_state_change_cb(SettingsScreen_t * const settingsScreen, SettingsScreenOnStateChangeCb_t SettingsScreenOnStateChangeCb);
void settings_screen_register_API_interface(SettingsScreen_t * const settingsScreen, SettingsScreenAPIInterface_t * const settingsScreenAPIInterface);
void settings_screen_create(SettingsScreen_t * const settingsScreen);

View File

@ -303,11 +303,7 @@ void watch_face_create(WatchFace_t * const watchFace)
lv_obj_del(watchFace->batteryIndicator.batteryIcon);
watchFace->batteryIndicator.batteryIcon = NULL;
}
watchFace->batteryIndicator.batteryIcon = lv_img_create(watchFace->display);
set_battery_state_icon(watchFace);
lv_img_set_zoom(watchFace->batteryIndicator.batteryIcon, 141);
lv_obj_align_to(watchFace->batteryIndicator.batteryIcon, watchFace->batteryIndicator.label, LV_ALIGN_OUT_BOTTOM_MID, 0, -9);
if(watchFace->batteryIndicator.lowBatteryAnimationTimer)
{
@ -318,6 +314,12 @@ void watch_face_create(WatchFace_t * const watchFace)
watchFace->batteryIndicator.lowBatteryAnimationTimer = lv_timer_create(&(battery_timer_anim_cb), 500, watchFace);
lv_timer_pause(watchFace->batteryIndicator.lowBatteryAnimationTimer);
// set_battery_state_icon internally needs to interact with the lowBatteryAnimationTimer,
// this is why we call the function after the timer has been created
set_battery_state_icon(watchFace);
lv_img_set_zoom(watchFace->batteryIndicator.batteryIcon, 141);
lv_obj_align_to(watchFace->batteryIndicator.batteryIcon, watchFace->batteryIndicator.label, LV_ALIGN_OUT_BOTTOM_MID, 0, -9);
// Bluetooth status icon is created here
if(watchFace->bluetoothIndicator.bluetoothIcon)
{

View File

@ -49,7 +49,7 @@
#define LV_MEM_CUSTOM 0
#if LV_MEM_CUSTOM == 0
/*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/
#define LV_MEM_SIZE (30 * 1024U) /*[bytes]*/
#define LV_MEM_SIZE (35 * 1024U) /*[bytes]*/
/*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/
#define LV_MEM_ADR 0 /*0: unused*/

View File

@ -6,6 +6,7 @@
* @version 0.1
* @date 2023-04-05
* Updated : 2023-10-15, fixed potential memory leak.
* Updated : 2023-10-17, fixed potential issue where a double quote is added at the start of a parsed string.
*
* @copyright MIT
*
@ -252,7 +253,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
{
case GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE:
// To prevent a potential memory leak if the parser is fed with bad data
// To prevent a potential memory leak if the parser is fed with ill formed data
_free_event_data();
if((start = strstr(_gadget_bridge_internals.buffer, "setTime("))
@ -428,7 +429,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
else to_return = GADGET_BRIDGE_PARSER_CODE_OK;
break;
case GADGET_BRIDGE_PARSER_FSM_FOUND_ID_SRC:
if((start = strstr(_gadget_bridge_internals.buffer, "src:")) &&
if((start = strstr(_gadget_bridge_internals.buffer, "src:\"")) &&
((end = strstr(_gadget_bridge_internals.buffer, ",title")) || (end2 = strstr(_gadget_bridge_internals.buffer, ",subject"))))
{
if((end && !end2) || (end != NULL && end < end2))
@ -458,7 +459,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
else to_return = GADGET_BRIDGE_PARSER_CODE_OK;
break;
case GADGET_BRIDGE_PARSER_FSM_FOUND_TITLE:
if((start = strstr(_gadget_bridge_internals.buffer, "title:")))
if((start = strstr(_gadget_bridge_internals.buffer, "title:\"")))
{
printf("###Parsing TITLE content\n");
@ -512,7 +513,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
}
break;
case GADGET_BRIDGE_PARSER_FSM_FOUND_SRC_BODY:
if((start = strstr(_gadget_bridge_internals.buffer, "body:")))
if((start = strstr(_gadget_bridge_internals.buffer, "body:\"")))
{
printf("###Parsing BODY content\n");
@ -704,7 +705,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
_gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE;
break;*/
case GADGET_BRIDGE_PARSER_FSM_FOUND_SUBJECT:
if((start = strstr(_gadget_bridge_internals.buffer, "subject:")))
if((start = strstr(_gadget_bridge_internals.buffer, "subject:\"")))
{
printf("###Parsing SUBJECT content\n");

View File

@ -202,7 +202,7 @@ typedef struct gadget_bridge_event_data
};
} gadget_bridge_event_data_t;
typedef void (*parser_event_callback_t)(const gadget_bridge_event_data_t *gadget_bridge_event_data);
typedef void (*parser_event_callback_t)(gadget_bridge_event_data_t *gadget_bridge_event_data);
/**
* @brief Sends an Android toast to GadgetBridge to be displayed on the phone.

View File

@ -50,18 +50,19 @@
<stdlib.h>
<string.h>
1696357704 source:d:\users\think\documents\w800_smart_watch\src\gadget_bridge_parser\gadget_bridge.c
1697540423 source:d:\users\think\documents\w800_smart_watch\src\gadget_bridge_parser\gadget_bridge.c
"gadget_bridge.h"
<stdio.h>
<stdlib.h>
<string.h>
<assert.h>
1695293778 d:\users\think\documents\w800_smart_watch\src\gadget_bridge_parser\gadget_bridge.h
1696487243 d:\users\think\documents\w800_smart_watch\src\gadget_bridge_parser\gadget_bridge.h
<stdint.h>
<stdbool.h>
<time.h>
1695293778 source:d:\users\think\documents\w800_smart_watch\src\gadget_bridge_parser\main.c
1697572727 source:d:\users\think\documents\w800_smart_watch\src\gadget_bridge_parser\main.c
<stdio.h>
<stdlib.h>
<string.h>

View File

@ -7,14 +7,14 @@
<Cursor1 position="4496" topLine="288" />
</Cursor>
</File>
<File name="gadget_bridge.c" open="1" top="1" tabpos="1" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="gadget_bridge.c" open="1" top="0" tabpos="1" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="71209" topLine="1490" />
<Cursor1 position="35064" topLine="963" />
</Cursor>
</File>
<File name="main.c" open="1" top="0" tabpos="3" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="11686" topLine="156" />
<Cursor1 position="11548" topLine="333" />
</Cursor>
</File>
</CodeBlocks_layout_file>

View File

@ -39,7 +39,7 @@ GB({t:"act",hrm:false,stp:true,int:10})[10]
[16]GB({t:"act",hrm:false,stp:false,int:10})[10]
**/
void parser_event(const gadget_bridge_event_data_t *gadget_bridge_event_data)
void parser_event(gadget_bridge_event_data_t *gadget_bridge_event_data)
{
printf("----------->Event of type : %s\n", gadget_bridge_event_type_2_str(gadget_bridge_event_data->event_type));
@ -351,6 +351,11 @@ const char *sample[] =
"ux pour la backyard ",
"!\nEncore bravo :cla",
"p::+1:\"})[10]",
"[16]GB({t:\"notify\",id",
":1697570919,src:\"Gadget",
"bridge\",subject:\"12345678912345678912345678912345678\",body:\"12345678912345678912345678912345678\",sender:\"12345678912345678912345678912345678\",tel:\"12345678912345678912345678912345678\"})[10]"
};
int main()

View File

@ -2,373 +2,204 @@
<CodeBlocks_layout_file>
<FileVersion major="1" minor="0" />
<ActiveTarget name="Debug" />
<File name="lvgl\lv_conf_template.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="56" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_timer.h" open="0" top="0" tabpos="10" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="635" topLine="36" />
</Cursor>
</File>
<File name="lvgl\src\draw\lv_draw_img.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="5230" topLine="191" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_disp.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="7126" topLine="230" />
</Cursor>
</File>
<File name="lvgl\src\layouts\flex\lv_flex.c" open="0" top="0" tabpos="8" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3097" topLine="74" />
</Cursor>
</File>
<File name="compass_assets.c" open="0" top="0" tabpos="13" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="143" />
</Cursor>
</File>
<File name="music_player_screen.h" open="1" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1263" topLine="24" />
</Cursor>
</File>
<File name="lvgl\examples\widgets\bar\lv_example_bar_6.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="181" topLine="0" />
</Cursor>
</File>
<File name="lv_drv_conf.h" open="0" top="0" tabpos="3" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="6602" topLine="208" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_indev_scroll.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="14405" topLine="323" />
</Cursor>
</File>
<File name="firmware_version.h" open="0" top="0" tabpos="9" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="160" topLine="0" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_area.h" open="0" top="0" tabpos="15" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1789" topLine="74" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_class.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1857" topLine="35" />
</Cursor>
</File>
<File name="lvgl\src\widgets\chart\lv_chart.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="11658" topLine="336" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_log.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1509" topLine="59" />
</Cursor>
</File>
<File name="lvgl\src\widgets\label\lv_label.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="5648" topLine="194" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_scroll.h" open="0" top="0" tabpos="16" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1988" topLine="67" />
</Cursor>
</File>
<File name="menu_screen.c" open="0" top="0" tabpos="11" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1107" topLine="0" />
</Cursor>
</File>
<File name="compass_screen.c" open="0" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3567" topLine="72" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_timer.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="5053" topLine="144" />
</Cursor>
</File>
<File name="lvgl\src\libs\ffmpeg\lv_ffmpeg.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="5784" topLine="170" />
</Cursor>
</File>
<File name="notification_screen.h" open="1" top="0" tabpos="1" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="387" topLine="0" />
</Cursor>
</File>
<File name="lvgl\src\draw\lv_draw_rect.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="539" topLine="9" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_disp.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="6135" topLine="182" />
</Cursor>
</File>
<File name="lv_drivers\lv_drv_conf_template.h" open="0" top="0" tabpos="11" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="10670" topLine="390" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_indev.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3034" topLine="107" />
</Cursor>
</File>
<File name="lv_drivers\win32drv\win32drv.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="524" topLine="954" />
</Cursor>
</File>
<File name="altimeter_screen.h" open="0" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1028" topLine="30" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj.h" open="0" top="0" tabpos="10" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2638" topLine="87" />
</Cursor>
</File>
<File name="lvgl\src\widgets\menu\lv_menu.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3706" topLine="117" />
</Cursor>
</File>
<File name="watch_face.h" open="0" top="0" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3688" topLine="16" />
</Cursor>
</File>
<File name="lvgl\src\hal\lv_hal_indev.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="5065" topLine="123" />
</Cursor>
</File>
<File name="lv_conf.h" open="0" top="0" tabpos="5" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="555" topLine="10" />
</Cursor>
</File>
<File name="lvgl\src\widgets\list\lv_list.h" open="0" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="721" topLine="16" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="7842" topLine="283" />
</Cursor>
</File>
<File name="lvgl\src\layouts\grid\lv_grid.h" open="0" top="0" tabpos="13" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="579" topLine="17" />
</Cursor>
</File>
<File name="find_my_phone_screen.c" open="0" top="0" tabpos="10" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1081" topLine="138" />
</Cursor>
</File>
<File name="lv_drivers\indev\keyboard.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="440" topLine="14" />
</Cursor>
</File>
<File name="lvgl\src\widgets\tileview\lv_tileview.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1055" topLine="40" />
</Cursor>
<Folding>
<Collapse line="8" />
<Collapse line="995" />
</Folding>
</File>
<File name="lvgl\demos\widgets\lv_demo_widgets.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2825" topLine="122" />
</Cursor>
</File>
<File name="lvgl\src\font\lv_symbol_def.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1135" topLine="14" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_pos.c" open="0" top="0" tabpos="12" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="10562" topLine="336" />
</Cursor>
</File>
<File name="lvgl\src\widgets\roller\lv_roller.h" open="0" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="715" topLine="26" />
</Cursor>
</File>
<File name="lvgl\src\hal\lv_hal_disp.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="10233" topLine="226" />
</Cursor>
</File>
<File name="lvgl\lvgl.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="138" />
</Cursor>
</File>
<File name="main.c" open="1" top="0" tabpos="3" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3368" topLine="116" />
</Cursor>
</File>
<File name="lvgl\src\layouts\flex\lv_flex.h" open="0" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="950" topLine="43" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_types.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1759" topLine="61" />
</Cursor>
</File>
<File name="watch_casio_assets.c" open="0" top="0" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2981397" topLine="949" />
</Cursor>
</File>
<File name="lvgl\src\widgets\imgbtn\lv_imgbtn.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2184" topLine="61" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_pos.h" open="0" top="0" tabpos="4" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="7730" topLine="167" />
</Cursor>
</File>
<File name="lvgl\src\widgets\label\lv_label.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1299" topLine="36" />
</Cursor>
</File>
<File name="lvgl\src\hal\lv_hal_disp.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="11123" topLine="327" />
</Cursor>
</File>
<File name="altimeter_screen.c" open="0" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="13638" topLine="409" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_tree.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2082" topLine="62" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_style.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="7273" topLine="217" />
</Cursor>
</File>
<File name="notification_screen.c" open="1" top="1" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2746" topLine="48" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_style_gen.h" open="0" top="0" tabpos="11" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="13017" topLine="346" />
</Cursor>
</File>
<File name="settings_screen.h" open="0" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1893" topLine="40" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_refr.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2447" topLine="75" />
</Cursor>
</File>
<File name="lv_drivers\win_drv.h" open="0" top="0" tabpos="10" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="585" topLine="0" />
</Cursor>
</File>
<File name="lvgl\src\font\lv_font.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="lvgl\src\widgets\menu\lv_menu.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="5535" topLine="120" />
<Cursor1 position="3706" topLine="117" />
</Cursor>
</File>
<File name="compass_screen.h" open="0" top="0" tabpos="8" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="music_player_screen.c" open="0" top="0" tabpos="4" split="0" active="1" splitpos="0" zoom_1="1" zoom_2="0">
<Cursor>
<Cursor1 position="1253" topLine="0" />
<Cursor1 position="22334" topLine="0" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_class.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="lvgl\lv_conf_template.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3011" topLine="100" />
<Cursor1 position="0" topLine="56" />
</Cursor>
</File>
<File name="settings_screen.c" open="0" top="0" tabpos="5" split="0" active="1" splitpos="513" zoom_1="0" zoom_2="0">
<File name="find_my_phone_screen.h" open="0" top="0" tabpos="9" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="37082" topLine="603" />
<Cursor1 position="1078" topLine="3" />
</Cursor>
</File>
<File name="lv_drivers\win32drv\win32drv.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="lvgl\src\misc\lv_timer.h" open="0" top="0" tabpos="10" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="15" />
<Cursor1 position="2886" topLine="90" />
</Cursor>
</File>
<File name="lvgl\demos\widgets\lv_demo_widgets.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="lv_drivers\lv_drv_conf_template.h" open="0" top="0" tabpos="11" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="456" topLine="6" />
<Cursor1 position="10670" topLine="390" />
</Cursor>
</File>
<File name="lvgl\src\widgets\img\lv_img.h" open="0" top="0" tabpos="3" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="lvgl\src\draw\lv_draw_img.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="4439" topLine="123" />
<Cursor1 position="5230" topLine="191" />
</Cursor>
</File>
<File name="lvgl\src\widgets\imgbtn\lv_imgbtn.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="lvgl\examples\widgets\bar\lv_example_bar_6.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2129" topLine="53" />
<Cursor1 position="181" topLine="0" />
</Cursor>
</File>
<File name="lvgl\src\font\lv_font_montserrat_12.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="lvgl\src\hal\lv_hal_indev.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="22" />
<Cursor1 position="5065" topLine="123" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_color.c" open="0" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="lvgl\src\widgets\list\lv_list.h" open="0" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="10782" topLine="316" />
<Cursor1 position="721" topLine="16" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_event.h" open="0" top="0" tabpos="4" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="compass_screen.c" open="0" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="5693" topLine="115" />
<Cursor1 position="1480" topLine="179" />
</Cursor>
</File>
<File name="lv_drivers\display\monitor.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="289" topLine="31" />
</Cursor>
</File>
<File name="lvgl\src\hal\lv_hal_disp.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="10233" topLine="226" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_style.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="9059" topLine="242" />
</Cursor>
</File>
<File name="lv_drivers\display\SSD1963.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1563" topLine="27" />
</Cursor>
</File>
<File name="lvgl\src\layouts\flex\lv_flex.h" open="0" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="950" topLine="43" />
</Cursor>
</File>
<File name="lvgl\src\widgets\list\lv_list.c" open="0" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="2" zoom_2="0">
<Cursor>
<Cursor1 position="2391" topLine="53" />
</Cursor>
</File>
<File name="menu_screen.c" open="0" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="8350" topLine="165" />
</Cursor>
</File>
<File name="altimeter_screen.h" open="0" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1028" topLine="31" />
</Cursor>
</File>
<File name="lvgl\src\widgets\label\lv_label.h" open="0" top="0" tabpos="9" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="969" topLine="39" />
</Cursor>
</File>
<File name="settings_screen.c" open="1" top="0" tabpos="1" split="0" active="1" splitpos="513" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="6343" topLine="145" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="7842" topLine="283" />
</Cursor>
</File>
<File name="watch_face.h" open="0" top="0" tabpos="14" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="225" topLine="6" />
</Cursor>
</File>
<File name="lvgl\src\font\lv_font_fmt_txt.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="24" />
</Cursor>
</File>
<File name="lvgl\src\layouts\flex\lv_flex.c" open="0" top="0" tabpos="8" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3097" topLine="74" />
</Cursor>
</File>
<File name="altimeter_screen_assets.c" open="0" top="0" tabpos="19" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="96342" topLine="161" />
</Cursor>
</File>
<File name="lvgl\src\widgets\chart\lv_chart.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="11658" topLine="336" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_tree.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1234" topLine="30" />
</Cursor>
</File>
<File name="lv_drivers\win32drv\win32drv.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="524" topLine="954" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_class.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1857" topLine="35" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_event.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="5365" topLine="214" />
</Cursor>
</File>
<File name="watch_face.c" open="1" top="0" tabpos="4" split="0" active="1" splitpos="702" zoom_1="0" zoom_2="-1">
<Cursor>
<Cursor1 position="8554" topLine="425" />
</Cursor>
</File>
<File name="lvgl\src\draw\lv_img_buf.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="6210" topLine="113" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_style_gen.c" open="0" top="0" tabpos="11" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="20039" topLine="604" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_event.h" open="1" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="11297" topLine="329" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_log.h" open="0" top="0" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2557" topLine="68" />
</Cursor>
</File>
<File name="lvgl\lvgl.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="138" />
</Cursor>
</File>
<File name="watch_menu_icons.c" open="0" top="0" tabpos="18" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="869291" topLine="156" />
<Cursor1 position="965838" topLine="209" />
</Cursor>
<Folding>
<Collapse line="2" />
@ -391,124 +222,39 @@
<Collapse line="1729" />
</Folding>
</File>
<File name="lvgl\src\widgets\menu\lv_menu.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3321" topLine="109" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_anim.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3835" topLine="68" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_log.h" open="0" top="0" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2557" topLine="68" />
</Cursor>
</File>
<File name="lv_drivers\display\SSD1963.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1563" topLine="27" />
</Cursor>
</File>
<File name="lvgl\src\draw\lv_img_buf.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="6210" topLine="113" />
</Cursor>
</File>
<File name="lvgl\src\lv_api_map.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="722" topLine="32" />
</Cursor>
</File>
<File name="lvgl\demos\widgets\assets\img_demo_widgets_avatar.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1282774" topLine="472" />
</Cursor>
</File>
<File name="lvgl\src\font\lv_font_montserrat_30.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="869" topLine="0" />
</Cursor>
</File>
<File name="lvgl\src\widgets\img\lv_img.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1863" topLine="59" />
</Cursor>
</File>
<File name="music_player_screen.c" open="1" top="0" tabpos="4" split="0" active="1" splitpos="0" zoom_1="1" zoom_2="0">
<Cursor>
<Cursor1 position="4937" topLine="104" />
</Cursor>
</File>
<File name="lv_drivers\display\monitor.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="289" topLine="31" />
</Cursor>
</File>
<File name="lvgl\src\widgets\list\lv_list.c" open="0" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="2" zoom_2="0">
<Cursor>
<Cursor1 position="2391" topLine="53" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_style_gen.c" open="0" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="6152" topLine="192" />
</Cursor>
</File>
<File name="lvgl\src\font\lv_font_fmt_txt.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="24" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_color.h" open="0" top="0" tabpos="5" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="6812" topLine="189" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_scroll.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="12525" topLine="363" />
</Cursor>
</File>
<File name="lvgl\src\hal\lv_hal_indev.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3566" topLine="102" />
</Cursor>
</File>
<File name="altimeter_screen_assets.c" open="0" top="0" tabpos="19" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="lvgl\demos\widgets\lv_demo_widgets.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="96342" topLine="161" />
<Cursor1 position="2825" topLine="122" />
</Cursor>
</File>
<File name="watch_face.c" open="0" top="0" tabpos="1" split="0" active="1" splitpos="702" zoom_1="1" zoom_2="-1">
<File name="compass_screen.h" open="0" top="0" tabpos="8" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="15425" topLine="414" />
<Cursor1 position="3981" topLine="81" />
</Cursor>
</File>
<File name="lvgl\src\widgets\spinbox\lv_spinbox.h" open="0" top="0" tabpos="18" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="lv_drv_conf.h" open="0" top="0" tabpos="3" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="4262" topLine="120" />
<Cursor1 position="6602" topLine="208" />
</Cursor>
</File>
<File name="find_my_phone_screen.h" open="0" top="0" tabpos="9" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="lvgl\src\misc\lv_log.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1078" topLine="3" />
<Cursor1 position="1509" topLine="59" />
</Cursor>
</File>
<File name="common_screen_components.h" open="0" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="lvgl\src\core\lv_obj_scroll.h" open="0" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="517" topLine="0" />
<Cursor1 position="4372" topLine="104" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_style.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="lvgl\src\libs\ffmpeg\lv_ffmpeg.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3064" topLine="106" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_tree.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1234" topLine="139" />
<Cursor1 position="5784" topLine="170" />
</Cursor>
</File>
<File name="lvgl\examples\widgets\menu\lv_example_menu_5.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
@ -516,14 +262,273 @@
<Cursor1 position="7631" topLine="141" />
</Cursor>
</File>
<File name="menu_screen.h" open="0" top="0" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="find_my_phone_screen.c" open="0" top="0" tabpos="10" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1081" topLine="138" />
</Cursor>
</File>
<File name="lvgl\src\draw\lv_draw_rect.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="539" topLine="9" />
</Cursor>
</File>
<File name="lvgl\src\lv_api_map.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="722" topLine="32" />
</Cursor>
</File>
<File name="lvgl\src\widgets\spinbox\lv_spinbox.h" open="0" top="0" tabpos="18" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="4262" topLine="120" />
</Cursor>
</File>
<File name="music_player_screen.h" open="0" top="0" tabpos="15" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1263" topLine="38" />
</Cursor>
</File>
<File name="lvgl\src\font\lv_font.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="5535" topLine="120" />
</Cursor>
</File>
<File name="lvgl\src\font\lv_symbol_def.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1135" topLine="14" />
</Cursor>
</File>
<File name="notification_screen.h" open="1" top="0" tabpos="3" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2362" topLine="27" />
</Cursor>
</File>
<File name="lvgl\demos\widgets\lv_demo_widgets.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="456" topLine="6" />
</Cursor>
</File>
<File name="lv_conf.h" open="0" top="0" tabpos="8" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="572" topLine="15" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_area.h" open="0" top="0" tabpos="15" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="8525" topLine="257" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_types.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1759" topLine="61" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_pos.h" open="0" top="0" tabpos="4" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="11878" topLine="258" />
</Cursor>
</File>
<File name="lvgl\src\widgets\menu\lv_menu.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3321" topLine="109" />
</Cursor>
</File>
<File name="menu_screen.h" open="0" top="0" tabpos="12" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="48" topLine="0" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_pos.c" open="0" top="0" tabpos="12" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="10562" topLine="336" />
</Cursor>
</File>
<File name="lvgl\src\widgets\img\lv_img.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1863" topLine="59" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_disp.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="7126" topLine="230" />
</Cursor>
</File>
<File name="firmware_version.h" open="0" top="0" tabpos="9" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="160" topLine="0" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_style_gen.h" open="0" top="0" tabpos="11" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="29532" topLine="611" />
</Cursor>
</File>
<File name="compass_assets.c" open="0" top="0" tabpos="13" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="143" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_anim.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="749" topLine="34" />
</Cursor>
</File>
<File name="lvgl\src\layouts\grid\lv_grid.h" open="0" top="0" tabpos="13" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="579" topLine="17" />
</Cursor>
</File>
<File name="common_screen_components.h" open="0" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="517" topLine="0" />
</Cursor>
</File>
<File name="lvgl\src\widgets\tileview\lv_tileview.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1055" topLine="40" />
</Cursor>
<Folding>
<Collapse line="8" />
<Collapse line="995" />
</Folding>
</File>
<File name="lvgl\src\widgets\imgbtn\lv_imgbtn.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2129" topLine="53" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_scroll.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="9479" topLine="300" />
</Cursor>
</File>
<File name="main.c" open="0" top="0" tabpos="3" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1743" topLine="54" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_indev.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3034" topLine="107" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_color.c" open="0" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="10782" topLine="316" />
</Cursor>
</File>
<File name="lvgl\src\widgets\imgbtn\lv_imgbtn.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2184" topLine="61" />
</Cursor>
</File>
<File name="lv_drivers\win32drv\win32drv.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="15" />
</Cursor>
</File>
<File name="watch_casio_assets.c" open="0" top="0" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2981397" topLine="949" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_class.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3011" topLine="100" />
</Cursor>
</File>
<File name="common_screen_components.c" open="0" top="0" tabpos="8" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="498" topLine="21" />
</Cursor>
</File>
<File name="lvgl\src\widgets\roller\lv_roller.h" open="0" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="715" topLine="26" />
</Cursor>
</File>
<File name="lvgl\src\widgets\img\lv_img.h" open="0" top="0" tabpos="3" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="4439" topLine="123" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_tree.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2082" topLine="62" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_refr.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2447" topLine="75" />
</Cursor>
</File>
<File name="lvgl\src\font\lv_font_montserrat_30.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="869" topLine="0" />
</Cursor>
</File>
<File name="lv_drivers\indev\keyboard.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="440" topLine="14" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj_style.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="7273" topLine="217" />
</Cursor>
</File>
<File name="settings_screen.h" open="1" top="0" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1893" topLine="6" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_timer.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="5053" topLine="144" />
</Cursor>
</File>
<File name="lvgl\src\widgets\label\lv_label.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="5010" topLine="164" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_disp.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="6135" topLine="182" />
</Cursor>
</File>
<File name="notification_screen.c" open="1" top="1" tabpos="5" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1528" topLine="15" />
</Cursor>
</File>
<File name="lvgl\src\font\lv_font_montserrat_12.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="22" />
</Cursor>
</File>
<File name="lvgl\src\misc\lv_color.h" open="0" top="0" tabpos="5" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1102" topLine="35" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_indev_scroll.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="14405" topLine="323" />
</Cursor>
</File>
<File name="altimeter_screen.c" open="0" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="9615" topLine="246" />
</Cursor>
</File>
<File name="lvgl\src\core\lv_obj.h" open="0" top="0" tabpos="10" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="10255" topLine="265" />
</Cursor>
</File>
<File name="lvgl\demos\widgets\assets\img_demo_widgets_avatar.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1282774" topLine="472" />
</Cursor>
</File>
</CodeBlocks_layout_file>

View File

@ -28,6 +28,8 @@ static void gesture_event_cb(lv_event_t * e)
break;
case LV_DIR_RIGHT:
LV_LOG_USER("GESTURE : RIGHT");
// We delete the refresh timer
lv_timer_del(compassScreen->refreshTimer);
// We create the menu screen and switch to it
extern MenuScreen_t menuScreen;
menu_screen_create(&menuScreen);
@ -44,8 +46,6 @@ static void gesture_event_cb(lv_event_t * e)
}
}
static lv_timer_t *timer;
static void cleanup_event_cb(lv_event_t * e)
{
CompassScreen_t *compassScreen = e->user_data;
@ -53,18 +53,20 @@ static void cleanup_event_cb(lv_event_t * e)
LV_LOG_USER("cleanup");
}
//To delete
static void timer_anim_cb(lv_timer_t *timer)
static void _compass_screen_refresh_timer_cb(lv_timer_t *timer)
{
CompassScreen_t *compassScreen = timer->user_data;
static uint16_t azimuth = 0;
static float temp = -20;
compass_screen_set_azimuth(compassScreen, azimuth++);
compass_screen_set_temperature(compassScreen, temp+=0.09);
if(temp > 120) temp = -20;
if(compassScreen->compassScreenAzimuthAndTemperatureCb)
{
uint16_t azimuth = 0;
float temperature = 0.0f;
//lv_meter_set_scale_range(compassScreen->compassGraduation.meter, compassScreen->compassGraduation.scale, 0, 330, 330, -azimuth-90);
compassScreen->compassScreenAzimuthAndTemperatureCb(&azimuth, &temperature);
compass_screen_set_azimuth(compassScreen, azimuth);
compass_screen_set_temperature(compassScreen, temperature);
}
}
static void create_cardinal(CompassCardinal_t *cardidanl, const char *cardinalText, lv_color_t textColor, lv_coord_t x, lv_coord_t y, lv_obj_t *parent)
@ -106,6 +108,28 @@ void compass_screen_init(CompassScreen_t * const compassScreen)
strcpy(compassScreen->compassTemperature.text, "0.00°C");
}
void compass_screen_register_on_state_change_cb(CompassScreen_t * const compassScreen, CompassScreenOnStateChangeCb_t compassScreenOnStateChangeCb)
{
if(!compassScreen)
{
LV_LOG_ERROR("NULL pointer given !");
return;
}
compassScreen->compassScreenOnStateChangeCb = compassScreenOnStateChangeCb;
}
void compass_screen_register_azimuth_and_temperature_cb(CompassScreen_t * const compassScreen, CompassScreenAzimuthAndTemperatureCb_t compassScreenAzimuthAndTemperatureCb)
{
if(!compassScreen)
{
LV_LOG_ERROR("NULL pointer given !");
return;
}
compassScreen->compassScreenAzimuthAndTemperatureCb = compassScreenAzimuthAndTemperatureCb;
}
void compass_screen_set_azimuth(CompassScreen_t * const compassScreen, uint16_t azimuth)
{
if(!compassScreen)
@ -165,7 +189,17 @@ void compass_screen_set_temperature(CompassScreen_t * const compassScreen, float
//Update the temperature label
sprintf(compassScreen->compassTemperature.text, "%.2f°C", temperature);
lv_label_set_text_static(compassScreen->compassTemperature.label, compassScreen->compassTemperature.text);
}
bool compass_screen_is_in_use(CompassScreen_t *const compassScreen)
{
if(!compassScreen)
{
LV_LOG_ERROR("NULL pointer given !");
return false;
}
return compassScreen->display != NULL;
}
void compass_screen_create(CompassScreen_t * const compassScreen)
@ -191,7 +225,7 @@ void compass_screen_create(CompassScreen_t * const compassScreen)
compassScreen->display = lv_obj_create(NULL);
lv_obj_set_style_bg_color(compassScreen->display, lv_color_white(), LV_PART_MAIN);
//Let's try to add some arcs
//Let's add some arcs
lv_obj_t *arc = lv_arc_create(compassScreen->display);
lv_arc_set_angles(arc, 0, 360);
lv_obj_set_style_arc_width(arc, 2, LV_PART_INDICATOR);
@ -308,8 +342,17 @@ void compass_screen_create(CompassScreen_t * const compassScreen)
//We register the event callback to handle the cleanup
lv_obj_add_event_cb(compassScreen->display, &(cleanup_event_cb), LV_EVENT_DELETE, compassScreen);
//To delete
timer = lv_timer_create(&(timer_anim_cb), 2, compassScreen);
//We create the refresh timer
if(compassScreen->refreshTimer)
{
LV_LOG_ERROR("refreshTimer should be NULL here !");
lv_timer_del(compassScreen->refreshTimer);
compassScreen->refreshTimer = NULL;
}
if(compassScreen->compassScreenOnStateChangeCb) compassScreen->compassScreenOnStateChangeCb(COMPASS_SCREEN_OPENED);
compassScreen->refreshTimer = lv_timer_create(&(_compass_screen_refresh_timer_cb), 20, compassScreen);
}
void compass_screen_destroy(CompassScreen_t * const compassScreen)
@ -330,6 +373,7 @@ void compass_screen_destroy(CompassScreen_t * const compassScreen)
compassScreen->northMarker = NULL;
compassScreen->compassGraduation.meter = NULL;
compassScreen->compassGraduation.scale = NULL;
compassScreen->refreshTimer = NULL;
lv_timer_del(timer);
if(compassScreen->compassScreenOnStateChangeCb) compassScreen->compassScreenOnStateChangeCb(COMPASS_SCREEN_CLOSED);
}

View File

@ -22,6 +22,16 @@ typedef struct CompassGraduation
lv_meter_scale_t *scale;
} CompassGraduation_t;
typedef enum CompassScreenState
{
COMPASS_SCREEN_OPENED = 0,
COMPASS_SCREEN_CLOSED
} CompassScreenState_e;
typedef void (*CompassScreenOnStateChangeCb_t)(CompassScreenState_e compassScreenState);
typedef void (*CompassScreenAzimuthAndTemperatureCb_t)(uint16_t *azimuth, float *temperature);
/* Compass screen context object */
typedef struct CompassScreen
{
@ -37,21 +47,77 @@ typedef struct CompassScreen
CompassLabel_t compassAzimuth;
CompassLabel_t compassTemperature;
CompassScreenOnStateChangeCb_t compassScreenOnStateChangeCb;
CompassScreenAzimuthAndTemperatureCb_t compassScreenAzimuthAndTemperatureCb;
lv_timer_t *refreshTimer;
} CompassScreen_t;
/* Initializes the compass screen context object */
/**
* @brief Initializes the compass screen object structure.
* @note This function has to be called first before any others.
*
* @param compassScreen a pointer to the compass screen object structure to initialize.
*/
void compass_screen_init(CompassScreen_t * const compassScreen);
/* Set the compassAzimuth in degrees to show */
/**
* @brief Registers a callback function which will be called every time the state of the application changes ie : is opened or closed.
* This callback should be used to initialize and deinitialize needed devices drivers like the magnetometer or the temperature sensor.
* @note The state of the application is passed as a parameter or the callback function.
*
* @param compassScreen a pointer to the compass screen object structure.
* @param compassScreenOnStateChangeCb the callback of type CompassScreenOnStateChangeCb_t to register.
*/
void compass_screen_register_on_state_change_cb(CompassScreen_t * const compassScreen, CompassScreenOnStateChangeCb_t compassScreenOnStateChangeCb);
/**
* @brief Registers a callback function which will be executed every time the compass refreshes.
* This callback should retrieve the azimuth and temperature and pass it through the provided pointers.
*
* @param compassScreen a pointer to the compass screen object structure.
* @param compassScreenOnStateChangeCb the callback of type CompassScreenAzimuthAndTemperatureCb_t to register.
*/
void compass_screen_register_azimuth_and_temperature_cb(CompassScreen_t * const compassScreen, CompassScreenAzimuthAndTemperatureCb_t compassScreenAzimuthAndTemperatureCb);
/**
* @brief Sets the azimuth in degrees (relative to the north) to show on the compass UI.
*
* @param compassScreen a pointer to the compass screen object structure.
* @param azimuth the azimuth in degrees (0 to 359) relative to north to show.
*/
void compass_screen_set_azimuth(CompassScreen_t * const compassScreen, uint16_t azimuth);
/* Set the compassTemperature in degrees celsius to show */
/**
* @brief Sets the temperature in degrees celsius to show on the compass UI.
*
* @param compassScreen a pointer to the compass screen object structure.
* @param temperature the temperature to display on the compass screen in degrees celsius.
*/
void compass_screen_set_temperature(CompassScreen_t * const compassScreen, float temperature);
/* Builds the compass screen graphically */
/**
* @brief Returns true if the compass screen is currently being used and displayed.
*
* @param compassScreen a pointer to the compass screen object structure.
* @return true if the compass screen is being used .
* @return false if the compass screen is not being used/currently displayed.
*/
bool compass_screen_is_in_use(CompassScreen_t * const compassScreen);
/**
* @brief Builds the compass screen graphically.
*
* @param compassScreen a pointer to the compass screen object structure.
*/
void compass_screen_create(CompassScreen_t * const compassScreen);
/* Frees all resources used by the CompassScreen object */
/**
* @brief Frees all resources used by the CompassScreen object, to be called when discarding the compass screen.
*
* @param compassScreen a pointer to the compass screen object structure.
*/
void compass_screen_destroy(CompassScreen_t * const compassScreen);
#endif // COMPASS_SCREEN_H

View File

@ -62,6 +62,30 @@ static void date_time_cb(struct tm * const dateTime)
*dateTime = *tm;
}
static void compass_screen_on_state_change_cb(CompassScreenState_e compassScreenState)
{
switch(compassScreenState)
{
case COMPASS_SCREEN_OPENED:
LV_LOG_USER("Compass Screen opened");
break;
case COMPASS_SCREEN_CLOSED:
default:
LV_LOG_USER("Compass Screen closed");
break;
}
}
static void azimuth_and_temperature_cb(uint16_t *azimuth, float *temperature)
{
static uint16_t _azimuth = 0;
static float _temp = -20;
*azimuth = _azimuth++;
*temperature = _temp += 0.9;
if(_temp > 120) _temp = -20;
}
static void alti_meas_cb(float * const temperature, float * const pressure, float * const altitude)
{
static float a = 425.5;
@ -110,21 +134,24 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLi
lv_win32_init(hInstance, SW_SHOWNORMAL, 240, 240, NULL);
/*Output prompt information to the console, you can also use printf() to print directly*/
LV_LOG_USER("LVGL initialization completed!");
LV_LOG_USER("LVGL initialization completed, color size is : %u !", LV_COLOR_SIZE);
LV_IMG_DECLARE(watch_mask)
/*Run the demo*/
//lv_demo_widgets();
lv_obj_t *top_layer = lv_layer_top();
lv_obj_t *sys_layer = lv_layer_sys();
//We apply the mask to simulate what we can see on the watch screen
lv_obj_t *screen_mask = lv_img_create(top_layer);
lv_obj_t *screen_mask = lv_img_create(sys_layer);
lv_img_set_src(screen_mask, &watch_mask);
watch_face_init(&watchFace);
menu_screen_init(&menuScreen);
compass_screen_init(&compassScreen);
compass_screen_register_on_state_change_cb(&compassScreen, &(compass_screen_on_state_change_cb));
compass_screen_register_azimuth_and_temperature_cb(&compassScreen, &(azimuth_and_temperature_cb));
settings_screen_init(&settingsScreen);
altimeter_screen_init(&altimeterScreen);
altimeter_screen_register_measurement_cb(&altimeterScreen, &(alti_meas_cb));
notification_screen_init(&notificationScreen);
find_my_phone_screen_init(&findMyPhoneScreen);
find_my_phone_screen_register_BLE_command_send_cb(&findMyPhoneScreen, &(sendMyFindPhoneBLECommandCb));
@ -138,8 +165,6 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLi
music_player_screen_set_music_position(&musicPlayerScreen, 2*60+12);
music_player_screen_set_music_playing_state(&musicPlayerScreen, MUSIC_CONTROL_PLAY);
altimeter_screen_register_measurement_cb(&altimeterScreen, &(alti_meas_cb));
watch_face_register_date_time_cb(&watchFace, &(date_time_cb));
watch_face_create(&watchFace);

View File

@ -1,15 +1,45 @@
#include <stdio.h>
#include <stdlib.h>
#include "notification_screen.h"
bool _notification_list_is_empty(NotificationList_t notificationList);
/* Internal API to manage notification objects */
bool _notification_list_is_empty(NotificationDataList_t notificationList);
void _notification_list_add_head(NotificationDataList_t *notificationList, NotificationData_t *notification);
NotificationData_t *_notification_list_remove_tail(NotificationDataList_t *notificationList);
NotificationData_t *_notification_list_remove_by_handle(NotificationDataList_t *notificationList, uint32_t handle);
uint8_t _notification_list_count(NotificationDataList_t notificationList);
uint8_t _notification_list_unread_count(NotificationDataList_t notificationList);
void _notification_list_add_head(NotificationList_t *notificationList, Notification_t *notification);
void _notification_list_debug(NotificationDataList_t notificationList);
/* Internal UI API */
void _display_message_notification(NotificationScreen_t * const notificationScreen, NotificationData_t *notification);
void _notification_popup_destroy(NotificationScreen_t * const notificationScreen);
const char *_notification_type_to_char(NotificationType_e notificationType);
const char *_notification_timestamp_to_date(time_t timestamp);
Notification_t *_notification_list_remove_tail(NotificationList_t *notificationList);
uint8_t _notification_list_count(NotificationList_t notificationList);
void _notification_list_debug(NotificationList_t notificationList);
static void notification_scrolled_event_cb(lv_event_t *e)
{
NotificationScreen_t *notificationScreen = lv_event_get_user_data(e);
NotificationData_t *notification = lv_obj_get_user_data(lv_event_get_target(e));
//If we didn't scroll down enough, make the notif pop again
if(lv_obj_get_scroll_y(e->target) >= 83)
{
lv_obj_scroll_to_y(e->target, 166, LV_ANIM_ON);
}
//Else we know that the user wants to close the notification, so we do it with an animation to reach 0
else if(lv_obj_get_scroll_y(e->target) != 0)
{
lv_obj_scroll_to_y(e->target, 0, LV_ANIM_ON);
}
else //We scrolled enough to tell that we saw the notification and that we want to close it
{
LV_LOG_USER("Notification closed");
_notification_popup_destroy(notificationScreen);
notificationScreen->new_notification_available = false;
notification->read = true;
if(notificationScreen->notificationOnStateChangeCb) notificationScreen->notificationOnStateChangeCb(NOTIFICATION_STATE_CLEARED);
}
}
void notification_screen_init(NotificationScreen_t * const notificationScreen)
{
@ -19,14 +49,14 @@ void notification_screen_init(NotificationScreen_t * const notificationScreen)
return;
}
memset(notificationScreen, 0, sizeof(NotificationScreen_t));
//Let's initialize the list of free notifications from the pool
for(uint8_t i = 0; i < MAX_NOTIFICATIONS_COUNT; i++)
_notification_list_add_head(&notificationScreen->freeNotificationList, notificationScreen->notificationPool + i);
notification_screen_notify(notificationScreen, 42, NOTIFICATION_TYPE_UNKNOWN, NULL, NULL);
}
void notification_screen_notify(NotificationScreen_t * const notificationScreen, uint32_t handle, NotificationType_e notificationType, char * title, char * body)
void notification_screen_register_on_state_change_cb(NotificationScreen_t * const notificationScreen, NotificationOnStateChangeCb_t notificationOnStateChangeCb)
{
if(!notificationScreen)
{
@ -34,7 +64,18 @@ void notification_screen_notify(NotificationScreen_t * const notificationScreen,
return;
}
Notification_t *notification = NULL;
notificationScreen->notificationOnStateChangeCb = notificationOnStateChangeCb;
}
void notification_screen_notify(NotificationScreen_t * const notificationScreen, uint32_t handle, time_t dateOfArrival, NotificationType_e notificationType, char * title, char * body)
{
if(!notificationScreen)
{
LV_LOG_ERROR("NULL pointer given !");
return;
}
NotificationData_t *notification = NULL;
//We try to get a notification from the free list.
if((notification = _notification_list_remove_tail(&notificationScreen->freeNotificationList)) == NULL)
@ -53,32 +94,66 @@ void notification_screen_notify(NotificationScreen_t * const notificationScreen,
}
notification->handle = handle;
notification->dateOfArrival = dateOfArrival;
notification->type = notificationType;
notification->title = title;
notification->body = body;
notification->read = false;
_notification_list_add_head(&notificationScreen->notificationList, notification);
notificationScreen->new_notification_available = true;
//Create and display a graphical widget containing the notification
lv_obj_t *notification_display = lv_layer_sys();
if(!notification_display)
switch(notificationType)
{
LV_LOG_ERROR("Could not retrieve sys layer !");
return;
case NOTIFICATION_TYPE_CALL:
break;
default:
_display_message_notification(notificationScreen, notification);
if(notificationScreen->notificationOnStateChangeCb) notificationScreen->notificationOnStateChangeCb(NOTIFICATION_STATE_DISPLAYED);
}
/*lv_obj_t *obj = lv_obj_create(notification_display);
lv_obj_set_style_bg_color(obj, lv_palette_main(LV_PALETTE_RED), LV_PART_MAIN);
lv_obj_set_height(obj, lv_disp_get_hor_res(NULL)/2);
lv_obj_set_style_bg_opa(notification_display, 255, LV_PART_MAIN);*/
}
bool _notification_list_is_empty(NotificationList_t notificationList)
bool notification_screen_new_notification_available(NotificationScreen_t * const notificationScreen)
{
if(!notificationScreen)
{
LV_LOG_ERROR("NULL pointer given !");
return false;
}
if(notificationScreen->new_notification_available)
{
notificationScreen->new_notification_available = false;
return true;
}
return false;
}
uint8_t notification_screen_notification_count(NotificationScreen_t * const notificationScreen)
{
return _notification_list_count(notificationScreen->notificationList);
}
uint8_t notification_screen_unread_notification_count(NotificationScreen_t * const notificationScreen)
{
return _notification_list_unread_count(notificationScreen->notificationList);;
}
void notification_screen_destroy(NotificationScreen_t * const notificationScreen)
{
if(!notificationScreen)
{
LV_LOG_ERROR("NULL pointer given !");
return;
}
}
bool _notification_list_is_empty(NotificationDataList_t notificationList)
{
return notificationList == NULL;
}
void _notification_list_add_head(NotificationList_t *notificationList, Notification_t *notification)
void _notification_list_add_head(NotificationDataList_t *notificationList, NotificationData_t *notification)
{
if(!notificationList || !notification) return;
@ -91,13 +166,13 @@ void _notification_list_add_head(NotificationList_t *notificationList, Notificat
}
}
Notification_t *_notification_list_remove_tail(NotificationList_t *notificationList)
NotificationData_t *_notification_list_remove_tail(NotificationDataList_t *notificationList)
{
if(!notificationList) return NULL;
if(_notification_list_is_empty(*notificationList)) return NULL;
Notification_t *toReturn = NULL;
NotificationData_t *toReturn = NULL;
//There is only one item in the list
if((*notificationList)->next == NULL)
@ -107,7 +182,7 @@ Notification_t *_notification_list_remove_tail(NotificationList_t *notificationL
return toReturn;
}
NotificationList_t cursor = *notificationList;
NotificationDataList_t cursor = *notificationList;
while(!_notification_list_is_empty(cursor->next->next))
{
cursor = cursor->next;
@ -118,7 +193,40 @@ Notification_t *_notification_list_remove_tail(NotificationList_t *notificationL
return toReturn;
}
uint8_t _notification_list_count(NotificationList_t notificationList)
NotificationData_t *_notification_list_remove_by_handle(NotificationDataList_t *notificationList, uint32_t handle)
{
if(!notificationList) return NULL;
if(_notification_list_is_empty(*notificationList)) return NULL;
NotificationData_t *toReturn = NULL;
//There is only one item in the list
if((*notificationList)->next == NULL)
{
if((*notificationList)->handle == handle)
{
toReturn = *notificationList;
*notificationList = NULL;
}
return toReturn;
}
NotificationDataList_t cursor = *notificationList;
while(!_notification_list_is_empty(cursor->next))
{
if(cursor->next->handle == handle)
{
toReturn = cursor->next;
cursor->next = NULL;
return toReturn;
}
cursor = cursor->next;
}
return toReturn;
}
uint8_t _notification_list_count(NotificationDataList_t notificationList)
{
uint8_t count = 0;
while(!_notification_list_is_empty(notificationList))
@ -130,7 +238,169 @@ uint8_t _notification_list_count(NotificationList_t notificationList)
return count;
}
void _notification_list_debug(NotificationList_t notificationList)
uint8_t _notification_list_unread_count(NotificationDataList_t notificationList)
{
uint8_t count = 0;
while(!_notification_list_is_empty(notificationList))
{
if(!notificationList->read)count++;
notificationList = notificationList->next;
}
return count;
}
void _display_message_notification(NotificationScreen_t * const notificationScreen, NotificationData_t *notification)
{
//Create and display a graphical widget containing the notification
lv_obj_t *notification_display = lv_layer_top();
if(!notification_display)
{
LV_LOG_ERROR("Could not retrieve sys layer !");
return;
}
/*We can have two cases :
1) No notification is currently being displayed, so we create the needed UI objects
2) A notification is currently being shown and all UI elements were already created / allocated
*/
lv_obj_set_user_data(notification_display, notification);
if(lv_obj_get_child_cnt(notification_display) == 0)
{
//Only allow to scroll down and not up (LV_DIR_TOP makes it, is it a bug ?)
lv_obj_set_scroll_dir(notification_display, LV_DIR_TOP);
lv_obj_add_event_cb(notification_display, &(notification_scrolled_event_cb), LV_EVENT_SCROLL_END, notificationScreen);
lv_obj_t *main_notification = lv_obj_create(notification_display);
lv_obj_set_size(main_notification, 202, 166);
lv_obj_set_style_pad_all(main_notification, 0, LV_PART_MAIN);
lv_obj_set_style_pad_top(main_notification, 10, LV_PART_MAIN);
lv_obj_set_style_border_width(main_notification, 0, LV_PART_MAIN);
lv_obj_set_style_radius(main_notification, 30, LV_PART_MAIN);
lv_obj_align(main_notification, LV_ALIGN_BOTTOM_MID,0,166);
lv_obj_set_style_bg_color(main_notification, lv_color_make(52, 93, 106), LV_PART_MAIN);
//lv_obj_set_style_opa(main_notification, 240, LV_PART_MAIN); //Opacity is too heavy on ram :-(
//Create the title, type and date labels
if(notificationScreen->type_label)
{
LV_LOG_ERROR("type_label should be NULL here !");
lv_obj_del(notificationScreen->type_label);
notificationScreen->type_label = NULL;
}
notificationScreen->type_label = lv_label_create(main_notification);
lv_obj_set_style_text_color(notificationScreen->type_label, lv_color_white(), LV_PART_MAIN);
lv_obj_set_style_pad_left(notificationScreen->type_label, 10, LV_PART_MAIN);
lv_label_set_long_mode(notificationScreen->type_label, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_obj_set_style_anim_speed(notificationScreen->type_label, 10, LV_PART_MAIN);
lv_obj_set_width(notificationScreen->type_label, lv_pct(27));
lv_label_set_text(notificationScreen->type_label, _notification_type_to_char(notification->type));
if(notificationScreen->title_label)
{
LV_LOG_ERROR("title_label should be NULL here !");
lv_obj_del(notificationScreen->title_label);
notificationScreen->title_label = NULL;
}
notificationScreen->title_label = lv_label_create(main_notification);
lv_obj_set_style_text_color(notificationScreen->title_label, lv_color_white(), LV_PART_MAIN);
lv_obj_align(notificationScreen->title_label, LV_ALIGN_TOP_MID, 0, 0);
lv_obj_set_style_anim_speed(notificationScreen->title_label, 10, LV_PART_MAIN);
lv_label_set_long_mode(notificationScreen->title_label, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_obj_set_width(notificationScreen->title_label, lv_pct(40));
lv_label_set_text_static(notificationScreen->title_label, notification->title);
if(notificationScreen->date_label)
{
LV_LOG_ERROR("date_label should be NULL here !");
lv_obj_del(notificationScreen->date_label);
notificationScreen->date_label = NULL;
}
notificationScreen->date_label = lv_label_create(main_notification);
lv_obj_set_style_pad_right(notificationScreen->date_label, 10, LV_PART_MAIN);
lv_obj_set_style_text_color(notificationScreen->date_label, lv_color_white(), LV_PART_MAIN);
lv_obj_align(notificationScreen->date_label, LV_ALIGN_TOP_RIGHT, 0, 0);
lv_label_set_text(notificationScreen->date_label, _notification_timestamp_to_date(notification->dateOfArrival));
//Create the sub-area in the notification
lv_obj_t *sub_area = lv_obj_create(main_notification);
lv_obj_set_style_pad_all(sub_area, 10, LV_PART_MAIN);
lv_obj_set_style_border_width(sub_area, 0, LV_PART_MAIN);
lv_obj_set_style_radius(sub_area, 0, LV_PART_MAIN);
lv_obj_set_width(sub_area, 202);
lv_obj_set_height(sub_area, 136);
lv_obj_align(sub_area, LV_ALIGN_BOTTOM_MID, 0, 0);
lv_obj_set_style_bg_color(sub_area, lv_color_make(22, 52, 62), LV_PART_MAIN);
//Create the main text
if(notificationScreen->body_label)
{
LV_LOG_ERROR("body_label should be NULL here !");
lv_obj_del(notificationScreen->body_label);
notificationScreen->body_label = NULL;
}
notificationScreen->body_label = lv_label_create(sub_area);
lv_obj_set_width(notificationScreen->body_label, 182);
lv_obj_set_style_text_color(notificationScreen->body_label, lv_color_white(), LV_PART_MAIN);
lv_obj_set_style_pad_all(notificationScreen->body_label, 0, LV_PART_MAIN);
lv_obj_set_style_pad_bottom(notificationScreen->body_label, 40, LV_PART_MAIN);
lv_label_set_long_mode(notificationScreen->body_label, LV_LABEL_LONG_WRAP);
lv_label_set_text_static(notificationScreen->body_label, notification->body);
lv_obj_scroll_to_y(notification_display, 166, LV_ANIM_ON);
}
else
{
LV_LOG_USER("A notification is already being displayed, updating it's content !");
//We just have to update the notification content
lv_label_set_text_static(notificationScreen->type_label, _notification_type_to_char(notification->type));
lv_label_set_text_static(notificationScreen->title_label, notification->title);
lv_label_set_text_static(notificationScreen->date_label, _notification_timestamp_to_date(notification->dateOfArrival));
lv_label_set_text_static(notificationScreen->body_label, notification->body);
}
}
void _notification_popup_destroy(NotificationScreen_t * const notificationScreen)
{
lv_obj_clean(lv_layer_top());
lv_obj_remove_event_cb_with_user_data(lv_layer_top(), &(notification_scrolled_event_cb), notificationScreen);
notificationScreen->type_label = NULL;
notificationScreen->title_label = NULL;
notificationScreen->date_label = NULL;
notificationScreen->body_label = NULL;
}
const char *_notification_type_to_char(NotificationType_e notificationType)
{
switch(notificationType)
{
case NOTIFICATION_TYPE_SMS:
return "Sms";
case NOTIFICATION_TYPE_EMAIL:
return "Email";
case NOTIFICATION_TYPE_WHATSAPP:
return "WhatsApp";
case NOTIFICATION_TYPE_GADGET_BRIDGE:
return "GadgetBridge";
case NOTIFICATION_TYPE_UNKNOWN:
default:
return "Unknown";
}
}
const char *_notification_timestamp_to_date(time_t timestamp)
{
static char date[9]; //Ex 7:23PM
struct tm *time = gmtime(&timestamp);
sprintf(date, "%s%d:%s%d", time->tm_hour > 10 ? "" : "0", time->tm_hour, time->tm_min > 10 ? "" : "0", time->tm_min);
return date;
}
void _notification_list_debug(NotificationDataList_t notificationList)
{
while(!_notification_list_is_empty(notificationList))
{

View File

@ -1,8 +1,13 @@
#ifndef NOTIFICATION_SCREEN_H
#define NOTIFICATION_SCREEN_H
#include "lvgl.h"
#include <time.h>
#define MAX_NOTIFICATIONS_COUNT (10) //The maximum number of notifications which will be stored before the oldest one gets discarded.
/* The maximum number of notifications which will be stored before the oldest one gets discarded
to make room for the new one.
*/
#define MAX_NOTIFICATIONS_COUNT (10)
typedef enum NotificationType
{
@ -11,32 +16,61 @@ typedef enum NotificationType
NOTIFICATION_TYPE_WHATSAPP,
NOTIFICATION_TYPE_GADGET_BRIDGE,
NOTIFICATION_TYPE_UNKNOWN,
// This enum value has no match in GadgetBridge's enum
NOTIFICATION_TYPE_CALL,
} NotificationType_e;
typedef struct Notification
typedef enum NotificationState
{
struct Notification *next;
NOTIFICATION_STATE_CLEARED = 0,
NOTIFICATION_STATE_DISPLAYED = 1,
} NotificationState_e;
typedef struct NotificationData
{
struct NotificationData *next;
uint32_t handle;
NotificationType_e type;
time_t dateOfArrival;
char *title;
char *body;
} Notification_t, *NotificationList_t;
NotificationType_e type;
bool read; // Has the notification been read (aka closed by the user)
} NotificationData_t, *NotificationDataList_t;
typedef void (*NotificationOnStateChangeCb_t)(NotificationState_e notificationState);
typedef struct NotificationScreen
{
//Can be erased attributes
// Can be erased attributes
lv_obj_t *display;
//Should not be erased attributes
Notification_t notificationPool[MAX_NOTIFICATIONS_COUNT];
NotificationList_t notificationList; //Actual notifications
NotificationList_t freeNotificationList; //Free notiffication object pool
// Should not be erased attributes
// Notification UI object
lv_obj_t *type_label;
lv_obj_t *title_label;
lv_obj_t *date_label;
lv_obj_t *body_label;
NotificationOnStateChangeCb_t notificationOnStateChangeCb;
// Notification history data structure
NotificationData_t notificationPool[MAX_NOTIFICATIONS_COUNT];
NotificationDataList_t notificationList; // Actual notifications
NotificationDataList_t freeNotificationList; // Free notification object pool
// Miscellaneous
bool new_notification_available;
} NotificationScreen_t;
void notification_screen_init(NotificationScreen_t * const notificationScreen);
void notification_screen_notify(NotificationScreen_t * const notificationScreen, uint32_t handle, NotificationType_e notificationType, char * title, char * body);
void notification_screen_register_on_state_change_cb(NotificationScreen_t * const notificationScreen, NotificationOnStateChangeCb_t notificationOnStateChangeCb);
void notification_screen_notify(NotificationScreen_t * const notificationScreen, uint32_t handle, time_t dateOfArrival, NotificationType_e notificationType, char * title, char * body);
bool notification_screen_new_notification_available(NotificationScreen_t * const notificationScreen);
uint8_t notification_screen_notification_count(NotificationScreen_t * const notificationScreen);
uint8_t notification_screen_unread_notification_count(NotificationScreen_t * const notificationScreen);
void notification_screen_create(NotificationScreen_t * const notificationScreen);

View File

@ -26,7 +26,7 @@ static void _reset_switch_pointers(SettingsScreen_t * const settingsScreen)
settingsScreen->ble_switch = NULL;
settingsScreen->auto_set_time_switch = NULL;
}
static lv_obj_t *add_menu_list_item(lv_obj_t *list, const char *text, lv_event_cb_t event_cb, void *user_data);
static lv_obj_t *add_menu_list_item(lv_obj_t *list, const char *text, lv_event_cb_t event_cb, void *user_data, SettingsScreenCategory_e category);
static void update_menu_list_item_text(lv_obj_t *menu_list_item, const char *text);
static void gesture_event_cb(lv_event_t *e)
@ -164,9 +164,6 @@ static void about_refresh_timer_cb(lv_timer_t *timer)
static void load_time_and_date_side_screen(SettingsScreen_t *settingsScreen)
{
lv_obj_clean(settingsScreen->side_screen);
_reset_switch_pointers(settingsScreen);
lv_obj_t *label = lv_label_create(settingsScreen->side_screen);
lv_label_set_text_static(label, "Set Time & Date :");
@ -254,9 +251,6 @@ static void load_time_and_date_side_screen(SettingsScreen_t *settingsScreen)
static void load_display_side_screen(SettingsScreen_t *settingsScreen)
{
lv_obj_clean(settingsScreen->side_screen);
_reset_switch_pointers(settingsScreen);
lv_obj_t *label = lv_label_create(settingsScreen->side_screen);
lv_label_set_text_static(label, "Brightness :");
@ -323,9 +317,6 @@ static void load_display_side_screen(SettingsScreen_t *settingsScreen)
static void load_notifications_side_screen(SettingsScreen_t *settingsScreen)
{
lv_obj_clean(settingsScreen->side_screen);
_reset_switch_pointers(settingsScreen);
lv_obj_t *label = lv_label_create(settingsScreen->side_screen);
lv_label_set_text_static(label, "Vibrate on\nnotifications :");
@ -352,9 +343,6 @@ static void load_notifications_side_screen(SettingsScreen_t *settingsScreen)
static void load_connectivity_side_screen(SettingsScreen_t *settingsScreen)
{
lv_obj_clean(settingsScreen->side_screen);
_reset_switch_pointers(settingsScreen);
lv_obj_t *label = lv_label_create(settingsScreen->side_screen);
lv_label_set_text_static(label, "Connectivity :");
@ -407,9 +395,6 @@ static void load_connectivity_side_screen(SettingsScreen_t *settingsScreen)
static void load_language_side_screen(SettingsScreen_t *settingsScreen)
{
lv_obj_clean(settingsScreen->side_screen);
_reset_switch_pointers(settingsScreen);
lv_obj_t *label = lv_label_create(settingsScreen->side_screen);
lv_label_set_text_static(label, "Language :");
@ -421,9 +406,6 @@ static void load_language_side_screen(SettingsScreen_t *settingsScreen)
static void load_about_side_screen(SettingsScreen_t *settingsScreen)
{
lv_obj_clean(settingsScreen->side_screen);
_reset_switch_pointers(settingsScreen);
lv_obj_t *label = lv_label_create(settingsScreen->side_screen);
lv_label_set_text_static(label, "System Info :");
@ -521,7 +503,7 @@ static void load_about_side_screen(SettingsScreen_t *settingsScreen)
lv_timer_del(settingsScreen->about_refresh_timer);
settingsScreen->about_refresh_timer = NULL;
}
settingsScreen->about_refresh_timer = lv_timer_create(&(about_refresh_timer_cb), 1000, settingsScreen);
settingsScreen->about_refresh_timer = lv_timer_create(&(about_refresh_timer_cb), 150, settingsScreen);
}
static void menu_list_item_event_handler(lv_event_t * e)
@ -541,6 +523,17 @@ void settings_screen_init(SettingsScreen_t * const settingsScreen)
memset(settingsScreen, 0, sizeof(SettingsScreen_t));
}
void settings_screen_register_on_state_change_cb(SettingsScreen_t * const settingsScreen, SettingsScreenOnStateChangeCb_t settingsScreenOnStateChangeCb)
{
if(!settingsScreen)
{
LV_LOG_ERROR("NULL pointer given !");
return;
}
settingsScreen->settingsScreenOnStateChangeCb = settingsScreenOnStateChangeCb;
}
void settings_screen_register_API_interface(SettingsScreen_t * const settingsScreen, SettingsScreenAPIInterface_t * const settingsScreenAPIInterface)
{
if(!settingsScreen)
@ -563,7 +556,7 @@ void settings_screen_create(SettingsScreen_t * const settingsScreen)
return;
}
//We create our parent screen :
// We create our parent screen :
if(settingsScreen->display)
{
LV_LOG_ERROR("display should be NULL here !");
@ -572,10 +565,10 @@ void settings_screen_create(SettingsScreen_t * const settingsScreen)
}
settingsScreen->display = lv_obj_create(NULL);
//We add the screen header
// We add the screen header
common_screen_header_component(settingsScreen->display, "Settings", 50);
//We create the menu list on the left hand side
// We create the menu list on the left hand side
lv_obj_t *menu_list = lv_list_create(settingsScreen->display);
lv_obj_set_size(menu_list, 75,190);
lv_obj_set_pos(menu_list, 0, 50);
@ -585,7 +578,7 @@ void settings_screen_create(SettingsScreen_t * const settingsScreen)
lv_obj_set_style_pad_left(menu_list, 0, LV_PART_MAIN);
lv_obj_set_style_pad_bottom(menu_list, 50, LV_PART_MAIN);
//We add the side screen containing the settings
// We add the side screen containing the settings
settingsScreen->side_screen = lv_obj_create(settingsScreen->display);
lv_obj_set_size(settingsScreen->side_screen, 165,190);
lv_obj_set_pos(settingsScreen->side_screen, 75, 50);
@ -595,20 +588,20 @@ void settings_screen_create(SettingsScreen_t * const settingsScreen)
lv_obj_set_style_pad_bottom(settingsScreen->side_screen, 70, LV_PART_MAIN);
lv_obj_set_scroll_dir(settingsScreen->side_screen, LV_DIR_VER);
//We add all the menu list items
settingsScreen->time_and_date_item = add_menu_list_item(menu_list, "Time & Date", &(menu_list_item_event_handler), settingsScreen);
settingsScreen->display_item = add_menu_list_item(menu_list, "Display", &(menu_list_item_event_handler), settingsScreen);
settingsScreen->notifications_item = add_menu_list_item(menu_list, "Notifications", &(menu_list_item_event_handler), settingsScreen);
settingsScreen->connectivity_item = add_menu_list_item(menu_list, "Connectivity", &(menu_list_item_event_handler), settingsScreen);
settingsScreen->language_item = add_menu_list_item(menu_list, "Language", &(menu_list_item_event_handler), settingsScreen);
settingsScreen->about_item = add_menu_list_item(menu_list, "About", &(menu_list_item_event_handler), settingsScreen);
// We add all the menu list items
settingsScreen->time_and_date_item = add_menu_list_item(menu_list, "Time & Date", &(menu_list_item_event_handler), settingsScreen, SETTINGS_SCREEN_CATEGORY_TIME_AND_DATE);
settingsScreen->display_item = add_menu_list_item(menu_list, "Display", &(menu_list_item_event_handler), settingsScreen, SETTINGS_SCREEN_CATEGORY_DISPLAY);
settingsScreen->notifications_item = add_menu_list_item(menu_list, "Notifications", &(menu_list_item_event_handler), settingsScreen, SETTINGS_SCREEN_CATEGORY_NOTIFICATION);
settingsScreen->connectivity_item = add_menu_list_item(menu_list, "Connectivity", &(menu_list_item_event_handler), settingsScreen, SETTINGS_SCREEN_CATEGORY_CONNECTIVITY);
settingsScreen->language_item = add_menu_list_item(menu_list, "Language", &(menu_list_item_event_handler), settingsScreen, SETTINGS_SCREEN_CATEGORY_LANGUAGE);
settingsScreen->about_item = add_menu_list_item(menu_list, "About", &(menu_list_item_event_handler), settingsScreen, SETTINGS_SCREEN_CATEGORY_ABOUT);
//We register the event callback to handle gesture
// We register the event callback to handle gesture
lv_obj_add_event_cb(settingsScreen->display, &(gesture_event_cb), LV_EVENT_GESTURE, settingsScreen);
//We register the event callback to handle the cleanup
// We register the event callback to handle the cleanup
lv_obj_add_event_cb(settingsScreen->display, &(cleanup_event_cb), LV_EVENT_DELETE, settingsScreen);
//We load the default side screen content (time and date)
// We load the default side screen content (time and date)
_simulate_side_screen_item_click(settingsScreen, settingsScreen->time_and_date_item);
}
@ -620,6 +613,12 @@ void settings_screen_destroy(SettingsScreen_t * const settingsScreen)
return;
}
if (settingsScreen->last_selected_item)
{
if (settingsScreen->settingsScreenOnStateChangeCb)
settingsScreen->settingsScreenOnStateChangeCb(SETTINGS_SCREEN_STATE_CLOSED, (SettingsScreenCategory_e)lv_obj_get_user_data(settingsScreen->last_selected_item));
}
settingsScreen->hour_roller = NULL;
settingsScreen->minute_roller = NULL;
settingsScreen->second_roller = NULL;
@ -641,13 +640,26 @@ static void _simulate_side_screen_item_click(SettingsScreen_t * const settingsSc
settingsScreen->about_refresh_timer = NULL;
}
//Updating the background of the selected category
// Updating the background of the selected category
lv_obj_set_style_bg_color(item, lv_color_make(178, 223, 219), LV_PART_MAIN);
if(settingsScreen->last_selected_item)
lv_obj_set_style_bg_color(settingsScreen->last_selected_item, lv_color_white(), LV_PART_MAIN);
// Let's call the settings screen on state change callback if registered
if(settingsScreen->settingsScreenOnStateChangeCb)
settingsScreen->settingsScreenOnStateChangeCb(SETTINGS_SCREEN_STATE_OPENED, (SettingsScreenCategory_e)lv_obj_get_user_data(item));
if(settingsScreen->last_selected_item)
{
if(settingsScreen->settingsScreenOnStateChangeCb)
settingsScreen->settingsScreenOnStateChangeCb(SETTINGS_SCREEN_STATE_CLOSED, (SettingsScreenCategory_e)lv_obj_get_user_data(settingsScreen->last_selected_item));
}
settingsScreen->last_selected_item = item;
lv_obj_clean(settingsScreen->side_screen);
_reset_switch_pointers(settingsScreen);
if(item == settingsScreen->time_and_date_item)
{
load_time_and_date_side_screen(settingsScreen);
@ -710,7 +722,7 @@ static void _enable_time_and_date_rollers(bool enabled, SettingsScreen_t * const
}
}
static lv_obj_t *add_menu_list_item(lv_obj_t *list, const char *text, lv_event_cb_t event_cb, void *user_data)
static lv_obj_t *add_menu_list_item(lv_obj_t *list, const char *text, lv_event_cb_t event_cb, void *user_data, SettingsScreenCategory_e category)
{
lv_obj_t *btn = lv_list_add_btn(list, NULL, text);
lv_obj_t *label = lv_obj_get_child(btn, 0);
@ -721,6 +733,7 @@ static lv_obj_t *add_menu_list_item(lv_obj_t *list, const char *text, lv_event_c
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
}
lv_obj_set_user_data(btn, (void *)category);
lv_obj_add_event_cb(btn, event_cb, LV_EVENT_CLICKED, user_data);
return btn;
}

View File

@ -8,6 +8,24 @@ typedef struct SettingsScreenAPIInterface
} SettingsScreenAPIInterface_t;
typedef enum SettingsScreenState
{
SETTINGS_SCREEN_STATE_OPENED = 0,
SETTINGS_SCREEN_STATE_CLOSED
} SettingsScreenState_e;
typedef enum SettingsScreenCategory
{
SETTINGS_SCREEN_CATEGORY_TIME_AND_DATE = 0,
SETTINGS_SCREEN_CATEGORY_DISPLAY,
SETTINGS_SCREEN_CATEGORY_NOTIFICATION,
SETTINGS_SCREEN_CATEGORY_CONNECTIVITY,
SETTINGS_SCREEN_CATEGORY_LANGUAGE,
SETTINGS_SCREEN_CATEGORY_ABOUT,
} SettingsScreenCategory_e;
typedef void (*SettingsScreenOnStateChangeCb_t)(SettingsScreenState_e settingsScreenState, SettingsScreenCategory_e settingsScreenCategory);
typedef struct SettingsScreen
{
SettingsScreenAPIInterface_t settingsScreenAPIInterface;
@ -64,10 +82,21 @@ typedef struct SettingsScreen
/* Other */
lv_timer_t *about_refresh_timer;
SettingsScreenOnStateChangeCb_t settingsScreenOnStateChangeCb;
} SettingsScreen_t;
void settings_screen_init(SettingsScreen_t * const settingsScreen);
/**
* @brief Registers a callback function which will be called every time the state of the application changes ie : is opened or closed.
* This callback should be used to initialize and deinitialize needed devices drivers like the magnetometer or the temperature sensor.
* @note The state of the application is passed as a parameter or the callback function.
*
* @param settingsScreen a pointer to the settings screen object structure.
* @param SettingsScreenOnStateChangeCb the callback of type @ref SettingsScreenOnStateChangeCb_t to register.
*/
void settings_screen_register_on_state_change_cb(SettingsScreen_t * const settingsScreen, SettingsScreenOnStateChangeCb_t SettingsScreenOnStateChangeCb);
void settings_screen_register_API_interface(SettingsScreen_t * const settingsScreen, SettingsScreenAPIInterface_t * const settingsScreenAPIInterface);
void settings_screen_create(SettingsScreen_t * const settingsScreen);

View File

@ -1,7 +1,9 @@
#include "lvgl.h"
#include "watch_face.h"
#include "menu_screen.h"
#include "notification_screen.h"
#include <stdio.h>
#include <stdlib.h>
LV_IMG_DECLARE(battery_low_icon)
LV_IMG_DECLARE(battery_charging_icon)
@ -64,8 +66,6 @@ static void cleanup_event_cb(lv_event_t * e)
static void update_watch_hands_angles(WatchFace_t * const watchFace, uint8_t increment)
{
static uint8_t dateNum = 1;
if(!watchFace)
{
LV_LOG_ERROR("NULL pointer given !");
@ -76,16 +76,13 @@ static void update_watch_hands_angles(WatchFace_t * const watchFace, uint8_t inc
if(watchFace->dateTimeCb)
{
//We compute each hand angle
if(!increment || watchFace->secondHand.handAngle >= 3660 || (int)watchFace->secondHand.handAngle % 100 > 50)
if(!increment || watchFace->secondHand.handAngle >= 3660 /*|| (int)watchFace->secondHand.handAngle % 100 > 50*/)
{
watchFace->dateTimeCb(&watchFace->dateTime);
watchFace->secondHand.handAngle = 60 * watchFace->dateTime.tm_sec;
dateNum++;
dateNum %= 31;
//Don't forget to update the day date window
sprintf(watchFace->dateWindow.dateWindowText, "%d", /*watchFace->dateTime.tm_mday*/ dateNum);
sprintf(watchFace->dateWindow.dateWindowText, "%d", watchFace->dateTime.tm_mday);
lv_label_set_text_static(watchFace->dateWindow.dateWindowWidget, watchFace->dateWindow.dateWindowText);
if(watchFace->batteryIndicatorCb)
@ -206,6 +203,20 @@ static void hide_hour_and_minutes_hand_cb(lv_event_t *e)
lv_obj_add_flag(watchFace->hourHand.handImg, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(watchFace->minuteHand.handImg, LV_OBJ_FLAG_HIDDEN);
}*/
//Just for testing purposes, create a new notification
char *title = malloc(strlen("JoeJohny John")+1);
strcpy(title, "JoeJohny John");
char *body = malloc(300+1);
strcpy(body, "Hey what's up dude ? What are you doing tonight ?\
Wanna go to the fair with me ?\
This is a quite long message I agree, but it is important\
to let you know what I do for me and you bro !");
extern NotificationScreen_t notificationScreen;
notification_screen_notify(&notificationScreen, 1696358171, time(NULL) + 3600*2, NOTIFICATION_TYPE_GADGET_BRIDGE, title, body);
LV_LOG_USER("unread(%u)/ total(%u)", notification_screen_unread_notification_count(&notificationScreen), notification_screen_notification_count(&notificationScreen));
}
void watch_face_init(WatchFace_t * const watchFace)
@ -304,11 +315,7 @@ void watch_face_create(WatchFace_t * const watchFace)
lv_obj_del(watchFace->batteryIndicator.batteryIcon);
watchFace->batteryIndicator.batteryIcon = NULL;
}
watchFace->batteryIndicator.batteryIcon = lv_img_create(watchFace->display);
set_battery_state_icon(watchFace);
lv_img_set_zoom(watchFace->batteryIndicator.batteryIcon, 141);
lv_obj_align_to(watchFace->batteryIndicator.batteryIcon, watchFace->batteryIndicator.label, LV_ALIGN_OUT_BOTTOM_MID, 0, -9);
if(watchFace->batteryIndicator.lowBatteryAnimationTimer)
{
@ -319,6 +326,12 @@ void watch_face_create(WatchFace_t * const watchFace)
watchFace->batteryIndicator.lowBatteryAnimationTimer = lv_timer_create(&(battery_timer_anim_cb), 500, watchFace);
lv_timer_pause(watchFace->batteryIndicator.lowBatteryAnimationTimer);
// set_battery_state_icon internally needs to interact with the lowBatteryAnimationTimer,
// this is why we call the function after the timer has been created
set_battery_state_icon(watchFace);
lv_img_set_zoom(watchFace->batteryIndicator.batteryIcon, 141);
lv_obj_align_to(watchFace->batteryIndicator.batteryIcon, watchFace->batteryIndicator.label, LV_ALIGN_OUT_BOTTOM_MID, 0, -9);
// Bluetooth status icon is created here
if(watchFace->bluetoothIndicator.bluetoothIcon)
{