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