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 를 위한 것들이다. 결국은 아래의 세션 계층으로 내려 보낸다.