PV1_MakeProject/Modules/alarmer/alarmer.c

574 lines
16 KiB
C
Raw Permalink Normal View History

#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; ///< <20><>
int month; ///< <20><>
int day; ///< <20><>
int hour; ///< Сʱ
int minute; ///< <20><><EFBFBD><EFBFBD>
int second; ///< <20><><EFBFBD><EFBFBD>
int weekDay; ///< <20><><EFBFBD><EFBFBD>
unsigned long long alarmId; ///< <20><><EFBFBD>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD><EFBFBD>ID
int itemType; ///< <20><><EFBFBD>ͣ<EFBFBD> 0 <20><><EFBFBD>ӣ<EFBFBD> 1 <20><><EFBFBD><EFBFBD>
int repeatMode; ///< <20>ظ<EFBFBD>ģʽ
unsigned long long voiceId; ///< <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԴID
char* strTips; ///< <20><><EFBFBD><EFBFBD> TTS <20>ı<EFBFBD>
char* resUrl; ///< <20><>ԴURL
char* voiceRes; ///< <20><>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>ID
char* voiceResType; ///< <20><>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD>
} 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;
}