blob: 6358033ba7c7cd7f580691c0af8bb4bcb8e28654 [file] [log] [blame]
liubin281ac462023-07-19 14:22:54 +08001/* //device/system/reference-ril/atchannel.c
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "atchannel.h"
19#include "at_tok.h"
20
21#include <stdio.h>
22#include <string.h>
23#include <pthread.h>
24#include <ctype.h>
25#include <stdlib.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <sys/time.h>
29#include <time.h>
30#include <unistd.h>
31
32#include "mbtk_log.h"
33#include "mbtk_type.h"
34#include "mbtk_utils.h"
35
36#define MAX_AT_RESPONSE (8 * 1024)
37#define HANDSHAKE_RETRY_COUNT 20
38#define HANDSHAKE_TIMEOUT_MSEC 500
b.liu06559f62024-11-01 18:48:22 +080039#define AT_BUFF_MAX 1024
liubin281ac462023-07-19 14:22:54 +080040
41static pthread_t s_tid_reader;
42static int s_at_fd = -1; /* fd of the AT channel */
43static int s_uart_fd = -1; /* fd of the UART channel */
44
45static ATUnsolHandler s_unsolHandler;
46
47/* for input buffering */
48
49static char s_ATBuffer[MAX_AT_RESPONSE+1];
50static char *s_ATBufferCur = s_ATBuffer;
51static char s_UartBuffer[MAX_AT_RESPONSE+1];
52static char *s_UartBufferCur = s_UartBuffer;
53
54static mbtk_ril_at_state_enum at_state = RIL_AT_STATE_CLOSED;
55
56#if AT_DEBUG
57void AT_DUMP(const char* prefix, const char* buff, int len)
58{
59 if (len < 0)
60 len = strlen(buff);
61 LOGD("%.*s", len, buff);
62}
63#endif
64
65/*
66 * There is one reader thread |s_tid_reader| and potentially multiple writer
67 * threads. |s_commandmutex| and |s_commandcond| are used to maintain the
68 * condition that the writer thread will not read from |sp_response| until the
69 * reader thread has signaled itself is finished, etc. |s_writeMutex| is used to
70 * prevent multiple writer threads from calling at_send_command_full_nolock
71 * function at the same time.
72 */
73
74// "Wait" when AT process...
75static pthread_mutex_t s_commandmutex = PTHREAD_MUTEX_INITIALIZER;
76static pthread_cond_t s_commandcond = PTHREAD_COND_INITIALIZER;
77
78static ATCommandType s_type;
79static const char *s_responsePrefix = NULL;
80static const char *s_smsPDU = NULL;
81static ATResponse *sp_response = NULL;
82static char s_curr_at[AT_BUFF_MAX];
83
84static void (*s_onTimeout)(void) = NULL;
85static void (*s_onReaderClosed)(void) = NULL;
86static int s_readerClosed;
87
88static void onReaderClosed();
89static int writeCtrlZ (const char *s);
90static int writeline (const char *s);
91
92typedef struct
93{
94 char *at_command;
95 long long timeout; // ms
96 bool timeout_close; // Close AT or not while AT response timeout.
97} at_timeout_t;
98
99static at_timeout_t at_timeout_list[] =
100{
101 {"AT+CRSM", 10000, false},
102// {"AT+COPS", 60000, false}
103};
104
105#define NS_PER_S 1000000000
106static void setTimespecRelative(struct timespec *p_ts, long long msec)
107{
108 struct timeval tv;
109
110 gettimeofday(&tv, (struct timezone *) NULL);
111
112 p_ts->tv_sec = tv.tv_sec + (msec / 1000);
113 p_ts->tv_nsec = (tv.tv_usec + (msec % 1000) * 1000L ) * 1000L;
114 /* assuming tv.tv_usec < 10^6 */
115 if (p_ts->tv_nsec >= NS_PER_S)
116 {
117 p_ts->tv_sec++;
118 p_ts->tv_nsec -= NS_PER_S;
119 }
120}
121
122static void sleepMsec(long long msec)
123{
124 struct timespec ts;
125 int err;
126
127 ts.tv_sec = (msec / 1000);
128 ts.tv_nsec = (msec % 1000) * 1000 * 1000;
129
130 do
131 {
132 err = nanosleep (&ts, &ts);
133 }
134 while (err < 0 && errno == EINTR);
135}
136
137
138
139/** add an intermediate response to sp_response*/
140static void addIntermediate(const char *line)
141{
142 ATLine *p_new;
143
144 p_new = (ATLine *) malloc(sizeof(ATLine));
145
146 p_new->line = strdup(line);
147
148// LOGD("line:%s", line);
149// LOGD("line-1:%s", p_new->line);
150
151 /* note: this adds to the head of the list, so the list
152 will be in reverse order of lines received. the order is flipped
153 again before passing on to the command issuer */
154 p_new->p_next = sp_response->p_intermediates;
155 sp_response->p_intermediates = p_new;
156}
157
158
159/**
160 * returns 1 if line is a final response indicating error
161 * See 27.007 annex B
162 * WARNING: NO CARRIER and others are sometimes unsolicited
163 */
164static const char * s_finalResponsesError[] =
165{
166 "ERROR",
167 "+CMS ERROR:",
168 "+CME ERROR:",
169// "NO CARRIER", /* sometimes! */ // Only for ATD ?
170 "NO ANSWER",
171 "NO DIALTONE",
172};
173static int isFinalResponseError(const char *line)
174{
175 size_t i;
176
177 for (i = 0 ; i < ARRAY_SIZE(s_finalResponsesError) ; i++)
178 {
179 if (strStartsWith(line, s_finalResponsesError[i]))
180 {
181 return 1;
182 }
183 }
184
185 if(!strncasecmp(s_curr_at, "ATD", 3) && strStartsWith(line, "NO CARRIER"))
186 {
187 return 1;
188 }
189
190 return 0;
191}
192
193/**
194 * returns 1 if line is a final response indicating success
195 * See 27.007 annex B
196 * WARNING: NO CARRIER and others are sometimes unsolicited
197 */
198static const char * s_finalResponsesSuccess[] =
199{
200 "OK",
201// "CONNECT" /* some stacks start up data on another channel */
202};
203static int isFinalResponseSuccess(const char *line)
204{
205 size_t i;
206
207 for (i = 0 ; i < ARRAY_SIZE(s_finalResponsesSuccess) ; i++)
208 {
209 if (strStartsWith(line, s_finalResponsesSuccess[i]))
210 {
211 return 1;
212 }
213 }
214
215 return 0;
216}
217
218/**
219 * returns 1 if line is a final response, either error or success
220 * See 27.007 annex B
221 * WARNING: NO CARRIER and others are sometimes unsolicited
222 */
223static int isFinalResponse(const char *line)
224{
225 return isFinalResponseSuccess(line) || isFinalResponseError(line);
226}
227
228/**
229 * returns 1 if line is the first line in (what will be) a two-line
230 * SMS unsolicited response
231 */
232static const char * s_smsUnsoliciteds[] =
233{
234 "+CMT:",
235 "+CDS:",
236 "+CBM:"
237};
238static int isSMSUnsolicited(const char *line)
239{
240 size_t i;
241
242 for (i = 0 ; i < ARRAY_SIZE(s_smsUnsoliciteds) ; i++)
243 {
244 if (strStartsWith(line, s_smsUnsoliciteds[i]))
245 {
246 return 1;
247 }
248 }
249
250 return 0;
251}
252
253
254/** assumes s_commandmutex is held */
255static void handleFinalResponse(const char *line)
256{
257 sp_response->finalResponse = strdup(line);
258
259 //LOGD("AT complete (pthread_cond_signal): %s",line);
260 pthread_cond_signal(&s_commandcond);
261}
262
263static void handleUnsolicited(const char *line)
264{
265 if (s_unsolHandler != NULL)
266 {
267 s_unsolHandler(line, NULL);
268 }
269}
270
271static void processLine(const char *line)
272{
273 pthread_mutex_lock(&s_commandmutex);
274// LOGD("LINE : %s", line);
275 if (sp_response == NULL)
276 {
277 /* no command pending */
278 handleUnsolicited(line);
279 }
280 else if (isFinalResponseSuccess(line))
281 {
282 sp_response->success = 1;
283 handleFinalResponse(line);
284 }
285 else if (isFinalResponseError(line))
286 {
287 sp_response->success = 0;
288 handleFinalResponse(line);
289 }
290 else if (s_smsPDU != NULL && 0 == strcmp(line, "> "))
291 {
292 // See eg. TS 27.005 4.3
293 // Commands like AT+CMGS have a "> " prompt
294 writeCtrlZ(s_smsPDU);
295 s_smsPDU = NULL;
296 }
297 else switch (s_type)
298 {
299 case NO_RESULT:
300 handleUnsolicited(line);
301 break;
302 case NUMERIC:
303 if (sp_response->p_intermediates == NULL
304 && isdigit(line[0])
305 )
306 {
307 addIntermediate(line);
308 }
309 else
310 {
311 /* either we already have an intermediate response or
312 the line doesn't begin with a digit */
313 handleUnsolicited(line);
314 }
315 break;
316 case SINGLELINE:
317 if (sp_response->p_intermediates == NULL
318 && strStartsWith (line, s_responsePrefix)
319 )
320 {
321 if(*line == '"')
322 {
323 char *line_temp = strdup(line);
b.liu5eb525a2025-05-24 10:47:40 +0800324 char *free_ptr = line_temp;
liubin281ac462023-07-19 14:22:54 +0800325 line_temp++;
326 if(strlen(line_temp) > 0)
327 {
328 char *ptr = line_temp + strlen(line_temp) - 1;
329 while(ptr >= line_temp && *ptr == '"')
330 {
331 *ptr = '\0';
332 ptr--;
333 }
334 }
335 addIntermediate(line_temp);
b.liu5eb525a2025-05-24 10:47:40 +0800336 free(free_ptr);
liubin281ac462023-07-19 14:22:54 +0800337 }
338 else
339 {
340 addIntermediate(line);
341 }
342 }
343 else
344 {
345 /* we already have an intermediate response */
346 handleUnsolicited(line);
347 }
348 break;
349 case MULTILINE:
350 if (strStartsWith (line, s_responsePrefix))
351 {
352 addIntermediate(line);
353 }
354 else
355 {
356 handleUnsolicited(line);
357 }
358 break;
359
360 default: /* this should never be reached */
361 LOGE("Unsupported AT command type %d\n", s_type);
362 handleUnsolicited(line);
363 break;
364 }
365
366 pthread_mutex_unlock(&s_commandmutex);
367}
368
369
370/**
371 * Returns a pointer to the end of the next line
372 * special-cases the "> " SMS prompt
373 *
374 * returns NULL if there is no complete line
375 */
376static char * findNextEOL(char *cur)
377{
378 if (cur[0] == '>' && cur[1] == ' ' && cur[2] == '\0')
379 {
380 /* SMS prompt character...not \r terminated */
381 return cur+2;
382 }
383
384 // Find next newline
385 while (*cur != '\0' && *cur != '\r' && *cur != '\n') cur++;
386
387 return *cur == '\0' ? NULL : cur;
388}
389
390
391/**
392 * Reads a line from the AT channel, returns NULL on timeout.
393 * Assumes it has exclusive read access to the FD
394 *
395 * This line is valid only until the next call to readline
396 *
397 * This function exists because as of writing, android libc does not
398 * have buffered stdio.
399 */
400
401static const char *readline()
402{
403 ssize_t count;
404
405 char *p_read = NULL;
406 char *p_eol = NULL;
407 char *ret;
408
409 /* this is a little odd. I use *s_ATBufferCur == 0 to
410 * mean "buffer consumed completely". If it points to a character, than
411 * the buffer continues until a \0
412 */
413 if (*s_ATBufferCur == '\0')
414 {
415 /* empty buffer */
416 s_ATBufferCur = s_ATBuffer;
417 *s_ATBufferCur = '\0';
418 p_read = s_ATBuffer;
419 }
420 else /* *s_ATBufferCur != '\0' */
421 {
422 /* there's data in the buffer from the last read */
423
424 // skip over leading newlines
425 while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
426 s_ATBufferCur++;
427
428 p_eol = findNextEOL(s_ATBufferCur);
429
430 if (p_eol == NULL)
431 {
432 /* a partial line. move it up and prepare to read more */
433 size_t len;
434
435 len = strlen(s_ATBufferCur);
436
437 memmove(s_ATBuffer, s_ATBufferCur, len + 1);
438 p_read = s_ATBuffer + len;
439 s_ATBufferCur = s_ATBuffer;
440 }
441 /* Otherwise, (p_eol !- NULL) there is a complete line */
442 /* that will be returned the while () loop below */
443 }
444
445 while (p_eol == NULL)
446 {
447 if (0 == MAX_AT_RESPONSE - (p_read - s_ATBuffer))
448 {
449 LOGE("ERROR: Input line exceeded buffer\n");
450 /* ditch buffer and start over again */
451 s_ATBufferCur = s_ATBuffer;
452 *s_ATBufferCur = '\0';
453 p_read = s_ATBuffer;
454 }
455
456 do
457 {
458 count = read(s_at_fd, p_read,
459 MAX_AT_RESPONSE - (p_read - s_ATBuffer));
460 usleep(10000);
461 }
462 while (count < 0 && errno == EINTR);
463
464 if (count > 0)
465 {
466 AT_DUMP( "<< ", p_read, count );
467
468 p_read[count] = '\0';
469
470 // skip over leading newlines
471 while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
472 s_ATBufferCur++;
473
474 p_eol = findNextEOL(s_ATBufferCur);
475 p_read += count;
476 }
477 else if (count <= 0)
478 {
479 /* read error encountered or EOF reached */
480 if(count == 0)
481 {
482 LOGD("atchannel: EOF reached");
483 }
484 else
485 {
486 LOGD("atchannel: read error %s", strerror(errno));
487 }
488 return NULL;
489 }
490 }
491
492 /* a full line in the buffer. Place a \0 over the \r and return */
493
494 ret = s_ATBufferCur;
495 *p_eol = '\0';
496 s_ATBufferCur = p_eol + 1; /* this will always be <= p_read, */
497 /* and there will be a \0 at *p_read */
498
499 LOGD("AT< %s", ret);
500 return ret;
501}
502
503static const char *readlineUrc()
504{
505 ssize_t count;
506
507 char *p_read = NULL;
508 char *p_eol = NULL;
509 char *ret;
510
511 /* this is a little odd. I use *s_ATBufferCur == 0 to
512 * mean "buffer consumed completely". If it points to a character, than
513 * the buffer continues until a \0
514 */
515 if (*s_UartBufferCur == '\0')
516 {
517 /* empty buffer */
518 s_UartBufferCur = s_UartBuffer;
519 *s_UartBufferCur = '\0';
520 p_read = s_UartBuffer;
521 }
522 else /* *s_ATBufferCur != '\0' */
523 {
524 /* there's data in the buffer from the last read */
525
526 // skip over leading newlines
527 while (*s_UartBufferCur == '\r' || *s_UartBufferCur == '\n')
528 s_UartBufferCur++;
529
530 p_eol = findNextEOL(s_UartBufferCur);
531
532 if (p_eol == NULL)
533 {
534 /* a partial line. move it up and prepare to read more */
535 size_t len;
536
537 len = strlen(s_UartBufferCur);
538
539 memmove(s_UartBuffer, s_UartBufferCur, len + 1);
540 p_read = s_UartBuffer + len;
541 s_UartBufferCur = s_UartBuffer;
542 }
543 /* Otherwise, (p_eol !- NULL) there is a complete line */
544 /* that will be returned the while () loop below */
545 }
546
547 while (p_eol == NULL)
548 {
549 if (0 == MAX_AT_RESPONSE - (p_read - s_UartBuffer))
550 {
551 LOGE("ERROR: Input line exceeded buffer\n");
552 /* ditch buffer and start over again */
553 s_UartBufferCur = s_UartBuffer;
554 *s_UartBufferCur = '\0';
555 p_read = s_UartBuffer;
556 }
557
558 do
559 {
560 count = read(s_uart_fd, p_read,
561 MAX_AT_RESPONSE - (p_read - s_UartBuffer));
562 usleep(10000);
563 }
564 while (count < 0 && errno == EINTR);
565
566 if (count > 0)
567 {
568 AT_DUMP( "<< ", p_read, count );
569
570 p_read[count] = '\0';
571
572 // skip over leading newlines
573 while (*s_UartBufferCur == '\r' || *s_UartBufferCur == '\n')
574 s_UartBufferCur++;
575
576 p_eol = findNextEOL(s_UartBufferCur);
577 p_read += count;
578 }
579 else if (count <= 0)
580 {
581 /* read error encountered or EOF reached */
582 if(count == 0)
583 {
584 LOGD("atchannel: EOF reached");
585 }
586 else
587 {
588 LOGD("atchannel: read error %s", strerror(errno));
589 }
590 return NULL;
591 }
592 }
593
594 /* a full line in the buffer. Place a \0 over the \r and return */
595
596 ret = s_UartBufferCur;
597 *p_eol = '\0';
598 s_UartBufferCur = p_eol + 1; /* this will always be <= p_read, */
599 /* and there will be a \0 at *p_read */
600
601 LOGD("URC< %s", ret);
602 return ret;
603}
604
605
606
607static void onReaderClosed()
608{
609 LOGD("onReaderClosed()");
610 if (s_onReaderClosed != NULL && s_readerClosed == 0)
611 {
612
613 pthread_mutex_lock(&s_commandmutex);
614
615 s_readerClosed = 1;
616
617 pthread_cond_signal(&s_commandcond);
618
619 pthread_mutex_unlock(&s_commandmutex);
620
621 s_onReaderClosed();
622 }
623}
624
625typedef struct
626{
627 int cid;
628 bool act;
629 bool waitting;
630} info_cgact_wait_t;
631extern info_cgact_wait_t cgact_wait;
632
633static void *readerLoop(void *arg)
634{
635 UNUSED(arg);
636 for (;;)
637 {
638 const char * line;
639
640 line = readline();
641
642 if (line == NULL)
643 {
644 break;
645 }
646
647 if(strStartsWith(line, "MBTK_AT_READY")) {
648 //handleUnsolicited(line);
649 continue;
650 } else if(strStartsWith(line, "CONNECT")) {
651 if(cgact_wait.waitting && cgact_wait.act) {
652 cgact_wait.waitting = false;
653 }
654 }
655
656 if(isSMSUnsolicited(line))
657 {
658 char *line1;
659 const char *line2;
660
661 // The scope of string returned by 'readline()' is valid only
662 // till next call to 'readline()' hence making a copy of line
663 // before calling readline again.
664 line1 = strdup(line);
665 line2 = readline();
666
667 if (line2 == NULL)
668 {
669 free(line1);
670 break;
671 }
672
673 if (s_unsolHandler != NULL)
674 {
675 s_unsolHandler (line1, line2);
676 }
677 free(line1);
678 }
679 else
680 {
681 processLine(line);
682 }
683 }
684
685 onReaderClosed();
686
687 return NULL;
688}
689
690static void *readerUrcLoop(void *arg)
691{
692 UNUSED(arg);
693 for (;;)
694 {
695 const char *line;
696
697 line = readlineUrc();
698
699 if (line == NULL)
700 {
701 break;
702 }
703
704 handleUnsolicited(line);
705 }
706
707 onReaderClosed();
708
709 return NULL;
710}
711
712
713/**
714 * Sends string s to the radio with a \r appended.
715 * Returns AT_ERROR_* on error, 0 on success
716 *
717 * This function exists because as of writing, android libc does not
718 * have buffered stdio.
719 */
720static int writeline (const char *s)
721{
722 size_t cur = 0;
723 size_t len = strlen(s);
724 ssize_t written;
725
726 if (s_at_fd < 0 || s_readerClosed > 0)
727 {
728 return AT_ERROR_CHANNEL_CLOSED;
729 }
730
731 LOGD("AT> %s", s);
732
733 AT_DUMP( ">> ", s, strlen(s) );
734
735 memset(s_curr_at, 0x0, AT_BUFF_MAX);
736 memcpy(s_curr_at, s, strlen(s));
737
738 /* the main string */
739 while (cur < len)
740 {
741 do
742 {
743 written = write (s_at_fd, s + cur, len - cur);
744 }
745 while (written < 0 && errno == EINTR);
746
747 if (written < 0)
748 {
749 return AT_ERROR_GENERIC;
750 }
751
752 cur += written;
753 }
754
755 /* the \r */
756
757 do
758 {
759 written = write (s_at_fd, "\r", 1);
760 }
761 while ((written < 0 && errno == EINTR) || (written == 0));
762
763 if (written < 0)
764 {
765 return AT_ERROR_GENERIC;
766 }
767
768 return 0;
769}
770
771static int writeCtrlZ (const char *s)
772{
773 size_t cur = 0;
774 size_t len = strlen(s);
775 ssize_t written;
776
777 if (s_at_fd < 0 || s_readerClosed > 0)
778 {
779 return AT_ERROR_CHANNEL_CLOSED;
780 }
781
782 LOGD("AT> %s^Z\n", s);
783
784 AT_DUMP( ">* ", s, strlen(s) );
785
786 /* the main string */
787 while (cur < len)
788 {
789 do
790 {
791 written = write (s_at_fd, s + cur, len - cur);
792 }
793 while (written < 0 && errno == EINTR);
794
795 if (written < 0)
796 {
797 return AT_ERROR_GENERIC;
798 }
799
800 cur += written;
801 }
802
803 /* the ^Z */
804
805 do
806 {
807 written = write (s_at_fd, "\032", 1);
808 }
809 while ((written < 0 && errno == EINTR) || (written == 0));
810
811 if (written < 0)
812 {
813 return AT_ERROR_GENERIC;
814 }
815
816 return 0;
817}
818
819static void clearPendingCommand()
820{
821 if (sp_response != NULL)
822 {
823 at_response_free(sp_response);
824 }
825
826 sp_response = NULL;
827 s_responsePrefix = NULL;
828 s_smsPDU = NULL;
829}
830
831
832/**
833 * Starts AT handler on stream "fd'
834 * returns 0 on success, -1 on error
835 */
836int at_open(int at_fd, int uart_fd, ATUnsolHandler h)
837{
838 int ret;
839 pthread_attr_t attr;
840
841 s_at_fd = at_fd;
842 s_uart_fd = uart_fd;
843 s_unsolHandler = h;
844 s_readerClosed = 0;
845 s_responsePrefix = NULL;
846 s_smsPDU = NULL;
847 sp_response = NULL;
848
849 pthread_attr_init (&attr);
850 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
b.liu9e8584b2024-11-06 19:21:28 +0800851 ret = pthread_create(&s_tid_reader, &attr, readerLoop, NULL);
liubin281ac462023-07-19 14:22:54 +0800852 if (ret < 0)
853 {
854 LOGE("AT thread create fail.");
855 return -1;
856 }
857
858 pthread_t uart_tid_reader;
b.liu9e8584b2024-11-06 19:21:28 +0800859 ret = pthread_create(&uart_tid_reader, &attr, readerUrcLoop, NULL);
liubin281ac462023-07-19 14:22:54 +0800860 if (ret < 0)
861 {
862 LOGE("Uart thread create fail.");
863 return -1;
864 }
865
866 return 0;
867}
868
869/* FIXME is it ok to call this from the reader and the command thread? */
870void at_close()
871{
872 LOGD("at_close()");
873 if (s_at_fd >= 0)
874 {
875 close(s_at_fd);
876 }
877 if (s_uart_fd >= 0)
878 {
879 close(s_uart_fd);
880 }
881 s_at_fd = -1;
882 s_uart_fd = -1;
883
884 pthread_mutex_lock(&s_commandmutex);
885 s_readerClosed = 1;
886 pthread_cond_signal(&s_commandcond);
887 pthread_mutex_unlock(&s_commandmutex);
888 /* the reader thread should eventually die */
889
890 at_state = RIL_AT_STATE_CLOSED;
891}
892
893static ATResponse * at_response_new()
894{
895 return (ATResponse *) calloc(1, sizeof(ATResponse));
896}
897
898void at_response_free(ATResponse *p_response)
899{
900 ATLine *p_line;
901
902 if (p_response == NULL) return;
903
904 p_line = p_response->p_intermediates;
905
906 while (p_line != NULL)
907 {
908 ATLine *p_toFree;
909
910 p_toFree = p_line;
911 p_line = p_line->p_next;
912
913 free(p_toFree->line);
914 free(p_toFree);
915 }
916
917 free (p_response->finalResponse);
918 free (p_response);
919}
920
921/**
922 * The line reader places the intermediate responses in reverse order
923 * here we flip them back
924 */
925static void reverseIntermediates(ATResponse *p_response)
926{
927 ATLine *pcur,*pnext;
928
929 pcur = p_response->p_intermediates;
930 p_response->p_intermediates = NULL;
931
932 while (pcur != NULL)
933 {
934 pnext = pcur->p_next;
935 pcur->p_next = p_response->p_intermediates;
936 p_response->p_intermediates = pcur;
937 pcur = pnext;
938 }
939}
940
941static long long at_timeout_get(const char *at_command, bool *timeout_close)
942{
943 long long timeout = 0;
944 int i;
945 for(i = 0; i < ARRAY_SIZE(at_timeout_list); i++)
946 {
947 if(!strncasecmp(at_command, at_timeout_list[i].at_command, strlen(at_timeout_list[i].at_command)))
948 {
949 timeout = at_timeout_list[i].timeout;
950 *timeout_close = at_timeout_list[i].timeout_close;
951 break;
952 }
953 }
954
955 return timeout;
956}
957
958/**
959 * Internal send_command implementation
960 * Doesn't lock or call the timeout callback
961 *
962 * timeoutMsec == 0 means infinite timeout
963 */
964static int at_send_command_full_nolock (const char *command, ATCommandType type,
965 const char *responsePrefix, const char *smspdu,
966 long long timeoutMsec, ATResponse **pp_outResponse)
967{
968 int err = 0;
969 bool tiemout_close = true;
970 struct timespec ts;
971 if(at_state == RIL_AT_STATE_READY)
972 at_state = RIL_AT_STATE_BUSY;
973
974 if(sp_response != NULL)
975 {
976 err = AT_ERROR_COMMAND_PENDING;
977 goto error;
978 }
979
980 err = writeline (command);
981
982 if (err < 0)
983 {
984 goto error;
985 }
986
987 s_type = type;
988 s_responsePrefix = responsePrefix;
989 s_smsPDU = smspdu;
990 sp_response = at_response_new();
991
992 if(timeoutMsec == 0)
993 {
994 timeoutMsec = at_timeout_get(command, &tiemout_close);
995 }
996
997 if (timeoutMsec != 0)
998 {
999 setTimespecRelative(&ts, timeoutMsec);
1000 }
1001
1002 while (sp_response->finalResponse == NULL && s_readerClosed == 0)
1003 {
1004 //LOGD("AT wait time:%lld",timeoutMsec);
1005 if (timeoutMsec != 0)
1006 {
1007 err = pthread_cond_timedwait(&s_commandcond, &s_commandmutex, &ts);
1008 }
1009 else
1010 {
1011 err = pthread_cond_wait(&s_commandcond, &s_commandmutex);
1012 }
1013
1014 //LOGD("AT continue:err - %d",err);
1015 if (err == ETIMEDOUT)
1016 {
1017 if(tiemout_close)
1018 {
1019 err = AT_ERROR_TIMEOUT_CLOSE;
1020 }
1021 else
1022 {
1023 err = AT_ERROR_TIMEOUT;
1024 }
1025 goto error;
1026 }
1027 }
1028
1029 if (pp_outResponse == NULL)
1030 {
1031 at_response_free(sp_response);
1032 }
1033 else
1034 {
1035 /* line reader stores intermediate responses in reverse order */
1036 reverseIntermediates(sp_response);
1037 *pp_outResponse = sp_response;
1038 }
1039
1040 sp_response = NULL;
1041
1042 if(s_readerClosed > 0)
1043 {
1044 err = AT_ERROR_CHANNEL_CLOSED;
1045 goto error;
1046 }
1047
1048 err = 0;
1049error:
1050 if(at_state == RIL_AT_STATE_BUSY)
1051 at_state = RIL_AT_STATE_READY;
1052 clearPendingCommand();
1053
1054 return err;
1055}
1056
1057/**
1058 * Internal send_command implementation
1059 *
1060 * timeoutMsec == 0 means infinite timeout
1061 */
1062static int at_send_command_full (const char *command, ATCommandType type,
1063 const char *responsePrefix, const char *smspdu,
1064 long long timeoutMsec, ATResponse **pp_outResponse)
1065{
1066 int err;
1067
1068 if (0 != pthread_equal(s_tid_reader, pthread_self()))
1069 {
1070 /* cannot be called from reader thread */
1071 LOGE("cannot be called from reader thread.");
1072 return AT_ERROR_INVALID_THREAD;
1073 }
1074
1075 // Waitting for previous AT complete.
1076 while(at_state == RIL_AT_STATE_BUSY)
1077 {
1078 usleep(10000);
1079 }
1080
1081 pthread_mutex_lock(&s_commandmutex);
1082
1083 err = at_send_command_full_nolock(command, type,
1084 responsePrefix, smspdu,
1085 timeoutMsec, pp_outResponse);
1086
1087 pthread_mutex_unlock(&s_commandmutex);
1088
1089 if (err == AT_ERROR_TIMEOUT_CLOSE && s_onTimeout != NULL)
1090 {
1091 s_onTimeout();
1092 }
1093
1094 return err;
1095}
1096
1097
1098/**
1099 * Issue a single normal AT command with no intermediate response expected
1100 *
1101 * "command" should not include \r
1102 * pp_outResponse can be NULL
1103 *
1104 * if non-NULL, the resulting ATResponse * must be eventually freed with
1105 * at_response_free
1106 */
1107int at_send_command (const char *command, ATResponse **pp_outResponse)
1108{
1109 return at_send_command_full (command, NO_RESULT, NULL,
1110 NULL, 0, pp_outResponse);
1111}
1112
1113
1114int at_send_command_singleline (const char *command,
1115 const char *responsePrefix,
1116 ATResponse **pp_outResponse)
1117{
1118 int err;
1119
1120 err = at_send_command_full (command, SINGLELINE, responsePrefix,
1121 NULL, 0, pp_outResponse);
1122
1123 if (err == 0 && pp_outResponse != NULL
1124 && (*pp_outResponse)->success > 0
1125 && (*pp_outResponse)->p_intermediates == NULL
1126 )
1127 {
1128 /* successful command must have an intermediate response */
1129 at_response_free(*pp_outResponse);
1130 *pp_outResponse = NULL;
1131 return AT_ERROR_INVALID_RESPONSE;
1132 }
1133
1134 return err;
1135}
1136
1137int at_send_command_singleline_with_timeout (const char *command,
1138 const char *responsePrefix,
1139 ATResponse **pp_outResponse,long long timeoutMsec)
1140{
1141 int err;
1142
1143 err = at_send_command_full (command, SINGLELINE, responsePrefix,
1144 NULL, timeoutMsec, pp_outResponse);
1145
1146 if (err == 0 && pp_outResponse != NULL
1147 && (*pp_outResponse)->success > 0
1148 && (*pp_outResponse)->p_intermediates == NULL
1149 )
1150 {
1151 /* successful command must have an intermediate response */
1152 at_response_free(*pp_outResponse);
1153 *pp_outResponse = NULL;
1154 return AT_ERROR_INVALID_RESPONSE;
1155 }
1156
1157 return err;
1158}
1159
1160
1161
1162int at_send_command_numeric (const char *command,
1163 ATResponse **pp_outResponse)
1164{
1165 int err;
1166
1167 err = at_send_command_full (command, NUMERIC, NULL,
1168 NULL, 0, pp_outResponse);
1169
1170 if (err == 0 && pp_outResponse != NULL
1171 && (*pp_outResponse)->success > 0
1172 && (*pp_outResponse)->p_intermediates == NULL
1173 )
1174 {
1175 /* successful command must have an intermediate response */
1176 at_response_free(*pp_outResponse);
1177 *pp_outResponse = NULL;
1178 return AT_ERROR_INVALID_RESPONSE;
1179 }
1180
1181 return err;
1182}
1183
1184
1185int at_send_command_sms (const char *command,
1186 const char *pdu,
1187 const char *responsePrefix,
1188 ATResponse **pp_outResponse)
1189{
1190 int err;
1191
1192 err = at_send_command_full (command, SINGLELINE, responsePrefix,
1193 pdu, 0, pp_outResponse);
1194
1195 if (err == 0 && pp_outResponse != NULL
1196 && (*pp_outResponse)->success > 0
1197 && (*pp_outResponse)->p_intermediates == NULL
1198 )
1199 {
1200 /* successful command must have an intermediate response */
1201 at_response_free(*pp_outResponse);
1202 *pp_outResponse = NULL;
1203 return AT_ERROR_INVALID_RESPONSE;
1204 }
1205
1206 return err;
1207}
1208
1209
1210int at_send_command_multiline (const char *command,
1211 const char *responsePrefix,
1212 ATResponse **pp_outResponse)
1213{
1214 int err;
1215
1216 err = at_send_command_full (command, MULTILINE, responsePrefix,
1217 NULL, 0, pp_outResponse);
1218
1219 return err;
1220}
1221
1222
1223/** This callback is invoked on the command thread */
1224void at_set_on_timeout(void (*onTimeout)(void))
1225{
1226 s_onTimeout = onTimeout;
1227}
1228
1229/**
1230 * This callback is invoked on the reader thread (like ATUnsolHandler)
1231 * when the input stream closes before you call at_close
1232 * (not when you call at_close())
1233 * You should still call at_close()
1234 */
1235
1236void at_set_on_reader_closed(void (*onClose)(void))
1237{
1238 s_onReaderClosed = onClose;
1239}
1240
1241
1242/**
1243 * Periodically issue an AT command and wait for a response.
1244 * Used to ensure channel has start up and is active
1245 */
1246int at_handshake()
1247{
b.liu9e8584b2024-11-06 19:21:28 +08001248// int i;
liubin281ac462023-07-19 14:22:54 +08001249 int err = 0;
1250
1251 if (0 != pthread_equal(s_tid_reader, pthread_self()))
1252 {
1253 /* cannot be called from reader thread */
1254 return AT_ERROR_INVALID_THREAD;
1255 }
1256 pthread_mutex_lock(&s_commandmutex);
1257
1258#if 0
1259 for (i = 0 ; i < HANDSHAKE_RETRY_COUNT ; i++)
1260 {
1261 /* some stacks start with verbose off */
1262 err = at_send_command_full_nolock("ATE0Q0V1", NO_RESULT,
1263 NULL, NULL, HANDSHAKE_TIMEOUT_MSEC, NULL);
1264
1265 if (err == 0)
1266 {
1267 break;
1268 }
1269 }
1270#else
1271 err = at_send_command_full_nolock("ATE0Q0V1", NO_RESULT,
1272 NULL, NULL, 0, NULL);
1273#endif
1274
1275 if (err == 0)
1276 {
1277 /* pause for a bit to let the input buffer drain any unmatched OK's
1278 (they will appear as extraneous unsolicited responses) */
1279 sleepMsec(HANDSHAKE_TIMEOUT_MSEC);
1280 }
1281
1282 pthread_mutex_unlock(&s_commandmutex);
1283
1284
1285 return err;
1286}
1287
1288/**
1289 * Returns error code from response
1290 * Assumes AT+CMEE=1 (numeric) mode
1291 */
b.liu5eb525a2025-05-24 10:47:40 +08001292AT_CME_Error at_get_cme_error(const ATResponse *p_response)
liubin281ac462023-07-19 14:22:54 +08001293{
1294 int ret;
1295 int err;
1296 char *p_cur;
1297
1298 if (p_response->success > 0)
1299 {
1300 return CME_SUCCESS;
1301 }
1302
1303 if (p_response->finalResponse == NULL
1304 || !strStartsWith(p_response->finalResponse, "+CME ERROR:")
1305 )
1306 {
1307 return CME_ERROR_NON_CME;
1308 }
1309
1310 p_cur = p_response->finalResponse;
1311 err = at_tok_start(&p_cur);
1312
1313 if (err < 0)
1314 {
1315 return CME_ERROR_NON_CME;
1316 }
1317
1318 err = at_tok_nextint(&p_cur, &ret);
1319
1320 if (err < 0)
1321 {
1322 return CME_ERROR_NON_CME;
1323 }
1324
1325 return ret;
1326}
1327
1328mbtk_ril_at_state_enum at_state_get()
1329{
1330 return at_state;
1331}
1332
1333void at_state_set(mbtk_ril_at_state_enum state)
1334{
1335 at_state = state;
1336}
1337
1338bool at_rsp_check(ATResponse *p_response)
1339{
1340 if(!p_response || !p_response->success)
1341 return false;
1342
1343 return true;
1344}
1345
1346void unused_func()
1347{
1348 isFinalResponse(NULL);
1349}
1350