展锐ATRouter 业务逻辑梳理

最近搞udx710,用了ATRouter,对展锐的AT处理逻辑大概做了下梳理,还有ATRouter整体的框架和处理流程。

1.AT处理简要流程

我大概简单说明下,从AT工具(我用的sscom)通过USB AT口发AT到模组内部对应的端口,内部端口由ATRouter管理,ATRouter读取到AT请求,初步解析,根据解析的AT名调用不同的处理函数,由不同的函数处理并调用ATRouter的接口返回响应。如果各分支有相同的AT名,则匹配规则MINIAP的优先级最高,然后是command AT,后面的可以自己看GetATRequestTarget()这个函数。

2. ATRouter框架逻辑梳理

接下来看看ATRouter整体框架逻辑。ATRouter配置文件在/etc/atrouter/system.ini,我们改成了/data/system.ini(原因未知)。

2.1 system.ini配置文件内容

下面是双卡的配置,双卡最多支持六组通路

[Log]
Level=3

[RouterSettings]
SimNum=2
INDChnl=/dev/stty_lte20

[SIM0Settings]
InitNum=3
APChnl0=/dev/ttyGS2
APChnl1=/dev/ttyGS3
APChnl2=/dev/ttyAT0
CPChnl0=/dev/stty_lte4
CPChnl1=/dev/stty_lte5
CPChnl2=/dev/stty_lte6

[SIM1Settings]
InitNum=3
APChnl0=/dev/ttyGS5
APChnl1=/dev/ttyAT8
APChnl2=/dev/ttySE1
CPChnl0=/dev/stty_lte7
CPChnl1=/dev/stty_lte8
CPChnl2=/dev/stty_lte9

[Propertys]
debug=1
debug_key=1234
diag=1
diag_key=1234
virtualcn=0

下面是单卡的配置,双卡最多支持八组通路

[Log]
Level=3

[RouterSettings]
SimNum=1
INDChnl=/dev/stty_lte20

[SIM0Settings]
InitNum=6
APChnl0=/dev/ttyGS2
APChnl1=/dev/ttyGS3
APChnl2=/dev/ttyAT0
APChnl3=/dev/ttyGS5
APChnl4=/dev/ttyAT8
APChnl5=/dev/ttySE1
CPChnl0=/dev/stty_lte4
CPChnl1=/dev/stty_lte5
CPChnl2=/dev/stty_lte6
CPChnl3=/dev/stty_lte7
CPChnl4=/dev/stty_lte8
CPChnl5=/dev/stty_lte9

[SIM1Settings]
InitNum=0

[Propertys]
debug=1
debug_key=1234
diag=1
diag_key=1234
virtualcn=0

ATRouter主框架图

2.2 main

首先ATRouter main函数进来创建ATMain对象,调用成员方法BeginRun();

2.2.1 ATMain->BeginRun()

2.2.1.1 GetBaseConfig()

ATMain->BeginRun()中首先调用GetBaseConfig();主要用于获取log等级配置、sim通道个数、主动上报的设备节点路径;

2.2.1.2 CreateModules()

然后调用CreateModules();主要用于创建核心管理对象MiniAPService、DATAHandler、MuxHandler、RouterManger;
如果是单卡模式,还需要创建ModemManager对象。

2.2.1.3 GetRouterConfig()

然后调用GetRouterConfig();主要用于获取sim通道配置,单卡则获取sim0的配置,双卡则获取sim0和sim1的配置;

2.2.1.3.1GetSIMConfig()

在GetRouterConfig()中调用GetSIMConfig()函数,主要用于获取对应sim通路的AT通路个数,每条通路有对应的AP和CP节点,然后默认给通路速率置为115200;

2.2.1.4 执行StarkWrok

创建线程去执行MiniAPService、DATAHandler、MuxHandler对象的StartWork()函数;
如果是单卡模式,则执行ModemManager的StartWrok()函数;
然后执行RouterManger的StartWork()函数;
重点是这几个StartWork函数,下面重点讲一下这几个StartWork

