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