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&nbsp;HRilOps&nbsp;\*RilInitOps(const&nbsp;struct&nbsp;HRilReport&nbsp;\*&nbsp;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&nbsp;ReqDial(ReqDataInfo&nbsp;\*requestInfo,&nbsp;const&nbsp;void&nbsp;\*data,&nbsp;size_t&nbsp;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&nbsp;(\*OnCallReport)(struct&nbsp;ReportInfo&nbsp;reportInfo,&nbsp;const&nbsp;void&nbsp;\*data,&nbsp;size_t&nbsp;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&nbsp;OnNotifyOps(const&nbsp;char&nbsp;\*s,&nbsp;const&nbsp;char&nbsp;\*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    ![](figures/en-us_image_0000001171507146.png)
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    ![](figures/en-us_image_0000001214727595.png)
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