100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/* //device/system/reference-ril/atchannel.c
200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project**
300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project** Copyright 2006, The Android Open Source Project
400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project**
500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");
600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project** you may not use this file except in compliance with the License.
700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project** You may obtain a copy of the License at
800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project**
900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project**     http://www.apache.org/licenses/LICENSE-2.0
1000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project**
1100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project** Unless required by applicable law or agreed to in writing, software
1200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project** distributed under the License is distributed on an "AS IS" BASIS,
1300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project** See the License for the specific language governing permissions and
1500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project** limitations under the License.
1600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project*/
1700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
1800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include "atchannel.h"
1900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include "at_tok.h"
2000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
2100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include <stdio.h>
2200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include <string.h>
2300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include <pthread.h>
2400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include <ctype.h>
2500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include <stdlib.h>
2600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include <errno.h>
2700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include <fcntl.h>
2800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include <sys/time.h>
2900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include <time.h>
3000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include <unistd.h>
3100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
3200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#define LOG_NDEBUG 0
3300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#define LOG_TAG "AT"
3400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include <utils/Log.h>
3500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
3600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#ifdef HAVE_ANDROID_OS
3700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/* for IOCTL's */
3800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include <linux/omap_csmi.h>
3900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#endif /*HAVE_ANDROID_OS*/
4000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
4100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#include "misc.h"
4200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
4300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#ifdef HAVE_ANDROID_OS
4400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#define USE_NP 1
4500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#endif /* HAVE_ANDROID_OS */
4600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
4700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
4800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#define NUM_ELEMS(x) (sizeof(x)/sizeof(x[0]))
4900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
5000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#define MAX_AT_RESPONSE (8 * 1024)
5100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#define HANDSHAKE_RETRY_COUNT 8
5200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#define HANDSHAKE_TIMEOUT_MSEC 250
5300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
5400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic pthread_t s_tid_reader;
5500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic int s_fd = -1;    /* fd of the AT channel */
5600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic ATUnsolHandler s_unsolHandler;
5700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
5800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/* for input buffering */
5900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
6000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic char s_ATBuffer[MAX_AT_RESPONSE+1];
6100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic char *s_ATBufferCur = s_ATBuffer;
6200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
6300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic int s_ackPowerIoctl; /* true if TTY has android byte-count
6400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                                handshake for low power*/
6500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic int s_readCount = 0;
6600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
6700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#if AT_DEBUG
6800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectvoid  AT_DUMP(const char*  prefix, const char*  buff, int  len)
6900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
7000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (len < 0)
7100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        len = strlen(buff);
724dcab4f90d2d49e40100e4888b1411dfbd1c9783Wink Saville    RLOGD("%.*s", len, buff);
7300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
7400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#endif
7500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
7600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/*
7700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * for current pending command
7800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * these are protected by s_commandmutex
7900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
8000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
8100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic pthread_mutex_t s_commandmutex = PTHREAD_MUTEX_INITIALIZER;
8200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic pthread_cond_t s_commandcond = PTHREAD_COND_INITIALIZER;
8300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
8400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic ATCommandType s_type;
8500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic const char *s_responsePrefix = NULL;
8600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic const char *s_smsPDU = NULL;
8700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic ATResponse *sp_response = NULL;
8800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
8900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic void (*s_onTimeout)(void) = NULL;
9000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic void (*s_onReaderClosed)(void) = NULL;
9100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic int s_readerClosed;
9200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
9300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic void onReaderClosed();
9400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic int writeCtrlZ (const char *s);
9500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic int writeline (const char *s);
9600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
9700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#ifndef USE_NP
9800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic void setTimespecRelative(struct timespec *p_ts, long long msec)
9900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
10000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    struct timeval tv;
10100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
10200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    gettimeofday(&tv, (struct timezone *) NULL);
10300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
10400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    /* what's really funny about this is that I know
10500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project       pthread_cond_timedwait just turns around and makes this
10600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project       a relative time again */
10700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    p_ts->tv_sec = tv.tv_sec + (msec / 1000);
10800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    p_ts->tv_nsec = (tv.tv_usec + (msec % 1000) * 1000L ) * 1000L;
10900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
11000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#endif /*USE_NP*/
11100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
11200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic void sleepMsec(long long msec)
11300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
11400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    struct timespec ts;
11500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    int err;
11600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
11700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ts.tv_sec = (msec / 1000);
11800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ts.tv_nsec = (msec % 1000) * 1000 * 1000;
11900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
12000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    do {
12100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        err = nanosleep (&ts, &ts);
12200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    } while (err < 0 && errno == EINTR);
12300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
12400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
12500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
12600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
12700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/** add an intermediate response to sp_response*/
12800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic void addIntermediate(const char *line)
12900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
13000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ATLine *p_new;
13100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
13200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    p_new = (ATLine  *) malloc(sizeof(ATLine));
13300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
13400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    p_new->line = strdup(line);
13500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
13600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    /* note: this adds to the head of the list, so the list
13700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project       will be in reverse order of lines received. the order is flipped
13800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project       again before passing on to the command issuer */
13900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    p_new->p_next = sp_response->p_intermediates;
14000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    sp_response->p_intermediates = p_new;
14100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
14200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
14300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
14400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
14500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * returns 1 if line is a final response indicating error
14600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * See 27.007 annex B
14700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * WARNING: NO CARRIER and others are sometimes unsolicited
14800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
14900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic const char * s_finalResponsesError[] = {
15000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    "ERROR",
15100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    "+CMS ERROR:",
15200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    "+CME ERROR:",
15300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    "NO CARRIER", /* sometimes! */
15400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    "NO ANSWER",
15500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    "NO DIALTONE",
15600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project};
15700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic int isFinalResponseError(const char *line)
15800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
15900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    size_t i;
16000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
16100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    for (i = 0 ; i < NUM_ELEMS(s_finalResponsesError) ; i++) {
16200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        if (strStartsWith(line, s_finalResponsesError[i])) {
16300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            return 1;
16400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        }
16500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
16600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
16700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return 0;
16800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
16900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
17000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
17100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * returns 1 if line is a final response indicating success
17200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * See 27.007 annex B
17300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * WARNING: NO CARRIER and others are sometimes unsolicited
17400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
17500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic const char * s_finalResponsesSuccess[] = {
17600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    "OK",
17700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    "CONNECT"       /* some stacks start up data on another channel */
17800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project};
17900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic int isFinalResponseSuccess(const char *line)
18000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
18100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    size_t i;
18200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
18300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    for (i = 0 ; i < NUM_ELEMS(s_finalResponsesSuccess) ; i++) {
18400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        if (strStartsWith(line, s_finalResponsesSuccess[i])) {
18500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            return 1;
18600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        }
18700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
18800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
18900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return 0;
19000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
19100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
19200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
19300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * returns 1 if line is a final response, either  error or success
19400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * See 27.007 annex B
19500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * WARNING: NO CARRIER and others are sometimes unsolicited
19600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
19700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic int isFinalResponse(const char *line)
19800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
19900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return isFinalResponseSuccess(line) || isFinalResponseError(line);
20000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
20100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
20200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
20300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
20400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * returns 1 if line is the first line in (what will be) a two-line
20500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * SMS unsolicited response
20600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
20700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic const char * s_smsUnsoliciteds[] = {
20800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    "+CMT:",
20900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    "+CDS:",
21000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    "+CBM:"
21100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project};
21200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic int isSMSUnsolicited(const char *line)
21300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
21400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    size_t i;
21500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
21600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    for (i = 0 ; i < NUM_ELEMS(s_smsUnsoliciteds) ; i++) {
21700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        if (strStartsWith(line, s_smsUnsoliciteds[i])) {
21800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            return 1;
21900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        }
22000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
22100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
22200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return 0;
22300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
22400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
22500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
22600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/** assumes s_commandmutex is held */
22700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic void handleFinalResponse(const char *line)
22800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
22900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    sp_response->finalResponse = strdup(line);
23000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
23100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pthread_cond_signal(&s_commandcond);
23200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
23300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
23400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic void handleUnsolicited(const char *line)
23500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
23600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (s_unsolHandler != NULL) {
23700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        s_unsolHandler(line, NULL);
23800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
23900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
24000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
24100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic void processLine(const char *line)
24200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
24300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pthread_mutex_lock(&s_commandmutex);
24400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
24500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (sp_response == NULL) {
24600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        /* no command pending */
24700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        handleUnsolicited(line);
24800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    } else if (isFinalResponseSuccess(line)) {
24900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        sp_response->success = 1;
25000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        handleFinalResponse(line);
25100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    } else if (isFinalResponseError(line)) {
25200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        sp_response->success = 0;
25300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        handleFinalResponse(line);
25400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    } else if (s_smsPDU != NULL && 0 == strcmp(line, "> ")) {
25500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        // See eg. TS 27.005 4.3
25600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        // Commands like AT+CMGS have a "> " prompt
25700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        writeCtrlZ(s_smsPDU);
25800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        s_smsPDU = NULL;
25900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    } else switch (s_type) {
26000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        case NO_RESULT:
26100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            handleUnsolicited(line);
26200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            break;
26300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        case NUMERIC:
26400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            if (sp_response->p_intermediates == NULL
26500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                && isdigit(line[0])
26600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            ) {
26700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                addIntermediate(line);
26800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            } else {
26900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                /* either we already have an intermediate response or
27000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                   the line doesn't begin with a digit */
27100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                handleUnsolicited(line);
27200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            }
27300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            break;
27400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        case SINGLELINE:
27500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            if (sp_response->p_intermediates == NULL
27600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                && strStartsWith (line, s_responsePrefix)
27700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            ) {
27800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                addIntermediate(line);
27900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            } else {
28000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                /* we already have an intermediate response */
28100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                handleUnsolicited(line);
28200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            }
28300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            break;
28400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        case MULTILINE:
28500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            if (strStartsWith (line, s_responsePrefix)) {
28600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                addIntermediate(line);
28700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            } else {
28800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                handleUnsolicited(line);
28900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            }
29000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        break;
29100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
29200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        default: /* this should never be reached */
2934dcab4f90d2d49e40100e4888b1411dfbd1c9783Wink Saville            RLOGE("Unsupported AT command type %d\n", s_type);
29400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            handleUnsolicited(line);
29500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        break;
29600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
29700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
29800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pthread_mutex_unlock(&s_commandmutex);
29900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
30000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
30100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
30200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
30300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * Returns a pointer to the end of the next line
30400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * special-cases the "> " SMS prompt
30500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project *
30600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * returns NULL if there is no complete line
30700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
30800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic char * findNextEOL(char *cur)
30900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
31000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (cur[0] == '>' && cur[1] == ' ' && cur[2] == '\0') {
31100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        /* SMS prompt character...not \r terminated */
31200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return cur+2;
31300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
31400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
31500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    // Find next newline
31600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    while (*cur != '\0' && *cur != '\r' && *cur != '\n') cur++;
31700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
31800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return *cur == '\0' ? NULL : cur;
31900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
32000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
32100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
32200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
32300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * Reads a line from the AT channel, returns NULL on timeout.
32400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * Assumes it has exclusive read access to the FD
32500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project *
32600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * This line is valid only until the next call to readline
32700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project *
32800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * This function exists because as of writing, android libc does not
32900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * have buffered stdio.
33000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
33100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
33200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic const char *readline()
33300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
33400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ssize_t count;
33500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
33600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    char *p_read = NULL;
33700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    char *p_eol = NULL;
33800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    char *ret;
33900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
34000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    /* this is a little odd. I use *s_ATBufferCur == 0 to
34100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project     * mean "buffer consumed completely". If it points to a character, than
34200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project     * the buffer continues until a \0
34300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project     */
34400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (*s_ATBufferCur == '\0') {
34500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        /* empty buffer */
34600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        s_ATBufferCur = s_ATBuffer;
34700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        *s_ATBufferCur = '\0';
34800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        p_read = s_ATBuffer;
34900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    } else {   /* *s_ATBufferCur != '\0' */
35000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        /* there's data in the buffer from the last read */
35100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
35200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        // skip over leading newlines
35300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
35400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            s_ATBufferCur++;
35500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
35600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        p_eol = findNextEOL(s_ATBufferCur);
35700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
35800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        if (p_eol == NULL) {
35900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            /* a partial line. move it up and prepare to read more */
36000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            size_t len;
36100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
36200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            len = strlen(s_ATBufferCur);
36300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
36400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            memmove(s_ATBuffer, s_ATBufferCur, len + 1);
36500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            p_read = s_ATBuffer + len;
36600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            s_ATBufferCur = s_ATBuffer;
36700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        }
36800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        /* Otherwise, (p_eol !- NULL) there is a complete line  */
36900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        /* that will be returned the while () loop below        */
37000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
37100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
37200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    while (p_eol == NULL) {
37300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        if (0 == MAX_AT_RESPONSE - (p_read - s_ATBuffer)) {
3744dcab4f90d2d49e40100e4888b1411dfbd1c9783Wink Saville            RLOGE("ERROR: Input line exceeded buffer\n");
37500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            /* ditch buffer and start over again */
37600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            s_ATBufferCur = s_ATBuffer;
37700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            *s_ATBufferCur = '\0';
37800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            p_read = s_ATBuffer;
37900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        }
38000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
38100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        do {
38200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            count = read(s_fd, p_read,
38300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                            MAX_AT_RESPONSE - (p_read - s_ATBuffer));
38400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        } while (count < 0 && errno == EINTR);
38500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
38600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        if (count > 0) {
38700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            AT_DUMP( "<< ", p_read, count );
38800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            s_readCount += count;
38900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
39000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            p_read[count] = '\0';
39100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
39200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            // skip over leading newlines
39300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
39400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                s_ATBufferCur++;
39500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
39600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            p_eol = findNextEOL(s_ATBufferCur);
39700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            p_read += count;
39800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        } else if (count <= 0) {
39900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            /* read error encountered or EOF reached */
40000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            if(count == 0) {
4014dcab4f90d2d49e40100e4888b1411dfbd1c9783Wink Saville                RLOGD("atchannel: EOF reached");
40200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            } else {
4034dcab4f90d2d49e40100e4888b1411dfbd1c9783Wink Saville                RLOGD("atchannel: read error %s", strerror(errno));
40400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            }
40500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            return NULL;
40600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        }
40700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
40800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
40900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    /* a full line in the buffer. Place a \0 over the \r and return */
41000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
41100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ret = s_ATBufferCur;
41200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    *p_eol = '\0';
41300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_ATBufferCur = p_eol + 1; /* this will always be <= p_read,    */
41400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                              /* and there will be a \0 at *p_read */
41500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
4164dcab4f90d2d49e40100e4888b1411dfbd1c9783Wink Saville    RLOGD("AT< %s\n", ret);
41700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return ret;
41800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
41900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
42000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
42100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic void onReaderClosed()
42200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
42300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (s_onReaderClosed != NULL && s_readerClosed == 0) {
42400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
42500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        pthread_mutex_lock(&s_commandmutex);
42600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
42700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        s_readerClosed = 1;
42800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
42900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        pthread_cond_signal(&s_commandcond);
43000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
43100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        pthread_mutex_unlock(&s_commandmutex);
43200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
43300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        s_onReaderClosed();
43400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
43500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
43600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
43700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
43800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic void *readerLoop(void *arg)
43900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
44000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    for (;;) {
44100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        const char * line;
44200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
44300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        line = readline();
44400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
44500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        if (line == NULL) {
44600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            break;
44700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        }
44800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
44900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        if(isSMSUnsolicited(line)) {
45000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            char *line1;
45100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            const char *line2;
45200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
45300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            // The scope of string returned by 'readline()' is valid only
45400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            // till next call to 'readline()' hence making a copy of line
45500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            // before calling readline again.
45600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            line1 = strdup(line);
45700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            line2 = readline();
45800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
45900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            if (line2 == NULL) {
46000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                break;
46100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            }
46200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
46300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            if (s_unsolHandler != NULL) {
46400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                s_unsolHandler (line1, line2);
46500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            }
46600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            free(line1);
46700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        } else {
46800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            processLine(line);
46900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        }
47000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
47100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#ifdef HAVE_ANDROID_OS
47200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        if (s_ackPowerIoctl > 0) {
47300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            /* acknowledge that bytes have been read and processed */
47400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            ioctl(s_fd, OMAP_CSMI_TTY_ACK, &s_readCount);
47500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            s_readCount = 0;
47600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        }
47700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#endif /*HAVE_ANDROID_OS*/
47800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
47900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
48000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    onReaderClosed();
48100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
48200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return NULL;
48300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
48400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
48500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
48600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * Sends string s to the radio with a \r appended.
48700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * Returns AT_ERROR_* on error, 0 on success
48800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project *
48900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * This function exists because as of writing, android libc does not
49000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * have buffered stdio.
49100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
49200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic int writeline (const char *s)
49300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
49400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    size_t cur = 0;
49500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    size_t len = strlen(s);
49600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ssize_t written;
49700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
49800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (s_fd < 0 || s_readerClosed > 0) {
49900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return AT_ERROR_CHANNEL_CLOSED;
50000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
50100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
5024dcab4f90d2d49e40100e4888b1411dfbd1c9783Wink Saville    RLOGD("AT> %s\n", s);
50300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
50400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    AT_DUMP( ">> ", s, strlen(s) );
50500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
50600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    /* the main string */
50700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    while (cur < len) {
50800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        do {
50900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            written = write (s_fd, s + cur, len - cur);
51000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        } while (written < 0 && errno == EINTR);
51100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
51200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        if (written < 0) {
51300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            return AT_ERROR_GENERIC;
51400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        }
51500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
51600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        cur += written;
51700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
51800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
51900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    /* the \r  */
52000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
52100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    do {
52200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        written = write (s_fd, "\r" , 1);
52300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    } while ((written < 0 && errno == EINTR) || (written == 0));
52400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
52500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (written < 0) {
52600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return AT_ERROR_GENERIC;
52700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
52800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
52900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return 0;
53000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
53100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic int writeCtrlZ (const char *s)
53200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
53300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    size_t cur = 0;
53400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    size_t len = strlen(s);
53500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ssize_t written;
53600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
53700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (s_fd < 0 || s_readerClosed > 0) {
53800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return AT_ERROR_CHANNEL_CLOSED;
53900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
54000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
5414dcab4f90d2d49e40100e4888b1411dfbd1c9783Wink Saville    RLOGD("AT> %s^Z\n", s);
54200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
54300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    AT_DUMP( ">* ", s, strlen(s) );
54400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
54500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    /* the main string */
54600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    while (cur < len) {
54700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        do {
54800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            written = write (s_fd, s + cur, len - cur);
54900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        } while (written < 0 && errno == EINTR);
55000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
55100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        if (written < 0) {
55200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            return AT_ERROR_GENERIC;
55300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        }
55400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
55500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        cur += written;
55600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
55700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
55800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    /* the ^Z  */
55900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
56000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    do {
56100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        written = write (s_fd, "\032" , 1);
56200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    } while ((written < 0 && errno == EINTR) || (written == 0));
56300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
56400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (written < 0) {
56500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return AT_ERROR_GENERIC;
56600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
56700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
56800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return 0;
56900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
57000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
57100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic void clearPendingCommand()
57200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
57300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (sp_response != NULL) {
57400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        at_response_free(sp_response);
57500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
57600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
57700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    sp_response = NULL;
57800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_responsePrefix = NULL;
57900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_smsPDU = NULL;
58000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
58100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
58200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
58300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
58400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * Starts AT handler on stream "fd'
58500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * returns 0 on success, -1 on error
58600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
58700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectint at_open(int fd, ATUnsolHandler h)
58800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
58900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    int ret;
59000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pthread_t tid;
59100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pthread_attr_t attr;
59200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
59300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_fd = fd;
59400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_unsolHandler = h;
59500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_readerClosed = 0;
59600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
59700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_responsePrefix = NULL;
59800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_smsPDU = NULL;
59900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    sp_response = NULL;
60000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
60100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    /* Android power control ioctl */
60200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#ifdef HAVE_ANDROID_OS
60300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#ifdef OMAP_CSMI_POWER_CONTROL
60400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ret = ioctl(fd, OMAP_CSMI_TTY_ENABLE_ACK);
60500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if(ret == 0) {
60600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        int ack_count;
60700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project		int read_count;
60800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        int old_flags;
60900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        char sync_buf[256];
61000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        old_flags = fcntl(fd, F_GETFL, 0);
61100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        fcntl(fd, F_SETFL, old_flags | O_NONBLOCK);
61200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        do {
61300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            ioctl(fd, OMAP_CSMI_TTY_READ_UNACKED, &ack_count);
61400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project			read_count = 0;
61500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            do {
61600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                ret = read(fd, sync_buf, sizeof(sync_buf));
61700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project				if(ret > 0)
61800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project					read_count += ret;
61900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            } while(ret > 0 || (ret < 0 && errno == EINTR));
62000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            ioctl(fd, OMAP_CSMI_TTY_ACK, &ack_count);
62100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project         } while(ack_count > 0 || read_count > 0);
62200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        fcntl(fd, F_SETFL, old_flags);
62300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        s_readCount = 0;
62400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        s_ackPowerIoctl = 1;
62500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
62600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    else
62700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        s_ackPowerIoctl = 0;
62800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
62900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#else // OMAP_CSMI_POWER_CONTROL
63000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_ackPowerIoctl = 0;
63100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
63200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#endif // OMAP_CSMI_POWER_CONTROL
63300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#endif /*HAVE_ANDROID_OS*/
63400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
63500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pthread_attr_init (&attr);
63600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
63700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
63800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
63900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
64000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (ret < 0) {
64100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        perror ("pthread_create");
64200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return -1;
64300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
64400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
64500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
64600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return 0;
64700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
64800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
64900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/* FIXME is it ok to call this from the reader and the command thread? */
65000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectvoid at_close()
65100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
65200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (s_fd >= 0) {
65300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        close(s_fd);
65400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
65500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_fd = -1;
65600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
65700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pthread_mutex_lock(&s_commandmutex);
65800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
65900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_readerClosed = 1;
66000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
66100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pthread_cond_signal(&s_commandcond);
66200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
66300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pthread_mutex_unlock(&s_commandmutex);
66400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
66500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    /* the reader thread should eventually die */
66600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
66700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
66800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic ATResponse * at_response_new()
66900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
67000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return (ATResponse *) calloc(1, sizeof(ATResponse));
67100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
67200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
67300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectvoid at_response_free(ATResponse *p_response)
67400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
67500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ATLine *p_line;
67600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
67700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (p_response == NULL) return;
67800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
67900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    p_line = p_response->p_intermediates;
68000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
68100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    while (p_line != NULL) {
68200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        ATLine *p_toFree;
68300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
68400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        p_toFree = p_line;
68500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        p_line = p_line->p_next;
68600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
68700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        free(p_toFree->line);
68800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        free(p_toFree);
68900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
69000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
69100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    free (p_response->finalResponse);
69200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    free (p_response);
69300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
69400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
69500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
69600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * The line reader places the intermediate responses in reverse order
69700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * here we flip them back
69800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
69900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic void reverseIntermediates(ATResponse *p_response)
70000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
70100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ATLine *pcur,*pnext;
70200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
70300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pcur = p_response->p_intermediates;
70400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    p_response->p_intermediates = NULL;
70500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
70600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    while (pcur != NULL) {
70700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        pnext = pcur->p_next;
70800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        pcur->p_next = p_response->p_intermediates;
70900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        p_response->p_intermediates = pcur;
71000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        pcur = pnext;
71100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
71200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
71300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
71400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
71500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * Internal send_command implementation
71600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * Doesn't lock or call the timeout callback
71700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project *
71800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * timeoutMsec == 0 means infinite timeout
71900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
72000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
72100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic int at_send_command_full_nolock (const char *command, ATCommandType type,
72200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                    const char *responsePrefix, const char *smspdu,
72300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                    long long timeoutMsec, ATResponse **pp_outResponse)
72400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
72500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    int err = 0;
72600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#ifndef USE_NP
72700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    struct timespec ts;
72800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#endif /*USE_NP*/
72900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
73000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if(sp_response != NULL) {
73100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        err = AT_ERROR_COMMAND_PENDING;
73200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        goto error;
73300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
73400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
73500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    err = writeline (command);
73600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
73700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (err < 0) {
73800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        goto error;
73900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
74000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
74100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_type = type;
74200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_responsePrefix = responsePrefix;
74300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_smsPDU = smspdu;
74400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    sp_response = at_response_new();
74500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
74600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#ifndef USE_NP
74700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (timeoutMsec != 0) {
74800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        setTimespecRelative(&ts, timeoutMsec);
74900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
75000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#endif /*USE_NP*/
75100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
75200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    while (sp_response->finalResponse == NULL && s_readerClosed == 0) {
75300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        if (timeoutMsec != 0) {
75400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#ifdef USE_NP
75500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            err = pthread_cond_timeout_np(&s_commandcond, &s_commandmutex, timeoutMsec);
75600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#else
75700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            err = pthread_cond_timedwait(&s_commandcond, &s_commandmutex, &ts);
75800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project#endif /*USE_NP*/
75900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        } else {
76000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            err = pthread_cond_wait(&s_commandcond, &s_commandmutex);
76100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        }
76200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
76300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        if (err == ETIMEDOUT) {
76400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            err = AT_ERROR_TIMEOUT;
76500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            goto error;
76600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        }
76700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
76800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
76900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (pp_outResponse == NULL) {
77000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        at_response_free(sp_response);
77100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    } else {
77200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        /* line reader stores intermediate responses in reverse order */
77300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        reverseIntermediates(sp_response);
77400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        *pp_outResponse = sp_response;
77500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
77600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
77700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    sp_response = NULL;
77800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
77900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if(s_readerClosed > 0) {
78000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        err = AT_ERROR_CHANNEL_CLOSED;
78100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        goto error;
78200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
78300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
78400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    err = 0;
78500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projecterror:
78600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    clearPendingCommand();
78700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
78800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return err;
78900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
79000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
79100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
79200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * Internal send_command implementation
79300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project *
79400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * timeoutMsec == 0 means infinite timeout
79500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
79600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectstatic int at_send_command_full (const char *command, ATCommandType type,
79700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                    const char *responsePrefix, const char *smspdu,
79800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                    long long timeoutMsec, ATResponse **pp_outResponse)
79900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
80000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    int err;
80100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
80200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (0 != pthread_equal(s_tid_reader, pthread_self())) {
80300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        /* cannot be called from reader thread */
80400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return AT_ERROR_INVALID_THREAD;
80500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
80600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
80700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pthread_mutex_lock(&s_commandmutex);
80800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
80900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    err = at_send_command_full_nolock(command, type,
81000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                    responsePrefix, smspdu,
81100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                    timeoutMsec, pp_outResponse);
81200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
81300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pthread_mutex_unlock(&s_commandmutex);
81400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
81500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (err == AT_ERROR_TIMEOUT && s_onTimeout != NULL) {
81600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        s_onTimeout();
81700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
81800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
81900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return err;
82000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
82100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
82200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
82300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
82400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * Issue a single normal AT command with no intermediate response expected
82500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project *
82600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * "command" should not include \r
82700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * pp_outResponse can be NULL
82800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project *
82900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * if non-NULL, the resulting ATResponse * must be eventually freed with
83000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * at_response_free
83100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
83200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectint at_send_command (const char *command, ATResponse **pp_outResponse)
83300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
83400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    int err;
83500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
83600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    err = at_send_command_full (command, NO_RESULT, NULL,
83700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                                    NULL, 0, pp_outResponse);
83800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
83900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return err;
84000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
84100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
84200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
84300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectint at_send_command_singleline (const char *command,
84400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                                const char *responsePrefix,
84500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                                 ATResponse **pp_outResponse)
84600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
84700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    int err;
84800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
84900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    err = at_send_command_full (command, SINGLELINE, responsePrefix,
85000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                                    NULL, 0, pp_outResponse);
85100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
85200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (err == 0 && pp_outResponse != NULL
85300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        && (*pp_outResponse)->success > 0
85400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        && (*pp_outResponse)->p_intermediates == NULL
85500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ) {
85600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        /* successful command must have an intermediate response */
85700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        at_response_free(*pp_outResponse);
85800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        *pp_outResponse = NULL;
85900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return AT_ERROR_INVALID_RESPONSE;
86000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
86100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
86200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return err;
86300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
86400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
86500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
86600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectint at_send_command_numeric (const char *command,
86700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                                 ATResponse **pp_outResponse)
86800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
86900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    int err;
87000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
87100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    err = at_send_command_full (command, NUMERIC, NULL,
87200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                                    NULL, 0, pp_outResponse);
87300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
87400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (err == 0 && pp_outResponse != NULL
87500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        && (*pp_outResponse)->success > 0
87600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        && (*pp_outResponse)->p_intermediates == NULL
87700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ) {
87800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        /* successful command must have an intermediate response */
87900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        at_response_free(*pp_outResponse);
88000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        *pp_outResponse = NULL;
88100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return AT_ERROR_INVALID_RESPONSE;
88200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
88300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
88400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return err;
88500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
88600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
88700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
88800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectint at_send_command_sms (const char *command,
88900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                                const char *pdu,
89000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                                const char *responsePrefix,
89100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                                 ATResponse **pp_outResponse)
89200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
89300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    int err;
89400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
89500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    err = at_send_command_full (command, SINGLELINE, responsePrefix,
89600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                                    pdu, 0, pp_outResponse);
89700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
89800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (err == 0 && pp_outResponse != NULL
89900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        && (*pp_outResponse)->success > 0
90000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        && (*pp_outResponse)->p_intermediates == NULL
90100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ) {
90200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        /* successful command must have an intermediate response */
90300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        at_response_free(*pp_outResponse);
90400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        *pp_outResponse = NULL;
90500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return AT_ERROR_INVALID_RESPONSE;
90600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
90700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
90800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return err;
90900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
91000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
91100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
91200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectint at_send_command_multiline (const char *command,
91300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                                const char *responsePrefix,
91400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                                 ATResponse **pp_outResponse)
91500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
91600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    int err;
91700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
91800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    err = at_send_command_full (command, MULTILINE, responsePrefix,
91900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                                    NULL, 0, pp_outResponse);
92000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
92100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return err;
92200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
92300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
92400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
92500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/** This callback is invoked on the command thread */
92600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectvoid at_set_on_timeout(void (*onTimeout)(void))
92700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
92800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_onTimeout = onTimeout;
92900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
93000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
93100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
93200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project *  This callback is invoked on the reader thread (like ATUnsolHandler)
93300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project *  when the input stream closes before you call at_close
93400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project *  (not when you call at_close())
93500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project *  You should still call at_close()
93600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
93700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
93800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectvoid at_set_on_reader_closed(void (*onClose)(void))
93900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
94000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    s_onReaderClosed = onClose;
94100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
94200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
94300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
94400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
94500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * Periodically issue an AT command and wait for a response.
94600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * Used to ensure channel has start up and is active
94700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
94800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
94900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Projectint at_handshake()
95000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
95100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    int i;
95200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    int err = 0;
95300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
95400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (0 != pthread_equal(s_tid_reader, pthread_self())) {
95500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        /* cannot be called from reader thread */
95600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return AT_ERROR_INVALID_THREAD;
95700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
95800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
95900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pthread_mutex_lock(&s_commandmutex);
96000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
96100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    for (i = 0 ; i < HANDSHAKE_RETRY_COUNT ; i++) {
96200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        /* some stacks start with verbose off */
96300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        err = at_send_command_full_nolock ("ATE0Q0V1", NO_RESULT,
96400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project                    NULL, NULL, HANDSHAKE_TIMEOUT_MSEC, NULL);
96500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
96600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        if (err == 0) {
96700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project            break;
96800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        }
96900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
97000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
97100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (err == 0) {
97200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        /* pause for a bit to let the input buffer drain any unmatched OK's
97300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project           (they will appear as extraneous unsolicited responses) */
97400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
97500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        sleepMsec(HANDSHAKE_TIMEOUT_MSEC);
97600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
97700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
97800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    pthread_mutex_unlock(&s_commandmutex);
97900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
98000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return err;
98100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
98200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
98300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project/**
98400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * Returns error code from response
98500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project * Assumes AT+CMEE=1 (numeric) mode
98600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project */
98700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source ProjectAT_CME_Error at_get_cme_error(const ATResponse *p_response)
98800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project{
98900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    int ret;
99000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    int err;
99100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    char *p_cur;
99200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
99300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (p_response->success > 0) {
99400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return CME_SUCCESS;
99500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
99600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
99700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (p_response->finalResponse == NULL
99800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        || !strStartsWith(p_response->finalResponse, "+CME ERROR:")
99900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    ) {
100000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return CME_ERROR_NON_CME;
100100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
100200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
100300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    p_cur = p_response->finalResponse;
100400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    err = at_tok_start(&p_cur);
100500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
100600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (err < 0) {
100700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return CME_ERROR_NON_CME;
100800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
100900f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
101000f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    err = at_tok_nextint(&p_cur, &ret);
101100f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
101200f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    if (err < 0) {
101300f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project        return CME_ERROR_NON_CME;
101400f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    }
101500f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
101600f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project    return (AT_CME_Error) ret;
101700f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project}
101800f06fc3fdb05d4276e76091cacb42b6f6862222The Android Open Source Project
1019