503 lines
14 KiB
C
503 lines
14 KiB
C
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <stdbool.h>
|
||
|
||
#include "tvs_api/tvs_api.h"
|
||
#include "tvs_alert_impl.h"
|
||
#include "tvs_api_impl.h"
|
||
#include "system/includes.h"
|
||
|
||
#include "cJSON_common/cJSON.h"
|
||
#include "os/os_api.h"
|
||
#include "time.h"
|
||
#include "timer.h"
|
||
#include "tvs_media_player_inner.h"
|
||
#include "server/ai_server.h"
|
||
|
||
|
||
//打开则使用RTC闹钟,关闭使用系统闹钟
|
||
#define USE_RTC_ALARM 0
|
||
#define ALARM_TIMEOUT 60
|
||
|
||
//引用tencent平台api
|
||
extern const struct ai_sdk_api tc_tvs_api;
|
||
extern u8 upgrade_flag;
|
||
extern void tvs_taskq_post(int msg);
|
||
|
||
u8 alarm_rings = 0; //闹钟开启标志位
|
||
u8 alarm_interrupt_mode = 0; //0. 关闭语音识别 响应闹钟 1. 无视闹钟 继续当前语音识别
|
||
static int alert_init_flag = 0;
|
||
static int wakeup_timeout_id = 0;
|
||
static int alarm_wakeup_pid = 0;
|
||
|
||
|
||
|
||
typedef struct AlertInfo {
|
||
struct list_head entry;
|
||
char *schedule;
|
||
char *token;
|
||
char *type;
|
||
char *url;
|
||
int id;
|
||
time_t tSet;
|
||
} alert_info;
|
||
|
||
static alert_info alert_head;
|
||
|
||
typedef struct AlarmInfo {
|
||
int year;
|
||
int month;
|
||
int day;
|
||
int hour;
|
||
int min;
|
||
int sec;
|
||
} alarm_info;
|
||
|
||
extern void set_alarm_ctrl(u8 set_alarm);
|
||
static void rings(void *priv);
|
||
static void RTC_alarm(alert_info *new_alert);
|
||
|
||
|
||
|
||
static int time_quit = 1;
|
||
|
||
__attribute__((weak)) int get_listen_flag()
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
#if USE_RTC_ALARM
|
||
/* 打开闹钟开关 */
|
||
static struct sys_time set_alarm = {
|
||
.year = 2020,
|
||
.month = 10,
|
||
.day = 10,
|
||
.hour = 10,
|
||
.min = 10,
|
||
.sec = 10,
|
||
};
|
||
|
||
static void RTC_alarm_task(void)
|
||
{
|
||
void *dev = NULL;
|
||
dev = dev_open("rtc", NULL);
|
||
|
||
while (1) {
|
||
/* 获取时间信息 */
|
||
dev_ioctl(dev, IOCTL_GET_SYS_TIME, (u32)&set_alarm);
|
||
printf("time_run: %d-%d-%d %d:%d:%d\n", set_alarm.year, set_alarm.month, set_alarm.day, set_alarm.hour, set_alarm.min, set_alarm.sec);
|
||
/* 延时1秒 */
|
||
os_time_dly(100);
|
||
if (time_quit == 1) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
static void RTC_alarm(alert_info *new_alert)
|
||
{
|
||
void *dev = NULL;
|
||
|
||
|
||
/* 打开RTC设备 */
|
||
dev = dev_open("rtc", NULL);
|
||
|
||
/* 获取时间信息 */
|
||
dev_ioctl(dev, IOCTL_GET_ALARM, (u32)&set_alarm);
|
||
/* 打印时间信息 */
|
||
printf("get_alarm_time: %d-%d-%d %d:%d:%d\n", set_alarm.year, set_alarm.month, set_alarm.day, set_alarm.hour, set_alarm.min, set_alarm.sec);
|
||
|
||
/* u8 weekday = dev_ioctl(dev, IOCTL_GET_WEEKDAY, (u32)&set_alarm); */
|
||
/* printf("weekday = %d", weekday); */
|
||
|
||
/* 注册闹钟响铃回调函数 */
|
||
set_rtc_isr_callback(rings, (void *)new_alert);
|
||
|
||
set_alarm_ctrl(1);
|
||
/* 设置闹钟 */
|
||
struct tm tm = {0};
|
||
time_t timestamp = new_alert->tSet + 28800;
|
||
localtime_r(×tamp, &tm);
|
||
struct sys_time info = {0};
|
||
info.year = tm.tm_year + 1900;
|
||
info.month = tm.tm_mon + 1;
|
||
info.day = tm.tm_mday;
|
||
info.hour = tm.tm_hour;
|
||
info.min = tm.tm_min;
|
||
info.sec = tm.tm_sec;
|
||
dev_ioctl(dev, IOCTL_SET_ALARM, (u32)&info);
|
||
|
||
/* 清空时间信息 */
|
||
memset(&set_alarm, 0, sizeof(set_alarm));
|
||
/* 获取设置的闹钟信息 */
|
||
dev_ioctl(dev, IOCTL_GET_ALARM, (u32)&set_alarm);
|
||
printf("get_alarm_time: %d-%d-%d %d:%d:%d\n", set_alarm.year, set_alarm.month, set_alarm.day, set_alarm.hour, set_alarm.min, set_alarm.sec);
|
||
|
||
/* 关闭RTC设备 */
|
||
dev_close(dev);
|
||
dev = NULL;
|
||
|
||
#if 1
|
||
//创建闹钟线程 用来测试的 看下是否创建或在跑时
|
||
if (time_quit) {
|
||
time_quit = 0;
|
||
thread_fork("RTC_alarm", 20, 500, 0, NULL, RTC_alarm_task, NULL);
|
||
}
|
||
#endif
|
||
}
|
||
|
||
static void set_new_rtc_alarm(void)
|
||
{
|
||
struct list_head *pos = NULL;
|
||
alert_info *alert = NULL;
|
||
alert_info *save_alert = NULL;
|
||
alert_info *backup_alert = NULL;
|
||
list_for_each(pos, &alert_head.entry) {
|
||
alert = list_entry(pos, alert_info, entry);
|
||
if (save_alert == NULL) {
|
||
save_alert = alert;
|
||
} else {
|
||
if (alert->tSet < save_alert->tSet) {
|
||
save_alert = alert;
|
||
}
|
||
}
|
||
}
|
||
if (save_alert != NULL) {
|
||
RTC_alarm(save_alert);
|
||
} else {
|
||
set_alarm_ctrl(0);
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
static void SYS_alarm(alert_info *new_alert)
|
||
{
|
||
u32 now_time = time(NULL);
|
||
u32 timeout = (new_alert->tSet > now_time) ? (new_alert->tSet - now_time) : 0;
|
||
if (!timeout) {
|
||
return ;
|
||
}
|
||
new_alert->id = sys_timeout_add_to_task("app_core", new_alert, rings, timeout * 1000);
|
||
}
|
||
|
||
#endif
|
||
|
||
static void del_alarm_info(void *priv)
|
||
{
|
||
//删除闹钟
|
||
struct list_head *pos = NULL;
|
||
alert_info *del_alert = NULL;
|
||
alert_info *alert = (alert_info *)priv;
|
||
|
||
list_for_each(pos, &alert_head.entry) {
|
||
del_alert = list_entry(pos, alert_info, entry);
|
||
if (!strcmp(del_alert->token, alert->token)) {
|
||
list_del(&del_alert->entry);
|
||
free(del_alert->schedule);
|
||
free(del_alert->token);
|
||
free(del_alert->type);
|
||
free(del_alert);
|
||
printf("-------%s---------%d-----del !\n\n", __func__, __LINE__);
|
||
break;
|
||
}
|
||
}
|
||
#if USE_RTC_ALARM
|
||
set_new_rtc_alarm();
|
||
#endif
|
||
}
|
||
|
||
|
||
//要是停止闹钟 调用这个函数
|
||
void alarm_rings_stop(int tvs_alert_stop_reason)
|
||
{
|
||
if (alarm_rings == 0) {
|
||
return ;
|
||
}
|
||
os_taskq_post("alarm_wakeup", 1, tvs_alert_stop_reason);
|
||
}
|
||
|
||
static void wakeup_timeout(void *priv)
|
||
{
|
||
if (alarm_rings == 0) {
|
||
return ;
|
||
}
|
||
os_taskq_post("alarm_wakeup", 1, TVS_ALART_STOP_REASON_TIMEOUT);
|
||
}
|
||
|
||
static void alarm_wakeup(void *priv)
|
||
{
|
||
alert_info *alert = (alert_info *)priv;
|
||
int err = 0;
|
||
int msg[32] = {0};
|
||
if (!upgrade_flag) {
|
||
|
||
if (alarm_interrupt_mode == 0) { //0. 关闭语音识别 响应闹钟
|
||
if (get_listen_flag() >= 2) {
|
||
alarm_rings = 1;
|
||
tvs_taskq_post(TC_RECORD_STOP);
|
||
while (get_listen_flag() >= 2) { //等待关闭语音识别
|
||
os_time_dly(20);
|
||
}
|
||
}
|
||
} else if (alarm_interrupt_mode == 1) { //1. 无视闹钟 继续当前语音识别
|
||
if (get_listen_flag() >= 2) {
|
||
//不上报闹钟响铃也不上报闹钟停止, 看下云端会不会有影响, 没影响就不处理
|
||
goto alarm_exit;
|
||
}
|
||
}
|
||
|
||
alarm_rings = 1;
|
||
tvs_media_player_inner_pause_play();
|
||
wakeup_timeout_id = sys_timeout_add_to_task("app_core", NULL, wakeup_timeout, ALARM_TIMEOUT * 1000);
|
||
on_alert_trigger_start((const char *)alert->token);
|
||
ai_server_event_url(&tc_tvs_api, alert->url, AI_SERVER_EVENT_URL);
|
||
while (1) {
|
||
err = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
|
||
if (err != OS_TASKQ || msg[0] != Q_USER) {
|
||
continue;
|
||
}
|
||
if ((msg[1] == TVS_ALART_STOP_REASON_NEW_RECO) || (msg[1] == TVS_ALART_STOP_REASON_MANNUAL) || (msg[1] == TVS_ALART_STOP_REASON_TIMEOUT)) {
|
||
break;
|
||
}
|
||
}
|
||
if (wakeup_timeout_id) {
|
||
sys_timeout_del(wakeup_timeout_id);
|
||
}
|
||
ai_server_event_url(&tc_tvs_api, NULL, AI_SERVER_EVENT_STOP);
|
||
on_alert_trigger_stop((const char *)alert->token, msg[1]);
|
||
alarm_rings = 0;
|
||
tvs_media_player_inner_start_play();
|
||
}
|
||
alarm_exit:
|
||
|
||
thread_fork("del_alarm_info", 20, 1024, 0, NULL, del_alarm_info, priv);
|
||
}
|
||
|
||
/* 闹钟响了进行这个函数 */
|
||
static void rings(void *priv)
|
||
{
|
||
alert_info *alert = (alert_info *)priv;
|
||
printf("alarm clock is rings!!!!!!!!!!!!!!!");
|
||
time_quit = 1;
|
||
if (!alarm_wakeup_pid) {
|
||
thread_fork("alarm_wakeup", 20, 500, 10, &alarm_wakeup_pid, alarm_wakeup, priv);
|
||
}
|
||
|
||
}
|
||
|
||
static int tvs_alert_adapter_impl_new(tvs_alert_infos *alerts, int alert_count)
|
||
{
|
||
//保存闹钟
|
||
int days_in_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||
cJSON *json = NULL, *schedule = NULL, *token = NULL, *type = NULL, *assets = NULL, *index = NULL, *url = NULL;
|
||
struct list_head *pos = NULL;
|
||
alert_info *new_alert = NULL;
|
||
|
||
json = cJSON_Parse(alerts->alert_detail);
|
||
|
||
schedule = cJSON_GetObjectItem(json, "scheduledTime");
|
||
token = cJSON_GetObjectItem(json, "token");
|
||
type = cJSON_GetObjectItem(json, "type");
|
||
|
||
assets = cJSON_GetObjectItem(json, "assets");
|
||
//看json字符串 目前只有一个index,后续如果还有其他的再修改
|
||
index = cJSON_GetArrayItem(assets, 0);
|
||
url = cJSON_GetObjectItem(index, "url");
|
||
|
||
|
||
//判断是否已经创建该闹钟
|
||
list_for_each(pos, &alert_head.entry) {
|
||
new_alert = list_entry(pos, alert_info, entry);
|
||
if (!strcmp(new_alert->schedule, schedule->valuestring)) {
|
||
printf("-------%s---------%d-----already existence !", __func__, __LINE__);
|
||
cJSON_Delete(json);
|
||
return 0;
|
||
}
|
||
|
||
}
|
||
//存储闹钟信息到节点
|
||
new_alert = (alert_info *)calloc(1, sizeof(alert_info));
|
||
if (!new_alert) {
|
||
printf("-----------%s-----------%d calloc failed", __func__, __LINE__);
|
||
return -1;
|
||
}
|
||
new_alert->schedule = strdup(schedule->valuestring);
|
||
new_alert->token = strdup(token->valuestring);
|
||
new_alert->type = strdup(type->valuestring);
|
||
new_alert->url = strdup(url->valuestring);
|
||
|
||
list_add_tail(&new_alert->entry, &alert_head.entry);
|
||
|
||
alarm_info info = {0};
|
||
//获取年月日时分秒,继而创建闹钟
|
||
sscanf(schedule->valuestring, "%d-%d-%dT%d:%d:%d", &info.year, &info.month, &info.day, &info.hour, &info.min, &info.sec);
|
||
|
||
struct tm tm_set;
|
||
memset(&tm_set, 0, sizeof(struct tm));
|
||
tm_set.tm_year = info.year - 1900;
|
||
tm_set.tm_mon = info.month - 1;
|
||
tm_set.tm_mday = info.day;
|
||
tm_set.tm_hour = info.hour;
|
||
tm_set.tm_min = info.min;
|
||
tm_set.tm_sec = info.sec;
|
||
|
||
new_alert->tSet = mktime(&tm_set);
|
||
printf("---------%s-------------%d---------time = %ld set = %ld\r\n", __func__, __LINE__, time(NULL), new_alert->tSet);
|
||
|
||
#if 0 //只供测试使用只供测试使用
|
||
info.hour += 8; //东八区
|
||
if (info.hour > 24) {
|
||
info.hour -= 24;
|
||
info.day += 1;
|
||
int leap = ((!(info.year / 4) && (info.year / 100)) || !(info.year / 400)) ? 1 : 0;
|
||
if (info.day > days_in_month[info.month] + ((info.month == 2) ? leap : 0)) {
|
||
info.day = 1;
|
||
info.month += 1;
|
||
if (info.month > 12) {
|
||
info.month = 1;
|
||
info.year += 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
printf("---------%s-------------%d---%d-%d-%dT%d:%d:%d----------------------------------\n\n\n", __func__, __LINE__, info.year, info.month, info.day, info.hour, info.min, info.sec);
|
||
#endif
|
||
|
||
#if USE_RTC_ALARM
|
||
/* RTC_alarm(new_alert); */
|
||
set_new_rtc_alarm();
|
||
#else
|
||
SYS_alarm(new_alert);
|
||
#endif
|
||
cJSON_Delete(json);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int tvs_alert_adapter_impl_delete(tvs_alert_summary *alerts, int alert_count)
|
||
{
|
||
//删除闹钟
|
||
struct list_head *pos = NULL;
|
||
alert_info *del_alert = NULL;
|
||
|
||
|
||
list_for_each(pos, &alert_head.entry) {
|
||
del_alert = list_entry(pos, alert_info, entry);
|
||
if (!strcmp(del_alert->token, alerts->alert_token)) {
|
||
#if !(USE_RTC_ALARM)
|
||
sys_timeout_del(del_alert->id);
|
||
#endif
|
||
list_del(&del_alert->entry);
|
||
free(del_alert->schedule);
|
||
free(del_alert->token);
|
||
free(del_alert->type);
|
||
free(del_alert->url);
|
||
free(del_alert);
|
||
printf("-------%s---------%d-----del !\n\n", __func__, __LINE__);
|
||
break;
|
||
}
|
||
}
|
||
#if USE_RTC_ALARM
|
||
set_new_rtc_alarm();
|
||
#endif
|
||
|
||
return 0;
|
||
}
|
||
|
||
void *tvs_alert_adapter_impl_get_all_alerts()
|
||
{
|
||
cJSON *alert_arr = cJSON_CreateArray();
|
||
//获取闹钟概要信息并填充json,必须返回cJSON*类型的数据
|
||
struct list_head *pos = NULL;
|
||
alert_info *alert = NULL;
|
||
|
||
list_for_each(pos, &alert_head.entry) {
|
||
alert = list_entry(pos, alert_info, entry);
|
||
|
||
cJSON *node = cJSON_CreateObject();
|
||
cJSON_AddItemToObject(node, "scheduledTime", cJSON_CreateString(alert->schedule));
|
||
cJSON_AddItemToObject(node, "token", cJSON_CreateString(alert->token));
|
||
cJSON_AddItemToObject(node, "type", cJSON_CreateString(alert->type));
|
||
|
||
cJSON_AddItemToArray(alert_arr, node);
|
||
}
|
||
|
||
|
||
return alert_arr;
|
||
}
|
||
|
||
// TO-DO 闹钟响铃时需要调用此函数通知SDK
|
||
void on_alert_trigger_start(const char *alert_token)
|
||
{
|
||
if (alert_token == NULL) {
|
||
return;
|
||
}
|
||
tvs_alert_adapter_on_trigger(alert_token);
|
||
}
|
||
|
||
// TO-DO 闹钟响铃之后,超时或者手动停止,都需要调用此函数通知SDK
|
||
void on_alert_trigger_stop(const char *alert_token, tvs_alert_stop_reason reason)
|
||
{
|
||
if (alert_token == NULL) {
|
||
return;
|
||
}
|
||
tvs_alert_adapter_on_trigger_stop(alert_token, reason);
|
||
}
|
||
|
||
static void alert_init()
|
||
{
|
||
if (alert_init_flag) {
|
||
return;
|
||
}
|
||
//闹钟节点头初始化
|
||
INIT_LIST_HEAD(&alert_head.entry);
|
||
alert_init_flag = 1;
|
||
|
||
}
|
||
|
||
//删除所有闹钟,云端的不删除,因为重新连接云端之后也可以从云端拿回闹钟信息
|
||
void tvs_uninit_alert(void)
|
||
{
|
||
struct list_head *pos = NULL;
|
||
alert_info *del_alert = NULL;
|
||
alert_info *safe_alert = NULL;
|
||
|
||
int cnt = 0;
|
||
|
||
list_for_each_entry_safe(del_alert, safe_alert, &alert_head.entry, entry) {
|
||
list_del(&del_alert->entry);
|
||
#if !(USE_RTC_ALARM)
|
||
sys_timeout_del(del_alert->id);
|
||
#endif
|
||
free(del_alert->schedule);
|
||
free(del_alert->token);
|
||
free(del_alert->type);
|
||
free(del_alert->url);
|
||
free(del_alert);
|
||
printf("-------%s---------%d-----del %d!\n\n", __func__, __LINE__, cnt++);
|
||
}
|
||
#if USE_RTC_ALARM
|
||
set_alarm_ctrl(0); //关闭RTC闹钟
|
||
#endif
|
||
/* alert_head.entry = NULL; */
|
||
|
||
}
|
||
|
||
int tvs_init_alert_adater_impl(tvs_alert_adapter *ad)
|
||
{
|
||
if (NULL == ad) {
|
||
return -1;
|
||
}
|
||
|
||
// 初始化adapter
|
||
ad->do_delete = tvs_alert_adapter_impl_delete;
|
||
ad->do_new_alert = tvs_alert_adapter_impl_new;
|
||
ad->get_alerts_ex = tvs_alert_adapter_impl_get_all_alerts;
|
||
alert_init();
|
||
return 0;
|
||
}
|
||
|
||
|