1 /* //device/system/reference-ril/atchannel.c
3 ** Copyright 2006, The Android Open Source Project
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
9 ** http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "atchannel.h"
34 #include <utils/Log.h>
38 #ifdef HAVE_ANDROID_OS
40 #endif /* HAVE_ANDROID_OS */
43 #define NUM_ELEMS(x) (sizeof(x)/sizeof(x[0]))
45 #define MAX_AT_RESPONSE (8 * 1024)
46 #define HANDSHAKE_RETRY_COUNT 8
47 #define HANDSHAKE_TIMEOUT_MSEC 250
49 static pthread_t s_tid_reader;
50 static int s_fd = -1; /* fd of the AT channel */
51 static ATUnsolHandler s_unsolHandler;
53 /* for input buffering */
55 static char s_ATBuffer[MAX_AT_RESPONSE+1];
56 static char *s_ATBufferCur = s_ATBuffer;
59 void AT_DUMP(const char* prefix, const char* buff, int len)
63 RLOGD("%.*s", len, buff);
68 * for current pending command
69 * these are protected by s_commandmutex
72 static pthread_mutex_t s_commandmutex = PTHREAD_MUTEX_INITIALIZER;
73 static pthread_cond_t s_commandcond = PTHREAD_COND_INITIALIZER;
75 static ATCommandType s_type;
76 static const char *s_responsePrefix = NULL;
77 static const char *s_smsPDU = NULL;
78 static ATResponse *sp_response = NULL;
80 static void (*s_onTimeout)(void) = NULL;
81 static void (*s_onReaderClosed)(void) = NULL;
82 static int s_readerClosed;
84 static void onReaderClosed();
85 static int writeCtrlZ (const char *s);
86 static int writeline (const char *s);
89 static void setTimespecRelative(struct timespec *p_ts, long long msec)
93 gettimeofday(&tv, (struct timezone *) NULL);
95 /* what's really funny about this is that I know
96 pthread_cond_timedwait just turns around and makes this
97 a relative time again */
98 p_ts->tv_sec = tv.tv_sec + (msec / 1000);
99 p_ts->tv_nsec = (tv.tv_usec + (msec % 1000) * 1000L ) * 1000L;
103 static void sleepMsec(long long msec)
108 ts.tv_sec = (msec / 1000);
109 ts.tv_nsec = (msec % 1000) * 1000 * 1000;
112 err = nanosleep (&ts, &ts);
113 } while (err < 0 && errno == EINTR);
118 /** add an intermediate response to sp_response*/
119 static void addIntermediate(const char *line)
123 p_new = (ATLine *) malloc(sizeof(ATLine));
125 p_new->line = strdup(line);
127 /* note: this adds to the head of the list, so the list
128 will be in reverse order of lines received. the order is flipped
129 again before passing on to the command issuer */
130 p_new->p_next = sp_response->p_intermediates;
131 sp_response->p_intermediates = p_new;
136 * returns 1 if line is a final response indicating error
138 * WARNING: NO CARRIER and others are sometimes unsolicited
140 static const char * s_finalResponsesError[] = {
144 "NO CARRIER", /* sometimes! */
148 static int isFinalResponseError(const char *line)
152 for (i = 0 ; i < NUM_ELEMS(s_finalResponsesError) ; i++) {
153 if (strStartsWith(line, s_finalResponsesError[i])) {
162 * returns 1 if line is a final response indicating success
164 * WARNING: NO CARRIER and others are sometimes unsolicited
166 static const char * s_finalResponsesSuccess[] = {
168 "CONNECT" /* some stacks start up data on another channel */
170 static int isFinalResponseSuccess(const char *line)
174 for (i = 0 ; i < NUM_ELEMS(s_finalResponsesSuccess) ; i++) {
175 if (strStartsWith(line, s_finalResponsesSuccess[i])) {
184 * returns 1 if line is a final response, either error or success
186 * WARNING: NO CARRIER and others are sometimes unsolicited
188 static int isFinalResponse(const char *line)
190 return isFinalResponseSuccess(line) || isFinalResponseError(line);
195 * returns 1 if line is the first line in (what will be) a two-line
196 * SMS unsolicited response
198 static const char * s_smsUnsoliciteds[] = {
203 static int isSMSUnsolicited(const char *line)
207 for (i = 0 ; i < NUM_ELEMS(s_smsUnsoliciteds) ; i++) {
208 if (strStartsWith(line, s_smsUnsoliciteds[i])) {
217 /** assumes s_commandmutex is held */
218 static void handleFinalResponse(const char *line)
220 sp_response->finalResponse = strdup(line);
222 pthread_cond_signal(&s_commandcond);
225 static void handleUnsolicited(const char *line)
227 if (s_unsolHandler != NULL) {
228 s_unsolHandler(line, NULL);
232 static void processLine(const char *line)
234 pthread_mutex_lock(&s_commandmutex);
236 if (sp_response == NULL) {
237 /* no command pending */
238 handleUnsolicited(line);
239 } else if (isFinalResponseSuccess(line)) {
240 sp_response->success = 1;
241 handleFinalResponse(line);
242 } else if (isFinalResponseError(line)) {
243 sp_response->success = 0;
244 handleFinalResponse(line);
245 } else if (s_smsPDU != NULL && 0 == strcmp(line, "> ")) {
246 // See eg. TS 27.005 4.3
247 // Commands like AT+CMGS have a "> " prompt
248 writeCtrlZ(s_smsPDU);
250 } else switch (s_type) {
252 handleUnsolicited(line);
255 if (sp_response->p_intermediates == NULL
258 addIntermediate(line);
260 /* either we already have an intermediate response or
261 the line doesn't begin with a digit */
262 handleUnsolicited(line);
266 if (sp_response->p_intermediates == NULL
267 && strStartsWith (line, s_responsePrefix)
269 addIntermediate(line);
271 /* we already have an intermediate response */
272 handleUnsolicited(line);
276 if (strStartsWith (line, s_responsePrefix)) {
277 addIntermediate(line);
279 handleUnsolicited(line);
283 default: /* this should never be reached */
284 RLOGE("Unsupported AT command type %d\n", s_type);
285 handleUnsolicited(line);
289 pthread_mutex_unlock(&s_commandmutex);
294 * Returns a pointer to the end of the next line
295 * special-cases the "> " SMS prompt
297 * returns NULL if there is no complete line
299 static char * findNextEOL(char *cur)
301 if (cur[0] == '>' && cur[1] == ' ' && cur[2] == '\0') {
302 /* SMS prompt character...not \r terminated */
307 while (*cur != '\0' && *cur != '\r' && *cur != '\n') cur++;
309 return *cur == '\0' ? NULL : cur;
314 * Reads a line from the AT channel, returns NULL on timeout.
315 * Assumes it has exclusive read access to the FD
317 * This line is valid only until the next call to readline
319 * This function exists because as of writing, android libc does not
320 * have buffered stdio.
323 static const char *readline()
331 /* this is a little odd. I use *s_ATBufferCur == 0 to
332 * mean "buffer consumed completely". If it points to a character, than
333 * the buffer continues until a \0
335 if (*s_ATBufferCur == '\0') {
337 s_ATBufferCur = s_ATBuffer;
338 *s_ATBufferCur = '\0';
340 } else { /* *s_ATBufferCur != '\0' */
341 /* there's data in the buffer from the last read */
343 // skip over leading newlines
344 while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
347 p_eol = findNextEOL(s_ATBufferCur);
350 /* a partial line. move it up and prepare to read more */
353 len = strlen(s_ATBufferCur);
355 memmove(s_ATBuffer, s_ATBufferCur, len + 1);
356 p_read = s_ATBuffer + len;
357 s_ATBufferCur = s_ATBuffer;
359 /* Otherwise, (p_eol !- NULL) there is a complete line */
360 /* that will be returned the while () loop below */
363 while (p_eol == NULL) {
364 if (0 == MAX_AT_RESPONSE - (p_read - s_ATBuffer)) {
365 RLOGE("ERROR: Input line exceeded buffer\n");
366 /* ditch buffer and start over again */
367 s_ATBufferCur = s_ATBuffer;
368 *s_ATBufferCur = '\0';
373 count = read(s_fd, p_read,
374 MAX_AT_RESPONSE - (p_read - s_ATBuffer));
375 } while (count < 0 && errno == EINTR);
378 AT_DUMP( "<< ", p_read, count );
380 p_read[count] = '\0';
382 // skip over leading newlines
383 while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
386 p_eol = findNextEOL(s_ATBufferCur);
388 } else if (count <= 0) {
389 /* read error encountered or EOF reached */
391 RLOGD("atchannel: EOF reached");
393 RLOGD("atchannel: read error %s", strerror(errno));
399 /* a full line in the buffer. Place a \0 over the \r and return */
403 s_ATBufferCur = p_eol + 1; /* this will always be <= p_read, */
404 /* and there will be a \0 at *p_read */
406 RLOGD("AT< %s\n", ret);
411 static void onReaderClosed()
413 if (s_onReaderClosed != NULL && s_readerClosed == 0) {
415 pthread_mutex_lock(&s_commandmutex);
419 pthread_cond_signal(&s_commandcond);
421 pthread_mutex_unlock(&s_commandmutex);
428 static void *readerLoop(void *arg)
439 if(isSMSUnsolicited(line)) {
443 // The scope of string returned by 'readline()' is valid only
444 // till next call to 'readline()' hence making a copy of line
445 // before calling readline again.
446 line1 = strdup(line);
453 if (s_unsolHandler != NULL) {
454 s_unsolHandler (line1, line2);
468 * Sends string s to the radio with a \r appended.
469 * Returns AT_ERROR_* on error, 0 on success
471 * This function exists because as of writing, android libc does not
472 * have buffered stdio.
474 static int writeline (const char *s)
477 size_t len = strlen(s);
480 if (s_fd < 0 || s_readerClosed > 0) {
481 return AT_ERROR_CHANNEL_CLOSED;
484 RLOGD("AT> %s\n", s);
486 AT_DUMP( ">> ", s, strlen(s) );
488 /* the main string */
491 written = write (s_fd, s + cur, len - cur);
492 } while (written < 0 && errno == EINTR);
495 return AT_ERROR_GENERIC;
504 written = write (s_fd, "\r" , 1);
505 } while ((written < 0 && errno == EINTR) || (written == 0));
508 return AT_ERROR_GENERIC;
513 static int writeCtrlZ (const char *s)
516 size_t len = strlen(s);
519 if (s_fd < 0 || s_readerClosed > 0) {
520 return AT_ERROR_CHANNEL_CLOSED;
523 RLOGD("AT> %s^Z\n", s);
525 AT_DUMP( ">* ", s, strlen(s) );
527 /* the main string */
530 written = write (s_fd, s + cur, len - cur);
531 } while (written < 0 && errno == EINTR);
534 return AT_ERROR_GENERIC;
543 written = write (s_fd, "\032" , 1);
544 } while ((written < 0 && errno == EINTR) || (written == 0));
547 return AT_ERROR_GENERIC;
553 static void clearPendingCommand()
555 if (sp_response != NULL) {
556 at_response_free(sp_response);
560 s_responsePrefix = NULL;
566 * Starts AT handler on stream "fd'
567 * returns 0 on success, -1 on error
569 int at_open(int fd, ATUnsolHandler h)
579 s_responsePrefix = NULL;
583 pthread_attr_init (&attr);
584 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
586 ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
589 perror ("pthread_create");
597 /* FIXME is it ok to call this from the reader and the command thread? */
605 pthread_mutex_lock(&s_commandmutex);
609 pthread_cond_signal(&s_commandcond);
611 pthread_mutex_unlock(&s_commandmutex);
613 /* the reader thread should eventually die */
616 static ATResponse * at_response_new()
618 return (ATResponse *) calloc(1, sizeof(ATResponse));
621 void at_response_free(ATResponse *p_response)
625 if (p_response == NULL) return;
627 p_line = p_response->p_intermediates;
629 while (p_line != NULL) {
633 p_line = p_line->p_next;
635 free(p_toFree->line);
639 free (p_response->finalResponse);
644 * The line reader places the intermediate responses in reverse order
645 * here we flip them back
647 static void reverseIntermediates(ATResponse *p_response)
651 pcur = p_response->p_intermediates;
652 p_response->p_intermediates = NULL;
654 while (pcur != NULL) {
655 pnext = pcur->p_next;
656 pcur->p_next = p_response->p_intermediates;
657 p_response->p_intermediates = pcur;
663 * Internal send_command implementation
664 * Doesn't lock or call the timeout callback
666 * timeoutMsec == 0 means infinite timeout
669 static int at_send_command_full_nolock (const char *command, ATCommandType type,
670 const char *responsePrefix, const char *smspdu,
671 long long timeoutMsec, ATResponse **pp_outResponse)
678 if(sp_response != NULL) {
679 err = AT_ERROR_COMMAND_PENDING;
683 err = writeline (command);
690 s_responsePrefix = responsePrefix;
692 sp_response = at_response_new();
695 if (timeoutMsec != 0) {
696 setTimespecRelative(&ts, timeoutMsec);
700 while (sp_response->finalResponse == NULL && s_readerClosed == 0) {
701 if (timeoutMsec != 0) {
703 err = pthread_cond_timeout_np(&s_commandcond, &s_commandmutex, timeoutMsec);
705 err = pthread_cond_timedwait(&s_commandcond, &s_commandmutex, &ts);
708 err = pthread_cond_wait(&s_commandcond, &s_commandmutex);
711 if (err == ETIMEDOUT) {
712 err = AT_ERROR_TIMEOUT;
717 if (pp_outResponse == NULL) {
718 at_response_free(sp_response);
720 /* line reader stores intermediate responses in reverse order */
721 reverseIntermediates(sp_response);
722 *pp_outResponse = sp_response;
727 if(s_readerClosed > 0) {
728 err = AT_ERROR_CHANNEL_CLOSED;
734 clearPendingCommand();
740 * Internal send_command implementation
742 * timeoutMsec == 0 means infinite timeout
744 static int at_send_command_full (const char *command, ATCommandType type,
745 const char *responsePrefix, const char *smspdu,
746 long long timeoutMsec, ATResponse **pp_outResponse)
750 if (0 != pthread_equal(s_tid_reader, pthread_self())) {
751 /* cannot be called from reader thread */
752 return AT_ERROR_INVALID_THREAD;
755 pthread_mutex_lock(&s_commandmutex);
757 err = at_send_command_full_nolock(command, type,
758 responsePrefix, smspdu,
759 timeoutMsec, pp_outResponse);
761 pthread_mutex_unlock(&s_commandmutex);
763 if (err == AT_ERROR_TIMEOUT && s_onTimeout != NULL) {
772 * Issue a single normal AT command with no intermediate response expected
774 * "command" should not include \r
775 * pp_outResponse can be NULL
777 * if non-NULL, the resulting ATResponse * must be eventually freed with
780 int at_send_command (const char *command, ATResponse **pp_outResponse)
784 err = at_send_command_full (command, NO_RESULT, NULL,
785 NULL, 0, pp_outResponse);
791 int at_send_command_singleline (const char *command,
792 const char *responsePrefix,
793 ATResponse **pp_outResponse)
797 err = at_send_command_full (command, SINGLELINE, responsePrefix,
798 NULL, 0, pp_outResponse);
800 if (err == 0 && pp_outResponse != NULL
801 && (*pp_outResponse)->success > 0
802 && (*pp_outResponse)->p_intermediates == NULL
804 /* successful command must have an intermediate response */
805 at_response_free(*pp_outResponse);
806 *pp_outResponse = NULL;
807 return AT_ERROR_INVALID_RESPONSE;
814 int at_send_command_numeric (const char *command,
815 ATResponse **pp_outResponse)
819 err = at_send_command_full (command, NUMERIC, NULL,
820 NULL, 0, pp_outResponse);
822 if (err == 0 && pp_outResponse != NULL
823 && (*pp_outResponse)->success > 0
824 && (*pp_outResponse)->p_intermediates == NULL
826 /* successful command must have an intermediate response */
827 at_response_free(*pp_outResponse);
828 *pp_outResponse = NULL;
829 return AT_ERROR_INVALID_RESPONSE;
836 int at_send_command_sms (const char *command,
838 const char *responsePrefix,
839 ATResponse **pp_outResponse)
843 err = at_send_command_full (command, SINGLELINE, responsePrefix,
844 pdu, 0, pp_outResponse);
846 if (err == 0 && pp_outResponse != NULL
847 && (*pp_outResponse)->success > 0
848 && (*pp_outResponse)->p_intermediates == NULL
850 /* successful command must have an intermediate response */
851 at_response_free(*pp_outResponse);
852 *pp_outResponse = NULL;
853 return AT_ERROR_INVALID_RESPONSE;
860 int at_send_command_multiline (const char *command,
861 const char *responsePrefix,
862 ATResponse **pp_outResponse)
866 err = at_send_command_full (command, MULTILINE, responsePrefix,
867 NULL, 0, pp_outResponse);
873 /** This callback is invoked on the command thread */
874 void at_set_on_timeout(void (*onTimeout)(void))
876 s_onTimeout = onTimeout;
880 * This callback is invoked on the reader thread (like ATUnsolHandler)
881 * when the input stream closes before you call at_close
882 * (not when you call at_close())
883 * You should still call at_close()
886 void at_set_on_reader_closed(void (*onClose)(void))
888 s_onReaderClosed = onClose;
893 * Periodically issue an AT command and wait for a response.
894 * Used to ensure channel has start up and is active
902 if (0 != pthread_equal(s_tid_reader, pthread_self())) {
903 /* cannot be called from reader thread */
904 return AT_ERROR_INVALID_THREAD;
907 pthread_mutex_lock(&s_commandmutex);
909 for (i = 0 ; i < HANDSHAKE_RETRY_COUNT ; i++) {
910 /* some stacks start with verbose off */
911 err = at_send_command_full_nolock ("ATE0Q0V1", NO_RESULT,
912 NULL, NULL, HANDSHAKE_TIMEOUT_MSEC, NULL);
920 /* pause for a bit to let the input buffer drain any unmatched OK's
921 (they will appear as extraneous unsolicited responses) */
923 sleepMsec(HANDSHAKE_TIMEOUT_MSEC);
926 pthread_mutex_unlock(&s_commandmutex);
932 * Returns error code from response
933 * Assumes AT+CMEE=1 (numeric) mode
935 AT_CME_Error at_get_cme_error(const ATResponse *p_response)
941 if (p_response->success > 0) {
945 if (p_response->finalResponse == NULL
946 || !strStartsWith(p_response->finalResponse, "+CME ERROR:")
948 return CME_ERROR_NON_CME;
951 p_cur = p_response->finalResponse;
952 err = at_tok_start(&p_cur);
955 return CME_ERROR_NON_CME;
958 err = at_tok_nextint(&p_cur, &ret);
961 return CME_ERROR_NON_CME;
964 return (AT_CME_Error) ret;