574 lines
16 KiB
C
574 lines
16 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/time.h>
|
|
#include <uv.h>
|
|
#include <dbus/dbus.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
#include <uthash/utlist.h>
|
|
#include <uthash/utarray.h>
|
|
|
|
#if defined(PLATFORM_R16) || defined (PLATFORM_CPU) || defined(PLATFORM_R311)
|
|
#include "log.h"
|
|
#include "libuv_dbus.h"
|
|
#include "json_struct.h"
|
|
#include "config_engine.h"
|
|
#else
|
|
#include <uvdbus/log.h>
|
|
#include <uvdbus/libuv_dbus.h>
|
|
#include <uvdbus/json_struct.h>
|
|
#include <uvdbus/config_engine.h>
|
|
#endif
|
|
|
|
#define MAX_DATETIME_STR (20)
|
|
#define DAYOF_SECONDS (24 * 3600)
|
|
#define IS_LEAP_YEAR(year) ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
|
|
|
|
#define PRE_INIT_DATETIME(val, item, defval) \
|
|
do { \
|
|
item = ((val) == -1) ? defval : (val); \
|
|
} while(0)
|
|
|
|
/****************************************************************************/
|
|
#define TIMER_TIMEOUT (200)
|
|
|
|
typedef void (*OnWallTimer)(UT_array* pArray);
|
|
|
|
typedef struct WALL_TIME_ALARMER
|
|
{
|
|
//char strDatetime[MAX_DATETIME_STR];
|
|
int waitDel;
|
|
time_t onTimestamp;
|
|
void* pPrivData;
|
|
|
|
struct WALL_TIME_ALARMER *next, *prev; ///< UT list pointer
|
|
} *PWALL_TIME_ALARMER;
|
|
|
|
static PWALL_TIME_ALARMER g_wTimerList = NULL;
|
|
static uv_rwlock_t g_uvWTimerRwLock;
|
|
/***************************************************************************/
|
|
typedef struct
|
|
{
|
|
int year; ///< 年
|
|
int month; ///< 月
|
|
int day; ///< 日
|
|
int hour; ///< 小时
|
|
int minute; ///< 分钟
|
|
int second; ///< 秒钟
|
|
int weekDay; ///< 星期
|
|
|
|
unsigned long long alarmId; ///< 提醒、闹钟ID
|
|
int itemType; ///< 类型: 0 闹钟, 1 提醒
|
|
int repeatMode; ///< 重复模式
|
|
|
|
unsigned long long voiceId; ///< 闹钟资源ID
|
|
char* strTips; ///< 提醒 TTS 文本
|
|
char* resUrl; ///< 资源URL
|
|
char* voiceRes; ///< 资源声音文件ID
|
|
char* voiceResType; ///< 资源类型
|
|
} ALARM_ITEM_INFO, *PALARM_ITEM_INFO;
|
|
|
|
typedef struct ALARM_TIMER
|
|
{
|
|
PALARM_ITEM_INFO pAlarmInfo;
|
|
|
|
time_t setTimestamp;
|
|
time_t delayTimestamp;
|
|
|
|
int priority;
|
|
int delayOnTimes;
|
|
|
|
PWALL_TIME_ALARMER pPrivTimer;
|
|
|
|
struct ALARM_TIMER *next, *prev;
|
|
} *PALARM_TIMER;
|
|
|
|
static unsigned char g_DayOfMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
|
|
static time_t __getAlarmOnTimestamp(PALARM_ITEM_INFO pInfo)
|
|
{
|
|
int ret = 0;
|
|
struct tm tmSet, localTime;
|
|
time_t timeStamp, timeSet;
|
|
|
|
if(pInfo == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
timeStamp = time((time_t*)NULL);
|
|
localtime_r(&timeStamp, &localTime);
|
|
|
|
PRE_INIT_DATETIME(pInfo->day, tmSet.tm_mday, localTime.tm_mday);
|
|
PRE_INIT_DATETIME(pInfo->month, tmSet.tm_mon, localTime.tm_mon);
|
|
PRE_INIT_DATETIME(pInfo->year, tmSet.tm_year, localTime.tm_year);
|
|
PRE_INIT_DATETIME(pInfo->second, tmSet.tm_sec, localTime.tm_sec);
|
|
PRE_INIT_DATETIME(pInfo->minute, tmSet.tm_min, localTime.tm_min);
|
|
PRE_INIT_DATETIME(pInfo->hour, tmSet.tm_hour, localTime.tm_hour);
|
|
|
|
|
|
switch(pInfo->repeatMode)
|
|
{
|
|
case REPEAT_MODE_NONE:
|
|
timeSet = mktime(&tmSet);
|
|
break;
|
|
case REPEAT_MODE_EVERY_DAY:
|
|
tmSet.tm_year = localTime.tm_year;
|
|
tmSet.tm_mon = localTime.tm_mon;
|
|
tmSet.tm_mday = localTime.tm_mday;
|
|
timeSet = mktime(&tmSet);
|
|
if(timeSet < timeStamp)
|
|
{
|
|
timeSet = DAYOF_SECONDS + timeStamp;
|
|
}
|
|
break;
|
|
case REPEAT_MODE_WORKDAY:
|
|
tmSet.tm_year = localTime.tm_year;
|
|
tmSet.tm_mon = localTime.tm_mon;
|
|
tmSet.tm_mday = localTime.tm_mday;
|
|
do
|
|
{
|
|
ret = CurrentIsWorkDay(tmSet.tm_year, tmSet.tm_yday);
|
|
|
|
timeSet = mktime(&tmSet);
|
|
|
|
if(ret == 0)
|
|
{
|
|
timeSet += DAYOF_SECONDS;
|
|
localtime_r(&timeSet, &tmSet);
|
|
}
|
|
} while(ret == 0);
|
|
|
|
if(ret < 0)
|
|
{
|
|
timeSet = 0;
|
|
}
|
|
break;
|
|
case REPEAT_MODE_WEEKEND:
|
|
tmSet.tm_year = localTime.tm_year;
|
|
tmSet.tm_mon = localTime.tm_mon;
|
|
tmSet.tm_mday = localTime.tm_mday;
|
|
tmSet.tm_wday = localTime.tm_wday;
|
|
ret == 0;
|
|
while(tmSet.tm_wday != 0 && tmSet.tm_wday != 6 && ret++ < 10)
|
|
{
|
|
timeSet = mktime(&tmSet) + DAYOF_SECONDS;
|
|
localtime_r(&timeSet, &tmSet);
|
|
}
|
|
break;
|
|
case REPEAT_MODE_WEEKDAY:
|
|
tmSet.tm_year = localTime.tm_year;
|
|
tmSet.tm_mon = localTime.tm_mon;
|
|
tmSet.tm_mday = localTime.tm_mday;
|
|
tmSet.tm_wday = localTime.tm_wday;
|
|
ret = pInfo->weekDay;
|
|
if(ret == 0)
|
|
{
|
|
ret = 1 << 0;
|
|
}
|
|
else if(ret & (1 << 7))
|
|
{
|
|
ret = 1 << 0;
|
|
}
|
|
|
|
timeSet = mktime(&tmSet);
|
|
|
|
while(((1 << tmSet.tm_wday) & ret) == 0)
|
|
{
|
|
timeSet = mktime(&tmSet) + DAYOF_SECONDS;
|
|
localtime_r(&timeSet, &tmSet);
|
|
}
|
|
break;
|
|
case REPEAT_MODE_EVERY_MONTH_DAY:
|
|
tmSet.tm_year = localTime.tm_year;
|
|
tmSet.tm_mon = localTime.tm_mon;
|
|
timeSet = mktime(&tmSet);
|
|
if(timeSet < timeStamp)
|
|
{
|
|
if(tmSet.tm_mon < 11)
|
|
{
|
|
tmSet.tm_mon++;
|
|
}
|
|
else
|
|
{
|
|
tmSet.tm_year++;
|
|
tmSet.tm_mon = 0;
|
|
}
|
|
|
|
timeSet = mktime(&tmSet);
|
|
}
|
|
break;
|
|
case REPEAT_MODE_EVERY_YEAR_DAY:
|
|
tmSet.tm_year = localTime.tm_year;
|
|
timeSet = mktime(&tmSet);
|
|
if(timeSet < timeStamp)
|
|
{
|
|
tmSet.tm_year++;
|
|
timeSet = mktime(&tmSet);
|
|
}
|
|
break;
|
|
case REPEAT_MODE_EVERY_TIME:
|
|
timeSet = mktime(&localTime);
|
|
if(pInfo->hour > 0)
|
|
{
|
|
timeSet += pInfo->hour * 3600;
|
|
}
|
|
if(pInfo->minute > 0)
|
|
{
|
|
timeSet += pInfo->minute * 60;
|
|
}
|
|
if(pInfo->second > 0)
|
|
{
|
|
timeSet += pInfo->second;
|
|
}
|
|
break;
|
|
case REPEAT_MODE_MONTH_LAST_DAY:
|
|
tmSet.tm_year = localTime.tm_year;
|
|
tmSet.tm_mon = localTime.tm_mon;
|
|
tmSet.tm_mday = g_DayOfMonth[localTime.tm_mon];
|
|
if(IS_LEAP_YEAR(localTime.tm_year) && (localTime.tm_mon == 1))
|
|
{
|
|
tmSet.tm_mday += 1;
|
|
}
|
|
timeSet = mktime(&tmSet);
|
|
if(timeSet < timeStamp)
|
|
{
|
|
if(tmSet.tm_mon < 11)
|
|
{
|
|
tmSet.tm_mon++;
|
|
}
|
|
else
|
|
{
|
|
tmSet.tm_mon = 0;
|
|
tmSet.tm_year++;
|
|
}
|
|
tmSet.tm_mday = g_DayOfMonth[tmSet.tm_mon];
|
|
if(IS_LEAP_YEAR(tmSet.tm_year) && (tmSet.tm_mon == 1))
|
|
{
|
|
tmSet.tm_mday += 1;
|
|
}
|
|
timeSet = mktime(&tmSet);
|
|
}
|
|
break;
|
|
case REPEAT_MODE_HOLIDAY:
|
|
tmSet.tm_year = localTime.tm_year;
|
|
tmSet.tm_mon = localTime.tm_mon;
|
|
tmSet.tm_mday = localTime.tm_mday;
|
|
do
|
|
{
|
|
ret = CurrentIsWorkDay(tmSet.tm_year, tmSet.tm_yday);
|
|
|
|
timeSet = mktime(&tmSet);
|
|
|
|
if(ret == 0)
|
|
{
|
|
timeSet += DAYOF_SECONDS;
|
|
localtime_r(&timeSet, &tmSet);
|
|
}
|
|
} while(ret == 1);
|
|
|
|
if(ret < 0)
|
|
{
|
|
timeSet = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
LOG_EX(LOG_Debug, "Timestamp = %u %s", timeSet, ctime(&timeSet));
|
|
return timeSet;
|
|
}
|
|
|
|
static PALARM_TIMER __createAlarmItem(PALARM_ITEM_INFO pInfo)
|
|
{
|
|
PALARM_TIMER pItem = (PALARM_TIMER)malloc(sizeof(struct ALARM_TIMER));
|
|
|
|
if(pItem == NULL)
|
|
{
|
|
LOG_EX(LOG_Error, "Malloc Memory Error: %u\n", sizeof(struct ALARM_TIMER));
|
|
return NULL;
|
|
}
|
|
|
|
memset(pItem, 0, sizeof(struct ALARM_TIMER));
|
|
|
|
pItem->pAlarmInfo = (PALARM_ITEM_INFO)malloc(sizeof(ALARM_ITEM_INFO));
|
|
|
|
if(pItem->pAlarmInfo == NULL)
|
|
{
|
|
free(pItem);
|
|
LOG_EX(LOG_Error, "Malloc Memory Error: %u\n", sizeof(struct ALARM_TIMER));
|
|
return NULL;
|
|
}
|
|
|
|
memset(pItem->pAlarmInfo, 0, sizeof(ALARM_ITEM_INFO));
|
|
|
|
pItem->pAlarmInfo->year = pInfo->year;
|
|
pItem->pAlarmInfo->month = pInfo->month;
|
|
pItem->pAlarmInfo->day = pInfo->day;
|
|
pItem->pAlarmInfo->hour = pInfo->hour;
|
|
pItem->pAlarmInfo->minute = pInfo->minute;
|
|
pItem->pAlarmInfo->second = pInfo->second;
|
|
pItem->pAlarmInfo->weekDay = pInfo->weekDay;
|
|
pItem->pAlarmInfo->alarmId = pInfo->alarmId;
|
|
pItem->pAlarmInfo->itemType = pInfo->itemType;
|
|
pItem->pAlarmInfo->repeatMode = pInfo->repeatMode;
|
|
pItem->pAlarmInfo->voiceId = pInfo->voiceId;
|
|
pItem->pAlarmInfo->strTips = strdup(pInfo->strTips);
|
|
pItem->pAlarmInfo->resUrl = strdup(pInfo->resUrl);
|
|
pItem->pAlarmInfo->voiceRes = strdup(pInfo->voiceRes);
|
|
pItem->pAlarmInfo->voiceResType = strdup(pInfo->voiceResType);
|
|
|
|
pItem->priority = 0;
|
|
pItem->delayOnTimes = 0;
|
|
|
|
return pItem;
|
|
}
|
|
|
|
static void __cleanupAlarmItem(PALARM_ITEM_INFO pItem)
|
|
{
|
|
if(pItem == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(pItem->strTips) free(pItem->strTips);
|
|
if(pItem->resUrl) free(pItem->resUrl);
|
|
if(pItem->voiceRes) free(pItem->voiceRes);
|
|
if(pItem->voiceResType) free(pItem->voiceResType);
|
|
|
|
free(pItem);
|
|
}
|
|
|
|
static void __cleanupAlarmTimer(PALARM_TIMER pItem)
|
|
{
|
|
if(pItem == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
__cleanupAlarmItem(pItem->pAlarmInfo);
|
|
free(pItem);
|
|
}
|
|
|
|
static PALARM_TIMER g_pAlarmList = NULL;
|
|
/***************************************************************************/
|
|
static OnWallTimer g_pWallTimerCb;
|
|
|
|
static void __timerout200msCb(uv_timer_t *puvTimer)
|
|
{
|
|
static int iCnt = 0;
|
|
int tolItems = -1;
|
|
UT_array *pArrayTm = NULL;
|
|
struct tm localTime;
|
|
time_t timeStamp;
|
|
PWALL_TIME_ALARMER pTimer = NULL, pTmp = NULL;
|
|
|
|
utarray_new(pArrayTm, &ut_int_icd);
|
|
|
|
iCnt++;
|
|
|
|
if(pArrayTm == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// upgrade current time and timestamp
|
|
timeStamp = time((time_t*)NULL);
|
|
localtime_r(&timeStamp, &localTime);
|
|
|
|
uv_rwlock_wrlock(&g_uvWTimerRwLock);
|
|
DL_FOREACH_SAFE(g_wTimerList, pTimer, pTmp)
|
|
{
|
|
// timer not on time
|
|
if(pTimer->onTimestamp <= timeStamp || pTimer->waitDel)
|
|
{
|
|
if(!pTimer->waitDel &&
|
|
(timeStamp - pTimer->onTimestamp) <= 1)
|
|
{
|
|
utarray_push_back(pArrayTm, pTimer->pPrivData);
|
|
}
|
|
|
|
DL_DELETE(g_wTimerList, pTimer);
|
|
free(pTimer);
|
|
pTimer = NULL;
|
|
}
|
|
}
|
|
uv_rwlock_wrunlock(&g_uvWTimerRwLock);
|
|
|
|
tolItems = utarray_len(pArrayTm);
|
|
if(tolItems > 0)
|
|
{
|
|
if(g_pWallTimerCb)
|
|
{
|
|
g_pWallTimerCb(pArrayTm);
|
|
}
|
|
LOG_EX(LOG_Debug, "Current item = %d\n", tolItems);
|
|
}
|
|
|
|
utarray_free(pArrayTm);
|
|
}
|
|
|
|
static int __timestampSort(PWALL_TIME_ALARMER p1, PWALL_TIME_ALARMER p2)
|
|
{
|
|
if(p1->waitDel != p2->waitDel)
|
|
{
|
|
if(p1->waitDel == TRUE)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return (p1->onTimestamp - p2->onTimestamp);
|
|
}
|
|
|
|
int WallTimerInit(OnWallTimer pTimerCb)
|
|
{
|
|
static uv_timer_t uvTimer;
|
|
uv_loop_t* pLoop = DBusLibuvGetRuntime()->pLoop;
|
|
|
|
g_pWallTimerCb = pTimerCb;
|
|
|
|
if(pLoop == NULL)
|
|
{
|
|
pLoop = uv_default_loop();
|
|
}
|
|
|
|
uv_rwlock_init(&g_uvWTimerRwLock);
|
|
|
|
uv_timer_init(pLoop, &uvTimer);
|
|
uv_timer_start(&uvTimer, __timerout200msCb, 0, TIMER_TIMEOUT);
|
|
}
|
|
|
|
PWALL_TIME_ALARMER WallTimerAddNew(time_t onTime, void* pPrvi)
|
|
{
|
|
PWALL_TIME_ALARMER pTm = (PWALL_TIME_ALARMER)malloc(sizeof(struct WALL_TIME_ALARMER));
|
|
|
|
if(pTm == NULL)
|
|
{
|
|
LOG_EX(LOG_Error, "Malloc Memory (%u) Error\n", sizeof(struct WALL_TIME_ALARMER));
|
|
return NULL;
|
|
}
|
|
|
|
memset(pTm, 0, sizeof(struct WALL_TIME_ALARMER));
|
|
|
|
pTm->onTimestamp = onTime;
|
|
pTm->pPrivData = pPrvi;
|
|
pTm->waitDel = FALSE;
|
|
|
|
uv_rwlock_wrlock(&g_uvWTimerRwLock);
|
|
DL_APPEND(g_wTimerList, pTm);
|
|
DL_SORT(g_wTimerList, __timestampSort);
|
|
uv_rwlock_wrunlock(&g_uvWTimerRwLock);
|
|
|
|
return pTm;
|
|
}
|
|
|
|
PWALL_TIME_ALARMER WallTimerAddNew2(char* pStrTime, void* pPrvi)
|
|
{
|
|
struct tm tm;
|
|
time_t tmSet;
|
|
|
|
if(pStrTime == NULL)
|
|
{
|
|
LOG_EX(LOG_Debug, "Input String Timer NULL\n");
|
|
return NULL;
|
|
}
|
|
|
|
memset(&tm, 0, sizeof(struct tm));
|
|
strptime(pStrTime, "%Y-%m-%d %H:%M:%S", &tm);
|
|
|
|
tmSet = mktime(&tm);
|
|
|
|
LOG_EX(LOG_Debug, "Add WallTimer: [%s] --> (%u)\n", pStrTime, tmSet);
|
|
return WallTimerAddNew(tmSet, pPrvi);
|
|
}
|
|
|
|
int WallTimerDel(PWALL_TIME_ALARMER pTimer)
|
|
{
|
|
if(pTimer == NULL)
|
|
{
|
|
return -ERR_INPUT_PARAMS;
|
|
}
|
|
|
|
pTimer->waitDel = TRUE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static PDBUS_MSG_PACK __dBusOnMessage(uv_loop_t *pLoop, DBusConnection *pConn, PDBUS_MSG_PACK pMsg)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static void __OnWallTimer(UT_array* pArray)
|
|
{
|
|
for(int *p=(int*)utarray_front(pArray); p!=NULL;
|
|
p=(int*)utarray_next(pArray, p))
|
|
{
|
|
LOG_EX(LOG_Debug, "Timer Value = %d\n", *p);
|
|
}
|
|
}
|
|
|
|
static void __unittest_getAlarmOnTimestamp(void)
|
|
{
|
|
ALARM_ITEM_INFO aInfo;
|
|
|
|
struct tm localTime;
|
|
time_t timeStamp;
|
|
|
|
timeStamp = time((time_t*)NULL) + 10;
|
|
localtime_r(&timeStamp, &localTime);
|
|
|
|
memset(&aInfo, 0, sizeof(ALARM_ITEM_INFO));
|
|
aInfo.day = localTime.tm_mday;
|
|
aInfo.month = localTime.tm_mon;
|
|
aInfo.year = localTime.tm_year;
|
|
aInfo.hour = localTime.tm_hour;
|
|
aInfo.minute = localTime.tm_min;
|
|
aInfo.second = localTime.tm_sec;
|
|
|
|
|
|
aInfo.repeatMode = REPEAT_MODE_EVERY_TIME;
|
|
|
|
LOG_EX(LOG_Debug, "Unit Test Input: Timestamp = %u %s", timeStamp, ctime(&timeStamp));
|
|
for(int i = 1; i <= 100; i++)
|
|
{
|
|
aInfo.hour = i;
|
|
aInfo.minute = 0;
|
|
aInfo.second = 0;
|
|
__getAlarmOnTimestamp(&aInfo);
|
|
}
|
|
}
|
|
int main(int argc, char **argv)
|
|
{
|
|
int ret = 0;
|
|
|
|
DBusConnection* pBus;
|
|
uv_loop_t* pLoop = GetDBusDefaultLoop();
|
|
|
|
pBus = DBusWithLibuvInit(pLoop, g_pModInfoTable[MODULE_ALARM].modAliase,
|
|
__dBusOnMessage,
|
|
NULL,
|
|
NULL, &ret);
|
|
|
|
if(pBus == NULL)
|
|
{
|
|
fprintf(stderr, "DBusWithLibuvInit Error: %d\n", ret);
|
|
return 0;
|
|
}
|
|
|
|
WallTimerInit(__OnWallTimer);
|
|
|
|
__unittest_getAlarmOnTimestamp();
|
|
|
|
RunUVLoop(pLoop);
|
|
|
|
return 0;
|
|
}
|
|
|