3. 核心对象StartWork

我就按启动顺序讲吧:

3.1 MiniAPService

MiniAPService StartWork主要是用于注册自定义AT。
展锐原生方案是用户添加动态库,实现register_this_lib_ext()注册AT函数,放在/usr/lib/atlib/目录下,由MiniAPService的AT_modules_load()加载动态库中register_this_lib_ext()函数并调用注册。
我们目前没有用展锐原生的逻辑,是在StartWork函数中加了自己的注册AT函数RegCustomAt()。省去了加载动态库这一步骤。
初始化的ofono句柄,会在AT触发时传入注册AT回调函数。
Liot_ATInitApiClient()这个是我们自己加的,目的是做一些初始化,例如AMS客户端初始化之类的,如果有需要在ATRouter初始化功能配置的可以加在这。
MiniAPService逻辑
然后看看AT回调函数注册,展锐原生的注册AT结构体如下:

typedef struct at_linuxcmd_str {
    
    
   /* AT名 */
  char at_cmd[32];
  /* AT回调函数 data为初始化时的ofono句柄,传入的是对应simID的ofono句柄 */
  int (*cmd_hdlr)(ATRequest* atrequest, ATResponse* atresponse, void *data);
} at_linuxcmd_t;

因为展锐原生的这套逻辑没有对AT进行解析,所以在收到AT时还需要自己解码,我们自己的回调逻辑是先调用标准解析函数Liot_LATPreParser()预解析AT,将AT类型、参数等信息先解码出来,然后再调用最终对应的AT处理函数。解析完后的AT请求结构体如下:

typedef struct
{
    
    
    Liot_ATCommandType_E type;              /*!< 指令类型 */
    int argc;                               /*!< 参数个数 */
    char **argv;                            /*!< 所有参数 */
    void *data;                             /*!< ofnon句柄 */
    char *name;                             /*!< 指令名称 */
    int simId;                              /*!< SIM卡ID */
}Liot_AtRequest;

3.2 DATAHandler

DATAHandler StartWork主要是用于PPP服务,具体逻辑不太清楚。

3.3 MuxHandler

MuxHandler StartWork主要是接收处理MUX消息。
首先创建线程,线程中启动netlink服务,阻塞接收MUX请求并处理;具体业务不太清楚。

3.4 ModemManager

ModemManager StartWork主要是在单卡模式下接收处理modem状态变化事件,并提供发送CP AT接口。
首先调用Init_CPCmd_Router(),打开CP通路,创建线程读取AT响应,读到响应发送AT响应信号,调用sendCpcmd()函数发送AT后内部会阻塞等待响应信号;
调用CreatSocketConnect()创建socket连接moded;
调用GetBootMode()获取boot状态,这个不是很清楚具体作用。
调用CreateAcceptAndReadThread()函数创建线程阻塞读socket,主要是读取modem状态,modem状态改变时在这里会收到,存储状态到全局变量,发送modem状态改变信号;
调用CreateWaitAndListenThread()函数创建线程阻塞等待modem状态改变信号,当modem状态变为ALIVE时,调用InitModem()函数初始化modem配置,下发modem配置相关AT,需要开机配置的AT列表可以在这里添加。
ModemManager 逻辑

3.5 RouterManger

RouterManger StartWork属于核心业务,包括创建启动各个通路的ATRouter对象,主动上报逻辑处理,PPP、MUX业务处理等
首先调用GetInitInfo()获取主动上报通路和每个SIMID对应的通路个数,还有总的通路个数到RouterManager全局变量中。
然后调用IniCPChnlInfo()函数创建CP通路节点队列,并将/dev/stty_lte4~/dev/stty_lte10和/dev/stty_lte24入队,具体用法暂时没了解到。
然后调用CreateInitRouter()函数,根据simID创建对应simID下的通路个数个ATRouter对象,并加入到m_sim_router_info_tbl[simID]表中。
然后创建线程执行RouterHandler()函数,这个函数调用RouterHandler(),RouterHandler内部实现主要是调用StartRouter()和阻塞等待读取队列Router相关事件,包括以下几个事件

