1 /* //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 #include <sys/timeb.h>
32 #include <stdarg.h>
33
34 #include "QMIThread.h"
35 #define LOGE dbg_time
36 #define LOGD dbg_time
37
38 #define NUM_ELEMS(x) (sizeof(x)/sizeof(x[0]))
39
40 #define MAX_AT_RESPONSE sizeof(cm_recv_buf)
41 #define HANDSHAKE_RETRY_COUNT 8
42 #define HANDSHAKE_TIMEOUT_MSEC 1000
43
44 static pthread_t s_tid_reader;
45 static int s_fd = -1; /* fd of the AT channel */
46 static ATUnsolHandler s_unsolHandler;
47
48 /* for input buffering */
49
50 static char *s_ATBuffer = (char *)cm_recv_buf;
51 static char *s_ATBufferCur = (char *)cm_recv_buf;
52
53 static int s_readCount = 0;
54
55 #if AT_DEBUG
AT_DUMP(const char * prefix,const char * buff,int len)56 void AT_DUMP(const char* prefix, const char* buff, int len)
57 {
58 if (len < 0)
59 len = strlen(buff);
60 LOGD("%.*s", len, buff);
61 }
62 #endif
63
64 /*
65 * for current pending command
66 * these are protected by s_commandmutex
67 */
68 static ATCommandType s_type;
69 static const char *s_responsePrefix = NULL;
70 static const char *s_smsPDU = NULL;
71 static const char *s_raw_data = NULL;
72 static size_t s_raw_len;
73 static ATResponse *sp_response = NULL;
74
75 static void (*s_onTimeout)(void) = NULL;
76 static void (*s_onReaderClosed)(void) = NULL;
77 static int s_readerClosed;
78
79 static void onReaderClosed();
80 static int writeCtrlZ (const char *s);
81 static int writeline (const char *s);
82 static int writeraw (const char *s, size_t len);
83
sleepMsec(long long msec)84 static void sleepMsec(long long msec)
85 {
86 struct timespec ts;
87 int err;
88
89 ts.tv_sec = (msec / 1000);
90 ts.tv_nsec = (msec % 1000) * 1000 * 1000;
91
92 do {
93 err = nanosleep (&ts, &ts);
94 } while (err < 0 && errno == EINTR);
95 }
96
97 /** returns 1 if line starts with prefix, 0 if it does not */
strStartsWith(const char * line,const char * prefix)98 int strStartsWith(const char *line, const char *prefix)
99 {
100 for ( ; *line != '\0' && *prefix != '\0' ; line++, prefix++) {
101 if (*line != *prefix) {
102 return 0;
103 }
104 }
105
106 return *prefix == '\0';
107 }
108
109 /** add an intermediate response to sp_response*/
addIntermediate(const char * line)110 static void addIntermediate(const char *line)
111 {
112 ATLine *p_new;
113
114 p_new = (ATLine *) malloc(sizeof(ATLine));
115
116 p_new->line = strdup(line);
117
118 /* note: this adds to the head of the list, so the list
119 will be in reverse order of lines received. the order is flipped
120 again before passing on to the command issuer */
121 p_new->p_next = sp_response->p_intermediates;
122 sp_response->p_intermediates = p_new;
123 }
124
125
126 /**
127 * returns 1 if line is a final response indicating error
128 * See 27.007 annex B
129 * WARNING: NO CARRIER and others are sometimes unsolicited
130 */
131 static const char * s_finalResponsesError[] = {
132 "ERROR",
133 "+CMS ERROR:",
134 "+CME ERROR:",
135 "NO CARRIER", /* sometimes! */
136 "NO ANSWER",
137 "NO DIALTONE",
138 };
isFinalResponseError(const char * line)139 static int isFinalResponseError(const char *line)
140 {
141 size_t i;
142
143 for (i = 0 ; i < NUM_ELEMS(s_finalResponsesError) ; i++) {
144 if (strStartsWith(line, s_finalResponsesError[i])) {
145 return 1;
146 }
147 }
148
149 return 0;
150 }
151
152 /**
153 * returns 1 if line is a final response indicating success
154 * See 27.007 annex B
155 * WARNING: NO CARRIER and others are sometimes unsolicited
156 */
157 static const char * s_finalResponsesSuccess[] = {
158 "OK",
159 "+QIND: \"FOTA\",\"END\",0",
160 "CONNECT" /* some stacks start up data on another channel */
161 };
162
isFinalResponseSuccess(const char * line)163 static int isFinalResponseSuccess(const char *line)
164 {
165 size_t i;
166
167 for (i = 0 ; i < NUM_ELEMS(s_finalResponsesSuccess) ; i++) {
168 if (strStartsWith(line, s_finalResponsesSuccess[i])) {
169 return 1;
170 }
171 }
172
173 return 0;
174 }
175
176 #if 0
177 /**
178 * returns 1 if line is a final response, either error or success
179 * See 27.007 annex B
180 * WARNING: NO CARRIER and others are sometimes unsolicited
181 */
182 static int isFinalResponse(const char *line)
183 {
184 return isFinalResponseSuccess(line) || isFinalResponseError(line);
185 }
186 #endif
187
188 /**
189 * returns 1 if line is the first line in (what will be) a two-line
190 * SMS unsolicited response
191 */
192 static const char * s_smsUnsoliciteds[] = {
193 "+CMT:",
194 "+CDS:",
195 "+CBM:",
196 "+CMTI:"
197 };
isSMSUnsolicited(const char * line)198 static int isSMSUnsolicited(const char *line)
199 {
200 size_t i;
201
202 for (i = 0 ; i < NUM_ELEMS(s_smsUnsoliciteds) ; i++) {
203 if (strStartsWith(line, s_smsUnsoliciteds[i])) {
204 return 1;
205 }
206 }
207
208 return 0;
209 }
210
211
212 /** assumes s_commandmutex is held */
handleFinalResponse(const char * line)213 static void handleFinalResponse(const char *line)
214 {
215 sp_response->finalResponse = strdup(line);
216
217 pthread_cond_signal(&cm_command_cond);
218 }
219
handleUnsolicited(const char * line)220 static void handleUnsolicited(const char *line)
221 {
222 if (s_unsolHandler != NULL) {
223 s_unsolHandler(line, NULL);
224 }
225 }
226
processLine(const char * line)227 static void processLine(const char *line)
228 {
229 pthread_mutex_lock(&cm_command_mutex);
230
231 if (sp_response == NULL) {
232 /* no command pending */
233 handleUnsolicited(line);
234 } else if (s_raw_data != NULL && 0 == strcmp(line, "CONNECT")) {
235 usleep(500*1000); //for EC20
236 writeraw(s_raw_data, s_raw_len);
237 s_raw_data = NULL;
238 } else if (isFinalResponseSuccess(line)) {
239 sp_response->success = 1;
240 handleFinalResponse(line);
241 } else if (isFinalResponseError(line)) {
242 sp_response->success = 0;
243 handleFinalResponse(line);
244 } else if (s_smsPDU != NULL && 0 == strcmp(line, "> ")) {
245 // See eg. TS 27.005 4.3
246 // Commands like AT+CMGS have a "> " prompt
247 writeCtrlZ(s_smsPDU);
248 s_smsPDU = NULL;
249 } else switch (s_type) {
250 case NO_RESULT:
251 handleUnsolicited(line);
252 break;
253 case NUMERIC:
254 if (sp_response->p_intermediates == NULL
255 && isdigit(line[0])
256 ) {
257 addIntermediate(line);
258 } else {
259 /* either we already have an intermediate response or
260 the line doesn't begin with a digit */
261 handleUnsolicited(line);
262 }
263 break;
264 case SINGLELINE:
265 if (sp_response->p_intermediates == NULL
266 && strStartsWith (line, s_responsePrefix)
267 ) {
268 addIntermediate(line);
269 } else {
270 /* we already have an intermediate response */
271 handleUnsolicited(line);
272 }
273 break;
274 case MULTILINE:
275 if (strStartsWith (line, s_responsePrefix)) {
276 addIntermediate(line);
277 } else {
278 handleUnsolicited(line);
279 }
280 break;
281
282 default: /* this should never be reached */
283 LOGE("Unsupported AT command type %d\n", s_type);
284 handleUnsolicited(line);
285 break;
286 }
287
288 pthread_mutex_unlock(&cm_command_mutex);
289 }
290
291
292 /**
293 * Returns a pointer to the end of the next line
294 * special-cases the "> " SMS prompt
295 *
296 * returns NULL if there is no complete line
297 */
findNextEOL(char * cur)298 static char * findNextEOL(char *cur)
299 {
300 if (cur[0] == '>' && cur[1] == ' ' && cur[2] == '\0') {
301 /* SMS prompt character...not \r terminated */
302 return cur+2;
303 }
304
305 // Find next newline
306 while (*cur != '\0' && *cur != '\r' && *cur != '\n') cur++;
307
308 return *cur == '\0' ? NULL : cur;
309 }
310
311
312 /**
313 * Reads a line from the AT channel, returns NULL on timeout.
314 * Assumes it has exclusive read access to the FD
315 *
316 * This line is valid only until the next call to readline
317 *
318 * This function exists because as of writing, android libc does not
319 * have buffered stdio.
320 */
321
readline()322 static const char *readline()
323 {
324 ssize_t count;
325
326 char *p_read = NULL;
327 char *p_eol = NULL;
328 char *ret;
329
330 /* this is a little odd. I use *s_ATBufferCur == 0 to
331 * mean "buffer consumed completely". If it points to a character, than
332 * the buffer continues until a \0
333 */
334 if (*s_ATBufferCur == '\0') {
335 /* empty buffer */
336 s_ATBufferCur = s_ATBuffer;
337 *s_ATBufferCur = '\0';
338 p_read = s_ATBuffer;
339 } else { /* *s_ATBufferCur != '\0' */
340 /* there's data in the buffer from the last read */
341
342 // skip over leading newlines
343 while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
344 s_ATBufferCur++;
345
346 p_eol = findNextEOL(s_ATBufferCur);
347
348 if (p_eol == NULL) {
349 /* a partial line. move it up and prepare to read more */
350 size_t len;
351
352 len = strlen(s_ATBufferCur);
353
354 memmove(s_ATBuffer, s_ATBufferCur, len + 1);
355 p_read = s_ATBuffer + len;
356 s_ATBufferCur = s_ATBuffer;
357 }
358 /* Otherwise, (p_eol !- NULL) there is a complete line */
359 /* that will be returned the while () loop below */
360 }
361
362 while (p_eol == NULL) {
363 if (0 == MAX_AT_RESPONSE - (p_read - s_ATBuffer)) {
364 LOGE("ERROR: Input line exceeded buffer\n");
365 /* ditch buffer and start over again */
366 s_ATBufferCur = s_ATBuffer;
367 *s_ATBufferCur = '\0';
368 p_read = s_ATBuffer;
369 }
370
371 do {
372 while (s_fd > 0) {
373 struct pollfd pollfds[1] = {{s_fd, POLLIN, 0}};
374 int ret;
375
376 do {
377 ret = poll(pollfds, 1, -1);
378 } while ((ret < 0) && (errno == EINTR));
379
380 if (pollfds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
381 break;
382 } else if (pollfds[0].revents & (POLLIN)) {
383 break;
384 }
385 };
386
387 count = (s_fd == -1) ? 0 : read(s_fd, p_read,
388 MAX_AT_RESPONSE - (p_read - s_ATBuffer));
389 } while (count < 0 && errno == EINTR);
390
391 if (count > 0) {
392 AT_DUMP( "<< ", p_read, count );
393 s_readCount += count;
394
395 p_read[count] = '\0';
396
397 // skip over leading newlines
398 while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
399 s_ATBufferCur++;
400
401 p_eol = findNextEOL(s_ATBufferCur);
402 p_read += count;
403 } else if (count <= 0) {
404 /* read error encountered or EOF reached */
405 if(count == 0) {
406 LOGD("atchannel: EOF reached");
407 } else {
408 LOGD("atchannel: read error %s", strerror(errno));
409 }
410 return NULL;
411 }
412 }
413
414 /* a full line in the buffer. Place a \0 over the \r and return */
415
416 ret = s_ATBufferCur;
417 *p_eol = '\0';
418 s_ATBufferCur = p_eol + 1; /* this will always be <= p_read, */
419 /* and there will be a \0 at *p_read */
420
421 LOGD("AT< %s", ret);
422 return ret;
423 }
424
425
onReaderClosed()426 static void onReaderClosed()
427 {
428 LOGE("%s\n", __func__);
429 if (s_onReaderClosed != NULL && s_readerClosed == 0) {
430
431 pthread_mutex_lock(&cm_command_mutex);
432
433 s_readerClosed = 1;
434
435 pthread_cond_signal(&cm_command_cond);
436
437 pthread_mutex_unlock(&cm_command_mutex);
438
439 s_onReaderClosed();
440 }
441 }
442
443
readerLoop(void * arg)444 static void *readerLoop(void *arg)
445 {
446 (void)arg;
447
448 for (;;) {
449 const char * line;
450
451 line = readline();
452
453 if (line == NULL) {
454 break;
455 }
456
457 if(isSMSUnsolicited(line)) {
458 char *line1;
459 const char *line2;
460
461 // The scope of string returned by 'readline()' is valid only
462 // till next call to 'readline()' hence making a copy of line
463 // before calling readline again.
464 line1 = strdup(line);
465 line2 = readline();
466
467 if (line2 == NULL) {
468 break;
469 }
470
471 if (s_unsolHandler != NULL) {
472 s_unsolHandler (line1, line2);
473 }
474 free(line1);
475 } else {
476 processLine(line);
477 }
478 }
479
480 onReaderClosed();
481
482 return NULL;
483 }
484
485 /**
486 * Sends string s to the radio with a \r appended.
487 * Returns AT_ERROR_* on error, 0 on success
488 *
489 * This function exists because as of writing, android libc does not
490 * have buffered stdio.
491 */
writeline(const char * s)492 static int writeline (const char *s)
493 {
494 size_t cur = 0;
495 size_t len = strlen(s);
496 ssize_t written;
497 static char at_command[64];
498
499 if (s_fd < 0 || s_readerClosed > 0) {
500 return AT_ERROR_CHANNEL_CLOSED;
501 }
502
503 LOGD("AT> %s", s);
504
505 AT_DUMP( ">> ", s, strlen(s) );
506
507 #if 1 //send '\r' maybe fail via USB controller: Intel Corporation 7 Series/C210 Series Chipset Family USB xHCI Host Controller (rev 04)
508 if (len < (sizeof(at_command) - 1)) {
509 strcpy(at_command, s);
510 at_command[len++] = '\r';
511 s = (const char *)at_command;
512 }
513 #endif
514
515 /* the main string */
516 while (cur < len) {
517 do {
518 written = write (s_fd, s + cur, len - cur);
519 } while (written < 0 && errno == EINTR);
520
521 if (written < 0) {
522 return AT_ERROR_GENERIC;
523 }
524
525 cur += written;
526 }
527
528 #if 1 //Quectel send '\r' maybe fail via USB controller: Intel Corporation 7 Series/C210 Series Chipset Family USB xHCI Host Controller (rev 04)
529 if (s == (const char *)at_command) {
530 return 0;
531 }
532 #endif
533
534 /* the \r */
535
536 do {
537 written = write (s_fd, "\r" , 1);
538 } while ((written < 0 && errno == EINTR) || (written == 0));
539
540 if (written < 0) {
541 return AT_ERROR_GENERIC;
542 }
543
544 return 0;
545 }
writeCtrlZ(const char * s)546 static int writeCtrlZ (const char *s)
547 {
548 size_t cur = 0;
549 size_t len = strlen(s);
550 ssize_t written;
551
552 if (s_fd < 0 || s_readerClosed > 0) {
553 return AT_ERROR_CHANNEL_CLOSED;
554 }
555
556 LOGD("AT> %s^Z", s);
557
558 AT_DUMP( ">* ", s, strlen(s) );
559
560 /* the main string */
561 while (cur < len) {
562 do {
563 written = write (s_fd, s + cur, len - cur);
564 } while (written < 0 && errno == EINTR);
565
566 if (written < 0) {
567 return AT_ERROR_GENERIC;
568 }
569
570 cur += written;
571 }
572
573 /* the ^Z */
574
575 do {
576 written = write (s_fd, "\032" , 1);
577 } while ((written < 0 && errno == EINTR) || (written == 0));
578
579 if (written < 0) {
580 return AT_ERROR_GENERIC;
581 }
582
583 return 0;
584 }
585
writeraw(const char * s,size_t len)586 static int writeraw (const char *s, size_t len) {
587 size_t cur = 0;
588 ssize_t written;
589
590 if (s_fd < 0 || s_readerClosed > 0) {
591 return AT_ERROR_CHANNEL_CLOSED;
592 }
593
594 /* the main string */
595 while (cur < len) {
596 struct pollfd pollfds[1] = {{s_fd, POLLOUT, 0}};
597 int ret;
598
599 ret = poll(pollfds, 1, -1);
600 if (ret <= 0)
601 break;
602
603 do {
604 written = write (s_fd, s + cur, len - cur);
605 } while (written < 0 && errno == EINTR);
606
607 if (written < 0) {
608 return AT_ERROR_GENERIC;
609 }
610
611 cur += written;
612 }
613
614 if (written < 0) {
615 return AT_ERROR_GENERIC;
616 }
617
618 return cur;
619 }
620
clearPendingCommand()621 static void clearPendingCommand()
622 {
623 if (sp_response != NULL) {
624 at_response_free(sp_response);
625 }
626
627 sp_response = NULL;
628 s_responsePrefix = NULL;
629 s_smsPDU = NULL;
630 }
631
632
633 /**
634 * Starts AT handler on stream "fd'
635 * returns 0 on success, -1 on error
636 */
at_open(int fd,ATUnsolHandler h)637 int at_open(int fd, ATUnsolHandler h)
638 {
639 int ret;
640 pthread_attr_t attr;
641
642 s_fd = fd;
643 s_unsolHandler = h;
644 s_readerClosed = 0;
645
646 s_responsePrefix = NULL;
647 s_smsPDU = NULL;
648 sp_response = NULL;
649
650 pthread_attr_init (&attr);
651 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
652
653 ret = pthread_create(&s_tid_reader, &attr, readerLoop, NULL);
654
655 if (ret < 0) {
656 LOGE("readerLoop create fail!");
657 perror ("pthread_create\n");
658 return -1;
659 }
660
661 return 0;
662 }
663
664 /* FIXME is it ok to call this from the reader and the command thread? */
at_close()665 void at_close()
666 {
667 dbg_time("at_close\n");
668 if (s_fd >= 0) {
669 close(s_fd);
670 }
671 s_fd = -1;
672
673 pthread_mutex_lock(&cm_command_mutex);
674
675 s_readerClosed = 1;
676
677 pthread_cond_signal(&cm_command_cond);
678
679 pthread_mutex_unlock(&cm_command_mutex);
680
681 /* the reader thread should eventually die */
682 }
683
at_response_new()684 static ATResponse * at_response_new()
685 {
686 return (ATResponse *) calloc(1, sizeof(ATResponse));
687 }
688
at_response_free(ATResponse * p_response)689 void at_response_free(ATResponse *p_response)
690 {
691 ATLine *p_line;
692
693 if (p_response == NULL) return;
694
695 p_line = p_response->p_intermediates;
696
697 while (p_line != NULL) {
698 ATLine *p_toFree;
699
700 p_toFree = p_line;
701 p_line = p_line->p_next;
702
703 free(p_toFree->line);
704 free(p_toFree);
705 }
706
707 free (p_response->finalResponse);
708 free (p_response);
709 }
710
711 /**
712 * The line reader places the intermediate responses in reverse order
713 * here we flip them back
714 */
reverseIntermediates(ATResponse * p_response)715 static void reverseIntermediates(ATResponse *p_response)
716 {
717 ATLine *pcur,*pnext;
718
719 pcur = p_response->p_intermediates;
720 p_response->p_intermediates = NULL;
721
722 while (pcur != NULL) {
723 pnext = pcur->p_next;
724 pcur->p_next = p_response->p_intermediates;
725 p_response->p_intermediates = pcur;
726 pcur = pnext;
727 }
728 }
729
730 /**
731 * Internal send_command implementation
732 * Doesn't lock or call the timeout callback
733 *
734 * timeoutMsec == 0 means infinite timeout
735 */
at_send_command_full_nolock(const char * command,ATCommandType type,const char * responsePrefix,const char * smspdu,long long timeoutMsec,ATResponse ** pp_outResponse)736 static int at_send_command_full_nolock (const char *command, ATCommandType type,
737 const char *responsePrefix, const char *smspdu,
738 long long timeoutMsec, ATResponse **pp_outResponse)
739 {
740 int err = 0;
741
742 if (!timeoutMsec)
743 timeoutMsec = 15000;
744
745 if(sp_response != NULL) {
746 err = AT_ERROR_COMMAND_PENDING;
747 goto error;
748 }
749
750 if (command != NULL)
751 err = writeline (command);
752
753 if (err < 0) {
754 printf("%s errno: %d (%s)\n", __func__, errno, strerror(errno));
755 goto error;
756 }
757
758 s_type = type;
759 s_responsePrefix = responsePrefix;
760 s_smsPDU = smspdu;
761 sp_response = at_response_new();
762
763 while (sp_response->finalResponse == NULL && s_readerClosed == 0) {
764 err = pthread_cond_timeout_np(&cm_command_cond, &cm_command_mutex, timeoutMsec);
765
766 if (err == ETIMEDOUT) {
767 err = AT_ERROR_TIMEOUT;
768 goto error;
769 }
770 }
771
772 if (pp_outResponse == NULL) {
773 at_response_free(sp_response);
774 } else {
775 /* line reader stores intermediate responses in reverse order */
776 reverseIntermediates(sp_response);
777 *pp_outResponse = sp_response;
778 }
779
780 sp_response = NULL;
781
782 if(s_readerClosed > 0) {
783 err = AT_ERROR_CHANNEL_CLOSED;
784 goto error;
785 }
786
787 err = 0;
788 error:
789 clearPendingCommand();
790
791 return err;
792 }
793
794 /**
795 * Internal send_command implementation
796 *
797 * timeoutMsec == 0 means infinite timeout
798 */
at_send_command_full(const char * command,ATCommandType type,const char * responsePrefix,const char * smspdu,long long timeoutMsec,ATResponse ** pp_outResponse)799 static int at_send_command_full (const char *command, ATCommandType type,
800 const char *responsePrefix, const char *smspdu,
801 long long timeoutMsec, ATResponse **pp_outResponse)
802 {
803 int err;
804
805 if (0 != pthread_equal(s_tid_reader, pthread_self())) {
806 /* cannot be called from reader thread */
807 return AT_ERROR_INVALID_THREAD;
808 }
809
810 pthread_mutex_lock(&cm_command_mutex);
811
812 err = at_send_command_full_nolock(command, type,
813 responsePrefix, smspdu,
814 timeoutMsec, pp_outResponse);
815
816 pthread_mutex_unlock(&cm_command_mutex);
817
818 if (err == AT_ERROR_TIMEOUT && s_onTimeout != NULL) {
819 s_onTimeout();
820 }
821
822 return err;
823 }
824
825
826 /**
827 * Issue a single normal AT command with no intermediate response expected
828 *
829 * "command" should not include \r
830 * pp_outResponse can be NULL
831 *
832 * if non-NULL, the resulting ATResponse * must be eventually freed with
833 * at_response_free
834 */
at_send_command(const char * command,ATResponse ** pp_outResponse)835 int at_send_command (const char *command, ATResponse **pp_outResponse)
836 {
837 int err;
838
839 err = at_send_command_full (command, NO_RESULT, NULL,
840 NULL, 0, pp_outResponse);
841
842 return err;
843 }
844
845
at_send_command_singleline(const char * command,const char * responsePrefix,ATResponse ** pp_outResponse)846 int at_send_command_singleline (const char *command,
847 const char *responsePrefix,
848 ATResponse **pp_outResponse)
849 {
850 int err;
851
852 err = at_send_command_full (command, SINGLELINE, responsePrefix,
853 NULL, 0, pp_outResponse);
854
855 if (err == 0 && pp_outResponse != NULL
856 && (*pp_outResponse)->success > 0
857 && (*pp_outResponse)->p_intermediates == NULL
858 ) {
859 /* successful command must have an intermediate response */
860 at_response_free(*pp_outResponse);
861 *pp_outResponse = NULL;
862 return AT_ERROR_INVALID_RESPONSE;
863 }
864
865 return err;
866 }
867
868
at_send_command_numeric(const char * command,ATResponse ** pp_outResponse)869 int at_send_command_numeric (const char *command,
870 ATResponse **pp_outResponse)
871 {
872 int err;
873
874 err = at_send_command_full (command, NUMERIC, NULL,
875 NULL, 0, pp_outResponse);
876
877 if (err == 0 && pp_outResponse != NULL
878 && (*pp_outResponse)->success > 0
879 && (*pp_outResponse)->p_intermediates == NULL
880 ) {
881 /* successful command must have an intermediate response */
882 at_response_free(*pp_outResponse);
883 *pp_outResponse = NULL;
884 return AT_ERROR_INVALID_RESPONSE;
885 }
886
887 return err;
888 }
889
890
at_send_command_sms(const char * command,const char * pdu,const char * responsePrefix,ATResponse ** pp_outResponse)891 int at_send_command_sms (const char *command,
892 const char *pdu,
893 const char *responsePrefix,
894 ATResponse **pp_outResponse)
895 {
896 int err;
897
898 err = at_send_command_full (command, SINGLELINE, responsePrefix,
899 pdu, 0, pp_outResponse);
900
901 if (err == 0 && pp_outResponse != NULL
902 && (*pp_outResponse)->success > 0
903 && (*pp_outResponse)->p_intermediates == NULL
904 ) {
905 /* successful command must have an intermediate response */
906 at_response_free(*pp_outResponse);
907 *pp_outResponse = NULL;
908 return AT_ERROR_INVALID_RESPONSE;
909 }
910
911 return err;
912 }
913
at_send_command_multiline(const char * command,const char * responsePrefix,ATResponse ** pp_outResponse)914 int at_send_command_multiline (const char *command,
915 const char *responsePrefix,
916 ATResponse **pp_outResponse)
917 {
918 int err;
919
920 err = at_send_command_full (command, MULTILINE, responsePrefix,
921 NULL, 0, pp_outResponse);
922
923 return err;
924 }
925
at_send_command_raw(const char * command,const char * raw_data,unsigned int raw_len,const char * responsePrefix,ATResponse ** pp_outResponse)926 int at_send_command_raw (const char *command,
927 const char *raw_data, unsigned int raw_len,
928 const char *responsePrefix,
929 ATResponse **pp_outResponse)
930 {
931 int err;
932
933 s_raw_data = raw_data;
934 s_raw_len = raw_len;
935 err = at_send_command_full (command, SINGLELINE, responsePrefix,
936 NULL, 0, pp_outResponse);
937
938 return err;
939 }
940
941 /**
942 * Periodically issue an AT command and wait for a response.
943 * Used to ensure channel has start up and is active
944 */
945
at_handshake()946 int at_handshake()
947 {
948 int i;
949 int err = 0;
950
951 if (0 != pthread_equal(s_tid_reader, pthread_self())) {
952 /* cannot be called from reader thread */
953 return AT_ERROR_INVALID_THREAD;
954 }
955
956 pthread_mutex_lock(&cm_command_mutex);
957
958 for (i = 0 ; i < HANDSHAKE_RETRY_COUNT ; i++) {
959 /* some stacks start with verbose off */
960 err = at_send_command_full_nolock ("ATE0Q0V1", NO_RESULT,
961 NULL, NULL, HANDSHAKE_TIMEOUT_MSEC, NULL);
962
963 if (err == 0) {
964 break;
965 }
966 }
967
968 pthread_mutex_unlock(&cm_command_mutex);
969
970 if (err == 0) {
971 /* pause for a bit to let the input buffer drain any unmatched OK's
972 (they will appear as extraneous unsolicited responses) */
973
974 sleepMsec(HANDSHAKE_TIMEOUT_MSEC);
975 }
976
977 return err;
978 }
979
at_get_cme_error(const ATResponse * p_response)980 AT_CME_Error at_get_cme_error(const ATResponse *p_response)
981 {
982 int ret;
983 int err;
984 char *p_cur;
985
986 if (p_response == NULL)
987 return CME_ERROR_NON_CME;
988
989 if (p_response->success > 0) {
990 return CME_SUCCESS;
991 }
992
993 if (p_response->finalResponse == NULL
994 || !strStartsWith(p_response->finalResponse, "+CME ERROR:")
995 ) {
996 return CME_ERROR_NON_CME;
997 }
998
999 p_cur = p_response->finalResponse;
1000 err = at_tok_start(&p_cur);
1001
1002 if (err < 0) {
1003 return CME_ERROR_NON_CME;
1004 }
1005
1006 err = at_tok_nextint(&p_cur, &ret);
1007
1008 if (err < 0) {
1009 return CME_ERROR_NON_CME;
1010 }
1011
1012 return (AT_CME_Error) ret;
1013 }
1014
1015 /** This callback is invoked on the command thread */
at_set_on_timeout(void (* onTimeout)(void))1016 void at_set_on_timeout(void (*onTimeout)(void))
1017 {
1018 s_onTimeout = onTimeout;
1019 }
1020
1021 /**
1022 * This callback is invoked on the reader thread (like ATUnsolHandler)
1023 * when the input stream closes before you call at_close
1024 * (not when you call at_close())
1025 * You should still call at_close()
1026 */
at_set_on_reader_closed(void (* onClose)(void))1027 void at_set_on_reader_closed(void (*onClose)(void))
1028 {
1029 s_onReaderClosed = onClose;
1030 }
1031