1e41f4b71Sopenharmony_ci# Telephony Development 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci## Initializing a Modem Vendor Library 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci### When to Use 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ciInitializing 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: 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci- 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. 10e41f4b71Sopenharmony_ci- 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. 11e41f4b71Sopenharmony_ci- Return the function pointer of the service request API to RIL Adapter. 12e41f4b71Sopenharmony_ci 13e41f4b71Sopenharmony_ci### Available APIs 14e41f4b71Sopenharmony_ci 15e41f4b71Sopenharmony_ciThe following table describes the API for initializing a modem vendor library. 16e41f4b71Sopenharmony_ci 17e41f4b71Sopenharmony_ci**Table 1** API for initializing a modem vendor library 18e41f4b71Sopenharmony_ci 19e41f4b71Sopenharmony_ci| API | Description | 20e41f4b71Sopenharmony_ci| -------- | -------- | 21e41f4b71Sopenharmony_ci| const HRilOps \*RilInitOps(const struct HRilReport \* reportOps) | Provides an entry for running a modem vendor library.<br>Input parameter:<br>**reportOps**: Specifies the pointer to the event callback function, which is passed by RIL Adapter.<br/>Return result: function pointer of the service request API. | 22e41f4b71Sopenharmony_ci 23e41f4b71Sopenharmony_ci### How to Develop 24e41f4b71Sopenharmony_ci 25e41f4b71Sopenharmony_ci1. Set the event callback function pointers passed by RIL Adapter through **RilInitOps**. 26e41f4b71Sopenharmony_ci 27e41f4b71Sopenharmony_ci ``` 28e41f4b71Sopenharmony_ci // Define the callback function pointers of the modem vendor library. 29e41f4b71Sopenharmony_ci static struct HRilReport g_reportOps = { 30e41f4b71Sopenharmony_ci OnCallReport, // Callback function for call services 31e41f4b71Sopenharmony_ci OnDataReport, // Callback function for cellular data services 32e41f4b71Sopenharmony_ci OnModemReport, // Callback function for modem services 33e41f4b71Sopenharmony_ci OnNetworkReport, // Callback function for network search services 34e41f4b71Sopenharmony_ci OnSimReport, // Callback function for SIM card services 35e41f4b71Sopenharmony_ci OnSmsReport // Callback function for SMS services 36e41f4b71Sopenharmony_ci }; 37e41f4b71Sopenharmony_ci ``` 38e41f4b71Sopenharmony_ci 39e41f4b71Sopenharmony_ci 40e41f4b71Sopenharmony_ci2. Create the **g\_reader** main thread to enable message looping. 41e41f4b71Sopenharmony_ci 42e41f4b71Sopenharmony_ci ``` 43e41f4b71Sopenharmony_ci pthread_attr_t t; 44e41f4b71Sopenharmony_ci pthread_attr_init(&t); 45e41f4b71Sopenharmony_ci pthread_attr_setdetachstate(&t, PTHREAD_CREATE_DETACHED); 46e41f4b71Sopenharmony_ci ret = pthread_create(&g_reader, &t, ReaderLoop, &t); // Create the g_reader thread. 47e41f4b71Sopenharmony_ci ``` 48e41f4b71Sopenharmony_ci 49e41f4b71Sopenharmony_ci 50e41f4b71Sopenharmony_ci3. 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. 51e41f4b71Sopenharmony_ci 52e41f4b71Sopenharmony_ci ``` 53e41f4b71Sopenharmony_ci g_fd = open(g_devicePath, O_RDWR); // Open the device node specified by g_devicePath. 54e41f4b71Sopenharmony_ci pthread_attr_init(&attr); 55e41f4b71Sopenharmony_ci pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 56e41f4b71Sopenharmony_ci ret = pthread_create(&g_eventListeners, &attr, EventListeners, NULL); 57e41f4b71Sopenharmony_ci ``` 58e41f4b71Sopenharmony_ci 59e41f4b71Sopenharmony_ci 60e41f4b71Sopenharmony_ci4. Return the function pointer of the service request API. 61e41f4b71Sopenharmony_ci 62e41f4b71Sopenharmony_ci ``` 63e41f4b71Sopenharmony_ci // Structure for the service request API of the call module 64e41f4b71Sopenharmony_ci typedef struct { 65e41f4b71Sopenharmony_ci // Obtain the call list. 66e41f4b71Sopenharmony_ci void (*GetCallList)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 67e41f4b71Sopenharmony_ci // Make a call. 68e41f4b71Sopenharmony_ci void (*Dial)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 69e41f4b71Sopenharmony_ci // Disconnect a call. 70e41f4b71Sopenharmony_ci void (*Hangup)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 71e41f4b71Sopenharmony_ci // Reject a call. 72e41f4b71Sopenharmony_ci void (*Reject)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 73e41f4b71Sopenharmony_ci // Answer a call. 74e41f4b71Sopenharmony_ci void (*Answer)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 75e41f4b71Sopenharmony_ci } HRilCallReq; 76e41f4b71Sopenharmony_ci 77e41f4b71Sopenharmony_ci // Callback function pointers of the call module 78e41f4b71Sopenharmony_ci static const HRilCallReq g_callReqOps = { 79e41f4b71Sopenharmony_ci .GetCallList = ReqGetCallList, // Obtain the call list. 80e41f4b71Sopenharmony_ci .Dial = ReqDial, // Make a call. 81e41f4b71Sopenharmony_ci .Hangup = ReqHangup, // Disconnect a call. 82e41f4b71Sopenharmony_ci .Reject = ReqReject, // Reject a call. 83e41f4b71Sopenharmony_ci .Answer = ReqAnswer, // Answer a call. 84e41f4b71Sopenharmony_ci }; 85e41f4b71Sopenharmony_ci 86e41f4b71Sopenharmony_ci // Service request structure 87e41f4b71Sopenharmony_ci typedef struct { 88e41f4b71Sopenharmony_ci const HRilCallReq *callOps; // Pointer to the structure of call service requests 89e41f4b71Sopenharmony_ci const HRilSimReq *simOps; // Pointer to the structure of SIM card service requests 90e41f4b71Sopenharmony_ci const HRilSmsReq *smsOps; // Pointer to the structure of SMS and MMS service requests 91e41f4b71Sopenharmony_ci const HRilDataReq *dataOps; // Pointer to the structure of cellular data service requests 92e41f4b71Sopenharmony_ci const HRilNetworkReq *networkOps; // Pointer to the structure of network search service requests 93e41f4b71Sopenharmony_ci const HRilModemReq *modemOps; // Pointer to the structure of modem service requests 94e41f4b71Sopenharmony_ci } HRilOps; 95e41f4b71Sopenharmony_ci 96e41f4b71Sopenharmony_ci // Service request APIs 97e41f4b71Sopenharmony_ci HRilOps g_hrilOps = { 98e41f4b71Sopenharmony_ci .callOps = &g_callReqOps, // API for call service requests 99e41f4b71Sopenharmony_ci .simOps = &g_simReqOps, // API for SIM card service requests 100e41f4b71Sopenharmony_ci .smsOps = &g_smsReqOps, // API for SMS and MMS service requests 101e41f4b71Sopenharmony_ci .networkOps = &g_networkReqOps, // API for cellular data service requests 102e41f4b71Sopenharmony_ci .dataOps = &g_dataReqOps, // API for network search service requests 103e41f4b71Sopenharmony_ci .modemOps = &g_modemReqOps, // API for modem service requests 104e41f4b71Sopenharmony_ci }; 105e41f4b71Sopenharmony_ci ``` 106e41f4b71Sopenharmony_ci 107e41f4b71Sopenharmony_ci 108e41f4b71Sopenharmony_ci### Debugging and Verification 109e41f4b71Sopenharmony_ci 110e41f4b71Sopenharmony_ci1. Use the [hdc\_std](../subsystems/subsys-toolchain-hdc-guide.md#how-to-obtain) 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](#integrating-modem-vendor-libraries). 111e41f4b71Sopenharmony_ci 112e41f4b71Sopenharmony_ci ``` 113e41f4b71Sopenharmony_ci hdc_std file send libril_vendor.z.so /system/lib/ 114e41f4b71Sopenharmony_ci ``` 115e41f4b71Sopenharmony_ci 116e41f4b71Sopenharmony_ci2. Reboot the debugging device. 117e41f4b71Sopenharmony_ci 118e41f4b71Sopenharmony_ci ``` 119e41f4b71Sopenharmony_ci hdc_std shell sync 120e41f4b71Sopenharmony_ci hdc_std shell reboot 121e41f4b71Sopenharmony_ci ``` 122e41f4b71Sopenharmony_ci 123e41f4b71Sopenharmony_ci3. 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: 124e41f4b71Sopenharmony_ci 125e41f4b71Sopenharmony_ci ``` 126e41f4b71Sopenharmony_ci 09-02 07:40:47.807 455 455 I 01f08/HrilHdf: [LoadVendor-(hril_hdf.c:148)] RilInit LoadVendor start with rilLibPath:libril_vendor.z.so 127e41f4b71Sopenharmony_ci 09-02 07:40:47.830 455 455 I 01f08/HrilHdf: [LoadVendor-(hril_hdf.c:163)] HRilRegOps completed 128e41f4b71Sopenharmony_ci ``` 129e41f4b71Sopenharmony_ci 130e41f4b71Sopenharmony_ci 131e41f4b71Sopenharmony_ci## Responding to Modem Service Requests 132e41f4b71Sopenharmony_ci 133e41f4b71Sopenharmony_ci### When to Use 134e41f4b71Sopenharmony_ci 135e41f4b71Sopenharmony_ciAfter 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. 136e41f4b71Sopenharmony_ci 137e41f4b71Sopenharmony_ci### Available APIs 138e41f4b71Sopenharmony_ci 139e41f4b71Sopenharmony_ciThe following table describes the APIs for responding to modem service requests, with the dial module as an example. 140e41f4b71Sopenharmony_ci 141e41f4b71Sopenharmony_ci**Table 2** APIs for responding to modem service requests 142e41f4b71Sopenharmony_ci 143e41f4b71Sopenharmony_ci| API | Description | 144e41f4b71Sopenharmony_ci| -------- | -------- | 145e41f4b71Sopenharmony_ci| void ReqDial(ReqDataInfo \*requestInfo, const void \*data, size_t dataLen); | Processes number dial requests.<br>Input parameters:<br>**requestInfo**: request type<br/>**data**: called number<br/>**dataLen**: data length<br/>Return value: none | 146e41f4b71Sopenharmony_ci| void (\*OnCallReport)(struct ReportInfo reportInfo, const void \*data, size_t dataLen); | Reports the execution result of a service request to RIL Adapter.<br>Input parameters:<br>**reportInfo**: request type<br/>**data**: called number<br/>**dataLen**: data length<br/>Return value: none | 147e41f4b71Sopenharmony_ci 148e41f4b71Sopenharmony_ci### How to Develop 149e41f4b71Sopenharmony_ci 150e41f4b71Sopenharmony_ci1. Implement processing of dial requests in the **ReqDial\(\)** API. 151e41f4b71Sopenharmony_ci 152e41f4b71Sopenharmony_ci ``` 153e41f4b71Sopenharmony_ci // Implement the API for processing dial requests. 154e41f4b71Sopenharmony_ci void ReqDial(ReqDataInfo *requestInfo, const void *data, size_t dataLen) 155e41f4b71Sopenharmony_ci { 156e41f4b71Sopenharmony_ci HRilDial *pDial = NULL; 157e41f4b71Sopenharmony_ci char cmd[MAX_BUFF_SIZE] = {0}; 158e41f4b71Sopenharmony_ci const char *clir = NULL; 159e41f4b71Sopenharmony_ci int ret; 160e41f4b71Sopenharmony_ci int err = HRIL_ERR_SUCCESS; 161e41f4b71Sopenharmony_ci struct ReportInfo reportInfo = {}; 162e41f4b71Sopenharmony_ci ResponseInfo *pResponse = NULL; 163e41f4b71Sopenharmony_ci if (data == NULL) { 164e41f4b71Sopenharmony_ci TELEPHONY_LOGE("data is null!!!"); 165e41f4b71Sopenharmony_ci err = HRIL_ERR_INVALID_PARAMETER; 166e41f4b71Sopenharmony_ci reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0); 167e41f4b71Sopenharmony_ci OnCallReport(reportInfo, NULL, 0); 168e41f4b71Sopenharmony_ci return; 169e41f4b71Sopenharmony_ci } 170e41f4b71Sopenharmony_ci pDial = (HRilDial *)data; 171e41f4b71Sopenharmony_ci switch (pDial->clir) { 172e41f4b71Sopenharmony_ci case CALL_CLIR_INVOCATION: 173e41f4b71Sopenharmony_ci clir = "I"; 174e41f4b71Sopenharmony_ci break; /* invocation */ 175e41f4b71Sopenharmony_ci case CALL_CLIR_SUPPRESSION: 176e41f4b71Sopenharmony_ci clir = "i"; 177e41f4b71Sopenharmony_ci break; /* suppression */ 178e41f4b71Sopenharmony_ci case CALL_CLIR_SUBSCRIPTION_DEFUALT: 179e41f4b71Sopenharmony_ci default: 180e41f4b71Sopenharmony_ci clir = ""; 181e41f4b71Sopenharmony_ci break; /* subscription default */ 182e41f4b71Sopenharmony_ci } 183e41f4b71Sopenharmony_ci (void)sprintf_s(cmd, MAX_BUFF_SIZE, "ATD%s%s;", pDial->address, clir); 184e41f4b71Sopenharmony_ci ret = SendCommandLock(cmd, NULL, 0, &pResponse); // Send the AT command. 185e41f4b71Sopenharmony_ci ...... 186e41f4b71Sopenharmony_ci } 187e41f4b71Sopenharmony_ci ``` 188e41f4b71Sopenharmony_ci 189e41f4b71Sopenharmony_ci2. After the modem executes the dial command, report the execution result to RIL Adapter via **OnCallReport\(\)**. 190e41f4b71Sopenharmony_ci 191e41f4b71Sopenharmony_ci ``` 192e41f4b71Sopenharmony_ci ret = SendCommandLock(cmd, NULL, 0, &pResponse); 193e41f4b71Sopenharmony_ci if (ret != 0 || (pResponse != NULL && pResponse->success == 0)) { 194e41f4b71Sopenharmony_ci TELEPHONY_LOGE("ATD send failed"); 195e41f4b71Sopenharmony_ci err = HRIL_ERR_GENERIC_FAILURE; 196e41f4b71Sopenharmony_ci } 197e41f4b71Sopenharmony_ci reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0); 198e41f4b71Sopenharmony_ci OnCallReport(reportInfo, NULL, 0); // Invoke the callback function of the call service. 199e41f4b71Sopenharmony_ci ``` 200e41f4b71Sopenharmony_ci 201e41f4b71Sopenharmony_ci 202e41f4b71Sopenharmony_ci### Debugging and Verification 203e41f4b71Sopenharmony_ci 204e41f4b71Sopenharmony_ci1. Use the [hdc\_std](../subsystems/subsys-toolchain-hdc-guide.md#how-to-obtain) 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. 205e41f4b71Sopenharmony_ci 206e41f4b71Sopenharmony_ci ``` 207e41f4b71Sopenharmony_ci hdc_std file send libril_vendor.z.so /system/lib/ 208e41f4b71Sopenharmony_ci ``` 209e41f4b71Sopenharmony_ci 210e41f4b71Sopenharmony_ci2. Reboot the debugging device. 211e41f4b71Sopenharmony_ci 212e41f4b71Sopenharmony_ci ``` 213e41f4b71Sopenharmony_ci hdc_std shell sync 214e41f4b71Sopenharmony_ci hdc_std shell reboot 215e41f4b71Sopenharmony_ci ``` 216e41f4b71Sopenharmony_ci 217e41f4b71Sopenharmony_ci3. 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. 218e41f4b71Sopenharmony_ci 219e41f4b71Sopenharmony_ci ``` 220e41f4b71Sopenharmony_ci hdc_std shell 221e41f4b71Sopenharmony_ci # ./system/bin/ril_adapter_test 222e41f4b71Sopenharmony_ci ----> Test Enter --------->Call--------------------- 223e41f4b71Sopenharmony_ci 224e41f4b71Sopenharmony_ci 1----> RilUnitTest::OnRequestCallDialTest 225e41f4b71Sopenharmony_ci 2----> RilUnitTest:: OnRequestCallHangupTest 226e41f4b71Sopenharmony_ci 3----> RilUnitTest:: OnRequestCallAnswerTest 227e41f4b71Sopenharmony_ci 4----> RilUnitTest::OnRequestCallGetCurrentCallsStatusTest 228e41f4b71Sopenharmony_ci 5----> RilUnitTest::OnRequestRefusedCallTest 229e41f4b71Sopenharmony_ci 230e41f4b71Sopenharmony_ci 1 231e41f4b71Sopenharmony_ci ``` 232e41f4b71Sopenharmony_ci 233e41f4b71Sopenharmony_ci4. 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: 234e41f4b71Sopenharmony_ci 235e41f4b71Sopenharmony_ci ``` 236e41f4b71Sopenharmony_ci 09-02 07:55:09.073 455 2059 I 01f08/RilVendor: [SendCommandLock-(at_support.c:226)] command ATD18675231804;, NeedATPause:0, atCmd:AT 237e41f4b71Sopenharmony_ci 09-02 07:55:09.099 455 2053 I 01f08/Rilvendor: [ProcessResponse-(at_support.c:159)] processLine line = OK 238e41f4b71Sopenharmony_ci 09-02 07:55:09.100 455 2053 E 01f08/RilVendor: [ReportStrWith-(vendor_util.c:63)] str or prefix parameter is null. 239e41f4b71Sopenharmony_ci 09-02 07:55:09.100 455 2053 E 01f08/RilVendor: [ProcessLastResponse-(vendor_channel.c:77)] g_bufferCur endLine is null 240e41f4b71Sopenharmony_ci 09-02 07:55:09.100 455 2059 I 01f08/RilVendor: [SendCommandLock-(at_support.c:243)] err = 0 241e41f4b71Sopenharmony_ci 09-02 07:55:09.100 455 2053 I 01f08/RilVendor: [ProcessResponse-(at_support.c:159)] processLine line = ^ORIG:1,0 242e41f4b71Sopenharmony_ci ``` 243e41f4b71Sopenharmony_ci 244e41f4b71Sopenharmony_ci 245e41f4b71Sopenharmony_ci## Reporting Modem Events 246e41f4b71Sopenharmony_ci 247e41f4b71Sopenharmony_ci### When to Use 248e41f4b71Sopenharmony_ci 249e41f4b71Sopenharmony_ciA 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. 250e41f4b71Sopenharmony_ci 251e41f4b71Sopenharmony_ci### Available APIs 252e41f4b71Sopenharmony_ci 253e41f4b71Sopenharmony_ciThe following table describes the API for reporting modem events. 254e41f4b71Sopenharmony_ci 255e41f4b71Sopenharmony_ci**Table 3** API for reporting modem events 256e41f4b71Sopenharmony_ci 257e41f4b71Sopenharmony_ci| API | Description | 258e41f4b71Sopenharmony_ci| -------- | -------- | 259e41f4b71Sopenharmony_ci| void OnNotifyOps(const char \*s, const char \*smsPdu) | Distributes the events reported by the modem.<br>Input parameters:<br/>**s**: AT command prefix<br/>**smsPdu**: PDU of the SMS message<br/>Return value: none | 260e41f4b71Sopenharmony_ci 261e41f4b71Sopenharmony_ci### How to Develop 262e41f4b71Sopenharmony_ci 263e41f4b71Sopenharmony_ci1. 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. 264e41f4b71Sopenharmony_ci 265e41f4b71Sopenharmony_ci ``` 266e41f4b71Sopenharmony_ci // Parse the data reported by the modem as events proactively reported by the corresponding module. 267e41f4b71Sopenharmony_ci void OnNotifyOps(const char *s, const char *smsPdu) 268e41f4b71Sopenharmony_ci { 269e41f4b71Sopenharmony_ci int ret = 0; 270e41f4b71Sopenharmony_ci struct ReportInfo reportInfo = {0}; 271e41f4b71Sopenharmony_ci reportInfo.error = HRIL_ERR_SUCCESS; 272e41f4b71Sopenharmony_ci reportInfo.type = HRIL_NOTIFICATION; 273e41f4b71Sopenharmony_ci if (GetRadioState() == HRIL_RADIO_POWER_STATE_UNAVAILABLE) { 274e41f4b71Sopenharmony_ci return; 275e41f4b71Sopenharmony_ci } 276e41f4b71Sopenharmony_ci TELEPHONY_LOGD("enter to [%{public}s]:%{public}s", s, smsPdu); 277e41f4b71Sopenharmony_ci // Determine the type of the proactively reported events based on the AT command. 278e41f4b71Sopenharmony_ci if (ReportStrWith(s, "+CRING:") || ReportStrWith(s, "RING") || ReportStrWith(s, "IRING") || 279e41f4b71Sopenharmony_ci ReportStrWith(s, "NO CARRIER") || ReportStrWith(s, "+CCWA") || ReportStrWith(s, "^CCALLSTATE") || 280e41f4b71Sopenharmony_ci ReportStrWith(s, "^CEND") || ReportStrWith(s, "^CCWA")) { 281e41f4b71Sopenharmony_ci reportInfo.notifyId = HNOTI_CALL_STATE_UPDATED; 282e41f4b71Sopenharmony_ci OnCallReport(reportInfo, NULL, 0); 283e41f4b71Sopenharmony_ci } else if (ReportStrWith(s, "+CMT:")) { 284e41f4b71Sopenharmony_ci reportInfo.notifyId = HNOTI_SMS_NEW_SMS; 285e41f4b71Sopenharmony_ci OnSmsReport(reportInfo, (void *)smsPdu, strlen(smsPdu)); 286e41f4b71Sopenharmony_ci } 287e41f4b71Sopenharmony_ci // Report the events of each module to the hril layer. 288e41f4b71Sopenharmony_ci ... 289e41f4b71Sopenharmony_ci } 290e41f4b71Sopenharmony_ci ``` 291e41f4b71Sopenharmony_ci 292e41f4b71Sopenharmony_ci 293e41f4b71Sopenharmony_ci2. Distribute the reported events from the **hril** layer to the Telephony Service layer. 294e41f4b71Sopenharmony_ci 295e41f4b71Sopenharmony_ci ``` 296e41f4b71Sopenharmony_ci // Report the call status proactively. 297e41f4b71Sopenharmony_ci int32_t HRilCall::CallStateUpdated( 298e41f4b71Sopenharmony_ci int32_t slotId, int32_t notifyType, const HRilErrno e, const void *response, size_t responseLen) 299e41f4b71Sopenharmony_ci { 300e41f4b71Sopenharmony_ci struct HdfSBuf *dataSbuf = HdfSBufTypedObtain(SBUF_IPC); 301e41f4b71Sopenharmony_ci if (serviceCallbackNotify_ == nullptr) { 302e41f4b71Sopenharmony_ci TELEPHONY_LOGE("RilAdapter serviceCallbackNotify_ is null"); 303e41f4b71Sopenharmony_ci HdfSBufRecycle(dataSbuf); 304e41f4b71Sopenharmony_ci return HDF_FAILURE; 305e41f4b71Sopenharmony_ci } 306e41f4b71Sopenharmony_ci // Distribute events. 307e41f4b71Sopenharmony_ci int32_t ret = serviceCallbackNotify_->dispatcher->Dispatch( 308e41f4b71Sopenharmony_ci serviceCallbackNotify_, HNOTI_CALL_STATE_UPDATED, dataSbuf, nullptr); 309e41f4b71Sopenharmony_ci if (ret != HDF_SUCCESS) { 310e41f4b71Sopenharmony_ci HdfSBufRecycle(dataSbuf); 311e41f4b71Sopenharmony_ci return HDF_FAILURE; 312e41f4b71Sopenharmony_ci } 313e41f4b71Sopenharmony_ci HdfSBufRecycle(dataSbuf); 314e41f4b71Sopenharmony_ci return HDF_SUCCESS; 315e41f4b71Sopenharmony_ci } 316e41f4b71Sopenharmony_ci ``` 317e41f4b71Sopenharmony_ci 318e41f4b71Sopenharmony_ci 319e41f4b71Sopenharmony_ci### Debugging and Verification 320e41f4b71Sopenharmony_ci 321e41f4b71Sopenharmony_ci1. Use the [hdc\_std](../subsystems/subsys-toolchain-hdc-guide.md#how-to-obtain) 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. 322e41f4b71Sopenharmony_ci 323e41f4b71Sopenharmony_ci ``` 324e41f4b71Sopenharmony_ci hdc_std file send libril_vendor.z.so /system/lib/ 325e41f4b71Sopenharmony_ci ``` 326e41f4b71Sopenharmony_ci 327e41f4b71Sopenharmony_ci2. Reboot the debugging device. 328e41f4b71Sopenharmony_ci 329e41f4b71Sopenharmony_ci ``` 330e41f4b71Sopenharmony_ci hdc_std shell sync 331e41f4b71Sopenharmony_ci hdc_std shell reboot 332e41f4b71Sopenharmony_ci ``` 333e41f4b71Sopenharmony_ci 334e41f4b71Sopenharmony_ci3. 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. 335e41f4b71Sopenharmony_ci 336e41f4b71Sopenharmony_ci ``` 337e41f4b71Sopenharmony_ci hdc_std shell 338e41f4b71Sopenharmony_ci # ./system/bin/ril_adapter_test 339e41f4b71Sopenharmony_ci ----> Test Enter --------->Call--------------------- 340e41f4b71Sopenharmony_ci 341e41f4b71Sopenharmony_ci 1----> RilUnitTest::OnRequestCallDialTest 342e41f4b71Sopenharmony_ci 2----> RilUnitTest:: OnRequestCallHangupTest 343e41f4b71Sopenharmony_ci 3----> RilUnitTest:: OnRequestCallAnswerTest 344e41f4b71Sopenharmony_ci 4----> RilUnitTest::OnRequestCallGetCurrentCallsStatusTest 345e41f4b71Sopenharmony_ci 5----> RilUnitTest::OnRequestRefusedCallTest 346e41f4b71Sopenharmony_ci 347e41f4b71Sopenharmony_ci 1 348e41f4b71Sopenharmony_ci ``` 349e41f4b71Sopenharmony_ci 350e41f4b71Sopenharmony_ci4. 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: 351e41f4b71Sopenharmony_ci 352e41f4b71Sopenharmony_ci ``` 353e41f4b71Sopenharmony_ci 01-01 00:08:01.334 546 551 D 02b01/TelRilTest: [DialResponse-(tel_ril_call.cpp:280)] DialResponse --> radioResponseInfo->serial:2, radioResponseInfo->error:0 354e41f4b71Sopenharmony_ci 01-01 00:08:01.334 546 557 D 02b01/TelRilTest: [ProcessEvent-(tel_ril_test.cpp:1262)] TelRilTest::DemoHandler::ProcessEvent --> eventId:101 355e41f4b71Sopenharmony_ci 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: [ReadResponse-(channel.c:93)] g_bufferCur : 356e41f4b71Sopenharmony_ci 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: ^ORIG:1,0 357e41f4b71Sopenharmony_ci 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: [ReadResponse-(channel.c:108)] AT< ^ORIG:1,0 358e41f4b71Sopenharmony_ci 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: [ProcessResponse-(at_support.c:137)] processLine line = ^ORIG:1,0 359e41f4b71Sopenharmony_ci 01-01 00:08:01.334 143 512 D 02b01/Rilvendor: [OnNotifyOps-(vendor_report.c:126)] enter to [^ORIG:1,0]:(null) 360e41f4b71Sopenharmony_ci 01-01 00:08:01.335 143 512 W 02b01/Rilvendor: [OnNotifyOps-(vendor_report.c:167)] enter to is unrecognized command: ^ORIG:1,0 361e41f4b71Sopenharmony_ci 01-01 00:08:01.335 143 512 D 02b01/Rilvendor: [ProcessLastResponse-(channel.c:37)] last data more than one line , FindEndOfLine g_bufferCur: 362e41f4b71Sopenharmony_ci 01-01 00:08:01.335 143 512 E 02b01/Rilvendor: [ProcessLastResponse-(channel.c:39)] g_bufferCur endLine is null 363e41f4b71Sopenharmony_ci 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: [ReadResponse-(channel.c:93)] g_bufferCur : 364e41f4b71Sopenharmony_ci 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: ^CCALLSTATE: 1,0,1 365e41f4b71Sopenharmony_ci 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: [ReadResponse-(channel.c:108)] AT< ^CCALLSTATE: 1,0,1 366e41f4b71Sopenharmony_ci 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: [ProcessResponse-(at_support.c:137)] processLine line = ^CCALLSTATE: 1,0,1 367e41f4b71Sopenharmony_ci 01-01 00:08:01.336 143 512 D 02b01/Rilvendor: [OnNotifyOps-(vendor_report.c:126)] enter to [^CCALLSTATE: 1,0,1]:(null) 368e41f4b71Sopenharmony_ci 01-01 00:08:01.336 546 551 D 02b01/CoreService: [OnRemoteRequest-(tel_ril_manager.cpp:80)] RilManager OnRemoteRequest code:1001 369e41f4b71Sopenharmony_ci 01-01 00:08:01.336 546 551 D 02b01/CoreService: [NotifyObserver-(observer_handler.cpp:76)] handler->SendEvent:8 370e41f4b71Sopenharmony_ci ``` 371e41f4b71Sopenharmony_ci 372e41f4b71Sopenharmony_ci 373e41f4b71Sopenharmony_ci### Development Examples 374e41f4b71Sopenharmony_ci 375e41f4b71Sopenharmony_ci- **Outgoing Call** 376e41f4b71Sopenharmony_ci 377e41f4b71Sopenharmony_ci The following figure shows the API calling for an outgoing call. 378e41f4b71Sopenharmony_ci 379e41f4b71Sopenharmony_ci **Figure 1** Time sequence of API calling for an outgoing call<a name="fig494mcpsimp"></a> 380e41f4b71Sopenharmony_ci 381e41f4b71Sopenharmony_ci 382e41f4b71Sopenharmony_ci  383e41f4b71Sopenharmony_ci 384e41f4b71Sopenharmony_ci 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\(\)**. 385e41f4b71Sopenharmony_ci 386e41f4b71Sopenharmony_ci ``` 387e41f4b71Sopenharmony_ci // Callback function pointer of the call module 388e41f4b71Sopenharmony_ci static const HRilCallReq g_callReqOps = { 389e41f4b71Sopenharmony_ci .GetCallList = ReqGetCallList, // Obtain the call list. 390e41f4b71Sopenharmony_ci .Dial = ReqDial, // Make a call. 391e41f4b71Sopenharmony_ci .Hangup = ReqHangup, // Disconnect a call. 392e41f4b71Sopenharmony_ci .Reject = ReqReject, // Reject a call. 393e41f4b71Sopenharmony_ci .Answer = ReqAnswer, // Answer a call. 394e41f4b71Sopenharmony_ci }; 395e41f4b71Sopenharmony_ci 396e41f4b71Sopenharmony_ci // Service request APIs 397e41f4b71Sopenharmony_ci HRilOps g_hrilOps = { 398e41f4b71Sopenharmony_ci .callOps = &g_callReqOps, // API for call service requests 399e41f4b71Sopenharmony_ci .simOps = &g_simReqOps, // API for SIM card service requests 400e41f4b71Sopenharmony_ci .smsOps = &g_smsReqOps, // API for SMS and MMS service requests 401e41f4b71Sopenharmony_ci .networkOps = &g_networkReqOps, // API for cellular data service requests 402e41f4b71Sopenharmony_ci .dataOps = &g_dataReqOps, // API for network search service requests 403e41f4b71Sopenharmony_ci .modemOps = &g_modemReqOps, // API for modem service requests 404e41f4b71Sopenharmony_ci }; 405e41f4b71Sopenharmony_ci 406e41f4b71Sopenharmony_ci // Implement the API for processing dial requests. 407e41f4b71Sopenharmony_ci void ReqDial(ReqDataInfo *requestInfo, const void *data, size_t dataLen) 408e41f4b71Sopenharmony_ci { 409e41f4b71Sopenharmony_ci HRilDial *pDial = NULL; 410e41f4b71Sopenharmony_ci char cmd[MAX_BUFF_SIZE] = {0}; 411e41f4b71Sopenharmony_ci const char *clir = NULL; 412e41f4b71Sopenharmony_ci int ret; 413e41f4b71Sopenharmony_ci int err = HRIL_ERR_SUCCESS; 414e41f4b71Sopenharmony_ci struct ReportInfo reportInfo = {}; 415e41f4b71Sopenharmony_ci ResponseInfo *pResponse = NULL; 416e41f4b71Sopenharmony_ci if (data == NULL) { 417e41f4b71Sopenharmony_ci TELEPHONY_LOGE("data is null!!!"); 418e41f4b71Sopenharmony_ci err = HRIL_ERR_INVALID_PARAMETER; 419e41f4b71Sopenharmony_ci reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0); 420e41f4b71Sopenharmony_ci OnCallReport(reportInfo, NULL, 0); 421e41f4b71Sopenharmony_ci return; 422e41f4b71Sopenharmony_ci } 423e41f4b71Sopenharmony_ci pDial = (HRilDial *)data; 424e41f4b71Sopenharmony_ci switch (pDial->clir) { 425e41f4b71Sopenharmony_ci case CALL_CLIR_INVOCATION: 426e41f4b71Sopenharmony_ci clir = "I"; 427e41f4b71Sopenharmony_ci break; /* invocation */ 428e41f4b71Sopenharmony_ci case CALL_CLIR_SUPPRESSION: 429e41f4b71Sopenharmony_ci clir = "i"; 430e41f4b71Sopenharmony_ci break; /* suppression */ 431e41f4b71Sopenharmony_ci case CALL_CLIR_SUBSCRIPTION_DEFUALT1: 432e41f4b71Sopenharmony_ci default: 433e41f4b71Sopenharmony_ci clir = ""; 434e41f4b71Sopenharmony_ci break; /* subscription default */ 435e41f4b71Sopenharmony_ci } 436e41f4b71Sopenharmony_ci (void)sprintf_s(cmd, MAX_BUFF_SIZE, "ATD%s%s;", pDial->address, clir); 437e41f4b71Sopenharmony_ci ret = SendCommandLock(cmd, NULL, 0, &pResponse); // Send the AT command. 438e41f4b71Sopenharmony_ci if (ret != 0) { 439e41f4b71Sopenharmony_ci err = HRIL_ERR_CMD_SEND_FAILURE; 440e41f4b71Sopenharmony_ci TELEPHONY_LOGE("ATD send failed"); 441e41f4b71Sopenharmony_ci } else { 442e41f4b71Sopenharmony_ci if (pResponse != NULL && pResponse->success == 0) { 443e41f4b71Sopenharmony_ci TELEPHONY_LOGE("ReqDial return ERROR"); 444e41f4b71Sopenharmony_ci err = HRIL_ERR_CMD_NO_CARRIER; 445e41f4b71Sopenharmony_ci } 446e41f4b71Sopenharmony_ci } 447e41f4b71Sopenharmony_ci reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0); 448e41f4b71Sopenharmony_ci OnCallReport(reportInfo, NULL, 0); // Invoke the callback function of the call service. 449e41f4b71Sopenharmony_ci FreeResponseInfo(pResponse); 450e41f4b71Sopenharmony_ci } 451e41f4b71Sopenharmony_ci ``` 452e41f4b71Sopenharmony_ci 453e41f4b71Sopenharmony_ci 454e41f4b71Sopenharmony_ci- **Incoming Call** 455e41f4b71Sopenharmony_ci 456e41f4b71Sopenharmony_ci The following figure shows the API calling of an incoming call. 457e41f4b71Sopenharmony_ci 458e41f4b71Sopenharmony_ci **Figure 2** Time sequence of API calling for an incoming call<a name="fig556mcpsimp"></a> 459e41f4b71Sopenharmony_ci 460e41f4b71Sopenharmony_ci 461e41f4b71Sopenharmony_ci  462e41f4b71Sopenharmony_ci 463e41f4b71Sopenharmony_ci 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. 464e41f4b71Sopenharmony_ci 465e41f4b71Sopenharmony_ci 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\)**. 466e41f4b71Sopenharmony_ci 467e41f4b71Sopenharmony_ci ``` 468e41f4b71Sopenharmony_ci // Parse the data reported by the modem as events proactively reported by the corresponding module. 469e41f4b71Sopenharmony_ci void OnNotifyOps(const char *s, const char *smsPdu) 470e41f4b71Sopenharmony_ci { 471e41f4b71Sopenharmony_ci int ret = 0; 472e41f4b71Sopenharmony_ci struct ReportInfo reportInfo = {0}; 473e41f4b71Sopenharmony_ci reportInfo.error = HRIL_ERR_SUCCESS; 474e41f4b71Sopenharmony_ci reportInfo.type = HRIL_NOTIFICATION; 475e41f4b71Sopenharmony_ci if (GetRadioState() == HRIL_RADIO_POWER_STATE_UNAVAILABLE) { 476e41f4b71Sopenharmony_ci return; 477e41f4b71Sopenharmony_ci } 478e41f4b71Sopenharmony_ci TELEPHONY_LOGD("enter to [%{public}s]:%{public}s", s, smsPdu); 479e41f4b71Sopenharmony_ci // Determine the type of the proactively reported events based on the AT command. 480e41f4b71Sopenharmony_ci if (ReportStrWith(s, "+CRING:") || ReportStrWith(s, "RING") || ReportStrWith(s, "IRING") || 481e41f4b71Sopenharmony_ci ReportStrWith(s, "NO CARRIER") || ReportStrWith(s, "+CCWA") || ReportStrWith(s, "^CCALLSTATE") || 482e41f4b71Sopenharmony_ci ReportStrWith(s, "^CEND") || ReportStrWith(s, "^CCWA")) { 483e41f4b71Sopenharmony_ci reportInfo.notifyId = HNOTI_CALL_STATE_UPDATED; 484e41f4b71Sopenharmony_ci OnCallReport(reportInfo, NULL, 0); // Invoke the callback function of the call service. 485e41f4b71Sopenharmony_ci } else if (ReportStrWith(s, "+CMT:")) { 486e41f4b71Sopenharmony_ci reportInfo.notifyId = HNOTI_SMS_NEW_SMS; 487e41f4b71Sopenharmony_ci OnSmsReport(reportInfo, (void *)smsPdu, strlen(smsPdu)); 488e41f4b71Sopenharmony_ci } 489e41f4b71Sopenharmony_ci // add your codes 490e41f4b71Sopenharmony_ci ...... 491e41f4b71Sopenharmony_ci } 492e41f4b71Sopenharmony_ci ``` 493e41f4b71Sopenharmony_ci 494e41f4b71Sopenharmony_ci 495e41f4b71Sopenharmony_ci## Integrating Modem Vendor Libraries 496e41f4b71Sopenharmony_ci 497e41f4b71Sopenharmony_ci### Configuring Compilation Information 498e41f4b71Sopenharmony_ci 499e41f4b71Sopenharmony_ciCompile 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](#initializing-a-modem-vendor-library). The following is an example of **BUILD.gn**: 500e41f4b71Sopenharmony_ci 501e41f4b71Sopenharmony_ci``` 502e41f4b71Sopenharmony_ciimport("//build/ohos.gni") 503e41f4b71Sopenharmony_ciRIL_ADAPTER = "//base/telephony" 504e41f4b71Sopenharmony_ciohos_shared_library("ril_vendor") { // Modem vendor library 505e41f4b71Sopenharmony_ci sources = [ // Source files to compile 506e41f4b71Sopenharmony_ci "at_call.c", 507e41f4b71Sopenharmony_ci "at_data.c", 508e41f4b71Sopenharmony_ci "xxx.c", 509e41f4b71Sopenharmony_ci ] 510e41f4b71Sopenharmony_ci include_dirs = [ // Header files 511e41f4b71Sopenharmony_ci "$RIL_ADAPTER/ril_adapter/vendor/include", 512e41f4b71Sopenharmony_ci "$RIL_ADAPTER/ril_adapter/interfaces/innerkits", 513e41f4b71Sopenharmony_ci "include", 514e41f4b71Sopenharmony_ci ] 515e41f4b71Sopenharmony_ci deps = [ // Internal dependencies 516e41f4b71Sopenharmony_ci "//drivers/adapter/uhdf2/osal:libhdf_utils", 517e41f4b71Sopenharmony_ci "//base/telephony/core_service/utils:libtelephony_common", 518e41f4b71Sopenharmony_ci ] 519e41f4b71Sopenharmony_ci external_deps = [ "hilog:libhilog" ] // External dependencies 520e41f4b71Sopenharmony_ci 521e41f4b71Sopenharmony_ci part_name = "ril_adapter" // Part name 522e41f4b71Sopenharmony_ci subsystem_name = "telephony" // Subsystem name 523e41f4b71Sopenharmony_ci} 524e41f4b71Sopenharmony_ci``` 525e41f4b71Sopenharmony_ci 526e41f4b71Sopenharmony_ci### Debugging and Verification 527e41f4b71Sopenharmony_ci 528e41f4b71Sopenharmony_ci1. Compile the code. 529e41f4b71Sopenharmony_ci2. 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. 530e41f4b71Sopenharmony_ci 531