From c342a8d3f03a1f27b9cd7b41e22b9b75fe85e136 Mon Sep 17 00:00:00 2001 From: skiinder Date: Mon, 13 Apr 2026 16:43:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(protocol):=20=E6=B7=BB=E5=8A=A0=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E5=90=8C=E6=AD=A5=E5=92=8C=E4=B8=BB=E9=A2=98=E9=A2=9C?= =?UTF-8?q?=E8=89=B2=E5=8D=8F=E8=AE=AE=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加CDC_PROTO_TYPE_LED_STATE、CDC_PROTO_TYPE_TIME_SYNC和 CDC_PROTO_TYPE_THEME_RGB协议类型定义 - 在protobuf中定义LedState、TimeSync和ThemeRgb消息结构 - 更新CdcPacketBody消息以包含新的协议类型 - 增加协议能力标志位以支持新功能 --- CMakeLists.txt | 4 + inc/events/datetime_event.h | 26 ++++ inc/events/theme_rgb_update_event.h | 24 ++++ inc/events/time_sync_event.h | 26 ++++ inc/protocol_module.h | 3 + proto/device_comm.proto | 25 +++- src/display_module.c | 32 ++++- src/events/datetime_event.c | 27 ++++ src/events/theme_rgb_update_event.c | 34 +++++ src/events/time_sync_event.c | 41 ++++++ src/led_strip_module.c | 21 ++++ src/protocol_module.c | 135 +++++++++++++++++++- src/time_sync_module.c | 186 ++++++++++++++++++++++++++++ 13 files changed, 579 insertions(+), 5 deletions(-) create mode 100644 inc/events/datetime_event.h create mode 100644 inc/events/theme_rgb_update_event.h create mode 100644 inc/events/time_sync_event.h create mode 100644 src/events/datetime_event.c create mode 100644 src/events/theme_rgb_update_event.c create mode 100644 src/events/time_sync_event.c create mode 100644 src/time_sync_module.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e0609a2..6161d4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ target_sources(app PRIVATE src/led_effect/led_effect_registry.c src/led_effect/effects/led_effect_key_fade.c src/led_strip_module.c + src/time_sync_module.c src/ui/ui_main.c src/cdc_wrapper_module.c src/protocol_module.c @@ -43,6 +44,7 @@ target_sources(app PRIVATE src/events/ble_serial_rx_event.c src/events/ble_serial_tx_event.c src/events/cdc_proto_tx_event.c + src/events/datetime_event.c src/events/encoder_event.c src/events/function_bitmap_update_event.c src/events/hid_led_event.c @@ -55,6 +57,8 @@ target_sources(app PRIVATE src/events/keyboard_hid_report_event.c src/events/mode_switch_event.c src/events/set_protocol_event.c + src/events/theme_rgb_update_event.c + src/events/time_sync_event.c src/events/usb_cdc_rx_event.c src/events/usb_cdc_tx_event.c src/events/usb_device_state_event.c diff --git a/inc/events/datetime_event.h b/inc/events/datetime_event.h new file mode 100644 index 0000000..ec9848c --- /dev/null +++ b/inc/events/datetime_event.h @@ -0,0 +1,26 @@ +#ifndef BLINKY_DATETIME_EVENT_H_ +#define BLINKY_DATETIME_EVENT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define DATETIME_EVENT_DATE_TEXT_LEN 16 +#define DATETIME_EVENT_TIME_TEXT_LEN 16 + +struct datetime_event { + struct app_event_header header; + char date_text[DATETIME_EVENT_DATE_TEXT_LEN]; + char time_text[DATETIME_EVENT_TIME_TEXT_LEN]; +}; + +APP_EVENT_TYPE_DECLARE(datetime_event); + +#ifdef __cplusplus +} +#endif + +#endif /* BLINKY_DATETIME_EVENT_H_ */ diff --git a/inc/events/theme_rgb_update_event.h b/inc/events/theme_rgb_update_event.h new file mode 100644 index 0000000..b83fd68 --- /dev/null +++ b/inc/events/theme_rgb_update_event.h @@ -0,0 +1,24 @@ +#ifndef BLINKY_THEME_RGB_UPDATE_EVENT_H_ +#define BLINKY_THEME_RGB_UPDATE_EVENT_H_ + +#include +#include + +#include "theme_color.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct theme_rgb_update_event { + struct app_event_header header; + struct theme_rgb theme; +}; + +APP_EVENT_TYPE_DECLARE(theme_rgb_update_event); + +#ifdef __cplusplus +} +#endif + +#endif /* BLINKY_THEME_RGB_UPDATE_EVENT_H_ */ diff --git a/inc/events/time_sync_event.h b/inc/events/time_sync_event.h new file mode 100644 index 0000000..1522fd5 --- /dev/null +++ b/inc/events/time_sync_event.h @@ -0,0 +1,26 @@ +#ifndef BLINKY_TIME_SYNC_EVENT_H_ +#define BLINKY_TIME_SYNC_EVENT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct time_sync_event { + struct app_event_header header; + uint32_t version; + uint32_t flags; + int32_t timezone_min; + uint64_t utc_ms; + uint32_t accuracy_ms; +}; + +APP_EVENT_TYPE_DECLARE(time_sync_event); + +#ifdef __cplusplus +} +#endif + +#endif /* BLINKY_TIME_SYNC_EVENT_H_ */ diff --git a/inc/protocol_module.h b/inc/protocol_module.h index 64283f7..e6c1238 100644 --- a/inc/protocol_module.h +++ b/inc/protocol_module.h @@ -12,6 +12,9 @@ extern "C" { #define CDC_PROTO_TYPE_HELLO_RSP 0x02U #define CDC_PROTO_TYPE_BITMAP 0x10U #define CDC_PROTO_TYPE_FUNCTION_KEY_EVENT 0x20U +#define CDC_PROTO_TYPE_LED_STATE 0x21U +#define CDC_PROTO_TYPE_TIME_SYNC 0x30U +#define CDC_PROTO_TYPE_THEME_RGB 0x31U #define CDC_PROTO_TYPE_ACK 0x7EU #define CDC_PROTO_TYPE_ERROR 0x7FU diff --git a/proto/device_comm.proto b/proto/device_comm.proto index 7463555..b97b3a6 100644 --- a/proto/device_comm.proto +++ b/proto/device_comm.proto @@ -27,6 +27,24 @@ message FunctionKeyEvent { KeyAction action = 2; } +message LedState { + uint32 led_mask = 1; +} + +message TimeSync { + uint32 version = 1; + uint32 flags = 2; + sint32 timezone_min = 3; + fixed64 utc_ms = 4; + fixed32 accuracy_ms = 5; +} + +message ThemeRgb { + uint32 red = 1; + uint32 green = 2; + uint32 blue = 3; +} + message Ack { uint32 acked_type = 1; } @@ -50,7 +68,10 @@ message CdcPacketBody { HelloRsp hello_rsp = 2; Bitmap bitmap = 3; FunctionKeyEvent function_key_event = 4; - Ack ack = 5; - Error error = 6; + LedState led_state = 5; + TimeSync time_sync = 6; + ThemeRgb theme_rgb = 7; + Ack ack = 8; + Error error = 9; } } diff --git a/src/display_module.c b/src/display_module.c index cab9e48..08d773a 100644 --- a/src/display_module.c +++ b/src/display_module.c @@ -14,8 +14,10 @@ #include #include "bat_state_event.h" +#include "datetime_event.h" #include "hid_led_event.h" #include "mode_switch_event.h" +#include "theme_rgb_update_event.h" #include "theme_color.h" #include "ui/ui_main.h" @@ -40,6 +42,8 @@ static struct ui_main_model ui_model = { static bool initialized; static bool running; static bool lvgl_initialized; +static char date_text[DATETIME_EVENT_DATE_TEXT_LEN] = "1970/01/01"; +static char time_text[DATETIME_EVENT_TIME_TEXT_LEN] = "00:00:00"; static int backlight_set(bool on) { @@ -93,7 +97,7 @@ static int module_start(void) lvgl_initialized = true; lvgl_lock(); - ui_main_init(&ui_model, "WH Mini", "Hello World"); + ui_main_init(&ui_model, date_text, time_text); lvgl_unlock(); } @@ -135,7 +139,7 @@ static void refresh_ui(void) } lvgl_lock(); - ui_main_refresh_all(&ui_model, "WH Mini", "Hello World"); + ui_main_refresh_all(&ui_model, date_text, time_text); lvgl_unlock(); } @@ -167,6 +171,28 @@ static bool app_event_handler(const struct app_event_header *aeh) return false; } + if (is_theme_rgb_update_event(aeh)) { + const struct theme_rgb_update_event *event = + cast_theme_rgb_update_event(aeh); + + ui_model.theme_color = (lv_color_t)LV_COLOR_MAKE(event->theme.r, + event->theme.g, + event->theme.b); + refresh_ui(); + return false; + } + + if (is_datetime_event(aeh)) { + const struct datetime_event *event = cast_datetime_event(aeh); + + strncpy(date_text, event->date_text, sizeof(date_text)); + date_text[sizeof(date_text) - 1] = '\0'; + strncpy(time_text, event->time_text, sizeof(time_text)); + time_text[sizeof(time_text) - 1] = '\0'; + refresh_ui(); + return false; + } + if (is_module_state_event(aeh)) { const struct module_state_event *event = cast_module_state_event(aeh); int err; @@ -221,8 +247,10 @@ static bool app_event_handler(const struct app_event_header *aeh) APP_EVENT_LISTENER(MODULE, app_event_handler); APP_EVENT_SUBSCRIBE(MODULE, bat_state_event); +APP_EVENT_SUBSCRIBE(MODULE, datetime_event); APP_EVENT_SUBSCRIBE(MODULE, hid_led_event); APP_EVENT_SUBSCRIBE(MODULE, module_state_event); APP_EVENT_SUBSCRIBE(MODULE, mode_switch_event); +APP_EVENT_SUBSCRIBE(MODULE, theme_rgb_update_event); APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event); APP_EVENT_SUBSCRIBE(MODULE, wake_up_event); diff --git a/src/events/datetime_event.c b/src/events/datetime_event.c new file mode 100644 index 0000000..254ee65 --- /dev/null +++ b/src/events/datetime_event.c @@ -0,0 +1,27 @@ +#include "datetime_event.h" + +static void log_datetime_event(const struct app_event_header *aeh) +{ + const struct datetime_event *event = cast_datetime_event(aeh); + + APP_EVENT_MANAGER_LOG(aeh, "date:%s time:%s", + event->date_text, event->time_text); +} + +static void profile_datetime_event(struct log_event_buf *buf, + const struct app_event_header *aeh) +{ + ARG_UNUSED(buf); + ARG_UNUSED(aeh); +} + +APP_EVENT_INFO_DEFINE(datetime_event, + ENCODE(), + ENCODE(), + profile_datetime_event); + +APP_EVENT_TYPE_DEFINE(datetime_event, + log_datetime_event, + &datetime_event_info, + APP_EVENT_FLAGS_CREATE( + APP_EVENT_TYPE_FLAGS_INIT_LOG_ENABLE)); diff --git a/src/events/theme_rgb_update_event.c b/src/events/theme_rgb_update_event.c new file mode 100644 index 0000000..e87f109 --- /dev/null +++ b/src/events/theme_rgb_update_event.c @@ -0,0 +1,34 @@ +#include "theme_rgb_update_event.h" + +static void log_theme_rgb_update_event(const struct app_event_header *aeh) +{ + const struct theme_rgb_update_event *event = + cast_theme_rgb_update_event(aeh); + + APP_EVENT_MANAGER_LOG(aeh, "r:%u g:%u b:%u", + event->theme.r, event->theme.g, event->theme.b); +} + +static void profile_theme_rgb_update_event(struct log_event_buf *buf, + const struct app_event_header *aeh) +{ + const struct theme_rgb_update_event *event = + cast_theme_rgb_update_event(aeh); + + nrf_profiler_log_encode_uint8(buf, event->theme.r); + nrf_profiler_log_encode_uint8(buf, event->theme.g); + nrf_profiler_log_encode_uint8(buf, event->theme.b); +} + +APP_EVENT_INFO_DEFINE(theme_rgb_update_event, + ENCODE(NRF_PROFILER_ARG_U8, + NRF_PROFILER_ARG_U8, + NRF_PROFILER_ARG_U8), + ENCODE("r", "g", "b"), + profile_theme_rgb_update_event); + +APP_EVENT_TYPE_DEFINE(theme_rgb_update_event, + log_theme_rgb_update_event, + &theme_rgb_update_event_info, + APP_EVENT_FLAGS_CREATE( + APP_EVENT_TYPE_FLAGS_INIT_LOG_ENABLE)); diff --git a/src/events/time_sync_event.c b/src/events/time_sync_event.c new file mode 100644 index 0000000..9be11a5 --- /dev/null +++ b/src/events/time_sync_event.c @@ -0,0 +1,41 @@ +#include "time_sync_event.h" + +static void log_time_sync_event(const struct app_event_header *aeh) +{ + const struct time_sync_event *event = cast_time_sync_event(aeh); + + APP_EVENT_MANAGER_LOG(aeh, + "ver:%u flags:0x%08x tz:%d utc_ms:%llu acc:%u", + event->version, + event->flags, + event->timezone_min, + event->utc_ms, + event->accuracy_ms); +} + +static void profile_time_sync_event(struct log_event_buf *buf, + const struct app_event_header *aeh) +{ + const struct time_sync_event *event = cast_time_sync_event(aeh); + + nrf_profiler_log_encode_uint32(buf, event->version); + nrf_profiler_log_encode_uint32(buf, event->flags); + nrf_profiler_log_encode_int32(buf, event->timezone_min); + nrf_profiler_log_encode_uint32(buf, (uint32_t)(event->utc_ms & 0xFFFFFFFFULL)); + nrf_profiler_log_encode_uint32(buf, event->accuracy_ms); +} + +APP_EVENT_INFO_DEFINE(time_sync_event, + ENCODE(NRF_PROFILER_ARG_U32, + NRF_PROFILER_ARG_U32, + NRF_PROFILER_ARG_S32, + NRF_PROFILER_ARG_U32, + NRF_PROFILER_ARG_U32), + ENCODE("version", "flags", "timezone_min", "utc_ms_lo", "accuracy_ms"), + profile_time_sync_event); + +APP_EVENT_TYPE_DEFINE(time_sync_event, + log_time_sync_event, + &time_sync_event_info, + APP_EVENT_FLAGS_CREATE( + APP_EVENT_TYPE_FLAGS_INIT_LOG_ENABLE)); diff --git a/src/led_strip_module.c b/src/led_strip_module.c index 5a8fbee..81a67aa 100644 --- a/src/led_strip_module.c +++ b/src/led_strip_module.c @@ -18,6 +18,7 @@ #include "led_effect/led_effect.h" #include "led_strip_en_event.h" +#include "theme_rgb_update_event.h" #include "theme_color.h" LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); @@ -276,6 +277,21 @@ static bool handle_led_strip_en_event(const struct led_strip_en_event *event) return false; } +static bool handle_theme_rgb_update_event(const struct theme_rgb_update_event *event) +{ + current_theme = event->theme; + + if ((effect != NULL) && (effect->ops != NULL)) { + effect->ops->set_theme(effect, ¤t_theme); + } + + if (running && enabled && (effect != NULL) && effect->ops->is_active(effect)) { + schedule_effect_tick(K_NO_WAIT); + } + + return false; +} + static bool app_event_handler(const struct app_event_header *aeh) { if (is_button_event(aeh)) { @@ -286,6 +302,10 @@ static bool app_event_handler(const struct app_event_header *aeh) return handle_led_strip_en_event(cast_led_strip_en_event(aeh)); } + if (is_theme_rgb_update_event(aeh)) { + return handle_theme_rgb_update_event(cast_theme_rgb_update_event(aeh)); + } + if (is_module_state_event(aeh)) { const struct module_state_event *event = cast_module_state_event(aeh); @@ -343,5 +363,6 @@ APP_EVENT_LISTENER(MODULE, app_event_handler); APP_EVENT_SUBSCRIBE_EARLY(MODULE, button_event); APP_EVENT_SUBSCRIBE(MODULE, led_strip_en_event); APP_EVENT_SUBSCRIBE(MODULE, module_state_event); +APP_EVENT_SUBSCRIBE(MODULE, theme_rgb_update_event); APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event); APP_EVENT_SUBSCRIBE(MODULE, wake_up_event); diff --git a/src/protocol_module.c b/src/protocol_module.c index 29823c8..fb5b247 100644 --- a/src/protocol_module.c +++ b/src/protocol_module.c @@ -18,8 +18,11 @@ #include +#include "theme_rgb_update_event.h" +#include "time_sync_event.h" #include "cdc_proto_tx_event.h" #include "function_bitmap_update_event.h" +#include "hid_led_event.h" #include "key_function_event.h" #include "protocol_module.h" #include "usb_device_state_event.h" @@ -31,7 +34,7 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); #define PROTOCOL_PRODUCT_ID 0x52F0U #define PROTOCOL_FIRMWARE_MAJOR 0U #define PROTOCOL_FIRMWARE_MINOR 0U -#define PROTOCOL_CAPABILITY_FLAGS BIT(0) +#define PROTOCOL_CAPABILITY_FLAGS (BIT(0) | BIT(1) | BIT(2) | BIT(3)) static bool initialized; static bool running; @@ -50,6 +53,12 @@ static bool type_matches_body(uint8_t type, const CdcPacketBody *body) return body->which_body == CdcPacketBody_bitmap_tag; case CDC_PROTO_TYPE_FUNCTION_KEY_EVENT: return body->which_body == CdcPacketBody_function_key_event_tag; + case CDC_PROTO_TYPE_LED_STATE: + return body->which_body == CdcPacketBody_led_state_tag; + case CDC_PROTO_TYPE_TIME_SYNC: + return body->which_body == CdcPacketBody_time_sync_tag; + case CDC_PROTO_TYPE_THEME_RGB: + return body->which_body == CdcPacketBody_theme_rgb_tag; case CDC_PROTO_TYPE_ACK: return body->which_body == CdcPacketBody_ack_tag; case CDC_PROTO_TYPE_ERROR: @@ -152,6 +161,17 @@ static int encode_function_key_event(uint16_t usage, uint8_t action, return encode_body(&body, payload, payload_buf_size, payload_len); } +static int encode_led_state(uint32_t led_mask, uint8_t *payload, + size_t payload_buf_size, size_t *payload_len) +{ + CdcPacketBody body = CdcPacketBody_init_zero; + + body.which_body = CdcPacketBody_led_state_tag; + body.body.led_state.led_mask = led_mask; + + return encode_body(&body, payload, payload_buf_size, payload_len); +} + static int submit_cdc_proto_tx_event(uint8_t type, const uint8_t *payload, size_t payload_len) { @@ -188,6 +208,45 @@ static int submit_function_bitmap_update_event(const Bitmap *bitmap) return 0; } +static int submit_theme_rgb_update_event(const ThemeRgb *theme_rgb) +{ + struct theme_rgb_update_event *event; + + if ((theme_rgb == NULL) || + (theme_rgb->red > 255U) || + (theme_rgb->green > 255U) || + (theme_rgb->blue > 255U)) { + return -EINVAL; + } + + event = new_theme_rgb_update_event(); + event->theme.r = (uint8_t)theme_rgb->red; + event->theme.g = (uint8_t)theme_rgb->green; + event->theme.b = (uint8_t)theme_rgb->blue; + APP_EVENT_SUBMIT(event); + + return 0; +} + +static int submit_time_sync_event(const TimeSync *time_sync) +{ + struct time_sync_event *event; + + if (time_sync == NULL) { + return -EINVAL; + } + + event = new_time_sync_event(); + event->version = time_sync->version; + event->flags = time_sync->flags; + event->timezone_min = time_sync->timezone_min; + event->utc_ms = time_sync->utc_ms; + event->accuracy_ms = time_sync->accuracy_ms; + APP_EVENT_SUBMIT(event); + + return 0; +} + static int encode_error_response(uint8_t req_type, ErrorCode error_code, uint8_t *rsp_type, uint8_t *rsp_payload, size_t rsp_payload_buf_size, @@ -339,6 +398,51 @@ int protocol_module_process_cdc_packet(uint8_t req_type, return encode_ack_response(req_type, rsp_type, rsp_payload, rsp_payload_buf_size, rsp_payload_len); + case CDC_PROTO_TYPE_TIME_SYNC: + if (!hello_done) { + return encode_error_response(req_type, ErrorCode_ERROR_CODE_NOT_READY, + rsp_type, rsp_payload, + rsp_payload_buf_size, + rsp_payload_len); + } + + if (body.body.time_sync.version != 1U) { + return encode_error_response(req_type, ErrorCode_ERROR_CODE_INVALID_PARAM, + rsp_type, rsp_payload, + rsp_payload_buf_size, + rsp_payload_len); + } + + err = submit_time_sync_event(&body.body.time_sync); + if (err) { + return encode_error_response(req_type, ErrorCode_ERROR_CODE_INVALID_PARAM, + rsp_type, rsp_payload, + rsp_payload_buf_size, + rsp_payload_len); + } + + return encode_ack_response(req_type, rsp_type, rsp_payload, + rsp_payload_buf_size, rsp_payload_len); + + case CDC_PROTO_TYPE_THEME_RGB: + if (!hello_done) { + return encode_error_response(req_type, ErrorCode_ERROR_CODE_NOT_READY, + rsp_type, rsp_payload, + rsp_payload_buf_size, + rsp_payload_len); + } + + err = submit_theme_rgb_update_event(&body.body.theme_rgb); + if (err) { + return encode_error_response(req_type, ErrorCode_ERROR_CODE_INVALID_PARAM, + rsp_type, rsp_payload, + rsp_payload_buf_size, + rsp_payload_len); + } + + return encode_ack_response(req_type, rsp_type, rsp_payload, + rsp_payload_buf_size, rsp_payload_len); + default: LOG_WRN("Unsupported CDC protocol type:0x%02x", req_type); return encode_error_response(req_type, ErrorCode_ERROR_CODE_UNKNOWN_TYPE, @@ -373,6 +477,30 @@ static bool handle_key_function_event(const struct key_function_event *event) return false; } +static bool handle_hid_led_event(const struct hid_led_event *event) +{ + uint8_t payload[64]; + size_t payload_len; + int err; + + if (!running || !usb_active || !hello_done) { + return false; + } + + err = encode_led_state(event->led_bm, payload, sizeof(payload), &payload_len); + if (err) { + LOG_WRN("LedState encode failed (%d)", err); + return false; + } + + err = submit_cdc_proto_tx_event(CDC_PROTO_TYPE_LED_STATE, payload, payload_len); + if (err) { + LOG_WRN("LedState submit failed (%d)", err); + } + + return false; +} + static bool handle_usb_device_state_event(const struct usb_device_state_event *event) { usb_active = (event->state == USB_DEVICE_STATE_ACTIVE); @@ -389,6 +517,10 @@ static bool app_event_handler(const struct app_event_header *aeh) return handle_key_function_event(cast_key_function_event(aeh)); } + if (is_hid_led_event(aeh)) { + return handle_hid_led_event(cast_hid_led_event(aeh)); + } + if (is_usb_device_state_event(aeh)) { return handle_usb_device_state_event(cast_usb_device_state_event(aeh)); } @@ -453,6 +585,7 @@ static bool app_event_handler(const struct app_event_header *aeh) } APP_EVENT_LISTENER(MODULE, app_event_handler); +APP_EVENT_SUBSCRIBE(MODULE, hid_led_event); APP_EVENT_SUBSCRIBE(MODULE, key_function_event); APP_EVENT_SUBSCRIBE(MODULE, module_state_event); APP_EVENT_SUBSCRIBE(MODULE, usb_device_state_event); diff --git a/src/time_sync_module.c b/src/time_sync_module.c new file mode 100644 index 0000000..014a3a3 --- /dev/null +++ b/src/time_sync_module.c @@ -0,0 +1,186 @@ +#include +#include +#include + +#include + +#define MODULE time_sync_module +#include +#include + +#include +#include +#include + +#include "datetime_event.h" +#include "time_sync_event.h" + +LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); + +#define TIME_SYNC_REFRESH_PERIOD K_SECONDS(1) + +static struct k_work_delayable refresh_work; +static bool initialized; +static bool running; +static int32_t timezone_min; +static uint64_t utc_ms_base; +static int64_t uptime_ms_base; + +static void submit_datetime_event(void) +{ + struct datetime_event *event = new_datetime_event(); + struct tm tm_buf; + time_t seconds; + int64_t local_ms; + + local_ms = (int64_t)utc_ms_base + + (k_uptime_get() - uptime_ms_base) + + ((int64_t)timezone_min * 60LL * 1000LL); + if (local_ms < 0) { + local_ms = 0; + } + + seconds = (time_t)(local_ms / 1000LL); + if (gmtime_r(&seconds, &tm_buf) == NULL) { + strncpy(event->date_text, "1970/01/01", sizeof(event->date_text)); + strncpy(event->time_text, "00:00:00", sizeof(event->time_text)); + } else { + snprintk(event->date_text, sizeof(event->date_text), + "%04u/%02u/%02u", + (unsigned int)(tm_buf.tm_year + 1900), + (unsigned int)(tm_buf.tm_mon + 1), + (unsigned int)tm_buf.tm_mday); + snprintk(event->time_text, sizeof(event->time_text), + "%02u:%02u:%02u", + (unsigned int)tm_buf.tm_hour, + (unsigned int)tm_buf.tm_min, + (unsigned int)tm_buf.tm_sec); + } + + APP_EVENT_SUBMIT(event); +} + +static void refresh_work_handler(struct k_work *work) +{ + ARG_UNUSED(work); + + if (!running) { + return; + } + + submit_datetime_event(); + k_work_reschedule(&refresh_work, TIME_SYNC_REFRESH_PERIOD); +} + +static int module_init(void) +{ + timezone_min = 0; + utc_ms_base = 0U; + uptime_ms_base = k_uptime_get(); + k_work_init_delayable(&refresh_work, refresh_work_handler); + return 0; +} + +static int module_start(void) +{ + if (running) { + return 0; + } + + running = true; + k_work_reschedule(&refresh_work, K_NO_WAIT); + + return 0; +} + +static void module_pause(void) +{ + if (!running) { + return; + } + + k_work_cancel_delayable(&refresh_work); + running = false; +} + +static bool handle_time_sync_event(const struct time_sync_event *event) +{ + if (event->version != 1U) { + LOG_WRN("Unexpected TimeSync version:%u", event->version); + return false; + } + + timezone_min = event->timezone_min; + utc_ms_base = event->utc_ms; + uptime_ms_base = k_uptime_get(); + + if (running) { + k_work_reschedule(&refresh_work, K_NO_WAIT); + } + + return false; +} + +static bool app_event_handler(const struct app_event_header *aeh) +{ + if (is_time_sync_event(aeh)) { + return handle_time_sync_event(cast_time_sync_event(aeh)); + } + + if (is_module_state_event(aeh)) { + const struct module_state_event *event = cast_module_state_event(aeh); + int err; + + if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { + if (!initialized) { + err = module_init(); + if (err) { + module_set_state(MODULE_STATE_ERROR); + return false; + } + + initialized = true; + } + + err = module_start(); + if (err) { + module_set_state(MODULE_STATE_ERROR); + } else { + module_set_state(MODULE_STATE_READY); + } + } + + return false; + } + + if (is_power_down_event(aeh)) { + if (initialized) { + module_pause(); + module_set_state(MODULE_STATE_STANDBY); + } + + return false; + } + + if (is_wake_up_event(aeh)) { + if (initialized) { + int err = module_start(); + + if (err) { + module_set_state(MODULE_STATE_ERROR); + } else { + module_set_state(MODULE_STATE_READY); + } + } + + return false; + } + + return false; +} + +APP_EVENT_LISTENER(MODULE, app_event_handler); +APP_EVENT_SUBSCRIBE(MODULE, module_state_event); +APP_EVENT_SUBSCRIBE(MODULE, time_sync_event); +APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event); +APP_EVENT_SUBSCRIBE(MODULE, wake_up_event);