397 lines
10 KiB
C
397 lines
10 KiB
C
#include "app_config.h"
|
|
#include "rtc/alarm.h"
|
|
#include "app_action.h"
|
|
#include "system/includes.h"
|
|
#include "clock_cfg.h"
|
|
#include "ioctl_cmds.h"
|
|
#include "system/sys_time.h"
|
|
|
|
#if (TCFG_APP_RTC_EN && TCFG_USE_VIRTUAL_RTC)
|
|
|
|
|
|
/*************************************************************
|
|
此文件函数主要是虚拟rtc设备的实现
|
|
应用于不外挂晶振的场景,用户可以忽略实现,
|
|
最后的应用的接口与挂晶振的接口一致
|
|
**************************************************************/
|
|
|
|
|
|
#define WRITE_ALARM BIT(1)
|
|
#define READ_ALARM BIT(5)
|
|
|
|
#define WRITE_RTC BIT(0)
|
|
#define READ_RTC BIT(4)
|
|
|
|
#define MAX_YEAR 2099
|
|
#define MIN_YEAR 2000
|
|
|
|
|
|
typedef struct _RTC_SIMULATE_VAR {
|
|
struct device device;
|
|
struct sys_time sys_simulate_time;
|
|
struct sys_time sys_alarm_time;
|
|
/* OS_MUTEX mutex; */
|
|
} RTC_SIMULATE_VAR;
|
|
|
|
#define __this (&rtc_smulate_var)
|
|
static RTC_SIMULATE_VAR rtc_smulate_var sec(.vir_rtc) = {0};
|
|
|
|
volatile static u8 g_alarm_flag = 0;
|
|
static u64 sum_nsec = 0;
|
|
extern u16 __month_to_day(u16 year, u8 month);
|
|
|
|
static void write_alarm(struct sys_time *alarm_time);
|
|
void set_alarm_default_time(struct sys_time *t)
|
|
{
|
|
t->year = 2019;
|
|
t->month = 1;
|
|
t->day = 1;
|
|
t->hour = 18;
|
|
t->min = 19;
|
|
t->sec = 00;
|
|
write_alarm(t);
|
|
}
|
|
__attribute__((weak))void alm_wakeup_isr(void);
|
|
__attribute__((weak)) void set_rtc_default_time(struct sys_time *t);
|
|
u8 rtc_get_time_vm();
|
|
u8 rtc_save_time_vm();
|
|
u8 rtc_get_alm_vm();
|
|
u8 rtc_save_alm_vm();
|
|
|
|
static u8 is_the_same_time(struct sys_time *time1, struct sys_time *time2)
|
|
{
|
|
return (time1->year == time2->year &&
|
|
time1->month == time2->month &&
|
|
time1->day == time2->day &&
|
|
time1->hour == time2->hour &&
|
|
time1->min == time2->min &&
|
|
time1->sec == time2->sec);
|
|
}
|
|
|
|
void rtc_simulate_dump()
|
|
{
|
|
printf("rtc_simulate_time: %d-%d-%d %d:%d:%d\n",
|
|
__this->sys_simulate_time.year,
|
|
__this->sys_simulate_time.month,
|
|
__this->sys_simulate_time.day,
|
|
__this->sys_simulate_time.hour,
|
|
__this->sys_simulate_time.min,
|
|
__this->sys_simulate_time.sec);
|
|
|
|
/* printf("rtc_alarm_time: %d-%d-%d %d:%d:%d\n", */
|
|
/* __this->sys_alarm_time.year, */
|
|
/* __this->sys_alarm_time.month, */
|
|
/* __this->sys_alarm_time.day, */
|
|
/* __this->sys_alarm_time.hour, */
|
|
/* __this->sys_alarm_time.min, */
|
|
/* __this->sys_alarm_time.sec); */
|
|
|
|
/* printf("alarm_flag = %d\n", g_alarm_flag); */
|
|
}
|
|
|
|
|
|
static int rtc_simulate_init(const struct dev_node *node, void *arg)
|
|
{
|
|
if (power_return_flag()) {
|
|
/* os_mutex_create(&__this->mutex); */
|
|
if (0) {
|
|
|
|
} else if (set_rtc_default_time) {
|
|
set_rtc_default_time(&__this->sys_simulate_time);
|
|
} else {
|
|
__this->sys_simulate_time.year = 2020;
|
|
__this->sys_simulate_time.month = 1;
|
|
__this->sys_simulate_time.day = 1;
|
|
__this->sys_simulate_time.hour = 0;
|
|
__this->sys_simulate_time.min = 0;
|
|
__this->sys_simulate_time.sec = 0;
|
|
}
|
|
} else {
|
|
if (__this->sys_simulate_time.year == 0) {
|
|
__this->sys_simulate_time.year = 2021;
|
|
}
|
|
if (__this->sys_simulate_time.month == 0) {
|
|
__this->sys_simulate_time.month = 1;
|
|
}
|
|
if (__this->sys_simulate_time.day == 0) {
|
|
__this->sys_simulate_time.day = 1;
|
|
}
|
|
}
|
|
|
|
rtc_get_alm_vm();
|
|
rtc_save_time_vm();
|
|
|
|
/* set_rtc_default_time(&__this->sys_simulate_time); */
|
|
printf("rtc_simulate_init: %d-%d-%d %d:%d:%d\n",
|
|
__this->sys_simulate_time.year,
|
|
__this->sys_simulate_time.month,
|
|
__this->sys_simulate_time.day,
|
|
__this->sys_simulate_time.hour,
|
|
__this->sys_simulate_time.min,
|
|
__this->sys_simulate_time.sec);
|
|
/* sys_timer_add(NULL, rtc_simulate_dump, 1000); */
|
|
|
|
/* set_alarm_default_time(&__this->sys_alarm_time); */
|
|
return 0;
|
|
}
|
|
|
|
static int rtc_simulate_open(const char *name, struct device **device, void *arg)
|
|
{
|
|
*device = &__this->device;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void write_alarm(struct sys_time *alarm_time)
|
|
{
|
|
local_irq_disable();
|
|
memcpy(&__this->sys_alarm_time, alarm_time, sizeof(struct sys_time));
|
|
rtc_save_alm_vm();
|
|
local_irq_enable();
|
|
}
|
|
|
|
static void read_alarm(struct sys_time *alarm_time)
|
|
{
|
|
local_irq_disable();
|
|
rtc_get_alm_vm();
|
|
memcpy(alarm_time, &__this->sys_alarm_time, sizeof(struct sys_time));
|
|
local_irq_enable();
|
|
}
|
|
|
|
static void write_sys_time(struct sys_time *curr_time)
|
|
{
|
|
local_irq_disable();
|
|
memcpy(&__this->sys_simulate_time, curr_time, sizeof(struct sys_time));
|
|
local_irq_enable();
|
|
}
|
|
|
|
static void read_sys_time(struct sys_time *curr_time)
|
|
{
|
|
local_irq_disable();
|
|
memcpy(curr_time, &__this->sys_simulate_time, sizeof(struct sys_time));
|
|
local_irq_enable();
|
|
}
|
|
|
|
void vir_set_alarm_ctrl(u8 set_alarm)
|
|
{
|
|
g_alarm_flag = set_alarm;
|
|
}
|
|
|
|
u8 vir_get_alarm_ctrl(void)
|
|
{
|
|
return g_alarm_flag;
|
|
}
|
|
|
|
static int rtc_simulate_ioctl(struct device *device, u32 cmd, u32 arg)
|
|
{
|
|
int err = 0;
|
|
switch (cmd) {
|
|
case IOCTL_SET_ALARM:
|
|
write_alarm((struct sys_time *)arg);
|
|
break;
|
|
case IOCTL_GET_ALARM:
|
|
read_alarm((struct sys_time *)arg);
|
|
break;
|
|
case IOCTL_SET_ALARM_ENABLE:
|
|
if (arg) {
|
|
vir_set_alarm_ctrl(1);
|
|
} else {
|
|
vir_set_alarm_ctrl(0);
|
|
}
|
|
break;
|
|
case IOCTL_GET_SYS_TIME:
|
|
read_sys_time((struct sys_time *)arg);
|
|
break;
|
|
case IOCTL_SET_SYS_TIME:
|
|
write_sys_time((struct sys_time *)arg);
|
|
break;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
|
|
u8 rtc_save_time_vm()
|
|
{
|
|
u8 ret = syscfg_write(VM_VIR_RTC_TIME, &__this->sys_simulate_time, sizeof(struct sys_time));
|
|
return ret;
|
|
}
|
|
|
|
u8 rtc_get_time_vm()
|
|
{
|
|
u8 ret = syscfg_read(VM_VIR_RTC_TIME, &__this->sys_simulate_time, sizeof(struct sys_time));
|
|
return ret;
|
|
}
|
|
|
|
u8 rtc_save_alm_vm()
|
|
{
|
|
u8 ret = syscfg_write(VM_VIR_ALM_TIME, &__this->sys_alarm_time, sizeof(struct sys_time));
|
|
return ret;
|
|
}
|
|
|
|
u8 rtc_get_alm_vm()
|
|
{
|
|
u8 ret = syscfg_read(VM_VIR_ALM_TIME, &__this->sys_alarm_time, sizeof(struct sys_time));
|
|
return ret;
|
|
}
|
|
|
|
|
|
u8 rtc_save_sum_nsec_vm()
|
|
{
|
|
u8 ret = syscfg_write(VM_VIR_SUM_NSEC, &sum_nsec, 8);
|
|
return ret;
|
|
}
|
|
|
|
u8 rtc_get_sum_nsec_vm()
|
|
{
|
|
u8 ret = syscfg_read(VM_VIR_SUM_NSEC, &sum_nsec, 8);
|
|
return ret;
|
|
}
|
|
|
|
void set_virtual_rtc_tick(u64 actual_ns)
|
|
{
|
|
#if (defined(TCFG_USE_VIRTUAL_RTC) && (TCFG_USE_VIRTUAL_RTC))
|
|
struct sys_time temp_time;
|
|
static u8 cal_flag = 0;
|
|
|
|
sum_nsec += actual_ns;
|
|
if (sum_nsec >= 1000000000) {
|
|
sum_nsec -= 1000000000;
|
|
cal_flag = 1;
|
|
}
|
|
|
|
if (cal_flag) {
|
|
cal_flag = 0;
|
|
read_sys_time(&temp_time);
|
|
if (++temp_time.sec >= 60) {
|
|
temp_time.sec = 0;
|
|
if (++temp_time.min >= 60) {
|
|
temp_time.min = 0;
|
|
if (++temp_time.hour >= 24) {
|
|
temp_time.hour = 0;
|
|
if (++temp_time.day > __month_to_day(temp_time.year, temp_time.month)) {
|
|
temp_time.day = 1;
|
|
if (++temp_time.month > 12) {
|
|
temp_time.month = 1;
|
|
if (++temp_time.year > MAX_YEAR) {
|
|
temp_time.year = MIN_YEAR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
write_sys_time(&temp_time);
|
|
/* printf("rtc_sys_time: %d-%d-%d %d:%d:%d\n", */
|
|
/* temp_time.year, */
|
|
/* temp_time.month, */
|
|
/* temp_time.day, */
|
|
/* temp_time.hour, */
|
|
/* temp_time.min, */
|
|
/* temp_time.sec); */
|
|
|
|
local_irq_disable();
|
|
/* rtc_get_alm_vm(); */
|
|
if (g_alarm_flag && is_the_same_time(&__this->sys_alarm_time, &__this->sys_simulate_time)) {
|
|
local_irq_enable();
|
|
if (alm_wakeup_isr) {
|
|
alm_wakeup_isr();
|
|
}
|
|
} else {
|
|
local_irq_enable();
|
|
}
|
|
|
|
}
|
|
#endif
|
|
}
|
|
|
|
extern void vir_rtc_get_actual_time(u64 *actual_time);
|
|
void vir_rtc_trim()
|
|
{
|
|
u64 actual_time;
|
|
vir_rtc_get_actual_time(&actual_time);
|
|
u32 sec = actual_time / 1000000000;
|
|
u32 min = sec / 60;
|
|
sec = sec % 60;
|
|
u32 hour = min / 60;
|
|
min = min % 60;
|
|
|
|
struct sys_time temp_time;
|
|
rtc_get_time_vm();
|
|
read_sys_time(&temp_time);
|
|
temp_time.sec += sec;
|
|
if (temp_time.sec >= 60) {
|
|
temp_time.min++;
|
|
temp_time.sec -= 60;
|
|
}
|
|
temp_time.min += min;
|
|
if (temp_time.min >= 60) {
|
|
temp_time.hour++;
|
|
temp_time.min -= 60;
|
|
}
|
|
temp_time.hour += hour;
|
|
if (temp_time.hour >= 24) {
|
|
temp_time.day++;
|
|
temp_time.hour -= 24;
|
|
if (temp_time.day > __month_to_day(temp_time.year, temp_time.month)) {
|
|
temp_time.day = 1;
|
|
if (++temp_time.month > 12) {
|
|
temp_time.month = 1;
|
|
if (++temp_time.year > MAX_YEAR) {
|
|
temp_time.year = MIN_YEAR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
write_sys_time(&temp_time);
|
|
rtc_get_sum_nsec_vm();
|
|
set_virtual_rtc_tick(actual_time % 1000000000);
|
|
printf("rtc_sys_time: %d-%d-%d %d:%d:%d\n",
|
|
temp_time.year,
|
|
temp_time.month,
|
|
temp_time.day,
|
|
temp_time.hour,
|
|
temp_time.min,
|
|
temp_time.sec);
|
|
}
|
|
|
|
u32 alm_trans_for_sec()
|
|
{
|
|
struct sys_time temp_time;
|
|
struct sys_time alm_time;
|
|
|
|
read_alarm(&alm_time);
|
|
u16 alm_day = ymd_to_day(&__this->sys_alarm_time);
|
|
|
|
/* rtc_get_time_vm(); */
|
|
read_sys_time(&temp_time);
|
|
u16 cur_day = ymd_to_day(&temp_time);
|
|
|
|
u32 alm_tmp = (alm_day << 17) | ((__this->sys_alarm_time.hour & 0x1f) << 12) | ((__this->sys_alarm_time.min & 0x3f) << 6) | (__this->sys_alarm_time.sec & 0x3f);
|
|
u32 cur_tmp = (cur_day << 17) | ((temp_time.hour & 0x1f) << 12) | ((temp_time.min & 0x3f) << 6) | (temp_time.sec & 0x3f);
|
|
if (alm_tmp < cur_tmp) {
|
|
return 0;
|
|
}
|
|
|
|
u32 day = alm_day - cur_day;
|
|
u32 hour = __this->sys_alarm_time.hour + day * 24 - temp_time.hour;
|
|
u32 min = __this->sys_alarm_time.min + hour * 60 - temp_time.min;
|
|
u32 sec = __this->sys_alarm_time.sec + min * 60 - temp_time.sec;
|
|
/* printf("alm_sec = %d\n", sec); */
|
|
return sec;
|
|
}
|
|
|
|
|
|
const struct device_operations rtc_simulate_ops = {
|
|
.init = rtc_simulate_init,
|
|
.open = rtc_simulate_open,
|
|
.ioctl = rtc_simulate_ioctl,
|
|
.read = NULL,
|
|
.write = NULL,
|
|
};
|
|
#else
|
|
void get_virtual_rtc_tick(u64 actual_ns)
|
|
{
|
|
g_printf("actual_time:%d", actual_ns);
|
|
}
|
|
#endif
|