/** @file DHL_Timer.c @brief Timer implementation. Copyright 2006~2010 Digital STREAM Technology, Inc. All Rights Reserved */ #include "DHL_OSAL.h" #include "DHL_DBG.h" #include "DHL_Timer.h" #include "DHL_DBG_Priv.h" #include "DHL_OSAL_Config.h" //#include ////#include DHL_MODULE("*TMR", 0); #if COMMENT ____Debug____(){} #endif //------------------------------------------------------------------ // Timer Debug Print //int g_Trace_bDHLTimer = 0; // tmprintÀÇ µð¹ö±× ¸Þ½ÃÁö¸¦ °¨Ãâ°æ¿ì 0 void *g_Trace_TimerHandle; // trace ÇϰíÀÚ ÇÏ´Â timer handle. #if COMMENT ____Config____(){} #endif #define DHL_TIMER_TASK_PRIO TASK_PRI_DRV_TIMER #define DHL_TIMER_TASK_STACK 8192 #if COMMENT ____Types____(){} #endif /* ¾Æ·¡ Á¤ÀÇµÈ °ªµéÀº flags ·Î »ç¿ëµÈ´Ù. */ #define TIMER_FLAG_NeedAck 0x40 // °ú°ÅÀÇ bNeedAck °ú µ¿ÀÏÇÑ ¿ªÇÒ. #define TIMER_FLAG_OldStyleProc 0x80 // timer procÀÌ DHL_TIMER_PROC_EX°¡ ¾Æ´Ï¶ó DHL_TIMER_PROC ÀÌ´Ù. // DHL_Timer.h¿¡¼­ 8ÀÚ·Î ¸í½Ã #define MAX_TIMER_NAME 8 #define DHL_TIMER_MAGICKEY 0x09110911 /* UINT32 ÆÄ¶ó¹ÌÅ͸¦ ¸î °³ ±îÁö Áö¿øÇÏ´ÂÁö.. ±âÁ¸ version 1 ¿¡¼­´Â ´Ü Çϳª¸¸ Áö¿øÇß¾úÀ½. */ #define MAX_NUMBER_OF_TIMER_PARAM 16 /* ŸÀÌ¸Ó Å½ºÅ© msg queÀÇ µðÆúÆ® Å©±â. ±âÁ¸ version 1 ¿¡¼­ÀÇ °ª°ú µ¿ÀÏÇÏ´Ù. */ #define DEFAULT_MSG_QUE_SIZE 20 typedef struct { UINT16 nId; // unique id that distinguish to other timer entries. BOOLEAN used; // TRUE if this timer entry is used (and active) UINT32 period; // timer period (if periodic timer), or timer delay (if oneshot timer) // unit is in TICKs UINT32 start; // timer start tick. // if this is periodic timer, it is reset to NOW at every timer expire. UINT16 flags; // flags DHL_TIMER_PROC_EX fn; // timer callback function UINT32 params[MAX_NUMBER_OF_TIMER_PARAM]; // user parameters } DHL_TIMER_ENTRY; typedef struct DHL_TIMER_t { UINT32 magic; char name[MAX_TIMER_NAME+1]; DHL_TIMER_INIT_PARAM param; // user settings parameter for timer init int nActiveTimer; // µî·ÏµÈ Active ŸÀÌ¸Ó °¹¼ö. // ÀÌ º¯¼ö´Â ¸ðµç ŽºÅ©¿¡¼­ ¼öÁ¤µÇ¹Ç·Î (SetTimer¿¡¼­´Â application task, // Oneshot ÇØÁ¦µÉ °æ¿ì³ª KillTimer¿¡´Â timer task µî..) µû¶ó¼­ lock »óÅ¿¡¼­ ¼öÁ¤Çϱ⠹ٶ÷. int maxActiveIndex; // ŸÀÌ¸Ó record¿¡¼­ ¹è¿­ À妽º °ªÀÇ ÃÖ´ë°ª. // Áß°£¿¡ ÀÖ´Â timer¸¦ KillTimer·Î ¾ø¾Ö¸é ¹è¿­ °¡¿îµ¥°¡ ºó »óŰ¡ µÇ´Âµ¥, // ÀÌ °æ¿ì nActiveTimer¿Í ¹«°üÇÑ °ªÀÌ µÉ ¼ö ÀÖ´Ù. // timer routineÀÇ core¿¡¼­ ÀÌ °ªÀ» ¾Ë°í ÀÖÀ¸¸é loop ¿À¹öÇìµå¸¦ ¾à°£ ÁÙÀÏ ¼ö ÀÖ´Ù. // todo.. // ÀÌ °ªÀÌ Ä¿Áö´Â ÄÚµå´Â Àִµ¥, ÁÙ¾îµå´Â ÄÚµå´Â ¾øÀ½. ±¸Çö ÇÊ¿ä.. DHL_OS_TASK_ID nTaskId; // timer service task id. UINT32 curServicedTimerId; // cafrii 060919 add // ÇöÀç timer task¿¡¼­ ¼­ºñ½º ÁßÀÎ timer id. // timer task°¡ idle »óÅÂÀÏ °æ¿ì¿¡´Â 0ÀÌ µÈ´Ù. DHL_OS_MSGQ_ID msgQue; // message queue of timer command DHL_OS_SEMA_ID semAck; // binary semaphore for returning ACK. DHL_OS_SEMA_ID mutexAck; // mutex for guard semAck struct DHL_TIMER_t *next; // for management.. next timer record info.. int nMaxSlot; // maximum number of timer slot info. int nUserParam; // number of user parameter. copied from param->num_user_param. // MAX_NUMBER_OF_TIMER_PARAM º¸´Ù Ŭ ¼ö ¾ø´Ù. int nMaxQueSize; // copied from param->msg_que_size. DHL_TIMER_ENTRY *info; // ŸÀÌ¸Ó Á¤º¸ º¯¼ö. } DHL_TIMER; /* timer command id. version 2 ¿¡¼­´Â timer id ¿Í command id ¸¦ ÅëÇÕÇÏ¿© »ç¿ëÇÑ´Ù. ±×¸®°í ¼ýÀÚÀÇ ¹üÀ§µµ 32-bit ¿¡¼­ 16-bit·Î Ãà¼ÒÇÏ¿´´Ù. */ enum TIMER_CMD_ID_t { eTMR_CMD_BEGIN = 0xfff0, // this is just marker. //eTMR_CMD_ADD, // ÀÌ TIMER_CMD_ID_t ¸í·Éµé ÀÌ¿ÜÀÇ °ªÀº ¸ðµÎ 'ADD'·Î µ¿ÀÛÇÑ´Ù. // µû¶ó¼­ º°µµÀÇ ADD ¸í·ÉÀ» º¸³¾ Çʿ䰡 ¾ø´Ù. eTMR_CMD_DELETE, // Timer entry Çϳª¸¦ »èÁ¦ÇÑ´Ù. // »èÁ¦ÇÒ timer ID´Â userParams[0]À» ÅëÇØ Àü´ÞÇÑ´Ù. eTMR_CMD_DELETE_ALL, // ¸ðµç timer entry »èÁ¦. eTMR_CMD_SHOW, eTMR_CMD_QUERY, eTMR_CMD_SYNC, // timer¸¦ ÀÏ¹Ý dpc task·Î »ç¿ëÇϴµ¥, // ƯÁ¤ ¸Þ½ÃÁö¸¦ wait ¸ðµå·Î µ¿ÀÛÇØ¾ßÇÑ ÇÏ´Â °æ¿ì // ÀÌ timer command¸¦ »ç¿ëÇϸé timer handler¿Í µ¿±âÈ­°¡ µÇ¾î // wait ¸ðµåÀÇ È¿°ú°¡ ³­´Ù. // app ¿¡¼­ Á÷Á¢ semaphore, mutex µîÀ» °ü¸®ÇÏ´Â °ÍÀÌ ¹ø°Å·Î¿ï °æ¿ì // °£´ÜÇÏ°Ô ÀÌ ¸í·ÉÀ» Ȱ¿ëÇÏ¸é µÈ´Ù. eTMR_CMD_SHUTDOWN, }; typedef struct { UINT16 idTimerOrCmd; // Timer ID in 'Add' mode, // or Command ID in other mode (delete, show, query, ...) // Timer ID should be unique in DHL_TIMER group. UINT16 flags; //UINT32 *pResult; // return value is passed to caller // synchronous (ack) mode´Â stop (kill timer) ¿¡¼­¸¸ »ç¿ëÇϹǷÎ, // ÀÌ °ªÀº nPeriodMs º¯¼ö °ø°£À» Ȱ¿ëÇϵµ·Ï ÇÑ´Ù. UINT32 nPeriodMs; // timer expire ÁÖ±â. // eTMR_CMD_DELETE ÀÎ °æ¿ì pResult ¿ªÇÒÀ» ÇÑ´Ù. DHL_TIMER_PROC_EX func; UINT32 userParams[MAX_NUMBER_OF_TIMER_PARAM]; // user parameter, passed to timer proc // ÀÌ userParamsÀº °¡º¯ ±æÀÌ ¹è¿­ÀÌ´Ù. // timer group ÃʱâÈ­ °úÁ¤¿¡¼­ ƯÁ¤ size·Î °íÁ¤µÈ´Ù. // ÀÌ Çʵ尡 ¸Ç ¸¶Áö¸·¿¡ À§Ä¡ÇØ¾ß ÇÑ´Ù. } DHL_TIMER_COMMAND; /** DHL_TIMER_COMMAND ÀÇ Å©±â´Â °¡º¯ÀÌ´Ù. Á¤È®ÇÑ size´Â nUserParam °ª¿¡ µû¶ó ´Þ¶óÁø´Ù. SendMessage ÇÒ ¶§ ±×³É ÃÖ´ë Áö¿ø °¹¼öÀÎ MAX_NUMBER_OF_TIMER_PARAM ¸¦ »ç¿ëÇÏÁö ¾Ê´Â ÀÌÀ¯´Â ºÒÇÊ¿äÇÑ memcopy overhead¸¦ ÁÙÀ̱â À§ÇÔÀÌ´Ù. */ #define TIMER_COMMAND_SIZE(num_param) (\ sizeof(DHL_TIMER_COMMAND) \ - sizeof(UINT32)*MAX_NUMBER_OF_TIMER_PARAM \ + sizeof(UINT32)*(num_param) \ ) #ifndef min #define min(a,b) ((a)<(b)?(a):(b)) #endif #if COMMENT ____Variables____(){} #endif DHL_TIMER *g_dhl_timer_list; #if COMMENT ______Func____(){} #endif // forward declarations void dhl_timer_module_init(void); static DHL_RESULT p_timer_check_valid(DHL_TIMER *timer) { if (timer == NULL || timer->magic != DHL_TIMER_MAGICKEY) { printf( "!! invalid timer\n"); return DHL_FAIL_INVALID_PARAM; } if (timer->nTaskId == 0) { printf( "!! Timer not initialized!\n"); return DHL_FAIL_NOT_INITIALIZED; } return DHL_OK; } #if COMMENT ______Method____(){} #endif /* add one timer entry this function should be called in timer task. */ static DHL_RESULT p_timer_add_entry(DHL_TIMER *timer, DHL_TIMER_COMMAND *cmd) { int i; int idSelected, idEmpty; //ASSERT(cmd->idCmd == eTMR_CMD_ADD); idSelected = -1; idEmpty = -1; // id¸¦ °Ë»öÇϸ鼭, µ¿½Ã¿¡ empty slotµµ ã´Â´Ù. // ÇØ´ç ID°¡ ÀÌ¹Ì »ç¿ëÁßÀ̶ó¸é °»½Å¸ðµå.. for (i=0; inMaxSlot; i++) { if (timer->info[i].used && timer->info[i].nId == cmd->idTimerOrCmd) { // ÀÌ¹Ì »ç¿ëÁßÀÌ´Ù.. // »õ·Î¿î parameter·Î updateÇϰí ÇÔ¼ö Á¾·á.. if (g_Trace_TimerHandle == timer) printf( "!! Timer [%d] already active. updated..\n", cmd->idTimerOrCmd); idSelected = i; break; } else if (timer->info[i].used == 0) { // ºñ¾îÀÖ´Â slotÀ» ã´Â´Ù.. if (idEmpty < 0) idEmpty = i; } } if (idSelected < 0) idSelected = idEmpty; if (idSelected >= 0) { DHL_TIMER_ENTRY *info = &timer->info[idSelected]; if (info->used == FALSE) { timer->nActiveTimer++; } info->nId = cmd->idTimerOrCmd; info->period = cmd->nPeriodMs; info->fn = cmd->func; for (i=0; inUserParam; i++) info->params[i] = cmd->userParams[i]; info->flags = cmd->flags; info->start = DHL_OS_GetMsCount(); info->used = TRUE; // maxActiveIndex¸¦ ¾Ë¾ÆµÎ¸é TimerTask¿¡¼­ loop¸¦ µ¹¶§ µµ¿òÀÌ µÈ´Ù. if (timer->maxActiveIndex < idSelected) timer->maxActiveIndex = idSelected; if (g_Trace_TimerHandle == timer) printf( "\t index %d, ID: %d, total %d active\n", idSelected, cmd->idTimerOrCmd, timer->nActiveTimer); } else { if (g_Trace_TimerHandle == timer) printf( "!! No more timer slot for ID: %d\n", cmd->idTimerOrCmd); // it may be available some time later because oneshot timer will die.. } return idSelected >= 0 ? DHL_OK : DHL_FAIL_NOT_AVAILABLE; } /* delete one timer entry. this function should be called in timer task. */ static DHL_RESULT p_timer_delete_entry(DHL_TIMER *timer, UINT32 nIdTimer) { int i; DHL_RESULT dhr = DHL_FAIL_NOT_FOUND; //ASSERT(cmd->idTimerOrCmd == eTMR_CMD_DELETE); if (nIdTimer == (UINT32)-1) { // delete all.. if (g_Trace_TimerHandle == timer) printf( "delete all timer entry\n"); memset(&timer->info, 0, timer->nMaxSlot*sizeof(DHL_TIMER_ENTRY)); timer->nActiveTimer = 0; timer->maxActiveIndex = -1; dhr = DHL_OK; } for (i=0;i<=timer->maxActiveIndex;i++) { if ((timer->info[i].used) && (timer->info[i].nId == nIdTimer)) { memset(&timer->info[i], 0, sizeof(DHL_TIMER_ENTRY)); timer->nActiveTimer--; if (g_Trace_TimerHandle == timer) printf( "StopTimer: index: %d, ID: %d\n", i, nIdTimer); dhr = DHL_OK; // ¹º°¡ À߸øµÇ¾î¼­ °°Àº ID·Î ¿©·¯°³°¡ µî·ÏµÇ¾î ÀÖÀ» ¼öµµ Àֱ⶧¹®¿¡ // ¿©±â¼­ loop¸¦ ³ª°¡Áö ¾Ê°í ¸ðµç timer record ¸¦ ´Ù °Ë»öÇØº»´Ù. } } return dhr; } /* show timer info */ static void p_timer_show(DHL_TIMER *timer, DHL_TIMER_COMMAND *cmd) { DHL_RESULT dhlResult; int i, k; char buf[80]; dhlResult = p_timer_check_valid(timer); if (dhlResult) return; DHL_OS_Printf("----- Timer Info 0x%x -----\n", timer); DHL_OS_Printf(" '%s', priority %d, max %d\n", timer->name, timer->param.task_priority, timer->nMaxSlot); for (i=0; i<=timer->maxActiveIndex; i++) { char *fname = NULL; if (!timer->info[i].used) continue; // dhl_dbg_find_sym_by_addr((UINT32)timer->info[i].fn, &fname); for (buf[0]=0, k=0; knUserParam); k++) sprintf(buf+strlen(buf), "%lx ", timer->info[i].params[k]); DHL_OS_Printf(" (%02d) ID %d, fn %x(%s) arg (%s), %d ms, f%x %s\n", i, timer->info[i].nId, timer->info[i].fn, fname ? fname : "?", buf, //timer->info[i].param, timer->info[i].period, //timer->info[i].period, timer->info[i].flags, timer->info[i].flags & eTIMER_FLAG_OneShot ? "oneshot" : timer->info[i].flags & eTIMER_FLAG_NowAndContinue ? "n&c" : "interval"); } DHL_OS_Printf("\n"); } void p_timer_call(DHL_TIMER *timer, UINT16 nTimerId, UINT16 flags, DHL_TIMER_PROC_EX pFn, UINT32 *userParams) { // timer callbackÀÌ ºÒ¸®´Â µ¿¾È¿¡´Â ¾î¶² timer id°¡ service ÁßÀÎÁö ±â·ÏÀ» ³²°ÜµÎÀÚ. timer->curServicedTimerId = nTimerId; if (g_Trace_TimerHandle == timer) printf( "\n---------- TimerExBegin: %x, ID %d, fn %x, param 0x%x \n", timer, nTimerId, pFn, userParams[0]); if (flags & TIMER_FLAG_OldStyleProc) ((DHL_TIMER_PROC)pFn)(nTimerId, userParams[0]); else pFn(nTimerId, userParams); if (g_Trace_TimerHandle == timer) printf( "---------- TimerExEnd: %x, ID %d \n\n", timer, nTimerId); timer->curServicedTimerId = 0; // timer id 0Àº ¿©±â¼­ ó·³ Ưº°ÇÑ Àǹ̷Π»ç¿ëÇϹǷÎ, ÀÏ¹Ý ID·Î´Â reserve ÇØ¾ß ÇÑ´Ù. } void p_timer_shutdown(DHL_TIMER *timer) { dprint(2, "timer stop requested..\n"); // TimerTerminate -> TimerTask shutdown ÀýÂ÷ Áß¿¡´Â race conditionÀ» °í·ÁÇÏÁö ¾Ê´Â´Ù. // µû¶ó¼­ client´Â shutdown sequence Áß¿¡´Â timer start µîÀÌ È£ÃâµÇÁö ¾Êµµ·Ï ÁÖÀÇÇØ¾ß ÇÑ´Ù. DHL_OS_DeleteSemaphore(timer->semAck); timer->semAck = 0; DHL_OS_DeleteSemaphore(timer->mutexAck); timer->mutexAck = 0; DHL_OS_DeleteMessageQueue(timer->msgQue); timer->msgQue = 0; dprint(2, "timer task about to shutdown..\n"); timer->nTaskId = 0; DHL_OS_SelfDeleteTask(); } #if COMMENT ____Task____() {} #endif /************************************************************************************* timer task - Timer Main Task. - µî·ÏµÈ Timer¸¦ °ü¸®ÇÑ´Ù. *************************************************************************************/ void dhl_timer_task(void* arg) { int i; DHL_RESULT result; DHL_TIMER_COMMAND cmd; int nMinRemainingTick; UINT32 uNow; DHL_TIMER *timer = (DHL_TIMER *)arg; // printf( "Timer Task Launched, timer %x, %u tick/s\n", timer, _second); // printf( "name '%s' max slot %d\n", timer->name, timer->nMaxSlot); while (TRUE) { DHL_OS_Delay(10); nMinRemainingTick = 0x7fffffff; // signed INT32 valueÀÇ ÃÖ´ë°ª.. //--------- timer expiration timeout üũ ------------ // ÇöÀç °¡Àå °¡±î¿î ½Ã°£ ³»¿¡ expire µÉ timer¸¦ ã´Â´Ù.. uNow = DHL_OS_GetMsCount(); for (i=0; i<=timer->maxActiveIndex; i++) { int nRemainTick; if (timer->info[i].used == 0) continue; nRemainTick = (int) (timer->info[i].start + timer->info[i].period - uNow); // ÀÌ¹Ì expire µÈ timer¶ó¸é remainÀº negative °ªÀ» °¡Áú °ÍÀÓ.. if (nMinRemainingTick > nRemainTick) { nMinRemainingTick = nRemainTick; // it can be negative!! } } //--------- wait message with/without timeout ------------ // ¼³·É, ÀÌ¹Ì expire µÈ timer entry°¡ ÀÖ´Ù°í ÇÏ´õ¶óµµ // timer ½ÇÇà ºÎÇϰ¡ ¸¹¾Æ¼­ command¸¦ ¾Æ¿¹ ¸ø¹Þ´Â »óȲÀÌ µÇÁö ¾Êµµ·Ï, // msgque ´Â ¹Ýµå½Ã ÇѹøÀº üũ¸¦ ¼öÇàÇÏ°í ³ª¼­ timer¸¦ ó¸®ÇØ ÁØ´Ù. if (nMinRemainingTick < 0) nMinRemainingTick = 0; // ¾ÆÁ÷ ³²Àº ½Ã°£ÀÌ ¸¹±â ¶§¹®¿¡ SleepÀ» ÇÑ´Ù. if (nMinRemainingTick < 0x7fffffff) { if (g_Trace_TimerHandle == timer) dprint(2, "Timer task enter sleep for %d ticks ....\n", nMinRemainingTick); result = DHL_OS_ReceiveMessage(timer->msgQue, &cmd, nMinRemainingTick); } else { // ó¸®ÇØ¾ß ÇÒ ³²Àº timer°¡ ¾ø´Ù¸é active µÉ¶§±îÁö ¹«ÇÑÁ¤ ±â´Ù¸®±â¸¸ ÇÏ¸é µÈ´Ù. // if (g_Trace_TimerHandle == timer) dprint(2, "Timer task enter sleep until timer set...z.z.z\n"); //OS_TakeSemaphore(timer->semWakeUp); result = DHL_OS_ReceiveMessage(timer->msgQue, &cmd, DHL_TIMEOUT_FOREVER); } //--------- process message if we got new one ------------ if (result == DHL_OK) // we got command { // È¿À²ÀûÀÎ dpc ¸í·É ¼öÇàÀ» À§ÇÑ Æ¯º°ÇÑ Ã³¸®. if (cmd.idTimerOrCmd < eTMR_CMD_BEGIN && cmd.nPeriodMs == 0 && (cmd.flags & eTIMER_FLAG_OneShot)) { // ¹Ù·Î Çѹø ½ÇÇà ÈÄ cancel µÇ´Â °ÍÀ̹ǷÎ, // ±»ÀÌ timer entry¿¡ µî·ÏÇÒ Çʿ䰡 ¾ø´Ù. p_timer_call(timer, cmd.idTimerOrCmd, cmd.flags, cmd.func, cmd.userParams); continue; } // add / delete / query / shutdown if (cmd.idTimerOrCmd < eTMR_CMD_BEGIN) { // This is Add command. result = p_timer_add_entry(timer, &cmd); if (g_Trace_TimerHandle == timer) DHL_TIMER_Show(timer); if (cmd.flags & eTIMER_FLAG_NowAndContinue) // µî·Ïµµ ÇÏÁö¸¸, Áö±Ý ¹Ù·Î ´çÀå callµµ ÇØÁÖ¾î¾ß ÇÑ´Ù. p_timer_call(timer, cmd.idTimerOrCmd, cmd.flags, cmd.func, cmd.userParams); } else if (cmd.idTimerOrCmd == eTMR_CMD_DELETE) { // delete ÀÎ °æ¿ì´Â »èÁ¦ÇÒ timer id°¡ userparam[0]À» ÅëÇØ Àü´Þ µÈ´Ù. result = p_timer_delete_entry(timer, cmd.userParams[0]); } else if (cmd.idTimerOrCmd == eTMR_CMD_DELETE_ALL) { result = p_timer_delete_entry(timer, (UINT32)-1); } else if (cmd.idTimerOrCmd == eTMR_CMD_SYNC) { ; // Ưº°È÷ ó¸®ÇÒ °Í ¾øÀ½. ±×³É ¾Æ·¡¿¡¼­ ack¸¸ ÁÖ¸é µÊ. } else if (cmd.idTimerOrCmd == eTMR_CMD_SHOW) { p_timer_show(timer, &cmd); } else if (cmd.idTimerOrCmd == eTMR_CMD_QUERY) { // not yet.. } else if (cmd.idTimerOrCmd == eTMR_CMD_SHUTDOWN) { break; } // »ç¿ë ¿¹¸¦ º¸¸é TimerStop ¿¡¼­¸¸ ack ¸ðµå¸¦ »ç¿ëÇϰí ÀÖÀ¸¹Ç·Î, // TimerStop ¿¡¼­ »ç¿ëµÇÁö ¾Ê´Â nPeriodMs º¯¼ö °ø°£À» result ¸®ÅÏ ¿ëµµ·Î »ç¿ëÇÑ´Ù. if (cmd.idTimerOrCmd == eTMR_CMD_DELETE && (cmd.flags & TIMER_FLAG_NeedAck)) { if (cmd.nPeriodMs) *(UINT32 *)(cmd.nPeriodMs) = (UINT32)result; DHL_OS_GiveSemaphore(timer->semAck); } if ((cmd.idTimerOrCmd == eTMR_CMD_SYNC) && (cmd.flags & TIMER_FLAG_NeedAck)) { DHL_OS_GiveSemaphore(timer->semAck); } } else if (result == DHL_FAIL_TIMEOUT) { // it is natural.. some timer entry is timed-out. } else { DHL_OS_Printf("!! timer rx msg result 0x%x \a\n", result); } //-------- timer entry ó¸® --------------- for (i=0; i<=timer->maxActiveIndex; i++) { DHL_TIMER_ENTRY *ti = &timer->info[i]; if (ti->used == FALSE) continue; // ÁöÁ¤ ½Ã°£ÀÌ °æ°úµÇ¾ú´ÂÁö üũ. Timeout µÇ¾úÀ¸¸é TimerÇÔ¼ö ¼öÇà. // if (DHL_OS_GetMsCount() - ti->start > ti->period) // Timer expired.. { UINT32 userParams[MAX_NUMBER_OF_TIMER_PARAM]; DHL_TIMER_PROC_EX pFn; UINT16 id, flags; BOOL bOneShot; // ¾Æ·¡¿¡¼­ oneshot ÀÎ °æ¿ì callback Àü¿¡ ¸ÕÀú ti¸¦ clear ½ÃŰ¹Ç·Î, // timer call¿¡ ÇÊ¿äÇÑ ¸ðµç ÆÄ¶ó¹ÌÅÍ´Â backup ÇØ µÎ¾î¾ß ÇÑ´Ù. pFn = ti->fn; id = ti->nId; flags = ti->flags; memcpy(userParams, ti->params, sizeof(UINT32)*timer->nUserParam); bOneShot = (flags & eTIMER_FLAG_OneShot) ? TRUE : FALSE; if (bOneShot) { // 1ȸ¼º Timer: ÀÌ timer¸¦ off½ÃŲ´Ù. memset(ti, 0, sizeof(DHL_TIMER_ENTRY)); timer->nActiveTimer--; } else { // Periodic Timer: tick counter¸¦ ¸®¼Â½ÃŲ´Ù. ti->start = DHL_OS_GetMsCount(); } p_timer_call(timer, id, flags, pFn, userParams); if (bOneShot) if (g_Trace_TimerHandle == timer) printf( "Oneshot timer ID %d killed\n", id); } } // end for (timer DB) } p_timer_shutdown(timer); DHL_OS_SelfDeleteTask(); } #if COMMENT ____LowLevel_API____(){} #endif DHL_RESULT DHL_TIMER_StartEx(DHL_TMHANDLE handle, UINT32 nIdTimer, UINT32 nPeriodMs, DHL_TIMER_PROC_EX func, int numParam, UINT32 *params, UINT16 flags) { DHL_RESULT dhlResult; DHL_TIMER *timer = (DHL_TIMER *)handle; DHL_TIMER_COMMAND cmd; DHL_OS_TASK_ID tid = DHL_OS_GetTaskID(); int i; if ((dhlResult = p_timer_check_valid(timer))!=0) return dhlResult; if (func == NULL) { printf( "!! func is null [%d]!\n", nIdTimer); return DHL_FAIL_INVALID_PARAM; } if (nIdTimer & 0xFFFF0000) { printf( "!! timer id should be 16-bits range.\n"); DHL_ASSERT(FALSE, ""); return DHL_FAIL_INVALID_PARAM; } if (nIdTimer >= eTMR_CMD_BEGIN || nIdTimer == 0) { printf( "!! timer id 0x%x is in reserved range.\n", nIdTimer); DHL_ASSERT(FALSE, ""); return DHL_FAIL_INVALID_PARAM; } if (nPeriodMs == 0 && !(flags & eTIMER_FLAG_OneShot)) { printf( "!! interval timer should have period.\n"); DHL_ASSERT(FALSE, ""); return DHL_FAIL_INVALID_PARAM; } // ½ÇÁ¦ parameterÀÇ °¹¼ö´Â Initialize ÇÒ ¶§ ÁöÁ¤Çß´ø ¼öº¸´Ù Å©¸é ¾ÈµÈ´Ù. if (numParam > timer->nUserParam) { numParam = timer->nUserParam; } // Initialize ¿¡¼­ ÁöÁ¤ÇÑ ¼ýÀÚº¸´Ù ÀûÀº °ÍÀº ±¦ÂúÀ½. 0À¸·Î ä¿öÁü. dprint(2, "%s: (ID %d, period %d, flags %x, %d params %x %x ..)\n", __FUNCTION__, nIdTimer, nPeriodMs, flags, numParam, params[0], params[1]); memset(&cmd, 0, sizeof(DHL_TIMER_COMMAND)); // ADDÀÇ °æ¿ì º°µµÀÇ command id¸¦ »ç¿ëÇÏÁö ¾Ê°í, ±×³É timer id¸¦ Àü¼ÛÇÑ´Ù. cmd.idTimerOrCmd = nIdTimer; cmd.nPeriodMs = nPeriodMs; cmd.func = func; cmd.flags = flags; for (i=0; inTaskId) { // send command asynchronously. // if we need return value, then we should use ack. // // cmd ÀÚü´Â ÃÖ´ë °¹¼öÀÇ user paramÀ» Æ÷ÇÔÇϰí ÀÖÁö¸¸ // OSAL ³»ºÎ¿¡¼­ ÇÊ¿äÇÑ ¸¸Å­¸¸ º¹»ç¸¦ ÇØ °¥ °ÍÀÌ´Ù. dhlResult = DHL_OS_SendMessage(timer->msgQue, &cmd, sizeof(cmd)); if (dhlResult) { // error check.. printf( "!! %s send cmd err %x\a\n", __FUNCTION__, dhlResult); } } else { // current task is THE TIMER task that we can add. // so, we can directly modify timer info. // dhlResult = p_timer_add_entry(timer, &cmd); } return dhlResult; } DHL_RESULT DHL_TIMER_Start(DHL_TMHANDLE handle, UINT32 nIdTimer, UINT32 nPeriodMs, DHL_TIMER_PROC func, UINT32 param, BOOL bOneShot) { UINT16 flags = \ bOneShot == 0 ? eTIMER_FLAG_Continue : \ bOneShot == 2 ? eTIMER_FLAG_NowAndContinue : eTIMER_FLAG_OneShot; flags |= TIMER_FLAG_OldStyleProc; return DHL_TIMER_StartEx(handle, nIdTimer, nPeriodMs, (DHL_TIMER_PROC_EX) func, 1, ¶m, flags); } DHL_RESULT DHL_TIMER_Stop(DHL_TMHANDLE handle, UINT32 nIdTimer) { DHL_RESULT dhlResult, dhReturnValue = DHL_OK; DHL_TIMER *timer = (DHL_TIMER *)handle; DHL_TIMER_COMMAND cmd; DHL_OS_TASK_ID tid = DHL_OS_GetTaskID(); if ((dhlResult = p_timer_check_valid(timer))!=0) return dhlResult; // À߸øµÈ timer id ´Â ¾Æ¹«·± ¿µÇâÀ» ³¢Ä¡Áö ¾Ê´Â´Ù. Á¦°Å. #if 0 if (nIdTimer == 0) { // cafrii 060919 add printf( "!! invalid timer id 0\n", nIdTimer); return DHL_FAIL_INVALID_PARAM; } #endif memset(&cmd, 0, sizeof(DHL_TIMER_COMMAND)); cmd.idTimerOrCmd = eTMR_CMD_DELETE; cmd.userParams[0] = nIdTimer & 0xFFFF; // id´Â 16-bits.. if (tid != timer->nTaskId) { int wait_count; cmd.flags |= TIMER_FLAG_NeedAck; // we always request ACK when send STOP command. cmd.nPeriodMs = (UINT32)&dhReturnValue; // need ack mechanism.. DHL_OS_TakeSemaphore(timer->mutexAck, DHL_TIMEOUT_FOREVER); DHL_OS_TakeSemaphore(timer->semAck, 0); // reset to none dhlResult = DHL_OS_SendMessage(timer->msgQue, &cmd, sizeof(cmd)); if (dhlResult) { // error check.. printf( "!! %s send cmd err %x\a\n", __FUNCTION__, dhlResult); } for (wait_count=0 ; wait_count<5; wait_count++) { if (wait_count) printf( "!! timer not responding.. wait %d..\n", wait_count); dhlResult = DHL_OS_TakeSemaphore(timer->semAck, 1000); if (dhlResult == DHL_OK) break; } dhlResult = dhReturnValue; DHL_OS_GiveSemaphore(timer->mutexAck); } else { // current task is THE TIMER task that we can add. // so, we can directly modify timer info. // dhlResult = p_timer_delete_entry(timer, nIdTimer); } return dhlResult; } DHL_RESULT DHL_TIMER_Sync(DHL_TMHANDLE handle) { DHL_RESULT dhlResult, dhReturnValue = DHL_OK; DHL_TIMER *timer = (DHL_TIMER *)handle; DHL_TIMER_COMMAND cmd; DHL_OS_TASK_ID tid = DHL_OS_GetTaskID(); if ((dhlResult = p_timer_check_valid(timer))!=0) return dhlResult; memset(&cmd, 0, sizeof(DHL_TIMER_COMMAND)); cmd.idTimerOrCmd = eTMR_CMD_SYNC; if (tid != timer->nTaskId) { int wait_count; cmd.flags |= TIMER_FLAG_NeedAck; // we need ACK for this command. // need ack mechanism.. DHL_OS_TakeSemaphore(timer->mutexAck, DHL_TIMEOUT_FOREVER); DHL_OS_TakeSemaphore(timer->semAck, 0); // reset to none dhlResult = DHL_OS_SendMessage(timer->msgQue, &cmd, sizeof(cmd)); if (dhlResult) { // error check.. printf( "!! %s send cmd err %x\a\n", __FUNCTION__, dhlResult); } for (wait_count=0 ; wait_count<5; wait_count++) { if (wait_count) printf( "!! timer '%s' not responding.. wait %d..\n", timer->name, wait_count); dhlResult = DHL_OS_TakeSemaphore(timer->semAck, 1000); if (dhlResult == DHL_OK) break; } dhlResult = dhReturnValue; DHL_OS_GiveSemaphore(timer->mutexAck); } else { DHL_ASSERT(FALSE, "invalid usage\n"); } return dhlResult; } void DHL_TIMER_Show(DHL_TMHANDLE handle) { DHL_RESULT dhlResult; DHL_TIMER *timer; DHL_TIMER_COMMAND cmd; DHL_OS_TASK_ID tid = DHL_OS_GetTaskID(); if (handle == 0) timer = g_dhl_timer_list; else timer = (DHL_TIMER *)handle; while (timer) { if ((dhlResult = p_timer_check_valid(timer))!=0) return; memset(&cmd, 0, sizeof(DHL_TIMER_COMMAND)); cmd.idTimerOrCmd = eTMR_CMD_SHOW; // this SHOW command do not use ACK. if (tid != timer->nTaskId) { // send command asynchronously.. dhlResult = DHL_OS_SendMessage(timer->msgQue, &cmd, sizeof(cmd)); if (dhlResult) { // error check.. printf( "!! %s send cmd err %x\a\n", __FUNCTION__, dhlResult); } } else { p_timer_show(timer, &cmd); } if (handle) // show only specified timer. break; if (tid != timer->nTaskId) { DHL_OS_Delay(100); // wait for timer tasks to print information } timer = timer->next; } } DHL_RESULT DHL_TIMER_Initialize(DHL_TIMER_INIT_PARAM *param, DHL_TMHANDLE *pHandle) { DHL_RESULT dhlResult = DHL_OK; int nAllocSize; char buf[20]; UINT32 mask; DHL_TIMER *timer = NULL; dprint(2, "%s: timer '%s' init, max %d, pri %d, stack %d, #param %d, qsize %d\n", __FUNCTION__, param->name, param->max_timer_entry, param->task_priority, param->stack_size, param->num_user_param, param->msg_que_size); *pHandle = NULL; // initialize first.. if (param->max_timer_entry <= 0) return DHL_FAIL_INVALID_PARAM; nAllocSize = sizeof(DHL_TIMER) + 4 + param->max_timer_entry * sizeof(DHL_TIMER_ENTRY) + 4; // assign some guard band space between master timer info and timer slot entries. timer = (DHL_TIMER *) DHL_OS_Malloc(nAllocSize); if (timer == NULL) return DHL_FAIL_OUT_OF_MEMORY; memset(timer, 0, nAllocSize); // name of timers strncpy(timer->name, param->name, MAX_TIMER_NAME); timer->name[MAX_TIMER_NAME] = 0; // max timer slots timer->nMaxSlot = param->max_timer_entry; // no active timer now. timer->maxActiveIndex = -1; // timer slots timer->info = (DHL_TIMER_ENTRY *) ((UINT8 *)timer + sizeof(DHL_TIMER) + 4); // num user param if (param->num_user_param == 0) timer->nUserParam = 1; // for backward compatibility else if (param->num_user_param > 0 && param->num_user_param <= MAX_NUMBER_OF_TIMER_PARAM) timer->nUserParam = param->num_user_param; else { printf( "!! num user param %d invalid.\n", param->num_user_param); goto label_end; } // message que size if (param->msg_que_size == 0) timer->nMaxQueSize = DEFAULT_MSG_QUE_SIZE; // for backward compatibility else if (param->msg_que_size > 0) timer->nMaxQueSize = param->msg_que_size; else { printf( "!! que size %d invalid.\n", param->msg_que_size); goto label_end; } // task´Â ¸Ç ¸¶Áö¸·¿¡ »ý¼ºÇÏ´Â °Ô ÁÁ´Ù. priority °ü·ÃÇÏ¿© ¸ÕÀú ½ÇÇà °¡´É¼ºÀÌ ÀÖÀ¸¹Ç·Î.. // memset(buf, 0, sizeof(buf)); strcpy(buf, "TS"); // timer ack sem strncpy(buf+2, timer->name, 6); timer->semAck = DHL_OS_CreateBinarySemaphore(buf, 0, 0); if (timer->semAck == 0) { printf( "!! Creating sem err\n"); dhlResult = DHL_FAIL_OUT_OF_RESOURCE; goto label_end; } // param->use_mutex_lock is never used at all. memset(buf, 0, sizeof(buf)); strcpy(buf, "TM"); // timer ack mutex strncpy(buf+2, timer->name, 6); timer->mutexAck = DHL_OS_CreateMutexSemaphore(buf); if (timer->mutexAck == 0) { printf( "!! Creating mutex err\n"); dhlResult = DHL_FAIL_OUT_OF_RESOURCE; goto label_end; } memset(buf, 0, sizeof(buf)); strcpy(buf, "TQ"); // timer cmd que strncpy(buf+2, timer->name, 6); #if 0//BRCM timer->msgQue = DHL_OS_CreateMessageQueue(buf, 0, TIMER_COMMAND_SIZE(timer->nUserParam), TIMER_COMMAND_SIZE(timer->nUserParam)); #else timer->msgQue = DHL_OS_CreateMessageQueue(buf, 0, timer->nMaxQueSize, TIMER_COMMAND_SIZE(timer->nUserParam)); #endif if (timer->msgQue == 0) { printf( "!! Creating msgq err\n"); dhlResult = DHL_FAIL_OUT_OF_RESOURCE; goto label_end; } timer->magic = DHL_TIMER_MAGICKEY; //timer->fnLock = dhl_timer_lock; //timer->fnUnlock = dhl_timer_unclock; timer->param = *param; timer->param.name = timer->name; mask = DHL_OS_DisableInterrupts(); timer->next = g_dhl_timer_list; g_dhl_timer_list = timer; DHL_OS_RestoreInterrupts(mask); //memdump(timer, sizeof(*timer), "timer"); //console_flush(); /* timer task priority°¡ ³ôÀ» °æ¿ì ÀÌ ÇÔ¼ö°¡ Á¾·áµÇÁö Àü¿¡µµ ¹Ù·Î timer task°¡ ½ÇÇà µÉ ¼ö ÀÖÀ½¿¡ À¯ÀÇÇÒ °Í. */ timer->nTaskId = DHL_OS_CreateTask((DHL_OS_TASKFUNCTION) dhl_timer_task, timer->name, param->task_priority, param->stack_size, (UINT32)timer); if (timer->nTaskId == (DHL_OS_TASK_ID) 0) { printf( "!! Creating task err\n"); dhlResult = DHL_FAIL_OUT_OF_RESOURCE; goto label_end; } //dhl_timer_show(0); if (pHandle) *pHandle = (DHL_TMHANDLE) timer; timer = 0; label_end: if (timer) { // clean up! printf( "!! err occurred in timer init. clean up!\n"); if (timer->semAck) DHL_OS_DeleteSemaphore(timer->semAck); if (timer->mutexAck) DHL_OS_DeleteSemaphore(timer->mutexAck); if (timer->msgQue) DHL_OS_DeleteMessageQueue(timer->msgQue); DHL_OS_Free((void**)&timer); } return dhlResult; } /** @todo Task Á¾·á OSAL API°¡ ¾ø´Ù¸é internal ¿ëµµÀÇ functionÀ» ¸¸µé¾î¼­ OSAL_Priv.h ¿¡ µî·ÏÇØ ³õ°í »ç¿ëÇÏ¸é µÉ °Í °°À½. */ void DHL_TIMER_Terminate(DHL_TMHANDLE handle) { DHL_RESULT dhlResult; DHL_TIMER *timer = (DHL_TIMER *)handle; UINT32 i; DHL_TIMER_COMMAND cmd; DHL_OS_TASK_ID tid = DHL_OS_GetTaskID(); // TimerTask°¡ ÀÚµ¿À¸·Î Á×À»¶§±îÁö ±â´Ù¸± ½Ã°£.. #define WAIT_TIME 5 // second. #define CHECK_PER_SECOND 5 // times. if ((dhlResult = p_timer_check_valid(timer))!=0) return; if (tid == timer->nTaskId) { printf( "!! %s: cannot shutdown timer in itself\n", __FUNCTION__); return; } memset(&cmd, 0, sizeof(DHL_TIMER_COMMAND)); cmd.idTimerOrCmd = eTMR_CMD_SHUTDOWN; dhlResult = DHL_OS_SendMessage(timer->msgQue, &cmd, sizeof(cmd)); if (dhlResult) { // error check.. printf( "!! %s send cmd err %x\n", __FUNCTION__, dhlResult); } for (i = 0; i < WAIT_TIME*CHECK_PER_SECOND; ++i) { if (timer->nTaskId == 0) { break; } DHL_OS_Delay(1000/CHECK_PER_SECOND); } // ÃæºÐÈ÷ ±â´Ù·È°Ç¸¸, Self Delete°¡ µÇÁö ¾Ê¾ÒÀ» °æ¿ì¿¡´Â °­Á¦ Á¾·á½ÃŲ´Ù. // if (timer->nTaskId != 0) { printf( "!! timer shutdown timeout!\n"); #if 0 DHL_ASSERT(dhl_os_delete_task(timer->nTaskId) == DHL_OK, "!! timer task destroy failled.. \n"); #endif } #if 0 // remove. if command not works, something is wrong. // ¿ø·¡ Timer task¿¡¼­ »èÁ¦ÇؾßÇÏ´Â °ÍµéÀÌ´Ù. if (timer->semAck) { OS_DeleteSemaphore(timer->semAck); timer->semAck = 0; } if (timer->mutexAck) { OS_DeleteSemaphore(timer->mutexAck); timer->mutexAck = 0; } #endif timer->nTaskId = 0; DHL_OS_Free((void**)&timer); } #if COMMENT ____HighLevel_API____(){} #endif DHL_TMHANDLE g_dhl_timer=NULL; DHL_RESULT DHL_SYS_TimerInit(void) { DHL_TIMER_INIT_PARAM* param; // dhl_timer_module_init(); param = (DHL_TIMER *) DHL_OS_Malloc(sizeof(DHL_TIMER_INIT_PARAM)); if (g_dhl_timer) return DHL_OK; // dhl timer already initialized. memset(param, 0, sizeof(DHL_TIMER_INIT_PARAM)); param->max_timer_entry = DHL_TIMER_MAX_ENTRY; param->name = "DHLTMR"; param->task_priority = DHL_TIMER_TASK_PRIO; param->stack_size = DHL_TIMER_TASK_STACK; param->use_mutex_lock = 0; // we should support ISR!! return DHL_TIMER_Initialize(param, &g_dhl_timer); } DHL_RESULT DHL_SYS_StartTimer(UINT32 nIdTimer, UINT32 nPeriodMs, DHL_TIMER_PROC func, UINT32 param, BOOL bOneShot) { return DHL_TIMER_Start(g_dhl_timer, nIdTimer, nPeriodMs, func, param, bOneShot); } DHL_RESULT DHL_SYS_KillTimer(UINT32 nIdTimer) { return DHL_TIMER_Stop(g_dhl_timer, nIdTimer); } void DHL_SYS_ShowTimer(void) { DHL_TIMER_Show(g_dhl_timer); } #if COMMENT ____Symbol____(){} #endif #if DHL_REGISTER_DEUBG_SYMBOLS static DHL_SymbolTable dhl_timer_symbol[] = { //---- functions //DHL_FNC_SYM_ENTRY(DHL_SYS_PrintTimer), //DHL_FNC_SYM_ENTRY(DHL_SYS_KillTimer), //---- variables //DHL_VAR_SYM_ENTRY(g_Trace_bDHLTimer), DHL_VAR_SYM_ENTRY(g_Trace_TimerHandle), }; #endif // DHL_REGISTER_DEBUG_SYMBOL #if COMMENT ____Init____(){} #endif void dhl_timer_module_init(void) { static BOOL s_module_init=FALSE; if (s_module_init) return; #if DHL_REGISTER_DEUBG_SYMBOLS DHL_DBG_RegisterSymbols(dhl_timer_symbol, DHL_NUMSYMBOLS(dhl_timer_symbol)); #endif s_module_init = TRUE; } /* end of file */