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