Add toolchain and mbtk source

Change-Id: Ie12546301367ea59240bf23d5e184ad7e36e40b3
diff --git a/mbtk/mbtk_ril/src/atchannel.c b/mbtk/mbtk_ril/src/atchannel.c
new file mode 100755
index 0000000..a1a9f21
--- /dev/null
+++ b/mbtk/mbtk_ril/src/atchannel.c
@@ -0,0 +1,1349 @@
+/* //device/system/reference-ril/atchannel.c
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "atchannel.h"
+#include "at_tok.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "mbtk_log.h"
+#include "mbtk_type.h"
+#include "mbtk_utils.h"
+
+#define MAX_AT_RESPONSE (8 * 1024)
+#define HANDSHAKE_RETRY_COUNT 20
+#define HANDSHAKE_TIMEOUT_MSEC 500
+#define AT_BUFF_MAX 100
+
+static pthread_t s_tid_reader;
+static int s_at_fd = -1;    /* fd of the AT channel */
+static int s_uart_fd = -1;    /* fd of the UART channel */
+
+static ATUnsolHandler s_unsolHandler;
+
+/* for input buffering */
+
+static char s_ATBuffer[MAX_AT_RESPONSE+1];
+static char *s_ATBufferCur = s_ATBuffer;
+static char s_UartBuffer[MAX_AT_RESPONSE+1];
+static char *s_UartBufferCur = s_UartBuffer;
+
+static mbtk_ril_at_state_enum at_state = RIL_AT_STATE_CLOSED;
+
+#if AT_DEBUG
+void  AT_DUMP(const char*  prefix, const char*  buff, int  len)
+{
+    if (len < 0)
+        len = strlen(buff);
+    LOGD("%.*s", len, buff);
+}
+#endif
+
+/*
+ * There is one reader thread |s_tid_reader| and potentially multiple writer
+ * threads. |s_commandmutex| and |s_commandcond| are used to maintain the
+ * condition that the writer thread will not read from |sp_response| until the
+ * reader thread has signaled itself is finished, etc. |s_writeMutex| is used to
+ * prevent multiple writer threads from calling at_send_command_full_nolock
+ * function at the same time.
+ */
+
+// "Wait" when AT process...
+static pthread_mutex_t s_commandmutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t s_commandcond = PTHREAD_COND_INITIALIZER;
+
+static ATCommandType s_type;
+static const char *s_responsePrefix = NULL;
+static const char *s_smsPDU = NULL;
+static ATResponse *sp_response = NULL;
+static char s_curr_at[AT_BUFF_MAX];
+
+static void (*s_onTimeout)(void) = NULL;
+static void (*s_onReaderClosed)(void) = NULL;
+static int s_readerClosed;
+
+static void onReaderClosed();
+static int writeCtrlZ (const char *s);
+static int writeline (const char *s);
+
+typedef struct
+{
+    char *at_command;
+    long long timeout;  // ms
+    bool timeout_close; // Close AT or not while AT response timeout.
+} at_timeout_t;
+
+static at_timeout_t at_timeout_list[] =
+{
+    {"AT+CRSM", 10000, false},
+//    {"AT+COPS", 60000, false}
+};
+
+#define NS_PER_S 1000000000
+static void setTimespecRelative(struct timespec *p_ts, long long msec)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, (struct timezone *) NULL);
+
+    p_ts->tv_sec = tv.tv_sec + (msec / 1000);
+    p_ts->tv_nsec = (tv.tv_usec + (msec % 1000) * 1000L ) * 1000L;
+    /* assuming tv.tv_usec < 10^6 */
+    if (p_ts->tv_nsec >= NS_PER_S)
+    {
+        p_ts->tv_sec++;
+        p_ts->tv_nsec -= NS_PER_S;
+    }
+}
+
+static void sleepMsec(long long msec)
+{
+    struct timespec ts;
+    int err;
+
+    ts.tv_sec = (msec / 1000);
+    ts.tv_nsec = (msec % 1000) * 1000 * 1000;
+
+    do
+    {
+        err = nanosleep (&ts, &ts);
+    }
+    while (err < 0 && errno == EINTR);
+}
+
+
+
+/** add an intermediate response to sp_response*/
+static void addIntermediate(const char *line)
+{
+    ATLine *p_new;
+
+    p_new = (ATLine  *) malloc(sizeof(ATLine));
+
+    p_new->line = strdup(line);
+
+//    LOGD("line:%s", line);
+//    LOGD("line-1:%s", p_new->line);
+
+    /* note: this adds to the head of the list, so the list
+       will be in reverse order of lines received. the order is flipped
+       again before passing on to the command issuer */
+    p_new->p_next = sp_response->p_intermediates;
+    sp_response->p_intermediates = p_new;
+}
+
+
+/**
+ * returns 1 if line is a final response indicating error
+ * See 27.007 annex B
+ * WARNING: NO CARRIER and others are sometimes unsolicited
+ */
+static const char * s_finalResponsesError[] =
+{
+    "ERROR",
+    "+CMS ERROR:",
+    "+CME ERROR:",
+//    "NO CARRIER", /* sometimes! */ // Only for ATD ?
+    "NO ANSWER",
+    "NO DIALTONE",
+};
+static int isFinalResponseError(const char *line)
+{
+    size_t i;
+
+    for (i = 0 ; i < ARRAY_SIZE(s_finalResponsesError) ; i++)
+    {
+        if (strStartsWith(line, s_finalResponsesError[i]))
+        {
+            return 1;
+        }
+    }
+
+    if(!strncasecmp(s_curr_at, "ATD", 3) && strStartsWith(line, "NO CARRIER"))
+    {
+        return 1;
+    }
+
+    return 0;
+}
+
+/**
+ * returns 1 if line is a final response indicating success
+ * See 27.007 annex B
+ * WARNING: NO CARRIER and others are sometimes unsolicited
+ */
+static const char * s_finalResponsesSuccess[] =
+{
+    "OK",
+//    "CONNECT"       /* some stacks start up data on another channel */
+};
+static int isFinalResponseSuccess(const char *line)
+{
+    size_t i;
+
+    for (i = 0 ; i < ARRAY_SIZE(s_finalResponsesSuccess) ; i++)
+    {
+        if (strStartsWith(line, s_finalResponsesSuccess[i]))
+        {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * returns 1 if line is a final response, either  error or success
+ * See 27.007 annex B
+ * WARNING: NO CARRIER and others are sometimes unsolicited
+ */
+static int isFinalResponse(const char *line)
+{
+    return isFinalResponseSuccess(line) || isFinalResponseError(line);
+}
+
+/**
+ * returns 1 if line is the first line in (what will be) a two-line
+ * SMS unsolicited response
+ */
+static const char * s_smsUnsoliciteds[] =
+{
+    "+CMT:",
+    "+CDS:",
+    "+CBM:"
+};
+static int isSMSUnsolicited(const char *line)
+{
+    size_t i;
+
+    for (i = 0 ; i < ARRAY_SIZE(s_smsUnsoliciteds) ; i++)
+    {
+        if (strStartsWith(line, s_smsUnsoliciteds[i]))
+        {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+
+/** assumes s_commandmutex is held */
+static void handleFinalResponse(const char *line)
+{
+    sp_response->finalResponse = strdup(line);
+
+    //LOGD("AT complete (pthread_cond_signal): %s",line);
+    pthread_cond_signal(&s_commandcond);
+}
+
+static void handleUnsolicited(const char *line)
+{
+    if (s_unsolHandler != NULL)
+    {
+        s_unsolHandler(line, NULL);
+    }
+}
+
+static void processLine(const char *line)
+{
+    pthread_mutex_lock(&s_commandmutex);
+//    LOGD("LINE : %s", line);
+    if (sp_response == NULL)
+    {
+        /* no command pending */
+        handleUnsolicited(line);
+    }
+    else if (isFinalResponseSuccess(line))
+    {
+        sp_response->success = 1;
+        handleFinalResponse(line);
+    }
+    else if (isFinalResponseError(line))
+    {
+        sp_response->success = 0;
+        handleFinalResponse(line);
+    }
+    else if (s_smsPDU != NULL && 0 == strcmp(line, "> "))
+    {
+        // See eg. TS 27.005 4.3
+        // Commands like AT+CMGS have a "> " prompt
+        writeCtrlZ(s_smsPDU);
+        s_smsPDU = NULL;
+    }
+    else switch (s_type)
+        {
+            case NO_RESULT:
+                handleUnsolicited(line);
+                break;
+            case NUMERIC:
+                if (sp_response->p_intermediates == NULL
+                    && isdigit(line[0])
+                   )
+                {
+                    addIntermediate(line);
+                }
+                else
+                {
+                    /* either we already have an intermediate response or
+                       the line doesn't begin with a digit */
+                    handleUnsolicited(line);
+                }
+                break;
+            case SINGLELINE:
+                if (sp_response->p_intermediates == NULL
+                    && strStartsWith (line, s_responsePrefix)
+                   )
+                {
+                    if(*line == '"')
+                    {
+                        char *line_temp = strdup(line);
+                        line_temp++;
+                        if(strlen(line_temp) > 0)
+                        {
+                            char *ptr = line_temp + strlen(line_temp) - 1;
+                            while(ptr >= line_temp && *ptr == '"')
+                            {
+                                *ptr = '\0';
+                                ptr--;
+                            }
+                        }
+                        addIntermediate(line_temp);
+                        free(line_temp);
+                    }
+                    else
+                    {
+                        addIntermediate(line);
+                    }
+                }
+                else
+                {
+                    /* we already have an intermediate response */
+                    handleUnsolicited(line);
+                }
+                break;
+            case MULTILINE:
+                if (strStartsWith (line, s_responsePrefix))
+                {
+                    addIntermediate(line);
+                }
+                else
+                {
+                    handleUnsolicited(line);
+                }
+                break;
+
+            default: /* this should never be reached */
+                LOGE("Unsupported AT command type %d\n", s_type);
+                handleUnsolicited(line);
+                break;
+        }
+
+    pthread_mutex_unlock(&s_commandmutex);
+}
+
+
+/**
+ * Returns a pointer to the end of the next line
+ * special-cases the "> " SMS prompt
+ *
+ * returns NULL if there is no complete line
+ */
+static char * findNextEOL(char *cur)
+{
+    if (cur[0] == '>' && cur[1] == ' ' && cur[2] == '\0')
+    {
+        /* SMS prompt character...not \r terminated */
+        return cur+2;
+    }
+
+    // Find next newline
+    while (*cur != '\0' && *cur != '\r' && *cur != '\n') cur++;
+
+    return *cur == '\0' ? NULL : cur;
+}
+
+
+/**
+ * Reads a line from the AT channel, returns NULL on timeout.
+ * Assumes it has exclusive read access to the FD
+ *
+ * This line is valid only until the next call to readline
+ *
+ * This function exists because as of writing, android libc does not
+ * have buffered stdio.
+ */
+
+static const char *readline()
+{
+    ssize_t count;
+
+    char *p_read = NULL;
+    char *p_eol = NULL;
+    char *ret;
+
+    /* this is a little odd. I use *s_ATBufferCur == 0 to
+     * mean "buffer consumed completely". If it points to a character, than
+     * the buffer continues until a \0
+     */
+    if (*s_ATBufferCur == '\0')
+    {
+        /* empty buffer */
+        s_ATBufferCur = s_ATBuffer;
+        *s_ATBufferCur = '\0';
+        p_read = s_ATBuffer;
+    }
+    else       /* *s_ATBufferCur != '\0' */
+    {
+        /* there's data in the buffer from the last read */
+
+        // skip over leading newlines
+        while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
+            s_ATBufferCur++;
+
+        p_eol = findNextEOL(s_ATBufferCur);
+
+        if (p_eol == NULL)
+        {
+            /* a partial line. move it up and prepare to read more */
+            size_t len;
+
+            len = strlen(s_ATBufferCur);
+
+            memmove(s_ATBuffer, s_ATBufferCur, len + 1);
+            p_read = s_ATBuffer + len;
+            s_ATBufferCur = s_ATBuffer;
+        }
+        /* Otherwise, (p_eol !- NULL) there is a complete line  */
+        /* that will be returned the while () loop below        */
+    }
+
+    while (p_eol == NULL)
+    {
+        if (0 == MAX_AT_RESPONSE - (p_read - s_ATBuffer))
+        {
+            LOGE("ERROR: Input line exceeded buffer\n");
+            /* ditch buffer and start over again */
+            s_ATBufferCur = s_ATBuffer;
+            *s_ATBufferCur = '\0';
+            p_read = s_ATBuffer;
+        }
+
+        do
+        {
+            count = read(s_at_fd, p_read,
+                         MAX_AT_RESPONSE - (p_read - s_ATBuffer));
+            usleep(10000);
+        }
+        while (count < 0 && errno == EINTR);
+
+        if (count > 0)
+        {
+            AT_DUMP( "<< ", p_read, count );
+
+            p_read[count] = '\0';
+
+            // skip over leading newlines
+            while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
+                s_ATBufferCur++;
+
+            p_eol = findNextEOL(s_ATBufferCur);
+            p_read += count;
+        }
+        else if (count <= 0)
+        {
+            /* read error encountered or EOF reached */
+            if(count == 0)
+            {
+                LOGD("atchannel: EOF reached");
+            }
+            else
+            {
+                LOGD("atchannel: read error %s", strerror(errno));
+            }
+            return NULL;
+        }
+    }
+
+    /* a full line in the buffer. Place a \0 over the \r and return */
+
+    ret = s_ATBufferCur;
+    *p_eol = '\0';
+    s_ATBufferCur = p_eol + 1; /* this will always be <= p_read,    */
+    /* and there will be a \0 at *p_read */
+
+    LOGD("AT< %s", ret);
+    return ret;
+}
+
+static const char *readlineUrc()
+{
+    ssize_t count;
+
+    char *p_read = NULL;
+    char *p_eol = NULL;
+    char *ret;
+
+    /* this is a little odd. I use *s_ATBufferCur == 0 to
+     * mean "buffer consumed completely". If it points to a character, than
+     * the buffer continues until a \0
+     */
+    if (*s_UartBufferCur == '\0')
+    {
+        /* empty buffer */
+        s_UartBufferCur = s_UartBuffer;
+        *s_UartBufferCur = '\0';
+        p_read = s_UartBuffer;
+    }
+    else       /* *s_ATBufferCur != '\0' */
+    {
+        /* there's data in the buffer from the last read */
+
+        // skip over leading newlines
+        while (*s_UartBufferCur == '\r' || *s_UartBufferCur == '\n')
+            s_UartBufferCur++;
+
+        p_eol = findNextEOL(s_UartBufferCur);
+
+        if (p_eol == NULL)
+        {
+            /* a partial line. move it up and prepare to read more */
+            size_t len;
+
+            len = strlen(s_UartBufferCur);
+
+            memmove(s_UartBuffer, s_UartBufferCur, len + 1);
+            p_read = s_UartBuffer + len;
+            s_UartBufferCur = s_UartBuffer;
+        }
+        /* Otherwise, (p_eol !- NULL) there is a complete line  */
+        /* that will be returned the while () loop below        */
+    }
+
+    while (p_eol == NULL)
+    {
+        if (0 == MAX_AT_RESPONSE - (p_read - s_UartBuffer))
+        {
+            LOGE("ERROR: Input line exceeded buffer\n");
+            /* ditch buffer and start over again */
+            s_UartBufferCur = s_UartBuffer;
+            *s_UartBufferCur = '\0';
+            p_read = s_UartBuffer;
+        }
+
+        do
+        {
+            count = read(s_uart_fd, p_read,
+                         MAX_AT_RESPONSE - (p_read - s_UartBuffer));
+            usleep(10000);
+        }
+        while (count < 0 && errno == EINTR);
+
+        if (count > 0)
+        {
+            AT_DUMP( "<< ", p_read, count );
+
+            p_read[count] = '\0';
+
+            // skip over leading newlines
+            while (*s_UartBufferCur == '\r' || *s_UartBufferCur == '\n')
+                s_UartBufferCur++;
+
+            p_eol = findNextEOL(s_UartBufferCur);
+            p_read += count;
+        }
+        else if (count <= 0)
+        {
+            /* read error encountered or EOF reached */
+            if(count == 0)
+            {
+                LOGD("atchannel: EOF reached");
+            }
+            else
+            {
+                LOGD("atchannel: read error %s", strerror(errno));
+            }
+            return NULL;
+        }
+    }
+
+    /* a full line in the buffer. Place a \0 over the \r and return */
+
+    ret = s_UartBufferCur;
+    *p_eol = '\0';
+    s_UartBufferCur = p_eol + 1; /* this will always be <= p_read,    */
+    /* and there will be a \0 at *p_read */
+
+    LOGD("URC< %s", ret);
+    return ret;
+}
+
+
+
+static void onReaderClosed()
+{
+    LOGD("onReaderClosed()");
+    if (s_onReaderClosed != NULL && s_readerClosed == 0)
+    {
+
+        pthread_mutex_lock(&s_commandmutex);
+
+        s_readerClosed = 1;
+
+        pthread_cond_signal(&s_commandcond);
+
+        pthread_mutex_unlock(&s_commandmutex);
+
+        s_onReaderClosed();
+    }
+}
+
+typedef struct
+{
+    int cid;
+    bool act;
+    bool waitting;
+} info_cgact_wait_t;
+extern info_cgact_wait_t cgact_wait;
+
+static void *readerLoop(void *arg)
+{
+    UNUSED(arg);
+    for (;;)
+    {
+        const char * line;
+
+        line = readline();
+
+        if (line == NULL)
+        {
+            break;
+        }
+
+        if(strStartsWith(line, "MBTK_AT_READY")) {
+            //handleUnsolicited(line);
+            continue;
+        } else if(strStartsWith(line, "CONNECT")) {
+            if(cgact_wait.waitting && cgact_wait.act) {
+                cgact_wait.waitting = false;
+            }
+        }
+
+        if(isSMSUnsolicited(line))
+        {
+            char *line1;
+            const char *line2;
+
+            // The scope of string returned by 'readline()' is valid only
+            // till next call to 'readline()' hence making a copy of line
+            // before calling readline again.
+            line1 = strdup(line);
+            line2 = readline();
+
+            if (line2 == NULL)
+            {
+                free(line1);
+                break;
+            }
+
+            if (s_unsolHandler != NULL)
+            {
+                s_unsolHandler (line1, line2);
+            }
+            free(line1);
+        }
+        else
+        {
+            processLine(line);
+        }
+    }
+
+    onReaderClosed();
+
+    return NULL;
+}
+
+static void *readerUrcLoop(void *arg)
+{
+    UNUSED(arg);
+    for (;;)
+    {
+        const char *line;
+
+        line = readlineUrc();
+
+        if (line == NULL)
+        {
+            break;
+        }
+
+        handleUnsolicited(line);
+    }
+
+    onReaderClosed();
+
+    return NULL;
+}
+
+
+/**
+ * Sends string s to the radio with a \r appended.
+ * Returns AT_ERROR_* on error, 0 on success
+ *
+ * This function exists because as of writing, android libc does not
+ * have buffered stdio.
+ */
+static int writeline (const char *s)
+{
+    size_t cur = 0;
+    size_t len = strlen(s);
+    ssize_t written;
+
+    if (s_at_fd < 0 || s_readerClosed > 0)
+    {
+        return AT_ERROR_CHANNEL_CLOSED;
+    }
+
+    LOGD("AT> %s", s);
+
+    AT_DUMP( ">> ", s, strlen(s) );
+
+    memset(s_curr_at, 0x0, AT_BUFF_MAX);
+    memcpy(s_curr_at, s, strlen(s));
+
+    /* the main string */
+    while (cur < len)
+    {
+        do
+        {
+            written = write (s_at_fd, s + cur, len - cur);
+        }
+        while (written < 0 && errno == EINTR);
+
+        if (written < 0)
+        {
+            return AT_ERROR_GENERIC;
+        }
+
+        cur += written;
+    }
+
+    /* the \r  */
+
+    do
+    {
+        written = write (s_at_fd, "\r", 1);
+    }
+    while ((written < 0 && errno == EINTR) || (written == 0));
+
+    if (written < 0)
+    {
+        return AT_ERROR_GENERIC;
+    }
+
+    return 0;
+}
+
+static int writeCtrlZ (const char *s)
+{
+    size_t cur = 0;
+    size_t len = strlen(s);
+    ssize_t written;
+
+    if (s_at_fd < 0 || s_readerClosed > 0)
+    {
+        return AT_ERROR_CHANNEL_CLOSED;
+    }
+
+    LOGD("AT> %s^Z\n", s);
+
+    AT_DUMP( ">* ", s, strlen(s) );
+
+    /* the main string */
+    while (cur < len)
+    {
+        do
+        {
+            written = write (s_at_fd, s + cur, len - cur);
+        }
+        while (written < 0 && errno == EINTR);
+
+        if (written < 0)
+        {
+            return AT_ERROR_GENERIC;
+        }
+
+        cur += written;
+    }
+
+    /* the ^Z  */
+
+    do
+    {
+        written = write (s_at_fd, "\032", 1);
+    }
+    while ((written < 0 && errno == EINTR) || (written == 0));
+
+    if (written < 0)
+    {
+        return AT_ERROR_GENERIC;
+    }
+
+    return 0;
+}
+
+static void clearPendingCommand()
+{
+    if (sp_response != NULL)
+    {
+        at_response_free(sp_response);
+    }
+
+    sp_response = NULL;
+    s_responsePrefix = NULL;
+    s_smsPDU = NULL;
+}
+
+
+/**
+ * Starts AT handler on stream "fd'
+ * returns 0 on success, -1 on error
+ */
+int at_open(int at_fd, int uart_fd, ATUnsolHandler h)
+{
+    int ret;
+    pthread_attr_t attr;
+
+    s_at_fd = at_fd;
+    s_uart_fd = uart_fd;
+    s_unsolHandler = h;
+    s_readerClosed = 0;
+    s_responsePrefix = NULL;
+    s_smsPDU = NULL;
+    sp_response = NULL;
+
+    pthread_attr_init (&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+    ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
+    if (ret < 0)
+    {
+        LOGE("AT thread create fail.");
+        return -1;
+    }
+
+    pthread_t uart_tid_reader;
+    ret = pthread_create(&uart_tid_reader, &attr, readerUrcLoop, &attr);
+    if (ret < 0)
+    {
+        LOGE("Uart thread create fail.");
+        return -1;
+    }
+
+    return 0;
+}
+
+/* FIXME is it ok to call this from the reader and the command thread? */
+void at_close()
+{
+    LOGD("at_close()");
+    if (s_at_fd >= 0)
+    {
+        close(s_at_fd);
+    }
+    if (s_uart_fd >= 0)
+    {
+        close(s_uart_fd);
+    }
+    s_at_fd = -1;
+    s_uart_fd = -1;
+
+    pthread_mutex_lock(&s_commandmutex);
+    s_readerClosed = 1;
+    pthread_cond_signal(&s_commandcond);
+    pthread_mutex_unlock(&s_commandmutex);
+    /* the reader thread should eventually die */
+
+    at_state = RIL_AT_STATE_CLOSED;
+}
+
+static ATResponse * at_response_new()
+{
+    return (ATResponse *) calloc(1, sizeof(ATResponse));
+}
+
+void at_response_free(ATResponse *p_response)
+{
+    ATLine *p_line;
+
+    if (p_response == NULL) return;
+
+    p_line = p_response->p_intermediates;
+
+    while (p_line != NULL)
+    {
+        ATLine *p_toFree;
+
+        p_toFree = p_line;
+        p_line = p_line->p_next;
+
+        free(p_toFree->line);
+        free(p_toFree);
+    }
+
+    free (p_response->finalResponse);
+    free (p_response);
+}
+
+/**
+ * The line reader places the intermediate responses in reverse order
+ * here we flip them back
+ */
+static void reverseIntermediates(ATResponse *p_response)
+{
+    ATLine *pcur,*pnext;
+
+    pcur = p_response->p_intermediates;
+    p_response->p_intermediates = NULL;
+
+    while (pcur != NULL)
+    {
+        pnext = pcur->p_next;
+        pcur->p_next = p_response->p_intermediates;
+        p_response->p_intermediates = pcur;
+        pcur = pnext;
+    }
+}
+
+static long long at_timeout_get(const char *at_command, bool *timeout_close)
+{
+    long long timeout = 0;
+    int i;
+    for(i = 0; i <  ARRAY_SIZE(at_timeout_list); i++)
+    {
+        if(!strncasecmp(at_command, at_timeout_list[i].at_command, strlen(at_timeout_list[i].at_command)))
+        {
+            timeout = at_timeout_list[i].timeout;
+            *timeout_close = at_timeout_list[i].timeout_close;
+            break;
+        }
+    }
+
+    return timeout;
+}
+
+/**
+ * Internal send_command implementation
+ * Doesn't lock or call the timeout callback
+ *
+ * timeoutMsec == 0 means infinite timeout
+ */
+static int at_send_command_full_nolock (const char *command, ATCommandType type,
+                                        const char *responsePrefix, const char *smspdu,
+                                        long long timeoutMsec, ATResponse **pp_outResponse)
+{
+    int err = 0;
+    bool tiemout_close = true;
+    struct timespec ts;
+    if(at_state == RIL_AT_STATE_READY)
+        at_state = RIL_AT_STATE_BUSY;
+
+    if(sp_response != NULL)
+    {
+        err = AT_ERROR_COMMAND_PENDING;
+        goto error;
+    }
+
+    err = writeline (command);
+
+    if (err < 0)
+    {
+        goto error;
+    }
+
+    s_type = type;
+    s_responsePrefix = responsePrefix;
+    s_smsPDU = smspdu;
+    sp_response = at_response_new();
+
+    if(timeoutMsec == 0)
+    {
+        timeoutMsec = at_timeout_get(command, &tiemout_close);
+    }
+
+    if (timeoutMsec != 0)
+    {
+        setTimespecRelative(&ts, timeoutMsec);
+    }
+
+    while (sp_response->finalResponse == NULL && s_readerClosed == 0)
+    {
+        //LOGD("AT wait time:%lld",timeoutMsec);
+        if (timeoutMsec != 0)
+        {
+            err = pthread_cond_timedwait(&s_commandcond, &s_commandmutex, &ts);
+        }
+        else
+        {
+            err = pthread_cond_wait(&s_commandcond, &s_commandmutex);
+        }
+
+        //LOGD("AT continue:err - %d",err);
+        if (err == ETIMEDOUT)
+        {
+            if(tiemout_close)
+            {
+                err = AT_ERROR_TIMEOUT_CLOSE;
+            }
+            else
+            {
+                err = AT_ERROR_TIMEOUT;
+            }
+            goto error;
+        }
+    }
+
+    if (pp_outResponse == NULL)
+    {
+        at_response_free(sp_response);
+    }
+    else
+    {
+        /* line reader stores intermediate responses in reverse order */
+        reverseIntermediates(sp_response);
+        *pp_outResponse = sp_response;
+    }
+
+    sp_response = NULL;
+
+    if(s_readerClosed > 0)
+    {
+        err = AT_ERROR_CHANNEL_CLOSED;
+        goto error;
+    }
+
+    err = 0;
+error:
+    if(at_state == RIL_AT_STATE_BUSY)
+        at_state = RIL_AT_STATE_READY;
+    clearPendingCommand();
+
+    return err;
+}
+
+/**
+ * Internal send_command implementation
+ *
+ * timeoutMsec == 0 means infinite timeout
+ */
+static int at_send_command_full (const char *command, ATCommandType type,
+                                 const char *responsePrefix, const char *smspdu,
+                                 long long timeoutMsec, ATResponse **pp_outResponse)
+{
+    int err;
+
+    if (0 != pthread_equal(s_tid_reader, pthread_self()))
+    {
+        /* cannot be called from reader thread */
+        LOGE("cannot be called from reader thread.");
+        return AT_ERROR_INVALID_THREAD;
+    }
+
+    // Waitting for previous AT complete.
+    while(at_state == RIL_AT_STATE_BUSY)
+    {
+        usleep(10000);
+    }
+
+    pthread_mutex_lock(&s_commandmutex);
+
+    err = at_send_command_full_nolock(command, type,
+                                      responsePrefix, smspdu,
+                                      timeoutMsec, pp_outResponse);
+
+    pthread_mutex_unlock(&s_commandmutex);
+
+    if (err == AT_ERROR_TIMEOUT_CLOSE && s_onTimeout != NULL)
+    {
+        s_onTimeout();
+    }
+
+    return err;
+}
+
+
+/**
+ * Issue a single normal AT command with no intermediate response expected
+ *
+ * "command" should not include \r
+ * pp_outResponse can be NULL
+ *
+ * if non-NULL, the resulting ATResponse * must be eventually freed with
+ * at_response_free
+ */
+int at_send_command (const char *command, ATResponse **pp_outResponse)
+{
+    return at_send_command_full (command, NO_RESULT, NULL,
+                                 NULL, 0, pp_outResponse);
+}
+
+
+int at_send_command_singleline (const char *command,
+                                const char *responsePrefix,
+                                ATResponse **pp_outResponse)
+{
+    int err;
+
+    err = at_send_command_full (command, SINGLELINE, responsePrefix,
+                                NULL, 0, pp_outResponse);
+
+    if (err == 0 && pp_outResponse != NULL
+        && (*pp_outResponse)->success > 0
+        && (*pp_outResponse)->p_intermediates == NULL
+       )
+    {
+        /* successful command must have an intermediate response */
+        at_response_free(*pp_outResponse);
+        *pp_outResponse = NULL;
+        return AT_ERROR_INVALID_RESPONSE;
+    }
+
+    return err;
+}
+
+int at_send_command_singleline_with_timeout (const char *command,
+        const char *responsePrefix,
+        ATResponse **pp_outResponse,long long timeoutMsec)
+{
+    int err;
+
+    err = at_send_command_full (command, SINGLELINE, responsePrefix,
+                                NULL, timeoutMsec, pp_outResponse);
+
+    if (err == 0 && pp_outResponse != NULL
+        && (*pp_outResponse)->success > 0
+        && (*pp_outResponse)->p_intermediates == NULL
+       )
+    {
+        /* successful command must have an intermediate response */
+        at_response_free(*pp_outResponse);
+        *pp_outResponse = NULL;
+        return AT_ERROR_INVALID_RESPONSE;
+    }
+
+    return err;
+}
+
+
+
+int at_send_command_numeric (const char *command,
+                             ATResponse **pp_outResponse)
+{
+    int err;
+
+    err = at_send_command_full (command, NUMERIC, NULL,
+                                NULL, 0, pp_outResponse);
+
+    if (err == 0 && pp_outResponse != NULL
+        && (*pp_outResponse)->success > 0
+        && (*pp_outResponse)->p_intermediates == NULL
+       )
+    {
+        /* successful command must have an intermediate response */
+        at_response_free(*pp_outResponse);
+        *pp_outResponse = NULL;
+        return AT_ERROR_INVALID_RESPONSE;
+    }
+
+    return err;
+}
+
+
+int at_send_command_sms (const char *command,
+                         const char *pdu,
+                         const char *responsePrefix,
+                         ATResponse **pp_outResponse)
+{
+    int err;
+
+    err = at_send_command_full (command, SINGLELINE, responsePrefix,
+                                pdu, 0, pp_outResponse);
+
+    if (err == 0 && pp_outResponse != NULL
+        && (*pp_outResponse)->success > 0
+        && (*pp_outResponse)->p_intermediates == NULL
+       )
+    {
+        /* successful command must have an intermediate response */
+        at_response_free(*pp_outResponse);
+        *pp_outResponse = NULL;
+        return AT_ERROR_INVALID_RESPONSE;
+    }
+
+    return err;
+}
+
+
+int at_send_command_multiline (const char *command,
+                               const char *responsePrefix,
+                               ATResponse **pp_outResponse)
+{
+    int err;
+
+    err = at_send_command_full (command, MULTILINE, responsePrefix,
+                                NULL, 0, pp_outResponse);
+
+    return err;
+}
+
+
+/** This callback is invoked on the command thread */
+void at_set_on_timeout(void (*onTimeout)(void))
+{
+    s_onTimeout = onTimeout;
+}
+
+/**
+ *  This callback is invoked on the reader thread (like ATUnsolHandler)
+ *  when the input stream closes before you call at_close
+ *  (not when you call at_close())
+ *  You should still call at_close()
+ */
+
+void at_set_on_reader_closed(void (*onClose)(void))
+{
+    s_onReaderClosed = onClose;
+}
+
+
+/**
+ * Periodically issue an AT command and wait for a response.
+ * Used to ensure channel has start up and is active
+ */
+int at_handshake()
+{
+    int i;
+    int err = 0;
+
+    if (0 != pthread_equal(s_tid_reader, pthread_self()))
+    {
+        /* cannot be called from reader thread */
+        return AT_ERROR_INVALID_THREAD;
+    }
+    pthread_mutex_lock(&s_commandmutex);
+
+#if 0
+    for (i = 0 ; i < HANDSHAKE_RETRY_COUNT ; i++)
+    {
+        /* some stacks start with verbose off */
+        err = at_send_command_full_nolock("ATE0Q0V1", NO_RESULT,
+                                          NULL, NULL, HANDSHAKE_TIMEOUT_MSEC, NULL);
+
+        if (err == 0)
+        {
+            break;
+        }
+    }
+#else
+    err = at_send_command_full_nolock("ATE0Q0V1", NO_RESULT,
+                                          NULL, NULL, 0, NULL);
+#endif
+
+    if (err == 0)
+    {
+        /* pause for a bit to let the input buffer drain any unmatched OK's
+           (they will appear as extraneous unsolicited responses) */
+        sleepMsec(HANDSHAKE_TIMEOUT_MSEC);
+    }
+
+    pthread_mutex_unlock(&s_commandmutex);
+
+
+    return err;
+}
+
+/**
+ * Returns error code from response
+ * Assumes AT+CMEE=1 (numeric) mode
+ */
+int at_get_cme_error(const ATResponse *p_response)
+{
+    int ret;
+    int err;
+    char *p_cur;
+
+    if (p_response->success > 0)
+    {
+        return CME_SUCCESS;
+    }
+
+    if (p_response->finalResponse == NULL
+        || !strStartsWith(p_response->finalResponse, "+CME ERROR:")
+       )
+    {
+        return CME_ERROR_NON_CME;
+    }
+
+    p_cur = p_response->finalResponse;
+    err = at_tok_start(&p_cur);
+
+    if (err < 0)
+    {
+        return CME_ERROR_NON_CME;
+    }
+
+    err = at_tok_nextint(&p_cur, &ret);
+
+    if (err < 0)
+    {
+        return CME_ERROR_NON_CME;
+    }
+
+    return ret;
+}
+
+mbtk_ril_at_state_enum at_state_get()
+{
+    return at_state;
+}
+
+void at_state_set(mbtk_ril_at_state_enum state)
+{
+    at_state = state;
+}
+
+bool at_rsp_check(ATResponse *p_response)
+{
+    if(!p_response || !p_response->success)
+        return false;
+
+    return true;
+}
+
+void unused_func()
+{
+    isFinalResponse(NULL);
+}
+