xref: /OK3568_Linux_fs/app/forlinx/quectelCM/atc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /******************************************************************************
2*4882a593Smuzhiyun   @file    atc.c
3*4882a593Smuzhiyun   @brief   at command.
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun   DESCRIPTION
6*4882a593Smuzhiyun   Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun   INITIALIZATION AND SEQUENCING REQUIREMENTS
9*4882a593Smuzhiyun   None.
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun   ---------------------------------------------------------------------------
12*4882a593Smuzhiyun   Copyright (c) 2016 - 2020 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.
13*4882a593Smuzhiyun   Quectel Wireless Solution Proprietary and Confidential.
14*4882a593Smuzhiyun   ---------------------------------------------------------------------------
15*4882a593Smuzhiyun ******************************************************************************/
16*4882a593Smuzhiyun #include <unistd.h>
17*4882a593Smuzhiyun #include <stdio.h>
18*4882a593Smuzhiyun #include <stdlib.h>
19*4882a593Smuzhiyun #include <string.h>
20*4882a593Smuzhiyun #include <ctype.h>
21*4882a593Smuzhiyun #include <fcntl.h>
22*4882a593Smuzhiyun #include <stddef.h>
23*4882a593Smuzhiyun #include <pthread.h>
24*4882a593Smuzhiyun #include <errno.h>
25*4882a593Smuzhiyun #include <time.h>
26*4882a593Smuzhiyun #include <signal.h>
27*4882a593Smuzhiyun #include <getopt.h>
28*4882a593Smuzhiyun #include <poll.h>
29*4882a593Smuzhiyun #include <sys/time.h>
30*4882a593Smuzhiyun #include <endian.h>
31*4882a593Smuzhiyun #include <time.h>
32*4882a593Smuzhiyun #include <sys/types.h>
33*4882a593Smuzhiyun #include <limits.h>
34*4882a593Smuzhiyun #include <inttypes.h>
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun extern int asprintf(char **s, const char *fmt, ...);
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #include "QMIThread.h"
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #include "atchannel.h"
41*4882a593Smuzhiyun #include "at_tok.h"
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun static int asr_style_atc = 0;
44*4882a593Smuzhiyun #define safe_free(__x) do { if (__x) { free((void *)__x); __x = NULL;}} while(0)
45*4882a593Smuzhiyun #define safe_at_response_free(__x) { if (__x) { at_response_free(__x); __x = NULL;}}
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #define at_response_error(err, p_response) \
48*4882a593Smuzhiyun     (err \
49*4882a593Smuzhiyun     || p_response == NULL \
50*4882a593Smuzhiyun     || p_response->finalResponse == NULL \
51*4882a593Smuzhiyun     || p_response->success == 0)
52*4882a593Smuzhiyun 
atc_init(PROFILE_T * profile)53*4882a593Smuzhiyun static int atc_init(PROFILE_T *profile) {
54*4882a593Smuzhiyun     int err;
55*4882a593Smuzhiyun     ATResponse *p_response = NULL;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun     (void)profile;
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun     err = at_handshake();
60*4882a593Smuzhiyun     if (err) {
61*4882a593Smuzhiyun         dbg_time("handshake fail, TODO ... ");
62*4882a593Smuzhiyun         goto exit;
63*4882a593Smuzhiyun     }
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun     at_send_command("AT+QCFG=\"NAT\",1", NULL);
66*4882a593Smuzhiyun     at_send_command_singleline("AT+QCFG=\"usbnet\"", "+QCFG:", NULL);
67*4882a593Smuzhiyun     at_send_command_multiline("AT+QNETDEVCTL=?", "+QNETDEVCTL:", NULL);
68*4882a593Smuzhiyun     at_send_command("AT+CGREG=2", NULL);
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun     err = at_send_command_singleline("AT+QNETDEVSTATUS=?", "+QNETDEVSTATUS:", &p_response);
71*4882a593Smuzhiyun     if (at_response_error(err, p_response))
72*4882a593Smuzhiyun         asr_style_atc = 1; //EC200T/EC100Y do not support this AT, but RG801/RG500U support
73*4882a593Smuzhiyun     safe_at_response_free(p_response);
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun exit:
76*4882a593Smuzhiyun     return err;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
atc_deinit(void)79*4882a593Smuzhiyun static int atc_deinit(void) {
80*4882a593Smuzhiyun     return 0;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun /**
84*4882a593Smuzhiyun  * Called by atchannel when an unsolicited line appears
85*4882a593Smuzhiyun  * This is called on atchannel's reader thread. AT commands may
86*4882a593Smuzhiyun  * not be issued here
87*4882a593Smuzhiyun  */
onUnsolicited(const char * s,const char * sms_pdu)88*4882a593Smuzhiyun static void onUnsolicited (const char *s, const char *sms_pdu)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun     (void)sms_pdu;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun     if (strStartsWith(s, "+QNETDEVSTATUS:")) {
93*4882a593Smuzhiyun         qmidevice_send_event_to_main(RIL_UNSOL_DATA_CALL_LIST_CHANGED);
94*4882a593Smuzhiyun     }
95*4882a593Smuzhiyun     else if (strStartsWith(s, "+CGREG:") || strStartsWith(s, "+C5GREG:")) {
96*4882a593Smuzhiyun         qmidevice_send_event_to_main(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED);
97*4882a593Smuzhiyun     }
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
atc_read_thread(void * param)100*4882a593Smuzhiyun static void * atc_read_thread(void *param) {
101*4882a593Smuzhiyun     PROFILE_T *profile = (PROFILE_T *)param;
102*4882a593Smuzhiyun     const char *cdc_wdm = (const char *)profile->qmichannel;
103*4882a593Smuzhiyun     int wait_for_request_quit = 0;
104*4882a593Smuzhiyun     int atc_fd;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun     atc_fd = cm_open_dev(cdc_wdm);
107*4882a593Smuzhiyun     if (atc_fd <= 0) {
108*4882a593Smuzhiyun         dbg_time("fail to open (%s), errno: %d (%s)", cdc_wdm, errno, strerror(errno));
109*4882a593Smuzhiyun         goto __quit;
110*4882a593Smuzhiyun     }
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun     dbg_time("atc_fd = %d", atc_fd);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun     if (at_open(atc_fd, onUnsolicited))
115*4882a593Smuzhiyun         goto __quit;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun     qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_CONNECTED);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun     while (atc_fd > 0) {
120*4882a593Smuzhiyun         struct pollfd pollfds[] = {{atc_fd, POLLIN, 0}, {qmidevice_control_fd[1], POLLIN, 0}};
121*4882a593Smuzhiyun         int ne, ret, nevents = 2;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun         ret = poll(pollfds, nevents, wait_for_request_quit ? 1000 : -1);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun         if (ret == 0 && wait_for_request_quit) {
126*4882a593Smuzhiyun             break;
127*4882a593Smuzhiyun         }
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun         if (ret < 0) {
130*4882a593Smuzhiyun             dbg_time("%s poll=%d, errno: %d (%s)", __func__, ret, errno, strerror(errno));
131*4882a593Smuzhiyun             break;
132*4882a593Smuzhiyun         }
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun         for (ne = 0; ne < nevents; ne++) {
135*4882a593Smuzhiyun             int fd = pollfds[ne].fd;
136*4882a593Smuzhiyun             short revents = pollfds[ne].revents;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun             if (revents & (POLLERR | POLLHUP | POLLNVAL)) {
139*4882a593Smuzhiyun                 dbg_time("%s poll err/hup/inval", __func__);
140*4882a593Smuzhiyun                 dbg_time("epoll fd = %d, events = 0x%04x", fd, revents);
141*4882a593Smuzhiyun                 if (revents & (POLLERR | POLLHUP | POLLNVAL))
142*4882a593Smuzhiyun                 goto __quit;
143*4882a593Smuzhiyun             }
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun             if ((revents & POLLIN) == 0)
146*4882a593Smuzhiyun                 continue;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun             if (atc_fd == fd) {
149*4882a593Smuzhiyun                 usleep(10*1000); //let atchannel.c read at response.
150*4882a593Smuzhiyun             }
151*4882a593Smuzhiyun             else if (fd == qmidevice_control_fd[1]) {
152*4882a593Smuzhiyun                 int triger_event;
153*4882a593Smuzhiyun                 if (read(fd, &triger_event, sizeof(triger_event)) == sizeof(triger_event)) {
154*4882a593Smuzhiyun                     //dbg_time("triger_event = 0x%x", triger_event);
155*4882a593Smuzhiyun                     switch (triger_event) {
156*4882a593Smuzhiyun                         case RIL_REQUEST_QUIT:
157*4882a593Smuzhiyun                             goto __quit;
158*4882a593Smuzhiyun                         break;
159*4882a593Smuzhiyun                         case SIG_EVENT_STOP:
160*4882a593Smuzhiyun                             wait_for_request_quit = 1;
161*4882a593Smuzhiyun                         break;
162*4882a593Smuzhiyun                         default:
163*4882a593Smuzhiyun                         break;
164*4882a593Smuzhiyun                     }
165*4882a593Smuzhiyun                 }
166*4882a593Smuzhiyun             }
167*4882a593Smuzhiyun         }
168*4882a593Smuzhiyun     }
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun __quit:
171*4882a593Smuzhiyun     at_close();
172*4882a593Smuzhiyun     qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED);
173*4882a593Smuzhiyun     dbg_time("%s exit", __func__);
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun     return NULL;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun const struct qmi_device_ops atc_dev_ops = {
179*4882a593Smuzhiyun     .init = atc_init,
180*4882a593Smuzhiyun     .deinit = atc_deinit,
181*4882a593Smuzhiyun     .read = atc_read_thread,
182*4882a593Smuzhiyun };
183*4882a593Smuzhiyun 
requestBaseBandVersion(PROFILE_T * profile)184*4882a593Smuzhiyun static int requestBaseBandVersion(PROFILE_T *profile) {
185*4882a593Smuzhiyun     int err;
186*4882a593Smuzhiyun     ATResponse *p_response = NULL;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun     (void)profile;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun     err = at_send_command_singleline("AT+CGMR", "\0", &p_response);
191*4882a593Smuzhiyun     if (at_response_error(err, p_response))
192*4882a593Smuzhiyun         goto exit;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun exit:
195*4882a593Smuzhiyun     safe_at_response_free(p_response);
196*4882a593Smuzhiyun     return err;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun 
requestGetSIMStatus(SIM_Status * pSIMStatus)199*4882a593Smuzhiyun static int requestGetSIMStatus(SIM_Status *pSIMStatus)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun     int err;
202*4882a593Smuzhiyun     ATResponse *p_response = NULL;
203*4882a593Smuzhiyun     char *cpinLine;
204*4882a593Smuzhiyun     char *cpinResult;
205*4882a593Smuzhiyun     int ret = SIM_NOT_READY;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun     err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
208*4882a593Smuzhiyun     if (at_response_error(err, p_response))
209*4882a593Smuzhiyun         goto done;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun     switch (at_get_cme_error(p_response))
212*4882a593Smuzhiyun     {
213*4882a593Smuzhiyun     case CME_SUCCESS:
214*4882a593Smuzhiyun         break;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun     case CME_SIM_NOT_INSERTED:
217*4882a593Smuzhiyun     case CME_OPERATION_NOT_ALLOWED:
218*4882a593Smuzhiyun     case CME_FAILURE:
219*4882a593Smuzhiyun         ret = SIM_ABSENT;
220*4882a593Smuzhiyun         goto done;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun     default:
223*4882a593Smuzhiyun         ret = SIM_NOT_READY;
224*4882a593Smuzhiyun         goto done;
225*4882a593Smuzhiyun     }
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun     cpinLine = p_response->p_intermediates->line;
228*4882a593Smuzhiyun     err = at_tok_start (&cpinLine);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun     if (err < 0)
231*4882a593Smuzhiyun     {
232*4882a593Smuzhiyun         ret = SIM_NOT_READY;
233*4882a593Smuzhiyun         goto done;
234*4882a593Smuzhiyun     }
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun     err = at_tok_nextstr(&cpinLine, &cpinResult);
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun     if (err < 0)
239*4882a593Smuzhiyun     {
240*4882a593Smuzhiyun         ret = SIM_NOT_READY;
241*4882a593Smuzhiyun         goto done;
242*4882a593Smuzhiyun     }
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun     if (0 == strcmp (cpinResult, "SIM PIN"))
245*4882a593Smuzhiyun     {
246*4882a593Smuzhiyun         ret = SIM_PIN;
247*4882a593Smuzhiyun         goto done;
248*4882a593Smuzhiyun     }
249*4882a593Smuzhiyun     else if (0 == strcmp (cpinResult, "SIM PUK"))
250*4882a593Smuzhiyun     {
251*4882a593Smuzhiyun         ret = SIM_PUK;
252*4882a593Smuzhiyun         goto done;
253*4882a593Smuzhiyun     }
254*4882a593Smuzhiyun     else if (0 == strcmp (cpinResult, "PH-NET PIN"))
255*4882a593Smuzhiyun     {
256*4882a593Smuzhiyun         return SIM_NETWORK_PERSONALIZATION;
257*4882a593Smuzhiyun     }
258*4882a593Smuzhiyun     else if (0 != strcmp (cpinResult, "READY"))
259*4882a593Smuzhiyun     {
260*4882a593Smuzhiyun         /* we're treating unsupported lock types as "sim absent" */
261*4882a593Smuzhiyun         ret = SIM_ABSENT;
262*4882a593Smuzhiyun         goto done;
263*4882a593Smuzhiyun     }
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun     ret = SIM_READY;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun done:
268*4882a593Smuzhiyun     safe_at_response_free(p_response);
269*4882a593Smuzhiyun     *pSIMStatus = ret;
270*4882a593Smuzhiyun     return err;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun 
requestRegistrationState(UCHAR * pPSAttachedState)273*4882a593Smuzhiyun static int requestRegistrationState(UCHAR *pPSAttachedState) {
274*4882a593Smuzhiyun     int err;
275*4882a593Smuzhiyun     ATResponse *p_response = NULL;
276*4882a593Smuzhiyun     ATLine *p_cur;
277*4882a593Smuzhiyun     int i;
278*4882a593Smuzhiyun     int cops_atc = -1;
279*4882a593Smuzhiyun     char *response[3] = {NULL, NULL, NULL};
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun     *pPSAttachedState = 0;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun     err = at_send_command_multiline(
284*4882a593Smuzhiyun               "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
285*4882a593Smuzhiyun               "+COPS:", &p_response);
286*4882a593Smuzhiyun     if (at_response_error(err, p_response))
287*4882a593Smuzhiyun         goto error;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun     for ( i = 0, p_cur = p_response->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next, i++) {
290*4882a593Smuzhiyun         int skip;
291*4882a593Smuzhiyun         char *line = p_cur->line;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun         err = at_tok_start(&line);
294*4882a593Smuzhiyun         if (err < 0) goto error;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun         err = at_tok_nextint(&line, &skip);
297*4882a593Smuzhiyun         if (err < 0) goto error;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun         if (!at_tok_hasmore(&line))
300*4882a593Smuzhiyun             continue;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun         err = at_tok_nextint(&line, &skip);
303*4882a593Smuzhiyun         if (err < 0) goto error;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun         if (!at_tok_hasmore(&line))
306*4882a593Smuzhiyun             continue;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun         err = at_tok_nextstr(&line, &(response[i]));
309*4882a593Smuzhiyun         if (err < 0) goto error;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun         if (!at_tok_hasmore(&line))
312*4882a593Smuzhiyun             continue;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun         err = at_tok_nextint(&line, &cops_atc);
315*4882a593Smuzhiyun         if (err < 0) goto error;
316*4882a593Smuzhiyun     }
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun     if (cops_atc != -1) {
319*4882a593Smuzhiyun         *pPSAttachedState = 1;
320*4882a593Smuzhiyun     }
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun error:
323*4882a593Smuzhiyun     safe_at_response_free(p_response);
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun     return err;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun 
requestSetupDataCall(PROFILE_T * profile,int curIpFamily)328*4882a593Smuzhiyun static int requestSetupDataCall(PROFILE_T *profile, int curIpFamily) {
329*4882a593Smuzhiyun     int err;
330*4882a593Smuzhiyun     ATResponse *p_response = NULL;
331*4882a593Smuzhiyun     char *cmd = NULL;
332*4882a593Smuzhiyun     ATLine *p_cur = NULL;
333*4882a593Smuzhiyun     char *line = NULL;
334*4882a593Smuzhiyun     int pdp = profile->pdp;
335*4882a593Smuzhiyun     int state = 0;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun     (void)curIpFamily;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun     if (asr_style_atc) {
340*4882a593Smuzhiyun         err = at_send_command_multiline("AT+CGACT?", "+CGACT:", &p_response);
341*4882a593Smuzhiyun         if (at_response_error(err, p_response))
342*4882a593Smuzhiyun             goto _error;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun         for (p_cur = p_response->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next) {
345*4882a593Smuzhiyun             int cid = 0;
346*4882a593Smuzhiyun             line = p_cur->line;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun             err = at_tok_start(&line);
349*4882a593Smuzhiyun             if (err < 0) goto _error;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun             err = at_tok_nextint(&line, &cid);
352*4882a593Smuzhiyun             if (err < 0) goto _error;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun             if (cid != pdp)
355*4882a593Smuzhiyun                 continue;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun             err = at_tok_nextint(&line, &state);
358*4882a593Smuzhiyun             if (err < 0) goto _error;
359*4882a593Smuzhiyun         }
360*4882a593Smuzhiyun         safe_at_response_free(p_response);
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun         if (state == 0) {
363*4882a593Smuzhiyun             asprintf(&cmd, "AT+CGACT=1,%d", pdp);
364*4882a593Smuzhiyun             err = at_send_command(cmd, &p_response);
365*4882a593Smuzhiyun             safe_free(cmd);
366*4882a593Smuzhiyun             if (at_response_error(err, p_response))
367*4882a593Smuzhiyun                 goto _error;
368*4882a593Smuzhiyun         }
369*4882a593Smuzhiyun     }
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun     if(asr_style_atc)
372*4882a593Smuzhiyun         asprintf(&cmd, "AT+QNETDEVCTL=1,%d,%d", pdp, 1);
373*4882a593Smuzhiyun     else
374*4882a593Smuzhiyun         asprintf(&cmd, "AT+QNETDEVCTL=%d,1,%d", pdp, 0);
375*4882a593Smuzhiyun     err = at_send_command(cmd, &p_response);
376*4882a593Smuzhiyun     safe_free(cmd);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun     if (at_response_error(err, p_response))
379*4882a593Smuzhiyun         goto _error;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun     if (!asr_style_atc) { //TODO some modems do not sync return setup call resule
382*4882a593Smuzhiyun         int t = 0;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun         asprintf(&cmd, "AT+QNETDEVSTATUS=%d", pdp);
385*4882a593Smuzhiyun         while (t++ < 30) {
386*4882a593Smuzhiyun             err = at_send_command_singleline(cmd, "+QNETDEVSTATUS", &p_response);
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun             if (!at_response_error(err, p_response)) {
389*4882a593Smuzhiyun                 safe_at_response_free(p_response);
390*4882a593Smuzhiyun                 break;
391*4882a593Smuzhiyun             }
392*4882a593Smuzhiyun             safe_at_response_free(p_response);
393*4882a593Smuzhiyun             sleep(1);
394*4882a593Smuzhiyun         }
395*4882a593Smuzhiyun         safe_free(cmd);
396*4882a593Smuzhiyun         if (t > 15)
397*4882a593Smuzhiyun             goto _error;
398*4882a593Smuzhiyun     }
399*4882a593Smuzhiyun     //some modem do not report URC
400*4882a593Smuzhiyun     qmidevice_send_event_to_main(RIL_UNSOL_DATA_CALL_LIST_CHANGED);
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun _error:
403*4882a593Smuzhiyun     safe_at_response_free(p_response);
404*4882a593Smuzhiyun     dbg_time("%s err=%d", __func__, err);
405*4882a593Smuzhiyun     return err;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun 
at_netdevstatus(int pdp,unsigned int * pV4Addr)408*4882a593Smuzhiyun static int at_netdevstatus(int pdp, unsigned int *pV4Addr) {
409*4882a593Smuzhiyun     int err;
410*4882a593Smuzhiyun     ATResponse *p_response = NULL;
411*4882a593Smuzhiyun     char *cmd = NULL;
412*4882a593Smuzhiyun     char *line;
413*4882a593Smuzhiyun     char *ipv4 = NULL;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun     *pV4Addr = 0;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun     asprintf(&cmd, "AT+QNETDEVSTATUS=%d", pdp);
418*4882a593Smuzhiyun     err = at_send_command_singleline(cmd, "+QNETDEVSTATUS", &p_response);
419*4882a593Smuzhiyun     safe_free(cmd);
420*4882a593Smuzhiyun     if (at_response_error(err, p_response))
421*4882a593Smuzhiyun         goto _error;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun     line = p_response->p_intermediates->line;
424*4882a593Smuzhiyun     err = at_tok_start(&line);
425*4882a593Smuzhiyun     if (err < 0)
426*4882a593Smuzhiyun         goto _error;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun     err = at_tok_nextstr(&line, &ipv4);
429*4882a593Smuzhiyun     if (err < 0) goto _error;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun     if (ipv4) {
432*4882a593Smuzhiyun         int addr[4] = {0, 0, 0, 0};
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun         sscanf(ipv4, "%d.%d.%d.%d", &addr[0], &addr[1], &addr[2], &addr[3]);
435*4882a593Smuzhiyun         *pV4Addr = (addr[0]) | (addr[1]<<8) | (addr[2]<<16) | (addr[3]<<24);
436*4882a593Smuzhiyun     }
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun _error:
439*4882a593Smuzhiyun     return err;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun 
requestQueryDataCall(UCHAR * pConnectionStatus,int curIpFamily)442*4882a593Smuzhiyun static int requestQueryDataCall(UCHAR  *pConnectionStatus, int curIpFamily) {
443*4882a593Smuzhiyun     int err;
444*4882a593Smuzhiyun     ATResponse *p_response = NULL;
445*4882a593Smuzhiyun     ATLine *p_cur = NULL;
446*4882a593Smuzhiyun     char *line = NULL;
447*4882a593Smuzhiyun     int state = 0;
448*4882a593Smuzhiyun     int bind = 0;
449*4882a593Smuzhiyun     int cid;
450*4882a593Smuzhiyun     int pdp = 1;
451*4882a593Smuzhiyun     unsigned int v4Addr = 0;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun     (void)curIpFamily;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun     *pConnectionStatus = QWDS_PKT_DATA_DISCONNECTED;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun     if (asr_style_atc)
458*4882a593Smuzhiyun         goto _asr_style_atc;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun     err = at_netdevstatus(pdp, &v4Addr);
461*4882a593Smuzhiyun     if (!err && v4Addr) {
462*4882a593Smuzhiyun         *pConnectionStatus = QWDS_PKT_DATA_CONNECTED;
463*4882a593Smuzhiyun         //if (profile->ipv4.Address == 0) {} //TODO
464*4882a593Smuzhiyun      }
465*4882a593Smuzhiyun     goto _error;
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun _asr_style_atc:
468*4882a593Smuzhiyun     err = at_send_command_multiline("AT+QNETDEVCTL?", "+QNETDEVCTL:", &p_response);
469*4882a593Smuzhiyun     if (at_response_error(err, p_response))
470*4882a593Smuzhiyun         goto _error;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun     for (p_cur = p_response->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next)
473*4882a593Smuzhiyun     {
474*4882a593Smuzhiyun         int tmp;
475*4882a593Smuzhiyun         //+QNETDECTL:<op>,<cid>,<urc_en>,<state>
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun         line = p_cur->line;
478*4882a593Smuzhiyun         err = at_tok_start(&line);
479*4882a593Smuzhiyun         if (err < 0)
480*4882a593Smuzhiyun             goto _error;
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun         err = at_tok_nextint(&line, &bind);
483*4882a593Smuzhiyun         if (err < 0)
484*4882a593Smuzhiyun             goto _error;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun         err = at_tok_nextint(&line, &cid);
487*4882a593Smuzhiyun         if (err < 0)
488*4882a593Smuzhiyun             goto _error;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun         if (cid != pdp)
491*4882a593Smuzhiyun             continue;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun         err = at_tok_nextint(&line, &tmp);
494*4882a593Smuzhiyun         if(err < 0)
495*4882a593Smuzhiyun             goto _error;
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun         err = at_tok_nextint(&line, &state);
498*4882a593Smuzhiyun         if(err < 0)
499*4882a593Smuzhiyun             goto _error;
500*4882a593Smuzhiyun     }
501*4882a593Smuzhiyun     safe_at_response_free(p_response);
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun     if (bind == 0 || state == 0)
504*4882a593Smuzhiyun         goto _error;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun     err = at_send_command_multiline("AT+CGACT?", "+CGACT:", &p_response);
507*4882a593Smuzhiyun     if (at_response_error(err, p_response))
508*4882a593Smuzhiyun         goto _error;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun     for (p_cur = p_response->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next)
511*4882a593Smuzhiyun     {
512*4882a593Smuzhiyun         line = p_cur->line;
513*4882a593Smuzhiyun         err = at_tok_start(&line);
514*4882a593Smuzhiyun         if (err < 0)
515*4882a593Smuzhiyun             goto _error;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun         err = at_tok_nextint(&line, &cid);
518*4882a593Smuzhiyun         if (err < 0)
519*4882a593Smuzhiyun             goto _error;
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun         if (cid != pdp)
522*4882a593Smuzhiyun             continue;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun         err = at_tok_nextint(&line, &state);
525*4882a593Smuzhiyun         if (err < 0)
526*4882a593Smuzhiyun             goto _error;
527*4882a593Smuzhiyun     }
528*4882a593Smuzhiyun     safe_at_response_free(p_response);
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun     if (bind && state)
531*4882a593Smuzhiyun         *pConnectionStatus = QWDS_PKT_DATA_CONNECTED;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun _error:
534*4882a593Smuzhiyun     safe_at_response_free(p_response);
535*4882a593Smuzhiyun     dbg_time("%s err=%d, call_state=%d", __func__, err, *pConnectionStatus);
536*4882a593Smuzhiyun     return err;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun 
requestDeactivateDefaultPDP(PROFILE_T * profile,int curIpFamily)539*4882a593Smuzhiyun static int requestDeactivateDefaultPDP(PROFILE_T *profile, int curIpFamily) {
540*4882a593Smuzhiyun     int err;
541*4882a593Smuzhiyun     char *cmd = NULL;
542*4882a593Smuzhiyun     int pdp = profile->pdp;
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun     (void)curIpFamily;
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun     if (asr_style_atc)
547*4882a593Smuzhiyun         asprintf(&cmd, "AT+QNETDEVCTL=0,%d,%d", pdp, 0);
548*4882a593Smuzhiyun     else
549*4882a593Smuzhiyun         asprintf(&cmd, "AT+QNETDEVCTL=%d,0,%d", pdp, 0);
550*4882a593Smuzhiyun     err = at_send_command(cmd, NULL);
551*4882a593Smuzhiyun     safe_free(cmd);
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun     dbg_time("%s err=%d", __func__, err);
554*4882a593Smuzhiyun     return err;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun 
requestGetIPAddress(PROFILE_T * profile,int curIpFamily)557*4882a593Smuzhiyun static int requestGetIPAddress(PROFILE_T *profile, int curIpFamily) {
558*4882a593Smuzhiyun     int err;
559*4882a593Smuzhiyun     ATResponse *p_response = NULL;
560*4882a593Smuzhiyun     char *cmd = NULL;
561*4882a593Smuzhiyun     ATLine *p_cur = NULL;
562*4882a593Smuzhiyun     char *line = NULL;
563*4882a593Smuzhiyun     int pdp = profile->pdp;
564*4882a593Smuzhiyun     unsigned int v4Addr = 0;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun     (void)curIpFamily;
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun     if (asr_style_atc)
569*4882a593Smuzhiyun         goto _asr_style_atc;
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun     err = at_netdevstatus(pdp, &v4Addr);
572*4882a593Smuzhiyun     if (err < 0) goto _error;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun     goto _error;
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun _asr_style_atc:
577*4882a593Smuzhiyun     asprintf(&cmd, "AT+CGPADDR=%d", profile->pdp);
578*4882a593Smuzhiyun     err = at_send_command_singleline(cmd, "+CGPADDR:", &p_response);
579*4882a593Smuzhiyun     safe_free(cmd);
580*4882a593Smuzhiyun     if (at_response_error(err, p_response))
581*4882a593Smuzhiyun         goto _error;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun     //+CGPADDR: 1,"10.201.80.91","2409:8930:4B3:41C7:F9B8:3D9B:A2F7:CA96"
584*4882a593Smuzhiyun     for (p_cur = p_response->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next)
585*4882a593Smuzhiyun     {
586*4882a593Smuzhiyun         char *ipv4 = NULL;
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun         line = p_cur->line;
589*4882a593Smuzhiyun         err = at_tok_start(&line);
590*4882a593Smuzhiyun         if (err < 0)
591*4882a593Smuzhiyun             goto _error;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun         err = at_tok_nextint(&line, &pdp);
594*4882a593Smuzhiyun         if (err < 0)
595*4882a593Smuzhiyun             goto _error;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun         if (pdp != profile->pdp)
598*4882a593Smuzhiyun             continue;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun         if (!at_tok_hasmore(&line))
601*4882a593Smuzhiyun             continue;
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun         err = at_tok_nextstr(&line, &ipv4);
604*4882a593Smuzhiyun         if (err < 0) goto _error;
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun         if (ipv4) {
607*4882a593Smuzhiyun             int addr[4] = {0, 0, 0, 0};
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun             sscanf(ipv4, "%d.%d.%d.%d", &addr[0], &addr[1], &addr[2], &addr[3]);
610*4882a593Smuzhiyun             v4Addr = (addr[0]) | (addr[1]<<8) | (addr[2]<<16) | (addr[3]<<24);
611*4882a593Smuzhiyun             break;
612*4882a593Smuzhiyun         }
613*4882a593Smuzhiyun     }
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun _error:
616*4882a593Smuzhiyun     if (!v4Addr && !err) {
617*4882a593Smuzhiyun         err = -1;
618*4882a593Smuzhiyun     }
619*4882a593Smuzhiyun     if (profile->ipv4.Address != v4Addr) {
620*4882a593Smuzhiyun         profile->ipv4.Address = v4Addr;
621*4882a593Smuzhiyun         if (v4Addr) {
622*4882a593Smuzhiyun             unsigned char *v4 = (unsigned char *)&v4Addr;
623*4882a593Smuzhiyun             dbg_time("%s %d.%d.%d.%d", __func__, v4[0], v4[1], v4[2], v4[3]);
624*4882a593Smuzhiyun         }
625*4882a593Smuzhiyun     }
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun     dbg_time("%s err=%d", __func__, err);
628*4882a593Smuzhiyun     return err;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun 
requestGetICCID(void)631*4882a593Smuzhiyun static int requestGetICCID(void) {
632*4882a593Smuzhiyun     int err;
633*4882a593Smuzhiyun     ATResponse *p_response = NULL;
634*4882a593Smuzhiyun     char *line;
635*4882a593Smuzhiyun     char *iccid;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun     err = at_send_command_singleline("AT+QCCID", "+QCCID:", &p_response);
638*4882a593Smuzhiyun     if (at_response_error(err, p_response))
639*4882a593Smuzhiyun         goto _error;
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun     line = p_response->p_intermediates->line;
642*4882a593Smuzhiyun     err = at_tok_start(&line);
643*4882a593Smuzhiyun     if (err < 0)
644*4882a593Smuzhiyun         goto _error;
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun     err = at_tok_nextstr(&line, &iccid);
647*4882a593Smuzhiyun     if (err < 0)
648*4882a593Smuzhiyun         goto _error;
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun     dbg_time("%s %s", __func__, iccid);
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun _error:
653*4882a593Smuzhiyun     safe_at_response_free(p_response);
654*4882a593Smuzhiyun     return err;
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun 
requestGetIMSI(void)657*4882a593Smuzhiyun static int requestGetIMSI(void) {
658*4882a593Smuzhiyun     int err;
659*4882a593Smuzhiyun     ATResponse *p_response = NULL;
660*4882a593Smuzhiyun     char *imsi;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun     err = at_send_command_numeric("AT+CIMI", &p_response);
663*4882a593Smuzhiyun     if (at_response_error(err, p_response))
664*4882a593Smuzhiyun         goto exit;
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun     imsi = p_response->p_intermediates->line;
667*4882a593Smuzhiyun     if (imsi) {
668*4882a593Smuzhiyun         dbg_time("%s %s", __func__, imsi);
669*4882a593Smuzhiyun     }
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun exit:
672*4882a593Smuzhiyun     safe_at_response_free(p_response);
673*4882a593Smuzhiyun     return err;
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun const struct request_ops atc_request_ops = {
677*4882a593Smuzhiyun     .requestBaseBandVersion = requestBaseBandVersion,
678*4882a593Smuzhiyun     .requestGetSIMStatus = requestGetSIMStatus,
679*4882a593Smuzhiyun     .requestRegistrationState = requestRegistrationState,
680*4882a593Smuzhiyun     .requestSetupDataCall = requestSetupDataCall,
681*4882a593Smuzhiyun     .requestQueryDataCall = requestQueryDataCall,
682*4882a593Smuzhiyun     .requestDeactivateDefaultPDP = requestDeactivateDefaultPDP,
683*4882a593Smuzhiyun     .requestGetIPAddress = requestGetIPAddress,
684*4882a593Smuzhiyun     .requestGetICCID = requestGetICCID,
685*4882a593Smuzhiyun     .requestGetIMSI = requestGetIMSI,
686*4882a593Smuzhiyun };
687*4882a593Smuzhiyun 
688