1# 电话服务开发指导<a name="ZH-CN_TOPIC_0000001167051994"></a> 2 3 4## Modem厂商库初始化开发指导<a name="section211mcpsimp"></a> 5 6### 场景介绍<a name="section213mcpsimp"></a> 7 8Modem厂商库初始化是指在厂商库里实现const HRilOps \*RilInitOps\(const struct HRilReport \*reportOps\)函数,在该函数里处理三个重要的功能: 9 10- 接收RIL Adapter事件回调的函数指针,当Modem有业务事件上报时,调用对应的函数指针,把事件上报给RIL Adapter。 11- 创建读取Modem设备节点的线程,在该线程里会循环地读取Modem上报的事件,并把接收的Modem信息解析为具体业务相关的事件进行上报。 12- 返回业务请求接口的函数指针给RIL Adapter。 13 14### 接口说明<a name="section811343241215"></a> 15 16Modem厂商库初始化接口。 17 18**表 1** Modem厂商库初始化接口功能介绍 19 20<a name="table223mcpsimp"></a> 21<table><thead align="left"><tr id="row229mcpsimp"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p231mcpsimp"><a name="p231mcpsimp"></a><a name="p231mcpsimp"></a>接口名</p> 22</th> 23<th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p233mcpsimp"><a name="p233mcpsimp"></a><a name="p233mcpsimp"></a>描述</p> 24</th> 25</tr> 26</thead> 27<tbody><tr id="row235mcpsimp"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p237mcpsimp"><a name="p237mcpsimp"></a><a name="p237mcpsimp"></a>const HRilOps *RilInitOps(const struct HRilReport * reportOps)</p> 28</td> 29<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p239mcpsimp"><a name="p239mcpsimp"></a><a name="p239mcpsimp"></a>接口功能:Modem厂商库运行的入口。</p> 30<p id="p240mcpsimp"><a name="p240mcpsimp"></a><a name="p240mcpsimp"></a>参数reportOps:RIL Adapter传入的事件回调函数指针。</p> 31<p id="p241mcpsimp"><a name="p241mcpsimp"></a><a name="p241mcpsimp"></a>返回值:业务请求接口的函数指针。</p> 32</td> 33</tr> 34</tbody> 35</table> 36 37### 开发步骤<a name="section51031144122"></a> 38 391. RilInitOps接口中设置RIL Adapter传入的事件回调函数指针。 40 41 ``` 42 // 定义Modem厂商库回调函数指针 43 static struct HRilReport g_reportOps = { 44 OnCallReport, // 通话相关业务回调函数 45 OnDataReport, // 蜂窝数据相关业务回调函数 46 OnModemReport, // Modem相关业务回调函数 47 OnNetworkReport, // 搜网相关业务回调函数 48 OnSimReport, // SIM卡相关业务回调函数 49 OnSmsReport // 短信相关业务回调函数 50 }; 51 ``` 52 53 541. 创建主线程g\_reader,开启消息循环。 55 56 ``` 57 pthread_attr_t t; 58 pthread_attr_init(&t); 59 pthread_attr_setdetachstate(&t, PTHREAD_CREATE_DETACHED); 60 ret = pthread_create(&g_reader, &t, ReaderLoop, &t); // 创建线程 61 ``` 62 63 641. 在g\_eventListeners线程用open\(\)打开Modem设备节点,并创建g\_reader线程循环读取处理Modem上报的消息。 65 66 ``` 67 g_fd = open(g_devicePath, O_RDWR); // 打开设备节点,入参g_devicePath是Modem设备节点 68 pthread_attr_init(&attr); 69 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 70 ret = pthread_create(&g_eventListeners, &attr, EventListeners, NULL); 71 ``` 72 73 741. 返回业务请求接口的函数指针。 75 76 ``` 77 // call模块业务请求接口结构体 78 typedef struct { 79 // 获取呼叫列表 80 void (*GetCallList)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 81 // 拨打电话 82 void (*Dial)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 83 // 挂断电话 84 void (*Hangup)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 85 // 拒接来电 86 void (*Reject)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 87 // 接听来电 88 void (*Answer)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 89 } HRilCallReq; 90 91 // call模块回调函数指针 92 static const HRilCallReq g_callReqOps = { 93 .GetCallList = ReqGetCallList, // 获取呼叫列表接口 94 .Dial = ReqDial, // 拨打电话接口 95 .Hangup = ReqHangup, // 挂断电话接口 96 .Reject = ReqReject, // 拒接来电接口 97 .Answer = ReqAnswer, // 接听来电接口 98 }; 99 100 // 业务请求结构体 101 typedef struct { 102 const HRilCallReq *callOps; // 通话相关业务请求结构体指针 103 const HRilSimReq *simOps; // SIM卡相关业务请求结构体指针 104 const HRilSmsReq *smsOps; // 短彩信相关业务请求结构体指针 105 const HRilDataReq *dataOps; // 蜂窝数据相关业务请求结构体指针 106 const HRilNetworkReq *networkOps; // 搜网相关业务请求结构体指针 107 const HRilModemReq *modemOps; // Modem相关业务请求结构体指针 108 } HRilOps; 109 110 // 业务请求接口定义 111 HRilOps g_hrilOps = { 112 .callOps = &g_callReqOps, // 定义通话业务请求接口 113 .simOps = &g_simReqOps, // 定义SIM卡业务请求接口 114 .smsOps = &g_smsReqOps, // 定义短彩信业务请求接口 115 .networkOps = &g_networkReqOps, // 定义蜂窝数据业务请求接口 116 .dataOps = &g_dataReqOps, // 定义搜网业务请求接口 117 .modemOps = &g_modemReqOps, // 定义Modem业务请求接口 118 }; 119 ``` 120 121 122### 调测验证<a name="section5351151517132"></a> 123 1241. 用[hdc\_std工具](subsys-toolchain-hdc-guide.md#section05992022154916)连接调试设备,把编译生成的libril\_vendor.z.so库文件(参见[Modem厂商库集成指导](#section590mcpsimp))通过以下命令推到/system/lib/目录下。 125 126 ``` 127 hdc_std file send libril_vendor.z.so /system/lib/ 128 ``` 129 1302. 执行hdc\_std shell sync,hdc\_std shell reboot重启设备。 131 132 ``` 133 hdc_std shell sync 134 hdc_std shell reboot 135 ``` 136 1373. 执行hdc\_std shell hilog,根据日志查看函数RilInitOps\(\)是否正确执行完成。如下调测验证日志供参考: 138 139 ``` 140 01-01 05:13:23.071 136 2319 D 00000/RilAdapterInit: [RilAdapterDispatch-(hril_hdf.c:55)] sbuf IPC obtain test success! 141 01-01 05:13:23.071 136 2319 D 00000/RilAdapterInit: [LoadVendor-(hril_hdf.c:33)] RilInit rilInit start 142 01-01 05:13:23.071 136 2319 D 00000/RilAdapterInit: [LoadVendor -(hril_hdf.c:45)] RilInit rilInit completed 143 ``` 144 145 146## Modem业务请求及响应开发指导<a name="section295mcpsimp"></a> 147 148### 场景介绍<a name="section297mcpsimp"></a> 149 150Modem业务请求及响应是指RIL Adapter收到电话服务具体业务请求后,调用Modem厂商库初始化获得的函数指针,把具体业务请求发送给厂商库,厂商库根据业务请求ID做相应的业务处理。 151 152### 接口说明<a name="section9503155219134"></a> 153 154Modem业务请求及响应接口。 155 156**表 2** Modem业务请求及响应接口功能介绍(以拨号功能模块为例) 157 158<a name="table303mcpsimp"></a> 159<table><thead align="left"><tr id="row309mcpsimp"><th class="cellrowborder" valign="top" width="49.84%" id="mcps1.2.3.1.1"><p id="p311mcpsimp"><a name="p311mcpsimp"></a><a name="p311mcpsimp"></a>接口名</p> 160</th> 161<th class="cellrowborder" valign="top" width="50.160000000000004%" id="mcps1.2.3.1.2"><p id="p313mcpsimp"><a name="p313mcpsimp"></a><a name="p313mcpsimp"></a>描述</p> 162</th> 163</tr> 164</thead> 165<tbody><tr id="row315mcpsimp"><td class="cellrowborder" valign="top" width="49.84%" headers="mcps1.2.3.1.1 "><p id="p317mcpsimp"><a name="p317mcpsimp"></a><a name="p317mcpsimp"></a>void ReqDial(ReqDataInfo *requestInfo, const void *data, size_t dataLen);</p> 166</td> 167<td class="cellrowborder" valign="top" width="50.160000000000004%" headers="mcps1.2.3.1.2 "><p id="p319mcpsimp"><a name="p319mcpsimp"></a><a name="p319mcpsimp"></a>接口功能:对拨号请求进行处理。</p> 168<p id="p320mcpsimp"><a name="p320mcpsimp"></a><a name="p320mcpsimp"></a>参数requestInfo:请求类型信息。</p> 169<p id="p321mcpsimp"><a name="p321mcpsimp"></a><a name="p321mcpsimp"></a>参数data:被叫号码信息。</p> 170<p id="p322mcpsimp"><a name="p322mcpsimp"></a><a name="p322mcpsimp"></a>参数dataLen:数据长度。</p> 171<p id="p323mcpsimp"><a name="p323mcpsimp"></a><a name="p323mcpsimp"></a>返回值:无。</p> 172</td> 173</tr> 174<tr id="row324mcpsimp"><td class="cellrowborder" valign="top" width="49.84%" headers="mcps1.2.3.1.1 "><p id="p326mcpsimp"><a name="p326mcpsimp"></a><a name="p326mcpsimp"></a>void (*OnCallReport)(struct ReportInfo reportInfo, const void *data, size_t dataLen);</p> 175</td> 176<td class="cellrowborder" valign="top" width="50.160000000000004%" headers="mcps1.2.3.1.2 "><p id="p328mcpsimp"><a name="p328mcpsimp"></a><a name="p328mcpsimp"></a>接口功能:对通话业务执行结果进行响应,即当请求业务执行完成后,Modem将该请求执行的结果上报给RIL Adapter。</p> 177<p id="p329mcpsimp"><a name="p329mcpsimp"></a><a name="p329mcpsimp"></a>参数reportInfo:返回类型信息。</p> 178<p id="p330mcpsimp"><a name="p330mcpsimp"></a><a name="p330mcpsimp"></a>参数data:返回数据。</p> 179<p id="p331mcpsimp"><a name="p331mcpsimp"></a><a name="p331mcpsimp"></a>参数dataLen:数据长度。</p> 180<p id="p332mcpsimp"><a name="p332mcpsimp"></a><a name="p332mcpsimp"></a>返回值:无。</p> 181</td> 182</tr> 183</tbody> 184</table> 185 186### 开发步骤<a name="section17190412101414"></a> 187 1881. 在ReqDial\(\)接口中对拨号请求进行处理。 189 190 ``` 191 // 拨号请求接口实现 192 void ReqDial(ReqDataInfo *requestInfo, const void *data, size_t dataLen) 193 { 194 HRilDial *pDial = NULL; 195 char cmd[MAX_BUFF_SIZE] = {0}; 196 const char *clir = NULL; 197 int ret; 198 int err = HRIL_ERR_SUCCESS; 199 struct ReportInfo reportInfo = {}; 200 ResponseInfo *pResponse = NULL; 201 if (data == NULL) { 202 TELEPHONY_LOGE("data is null!!!"); 203 err = HRIL_ERR_INVALID_PARAMETER; 204 reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0); 205 OnCallReport(reportInfo, NULL, 0); 206 return; 207 } 208 pDial = (HRilDial *)data; 209 switch (pDial->clir) { 210 case CALL_CLIR_INVOCATION: 211 clir = "I"; 212 break; /* invocation */ 213 case CALL_CLIR_SUPPRESSION: 214 clir = "i"; 215 break; /* suppression */ 216 case CALL_CLIR_SUBSCRIPTION_DEFUALT: 217 default: 218 clir = ""; 219 break; /* subscription default */ 220 } 221 (void)sprintf_s(cmd, MAX_BUFF_SIZE, "ATD%s%s;", pDial->address, clir); 222 ret = SendCommandLock(cmd, NULL, 0, &pResponse); // 发送AT指令 223 ...... 224 } 225 ``` 226 2272. 在Modem执行完拨号命令后,调用OnCallReport\(\)回调函数,把该请求执行的结果上报给RIL Adapter。 228 229 ``` 230 ret = SendCommandLock(cmd, NULL, 0, &pResponse); 231 if (ret != 0 || (pResponse != NULL && pResponse->success == 0)) { 232 TELEPHONY_LOGE("ATD send failed"); 233 err = HRIL_ERR_GENERIC_FAILURE; 234 } 235 reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0); 236 OnCallReport(reportInfo, NULL, 0); // 调用通话相关回调函数 237 ``` 238 239 240### 调测验证<a name="section10207938171413"></a> 241 2421. 用[hdc\_std工具](subsys-toolchain-hdc-guide.md#section05992022154916)工具连接调试设备,把编译生成的libril\_vendor.z.so库文件通过以下命令推到/system/lib/目录下。 243 244 ``` 245 hdc_std file send libril_vendor.z.so /system/lib/ 246 ``` 247 2482. 执行hdc\_std shell sync,hdc\_std shell reboot重启设备。 249 250 ``` 251 hdc_std shell sync 252 hdc_std shell reboot 253 ``` 254 2553. hdc\_std shell后执行./system/bin/ril\_adapter\_test,输入编号1,根据提示输入电话号码,测试拨打电话功能。 256 257 ``` 258 hdc_std shell 259 # ./system/bin/ril_adapter_test 260 ----> Test Enter --------->Call--------------------- 261 262 1----> RilUnitTest::OnRequestCallDialTest 263 2----> RilUnitTest:: OnRequestCallHangupTest 264 3----> RilUnitTest:: OnRequestCallAnswerTest 265 4----> RilUnitTest::OnRequestCallGetCurrentCallsStatusTest 266 5----> RilUnitTest::OnRequestRefusedCallTest 267 268 1 269 ``` 270 2714. 另开一个终端窗口,执行hdc\_std shell hilog,通过日志查看函数ReqDial\(\)是否正确执行完成。如下调测验证日志供参考: 272 273 ``` 274 01-01 05:27:27.419 136 408 D 02b01/Rilvendor: [SendCommandLock-(at_support.c:210)] SendCommandLock enter, cmd: ATD17620373527 275 01-01 05:27:27.419 136 408 D 02b01/Rilvendor: [SendCommandLock-(at_support.c:231)] SendCommandLock() command ATD17620373527 276 01-01 05:27:27.419 136 408 D 02b01/Rilvendor: [WriteATCommand-(channel.c:115)] WriteATCommand enter, cmd:ATD17620373527 277 01-01 05:27:27.421 136 187 D 02b01/Rilvendor: [ReadResponse-(channel.c:94)] g_bufferCur : 278 01-01 05:27:27.421 136 187 D 02b01/Rilvendor: OK 279 01-01 05:27:27.422 136 187 D 02b01/Rilvendor: [ProcessResponse-(at_support.c:144)] processLine line = OK 280 01-01 05:27:27.422 136 187 D 02b01/Rilvendor: [ReadResponse-(channel.c:81)] ReadResponse enter 281 01-01 05:27:27.422 136 187 D 02b01/Rilvendor: [ProcessLastResponse-(channel.c:37)] last data more than one line , FindEndOfLine g_bufferCur: 282 01-01 05:27:27.422 136 187 E 02b01/Rilvendor: [ProcessLastResponse-(channel.c:39)] g_bufferCur endLine is null 283 01-01 05:27:27.422 136 187 E 02b01/Rilvendor:^ORIG:1,0 284 01-01 05:27:27.422 136 408 E 02b01/Rilvendor: [SendCommandLock-(at_support.c:234)] processLine line = ^ORIG:1,0 285 01-01 05:27:27.422 136 408 E 02b01/Rilvendor: [SendCommandLock-(vendor_report.c:234)] enter to [^ORIG:1,0]:(null) 286 01-01 05:27:27.422 136 408 E 02b01/Rilvendor: [SendCommandLock-(at_support.c:264)] err = 0, cmd:ADT17620373527 287 ``` 288 289 290## Modem事件上报开发指导<a name="section390mcpsimp"></a> 291 292### 场景介绍<a name="section401mcpsimp"></a> 293 294Modem事件上报是指在厂商库的Modem设备节点读取线程,循环读取到Modem主动上报的消息后,对Modem上报事件进行解析,然后上报给RIL Adapter。 295 296### 接口说明<a name="section191193791518"></a> 297 298Modem事件上报接口。 299 300**表 3** Modem事件上报接口功能介绍 301 302<a name="table407mcpsimp"></a> 303<table><thead align="left"><tr id="row413mcpsimp"><th class="cellrowborder" valign="top" width="52%" id="mcps1.2.3.1.1"><p id="p415mcpsimp"><a name="p415mcpsimp"></a><a name="p415mcpsimp"></a>接口名</p> 304</th> 305<th class="cellrowborder" valign="top" width="48%" id="mcps1.2.3.1.2"><p id="p417mcpsimp"><a name="p417mcpsimp"></a><a name="p417mcpsimp"></a>描述</p> 306</th> 307</tr> 308</thead> 309<tbody><tr id="row419mcpsimp"><td class="cellrowborder" valign="top" width="52%" headers="mcps1.2.3.1.1 "><p id="p421mcpsimp"><a name="p421mcpsimp"></a><a name="p421mcpsimp"></a>void OnNotifyOps(const char *s, const char *smsPdu)</p> 310</td> 311<td class="cellrowborder" valign="top" width="48%" headers="mcps1.2.3.1.2 "><p id="p423mcpsimp"><a name="p423mcpsimp"></a><a name="p423mcpsimp"></a>接口功能:对Modem上报的事件进行分发处理。</p> 312<p id="p424mcpsimp"><a name="p424mcpsimp"></a><a name="p424mcpsimp"></a>参数s:AT指令前缀。</p> 313<p id="p425mcpsimp"><a name="p425mcpsimp"></a><a name="p425mcpsimp"></a>参数smsPdu:短信PDU信息。</p> 314<p id="p426mcpsimp"><a name="p426mcpsimp"></a><a name="p426mcpsimp"></a>返回值:无。</p> 315</td> 316</tr> 317</tbody> 318</table> 319 320### 开发步骤<a name="section16394112401512"></a> 321 3221. 在Modem设备节点读取线程g\_reader里调用OnNotifyOps\(\)解析具体的Modem上报事件,判断命令类型,并调用OnXxxReport\(\)把解析得到的各模块事件上报给hril业务层。 323 324 ``` 325 // 将Modem上报数据解析为对应模块的主动上报事件 326 void OnNotifyOps(const char *s, const char *smsPdu) 327 { 328 int ret = 0; 329 struct ReportInfo reportInfo = {0}; 330 reportInfo.error = HRIL_ERR_SUCCESS; 331 reportInfo.type = HRIL_NOTIFICATION; 332 if (GetRadioState() == HRIL_RADIO_POWER_STATE_UNAVAILABLE) { 333 return; 334 } 335 TELEPHONY_LOGD("enter to [%{public}s]:%{public}s", s, smsPdu); 336 // 通过AT指令判断主动上报命令类型 337 if (ReportStrWith(s, "+CRING:") || ReportStrWith(s, "RING") || ReportStrWith(s, "IRING") || 338 ReportStrWith(s, "NO CARRIER") || ReportStrWith(s, "+CCWA") || ReportStrWith(s, "^CCALLSTATE") || 339 ReportStrWith(s, "^CEND") || ReportStrWith(s, "^CCWA")) { 340 reportInfo.notifyId = HNOTI_CALL_STATE_UPDATED; 341 OnCallReport(reportInfo, NULL, 0); 342 } else if (ReportStrWith(s, "+CMT:")) { 343 reportInfo.notifyId = HNOTI_SMS_NEW_SMS; 344 OnSmsReport(reportInfo, (void *)smsPdu, strlen(smsPdu)); 345 } 346 // 将各模块事件上报给hril业务层 347 ...... 348 } 349 ``` 350 351 3521. hril业务层将上报事件分发给Telephony Service。 353 354 ``` 355 // 呼叫状态主动上报 356 int32_t HRilCall::CallStateUpdated( 357 int32_t slotId, int32_t notifyType, const HRilErrno e, const void *response, size_t responseLen) 358 { 359 struct HdfSBuf *dataSbuf = HdfSBufTypedObtain(SBUF_IPC); 360 if (serviceCallbackNotify_ == nullptr) { 361 TELEPHONY_LOGE("RilAdapter serviceCallbackNotify_ is null"); 362 HdfSBufRecycle(dataSbuf); 363 return HDF_FAILURE; 364 } 365 // 分发处理 366 int32_t ret = serviceCallbackNotify_->dispatcher->Dispatch( 367 serviceCallbackNotify_, HNOTI_CALL_STATE_UPDATED, dataSbuf, nullptr); 368 if (ret != HDF_SUCCESS) { 369 HdfSBufRecycle(dataSbuf); 370 return HDF_FAILURE; 371 } 372 HdfSBufRecycle(dataSbuf); 373 return HDF_SUCCESS; 374 } 375 ``` 376 377 378### 调测验证<a name="section16999174401516"></a> 379 3801. 用[hdc\_std工具](subsys-toolchain-hdc-guide.md#section05992022154916)工具连接调试设备,把编译生成的libril\_vendor.z.so库文件通过以下命令推到/system/lib/目录下。 381 382 ``` 383 hdc_std file send libril_vendor.z.so /system/lib/ 384 ``` 385 3862. 执行hdc\_std shell sync,hdc\_std shell reboot重启设备。 387 388 ``` 389 hdc_std shell sync 390 hdc_std shell reboot 391 ``` 392 3933. hdc\_std shell后执行./system/bin/ril\_adapter\_test,输入编号1,根据提示输入电话号码,测试拨打电话功能。 394 395 ``` 396 hdc_std shell 397 # ./system/bin/ril_adapter_test 398 ----> Test Enter --------->Call--------------------- 399 400 1----> RilUnitTest::OnRequestCallDialTest 401 2----> RilUnitTest:: OnRequestCallHangupTest 402 3----> RilUnitTest:: OnRequestCallAnswerTest 403 4----> RilUnitTest::OnRequestCallGetCurrentCallsStatusTest 404 5----> RilUnitTest::OnRequestRefusedCallTest 405 406 1 407 ``` 408 4094. 另开一个终端窗口,执行hdc\_std shell hilog,通过日志查看函数OnNotifyOps\(\)是否正确执行完成。如下调测验证日志供参考: 410 411 ``` 412 01-01 00:08:01.334 546 551 D 02b01/TelRilTest: [DialResponse-(tel_ril_call.cpp:280)] DialResponse --> radioResponseInfo->serial:2, radioResponseInfo->error:0 413 01-01 00:08:01.334 546 557 D 02b01/TelRilTest: [ProcessEvent-(tel_ril_test.cpp:1262)] TelRilTest::DemoHandler::ProcessEvent --> eventId:101 414 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: [ReadResponse-(channel.c:93)] g_bufferCur : 415 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: ^ORIG:1,0 416 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: [ReadResponse-(channel.c:108)] AT< ^ORIG:1,0 417 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: [ProcessResponse-(at_support.c:137)] processLine line = ^ORIG:1,0 418 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: [OnNotifyOps-(vendor_report.c:126)] enter to [^ORIG:1,0]:(null) 419 01-01 00:08:01.335 143 512 W 02b01/Rilvendor: [OnNotifyOps-(vendor_report.c:167)] enter to is unrecognized command: ^ORIG:1,0 420 01-01 00:08:01.335 143 512 D 02b01/Rilvendor: [ProcessLastResponse-(channel.c:37)] last data more than one line , FindEndOfLine g_bufferCur: 421 01-01 00:08:01.335 143 512 E 02b01/Rilvendor: [ProcessLastResponse-(channel.c:39)] g_bufferCur endLine is null 422 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: [ReadResponse-(channel.c:93)] g_bufferCur : 423 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: ^CCALLSTATE: 1,0,1 424 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: [ReadResponse-(channel.c:108)] AT< ^CCALLSTATE: 1,0,1 425 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: [ProcessResponse-(at_support.c:137)] processLine line = ^CCALLSTATE: 1,0,1 426 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: [OnNotifyOps-(vendor_report.c:126)] enter to [^CCALLSTATE: 1,0,1]:(null) 427 01-01 00:08:01.336 546 551 D 02b01/CoreService: [OnRemoteRequest-(tel_ril_manager.cpp:80)] RilManager OnRemoteRequest code:1001 428 01-01 00:08:01.336 546 551 D 02b01/CoreService: [NotifyObserver-(observer_handler.cpp:76)] handler->SendEvent:8 429 ``` 430 431 432### 开发实例<a name="section33444350167"></a> 433 434- **去电开发实例** 435 436 去电的调用流程示例如下图所示: 437 438 **图 1** 去电调用时序图<a name="fig494mcpsimp"></a> 439 ![](figure/去电调用时序图.png "去电调用时序图") 440 441 当应用触发去电动作时,RIL Adapter会接收到拨打电话的请求,hril调用对应的拨打电话的接口ReqDial\(\)。在该接口里会把电话服务传过来的数据封装为对应的AT指令发送到Modem,Modem执行完拨号命令后通过OnCallReport\(\)接口把响应结果上报给RIL Adapter。 442 443 ``` 444 // call模块回调函数指针 445 static const HRilCallReq g_callReqOps = { 446 .GetCallList = ReqGetCallList, // 获取呼叫列表接口 447 .Dial = ReqDial, // 拨打电话接口 448 .Hangup = ReqHangup, // 挂断电话接口 449 .Reject = ReqReject, // 拒接来电接口 450 .Answer = ReqAnswer, // 接听来电接口 451 }; 452 453 // 系统业务请求接口定义 454 HRilOps g_hrilOps = { 455 .callOps = &g_callReqOps, // 定义通话业务请求接口 456 .simOps = &g_simReqOps, // 定义SIM卡业务请求接口 457 .smsOps = &g_smsReqOps, // 定义短彩信业务请求接口 458 .networkOps = &g_networkReqOps, // 定义蜂窝数据业务请求接口 459 .dataOps = &g_dataReqOps, // 定义搜网业务请求接口 460 .modemOps = &g_modemReqOps, // 定义Modem业务请求接口 461 }; 462 463 // 拨号请求接口实现 464 void ReqDial(ReqDataInfo *requestInfo, const void *data, size_t dataLen) 465 { 466 HRilDial *pDial = NULL; 467 char cmd[MAX_BUFF_SIZE] = {0}; 468 const char *clir = NULL; 469 int ret; 470 int err = HRIL_ERR_SUCCESS; 471 struct ReportInfo reportInfo = {}; 472 ResponseInfo *pResponse = NULL; 473 if (data == NULL) { 474 TELEPHONY_LOGE("data is null!!!"); 475 err = HRIL_ERR_INVALID_PARAMETER; 476 reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0); 477 OnCallReport(reportInfo, NULL, 0); 478 return; 479 } 480 pDial = (HRilDial *)data; 481 switch (pDial->clir) { 482 case CALL_CLIR_INVOCATION: 483 clir = "I"; 484 break; /* invocation */ 485 case CALL_CLIR_SUPPRESSION: 486 clir = "i"; 487 break; /* suppression */ 488 case CALL_CLIR_SUBSCRIPTION_DEFUALT: 489 default: 490 clir = ""; 491 break; /* subscription default */ 492 } 493 (void)sprintf_s(cmd, MAX_BUFF_SIZE, "ATD%s%s;", pDial->address, clir); 494 ret = SendCommandLock(cmd, NULL, 0, &pResponse); // 发送AT命令 495 if (ret != 0) { 496 err = HRIL_ERR_CMD_SEND_FAILURE; 497 TELEPHONY_LOGE("ATD send failed"); 498 } else { 499 if (pResponse != NULL && pResponse->success == 0) { 500 TELEPHONY_LOGE("ReqDial return ERROR"); 501 err = HRIL_ERR_CMD_NO_CARRIER; 502 } 503 } 504 reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0); 505 OnCallReport(reportInfo, NULL, 0); // 调用通话相关业务回调函数 506 FreeResponseInfo(pResponse); 507 } 508 ``` 509 510 511- **来电开发实例** 512 513 来电的调用流程示例如下图所示: 514 515 **图 2** 来电调用时序图<a name="fig556mcpsimp"></a> 516 517 518 ![](figure/zh-cn_image_0000001214727595.png) 519 520 Modem设备节点读取线程g\_reader会循环读取Modem上报的消息,当Modem接收到来电时会主动上报来电相关的信息; 521 522 当该线程通过调用OnNotifyOps\(\)解析到Modem上报的数据是以"+CRING"、"RING"等字符开头时,表示有来电事件,然后通过OnCallReport\(reportInfo, NULL, 0\)上报给RIL Adapter完成来电事件上报。 523 524 ``` 525 // 将Modem上报数据解析为对应模块的主动上报事件 526 void OnNotifyOps(const char *s, const char *smsPdu) 527 { 528 int ret = 0; 529 struct ReportInfo reportInfo = {0}; 530 reportInfo.error = HRIL_ERR_SUCCESS; 531 reportInfo.type = HRIL_NOTIFICATION; 532 if (GetRadioState() == HRIL_RADIO_POWER_STATE_UNAVAILABLE) { 533 return; 534 } 535 TELEPHONY_LOGD("enter to [%{public}s]:%{public}s", s, smsPdu); 536 // 通过AT指令判断主动上报命令类型 537 if (ReportStrWith(s, "+CRING:") || ReportStrWith(s, "RING") || ReportStrWith(s, "IRING") || 538 ReportStrWith(s, "NO CARRIER") || ReportStrWith(s, "+CCWA") || ReportStrWith(s, "^CCALLSTATE") || 539 ReportStrWith(s, "^CEND") || ReportStrWith(s, "^CCWA")) { 540 reportInfo.notifyId = HNOTI_CALL_STATE_UPDATED; 541 OnCallReport(reportInfo, NULL, 0); // 调用通话相关业务回调函数 542 } else if (ReportStrWith(s, "+CMT:")) { 543 reportInfo.notifyId = HNOTI_SMS_NEW_SMS; 544 OnSmsReport(reportInfo, (void *)smsPdu, strlen(smsPdu)); 545 } 546 // add your codes 547 ...... 548 } 549 ``` 550 551 552## Modem厂商库集成指导<a name="section590mcpsimp"></a> 553 554### 编译设置<a name="section592mcpsimp"></a> 555 556Modem厂商库可通过BUILD.gn编译为一个动态库,在RIL Adapter启动时用dlopen方式加载到系统中,然后执行厂商库的初始化操作(参见[Modem厂商库初始化开发指导](#section211mcpsimp)),BUILD.gn编写示例如下: 557 558``` 559import("//build/ohos.gni") 560RIL_ADAPTER = "//base/telephony" 561ohos_shared_library("ril_vendor") { // Modem厂商库名称 562 sources = [ // 编译源文件 563 "at_call.c", 564 "at_data.c", 565 "xxx.c", 566 ] 567 include_dirs = [ // 包含的头文件目录 568 "$RIL_ADAPTER/ril_adapter/vendor/include", 569 "$RIL_ADAPTER/ril_adapter/interfaces/innerkits", 570 "include", 571 ] 572 deps = [ // 内部依赖 573 "//drivers/adapter/uhdf2/osal:libhdf_utils", 574 "//base/telephony/core_service/utils:libtelephony_common", 575 ] 576 external_deps = [ "hilog:libhilog" ] // 外部依赖 577 578 part_name = "ril_adapter" // 部件名称 579 subsystem_name = "telephony" // 子系统名称 580} 581``` 582 583### 调测验证<a name="section620mcpsimp"></a> 584 5851. 编译代码。 5862. 查看/out/{device_name}/telephony/ril\_adapter目录是否存在libril\_vendor.z.so,存在证明集成成功。否则检查代码,重新编译验证。 587 588