1# Telephony Development<a name="EN-US_TOPIC_0000001167051994"></a> 2 3## Initializing a Modem Vendor Library<a name="section211mcpsimp"></a> 4 5### When to Use<a name="section213mcpsimp"></a> 6 7Initializing a modem vendor library means to implement **const HRilOps \*RilInitOps\(const struct HRilReport \*reportOps\)** function in the vendor library. This function is mainly used to: 8 9- Receive function pointers to event callbacks of RIL Adapter. When a service event needs to be reported, the target pointer will be called to report the event to RIL Adapter. 10- Create a thread for reading modem nodes. In this thread, the data reported by the modem is read cyclically and parsed as a specific service event for reporting. 11- Return the function pointer of the service request API to RIL Adapter. 12 13### Available APIs<a name="section811343241215"></a> 14 15The following table describes the API for initializing a modem vendor library. 16 17**Table 1** API for initializing a modem vendor library 18 19<a name="table223mcpsimp"></a> 20<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>API</p> 21</th> 22<th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p233mcpsimp"><a name="p233mcpsimp"></a><a name="p233mcpsimp"></a>Description</p> 23</th> 24</tr> 25</thead> 26<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> 27</td> 28<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p239mcpsimp"><a name="p239mcpsimp"></a><a name="p239mcpsimp"></a>Function: Provides an entry for running a modem vendor library.</p> 29<p id="p56281836194610"><a name="p56281836194610"></a><a name="p56281836194610"></a>Input parameter:</p> 30<p id="p240mcpsimp"><a name="p240mcpsimp"></a><a name="p240mcpsimp"></a><strong id="b164737479278"><a name="b164737479278"></a><a name="b164737479278"></a>reportOps</strong>: Specifies the pointer to the event callback function, which is passed by RIL Adapter.</p> 31<p id="p241mcpsimp"><a name="p241mcpsimp"></a><a name="p241mcpsimp"></a>Return result: function pointer of the service request API.</p> 32</td> 33</tr> 34</tbody> 35</table> 36 37### How to Develop<a name="section51031144122"></a> 38 391. Set the event callback function pointers passed by RIL Adapter through **RilInitOps**. 40 41 ``` 42 // Define the callback function pointers of the modem vendor library. 43 static struct HRilReport g_reportOps = { 44 OnCallReport, // Callback function for call services 45 OnDataReport, // Callback function for cellular data services 46 OnModemReport, // Callback function for modem services 47 OnNetworkReport, // Callback function for network search services 48 OnSimReport, // Callback function for SIM card services 49 OnSmsReport // Callback function for SMS services 50 }; 51 ``` 52 53 541. Create the **g\_reader** main thread to enable message looping. 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); // Create the g_reader thread. 61 ``` 62 63 641. In the **g\_eventListeners** thread, use **open\(\)** to open a modem node and then create the **g\_reader** thread to read and process messages reported by the modem. 65 66 ``` 67 g_fd = open(g_devicePath, O_RDWR); // Open the device node specified by g_devicePath. 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. Return the function pointer of the service request API. 75 76 ``` 77 // Structure for the service request API of the call module 78 typedef struct { 79 // Obtain the call list. 80 void (*GetCallList)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 81 // Make a call. 82 void (*Dial)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 83 // Disconnect a call. 84 void (*Hangup)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 85 // Reject a call. 86 void (*Reject)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 87 // Answer a call. 88 void (*Answer)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 89 } HRilCallReq; 90 91 // Callback function pointers of the call module 92 static const HRilCallReq g_callReqOps = { 93 .GetCallList = ReqGetCallList, // Obtain the call list. 94 .Dial = ReqDial, // Make a call. 95 .Hangup = ReqHangup, // Disconnect a call. 96 .Reject = ReqReject, // Reject a call. 97 .Answer = ReqAnswer, // Answer a call. 98 }; 99 100 // Service request structure 101 typedef struct { 102 const HRilCallReq *callOps; // Pointer to the structure of call service requests 103 const HRilSimReq *simOps; // Pointer to the structure of SIM card service requests 104 const HRilSmsReq *smsOps; // Pointer to the structure of SMS and MMS service requests 105 const HRilDataReq *dataOps; // Pointer to the structure of cellular data service requests 106 const HRilNetworkReq *networkOps; // Pointer to the structure of network search service requests 107 const HRilModemReq *modemOps; // Pointer to the structure of modem service requests 108 } HRilOps; 109 110 // Service request APIs 111 HRilOps g_hrilOps = { 112 .callOps = &g_callReqOps, // API for call service requests 113 .simOps = &g_simReqOps, // API for SIM card service requests 114 .smsOps = &g_smsReqOps, // API for SMS and MMS service requests 115 .networkOps = &g_networkReqOps, // API for cellular data service requests 116 .dataOps = &g_dataReqOps, // API for network search service requests 117 .modemOps = &g_modemReqOps, // API for modem service requests 118 }; 119 ``` 120 121 122### Debugging and Verification<a name="section5351151517132"></a> 123 1241. Use the [hdc\_std](subsys-toolchain-hdc-guide.md#section05992022154916) tool to connect to a debugging device. Then, run the following command to send the generated **libril\_vendor.z.so** library file to the **/system/lib/** directory of the device. For details about how to integrate a library file, see [Integrating Modem Vendor Libraries](#section590mcpsimp). 125 126 ``` 127 hdc_std file send libril_vendor.z.so /system/lib/ 128 ``` 129 1302. Reboot the debugging device. 131 132 ``` 133 hdc_std shell sync 134 hdc_std shell reboot 135 ``` 136 1373. Run the **hdc\_std shell hilog** command to view the debug log, and check whether the **RilInitOps\(\)** function is successfully executed. The following debug log is for reference: 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## Responding to Modem Service Requests<a name="section295mcpsimp"></a> 147 148### When to Use<a name="section297mcpsimp"></a> 149 150After receiving a specific telephony service request, RIL Adapter calls the target function pointer obtained in modem vendor library initialization to send a specific service request to the vendor library. Then, the vendor library processes the request based on the request ID. 151 152### Available APIs<a name="section9503155219134"></a> 153 154The following table describes the APIs for responding to modem service requests, with the dial module as an example. 155 156**Table 2** APIs for responding to modem service requests 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>API</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>Description</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>Function: Processes number dial requests.</p> 168<p id="p12610151394115"><a name="p12610151394115"></a><a name="p12610151394115"></a>Input parameters:</p> 169<a name="ul105511416204116"></a><a name="ul105511416204116"></a><ul id="ul105511416204116"><li><strong id="b85517162414"><a name="b85517162414"></a><a name="b85517162414"></a>requestInfo</strong>: request type</li></ul> 170<a name="ul1676502416411"></a><a name="ul1676502416411"></a><ul id="ul1676502416411"><li><strong id="b1576510240416"><a name="b1576510240416"></a><a name="b1576510240416"></a>data</strong>: called number</li></ul> 171<a name="ul842034134114"></a><a name="ul842034134114"></a><ul id="ul842034134114"><li><strong id="b1542193411415"><a name="b1542193411415"></a><a name="b1542193411415"></a>dataLen</strong>: data length</li></ul> 172<p id="p323mcpsimp"><a name="p323mcpsimp"></a><a name="p323mcpsimp"></a>Return value: none</p> 173</td> 174</tr> 175<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> 176</td> 177<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>Function: Reports the execution result of a service request to RIL Adapter.</p> 178<p id="p489264432"><a name="p489264432"></a><a name="p489264432"></a>Input parameters:</p> 179<a name="ul44156301444"></a><a name="ul44156301444"></a><ul id="ul44156301444"><li><strong id="b15415930154418"><a name="b15415930154418"></a><a name="b15415930154418"></a>reportInfo</strong>: request type</li></ul> 180<a name="ul18380115494513"></a><a name="ul18380115494513"></a><ul id="ul18380115494513"><li><strong id="b83808549457"><a name="b83808549457"></a><a name="b83808549457"></a>data</strong>: called number</li></ul> 181<a name="ul118421156184517"></a><a name="ul118421156184517"></a><ul id="ul118421156184517"><li><strong id="b48421056144519"><a name="b48421056144519"></a><a name="b48421056144519"></a>dataLen</strong>: data length</li></ul> 182<p id="p332mcpsimp"><a name="p332mcpsimp"></a><a name="p332mcpsimp"></a>Return value: none</p> 183</td> 184</tr> 185</tbody> 186</table> 187 188### How to Develop<a name="section17190412101414"></a> 189 1901. Implement processing of dial requests in the **ReqDial\(\)** API. 191 192 ``` 193 // Implement the API for processing dial requests. 194 void ReqDial(ReqDataInfo *requestInfo, const void *data, size_t dataLen) 195 { 196 HRilDial *pDial = NULL; 197 char cmd[MAX_BUFF_SIZE] = {0}; 198 const char *clir = NULL; 199 int ret; 200 int err = HRIL_ERR_SUCCESS; 201 struct ReportInfo reportInfo = {}; 202 ResponseInfo *pResponse = NULL; 203 if (data == NULL) { 204 TELEPHONY_LOGE("data is null!!!"); 205 err = HRIL_ERR_INVALID_PARAMETER; 206 reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0); 207 OnCallReport(reportInfo, NULL, 0); 208 return; 209 } 210 pDial = (HRilDial *)data; 211 switch (pDial->clir) { 212 case CALL_CLIR_INVOCATION: 213 clir = "I"; 214 break; /* invocation */ 215 case CALL_CLIR_SUPPRESSION: 216 clir = "i"; 217 break; /* suppression */ 218 case CALL_CLIR_SUBSCRIPTION_DEFUALT: 219 default: 220 clir = ""; 221 break; /* subscription default */ 222 } 223 (void)sprintf_s(cmd, MAX_BUFF_SIZE, "ATD%s%s;", pDial->address, clir); 224 ret = SendCommandLock(cmd, NULL, 0, &pResponse); // Send the AT command. 225 ...... 226 } 227 ``` 228 2292. After the modem executes the dial command, report the execution result to RIL Adapter via **OnCallReport\(\)**. 230 231 ``` 232 ret = SendCommandLock(cmd, NULL, 0, &pResponse); 233 if (ret != 0 || (pResponse != NULL && pResponse->success == 0)) { 234 TELEPHONY_LOGE("ATD send failed"); 235 err = HRIL_ERR_GENERIC_FAILURE; 236 } 237 reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0); 238 OnCallReport(reportInfo, NULL, 0); // Invoke the callback function of the call service. 239 ``` 240 241 242### Debugging and Verification<a name="section10207938171413"></a> 243 2441. Use the [hdc\_std](subsys-toolchain-hdc-guide.md#section05992022154916) tool to connect to a debugging device. Then, run the following command to send the generated **libril\_vendor.z.so** library file to the **/system/lib/** directory of the device. 245 246 ``` 247 hdc_std file send libril_vendor.z.so /system/lib/ 248 ``` 249 2502. Reboot the debugging device. 251 252 ``` 253 hdc_std shell sync 254 hdc_std shell reboot 255 ``` 256 2573. Run the **hdc\_std shell** command. Then, run the **./system/bin/ril\_adapter\_test** command, type **1**, and enter the phone number as prompted to test the call function. 258 259 ``` 260 hdc_std shell 261 # ./system/bin/ril_adapter_test 262 ----> Test Enter --------->Call--------------------- 263 264 1----> RilUnitTest::OnRequestCallDialTest 265 2----> RilUnitTest:: OnRequestCallHangupTest 266 3----> RilUnitTest:: OnRequestCallAnswerTest 267 4----> RilUnitTest::OnRequestCallGetCurrentCallsStatusTest 268 5----> RilUnitTest::OnRequestRefusedCallTest 269 270 1 271 ``` 272 2734. Open another terminal window, and run the **hdc\_std shell hilog** command. Then, view the log to check whether **ReqDial\(\)** is successfully executed. The following debug log is for reference: 274 275 ``` 276 01-01 05:27:27.419 136 408 D 02b01/Rilvendor: [SendCommandLock-(at_support.c:210)] SendCommandLock enter, cmd: ATD17620373527 277 01-01 05:27:27.419 136 408 D 02b01/Rilvendor: [SendCommandLock-(at_support.c:231)] SendCommandLock() command ATD17620373527 278 01-01 05:27:27.419 136 408 D 02b01/Rilvendor: [WriteATCommand-(channel.c:115)] WriteATCommand enter, cmd:ATD17620373527 279 01-01 05:27:27.421 136 187 D 02b01/Rilvendor: [ReadResponse-(channel.c:94)] g_bufferCur : 280 01-01 05:27:27.421 136 187 D 02b01/Rilvendor: OK 281 01-01 05:27:27.422 136 187 D 02b01/Rilvendor: [ProcessResponse-(at_support.c:144)] processLine line = OK 282 01-01 05:27:27.422 136 187 D 02b01/Rilvendor: [ReadResponse-(channel.c:81)] ReadResponse enter 283 01-01 05:27:27.422 136 187 D 02b01/Rilvendor: [ProcessLastResponse-(channel.c:37)] last data more than one line , FindEndOfLine g_bufferCur: 284 01-01 05:27:27.422 136 187 E 02b01/Rilvendor: [ProcessLastResponse-(channel.c:39)] g_bufferCur endLine is null 285 01-01 05:27:27.422 136 187 E 02b01/Rilvendor:^ORIG:1,0 286 01-01 05:27:27.422 136 408 E 02b01/Rilvendor: [SendCommandLock-(at_support.c:234)] processLine line = ^ORIG:1,0 287 01-01 05:27:27.422 136 408 E 02b01/Rilvendor: [SendCommandLock-(vendor_report.c:234)] enter to [^ORIG:1,0]: (null) 288 01-01 05:27:27.422 136 408 E 02b01/Rilvendor: [SendCommandLock-(at_support.c:264)] err = 0, cmd:ADT17620373527 289 ``` 290 291 292## Reporting Modem Events<a name="section390mcpsimp"></a> 293 294### When to Use<a name="section401mcpsimp"></a> 295 296A modem node thread reads the messages reported by the modem cyclically, parses the messages into specific events, and then reports the events to RIL Adapter. 297 298### Available APIs<a name="section191193791518"></a> 299 300The following table describes the API for reporting modem events. 301 302**Table 3** API for reporting modem events 303 304<a name="table407mcpsimp"></a> 305<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>API</p> 306</th> 307<th class="cellrowborder" valign="top" width="48%" id="mcps1.2.3.1.2"><p id="p417mcpsimp"><a name="p417mcpsimp"></a><a name="p417mcpsimp"></a>Description</p> 308</th> 309</tr> 310</thead> 311<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> 312</td> 313<td class="cellrowborder" valign="top" width="48%" headers="mcps1.2.3.1.2 "><p id="p423mcpsimp"><a name="p423mcpsimp"></a><a name="p423mcpsimp"></a>Function: Distributes the events reported by the modem.</p> 314<p id="p17924530141912"><a name="p17924530141912"></a><a name="p17924530141912"></a>Input parameters:</p> 315<a name="ul678053915191"></a><a name="ul678053915191"></a><ul id="ul678053915191"><li><strong id="b14780173912196"><a name="b14780173912196"></a><a name="b14780173912196"></a>s</strong>: AT command prefix</li></ul> 316<a name="ul206343434192"></a><a name="ul206343434192"></a><ul id="ul206343434192"><li><strong id="b65891958173518"><a name="b65891958173518"></a><a name="b65891958173518"></a>smsPdu</strong>: PDU of the SMS message</li></ul> 317<p id="p426mcpsimp"><a name="p426mcpsimp"></a><a name="p426mcpsimp"></a>Return value: none</p> 318</td> 319</tr> 320</tbody> 321</table> 322 323### How to Develop<a name="section16394112401512"></a> 324 3251. Call **OnNotifyOps\(\)** in the g\_reader thread of the modem device node to parse reported modem events. On determining the command type, call **OnXxxReport\(\)** to report the parsed module events to the hril layer. 326 327 ``` 328 // Parse the data reported by the modem as events proactively reported by the corresponding module. 329 void OnNotifyOps(const char *s, const char *smsPdu) 330 { 331 int ret = 0; 332 struct ReportInfo reportInfo = {0}; 333 reportInfo.error = HRIL_ERR_SUCCESS; 334 reportInfo.type = HRIL_NOTIFICATION; 335 if (GetRadioState() == HRIL_RADIO_POWER_STATE_UNAVAILABLE) { 336 return; 337 } 338 TELEPHONY_LOGD("enter to [%{public}s]:%{public}s", s, smsPdu); 339 // Determine the type of the proactively reported events based on the AT command. 340 if (ReportStrWith(s, "+CRING:") || ReportStrWith(s, "RING") || ReportStrWith(s, "IRING") || 341 ReportStrWith(s, "NO CARRIER") || ReportStrWith(s, "+CCWA") || ReportStrWith(s, "^CCALLSTATE") || 342 ReportStrWith(s, "^CEND") || ReportStrWith(s, "^CCWA")) { 343 reportInfo.notifyId = HNOTI_CALL_STATE_UPDATED; 344 OnCallReport(reportInfo, NULL, 0); 345 } else if (ReportStrWith(s, "+CMT:")) { 346 reportInfo.notifyId = HNOTI_SMS_NEW_SMS; 347 OnSmsReport(reportInfo, (void *)smsPdu, strlen(smsPdu)); 348 } 349 // Report the events of each module to the hril layer. 350 ... 351 } 352 ``` 353 354 3551. Distribute the reported events from the **hril** layer to the Telephony Service layer. 356 357 ``` 358 // Report the call status proactively. 359 int32_t HRilCall::CallStateUpdated( 360 int32_t slotId, int32_t notifyType, const HRilErrno e, const void *response, size_t responseLen) 361 { 362 struct HdfSBuf *dataSbuf = HdfSBufTypedObtain(SBUF_IPC); 363 if (serviceCallbackNotify_ == nullptr) { 364 TELEPHONY_LOGE("RilAdapter serviceCallbackNotify_ is null"); 365 HdfSBufRecycle(dataSbuf); 366 return HDF_FAILURE; 367 } 368 // Distribute events. 369 int32_t ret = serviceCallbackNotify_->dispatcher->Dispatch( 370 serviceCallbackNotify_, HNOTI_CALL_STATE_UPDATED, dataSbuf, nullptr); 371 if (ret != HDF_SUCCESS) { 372 HdfSBufRecycle(dataSbuf); 373 return HDF_FAILURE; 374 } 375 HdfSBufRecycle(dataSbuf); 376 return HDF_SUCCESS; 377 } 378 ``` 379 380 381### Debugging and Verification<a name="section16999174401516"></a> 382 3831. Use the [hdc\_std](subsys-toolchain-hdc-guide.md#section05992022154916) tool to connect to a debugging device. Then, run the following command to send the generated **libril\_vendor.z.so** library file to the **/system/lib/** directory of the device. 384 385 ``` 386 hdc_std file send libril_vendor.z.so /system/lib/ 387 ``` 388 3892. Reboot the debugging device. 390 391 ``` 392 hdc_std shell sync 393 hdc_std shell reboot 394 ``` 395 3963. Run the **hdc\_std shell** command. Then, run the **./system/bin/ril\_adapter\_test** command, type **1**, and enter the phone number as prompted to test the call function. 397 398 ``` 399 hdc_std shell 400 # ./system/bin/ril_adapter_test 401 ----> Test Enter --------->Call--------------------- 402 403 1----> RilUnitTest::OnRequestCallDialTest 404 2----> RilUnitTest:: OnRequestCallHangupTest 405 3----> RilUnitTest:: OnRequestCallAnswerTest 406 4----> RilUnitTest::OnRequestCallGetCurrentCallsStatusTest 407 5----> RilUnitTest::OnRequestRefusedCallTest 408 409 1 410 ``` 411 4124. Open another terminal window, and run the **hdc\_std shell hilog** command. Then, view the log to check whether **OnNotifyOps\(\)** is successfully executed. The following debug log is for reference: 413 414 ``` 415 01-01 00:08:01.334 546 551 D 02b01/TelRilTest: [DialResponse-(tel_ril_call.cpp:280)] DialResponse --> radioResponseInfo->serial:2, radioResponseInfo->error:0 416 01-01 00:08:01.334 546 557 D 02b01/TelRilTest: [ProcessEvent-(tel_ril_test.cpp:1262)] TelRilTest::DemoHandler::ProcessEvent --> eventId:101 417 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: [ReadResponse-(channel.c:93)] g_bufferCur : 418 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: ^ORIG:1,0 419 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: [ReadResponse-(channel.c:108)] AT< ^ORIG:1,0 420 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: [ProcessResponse-(at_support.c:137)] processLine line = ^ORIG:1,0 421 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: [OnNotifyOps-(vendor_report.c:126)] enter to [^ORIG:1,0]:(null) 422 01-01 00:08:01.335 143 512 W 02b01/Rilvendor: [OnNotifyOps-(vendor_report.c:167)] enter to is unrecognized command: ^ORIG:1,0 423 01-01 00:08:01.335 143 512 D 02b01/Rilvendor: [ProcessLastResponse-(channel.c:37)] last data more than one line , FindEndOfLine g_bufferCur: 424 01-01 00:08:01.335 143 512 E 02b01/Rilvendor: [ProcessLastResponse-(channel.c:39)] g_bufferCur endLine is null 425 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: [ReadResponse-(channel.c:93)] g_bufferCur : 426 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: ^CCALLSTATE: 1,0,1 427 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: [ReadResponse-(channel.c:108)] AT< ^CCALLSTATE: 1,0,1 428 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: [ProcessResponse-(at_support.c:137)] processLine line = ^CCALLSTATE: 1,0,1 429 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: [OnNotifyOps-(vendor_report.c:126)] enter to [^CCALLSTATE: 1,0,1]:(null) 430 01-01 00:08:01.336 546 551 D 02b01/CoreService: [OnRemoteRequest-(tel_ril_manager.cpp:80)] RilManager OnRemoteRequest code:1001 431 01-01 00:08:01.336 546 551 D 02b01/CoreService: [NotifyObserver-(observer_handler.cpp:76)] handler->SendEvent:8 432 ``` 433 434 435### Development Examples<a name="section33444350167"></a> 436 437- **Outgoing Call** 438 439 The following figure shows the API calling for an outgoing call. 440 441 **Figure 1** Time sequence of API calling for an outgoing call<a name="fig494mcpsimp"></a> 442 443 444  445 446 When an application initiates an outgoing call, RIL Adapter receives a call request, and the **hril** layer invokes the **ReqDial\(\)** function. In **ReqDial\(\)**, the data passed by the Telephony Service is encapsulated as an AT command and sent to the modem. After executing the dial command, the modem reports the execution result to RIL Adapter through **OnCallReport\(\)**. 447 448 ``` 449 // Callback function pointer of the call module 450 static const HRilCallReq g_callReqOps = { 451 .GetCallList = ReqGetCallList, // Obtain the call list. 452 .Dial = ReqDial, // Make a call. 453 .Hangup = ReqHangup, // Disconnect a call. 454 .Reject = ReqReject, // Reject a call. 455 .Answer = ReqAnswer, // Answer a call. 456 }; 457 458 // Service request APIs 459 HRilOps g_hrilOps = { 460 .callOps = &g_callReqOps, // API for call service requests 461 .simOps = &g_simReqOps, // API for SIM card service requests 462 .smsOps = &g_smsReqOps, // API for SMS and MMS service requests 463 .networkOps = &g_networkReqOps, // API for cellular data service requests 464 .dataOps = &g_dataReqOps, // API for network search service requests 465 .modemOps = &g_modemReqOps, // API for modem service requests 466 }; 467 468 // Implement the API for processing dial requests. 469 void ReqDial(ReqDataInfo *requestInfo, const void *data, size_t dataLen) 470 { 471 HRilDial *pDial = NULL; 472 char cmd[MAX_BUFF_SIZE] = {0}; 473 const char *clir = NULL; 474 int ret; 475 int err = HRIL_ERR_SUCCESS; 476 struct ReportInfo reportInfo = {}; 477 ResponseInfo *pResponse = NULL; 478 if (data == NULL) { 479 TELEPHONY_LOGE("data is null!!!"); 480 err = HRIL_ERR_INVALID_PARAMETER; 481 reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0); 482 OnCallReport(reportInfo, NULL, 0); 483 return; 484 } 485 pDial = (HRilDial *)data; 486 switch (pDial->clir) { 487 case CALL_CLIR_INVOCATION: 488 clir = "I"; 489 break; /* invocation */ 490 case CALL_CLIR_SUPPRESSION: 491 clir = "i"; 492 break; /* suppression */ 493 case CALL_CLIR_SUBSCRIPTION_DEFUALT: 494 default: 495 clir = ""; 496 break; /* subscription default */ 497 } 498 (void)sprintf_s(cmd, MAX_BUFF_SIZE, "ATD%s%s;", pDial->address, clir); 499 ret = SendCommandLock(cmd, NULL, 0, &pResponse); // Send the AT command. 500 if (ret != 0) { 501 err = HRIL_ERR_CMD_SEND_FAILURE; 502 TELEPHONY_LOGE("ATD send failed"); 503 } else { 504 if (pResponse != NULL && pResponse->success == 0) { 505 TELEPHONY_LOGE("ReqDial return ERROR"); 506 err = HRIL_ERR_CMD_NO_CARRIER; 507 } 508 } 509 reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0); 510 OnCallReport(reportInfo, NULL, 0); // Invoke the callback function of the call service. 511 FreeResponseInfo(pResponse); 512 } 513 ``` 514 515 516- **Incoming Call** 517 518 The following figure shows the API calling of an incoming call. 519 520 **Figure 2** Time sequence of API calling for an incoming call<a name="fig556mcpsimp"></a> 521 522 523  524 525 The **g\_reader** thread cyclically reads the messages reported by the modem. When the modem receives an incoming call event, it actively reports the information about the incoming call. 526 527 The **g\_reader** thread calls **OnNotifyOps\(\)** to parse the reported information. If the parsed data reported by the modem starts with characters such as **+CRING** or **RING**, it indicates that an incoming call event exists. In this case, the event is reported to RIL Adapter through **OnCallReport\(reportInfo, NULL, 0\)**. 528 529 ``` 530 // Parse the data reported by the modem as events proactively reported by the corresponding module. 531 void OnNotifyOps(const char *s, const char *smsPdu) 532 { 533 int ret = 0; 534 struct ReportInfo reportInfo = {0}; 535 reportInfo.error = HRIL_ERR_SUCCESS; 536 reportInfo.type = HRIL_NOTIFICATION; 537 if (GetRadioState() == HRIL_RADIO_POWER_STATE_UNAVAILABLE) { 538 return; 539 } 540 TELEPHONY_LOGD("enter to [%{public}s]:%{public}s", s, smsPdu); 541 // Determine the type of the proactively reported events based on the AT command. 542 if (ReportStrWith(s, "+CRING:") || ReportStrWith(s, "RING") || ReportStrWith(s, "IRING") || 543 ReportStrWith(s, "NO CARRIER") || ReportStrWith(s, "+CCWA") || ReportStrWith(s, "^CCALLSTATE") || 544 ReportStrWith(s, "^CEND") || ReportStrWith(s, "^CCWA")) { 545 reportInfo.notifyId = HNOTI_CALL_STATE_UPDATED; 546 OnCallReport(reportInfo, NULL, 0); // Invoke the callback function of the call service. 547 } else if (ReportStrWith(s, "+CMT:")) { 548 reportInfo.notifyId = HNOTI_SMS_NEW_SMS; 549 OnSmsReport(reportInfo, (void *)smsPdu, strlen(smsPdu)); 550 } 551 // add your codes 552 ...... 553 } 554 ``` 555 556 557## Integrating Modem Vendor Libraries<a name="section590mcpsimp"></a> 558 559### Configuring Compilation Information<a name="section592mcpsimp"></a> 560 561Compile the modem vendor library into a dynamic library by using **BUILD.gn**. Upon startup, RIL Adapter loads the dynamic library to the system in dlopen mode and then initializes the library. For details about how to implement vendor library initialization, see [Initializing a Modem Vendor Library](#section211mcpsimp). The following is an example of **BUILD.gn**: 562 563``` 564import("//build/ohos.gni") 565RIL_ADAPTER = "//base/telephony" 566ohos_shared_library("ril_vendor") { // Modem vendor library 567 sources = [ // Source files to compile 568 "at_call.c", 569 "at_data.c", 570 "xxx.c", 571 ] 572 include_dirs = [ // Header files 573 "$RIL_ADAPTER/ril_adapter/vendor/include", 574 "$RIL_ADAPTER/ril_adapter/interfaces/innerkits", 575 "include", 576 ] 577 deps = [ // Internal dependencies 578 "//drivers/adapter/uhdf2/osal:libhdf_utils", 579 "//base/telephony/core_service/utils:libtelephony_common", 580 ] 581 external_deps = [ "hilog:libhilog" ] // External dependencies 582 583 part_name = "ril_adapter" // Part name 584 subsystem_name = "telephony" // Subsystem name 585} 586``` 587 588### Debugging and Verification<a name="section620mcpsimp"></a> 589 5901. Compile the code. 5912. Check whether **libril\_vendor.z.so** exists in the **/out/{device_name}/telephony/ril\_adapter** directory. If yes, the integration is successful. Otherwise, correct the error and perform debugging and verification again. 592 593