Mstar方案CEC启动流程
- 开机启动:
在android系统启动起来会调用MSrv_Control_common.cpp(该类继承与msrv,子类有MSrv_Control)中的PostVideoInit()函数(暂不跟踪系统从哪里调用该方法)
Z:\msd358_AN8.0\vendor\mstar\supernova\projects\msrv\control\src\MSrv_Control_common.cpp
BOOL MSrv_Control_common::PostVideoInit()
{
#if (CEC_ENABLE == 1)
CECStart();
#endif
return TRUE;
}
调用了CECStart()函数:
MSrv_CEC * MSrv_Control_common::GetMSrvCEC(void)
{
MSRV_CONTROL_COMMON_INFO("%s line %d\n", __PRETTY_FUNCTION__, __LINE__);
MSrv_CEC *p = dynamic_cast<MSrv_CEC *>(m_pMSrvList[E_MSRV_CEC]);//获取对象指针
ASSERT(p);
return p;
}
void MSrv_Control_common::CECStart(void)
{
pthread_attr_t attr2;
pthread_attr_init(&attr2);
pthread_attr_setdetachstate(&attr2, PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&attr2, PTHREAD_STACK_SIZE);
m_stCecThreadInfo.pclass = GetMSrvCEC();
if(m_stCecThreadInfo.bActive == FALSE) //该结构体中存下MSrv_CEC的类和一个CEC线程是否启动的类
{
if(PTH_RET_CHK(pthread_create(&m_CECThread, &attr2, GetMSrvCEC()->CECMonitor, &m_stCecThreadInfo)) != 0) //创建并启动线程,调用CECMonitor函数
{
ASSERT(0);
}
}
}
现在我们来看一下主要实现代码的MSrv_CEC.cpp,只列出主要代码,并进行注释梳理:
Z:\msd358_AN8.0\vendor\mstar\supernova\projects\msrv\common\src\MSrv_CEC.cpp
void * MSrv_CEC::CECMonitor(void *arg)
{
ST_THREAD_ARG_INFO *ptr = (ST_THREAD_ARG_INFO *)arg; //pthread_create的参数
MSrv_CEC *c_ptr = (MSrv_CEC*)ptr->pclass; //从参数中获取到对象
prctl(PR_SET_NAME, (unsigned long)"CECMonitor");//把当前线程命名为CECMonitor
c_ptr->m_pCec = mapi_interface::Get_mapi_cec();
if(c_ptr->m_pCec == NULL)
{
MSRV_CEC_ERROR("[CEC] mapi_interface::Get_mapi_cec() is NULL!\n");
}
else
{
pthread_cond_signal(&(c_ptr->m_CECCond)); //利用条件变量来唤醒阻塞线程
}
c_ptr->m_pCec->SetARC(FALSE);
MS_CEC_SETTING CEC_Setting;
memset(&CEC_Setting, 0, sizeof(CEC_Setting)); //清零
c_ptr->GetCECConfiguration(&CEC_Setting);//从数据库中获取CEC的状态
if( CEC_Setting.u8CECStatus == FALSE )
{
pthread_exit(NULL); //获取到CEC的状态为false,线程退出,函数结束
}
ptr->bActive = TRUE; //记录CEC的状态
c_ptr->m_CECInfoExtend.fCecProtocolFirstInit=FALSE;
c_ptr->CECInit();//初始化CEC相关数据
while(ptr->bActive)
{
usleep(CEC_HANDLER_POLLING_TIME);
MSrv_Control::GetMSrvCEC()->CECHandler();
}
mapi_interface::Get_mapi_cec()->CEC_Exit();
c_ptr->Finalize();
pthread_exit(NULL);
}
上述代码逻辑清晰:要注意的是,如果从数据库中获取的到CEC的状态为false,那么就会执行线程退出、函数结束。导致CEC初始化不能完整进行。那么再次使用CEC的话就会出问题。
上层app,主要调用MSrv_CEC中的SetCECConfiguration(MS_CEC_SETTING * CECSetting)来控制CEC、ARC,CECSetting参数中记录了详细的状态数据。
void MSrv_CEC::SetCECConfiguration(MS_CEC_SETTING * CECSetting)
{
if(m_pCec == NULL)
{
pthread_cond_wait(&m_CECCond, &m_CECMutex); //使用条件变量阻塞线程m_CECMutex,在CECMonitor有唤醒操作。
}
m_CECDatabase->SetCECSetting(CECSetting);//存到数据库中
if((m_CECSetting.bCECLink == FALSE)&&(CECSetting->u8CECStatus == TRUE))
{ printf("CEC_Setting.u8CECStatus2 =%d\n",CECSetting->u8CECStatus);
///CEC turn on
if((m_pCec->CEC_GetMsgCnt()) != 0 )
{
m_pCec->CEC_SetFifoIdx((m_pCec->CEC_GetFifoIdx() + m_pCec->CEC_GetMsgCnt())%(m_pCec->Get_CEC_FIFO_CNT()));
m_pCec->CEC_SetMsgCnt(0);
}
MSrv_Control::GetInstance()->CECStart(); //调用MSrv_Control_common.cpp中的CECStart()函数,就和上面逻辑一样,执行CECMonitor()方法,进行CEC初始化,注意这时候CEC的状态是true,所以不会执行线程退出动作!
}
else if(CECSetting->u8CECStatus == FALSE)
{
///CEC turn off
MSrv_Control::GetInstance()->CECStop();
}
if(OldARCStatus != NewARCStatus)
{
PostEvent(0, EV_AUDIO_MUTE, 0, 0);// report ui to unmute msg上传到上层
}
}
之后会执行m_CECMutex线程所指向的函数。