SIM Toolkit驱动开发
目的:最近刚刚接触RIL,RIL在Windows Mobile的驱动中还是比较复杂的,由于微软有关Phone的Feature全部在RIL中实现,就可以想象其复杂的程度了。网上去找关于如何做RIL的资料是非常的少,而且RIL这种东西又不是很难,难的东西模块已经帮我做好了,我们做的只需要把与上层的接口了解清楚,就行了。既然没有技术难度,何必每个做RIL的人,都需要从头开始熟悉呢,站着巨人的肩膀上就可以了,当然我不是巨人。我愿意当个挖井人,一人挖井,全村受益。
SIM ToolKit架构:要弄清楚SIM Toolkit, 就是了解其与上层的接口。如何把上层的函数请求包装成AT命令,往串口发送。串口来的数据,解析成上层所要的数据结构。上层通过RIL Toolkit 函数进行函数调用,实现请求。SIM Toolkit接口函数如下:
l RIL_GetSimToolkitProfile//获取STK的简要信息
l RIL_SetSimToolkitProfile//设置STK的简要信息
l RIL_SendSimToolkitCmdResponse//发送一个STK命令的响应
l RIL_SendSimToolkitEnvelopeCmd//发送一个envelope命令
l RIL_TerminateSimToolkitSession//终止STK会议
其中主要的最重要的一个函数是RIL_SendSimToolkitCmdResponse,其他几个在Simtkit中不会调用到。当底层有命令上来,需要上层做反应时,通过RIL_SendSimToolkitCmdResponse给予反馈。
代码分析:以模拟器的RILGSM分析, SIM Toolkit应用的架构如下图
RILGSM: GSM RIL驱动
SIMTkit: STK的功能函数及UI显示。
Tkitapp: 管理STK,STK的图标及程序的名字。
其中tkitapp和simtkit这两部分我们都不需要修改任何代码,只要修改rilgsm.dll代码,根据当前的模块跟上层完成接口就可以了。
其调用顺序如下:
解析SIM Toolkit的函数是ParseSIMToolkitCmdOrRsp,该函数在Response.cpp中。当收到串口STK通知时,我们调用这个函数去解析。在GSM中是“*STKN:”。ParseSIMToolkitCmdOrRsp函数的流程如下
ParseSIMToolkitCmdOrRsp 流程图
上图的流程中,调用ParseCommand来进行解析。ParseCommand流程图如下:
ParseCommand流程图
在ParseTextFormatCommand函数中是我们正在要去执行解析的函数,一般情况下,命令传过来的时候。如“*STKN:4,4524542100”,在“*STKN:”后面会带有一个数值,这个数值就是标志通知是什么类型的通知,看下ParseTextFormatCommand函数中的代码,先用ParseHexDWord去解析NotifyCode。
// First thing should be the Command ID.
if (!ParseHexDWord((LPCSTR)m_lpbParse, SIMTKIT_TEXTPARSE_PARSE_LEADINGZERO, dwNotifyCode, (LPCSTR&)m_lpbParse))
{
*pdwRetVal = SIM_RESPONSE_ERR_COMMANDNUMBER;
hr = E_FAIL;
goto Exit;
}
解析出NotifyCode之后,再进入相应的解析子函数。
switch(dwNotifyCode)
{
case SIM_NOTIFY_SETUPMENU:
case SIM_NOTIFY_SELECTITEM:
hr = ParseSetupMenu(dwNotifyCode, pbFifthByte);
break;
case SIM_NOTIFY_PLAYTONE:
hr = ParsePlayTone();
break;
case SIM_NOTIFY_DISPLAYTEXT:
hr = ParseDisplayText(pbFifthByte);
break;
case SIM_NOTIFY_GETINKEY:
hr = ParseGetInKey(pbFifthByte);
break;
case SIM_NOTIFY_GETINPUT:
hr = ParseGetInput(pbFifthByte);
break;
case SIM_NOTIFY_SETUPIDLEMODETEXT:
hr = ParseSetupIdleModeText();
break;
case SIM_NOTIFY_SENDSMS:
case SIM_NOTIFY_SENDSS:
case SIM_NOTIFY_SENDUSSD:
case SIM_NOTIFY_SETUPCALL:
case SIM_NOTIFY_SENDDTMF:
case SIM_NOTIFY_OPENCHANNEL:
case SIM_NOTIFY_CLOSECHANNEL:
case SIM_NOTIFY_RUNATCOMMAND:
hr = ParseUnsolicitedData();
break;
case SIM_NOTIFY_REFRESH:
hr = ParseRefresh(pbFifthByte);
break;
case SIM_NOTIFY_EVENTLIST:
hr = ParseEventList();
break;
case SIM_NOTIFY_LAUNCHBROWSER:
hr = ParseLaunchBrowser(pbFifthByte);
break;
case SIM_NOTIFY_RECEIVEDATA:
hr = ParseReceiveData();
break;
case SIM_NOTIFY_SENDDATA:
hr = ParseSendData();
break;
case SIM_NOTIFY_LANGUAGENOTIFICATION:
hr = ParseLanguageNotification();
break;
case SIM_NOTIFY_CALLSETUP:
case SIM_NOTIFY_MORETIME:
case SIM_NOTIFY_POLLINTERVAL:
case SIM_NOTIFY_POLLINGOFF:
case SIM_NOTIFY_LOCALINFO:
default:
// We don't understand this command
DEBUGMSG(ZONE_ERROR, (TEXT("RilDrv : SIMTKit: Don't understand command %x/r/n"), dwNotifyCode));
*pdwRetVal = SIM_RESPONSE_ERR_COMMANDTYPE;
hr = E_FAIL;
goto Exit;
}
每个解析函数主要的工作就是把字符串解析并赋值给CRilSimToolkitCommand的成员变量。CRilSimToolkitCommand有很多成员变量,我们该如何进行赋值呢。我们看到在ParseCommand的流程图中,在完成解析后,有一系列的BUILD打头的函数。这些函数,就是把数据打包成SIMTKIT要的数据,如SIMTEXT、SIMSMS、SIMCALL等等。下面举几个例子说明下
BuildSIMTEXT:
在BuildSIMTEXT中,就是把ParseDisplayText解析出来的数据,组装成SIMTEXT的结构,下面的伪代码可以看出。
SIMTEXT *pst = NULL;
pst->dwMinResponse = m_dwMinResponse;
pst->dwMaxResponse = m_dwMaxResponse;
pst->dwFlags = || bFifthByte;
pst + pst->dwTextOffset = m_pwszText;
pst->dwTextSize = m_dwTextLen;
pst + pst->dwDefaultTextOffset = m_pwszDefaultText;
pst->dwDefaultTextSize = m_dwDefaultTextLen;
pst->dwIconIdentifier = m_dwIconIdentifier;
pst->dwIconQualifier = m_dwIconQualifier;
我们从解析函数中看到pbFifthByte这个变量,传入了很多函数,他根据的NotifyCode,他的意义都不一样,这都需要看其对应的BUILD函数对于pbFifthByte是怎么用的。对于其他解析函数都一样,你都需要认认真真的把相应的BUILD函数看了之后,那个变量是对应AT命令通知的哪个字段。完成这件事之后,解析就非常简单了,就是一个解析,赋值的过程了。
完成了命令解析,也组装好数据结构,就往SIMtkit.dll通知了,在得到通知后,simtkit中会根据通知的类型,调用相应的功能,并显示相应的UI。并会通过RIL_SendSimToolkitCmdResponse对通知进行反馈。在RILDrv_SendSimToolkitCmdResponse中调用CRilSimToolkitResponse::CreateResponse,创建AT命令。这个过程就比较简单了,就不做说明了。