WinCE开发笔记 之 RIL
所有的AT指令都是异步的,CommandThread负责串行的下命令,
ResponseThread负责统一处理读上来的串口数据,包括回应和事件。
->rilmain.cpp的RIL_IOControl()
->msg.cpp的RIL_DeleteMsg()
构造CNotificationData(pnd),设置Blob(Code,Index)
->atcmd.cpp的QueueCmd(,szCmd,,,,pnd,)
->atcmd.cpp的QueueCmdWithTimeout()
构造CCommand(pCmd),传入szCmd和pnd
把pCmd放入CRilInstanceHandle的m_pCmdList中
把pCmd放入g_pCmdQ队列中,唤醒CommandThread
->atcmd.cpp的CRilHandle::CommandThread()
->comhand.cpp的CComHandle::SendRILCmdHandleRsp()
->rilhand.h的CRilHandle::StartWaitingForRsp()
设置m_fWaitingForRsp=1 和 m_pCurrCommand=pCmd
->comhand.cpp的CComHandle::WriteCmdsToComPort()
写串口
读取g_pRspQ队列的回应信息(pRsp),由ResponseThread写入
->rilhand.h的CRilHandle::StopWaitingForRsp()
设置m_fWaitingForRsp=0
->rilhand.cpp的CRilHandle::HandleRsp(rpCmd,pRsp)
->response.cpp的CResponse::ParseOKData()
假如当初注册了ParseFunc()则释放原来的Blob,回调具体的处理函数
取出最初的pnd
->rilhand.cpp的CRilHandle::BroadcastNotification(pnd)
取出Blob
->command.cpp的CCommand::SendResponse(Code,Blob)
假如当初没有设置CMDOPT_IGNORERSP的命令选项
->CRilInstanceHandle::Notify(Code,ID,Blob)
->把pCmd从CRilInstanceHandle的m_pCmdList中移除
->atcmd.cpp的CRilHandle::ResponseThread()
->atcmd.cpp的CRilHandle::HandleRxData()
->AppendReadBytes()把串口数据放入缓冲区
->GiveUpReadBytes()获得全部的新老串口数据
构造CResponse
->response.cpp的CResponse::AppendString()
->response.cpp的CResponse::Parse()
->事件->response.cpp的CResponse::ParseNotification()
->结果->response.cpp的CResponse::ParseOKOrError()
回应不完整则szRemainder和cbRemainder=0,否则等于下一个回应和长度
假如pRsp->FUnsolicited==0,也就是Unsolicited Result Code(非请求结果码)
假如FWaitingForRsp==1,调用atcmd.cpp的QueueRsp()唤醒CommandThread
假如是URC,pRsp->GetBlob()然后BroadcastRealBlobNotification()
剩下的串口数据调用AppendReadBytes(),重新开始一轮处理
最简单的AT指令,也就是只返回"OK",上面的处理过程很简单。
CRilHandle有内部缓冲区用来存放新老串口数据(例如上次没读完整),,
所以一进HandleRxData()就先AppendReadBytes()然后GiveUpReadBytes()
每个pRsp也有内部缓冲区,存放完整的回应数据。
对于有具体返回值的AT指令,例如AT+CSQ,
在misc.cpp的RILDrv_GetSignalQuality()调用QueueCmd()时,
注册ParseGetSignalQuality()作为而外的处理函数,
在CommandThread的HandleRsp()的ParseOKData()中被调用。
ParseGetSignalQuality()会分析回应数据,来构造新的Blob,
然后通过Blob通知调用者结果。
RIL应用程序一开始调用RIL_Initialize()会注册2个回调函数
pfnResult和pfnNotify,前者接收命令结果,后者接收事件(例如RING)。
有的AT指令会构造pnd传给QueueCmd,例如RILDrv_DeleteMsg(),
有的没有pnd,例如RILDrv_GetSignalQuality()。
前者在CommandThread的HandleRsp()结尾BroadcastNotification(pnd)。
"ATD"(呼出)有点麻烦,对方接起后才返回"OK",在此之前可能主叫方挂断,
也就是"ATD"在有回应之前下"ATH"指令。
因此comhand.cpp的CComHandle::SendRILCmdHandleRsp中对"ATD"和"ATA"有特殊处理,
启动专门的线程HangupThreadProc处理"ATH"。
->HangupThreadProc()
情况1:"ATD"/"ATA"指令还没下给串口
从g_pCmdQ中移走pCmd
pCmd->SendResponse(RIL_RESULT_NOCARRIER,NULL,0);
情况2:已经下给了串口
假如g_pCmdQ的下个命令是"ATH",因为g_pCmdQ是CPriorityQueue,"ATH"会排在最前
m_fCancelledDial=1
写"AT"到串口
对于上述情况2
comhand.cpp的CComHandle::SendRILCmdHandleRsp()
在获得pRsp("AT"的返回值"OK")后,判断m_fCancelledDial==1
调用pRsp->SetCallAborted()把"OK"的RESULT换成"NOCARRIER",此后按原流程处理。
"ATH"的指令未被丢弃,随后会再次发出,来防止对方"ATA"发生在"ATD"被取消的同时。
假如有模块的"ATD"直接返回"OK",那就不需要线程HangupThreadProc,
把RILDrv_Dial()的pnd去掉,不然收到"OK"就会BroadcastNotification(RIL_NOTIFY_CONNECT)。
另外response.cpp的CResponse::ParseNotification()可能也得加点东西。