From aa3dbec157b246973525d2dbc7ab5d3f15ba9bee Mon Sep 17 00:00:00 2001 From: caixiang2014 <953748225@qq.com> Date: Mon, 17 Aug 2026 17:27:48 +0800 Subject: [PATCH] feat: add network-synchronized log timestamps --- applications/VK_Client.c | 3 + applications/VK_Log.c | 121 +++++++++++++++++++++++++++++++++++++- applications/VK_Log.h | 3 + applications/drv_ec800k.c | 20 +++++++ applications/drv_ec800k.h | 3 + 5 files changed, 148 insertions(+), 2 deletions(-) diff --git a/applications/VK_Client.c b/applications/VK_Client.c index 0e3d569..dea1879 100644 --- a/applications/VK_Client.c +++ b/applications/VK_Client.c @@ -257,6 +257,9 @@ int16_t client_tcp_connect(Cclient_t *client) { } } + /* Query once after PDP is available, so network time has had a chance to sync. */ + BSP_LTE_InitLogClock(); + // BSP_LTE_SendCmd(AT_CFG_TRANS_SIZE, DEFAULT_EXPECT, DEFAULT_ERROR, LTE_CMD_WAIT_NORMAL); diff --git a/applications/VK_Log.c b/applications/VK_Log.c index 17ae994..99c224d 100644 --- a/applications/VK_Log.c +++ b/applications/VK_Log.c @@ -1,5 +1,110 @@ #include "VK_Log.h" #include +#include + +typedef struct +{ + rt_uint16_t year; + rt_uint8_t month; + rt_uint8_t day; + rt_uint8_t hour; + rt_uint8_t minute; + rt_uint8_t second; + rt_tick_t base_tick; + rt_bool_t valid; +} log_clock_t; + +static log_clock_t log_clock; + +static rt_bool_t is_leap_year(rt_uint16_t year) +{ + return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); +} + +static rt_uint8_t days_in_month(rt_uint16_t year, rt_uint8_t month) +{ + static const rt_uint8_t days[] = {31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31}; + return (month == 2 && is_leap_year(year)) ? 29 : days[month - 1]; +} + +static void log_clock_add_seconds(rt_uint32_t seconds, + rt_uint16_t *year, rt_uint8_t *month, + rt_uint8_t *day, rt_uint8_t *hour, + rt_uint8_t *minute, rt_uint8_t *second) +{ + rt_uint32_t days; + + *second += seconds % 60; + if (*second >= 60) { *second -= 60; seconds = seconds / 60 + 1; } + else { seconds /= 60; } + *minute += seconds % 60; + if (*minute >= 60) { *minute -= 60; seconds = seconds / 60 + 1; } + else { seconds /= 60; } + *hour += seconds % 24; + days = seconds / 24; + if (*hour >= 24) { *hour -= 24; days++; } + + while (days > 0) { + rt_uint8_t month_days = days_in_month(*year, *month); + if (*day < month_days) { (*day)++; days--; } + else { + *day = 1; + if (*month < 12) (*month)++; + else { *month = 1; (*year)++; } + days--; + } + } +} + +int dev_log_time_set_from_at(const char *response) +{ + const char *p; + rt_uint16_t year = 0; + rt_uint8_t fields[5]; + int year_digits = 0; + int i; + + if (response == RT_NULL) return -1; + p = rt_strstr(response, "+QLTS:"); + if (p != RT_NULL) year_digits = 4; + else { + p = rt_strstr(response, "+CCLK:"); + if (p == RT_NULL) return -1; + year_digits = 2; + } + p = strchr(p, '"'); + if (p == RT_NULL || p[1] == '"') return -1; + p++; + for (i = 0; i < year_digits; i++) { + if (p[i] < '0' || p[i] > '9') return -1; + year = (rt_uint16_t)(year * 10 + p[i] - '0'); + } + p += year_digits; + if (*p++ != '/') return -1; + for (i = 0; i < 5; i++) { + if (p[0] < '0' || p[0] > '9' || p[1] < '0' || p[1] > '9') return -1; + fields[i] = (rt_uint8_t)((p[0] - '0') * 10 + p[1] - '0'); + p += 2; + if (i == 0 && *p++ != '/') return -1; + if (i == 1 && *p++ != ',') return -1; + if (i >= 2 && i < 4 && *p++ != ':') return -1; + } + if ((year_digits == 4 && (year < 2000 || year > 2099)) || + (year_digits == 2 && year == 70 && fields[0] == 1 && fields[1] == 1) || + fields[0] < 1 || fields[0] > 12 || fields[1] < 1 || + fields[1] > days_in_month(year_digits == 2 ? (rt_uint16_t)(2000 + year) : year, + fields[0]) || fields[2] > 23 || + fields[3] > 59 || fields[4] > 59) return -1; + + log_clock.year = year_digits == 2 ? (rt_uint16_t)(2000 + year) : year; + log_clock.month = fields[0]; log_clock.day = fields[1]; + log_clock.hour = fields[2]; log_clock.minute = fields[3]; + log_clock.second = fields[4]; + log_clock.base_tick = rt_tick_get(); + log_clock.valid = RT_TRUE; + return 0; +} static struct ulog_backend vcom_backend; static rt_device_t log_dev = RT_NULL; @@ -16,8 +121,20 @@ static void vcom_log_output(struct ulog_backend *backend, (void)tag; (void)is_raw; - if (log_dev != RT_NULL && len > 0) - { + if (log_dev != RT_NULL && len > 0) { + char prefix[32]; + rt_uint16_t year = log_clock.year; + rt_uint8_t month = log_clock.month, day = log_clock.day; + rt_uint8_t hour = log_clock.hour, minute = log_clock.minute; + rt_uint8_t second = log_clock.second; + if (log_clock.valid) { + log_clock_add_seconds((rt_uint32_t)((rt_tick_get() - log_clock.base_tick) / + RT_TICK_PER_SECOND), + &year, &month, &day, &hour, &minute, &second); + rt_snprintf(prefix, sizeof(prefix), "[%04u-%02u-%02u %02u:%02u:%02u] ", + year, month, day, hour, minute, second); + (void)rt_device_write(log_dev, 0, prefix, rt_strlen(prefix)); + } (void)rt_device_write(log_dev, 0, log, len); } } diff --git a/applications/VK_Log.h b/applications/VK_Log.h index a4f8024..2e2ee11 100644 --- a/applications/VK_Log.h +++ b/applications/VK_Log.h @@ -10,6 +10,9 @@ extern "C"{ int dev_log_backend_init(rt_device_t dev); +/* Set the wall-clock baseline parsed from an EC800K QLTS/CCLK response. */ +int dev_log_time_set_from_at(const char *response); + #ifdef __cplusplus diff --git a/applications/drv_ec800k.c b/applications/drv_ec800k.c index 1e45526..ef242a4 100644 --- a/applications/drv_ec800k.c +++ b/applications/drv_ec800k.c @@ -37,6 +37,7 @@ CLte_dev_t lte_dev = { }; lte_diag_t lte_diag = {0}; +static bool lte_log_clock_query_done = false; void lte_diag_at_begin(const char *cmd) { rt_size_t i; @@ -134,6 +135,22 @@ void BSP_LTE_SetDataTxPaused(bool paused) { } } +void BSP_LTE_InitLogClock(void) { + if (lte_log_clock_query_done) { + return; + } + + lte_log_clock_query_done = true; + if (BSP_LTE_SendCmd(AT_QLTS, DEFAULT_EXPECT, DEFAULT_ERROR, + LTE_CMD_WAIT_NORMAL) == 0) { + if (dev_log_time_set_from_at((const char *)lte_dev.at_buf) != 0) { + LOG_W("EC800K clock is not synchronized; using untimestamped logs\n"); + } + } else { + LOG_W("EC800K clock query failed; using untimestamped logs\n"); + } +} + int16_t BSP_LTE_SendCmd(const char *cmd, const char *expect, const char *error, uint32_t waittime) { lte_diag_at_begin(cmd); @@ -365,6 +382,9 @@ void BSP_LTE_Config(void) { LOG_I("BSP_LTE_SendATE error\n"); } + /* Allow the network to update the module clock after registration. */ + BSP_LTE_SendCmd(AT_CTZU, DEFAULT_EXPECT, DEFAULT_ERROR, LTE_CMD_WAIT_NORMAL); + /*查询模块信息*/ if (lte_dev.dev_init_flag == true) { BSP_LTE_SendCmd(AT_ATI, DEFAULT_EXPECT, DEFAULT_ERROR, LTE_CMD_WAIT_NORMAL); diff --git a/applications/drv_ec800k.h b/applications/drv_ec800k.h index 7e5b9dc..4e20fee 100644 --- a/applications/drv_ec800k.h +++ b/applications/drv_ec800k.h @@ -71,6 +71,8 @@ extern "C" { #define AT_CIPMODE "AT+CIPMODE=1\r\n" #define AT_CCLK "AT+CCLK?\r\n" +#define AT_QLTS "AT+QLTS=2\r\n" +#define AT_CTZU "AT+CTZU=1\r\n" #define AT_GTPOS "AT+GTPOS?\r\n" #define AT_GTPOS0 "AT+GTPOS=0\r\n" // close @@ -317,6 +319,7 @@ void BSP_LTE_SendData(uint8_t *pdata, uint32_t length); void BSP_LTE_SetDataTxPaused(bool paused); void BSP_LTE_Config(void); +void BSP_LTE_InitLogClock(void); int BSP_LTE_GetICCID(char *pICCID);