#include #include #include #include #include #include #include #include #include #include #include #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 #include #include #include #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; }