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