diff --git a/Example/main.c b/Example/main.c index 143e905..96b631c 100644 --- a/Example/main.c +++ b/Example/main.c @@ -1892,6 +1892,7 @@ void test_nl80211(void) } #endif + int main(int argc, char **argv) { int i, j, ret = 0; @@ -1900,7 +1901,14 @@ int main(int argc, char **argv) uv_loop_t* pLoop = GetDBusDefaultLoop(); int modIdx = -1; char buf[256]; - + + + struct tm tm; + + memset(&tm, 0, sizeof(struct tm)); + strptime("2001-11-12 18:31:01", "%Y-%m-%d %H:%M:%S", &tm); + strftime(buf, sizeof(buf), "%d %b %Y %H:%M", &tm); + puts(buf); #if 0 i = GetServerModeFromCC(PUBLISH_MODE, &ret); @@ -1977,13 +1985,13 @@ int main(int argc, char **argv) //test_netlink(); #ifndef PLATFORM_CPU - BL_Init(NULL); + //BL_Init(NULL); //L_SendMessage((unsigned char*)&blMsg, sizeof(BL_IOT_MSG)); //test_netlink(); //__uvThreadTimerV2(pLoop); - test_task_new(__uvThreadNetlinkSend, NULL); + //test_task_new(__uvThreadNetlinkSend, NULL); #endif //DumpCurServerAddr("Default"); diff --git a/Framework/IoT/Boardlink/boardlink_iot.c b/Framework/IoT/Boardlink/boardlink_iot.c index 820cc52..2cd5135 100644 --- a/Framework/IoT/Boardlink/boardlink_iot.c +++ b/Framework/IoT/Boardlink/boardlink_iot.c @@ -12,8 +12,6 @@ #include "log.h" #include "libuv_dbus.h" #include "boardlink_iot.h" -#include "blsdk.h" -#include "blsdk_errno.h" #else #include #include diff --git a/Framework/Timer/timer.c b/Framework/Timer/timer.c index eb019b0..c8950e5 100644 --- a/Framework/Timer/timer.c +++ b/Framework/Timer/timer.c @@ -281,7 +281,10 @@ static int __getOnTimestamp(PALARM_ITEM_DATA pInfo) switch(pInfo->repeatMode) { case REPEAT_MODE_EVERY_MONTH_DAY: + pInfo->setDateTime.tm_mon = -1; + pInfo->setDateTime.tm_year = -1; case REPEAT_MODE_EVERY_YEAR_DAY: + pInfo->setDateTime.tm_year = -1; case REPEAT_MODE_NONE: if(pInfo->setDateTime.tm_year == -1) { @@ -347,16 +350,20 @@ static int __getOnTimestamp(PALARM_ITEM_DATA pInfo) { if(pInfo->repeatMode == REPEAT_MODE_EVERY_MONTH_DAY) { + DEBUG_CODE_LINE(); if(pInfo->onDateTime.tm_mon < 11) { + DEBUG_CODE_LINE(); pInfo->onDateTime.tm_mon++; } else { + DEBUG_CODE_LINE(); pInfo->onDateTime.tm_mon = 0; pInfo->onDateTime.tm_year++; } + DEBUG_CODE_LINE(); pInfo->onTimestamp = mktime(&pInfo->onDateTime); return (0); } diff --git a/Modules/alarmer/alarmer.c b/Modules/alarmer/alarmer.c new file mode 100644 index 0000000..1c78108 --- /dev/null +++ b/Modules/alarmer/alarmer.c @@ -0,0 +1,573 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PLATFORM_R16) || defined (PLATFORM_CPU) +#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; +} + diff --git a/build/Makefile.alarm.cross b/build/Makefile.alarm.cross index 208bc76..a4b573b 100644 --- a/build/Makefile.alarm.cross +++ b/build/Makefile.alarm.cross @@ -23,13 +23,13 @@ PLAT_LINUX ?= TRUE PLAT_WIN32 ?= FALSE PLAT_WIN64 ?= FALSE -VPATH = ../Modules/Alarm/ +VPATH = ../Modules/alarmer/ # source code # set the source file, don't used .o because of ... # MRS Board Source Files -PLAT_R16_SRCS = assistant.c +PLAT_R16_SRCS = alarmer.c PLAT_LINUX_SRCS := $(PLAT_R16_SRCS) # gcc CFLAGS diff --git a/include/libuv_dbus.h b/include/libuv_dbus.h index ef1a9c7..e019b8e 100644 --- a/include/libuv_dbus.h +++ b/include/libuv_dbus.h @@ -224,6 +224,8 @@ char* CfgGetStringValue(const char* pTags, char* pDefValue); double CfgGetFloatValue(const char* pTags, double defValue); int CfgGetBoolValue(const char* pTags, int defValue); void SetHBLAutoExit(int flag); + +extern char *strptime(const char *s, const char *format, struct tm *tm); #ifdef __cplusplus } #endif diff --git a/include/skins_res.h b/include/skins_res.h index 8e3fb8f..58b0838 100644 --- a/include/skins_res.h +++ b/include/skins_res.h @@ -91,6 +91,8 @@ const SKIN_RES_INFO g_SkinDefaultResTable[] = { {VOICE_RES, "0", "v5012", DEF_SKINS_ROOT_PATH"voice/a-a-02.mp3", "837a2222c961824e98c0d3751a234ae6"}, {VOICE_RES, "0", "v5013", DEF_SKINS_ROOT_PATH"voice/a-a-03.mp3", "0ec34a1f19ee7cea6b139d214e59026d"}, {VOICE_RES, "0", "v502", DEF_SKINS_ROOT_PATH"voice/a-n-01.mp3", "b1eb13ed8c9afaa2989763c3d379b39a"}, + {VOICE_RES, "0", "v601", DEF_SKINS_ROOT_PATH"voice/b-m-1.mp3", "820cf2c01e03726b95bc4346a2ce8f8b"}, + {VOICE_RES, "0", "v602", DEF_SKINS_ROOT_PATH"voice/b-m-2.mp3", "35a48b8ec586acfb99a612b4fc1ba57a"}, /////////////////////////////////////////////////////////////////////////////////////////////////////////// /// picture resources