ril核心代码简单介绍

转载请注明: www.max123.study-bbs.com

【代码核心结构】

    最通常想到的思路是,发送一个at命令,然后接收串口返回的响应数据,进而对数据进行解析,这个模型的优点是够简单,不少单片机程序会这样设计。缺点是整个过程是阻塞的,即一次只能处理一个命令,下一个命令必须等待上一个命令处理完毕。

阻塞行为特性在多任务系统中不被接受,因为会使得其他任务都进入无必要的阻塞,为了解决这个缺点,很容易想到应该设计一个队列Queue,这样客户端程序只需要把命令按先后顺序压入队列之中即可,异步等待回调或通知。这种模型下,有一个发送线程监控着队列,将队列的命令逐个发送给串口;另一个接收线程负责接收串口数据,这样一个异步模型就初步建立了。

 

A.发送一条命令】

如前所述,发送命令给串口,转换成发送到队列。

QueueCmdWithTimeOut(pCmd)

{

    // 将命令pCmd压入g_pCmdQ队列,如果队列满,则等待。

    g_pCmdQ->Put(pCmd, INFINITE);

}

 

B.发送线程】

CommandThread()

{

    // 从队列g_pCmdQ中按顺序取一条命令pCmd,如果没有命令则等待。

    g_pCmdQ->Get(pCmd, INFINITE);  

 

    // 将命令发送到串口,并处理响应

    SendRILCmdHandleRsp(pCmd);

}

这样,当有多命令时候,命令送到队列即可,除非队列满了,否则发送命令的客户端不会阻塞,阻塞的仅仅是发送线程。

 

C.接收线程】

ResponseThread()

{

    // 从串口读数据到缓存szData.

    Read(szData);

    // 处理接收到的数据

    HandleRxData(szData);

}

 

【接收线程对数据的处理】

1.接收线程在处理时候要注意串行数据接收的特性,有时候响应并没有完整的接受到,而是接收一半。所以HandleRxData面对无法解析的返回数据时候不能直接抛弃数据,而是继续接收数据append到之前的数据,待下一次来解析。

2.在我们描述的模型中,控制Modem的流程是发一个命令,得一个响应,但是还有很多例外。Modem也会主动发送一些非预期的响应,比如来电通知响应。因此接收线程也要担负部分解析的工作,这在在面HandleRxData伪代码中的AppendString实现。

 

HandleRxData(szData)

{

    // 将接收到的数据append到一个全局缓冲AA中可能有上一次剩下的数据

    AppendReadBytes(szData);

   

    // GiveUpReadBytesA中的数据取出到szAppend,长度是cbAppend

    while(GievUpReadBytes(szAppend, cbAppend)) {

 

       // 如果A没有数据,代表处理完毕,退出循环

       if (!cbAppend )   break;

 

       // 处理szAppend里面的数据,剩下些无法处理数据szRemainder

       pRsp->AppendString(szAppend, szRemainder);

 

       // szRemainder=0 代表已经无法解析 把剩下数据退回到A 退出循环

       if (!szRemainder) {

           InheritReadBytes(); // 剩下数据退回A

break;

} else {

    // 对当前一条响应的解析已经完毕

    // 根据响应的属性,Unsolicited? Unreconized? Notify?

    // 做处理,将响应压入g_pRspQ队列中。

    if (need) g_pRspQ->Put(pRsp);

    AppendReadBytes(szRemainder); // 剩下数据退回A

}

}

}

Unreconfized就是无法识别的响应,Unsolicited是非预期的响应。

 

【发送线程等待响应】

    在发送线程中使用SendRILHandleRsp来发送at命令到串口,如同函数名,这个函数还负责处理本命令的response。问题来了,这个response从何获得? 接收线程在处理response完毕后会把它压入另外一个全局队列中g_pRspQ.

SendRILHandleRsp()

{

    WriteCmdsToComPort(szCmd);

    g_pRspQ->Get(pRsp, dwTimeout);

    HandleRsp(pRsp);

}

    队列的PutGet是同步的,因此看出,在发送和接收线程存在同步机制。

 

    下面是稍微详细一点的代码

 

CRilHandle::StartInit()

{

    m_pInstances = new CDblList<CRilInstanceHandle>;

    m_pComDevice = COM_OpenInternal();

    m_pComDevice->InitComPortForRIL(NULL, NULL); // 串口的设置

    LaunchThreads();         // 启动发送和接收线程

    SendComInitString(0);    // 发送一串初始命令

   

}

 

CRilHandle::LaunchThreads()

{

    g_pCmdQ = new CPriorityQueue<CCommand, 40>;

    g_pRspQ = new CQueue<CResponse, 10>;

    g_pSimLockedQueue = new CQueue<CCommand, 10>;

 

    CreateThread(CmdThreadProc);

    CreateThread(ReadThreadProc);

    m_pCRilNdis->NdisStart(m_hCancelEvent);

}

 

 DWORD CRilHandle::CommandThread()

{

    While(1) {

    WaitForCommandOrCancel(); // 等待命令

    g_pCmdQ->Get(pCmd, INFINITE); // 得到下一个命令

    m_pComDevice->SendRILCmdHandleRsp();

    if (m_pComDevice->FDataMode()) // 如果在数据传输模式

       // 退出数数据传输模式

   

}

}

 

DWORD CRilHandle::ResponseThread()

{

    While(1) {

       WaitCommEvent(&dwMask); // 等待串口事件.

       // 这里会使用PDD的全局参数dwDefaultCOMMask来决定等待哪些串口事件

       if dwMask & EV_RXCHAR    // 串口接收通知

           ReadFile(szData, dwRead);   // 读取串口数据

       HandleRxData(szData, dwRead, false);   // 处理接收到的数据

}

}

你可能感兴趣的:(ril核心代码简单介绍)