atchannel.c
上传用户:rftzhifu
上传日期:2017-02-21
资源大小:229k
文件大小:24k
源码类别:

android开发

开发平台:

Unix_Linux

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