Resource Layer
리소스 계층은 유사한 목적을 위한 object 집합이며 또 그 사용법에 대한 프로토콜을 말한다. 호스트는 opencable 에서 규정한 기본적인 function set(resource) 을 반드시 가지고 있어야 하며 POD는 host 가 보유한 resource 의 종류를 미리 알고 필요에 따라 그사용을 요청한다. 각 resource 는 resource id 로 구분된다.
session layer 로 부터 받은 data 는 byte 단위의 array 이다. 이 array byte 데이터를 규격에서 제시한 resource object 의 데이터 구조로 바꿔서 application layer 로 보내는 역할이다.
이제 직접 소스를 보자.
/* ========================================================================= Required Function Decription ========================================================================= */ void resourceTask() { CABLE_Q *pPodMsg, podMsg; while(1) { pPodMsg = message_receive_timeout (pResourceQid, TIMEOUT_INFINITY); podMsg = *pPodMsg; message_release (pResourceQid, pPodMsg); switch(podMsg.tag) { case CI_SESSION_TAG: // 세션 계층으로 부터 올라올 때 #ifdef LAYER_DEBUG_CHECK ARENA_Print(("\n[DEBUG-PODLayer-ResourceLayer-resourceTask]Rcv Session Msg In Session \n")); #endif parse_APDU(&podMsg); free(podMsg.ptr); break; case CI_APPLICATION_TAG: // 애플리 케이션 계층에서 내려올 때 #ifdef LAYER_DEBUG_CHECK ARENA_Print(("\n[DEBUG-PODLayer-ResourceLayer-resourceTask]Rcv App Msg In Session Size %d\n",sizeof(podMsg.ptr))); #endif make_APDU(&podMsg); break; case CI_LAYER_CLOSE_TAG: // 종료 할 때 // printf("\n[POD_CI] RESOURCE TASK SUSPEND\n"); message_delete_queue (pResourceQid); task_exit (0); break; default: #ifdef ERR_CHECK { ARENA_Print(("[ERR-PODLayer-ResourceLayer-Task] Illegal Message Tag(RESOURCE) = %d\n",podMsg.tag)); } #endif break; } } }
다른 계층과 마찬가지로 독립된 하나의 태스크로 이루어져 있다. 또한 case 로 각각의 상황에 맞게 정해진 루틴을 수행하도록 했다.
우선 APDU 를 파싱하는 부분부터 보기로 하자.
리소스 부분은 다른 계층과는 비교도 안될 정도로 tag 가 많다. 그 만큼 기능이 많다고 생각하면 되겠다.
아무래도 하위에서 상위 부분으로 올라가면 올라갈수록 복잡해지는 건 당연한 일이다. 각각의 상황에 맞게 처리를 수행한 후에 알맞는 상단의 애플리케이션 계층으로 보낸다. 좀더 자세히 설명하자면, 상단의 애플리케이션에서의 태스크가 또하나 만들어 지면서 돌아가게 된다.
/* ========================================================================= Required Function Decription ========================================================================= */ message_queue_t *select_app(U16 ssnb) { // message_queue_t pTargetQid=0; //edit ty message_queue_t *qid;// = 0; //by ty switch(ssnb_rid[ssnb-1]) { case POD_RESOURCE_MANAGER: qid = pRmQid; break; case POD_APPLICATION_INFO: qid = pInfoQid; break; case POD_CONDITIONAL_ACCESS_SUPPORT: qid = pCaQid; break; case POD_HOST_CONTROL: qid = pHcQid; break; case POD_SYSTEM_TIME: qid = pTimeQid; break; case POD_EXTENDED_CHANNEL_SUPPORT: qid = pEcQid; break; case POD_MMI: qid = pMmiQid; break; /* case POD_LOW_SPEED_COMMUNICATION: qid =pLscQid; break; case POD_GENERIC_IPPV_SUPPORT: qid = pIppvQid; break; */ case POD_COPY_PROTECTION: qid = pCpQid; break; case POD_HOMING: qid = pHomingQid; break; case POD_GENERIC_FEATURE_CONTROL: qid = pGfQid; break; case POD_SPECIFIC_APPLICATION_SUPPORT: qid = pSasQid; break; case POD_GENERIC_DIAGNOSTIC: qid = pGenericDiagnosticQid; break; case POD_SYSTEM_CONTROL: qid = pScQid; break; default: #ifdef ERR_CHECK { ARENA_Print(("[ERROR-PODLayer-SessionLayer-select_app] Illegal session number pattern => [qid=%x] [ssnb=%x]\n",ssnb_rid[ssnb-1],ssnb)); } #endif break; } return(qid); }
이번에는 APDU 를 만드는 루틴을 보도록 하자!
void make_APDU(struct MESSAGE_Q* msgbuf) { struct PROFILE_OBJ *profile; struct APP_INFO_REQ_OBJ *app_info_req; struct SERVER_QUERY_OBJ *server_query; struct CA_PMT_INQ_OBJ *capmt; struct OOB_RXTX_TUNE_CNF_OBJ *oobtx; struct OOB_RXTX_TUNE_CNF_OBJ *oobrx; struct SYSTEM_TIME_CNF_OBJ *stime; struct INBAND_TUNE_CNF_OBJ *inbandtune; struct OPEN_MMI_CNF_OBJ *ommicnf; struct CLOSE_MMI_CNF_OBJ *cmmicnf; struct COMMS_REPLY_OBJ *comreply; struct COMESSAGE_OBJ *comessage; struct PROGRAM_REQ_OBJ *program; struct PURCHASE_REQ_OBJ *purchase; struct CANCEL_REQ_OBJ *cancel; struct HISTORY_REQ_OBJ *history; struct NEW_FLOW_REQ_OBJ *new_flow; struct DELETE_FLOW_REQ_OBJ *delete_flow; struct LOST_FLOW_CNF_OBJ *lost_flow; struct NEW_FLOW_CNF_OBJ *new_flow_cnf; struct DELETE_FLOW_CNF_OBJ *delete_flow_cnf; struct LOST_FLOW_IND_OBJ *lost_flow_ind; struct SET_DSG_MODE_OBJ *set_dsg_mode; struct DSG_PACKET_ERROR_OBJ *dsg_packet_error; struct CP_OPEN_CNF_OBJ *cp_open; struct CP_DATA_CNF_OBJ *cp_data; struct CP_SYNC_CNF_OBJ *cp_sync; struct FEATURE_LIST_OBJ *feature_list; struct FEATURE_PARAMETERS_OBJ *feature_parameter; struct FEATURE_PARAMETERS_CNF_OBJ *parameters_cnf; struct DIAGNOSTIC_CNF_OBJ *diagnostic_cnf; struct HOST_INFO_RESPONSE_OBJ *host_info_response; struct CODE_VERSION_TABLE_REPLY_OBJ *code_version_table_reply; struct HOST_DOWNLOAD_CONTROL_OBJ *host_download_control; struct SAS_CONNECT_RQST_OBJ *sas_connect_rqst; // struct SAS_DATA_RQST_OBJ *sas_data_rqst; struct SAS_DATA_AV_OBJ *sas_data_av; struct SAS_DATA_CNF_OBJ *sas_data_cnf; struct SAS_SERVER_QUERY_OBJ *sas_server_query; struct SAS_SERVER_REPLY_OBJ *sas_server_reply; U8 tcid; U16 ssnb; U32 tag; tcid = msgbuf->tcid; ssnb = msgbuf->ssnb; tag = msgbuf->pri; switch(tag) { //RESOURCE_MANAGER======================================================== case PROFILE_INQ: make_NODATA(tag, tcid, ssnb); break; case PROFILE_CHANGE: make_NODATA(tag, tcid, ssnb); break; case PROFILE_REPLY: profile = (struct PROFILE_OBJ*)msgbuf->ptr; make_PROFILE_REPLY(profile, tcid, ssnb); free(profile); break;
위에서 보면 알겠지만, 많은 struct 가 선언되어 있다. 모두 각각의 object tag 를 위한 것들이다. 결국은 아래의 세션 계층으로 내려 보낸다.