/* DMW_PsiTask.c DST TV MW PSI Scan Module PSI scan Worker Task implementation Copyright 2006~2009 Digital STREAM Technology, Inc. All Rights Reserved */ #include "DMW_Platform.h" #include "DMW_PsiConfig.h" #include "DMW_PsiTypes.h" #include "DMW_PsiEngine.h" #if USE_OSX_TASK #include "OSX_Task.h" #endif DHL_MODULE("psitsk", 1); #if COMMENT ____Config____(){} #endif #define PSIM_TASK_PRIORITY TASK_PRI_DMW_PSI #if COMMENT ____Structures____(){} #endif #if !USE_OSX_TASK typedef struct { //S_PSIM_MSG_HDR hdr; /* ¾î¶² µ¿ÀÛÀ» ¼öÇàÇÒ °ÍÀÎÁö¸¦ ÁöÁ¤ÇÏ´Â ¸í·É ID. */ E_PSIM_CMD cmd_id; //S_PSIM_PORT *tsport; // it should be part of payload.. /* message¸¦ º¸³»´Â client°¡ message ½ÇÇà Á¾·á¸¦ ack·Î ¹Þ°í ½ÍÀº °æ¿ì event semÀ» »ý¼ºÇÏ¿© °°ÀÌ º¸³»¸é worker task´Â command ó¸® ÈÄ ÀÌ semÀ» release ÇÑ´Ù. */ //OS_SEMAPHORE_ID sem_ack; // ack semaphore. BOOL sync; UINT32 payload[2]; } S_PSIM_MSG; /* task context. task state Á¤º¸ */ typedef struct S_PSIM_TASK_t { UINT32 magic; DHL_OS_TASK_ID task_id; DHL_OS_SEMA_ID mutex; DHL_OS_SEMA_ID acksem; DHL_OS_MSGQ_ID queue; // currently, we have only one psi_scan module. // S_PSIM_CONTEXT *module; } S_PSIM_TASK; S_PSIM_TASK g_psi_task; PSI_STATIC S_PSIM_TASK *GetPsiTask(void) { return &g_psi_task; } #else // USE_OSX_TASK static H_OSX_TASK s_psi_task_handle; static DHL_OS_TASK_ID s_psi_task_id; #endif /* PSI Engine Context */ S_PSIM_CONTEXT *g_psi_module_context; #if COMMENT ____Declare____(){} #endif #if !USE_OSX_TASK PSI_STATIC void _PsiWorkerTask(UINT32 arg); #endif #if COMMENT ____MsgHandler____(){} #endif #if !USE_OSX_TASK /* message ó¸® Çڵ鷯ÀÇ prototype */ typedef STATUS (*PSI_MSG_HANDLER)(S_PSIM_TASK *pTask, S_PSIM_MSG *pMsg); STATUS PsiMsgHandler_ScanStart(S_PSIM_TASK *pTask, S_PSIM_MSG *pMsg) { /* event handler of ePSIM_CMD_ScanStart ÀÔ·Â [0] tDHL_TSD *tsd [1] S_PSIM_USER_INPUT *input */ tDHL_TSD tsd = (tDHL_TSD) pMsg->payload[0]; S_PSIM_USER_INPUT *input = (S_PSIM_USER_INPUT *) pMsg->payload[1]; dprint(3, "%s: tsd %x, rf %d, #%d, $%d\n", __FUNCTION__, tsd, input->rf, input->program_number, input->source_id); return PSIE_StartPsiScan(pTask->module, tsd, input); } STATUS PsiMsgHandler_ScanStop(S_PSIM_TASK *pTask, S_PSIM_MSG *pMsg) { /* event handler of // [0] S_PSIE_PORT *tsport // [1] -- */ tDHL_TSD *tsd = (tDHL_TSD *) pMsg->payload[0]; dprint(3, "%s: tsd %x\n", __FUNCTION__, tsd); return PSIE_StopPsiScan(pTask->module, tsd); } STATUS PsiMsgHandler_TableReceived(S_PSIM_TASK *pTask, S_PSIM_MSG *pMsg) { /* event handler of ePSIM_CMD_ScanStop ÀÔ·Â [0] S_PSIE_PORT *tsport, [1] tDHL_PSIDataArray *desc */ S_PSIM_PORT *tsport = (S_PSIM_PORT *) pMsg->payload[0]; tDHL_PSI_DataArray *desc = (tDHL_PSI_DataArray *) pMsg->payload[1]; return PSIE_ProcessReceivedTable(pTask->module, tsport, desc); } STATUS PsiMsgHandler_DeleteTables(S_PSIM_TASK *pTask, S_PSIM_MSG *pMsg) { /* event handler of ePSIM_CMD_DeleteTables ÀÔ·Â // [0] int id (rf). if id is 0, delete all tables. // [1] -- */ int id = (int) pMsg->payload[0]; return PSIE_DeleteTables(pTask->module, id); } #else // USE_OSX_TASK PSI_STATIC void PsiCmd_ScanStart(E_PSIM_CMD cmd, tDHL_TSD tsd, S_PSIM_USER_INPUT *input) { dprint(3, "%s: tsd %x, rf %d, #%d, $%d\n", __FUNCTION__, tsd, input->rf, input->program_number, input->source_id); PSIE_StartPsiScan(g_psi_module_context, tsd, input); } PSI_STATIC void PsiCmd_ScanStop(E_PSIM_CMD cmd, tDHL_TSD tsd) { dprint(3, "%s: tsd %x\n", __FUNCTION__, tsd); PSIE_StopPsiScan(g_psi_module_context, tsd); } PSI_STATIC void PsiCmd_TableReceived(E_PSIM_CMD cmd, S_PSIM_PORT *tsport, tDHL_PSI_DataArray *desc) { PSIE_ProcessReceivedTable(g_psi_module_context, tsport, desc); } PSI_STATIC void PsiCmd_DeleteTables(E_PSIM_CMD cmd, int id) { PSIE_DeleteTables(g_psi_module_context, id); } #endif #if COMMENT ____Private____(){} #endif #if !USE_OSX_TASK /* Command Dispatch Table */ typedef struct { E_PSIM_CMD cmd_id; PSI_MSG_HANDLER handler; } S_PSIM_CMD_ENTRY; S_PSIM_CMD_ENTRY g_psi_cmd_table[] = { { ePSIM_CMD_ScanStart, PsiMsgHandler_ScanStart, }, { ePSIM_CMD_ScanStop, PsiMsgHandler_ScanStop, }, { ePSIM_CMD_DeleteTables, PsiMsgHandler_DeleteTables, }, { ePSIM_CMD_TableReceived, PsiMsgHandler_TableReceived, }, { ePSIM_CMD_Exit, 0 }, }; PSI_STATIC BOOL IsExitMessage(S_PSIM_MSG *pMsg) { return pMsg->cmd_id == ePSIM_CMD_Exit ? TRUE : FALSE; } /* get message ¼öÇà½Ã ÇÊ¿äÇÑ timeoutÀ» ¸®ÅÏÇÑ´Ù. ÇöÀç task state¿¡ µû¶ó ´Þ¶óÁü. idle processing ÇÒ °ÍÀÌ ¾ø´Ù¸é timeout ÇÊ¿ä ¾øÀ½. */ PSI_STATIC UINT32 GetTimeout(S_PSIM_TASK *pTask) { UINT32 timeOut; // ÇöÀç ÀÌ task´Â ÇϳªÀÇ ¸ðµâ¸¸À» Áö¿øÇÔ. // º¹¼ö ¸ðµâÀÎ °æ¿ì´Â ¿©·¯ ¸ðµâ Áß¿¡¼­ ªÀº timeout À» ¼±ÅÃ. timeOut = PSIE_GetTimeout(pTask->module); return timeOut; } /* queue¿¡¼­ message¸¦ ¹Þ´Â´Ù. */ PSI_STATIC int GetMessage(S_PSIM_TASK *pTask, S_PSIM_MSG *pMsg, UINT32 nWaitTimeout) { int nMsgLen; int err; /* cafrii 090717 OSAL tick Àº signed integer ÀÓ. 0 À̸é no wait ·Î µ¿ÀÛ. OSAL API »ó¿¡ ¸íÈ®ÇÏ°Ô ±â¼úÀº ¾ÈµÇ¾î ÀÖ´Â °Í °°Áö¸¸ ¼Ò½º ÄÚµå´Â ±×·¸°Ô µÇ¾î ÀÖÀ½. */ if ((int)nWaitTimeout >= 0 && nWaitTimeout < 0x7FFFFFFF) { //dprint(2, "rx msg wait tick %x\n", nWaitTimeout); err = DHL_OS_ReceiveMessage(pTask->queue, pMsg, nWaitTimeout); } else { //dprint(2, "rx msg forever\n"); err = DHL_OS_ReceiveMessage(pTask->queue, pMsg, DHL_TIMEOUT_FOREVER); } return err; } /* Task·Î ¸í·ÉÀ» Àü´ÞÇÑ´Ù. ÀÌ ÇÔ¼ö´Â Interrupt ISR state¿¡¼­µµ È£ÃâÀÌ °¡´ÉÇØ¾ß ÇÑ´Ù. */ PSI_STATIC STATUS SendMessage(E_PSIM_CMD cmd_id, UINT32 payload_0, UINT32 payload_1, BOOL bWait) { S_PSIM_TASK *pTask = GetPsiTask(); int err; STATUS status = statusOK; S_PSIM_MSG msg; //dprint(2, "send msg, cmd %x, p0 %x, p1 %x, wait %d\n", cmd_id, payload_0, payload_1, bWait); //memset(&msg, 0, sizeof(msg)); msg.cmd_id = cmd_id; msg.payload[0] = payload_0; msg.payload[1] = payload_1; msg.sync = bWait; //-------- if (bWait) { DHL_OS_TakeSemaphore(pTask->mutex, DHL_TIMEOUT_FOREVER); // flush ack semaphore for completeness. // because this is binary sem, one release is enough. // // cafrii, bugfix!! // give sem À» ÇÏ¸é ¾ÈµÇ°í, resetÀ» ÇØ¾ß ÇÔ. DHL_OS_TakeSemaphore(pTask->acksem, 0); } err = DHL_OS_SendMessage(pTask->queue, &msg, sizeof(msg)); if (err) { dprint(0, "!! send cmd msg err %d\n", err); status = statusQueueFull; } // for sync mode, we should wait until ack is coming. if (bWait && !err) { //dprint(2, ".. wait ack sem..\n"); DHL_OS_TakeSemaphore(pTask->acksem, DHL_TIMEOUT_FOREVER); //dprint(2, ".. ack sem released..\n"); } //-------- if (bWait) DHL_OS_GiveSemaphore(pTask->mutex); return status; } /* ÀÔ·Â ¹ÞÀº ¸Þ½ÃÁö¸¦ ó¸®ÇÑ´Ù. µî·ÏµÈ msg handler¸¦ È£ÃâÇÑ´Ù. */ PSI_STATIC STATUS ProcessMessage(S_PSIM_TASK *pTask, S_PSIM_MSG *pMsg) { int i; S_PSIM_CMD_ENTRY *entry; STATUS status = statusOK; int nCmds = sizeof(g_psi_cmd_table)/sizeof(g_psi_cmd_table[0]); for (i=0; icmd_id == pMsg->cmd_id) { dprint(3, "cmd %x matched, handler 0x%x\n", pMsg->cmd_id, entry->handler); if (entry->handler) status = (entry->handler)(pTask, pMsg); if (pMsg->sync) { dprint(2, "ack sem..\n"); DHL_OS_GiveSemaphore(pTask->acksem); } break; } } if (i>=nCmds) { // no such commands dprint(0, "!! cmd id 0x%x unknown\n", pMsg->cmd_id); } return status; } /* */ PSI_STATIC void DoPeriodicProcessing(S_PSIM_TASK *pTask) { PSIE_DoPeridicProcessing(pTask->module); } //------------------------------------------- // psi module ¸®¼Ò½ºµéÀ» ÁغñÇÑ´Ù. // PSI_STATIC STATUS CreateTaskResources(void) { S_PSIM_TASK *pTask = GetPsiTask(); if (pTask->task_id == 0 || pTask->mutex == 0 || pTask->acksem == 0 || pTask->queue == 0) { //UINT32 mask; int iPriorityScan = PSIM_TASK_PRIORITY; dprint(2, "%s..\n", __FUNCTION__); //mask = OS_LockTask(); if (pTask->mutex == 0) pTask->mutex = DHL_OS_CreateMutexSemaphore("PsiMutex"); if (pTask->acksem == 0) pTask->acksem = DHL_OS_CreateBinarySemaphore("PsiCmdAck", OS_SEM_FIFO, FALSE); if (pTask->queue == 0) pTask->queue = DHL_OS_CreateMessageQueue("PsiCmdQ", 0, 20, // max number of message. sizeof(S_PSIM_MSG)); // ¸Þ½ÃÁö ±æÀÌÀÇ ÃÖ´ë°ª. Á¤ÇØÁø ±¸Á¶Ã¼¸¦ »ç¿ëÇÏÀÚ. if (pTask->task_id == 0) { pTask->task_id = DHL_OS_CreateTask(_PsiWorkerTask, "tPsiScan", iPriorityScan, 8192, 0); if (pTask->task_id == (DHL_OS_TASK_ID)0) pTask->task_id = 0; } //OS_UnlockTask(mask); } if (pTask->task_id == 0 || pTask->mutex == 0 || pTask->acksem == 0 || pTask->queue == 0) { // ÇÊ¿äÇÑ resource°¡ ¾øÀ¸¹Ç·Î ÁøÇà ºÒ°¡.. // ±×·¯³ª shutdown ÇÒ ¶§ ±îÁö´Â ¸®¼Ò½º »èÁ¦´Â ÇÏÁö ¾Ê´Â´Ù. dprint(0, "!! resource err: task %x, mtx %x, ack %x, que %x\n", pTask->task_id, pTask->mutex, pTask->acksem, pTask->queue); DHL_ASSERT(FALSE, ""); return statusOutOfResource; } return statusOK; } #else PSI_STATIC STATUS StartOsxTask(void) { DHL_RESULT dhr; S_OSX_TASK_INIT_SETTING setting; S_OSX_TASK_INFO info; OSX_TaskGetDefaultInitSetting(&setting); setting.name = "Psi"; setting.max_scheduled_cmd = 4; setting.priority = PSIM_TASK_PRIORITY; setting.stack_size = 8192; setting.num_cmd_param = 2; setting.msg_que_size = 20; dhr = OSX_TaskStart(&setting, &s_psi_task_handle); if (dhr) { dprint(0, "!! psi task start err 0x%x\n", dhr); return statusError; } OSX_TaskGetInfo(s_psi_task_handle, &info); s_psi_task_id = info.tid; return statusOK; } #endif // USE_OSX_TASK #if COMMENT ____TaskBody____(){} #endif #if !USE_OSX_TASK PSI_STATIC void _PsiWorkerTask(UINT32 arg) { BOOL bExitFlag = FALSE; int err; UINT32 nWaitTimeout; S_PSIM_MSG msg; S_PSIM_TASK *pTask = GetPsiTask(); dprint(2, "psi task started\n"); // initialize task info.. pTask->magic = 0xcafe2009; pTask->module = g_psi_module_context; dprint(2, "change engine module (%x) state\n", pTask->module); PSIE_ChangeModuleState(pTask->module, ePSIM_MODULE_STATE_Idle); while (bExitFlag != TRUE) { // check current task state. nWaitTimeout = GetTimeout(pTask); err = GetMessage(pTask, &msg, nWaitTimeout); // message received? if (err) { dprint(0, "!! get msg err %d\n", err); } else if (IsExitMessage(&msg)) { dprint(2, "exit psi task..\n"); bExitFlag = TRUE; } else { ProcessMessage(pTask, &msg); } DoPeriodicProcessing(pTask); } pTask->magic = 0x0; DHL_OS_SelfDeleteTask(); } #endif // !USE_OSX_TASK #if COMMENT ____Public____(){} #endif /* psi task·Î ÀÏ¹Ý command¸¦ º¸³½´Ù. */ STATUS PSITASK_SendCommand(E_PSIM_CMD cmd_id, UINT32 payload_0, UINT32 payload_1, BOOL bWait) { #if !USE_OSX_TASK return SendMessage(cmd_id, payload_0, payload_1, bWait); #else DHL_RESULT dhr; F_OSX_TASK_PROC fn; if (cmd_id == ePSIM_CMD_ScanStart) fn = (F_OSX_TASK_PROC)PsiCmd_ScanStart; else if (cmd_id == ePSIM_CMD_ScanStop) fn = (F_OSX_TASK_PROC)PsiCmd_ScanStop; else if (cmd_id == ePSIM_CMD_DeleteTables) fn = (F_OSX_TASK_PROC)PsiCmd_DeleteTables; else if (cmd_id == ePSIM_CMD_TableReceived) fn = (F_OSX_TASK_PROC)PsiCmd_TableReceived; else return statusInvalidArgument; dhr = OSX_TaskRunCmd(s_psi_task_handle, cmd_id, 0, fn, payload_0, payload_1); if (dhr == DHL_OK && bWait) dhr = OSX_TaskSync(s_psi_task_handle); return dhr ? statusError : statusOK; #endif // USE_OSX_TASK } /* return TRUE if current task is psi task. */ BOOL PSITASK_IsPsiTask(void) { #if !USE_OSX_TASK S_PSIM_TASK *pTask = GetPsiTask(); if (DHL_OS_GetTaskID() == pTask->task_id) return TRUE; return FALSE; // this is not psi task.. #else if (DHL_OS_GetTaskID() == s_psi_task_id) return TRUE; return FALSE; // this is not psi task.. #endif } #if COMMENT ____Init____(){} #endif static DHL_SymbolTable __symbols[] = { //---- vars //DHL_VAR_SYM_ENTRY(g_Trace_PsiTask), 0, }; STATUS PSITASK_Init(void *pModuleContext) { dprint(2, "psitask init..\n"); g_psi_module_context = (S_PSIM_CONTEXT *)pModuleContext; DHL_DBG_RegisterSymbols(__symbols, DHL_NUMSYMBOLS(__symbols)); #if !USE_OSX_TASK return CreateTaskResources(); #else return StartOsxTask(); #endif // USE_OSX_TASK }