MESSAGE_TYPE_MESSAGE_ADD             	/* 新增ATRouter对象 */
MESSAGE_TYPE_MESSAGE_REMOVE  			/* 删除ATRouter对象 */
MESSAGE_TYPE_MESSAGE_RECOVERFROMMUX  	/* MUX相关 */
MESSAGE_TYPE_EVENT_PPPTRANSPORT			/* PPP相关 */

3.5.1 StartRouter()

因为StartRouter(),内部调用过多,单独讲一下
这个函数主要功能有四项,三项为展锐原生功能,一项是我们自己添加的,分别是:
1.根据simID启动各ATRouter的BeginRun()函数;
2.根据单双卡不同调用不同的主动上报处理逻辑StartWork(),单卡调用ATIndicationRouter的StartWork(),双卡调用LibatIndication()的StartWork();
3.调用ConnmanIndication的StartWork(),用于接收command进程的主动上报;
4.上报+LIND: AP READY到AT口,标识AT已经就绪,这个是我们自己加的;
StartRouter逻辑

3.5.1.1 ATRouter->BeginRun()

ATRouter->BeginRun(),主要是运行ATRouter对象,使其内部逻辑运行
首先创建线程执行ThreadForStartRun()函数;
ThreadForStartRun()中分别调用InitializeRouter、ATSession->StartLoop()、CPTransChan->StartWork()、PPPTransport->StartWork()、UartChannel->StartWork();
调用InitializeRouter()函数给CP、UART节点(UART节点对应配置文件中APChnl节点)和串口速率赋值。
调用ATSession->StartLoop()创建线程阻塞读取m_session_queue_队列,根据AT名把AT分为七类,分别是发给MINIAP、CMUX、格式类AT、控制类AT、CommanD AT、AP和CP同时处理AT、CP直接处理AT,处理完AT将响应写入m_uart_queue_队列;
调用CPTransChan->StartWork()初始化CP端口;
调用PPPTransport->StartWork()打开PPP通路,创建线程,线程中阻塞接收处理数据。具体业务不清楚;
调用UartChannel->StartWork()打开ATRouter对象的AP端口,并创建读写线程,读线程读AT口请求数据,写入到m_session_queue_队列中,写线程读m_uart_queue_队列节点,读到的数据写回AP通道;
ATRouterBeginRun逻辑

3.5.1.2 ATIndicationRouter->StartWork()

ATIndicationRouter->StartWork(),主要是在单卡模式下接收处理主动上报
调用OpenCPIndicationChannel()打开CP上报端口;
调用WakeoutMsgQInit()初始化消息队列(具体功能未知,猜测是报给ril);
然后创建线程执行ReadThreadFunc()函数,ReadThreadFunc()中阻塞读取CP上报端口,读到数据调用IndicationSplitBroadcast()广播到AT口;
读取到数据如果是+CRING或者+CMT 调用msgsndf发给对端;
单卡主动上报处理逻辑

3.5.1.3 LibatIndication->StartWork()

LibatIndication->StartWork(),主要是在双卡模式下接收处理主动上报
调用WakeoutMsgQInit()初始化消息队列;
注册回调函数为rsp_cmd();
收到主动上报调用HandleIndication(),判断如果是+CRING或者+CMT 调用msgsndf发给对端;调用Liot_ATUrcDeal()过滤上报(此处非展锐原生逻辑,原生逻辑不过滤),然后调用BroadcastIndication()广播到AT口,
双卡主动上报逻辑

3.5.1.4 ConnmanIndication->StartWork()

ConnmanIndication->StartWork(),主要是接收处理command过来的主动上报
调用client_init()函数连接command,并注册回调函数rsp_connman();
主动上报会触发rsp_connman(),在rsp_connman()中调用RouterManager->BroadcastIndication()广播主动上报;
command主动上报处理逻辑

猜你喜欢

转载自blog.csdn.net/qq_38721267/article/details/127936883