blob: 316e62a842e1a8720ce6ec079fbfc3f9e1727732 [file] [log] [blame]
b.liu87afc4c2024-08-14 17:33:45 +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.liu15f456b2024-10-31 20:16:06 +080039#define AT_BUFF_MAX 1024
b.liu87afc4c2024-08-14 17:33:45 +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);
324 line_temp++;
325 if(strlen(line_temp) > 0)
326 {
327 char *ptr = line_temp + strlen(line_temp) - 1;
328 while(ptr >= line_temp && *ptr == '"')
329 {
330 *ptr = '\0';
331 ptr--;
332 }
333 }
334 addIntermediate(line_temp);
335 free(line_temp);
336 }
337 else
338 {
339 addIntermediate(line);
340 }
341 }
342 else
343 {
344 /* we already have an intermediate response */
345 handleUnsolicited(line);
346 }
347 break;
348 case MULTILINE:
349 if (strStartsWith (line, s_responsePrefix))
350 {
351 addIntermediate(line);
352 }
353 else
354 {
355 handleUnsolicited(line);
356 }
357 break;
358
359 default: /* this should never be reached */
360 LOGE("Unsupported AT command type %d\n", s_type);
361 handleUnsolicited(line);
362 break;
363 }
364
365 pthread_mutex_unlock(&s_commandmutex);
366}
367
368
369/**
370 * Returns a pointer to the end of the next line
371 * special-cases the "> " SMS prompt
372 *
373 * returns NULL if there is no complete line
374 */
375static char * findNextEOL(char *cur)
376{
377 if (cur[0] == '>' && cur[1] == ' ' && cur[2] == '\0')
378 {
379 /* SMS prompt character...not \r terminated */
380 return cur+2;
381 }
382
383 // Find next newline
384 while (*cur != '\0' && *cur != '\r' && *cur != '\n') cur++;
385
386 return *cur == '\0' ? NULL : cur;
387}
388
389
390/**
391 * Reads a line from the AT channel, returns NULL on timeout.
392 * Assumes it has exclusive read access to the FD
393 *
394 * This line is valid only until the next call to readline
395 *
396 * This function exists because as of writing, android libc does not
397 * have buffered stdio.
398 */
399
400static const char *readline()
401{
402 ssize_t count;
403
404 char *p_read = NULL;
405 char *p_eol = NULL;
406 char *ret;
407
408 /* this is a little odd. I use *s_ATBufferCur == 0 to
409 * mean "buffer consumed completely". If it points to a character, than
410 * the buffer continues until a \0
411 */
412 if (*s_ATBufferCur == '\0')
413 {
414 /* empty buffer */
415 s_ATBufferCur = s_ATBuffer;
416 *s_ATBufferCur = '\0';
417 p_read = s_ATBuffer;
418 }
419 else /* *s_ATBufferCur != '\0' */
420 {
421 /* there's data in the buffer from the last read */
422
423 // skip over leading newlines
424 while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
425 s_ATBufferCur++;
426
427 p_eol = findNextEOL(s_ATBufferCur);
428
429 if (p_eol == NULL)
430 {
431 /* a partial line. move it up and prepare to read more */
432 size_t len;
433
434 len = strlen(s_ATBufferCur);
435
436 memmove(s_ATBuffer, s_ATBufferCur, len + 1);
437 p_read = s_ATBuffer + len;
438 s_ATBufferCur = s_ATBuffer;
439 }
440 /* Otherwise, (p_eol !- NULL) there is a complete line */
441 /* that will be returned the while () loop below */
442 }
443
444 while (p_eol == NULL)
445 {
446 if (0 == MAX_AT_RESPONSE - (p_read - s_ATBuffer))
447 {
448 LOGE("ERROR: Input line exceeded buffer\n");
449 /* ditch buffer and start over again */
450 s_ATBufferCur = s_ATBuffer;
451 *s_ATBufferCur = '\0';
452 p_read = s_ATBuffer;
453 }
454
455 do
456 {
457 count = read(s_at_fd, p_read,
458 MAX_AT_RESPONSE - (p_read - s_ATBuffer));
459 usleep(10000);
460 }
461 while (count < 0 && errno == EINTR);
462
463 if (count > 0)
464 {
465 AT_DUMP( "<< ", p_read, count );
466
467 p_read[count] = '\0';
468
469 // skip over leading newlines
470 while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
471 s_ATBufferCur++;
472
473 p_eol = findNextEOL(s_ATBufferCur);
474 p_read += count;
475 }
476 else if (count <= 0)
477 {
478 /* read error encountered or EOF reached */
479 if(count == 0)
480 {
481 LOGD("atchannel: EOF reached");
482 }
483 else
484 {
485 LOGD("atchannel: read error %s", strerror(errno));
486 }
487 return NULL;
488 }
489 }
490
491 /* a full line in the buffer. Place a \0 over the \r and return */
492
493 ret = s_ATBufferCur;
494 *p_eol = '\0';
495 s_ATBufferCur = p_eol + 1; /* this will always be <= p_read, */
496 /* and there will be a \0 at *p_read */
497
498 LOGD("AT< %s", ret);
499 return ret;
500}
501
502static const char *readlineUrc()
503{
504 ssize_t count;
505
506 char *p_read = NULL;
507 char *p_eol = NULL;
508 char *ret;
509
510 /* this is a little odd. I use *s_ATBufferCur == 0 to
511 * mean "buffer consumed completely". If it points to a character, than
512 * the buffer continues until a \0
513 */
514 if (*s_UartBufferCur == '\0')
515 {
516 /* empty buffer */
517 s_UartBufferCur = s_UartBuffer;
518 *s_UartBufferCur = '\0';
519 p_read = s_UartBuffer;
520 }
521 else /* *s_ATBufferCur != '\0' */
522 {
523 /* there's data in the buffer from the last read */
524
525 // skip over leading newlines
526 while (*s_UartBufferCur == '\r' || *s_UartBufferCur == '\n')
527 s_UartBufferCur++;
528
529 p_eol = findNextEOL(s_UartBufferCur);
530
531 if (p_eol == NULL)
532 {
533 /* a partial line. move it up and prepare to read more */
534 size_t len;
535
536 len = strlen(s_UartBufferCur);
537
538 memmove(s_UartBuffer, s_UartBufferCur, len + 1);
539 p_read = s_UartBuffer + len;
540 s_UartBufferCur = s_UartBuffer;
541 }
542 /* Otherwise, (p_eol !- NULL) there is a complete line */
543 /* that will be returned the while () loop below */
544 }
545
546 while (p_eol == NULL)
547 {
548 if (0 == MAX_AT_RESPONSE - (p_read - s_UartBuffer))
549 {
550 LOGE("ERROR: Input line exceeded buffer\n");
551 /* ditch buffer and start over again */
552 s_UartBufferCur = s_UartBuffer;
553 *s_UartBufferCur = '\0';
554 p_read = s_UartBuffer;
555 }
556
557 do
558 {
559 count = read(s_uart_fd, p_read,
560 MAX_AT_RESPONSE - (p_read - s_UartBuffer));
561 usleep(10000);
562 }
563 while (count < 0 && errno == EINTR);
564
565 if (count > 0)
566 {
567 AT_DUMP( "<< ", p_read, count );
568
569 p_read[count] = '\0';
570
571 // skip over leading newlines
572 while (*s_UartBufferCur == '\r' || *s_UartBufferCur == '\n')
573 s_UartBufferCur++;
574
575 p_eol = findNextEOL(s_UartBufferCur);
576 p_read += count;
577 }
578 else if (count <= 0)
579 {
580 /* read error encountered or EOF reached */
581 if(count == 0)
582 {
583 LOGD("atchannel: EOF reached");
584 }
585 else
586 {
587 LOGD("atchannel: read error %s", strerror(errno));
588 }
589 return NULL;
590 }
591 }
592
593 /* a full line in the buffer. Place a \0 over the \r and return */
594
595 ret = s_UartBufferCur;
596 *p_eol = '\0';
597 s_UartBufferCur = p_eol + 1; /* this will always be <= p_read, */
598 /* and there will be a \0 at *p_read */
599
600 LOGD("URC< %s", ret);
601 return ret;
602}
603
604
605
606static void onReaderClosed()
607{
608 LOGD("onReaderClosed()");
609 if (s_onReaderClosed != NULL && s_readerClosed == 0)
610 {
611
612 pthread_mutex_lock(&s_commandmutex);
613
614 s_readerClosed = 1;
615
616 pthread_cond_signal(&s_commandcond);
617
618 pthread_mutex_unlock(&s_commandmutex);
619
620 s_onReaderClosed();
621 }
622}
623
624static void *readerLoop(void *arg)
625{
626 UNUSED(arg);
627 for (;;)
628 {
629 const char * line;
630
631 line = readline();
632
633 if (line == NULL)
634 {
635 break;
636 }
637
638 if(strStartsWith(line, "MBTK_AT_READY")) {
639 //handleUnsolicited(line);
640 continue;
641 }
642
643 if(isSMSUnsolicited(line))
644 {
645 char *line1;
646 const char *line2;
647
648 // The scope of string returned by 'readline()' is valid only
649 // till next call to 'readline()' hence making a copy of line
650 // before calling readline again.
651 line1 = strdup(line);
652 line2 = readline();
653
654 if (line2 == NULL)
655 {
656 free(line1);
657 break;
658 }
659
660 if (s_unsolHandler != NULL)
661 {
662 s_unsolHandler (line1, line2);
663 }
664 free(line1);
665 }
666 else
667 {
668 processLine(line);
669 }
670 }
671
672 onReaderClosed();
673
674 return NULL;
675}
676
677static void *readerUrcLoop(void *arg)
678{
679 UNUSED(arg);
680 for (;;)
681 {
682 const char *line;
683
684 line = readlineUrc();
685
686 if (line == NULL)
687 {
688 break;
689 }
690
691 handleUnsolicited(line);
692 }
693
694 onReaderClosed();
695
696 return NULL;
697}
698
699
700/**
701 * Sends string s to the radio with a \r appended.
702 * Returns AT_ERROR_* on error, 0 on success
703 *
704 * This function exists because as of writing, android libc does not
705 * have buffered stdio.
706 */
707static int writeline (const char *s)
708{
709 size_t cur = 0;
710 size_t len = strlen(s);
711 ssize_t written;
712
713 if (s_at_fd < 0 || s_readerClosed > 0)
714 {
715 return AT_ERROR_CHANNEL_CLOSED;
716 }
717
718 LOGD("AT> %s", s);
719
720 AT_DUMP( ">> ", s, strlen(s) );
721
722 memset(s_curr_at, 0x0, AT_BUFF_MAX);
723 memcpy(s_curr_at, s, strlen(s));
724
725 /* the main string */
726 while (cur < len)
727 {
728 do
729 {
730 written = write (s_at_fd, s + cur, len - cur);
731 }
732 while (written < 0 && errno == EINTR);
733
734 if (written < 0)
735 {
736 return AT_ERROR_GENERIC;
737 }
738
739 cur += written;
740 }
741
742 /* the \r */
743
744 do
745 {
746 written = write (s_at_fd, "\r", 1);
747 }
748 while ((written < 0 && errno == EINTR) || (written == 0));
749
750 if (written < 0)
751 {
752 return AT_ERROR_GENERIC;
753 }
754
755 return 0;
756}
757
758static int writeCtrlZ (const char *s)
759{
760 size_t cur = 0;
761 size_t len = strlen(s);
762 ssize_t written;
763
764 if (s_at_fd < 0 || s_readerClosed > 0)
765 {
766 return AT_ERROR_CHANNEL_CLOSED;
767 }
768
769 LOGD("AT> %s^Z\n", s);
770
771 AT_DUMP( ">* ", s, strlen(s) );
772
773 /* the main string */
774 while (cur < len)
775 {
776 do
777 {
778 written = write (s_at_fd, s + cur, len - cur);
779 }
780 while (written < 0 && errno == EINTR);
781
782 if (written < 0)
783 {
784 return AT_ERROR_GENERIC;
785 }
786
787 cur += written;
788 }
789
790 /* the ^Z */
791
792 do
793 {
794 written = write (s_at_fd, "\032", 1);
795 }
796 while ((written < 0 && errno == EINTR) || (written == 0));
797
798 if (written < 0)
799 {
800 return AT_ERROR_GENERIC;
801 }
802
803 return 0;
804}
805
806static void clearPendingCommand()
807{
808 if (sp_response != NULL)
809 {
810 at_response_free(sp_response);
811 }
812
813 sp_response = NULL;
814 s_responsePrefix = NULL;
815 s_smsPDU = NULL;
816}
817
818
819/**
820 * Starts AT handler on stream "fd'
821 * returns 0 on success, -1 on error
822 */
823int at_open(int at_fd, int uart_fd, ATUnsolHandler h)
824{
825 int ret;
826 pthread_attr_t attr;
827
828 s_at_fd = at_fd;
829 s_uart_fd = uart_fd;
830 s_unsolHandler = h;
831 s_readerClosed = 0;
832 s_responsePrefix = NULL;
833 s_smsPDU = NULL;
834 sp_response = NULL;
835
836 pthread_attr_init (&attr);
837 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
838 ret = pthread_create(&s_tid_reader, &attr, readerLoop, NULL);
839 if (ret < 0)
840 {
841 LOGE("AT thread create fail.");
842 return -1;
843 }
844
845 pthread_t uart_tid_reader;
846 ret = pthread_create(&uart_tid_reader, &attr, readerUrcLoop, NULL);
847 if (ret < 0)
848 {
849 LOGE("Uart thread create fail.");
850 return -1;
851 }
852
853 return 0;
854}
855
856/* FIXME is it ok to call this from the reader and the command thread? */
857void at_close()
858{
859 LOGD("at_close()");
860 if (s_at_fd >= 0)
861 {
862 close(s_at_fd);
863 }
864 if (s_uart_fd >= 0)
865 {
866 close(s_uart_fd);
867 }
868 s_at_fd = -1;
869 s_uart_fd = -1;
870
871 pthread_mutex_lock(&s_commandmutex);
872 s_readerClosed = 1;
873 pthread_cond_signal(&s_commandcond);
874 pthread_mutex_unlock(&s_commandmutex);
875 /* the reader thread should eventually die */
876
877 at_state = RIL_AT_STATE_CLOSED;
878}
879
880static ATResponse * at_response_new()
881{
882 return (ATResponse *) calloc(1, sizeof(ATResponse));
883}
884
885void at_response_free(ATResponse *p_response)
886{
887 ATLine *p_line;
888
889 if (p_response == NULL) return;
890
891 p_line = p_response->p_intermediates;
892
893 while (p_line != NULL)
894 {
895 ATLine *p_toFree;
896
897 p_toFree = p_line;
898 p_line = p_line->p_next;
899
900 free(p_toFree->line);
901 free(p_toFree);
902 }
903
904 free (p_response->finalResponse);
905 free (p_response);
906}
907
908/**
909 * The line reader places the intermediate responses in reverse order
910 * here we flip them back
911 */
912static void reverseIntermediates(ATResponse *p_response)
913{
914 ATLine *pcur,*pnext;
915
916 pcur = p_response->p_intermediates;
917 p_response->p_intermediates = NULL;
918
919 while (pcur != NULL)
920 {
921 pnext = pcur->p_next;
922 pcur->p_next = p_response->p_intermediates;
923 p_response->p_intermediates = pcur;
924 pcur = pnext;
925 }
926}
927
928static long long at_timeout_get(const char *at_command, bool *timeout_close)
929{
930 long long timeout = 0;
931 int i;
932 for(i = 0; i < ARRAY_SIZE(at_timeout_list); i++)
933 {
934 if(!strncasecmp(at_command, at_timeout_list[i].at_command, strlen(at_timeout_list[i].at_command)))
935 {
936 timeout = at_timeout_list[i].timeout;
937 *timeout_close = at_timeout_list[i].timeout_close;
938 break;
939 }
940 }
941
942 return timeout;
943}
944
945/**
946 * Internal send_command implementation
947 * Doesn't lock or call the timeout callback
948 *
949 * timeoutMsec == 0 means infinite timeout
950 */
951static int at_send_command_full_nolock (const char *command, ATCommandType type,
952 const char *responsePrefix, const char *smspdu,
953 long long timeoutMsec, ATResponse **pp_outResponse)
954{
955 int err = 0;
956 bool tiemout_close = true;
957 struct timespec ts;
958 if(at_state == RIL_AT_STATE_READY)
959 at_state = RIL_AT_STATE_BUSY;
960
961 if(sp_response != NULL)
962 {
963 err = AT_ERROR_COMMAND_PENDING;
964 goto error;
965 }
966
967 err = writeline (command);
968
969 if (err < 0)
970 {
971 goto error;
972 }
973
974 s_type = type;
975 s_responsePrefix = responsePrefix;
976 s_smsPDU = smspdu;
977 sp_response = at_response_new();
978
979 if(timeoutMsec == 0)
980 {
981 timeoutMsec = at_timeout_get(command, &tiemout_close);
982 }
983
984 if (timeoutMsec != 0)
985 {
986 setTimespecRelative(&ts, timeoutMsec);
987 }
988
989 while (sp_response->finalResponse == NULL && s_readerClosed == 0)
990 {
991 //LOGD("AT wait time:%lld",timeoutMsec);
992 if (timeoutMsec != 0)
993 {
994 err = pthread_cond_timedwait(&s_commandcond, &s_commandmutex, &ts);
995 }
996 else
997 {
998 err = pthread_cond_wait(&s_commandcond, &s_commandmutex);
999 }
1000
1001 //LOGD("AT continue:err - %d",err);
1002 if (err == ETIMEDOUT)
1003 {
1004 if(tiemout_close)
1005 {
1006 err = AT_ERROR_TIMEOUT_CLOSE;
1007 }
1008 else
1009 {
1010 err = AT_ERROR_TIMEOUT;
1011 }
1012 goto error;
1013 }
1014 }
1015
1016 if (pp_outResponse == NULL)
1017 {
1018 at_response_free(sp_response);
1019 }
1020 else
1021 {
1022 /* line reader stores intermediate responses in reverse order */
1023 reverseIntermediates(sp_response);
1024 *pp_outResponse = sp_response;
1025 }
1026
1027 sp_response = NULL;
1028
1029 if(s_readerClosed > 0)
1030 {
1031 err = AT_ERROR_CHANNEL_CLOSED;
1032 goto error;
1033 }
1034
1035 err = 0;
1036error:
1037 if(at_state == RIL_AT_STATE_BUSY)
1038 at_state = RIL_AT_STATE_READY;
1039 clearPendingCommand();
1040
1041 return err;
1042}
1043
1044/**
1045 * Internal send_command implementation
1046 *
1047 * timeoutMsec == 0 means infinite timeout
1048 */
1049static int at_send_command_full (const char *command, ATCommandType type,
1050 const char *responsePrefix, const char *smspdu,
1051 long long timeoutMsec, ATResponse **pp_outResponse)
1052{
1053 int err;
1054
1055 if (0 != pthread_equal(s_tid_reader, pthread_self()))
1056 {
1057 /* cannot be called from reader thread */
1058 LOGE("cannot be called from reader thread.");
1059 return AT_ERROR_INVALID_THREAD;
1060 }
1061
1062 // Waitting for previous AT complete.
1063 while(at_state == RIL_AT_STATE_BUSY)
1064 {
1065 usleep(10000);
1066 }
1067
1068 pthread_mutex_lock(&s_commandmutex);
1069
1070 err = at_send_command_full_nolock(command, type,
1071 responsePrefix, smspdu,
1072 timeoutMsec, pp_outResponse);
1073
1074 pthread_mutex_unlock(&s_commandmutex);
1075
1076 if (err == AT_ERROR_TIMEOUT_CLOSE && s_onTimeout != NULL)
1077 {
1078 s_onTimeout();
1079 }
1080
1081 return err;
1082}
1083
1084
1085/**
1086 * Issue a single normal AT command with no intermediate response expected
1087 *
1088 * "command" should not include \r
1089 * pp_outResponse can be NULL
1090 *
1091 * if non-NULL, the resulting ATResponse * must be eventually freed with
1092 * at_response_free
1093 */
1094int at_send_command (const char *command, ATResponse **pp_outResponse)
1095{
1096 return at_send_command_full (command, NO_RESULT, NULL,
1097 NULL, 0, pp_outResponse);
1098}
1099
1100
1101int at_send_command_singleline (const char *command,
1102 const char *responsePrefix,
1103 ATResponse **pp_outResponse)
1104{
1105 int err;
1106
1107 err = at_send_command_full (command, SINGLELINE, responsePrefix,
1108 NULL, 0, pp_outResponse);
1109
1110 if (err == 0 && pp_outResponse != NULL
1111 && (*pp_outResponse)->success > 0
1112 && (*pp_outResponse)->p_intermediates == NULL
1113 )
1114 {
1115 /* successful command must have an intermediate response */
1116 at_response_free(*pp_outResponse);
1117 *pp_outResponse = NULL;
1118 return AT_ERROR_INVALID_RESPONSE;
1119 }
1120
1121 return err;
1122}
1123
1124int at_send_command_singleline_with_timeout (const char *command,
1125 const char *responsePrefix,
1126 ATResponse **pp_outResponse,long long timeoutMsec)
1127{
1128 int err;
1129
1130 err = at_send_command_full (command, SINGLELINE, responsePrefix,
1131 NULL, timeoutMsec, pp_outResponse);
1132
1133 if (err == 0 && pp_outResponse != NULL
1134 && (*pp_outResponse)->success > 0
1135 && (*pp_outResponse)->p_intermediates == NULL
1136 )
1137 {
1138 /* successful command must have an intermediate response */
1139 at_response_free(*pp_outResponse);
1140 *pp_outResponse = NULL;
1141 return AT_ERROR_INVALID_RESPONSE;
1142 }
1143
1144 return err;
1145}
1146
1147
1148
1149int at_send_command_numeric (const char *command,
1150 ATResponse **pp_outResponse)
1151{
1152 int err;
1153
1154 err = at_send_command_full (command, NUMERIC, NULL,
1155 NULL, 0, pp_outResponse);
1156
1157 if (err == 0 && pp_outResponse != NULL
1158 && (*pp_outResponse)->success > 0
1159 && (*pp_outResponse)->p_intermediates == NULL
1160 )
1161 {
1162 /* successful command must have an intermediate response */
1163 at_response_free(*pp_outResponse);
1164 *pp_outResponse = NULL;
1165 return AT_ERROR_INVALID_RESPONSE;
1166 }
1167
1168 return err;
1169}
1170
1171
1172int at_send_command_sms (const char *command,
1173 const char *pdu,
1174 const char *responsePrefix,
1175 ATResponse **pp_outResponse)
1176{
1177 int err;
1178
1179 err = at_send_command_full (command, SINGLELINE, responsePrefix,
1180 pdu, 0, pp_outResponse);
1181
1182 if (err == 0 && pp_outResponse != NULL
1183 && (*pp_outResponse)->success > 0
1184 && (*pp_outResponse)->p_intermediates == NULL
1185 )
1186 {
1187 /* successful command must have an intermediate response */
1188 at_response_free(*pp_outResponse);
1189 *pp_outResponse = NULL;
1190 return AT_ERROR_INVALID_RESPONSE;
1191 }
1192
1193 return err;
1194}
1195
1196
1197int at_send_command_multiline (const char *command,
1198 const char *responsePrefix,
1199 ATResponse **pp_outResponse)
1200{
1201 int err;
1202
1203 err = at_send_command_full (command, MULTILINE, responsePrefix,
1204 NULL, 0, pp_outResponse);
1205
1206 return err;
1207}
1208
1209
1210/** This callback is invoked on the command thread */
1211void at_set_on_timeout(void (*onTimeout)(void))
1212{
1213 s_onTimeout = onTimeout;
1214}
1215
1216/**
1217 * This callback is invoked on the reader thread (like ATUnsolHandler)
1218 * when the input stream closes before you call at_close
1219 * (not when you call at_close())
1220 * You should still call at_close()
1221 */
1222
1223void at_set_on_reader_closed(void (*onClose)(void))
1224{
1225 s_onReaderClosed = onClose;
1226}
1227
1228
1229/**
1230 * Periodically issue an AT command and wait for a response.
1231 * Used to ensure channel has start up and is active
1232 */
1233int at_handshake()
1234{
1235 int i;
1236 int err = 0;
1237
1238 if (0 != pthread_equal(s_tid_reader, pthread_self()))
1239 {
1240 /* cannot be called from reader thread */
1241 return AT_ERROR_INVALID_THREAD;
1242 }
1243 pthread_mutex_lock(&s_commandmutex);
1244
1245#if 0
1246 for (i = 0 ; i < HANDSHAKE_RETRY_COUNT ; i++)
1247 {
1248 /* some stacks start with verbose off */
1249 err = at_send_command_full_nolock("ATE0Q0V1", NO_RESULT,
1250 NULL, NULL, HANDSHAKE_TIMEOUT_MSEC, NULL);
1251
1252 if (err == 0)
1253 {
1254 break;
1255 }
1256 }
1257#else
1258 err = at_send_command_full_nolock("ATE0Q0V1", NO_RESULT,
1259 NULL, NULL, 0, NULL);
1260#endif
1261
1262 if (err == 0)
1263 {
1264 /* pause for a bit to let the input buffer drain any unmatched OK's
1265 (they will appear as extraneous unsolicited responses) */
1266 sleepMsec(HANDSHAKE_TIMEOUT_MSEC);
1267 }
1268
1269 pthread_mutex_unlock(&s_commandmutex);
1270
1271
1272 return err;
1273}
1274
1275/**
1276 * Returns error code from response
1277 * Assumes AT+CMEE=1 (numeric) mode
1278 */
1279int at_get_cme_error(const ATResponse *p_response)
1280{
1281 int ret;
1282 int err;
1283 char *p_cur;
1284
1285 if (p_response->success > 0)
1286 {
1287 return CME_SUCCESS;
1288 }
1289
1290 if (p_response->finalResponse == NULL
1291 || !strStartsWith(p_response->finalResponse, "+CME ERROR:")
1292 )
1293 {
1294 return CME_ERROR_NON_CME;
1295 }
1296
1297 p_cur = p_response->finalResponse;
1298 err = at_tok_start(&p_cur);
1299
1300 if (err < 0)
1301 {
1302 return CME_ERROR_NON_CME;
1303 }
1304
1305 err = at_tok_nextint(&p_cur, &ret);
1306
1307 if (err < 0)
1308 {
1309 return CME_ERROR_NON_CME;
1310 }
1311
1312 return ret;
1313}
1314
1315mbtk_ril_at_state_enum at_state_get()
1316{
1317 return at_state;
1318}
1319
1320void at_state_set(mbtk_ril_at_state_enum state)
1321{
1322 at_state = state;
1323}
1324
1325bool at_rsp_check(ATResponse *p_response)
1326{
1327 if(!p_response || !p_response->success)
1328 return false;
1329
1330 return true;
1331}
1332
1333void unused_func()
1334{
1335 isFinalResponse(NULL);
1336}
1337