生成的代码包
This commit is contained in:
@@ -0,0 +1,363 @@
|
||||
/******************************************************************************
|
||||
* @file usr_rtc.c
|
||||
* @brief 板级 RTC 外设实现(BR28 硬件 rtc_dev_ops)
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.19
|
||||
* @version V1.1.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.19, cyWu, 从模组固件移植至 SOC SDK
|
||||
* - V1.1.0, 2026.08.19, cyWu, 精简公共接口与缓存逻辑
|
||||
******************************************************************************/
|
||||
|
||||
#include "system/includes.h"
|
||||
#include "app_config.h"
|
||||
#include "usr_rtc.h"
|
||||
#include "asm/rtc.h"
|
||||
|
||||
#define LOG_TAG_CONST APP
|
||||
#define LOG_TAG "[USR_RTC]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
/*============================================================================*/
|
||||
/* 私有宏 / 类型 */
|
||||
/*============================================================================*/
|
||||
|
||||
#define USR_RTC_TZ_MAGIC (0x52544331u) /**< 'RTC1',校验 VM 时区 */
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
int32_t tz_s;
|
||||
} UsrRtcTzVm_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t inited;
|
||||
uint8_t tz_valid;
|
||||
int32_t tz_s;
|
||||
void *dev;
|
||||
} UsrRtc_t;
|
||||
|
||||
/*============================================================================*/
|
||||
/* 私有变量 */
|
||||
/*============================================================================*/
|
||||
|
||||
static UsrRtc_t s_rtc;
|
||||
|
||||
/*============================================================================*/
|
||||
/* 私有函数声明 */
|
||||
/*============================================================================*/
|
||||
|
||||
static uint8_t usr_rtc_is_leap(uint16_t year);
|
||||
static uint8_t usr_rtc_days_in_month(uint16_t year, uint8_t month);
|
||||
static uint8_t usr_rtc_year_ok(uint16_t year);
|
||||
static void usr_rtc_unix_to_calendar(uint32_t unix_utc, int32_t tz_s,
|
||||
struct sys_time *t);
|
||||
static UsrRtc_Ret_t usr_rtc_write(const struct sys_time *t);
|
||||
static void usr_rtc_load_tz(void);
|
||||
static void usr_rtc_save_tz(int32_t tz_s);
|
||||
|
||||
/*============================================================================*/
|
||||
/* 公有函数 */
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief 打开 rtc 设备并加载时区
|
||||
* @return UsrRtc_Ret_t
|
||||
*/
|
||||
UsrRtc_Ret_t usr_rtc_init(void)
|
||||
{
|
||||
struct sys_time t;
|
||||
|
||||
if (s_rtc.inited)
|
||||
{
|
||||
return USR_RTC_OK;
|
||||
}
|
||||
|
||||
#if TCFG_APP_RTC_EN
|
||||
s_rtc.dev = dev_open("rtc", NULL);
|
||||
if (!s_rtc.dev)
|
||||
{
|
||||
log_error("open rtc fail");
|
||||
return USR_RTC_ERR_NOT_INIT;
|
||||
}
|
||||
#else
|
||||
log_error("TCFG_APP_RTC_EN=0");
|
||||
return USR_RTC_ERR_NOT_INIT;
|
||||
#endif
|
||||
|
||||
usr_rtc_load_tz();
|
||||
s_rtc.inited = 1;
|
||||
|
||||
memset(&t, 0, sizeof(t));
|
||||
read_sys_time(&t);
|
||||
log_info("rtc open %u-%02u-%02u %02u:%02u:%02u tz=%ld tz_ok=%u",
|
||||
t.year, t.month, t.day, t.hour, t.min, t.sec,
|
||||
(long)s_rtc.tz_s, s_rtc.tz_valid);
|
||||
return USR_RTC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取当前本地时间
|
||||
* @param t 成功时赋值;失败不改动
|
||||
* @return 1/0
|
||||
*/
|
||||
uint8_t usr_rtc_get_time(struct sys_time *t)
|
||||
{
|
||||
struct sys_time tmp;
|
||||
|
||||
if (!t || !s_rtc.inited || !s_rtc.tz_valid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
read_sys_time(&tmp);
|
||||
if (!usr_rtc_year_ok(tmp.year))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
*t = tmp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UTC 秒 + 时区 → 本地日历写入 RTC
|
||||
* @param unix_utc UTC 秒
|
||||
* @param tz_s 时区偏移秒
|
||||
* @return UsrRtc_Ret_t
|
||||
*/
|
||||
UsrRtc_Ret_t usr_rtc_set_from_unix(uint64_t unix_utc, int32_t tz_s)
|
||||
{
|
||||
struct sys_time t;
|
||||
UsrRtc_Ret_t ret;
|
||||
|
||||
if (!s_rtc.inited)
|
||||
{
|
||||
return USR_RTC_ERR_NOT_INIT;
|
||||
}
|
||||
if (unix_utc == 0)
|
||||
{
|
||||
log_debug("unix=0, ignore");
|
||||
return USR_RTC_ERR_PARAM;
|
||||
}
|
||||
|
||||
/* 网关采样到写入大约慢 1s,在 UTC 上补偿 */
|
||||
unix_utc += USR_RTC_SYNC_COMPENSATE_S;
|
||||
if ((tz_s > USR_RTC_TZ_ABS_MAX_S) || (tz_s < -USR_RTC_TZ_ABS_MAX_S))
|
||||
{
|
||||
log_error("tz out of range %ld", (long)tz_s);
|
||||
return USR_RTC_ERR_PARAM;
|
||||
}
|
||||
if (unix_utc > 0xFFFFFFFFull)
|
||||
{
|
||||
log_error("unix too large");
|
||||
return USR_RTC_ERR_PARAM;
|
||||
}
|
||||
|
||||
usr_rtc_unix_to_calendar((uint32_t)unix_utc, tz_s, &t);
|
||||
if (!usr_rtc_year_ok(t.year))
|
||||
{
|
||||
log_error("year %u not in %u~%u, wait sync",
|
||||
t.year, USR_RTC_YEAR_MIN, USR_RTC_YEAR_MAX);
|
||||
return USR_RTC_ERR_INVALID;
|
||||
}
|
||||
|
||||
ret = usr_rtc_write(&t);
|
||||
if (ret != USR_RTC_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
usr_rtc_save_tz(tz_s);
|
||||
log_info("set rtc %u-%02u-%02u %02u:%02u:%02u tz=%ld",
|
||||
t.year, t.month, t.day, t.hour, t.min, t.sec, (long)tz_s);
|
||||
return USR_RTC_OK;
|
||||
}
|
||||
|
||||
/*============================================================================*/
|
||||
/* 私有函数 */
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief 写硬件日历
|
||||
* @param t 本地日历
|
||||
* @return UsrRtc_Ret_t
|
||||
*/
|
||||
static UsrRtc_Ret_t usr_rtc_write(const struct sys_time *t)
|
||||
{
|
||||
struct sys_time tmp;
|
||||
|
||||
if (!t)
|
||||
{
|
||||
return USR_RTC_ERR_PARAM;
|
||||
}
|
||||
if (!s_rtc.inited)
|
||||
{
|
||||
return USR_RTC_ERR_NOT_INIT;
|
||||
}
|
||||
if (!usr_rtc_year_ok(t->year) || (t->month < 1) || (t->month > 12) ||
|
||||
(t->day < 1) || (t->hour > 23) || (t->min > 59) || (t->sec > 59))
|
||||
{
|
||||
return USR_RTC_ERR_PARAM;
|
||||
}
|
||||
if (t->day > usr_rtc_days_in_month(t->year, t->month))
|
||||
{
|
||||
return USR_RTC_ERR_PARAM;
|
||||
}
|
||||
|
||||
tmp = *t;
|
||||
write_sys_time(&tmp);
|
||||
return USR_RTC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 是否闰年
|
||||
* @param year 公历年
|
||||
* @return 1/0
|
||||
*/
|
||||
static uint8_t usr_rtc_is_leap(uint16_t year)
|
||||
{
|
||||
if ((year % 400u) == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if ((year % 100u) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return ((year % 4u) == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 某月天数
|
||||
* @param year 年
|
||||
* @param month 月 1~12
|
||||
* @return 天数,非法月返回 0
|
||||
*/
|
||||
static uint8_t usr_rtc_days_in_month(uint16_t year, uint8_t month)
|
||||
{
|
||||
static const uint8_t days[12] = {
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
if ((month < 1) || (month > 12))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if ((month == 2) && usr_rtc_is_leap(year))
|
||||
{
|
||||
return 29;
|
||||
}
|
||||
return days[month - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 年份是否在合法窗口
|
||||
* @param year 年
|
||||
* @return 1/0
|
||||
*/
|
||||
static uint8_t usr_rtc_year_ok(uint16_t year)
|
||||
{
|
||||
return ((year >= USR_RTC_YEAR_MIN) && (year <= USR_RTC_YEAR_MAX)) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UTC 秒 + 时区 → 本地日历
|
||||
* @param unix_utc UTC 秒
|
||||
* @param tz_s 时区偏移
|
||||
* @param t 输出
|
||||
*/
|
||||
static void usr_rtc_unix_to_calendar(uint32_t unix_utc, int32_t tz_s,
|
||||
struct sys_time *t)
|
||||
{
|
||||
int64_t local;
|
||||
uint32_t days;
|
||||
uint32_t tod;
|
||||
uint16_t y;
|
||||
uint8_t m;
|
||||
uint8_t dim;
|
||||
|
||||
memset(t, 0, sizeof(*t));
|
||||
local = (int64_t)unix_utc + (int64_t)tz_s;
|
||||
if (local < 0)
|
||||
{
|
||||
local = 0;
|
||||
}
|
||||
|
||||
tod = (uint32_t)(local % 86400);
|
||||
days = (uint32_t)(local / 86400);
|
||||
t->sec = (uint8_t)(tod % 60u);
|
||||
t->min = (uint8_t)((tod / 60u) % 60u);
|
||||
t->hour = (uint8_t)(tod / 3600u);
|
||||
|
||||
y = 1970;
|
||||
while (1)
|
||||
{
|
||||
uint32_t diy = usr_rtc_is_leap(y) ? 366u : 365u;
|
||||
if (days < diy)
|
||||
{
|
||||
break;
|
||||
}
|
||||
days -= diy;
|
||||
y++;
|
||||
if (y > 4095u)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
t->year = y;
|
||||
|
||||
for (m = 1; m <= 12u; m++)
|
||||
{
|
||||
dim = usr_rtc_days_in_month(y, m);
|
||||
if (days < dim)
|
||||
{
|
||||
break;
|
||||
}
|
||||
days -= dim;
|
||||
}
|
||||
t->month = m;
|
||||
t->day = (uint8_t)(days + 1u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从 VM 加载时区
|
||||
*/
|
||||
static void usr_rtc_load_tz(void)
|
||||
{
|
||||
UsrRtcTzVm_t vm;
|
||||
int ret;
|
||||
|
||||
s_rtc.tz_valid = 0;
|
||||
s_rtc.tz_s = 0;
|
||||
memset(&vm, 0, sizeof(vm));
|
||||
ret = syscfg_read(CFG_USER_TIM_FLAG, (u8 *)&vm, sizeof(vm));
|
||||
if ((ret == (int)sizeof(vm)) && (vm.magic == USR_RTC_TZ_MAGIC))
|
||||
{
|
||||
if ((vm.tz_s <= USR_RTC_TZ_ABS_MAX_S) && (vm.tz_s >= -USR_RTC_TZ_ABS_MAX_S))
|
||||
{
|
||||
s_rtc.tz_s = vm.tz_s;
|
||||
s_rtc.tz_valid = 1;
|
||||
log_info("tz from vm %ld", (long)s_rtc.tz_s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
log_debug("tz vm empty");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 时区写入 VM
|
||||
* @param tz_s 时区偏移秒
|
||||
*/
|
||||
static void usr_rtc_save_tz(int32_t tz_s)
|
||||
{
|
||||
UsrRtcTzVm_t vm;
|
||||
|
||||
s_rtc.tz_s = tz_s;
|
||||
s_rtc.tz_valid = 1;
|
||||
vm.magic = USR_RTC_TZ_MAGIC;
|
||||
vm.tz_s = tz_s;
|
||||
syscfg_write(CFG_USER_TIM_FLAG, (u8 *)&vm, sizeof(vm));
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/******************************************************************************
|
||||
* @file usr_rtc.h
|
||||
* @brief 板级 RTC:硬件对时 + 客户读本地日历
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.19
|
||||
* @version V1.1.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.19, cyWu, 从模组固件移植至 SOC SDK
|
||||
* - V1.1.0, 2026.08.19, cyWu, 精简接口;usr_rtc_get_time 返回本地日历
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __USR_RTC_H__
|
||||
#define __USR_RTC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "system/sys_time.h"
|
||||
|
||||
/*============================================================================*/
|
||||
/* 宏定义 */
|
||||
/*============================================================================*/
|
||||
|
||||
#define USR_RTC_YEAR_MIN (2026u) /**< 合法年份下限 */
|
||||
#define USR_RTC_YEAR_MAX (2098u) /**< 合法年份上限 */
|
||||
#define USR_RTC_TZ_ABS_MAX_S (57600) /**< 时区偏移绝对值上限(±16h) */
|
||||
#define USR_RTC_SYNC_COMPENSATE_S (1u) /**< 网关对时延迟补偿(秒) */
|
||||
|
||||
/*============================================================================*/
|
||||
/* 错误码(init / set_from_unix) */
|
||||
/*============================================================================*/
|
||||
|
||||
typedef enum {
|
||||
USR_RTC_OK = 0,
|
||||
USR_RTC_ERR_PARAM,
|
||||
USR_RTC_ERR_NOT_INIT,
|
||||
USR_RTC_ERR_INVALID, /**< 年份非法,等待 App 对时 */
|
||||
} UsrRtc_Ret_t;
|
||||
|
||||
/*============================================================================*/
|
||||
/* 外部接口 */
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief 打开 "rtc" 设备并加载时区
|
||||
* @return UsrRtc_Ret_t
|
||||
* @note app_main 启动时调用一次即可
|
||||
*/
|
||||
UsrRtc_Ret_t usr_rtc_init(void);
|
||||
|
||||
/**
|
||||
* @brief 获取当前本地时间(客户常用)
|
||||
* @param t 成功时写入年月日时分秒;失败时不改动
|
||||
* @return 1=已对时且读成功,0=未初始化/未对时/参数非法
|
||||
*/
|
||||
uint8_t usr_rtc_get_time(struct sys_time *t);
|
||||
|
||||
/**
|
||||
* @brief App/网关 DEVICEINFO:UTC 秒 + 时区写入 RTC
|
||||
* @param unix_utc UTC Unix 秒;0 无效
|
||||
* @param tz_s 时区偏移秒(东八区 28800)
|
||||
* @return UsrRtc_Ret_t
|
||||
*/
|
||||
UsrRtc_Ret_t usr_rtc_set_from_unix(uint64_t unix_utc, int32_t tz_s);
|
||||
|
||||
#endif /* __USR_RTC_H__ */
|
||||
Reference in New Issue
Block a user