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