一,基本流程
ATCoP(AT Command Processor)是高通平台上对于AT命令处理的模块。基本上它遵循以下过程:
串口(sio)接收到串口发送过来的字符串--> AT Command Parser --> 产生一个重要的Token结构,它包含了命令名称,接收到的参数,以及response的buffer--> 之后AT Command ProcessorProcess 通过Token里面的信息查调用相应的AT 命令处理函数 -->处理完成后产生相应的response给TE。
二,具体代码实现
例子1 . 我们在USB MODEM上需要实现一个对PIN码校验的功能,即UIM的PIN功能开启以后,需要在PC端提示用户输入PIN码,但连续输入3次错误后需输入PUK解锁。
我们不需要修改高通默认的处理流程,只要在command table中添加相应的命令、处理函数:
{ "+CPIN", READ_ONLY|RESTRICTED,
SPECIAL_NONE, 0, NULL, NULL,
dsat707_exec_CPIN_cmd, NULL },
其中+CPIN就是我们定义的一个AT命令,dsat707_exec_CPIN_cmd就是对应的处理函数。
我们设想的+CPIN功能是:
A. 查询命令: AT+CPIN?
返回: READY 表示UIM没有
UIM PIN 表示UIM开启了PIN码功能,用户插入USB MODEM后需要输PIN码
UIM PUK 表示连续3次输入错误PIN,需要输入PUK解锁
VERIFIED 表示PIN码输入正确
UNBLOCKED 表示PUK输入正确,解锁成功
BLOCKED 如果是返回这个,很不幸的告诉你,你的卡GAME OVER!
B. 设置命令: AT+CPIN=1234 用户输入PIN码验证
AT+CPIN=12345678,1234 用户输入PUK以及新PIN码来解锁
OK,知道了具体的需求,就可以在处理函数dsat707_exec_CPIN_cmd中实现了:
首先判读接收到的+CPIN是什么格式的,是查询命令,设置命令,还是其他。我们可以通过Token结构中的tok_ptr->op参数来判断,如果tok_ptr->op == (NA|QU)表示查询命令;tok_ptr->op == (NA|EQ|AR)表示设置命令。
在查询命令中,我们只要通过获得UIM卡的PIN状态,把相应的状态以字符串的形式告诉PC端就可以了。当然可以在这里调用GSDI 的接口来查询PIN状态,但是在dsatme_init_me中已经向GSDI注册了一个回调函数:gsdi_pin_event_cb_func。 一旦GSDI检测到PIN码状态发生改变时,就会调用这个回调函数。所以我们可以定义一个全局变量,在回调函数中设置这个全局变量,之后在dsat707_exec_CPIN_cmd中判断这个全局变量,发送相应字符串。
在设置命令中,我们要限制用户只能在UIM PIN和UIM PUK 这两种状态才允许执行。在这里遇到了一个很大的难题,就是我们可以容易的通过GSDI的接口来解PIN和解PUK,但是要如何告知其他的service以及UI我们已经解锁了呢?? 可以采用一种“笨”办法,就是不通过直接调用GSDI接口来解PIN,而是模拟出一连串的按键,发送给UI解锁。比如接收到AT+CPIN=1234后,我们可以连续发送1,2,3,4,SEL一共5个KEY EVENT给UI,这样就如同用户在手机上按键解锁了。
例子2,来电---ATCoP中对同步事件的处理
同步事件的处理,我的理解就是ATCoP在其他task注册了一个同步事件的回调函数,一旦同步事件发生时,其他task就会调用这个回调函数来通知ATCoP调用相应的同步事件处理函数。一个典型的例子就是来电过程的处理:
1. dsatcmif_init_cmif -> cmif_register_cb_func---向CM task注册来电,或者对方应答回调
/* Register the CM call event callback function */
cm_status = cm_mm_client_call_reg (
dsatcm_client_id,
cmif_call_event_cb_func,
CM_CLIENT_EVENT_REG,
CM_CALL_EVENT_INCOM,
CM_CALL_EVENT_CONNECT,
NULL
);
2. 一旦有来电消息,cmif_call_event_cb_func构造事件的命令放入cmd buffer
cmd_buf->hdr.cmd_id = DS_AT_CM_CALL_INFO_CMD;
cmd_buf->cmd.call_event.event_info = *event_ptr;
cmd_buf->cmd.call_event.event = event;
ds_put_cmd(cmd_buf);---->调用(void)rex_set_sigs( &ds_tcb, DS_CMD_Q_SIG );通知ds_task来处理
3. 在 ds_task 中调用 dsi_process_cmds()处理命令
4. 调用dsat_process_async_cmd( cmd_ptr );
(1). 查找表async_event_table event_handler_func_ptr = async_event_table[i].event_handler[operating_mode];
(2). 调用相应的处理函数result_code = event_handler_func_ptr( dsatcmdp_at_state, cmd_ptr );
(3). 这里调用dsatcmif_cm_call_event_handler
(4). 调用来电处理函数 ,在这个函数里面会主动发送"Ring"字符串来通知PC端由来电了。
result = dsatvoice_call_event_incom(&cmd_ptr->cmd.call_event.event_info);