blob: f959a59d6e51affb6daea49a92cf8ce106e6505f [file] [log] [blame]
b.liu87afc4c2024-08-14 17:33:45 +08001/* //device/system/reference-ril/atchannel.c
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "atchannel.h"
19#include "at_tok.h"
20
21#include <stdio.h>
22#include <string.h>
23#include <pthread.h>
24#include <ctype.h>
25#include <stdlib.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <sys/time.h>
29#include <time.h>
30#include <unistd.h>
31
32#include "mbtk_log.h"
33#include "mbtk_type.h"
34#include "mbtk_utils.h"
35
36#define MAX_AT_RESPONSE (8 * 1024)
37#define HANDSHAKE_RETRY_COUNT 20
38#define HANDSHAKE_TIMEOUT_MSEC 500
b.liu15f456b2024-10-31 20:16:06 +080039#define AT_BUFF_MAX 1024
b.liu87afc4c2024-08-14 17:33:45 +080040
b.liub171c9a2024-11-12 19:23:29 +080041static pthread_t s_tid_reader[ATPORTTYPE_NUM];
42static int s_at_fd[ATPORTTYPE_NUM] = {-1}; /* fd of the AT channel */
b.liu87afc4c2024-08-14 17:33:45 +080043static int s_uart_fd = -1; /* fd of the UART channel */
44
45static ATUnsolHandler s_unsolHandler;
46
47/* for input buffering */
48
b.liub171c9a2024-11-12 19:23:29 +080049static char s_ATBuffer[ATPORTTYPE_NUM][MAX_AT_RESPONSE+1];
50static char *s_ATBufferCur[ATPORTTYPE_NUM] = {s_ATBuffer[ATPORTTYPE_0], s_ATBuffer[ATPORTTYPE_1], s_ATBuffer[ATPORTTYPE_2]};
b.liu87afc4c2024-08-14 17:33:45 +080051static char s_UartBuffer[MAX_AT_RESPONSE+1];
52static char *s_UartBufferCur = s_UartBuffer;
53
b.liub171c9a2024-11-12 19:23:29 +080054static mbtk_ril_at_state_enum at_state[ATPORTTYPE_NUM] = {RIL_AT_STATE_CLOSED};
b.liu87afc4c2024-08-14 17:33:45 +080055
56#if AT_DEBUG
57void AT_DUMP(const char* prefix, const char* buff, int len)
58{
59 if (len < 0)
60 len = strlen(buff);
61 LOGD("%.*s", len, buff);
62}
63#endif
64
65/*
66 * There is one reader thread |s_tid_reader| and potentially multiple writer
67 * threads. |s_commandmutex| and |s_commandcond| are used to maintain the
68 * condition that the writer thread will not read from |sp_response| until the
69 * reader thread has signaled itself is finished, etc. |s_writeMutex| is used to
70 * prevent multiple writer threads from calling at_send_command_full_nolock
71 * function at the same time.
72 */
73
74// "Wait" when AT process...
b.liub171c9a2024-11-12 19:23:29 +080075static pthread_mutex_t s_commandmutex[ATPORTTYPE_NUM] = {PTHREAD_MUTEX_INITIALIZER};
76static pthread_cond_t s_commandcond[ATPORTTYPE_NUM] = {PTHREAD_COND_INITIALIZER};
b.liu87afc4c2024-08-14 17:33:45 +080077
b.liub171c9a2024-11-12 19:23:29 +080078static ATCommandType s_type[ATPORTTYPE_NUM];
79static const char *s_responsePrefix[ATPORTTYPE_NUM] = {NULL};
80static const char *s_smsPDU[ATPORTTYPE_NUM] = {NULL};
81static ATResponse *sp_response[ATPORTTYPE_NUM] = {NULL};
82static char s_curr_at[ATPORTTYPE_NUM][AT_BUFF_MAX];
b.liu87afc4c2024-08-14 17:33:45 +080083
84static void (*s_onTimeout)(void) = NULL;
85static void (*s_onReaderClosed)(void) = NULL;
86static int s_readerClosed;
87
b.liub171c9a2024-11-12 19:23:29 +080088static void onReaderClosed(ATPortType_enum port);
89static int writeCtrlZ (ATPortType_enum port, const char *s);
90static int writeline (ATPortType_enum port, const char *s);
b.liu87afc4c2024-08-14 17:33:45 +080091
92typedef struct
93{
94 char *at_command;
95 long long timeout; // ms
96 bool timeout_close; // Close AT or not while AT response timeout.
97} at_timeout_t;
98
99static at_timeout_t at_timeout_list[] =
100{
101 {"AT+CRSM", 10000, false},
102// {"AT+COPS", 60000, false}
103};
104
105#define NS_PER_S 1000000000
106static void setTimespecRelative(struct timespec *p_ts, long long msec)
107{
108 struct timeval tv;
109
110 gettimeofday(&tv, (struct timezone *) NULL);
111
112 p_ts->tv_sec = tv.tv_sec + (msec / 1000);
113 p_ts->tv_nsec = (tv.tv_usec + (msec % 1000) * 1000L ) * 1000L;
114 /* assuming tv.tv_usec < 10^6 */
115 if (p_ts->tv_nsec >= NS_PER_S)
116 {
117 p_ts->tv_sec++;
118 p_ts->tv_nsec -= NS_PER_S;
119 }
120}
121
122static void sleepMsec(long long msec)
123{
124 struct timespec ts;
125 int err;
126
127 ts.tv_sec = (msec / 1000);
128 ts.tv_nsec = (msec % 1000) * 1000 * 1000;
129
130 do
131 {
132 err = nanosleep (&ts, &ts);
133 }
134 while (err < 0 && errno == EINTR);
135}
136
137
138
139/** add an intermediate response to sp_response*/
b.liub171c9a2024-11-12 19:23:29 +0800140static void addIntermediate(ATPortType_enum port, const char *line)
b.liu87afc4c2024-08-14 17:33:45 +0800141{
142 ATLine *p_new;
143
144 p_new = (ATLine *) malloc(sizeof(ATLine));
145
146 p_new->line = strdup(line);
147
148// LOGD("line:%s", line);
149// LOGD("line-1:%s", p_new->line);
150
151 /* note: this adds to the head of the list, so the list
152 will be in reverse order of lines received. the order is flipped
153 again before passing on to the command issuer */
b.liub171c9a2024-11-12 19:23:29 +0800154 p_new->p_next = sp_response[port]->p_intermediates;
155 sp_response[port]->p_intermediates = p_new;
b.liu87afc4c2024-08-14 17:33:45 +0800156}
157
158
159/**
160 * returns 1 if line is a final response indicating error
161 * See 27.007 annex B
162 * WARNING: NO CARRIER and others are sometimes unsolicited
163 */
164static const char * s_finalResponsesError[] =
165{
166 "ERROR",
167 "+CMS ERROR:",
168 "+CME ERROR:",
169// "NO CARRIER", /* sometimes! */ // Only for ATD ?
170 "NO ANSWER",
171 "NO DIALTONE",
172};
b.liub171c9a2024-11-12 19:23:29 +0800173static int isFinalResponseError(ATPortType_enum port, const char *line)
b.liu87afc4c2024-08-14 17:33:45 +0800174{
175 size_t i;
176
177 for (i = 0 ; i < ARRAY_SIZE(s_finalResponsesError) ; i++)
178 {
179 if (strStartsWith(line, s_finalResponsesError[i]))
180 {
181 return 1;
182 }
183 }
184
b.liub171c9a2024-11-12 19:23:29 +0800185 if(!strncasecmp(s_curr_at[port], "ATD", 3) && strStartsWith(line, "NO CARRIER"))
b.liu87afc4c2024-08-14 17:33:45 +0800186 {
187 return 1;
188 }
189
190 return 0;
191}
192
193/**
194 * returns 1 if line is a final response indicating success
195 * See 27.007 annex B
196 * WARNING: NO CARRIER and others are sometimes unsolicited
197 */
198static const char * s_finalResponsesSuccess[] =
199{
200 "OK",
201// "CONNECT" /* some stacks start up data on another channel */
202};
203static int isFinalResponseSuccess(const char *line)
204{
205 size_t i;
206
207 for (i = 0 ; i < ARRAY_SIZE(s_finalResponsesSuccess) ; i++)
208 {
209 if (strStartsWith(line, s_finalResponsesSuccess[i]))
210 {
211 return 1;
212 }
213 }
214
215 return 0;
216}
217
218/**
219 * returns 1 if line is a final response, either error or success
220 * See 27.007 annex B
221 * WARNING: NO CARRIER and others are sometimes unsolicited
222 */
b.liub171c9a2024-11-12 19:23:29 +0800223static int isFinalResponse(ATPortType_enum port, const char *line)
b.liu87afc4c2024-08-14 17:33:45 +0800224{
b.liub171c9a2024-11-12 19:23:29 +0800225 return isFinalResponseSuccess(line) || isFinalResponseError(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800226}
227
228/**
229 * returns 1 if line is the first line in (what will be) a two-line
230 * SMS unsolicited response
231 */
232static const char * s_smsUnsoliciteds[] =
233{
234 "+CMT:",
235 "+CDS:",
236 "+CBM:"
237};
238static int isSMSUnsolicited(const char *line)
239{
240 size_t i;
241
242 for (i = 0 ; i < ARRAY_SIZE(s_smsUnsoliciteds) ; i++)
243 {
244 if (strStartsWith(line, s_smsUnsoliciteds[i]))
245 {
246 return 1;
247 }
248 }
249
250 return 0;
251}
252
253
254/** assumes s_commandmutex is held */
b.liub171c9a2024-11-12 19:23:29 +0800255static void handleFinalResponse(ATPortType_enum port, const char *line)
b.liu87afc4c2024-08-14 17:33:45 +0800256{
b.liub171c9a2024-11-12 19:23:29 +0800257 sp_response[port]->finalResponse = strdup(line);
b.liu87afc4c2024-08-14 17:33:45 +0800258
259 //LOGD("AT complete (pthread_cond_signal): %s",line);
b.liub171c9a2024-11-12 19:23:29 +0800260 pthread_cond_signal(&s_commandcond[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800261}
262
263static void handleUnsolicited(const char *line)
264{
265 if (s_unsolHandler != NULL)
266 {
267 s_unsolHandler(line, NULL);
268 }
269}
270
b.liub171c9a2024-11-12 19:23:29 +0800271static void processLine(ATPortType_enum port, const char *line)
b.liu87afc4c2024-08-14 17:33:45 +0800272{
b.liub171c9a2024-11-12 19:23:29 +0800273 pthread_mutex_lock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800274// LOGD("LINE : %s", line);
b.liub171c9a2024-11-12 19:23:29 +0800275 if (sp_response[port] == NULL)
b.liu87afc4c2024-08-14 17:33:45 +0800276 {
277 /* no command pending */
278 handleUnsolicited(line);
279 }
280 else if (isFinalResponseSuccess(line))
281 {
b.liub171c9a2024-11-12 19:23:29 +0800282 sp_response[port]->success = 1;
283 handleFinalResponse(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800284 }
b.liub171c9a2024-11-12 19:23:29 +0800285 else if (isFinalResponseError(port, line))
b.liu87afc4c2024-08-14 17:33:45 +0800286 {
b.liub171c9a2024-11-12 19:23:29 +0800287 sp_response[port]->success = 0;
288 handleFinalResponse(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800289 }
b.liub171c9a2024-11-12 19:23:29 +0800290 else if (s_smsPDU[port] != NULL && 0 == strcmp(line, "> "))
b.liu87afc4c2024-08-14 17:33:45 +0800291 {
292 // See eg. TS 27.005 4.3
293 // Commands like AT+CMGS have a "> " prompt
b.liub171c9a2024-11-12 19:23:29 +0800294 writeCtrlZ(port, s_smsPDU[port]);
295 s_smsPDU[port] = NULL;
b.liu87afc4c2024-08-14 17:33:45 +0800296 }
b.liub171c9a2024-11-12 19:23:29 +0800297 else switch (s_type[port])
b.liu87afc4c2024-08-14 17:33:45 +0800298 {
299 case NO_RESULT:
300 handleUnsolicited(line);
301 break;
302 case NUMERIC:
b.liub171c9a2024-11-12 19:23:29 +0800303 if (sp_response[port]->p_intermediates == NULL
b.liu87afc4c2024-08-14 17:33:45 +0800304 && isdigit(line[0])
305 )
306 {
b.liub171c9a2024-11-12 19:23:29 +0800307 addIntermediate(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800308 }
309 else
310 {
311 /* either we already have an intermediate response or
312 the line doesn't begin with a digit */
313 handleUnsolicited(line);
314 }
315 break;
316 case SINGLELINE:
b.liub171c9a2024-11-12 19:23:29 +0800317 if (sp_response[port]->p_intermediates == NULL
318 && strStartsWith (line, s_responsePrefix[port])
b.liu87afc4c2024-08-14 17:33:45 +0800319 )
320 {
321 if(*line == '"')
322 {
323 char *line_temp = strdup(line);
324 line_temp++;
325 if(strlen(line_temp) > 0)
326 {
327 char *ptr = line_temp + strlen(line_temp) - 1;
328 while(ptr >= line_temp && *ptr == '"')
329 {
330 *ptr = '\0';
331 ptr--;
332 }
333 }
b.liub171c9a2024-11-12 19:23:29 +0800334 addIntermediate(port, line_temp);
b.liu87afc4c2024-08-14 17:33:45 +0800335 free(line_temp);
336 }
337 else
338 {
b.liub171c9a2024-11-12 19:23:29 +0800339 addIntermediate(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800340 }
341 }
342 else
343 {
344 /* we already have an intermediate response */
345 handleUnsolicited(line);
346 }
347 break;
348 case MULTILINE:
b.liub171c9a2024-11-12 19:23:29 +0800349 if (strStartsWith (line, s_responsePrefix[port]))
b.liu87afc4c2024-08-14 17:33:45 +0800350 {
b.liub171c9a2024-11-12 19:23:29 +0800351 addIntermediate(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800352 }
353 else
354 {
355 handleUnsolicited(line);
356 }
357 break;
358
359 default: /* this should never be reached */
b.liub171c9a2024-11-12 19:23:29 +0800360 LOGE("Unsupported AT command type %d\n", s_type[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800361 handleUnsolicited(line);
362 break;
363 }
364
b.liub171c9a2024-11-12 19:23:29 +0800365 pthread_mutex_unlock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800366}
367
368
369/**
370 * Returns a pointer to the end of the next line
371 * special-cases the "> " SMS prompt
372 *
373 * returns NULL if there is no complete line
374 */
375static char * findNextEOL(char *cur)
376{
377 if (cur[0] == '>' && cur[1] == ' ' && cur[2] == '\0')
378 {
379 /* SMS prompt character...not \r terminated */
380 return cur+2;
381 }
382
383 // Find next newline
384 while (*cur != '\0' && *cur != '\r' && *cur != '\n') cur++;
385
386 return *cur == '\0' ? NULL : cur;
387}
388
389
390/**
391 * Reads a line from the AT channel, returns NULL on timeout.
392 * Assumes it has exclusive read access to the FD
393 *
394 * This line is valid only until the next call to readline
395 *
396 * This function exists because as of writing, android libc does not
397 * have buffered stdio.
398 */
399
b.liub171c9a2024-11-12 19:23:29 +0800400static const char *readline(ATPortType_enum port)
b.liu87afc4c2024-08-14 17:33:45 +0800401{
402 ssize_t count;
403
404 char *p_read = NULL;
405 char *p_eol = NULL;
406 char *ret;
407
408 /* this is a little odd. I use *s_ATBufferCur == 0 to
409 * mean "buffer consumed completely". If it points to a character, than
410 * the buffer continues until a \0
411 */
b.liub171c9a2024-11-12 19:23:29 +0800412 if (*s_ATBufferCur[port] == '\0')
b.liu87afc4c2024-08-14 17:33:45 +0800413 {
414 /* empty buffer */
b.liub171c9a2024-11-12 19:23:29 +0800415 s_ATBufferCur[port] = s_ATBuffer[port];
416 *s_ATBufferCur[port] = '\0';
417 p_read = s_ATBuffer[port];
b.liu87afc4c2024-08-14 17:33:45 +0800418 }
419 else /* *s_ATBufferCur != '\0' */
420 {
421 /* there's data in the buffer from the last read */
422
423 // skip over leading newlines
b.liub171c9a2024-11-12 19:23:29 +0800424 while (*s_ATBufferCur[port] == '\r' || *s_ATBufferCur[port] == '\n')
425 s_ATBufferCur[port]++;
b.liu87afc4c2024-08-14 17:33:45 +0800426
b.liub171c9a2024-11-12 19:23:29 +0800427 p_eol = findNextEOL(s_ATBufferCur[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800428
429 if (p_eol == NULL)
430 {
431 /* a partial line. move it up and prepare to read more */
432 size_t len;
433
b.liub171c9a2024-11-12 19:23:29 +0800434 len = strlen(s_ATBufferCur[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800435
b.liub171c9a2024-11-12 19:23:29 +0800436 memmove(s_ATBuffer[port], s_ATBufferCur[port], len + 1);
437 p_read = s_ATBuffer[port] + len;
438 s_ATBufferCur[port] = s_ATBuffer[port];
b.liu87afc4c2024-08-14 17:33:45 +0800439 }
440 /* Otherwise, (p_eol !- NULL) there is a complete line */
441 /* that will be returned the while () loop below */
442 }
443
444 while (p_eol == NULL)
445 {
b.liub171c9a2024-11-12 19:23:29 +0800446 if (0 == MAX_AT_RESPONSE - (p_read - s_ATBuffer[port]))
b.liu87afc4c2024-08-14 17:33:45 +0800447 {
448 LOGE("ERROR: Input line exceeded buffer\n");
449 /* ditch buffer and start over again */
b.liub171c9a2024-11-12 19:23:29 +0800450 s_ATBufferCur[port] = s_ATBuffer[port];
451 *s_ATBufferCur[port] = '\0';
452 p_read = s_ATBuffer[port];
b.liu87afc4c2024-08-14 17:33:45 +0800453 }
454
455 do
456 {
b.liub171c9a2024-11-12 19:23:29 +0800457 count = read(s_at_fd[port], p_read,
458 MAX_AT_RESPONSE - (p_read - s_ATBuffer[port]));
b.liu87afc4c2024-08-14 17:33:45 +0800459 usleep(10000);
460 }
461 while (count < 0 && errno == EINTR);
462
463 if (count > 0)
464 {
465 AT_DUMP( "<< ", p_read, count );
466
467 p_read[count] = '\0';
468
469 // skip over leading newlines
b.liub171c9a2024-11-12 19:23:29 +0800470 while (*s_ATBufferCur[port] == '\r' || *s_ATBufferCur[port] == '\n')
471 s_ATBufferCur[port]++;
b.liu87afc4c2024-08-14 17:33:45 +0800472
b.liub171c9a2024-11-12 19:23:29 +0800473 p_eol = findNextEOL(s_ATBufferCur[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800474 p_read += count;
475 }
476 else if (count <= 0)
477 {
478 /* read error encountered or EOF reached */
479 if(count == 0)
480 {
b.liufd87baf2024-11-15 15:30:38 +0800481 LOGD("atchannel[Port-%d]: EOF reached", port);
b.liu87afc4c2024-08-14 17:33:45 +0800482 }
483 else
484 {
b.liufd87baf2024-11-15 15:30:38 +0800485 LOGD("atchannel[Port-%d]: read error %s", port, strerror(errno));
b.liu87afc4c2024-08-14 17:33:45 +0800486 }
487 return NULL;
488 }
489 }
490
491 /* a full line in the buffer. Place a \0 over the \r and return */
492
b.liub171c9a2024-11-12 19:23:29 +0800493 ret = s_ATBufferCur[port];
b.liu87afc4c2024-08-14 17:33:45 +0800494 *p_eol = '\0';
b.liub171c9a2024-11-12 19:23:29 +0800495 s_ATBufferCur[port] = p_eol + 1; /* this will always be <= p_read, */
b.liu87afc4c2024-08-14 17:33:45 +0800496 /* and there will be a \0 at *p_read */
497
b.liufd87baf2024-11-15 15:30:38 +0800498 LOGD("[Port-%d]AT< %s", port, ret);
b.liu87afc4c2024-08-14 17:33:45 +0800499 return ret;
500}
501
b.liufd87baf2024-11-15 15:30:38 +0800502static const char *readlineUrc(ATPortType_enum port)
b.liu87afc4c2024-08-14 17:33:45 +0800503{
504 ssize_t count;
505
506 char *p_read = NULL;
507 char *p_eol = NULL;
508 char *ret;
509
510 /* this is a little odd. I use *s_ATBufferCur == 0 to
511 * mean "buffer consumed completely". If it points to a character, than
512 * the buffer continues until a \0
513 */
514 if (*s_UartBufferCur == '\0')
515 {
516 /* empty buffer */
517 s_UartBufferCur = s_UartBuffer;
518 *s_UartBufferCur = '\0';
519 p_read = s_UartBuffer;
520 }
521 else /* *s_ATBufferCur != '\0' */
522 {
523 /* there's data in the buffer from the last read */
524
525 // skip over leading newlines
526 while (*s_UartBufferCur == '\r' || *s_UartBufferCur == '\n')
527 s_UartBufferCur++;
528
529 p_eol = findNextEOL(s_UartBufferCur);
530
531 if (p_eol == NULL)
532 {
533 /* a partial line. move it up and prepare to read more */
534 size_t len;
535
536 len = strlen(s_UartBufferCur);
537
538 memmove(s_UartBuffer, s_UartBufferCur, len + 1);
539 p_read = s_UartBuffer + len;
540 s_UartBufferCur = s_UartBuffer;
541 }
542 /* Otherwise, (p_eol !- NULL) there is a complete line */
543 /* that will be returned the while () loop below */
544 }
545
546 while (p_eol == NULL)
547 {
548 if (0 == MAX_AT_RESPONSE - (p_read - s_UartBuffer))
549 {
550 LOGE("ERROR: Input line exceeded buffer\n");
551 /* ditch buffer and start over again */
552 s_UartBufferCur = s_UartBuffer;
553 *s_UartBufferCur = '\0';
554 p_read = s_UartBuffer;
555 }
556
557 do
558 {
559 count = read(s_uart_fd, p_read,
560 MAX_AT_RESPONSE - (p_read - s_UartBuffer));
561 usleep(10000);
562 }
563 while (count < 0 && errno == EINTR);
564
565 if (count > 0)
566 {
567 AT_DUMP( "<< ", p_read, count );
568
569 p_read[count] = '\0';
570
571 // skip over leading newlines
572 while (*s_UartBufferCur == '\r' || *s_UartBufferCur == '\n')
573 s_UartBufferCur++;
574
575 p_eol = findNextEOL(s_UartBufferCur);
576 p_read += count;
577 }
578 else if (count <= 0)
579 {
580 /* read error encountered or EOF reached */
581 if(count == 0)
582 {
583 LOGD("atchannel: EOF reached");
584 }
585 else
586 {
587 LOGD("atchannel: read error %s", strerror(errno));
588 }
589 return NULL;
590 }
591 }
592
593 /* a full line in the buffer. Place a \0 over the \r and return */
594
595 ret = s_UartBufferCur;
596 *p_eol = '\0';
597 s_UartBufferCur = p_eol + 1; /* this will always be <= p_read, */
598 /* and there will be a \0 at *p_read */
599
b.liufd87baf2024-11-15 15:30:38 +0800600 LOGD("[Port-%d]URC< %s", port, ret);
b.liu87afc4c2024-08-14 17:33:45 +0800601 return ret;
602}
603
604
605
b.liub171c9a2024-11-12 19:23:29 +0800606static void onReaderClosed(ATPortType_enum port)
b.liu87afc4c2024-08-14 17:33:45 +0800607{
608 LOGD("onReaderClosed()");
609 if (s_onReaderClosed != NULL && s_readerClosed == 0)
610 {
611
b.liub171c9a2024-11-12 19:23:29 +0800612 pthread_mutex_lock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800613
614 s_readerClosed = 1;
615
b.liub171c9a2024-11-12 19:23:29 +0800616 pthread_cond_signal(&s_commandcond[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800617
b.liub171c9a2024-11-12 19:23:29 +0800618 pthread_mutex_unlock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800619
620 s_onReaderClosed();
621 }
622}
623
b.liu06559f62024-11-01 18:48:22 +0800624typedef struct
625{
626 int cid;
627 bool act;
628 bool waitting;
629} info_cgact_wait_t;
630extern info_cgact_wait_t cgact_wait;
631
b.liu87afc4c2024-08-14 17:33:45 +0800632static void *readerLoop(void *arg)
633{
634 UNUSED(arg);
b.liub171c9a2024-11-12 19:23:29 +0800635 ATPortType_enum *port = (ATPortType_enum*)arg;
b.liu87afc4c2024-08-14 17:33:45 +0800636 for (;;)
637 {
638 const char * line;
639
b.liub171c9a2024-11-12 19:23:29 +0800640 line = readline(*port);
b.liu87afc4c2024-08-14 17:33:45 +0800641
642 if (line == NULL)
643 {
b.liufd87baf2024-11-15 15:30:38 +0800644 //usleep(50000);
645 //continue;
b.liu87afc4c2024-08-14 17:33:45 +0800646 break;
647 }
648
649 if(strStartsWith(line, "MBTK_AT_READY")) {
650 //handleUnsolicited(line);
651 continue;
b.liu06559f62024-11-01 18:48:22 +0800652 } else if(strStartsWith(line, "CONNECT")) {
653 if(cgact_wait.waitting && cgact_wait.act) {
654 cgact_wait.waitting = false;
655 }
b.liu87afc4c2024-08-14 17:33:45 +0800656 }
657
658 if(isSMSUnsolicited(line))
659 {
660 char *line1;
661 const char *line2;
662
663 // The scope of string returned by 'readline()' is valid only
664 // till next call to 'readline()' hence making a copy of line
665 // before calling readline again.
666 line1 = strdup(line);
b.liub171c9a2024-11-12 19:23:29 +0800667 line2 = readline(*port);
b.liu87afc4c2024-08-14 17:33:45 +0800668
669 if (line2 == NULL)
670 {
671 free(line1);
672 break;
673 }
674
675 if (s_unsolHandler != NULL)
676 {
677 s_unsolHandler (line1, line2);
678 }
679 free(line1);
680 }
681 else
682 {
b.liub171c9a2024-11-12 19:23:29 +0800683 processLine(*port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800684 }
685 }
686
b.liub171c9a2024-11-12 19:23:29 +0800687 onReaderClosed(*port);
688
689 free(port);
b.liu87afc4c2024-08-14 17:33:45 +0800690
691 return NULL;
692}
693
694static void *readerUrcLoop(void *arg)
695{
696 UNUSED(arg);
b.liub171c9a2024-11-12 19:23:29 +0800697 ATPortType_enum *port = (ATPortType_enum*)arg;
b.liu87afc4c2024-08-14 17:33:45 +0800698 for (;;)
699 {
700 const char *line;
701
b.liufd87baf2024-11-15 15:30:38 +0800702 line = readlineUrc(*port);
b.liu87afc4c2024-08-14 17:33:45 +0800703
704 if (line == NULL)
705 {
706 break;
707 }
708
709 handleUnsolicited(line);
710 }
711
b.liub171c9a2024-11-12 19:23:29 +0800712 onReaderClosed(*port);
713
714 free(port);
b.liu87afc4c2024-08-14 17:33:45 +0800715
716 return NULL;
717}
718
719
720/**
721 * Sends string s to the radio with a \r appended.
722 * Returns AT_ERROR_* on error, 0 on success
723 *
724 * This function exists because as of writing, android libc does not
725 * have buffered stdio.
726 */
b.liub171c9a2024-11-12 19:23:29 +0800727static int writeline (ATPortType_enum port, const char *s)
b.liu87afc4c2024-08-14 17:33:45 +0800728{
729 size_t cur = 0;
730 size_t len = strlen(s);
731 ssize_t written;
732
b.liub171c9a2024-11-12 19:23:29 +0800733 if (s_at_fd[port] < 0 || s_readerClosed > 0)
b.liu87afc4c2024-08-14 17:33:45 +0800734 {
735 return AT_ERROR_CHANNEL_CLOSED;
736 }
737
b.liufd87baf2024-11-15 15:30:38 +0800738 LOGD("[Port-%d]AT> %s", port, s);
b.liu87afc4c2024-08-14 17:33:45 +0800739
740 AT_DUMP( ">> ", s, strlen(s) );
741
b.liub171c9a2024-11-12 19:23:29 +0800742 memset(s_curr_at[port], 0x0, AT_BUFF_MAX);
743 memcpy(s_curr_at[port], s, strlen(s));
b.liu87afc4c2024-08-14 17:33:45 +0800744
745 /* the main string */
746 while (cur < len)
747 {
748 do
749 {
b.liub171c9a2024-11-12 19:23:29 +0800750 written = write (s_at_fd[port], s + cur, len - cur);
b.liu87afc4c2024-08-14 17:33:45 +0800751 }
752 while (written < 0 && errno == EINTR);
753
754 if (written < 0)
755 {
756 return AT_ERROR_GENERIC;
757 }
758
759 cur += written;
760 }
761
762 /* the \r */
763
764 do
765 {
b.liub171c9a2024-11-12 19:23:29 +0800766 written = write (s_at_fd[port], "\r", 1);
b.liu87afc4c2024-08-14 17:33:45 +0800767 }
768 while ((written < 0 && errno == EINTR) || (written == 0));
769
770 if (written < 0)
771 {
772 return AT_ERROR_GENERIC;
773 }
774
775 return 0;
776}
777
b.liub171c9a2024-11-12 19:23:29 +0800778static int writeCtrlZ (ATPortType_enum port, const char *s)
b.liu87afc4c2024-08-14 17:33:45 +0800779{
780 size_t cur = 0;
781 size_t len = strlen(s);
782 ssize_t written;
783
b.liub171c9a2024-11-12 19:23:29 +0800784 if (s_at_fd[port] < 0 || s_readerClosed > 0)
b.liu87afc4c2024-08-14 17:33:45 +0800785 {
786 return AT_ERROR_CHANNEL_CLOSED;
787 }
788
789 LOGD("AT> %s^Z\n", s);
790
791 AT_DUMP( ">* ", s, strlen(s) );
792
793 /* the main string */
794 while (cur < len)
795 {
796 do
797 {
b.liub171c9a2024-11-12 19:23:29 +0800798 written = write (s_at_fd[port], s + cur, len - cur);
b.liu87afc4c2024-08-14 17:33:45 +0800799 }
800 while (written < 0 && errno == EINTR);
801
802 if (written < 0)
803 {
804 return AT_ERROR_GENERIC;
805 }
806
807 cur += written;
808 }
809
810 /* the ^Z */
811
812 do
813 {
b.liub171c9a2024-11-12 19:23:29 +0800814 written = write (s_at_fd[port], "\032", 1);
b.liu87afc4c2024-08-14 17:33:45 +0800815 }
816 while ((written < 0 && errno == EINTR) || (written == 0));
817
818 if (written < 0)
819 {
820 return AT_ERROR_GENERIC;
821 }
822
823 return 0;
824}
825
b.liub171c9a2024-11-12 19:23:29 +0800826static void clearPendingCommand(ATPortType_enum port)
b.liu87afc4c2024-08-14 17:33:45 +0800827{
b.liub171c9a2024-11-12 19:23:29 +0800828 if (sp_response[port] != NULL)
b.liu87afc4c2024-08-14 17:33:45 +0800829 {
b.liub171c9a2024-11-12 19:23:29 +0800830 at_response_free(sp_response[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800831 }
832
b.liub171c9a2024-11-12 19:23:29 +0800833 sp_response[port] = NULL;
834 s_responsePrefix[port] = NULL;
835 s_smsPDU[port] = NULL;
b.liu87afc4c2024-08-14 17:33:45 +0800836}
837
838
839/**
840 * Starts AT handler on stream "fd'
841 * returns 0 on success, -1 on error
842 */
b.liub171c9a2024-11-12 19:23:29 +0800843int at_open(ATPortType_enum port, int at_fd, int uart_fd, ATUnsolHandler h)
b.liu87afc4c2024-08-14 17:33:45 +0800844{
845 int ret;
846 pthread_attr_t attr;
847
b.liub171c9a2024-11-12 19:23:29 +0800848 s_at_fd[port] = at_fd;
b.liu87afc4c2024-08-14 17:33:45 +0800849 s_uart_fd = uart_fd;
850 s_unsolHandler = h;
851 s_readerClosed = 0;
b.liub171c9a2024-11-12 19:23:29 +0800852 s_responsePrefix[port] = NULL;
853 s_smsPDU[port] = NULL;
854 sp_response[port] = NULL;
855
856 ATPortType_enum *at_port_ptr = (ATPortType_enum*)malloc(sizeof(ATPortType_enum));
857 ATPortType_enum *urc_port_ptr = (ATPortType_enum*)malloc(sizeof(ATPortType_enum));
858 *at_port_ptr = port;
859 *urc_port_ptr = port;
b.liu87afc4c2024-08-14 17:33:45 +0800860
861 pthread_attr_init (&attr);
862 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
b.liub171c9a2024-11-12 19:23:29 +0800863 ret = pthread_create(&s_tid_reader[port], &attr, readerLoop, at_port_ptr);
b.liu87afc4c2024-08-14 17:33:45 +0800864 if (ret < 0)
865 {
866 LOGE("AT thread create fail.");
867 return -1;
868 }
869
b.liufd87baf2024-11-15 15:30:38 +0800870 if(port == ATPORTTYPE_0) { // URC only for ATPORTTYPE_0
871 pthread_t uart_tid_reader;
872 ret = pthread_create(&uart_tid_reader, &attr, readerUrcLoop, urc_port_ptr);
873 if (ret < 0)
874 {
875 LOGE("Uart thread create fail.");
876 return -1;
877 }
b.liu87afc4c2024-08-14 17:33:45 +0800878 }
879
880 return 0;
881}
882
883/* FIXME is it ok to call this from the reader and the command thread? */
b.liub171c9a2024-11-12 19:23:29 +0800884void at_close(ATPortType_enum port)
b.liu87afc4c2024-08-14 17:33:45 +0800885{
886 LOGD("at_close()");
b.liub171c9a2024-11-12 19:23:29 +0800887 if (s_at_fd[port] >= 0)
b.liu87afc4c2024-08-14 17:33:45 +0800888 {
b.liub171c9a2024-11-12 19:23:29 +0800889 close(s_at_fd[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800890 }
891 if (s_uart_fd >= 0)
892 {
893 close(s_uart_fd);
894 }
b.liub171c9a2024-11-12 19:23:29 +0800895 s_at_fd[port] = -1;
b.liu87afc4c2024-08-14 17:33:45 +0800896 s_uart_fd = -1;
897
b.liub171c9a2024-11-12 19:23:29 +0800898 pthread_mutex_lock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800899 s_readerClosed = 1;
b.liub171c9a2024-11-12 19:23:29 +0800900 pthread_cond_signal(&s_commandcond[port]);
901 pthread_mutex_unlock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800902 /* the reader thread should eventually die */
903
b.liub171c9a2024-11-12 19:23:29 +0800904 at_state[port] = RIL_AT_STATE_CLOSED;
b.liu87afc4c2024-08-14 17:33:45 +0800905}
906
907static ATResponse * at_response_new()
908{
909 return (ATResponse *) calloc(1, sizeof(ATResponse));
910}
911
912void at_response_free(ATResponse *p_response)
913{
914 ATLine *p_line;
915
916 if (p_response == NULL) return;
917
918 p_line = p_response->p_intermediates;
919
920 while (p_line != NULL)
921 {
922 ATLine *p_toFree;
923
924 p_toFree = p_line;
925 p_line = p_line->p_next;
926
927 free(p_toFree->line);
928 free(p_toFree);
929 }
930
931 free (p_response->finalResponse);
932 free (p_response);
933}
934
935/**
936 * The line reader places the intermediate responses in reverse order
937 * here we flip them back
938 */
939static void reverseIntermediates(ATResponse *p_response)
940{
941 ATLine *pcur,*pnext;
942
943 pcur = p_response->p_intermediates;
944 p_response->p_intermediates = NULL;
945
946 while (pcur != NULL)
947 {
948 pnext = pcur->p_next;
949 pcur->p_next = p_response->p_intermediates;
950 p_response->p_intermediates = pcur;
951 pcur = pnext;
952 }
953}
954
955static long long at_timeout_get(const char *at_command, bool *timeout_close)
956{
957 long long timeout = 0;
958 int i;
959 for(i = 0; i < ARRAY_SIZE(at_timeout_list); i++)
960 {
961 if(!strncasecmp(at_command, at_timeout_list[i].at_command, strlen(at_timeout_list[i].at_command)))
962 {
963 timeout = at_timeout_list[i].timeout;
964 *timeout_close = at_timeout_list[i].timeout_close;
965 break;
966 }
967 }
968
969 return timeout;
970}
971
972/**
973 * Internal send_command implementation
974 * Doesn't lock or call the timeout callback
975 *
976 * timeoutMsec == 0 means infinite timeout
977 */
b.liub171c9a2024-11-12 19:23:29 +0800978static int at_send_command_full_nolock (ATPortType_enum port, const char *command, ATCommandType type,
b.liu87afc4c2024-08-14 17:33:45 +0800979 const char *responsePrefix, const char *smspdu,
980 long long timeoutMsec, ATResponse **pp_outResponse)
981{
982 int err = 0;
983 bool tiemout_close = true;
984 struct timespec ts;
b.liub171c9a2024-11-12 19:23:29 +0800985 if(at_state[port] == RIL_AT_STATE_READY)
986 at_state[port] = RIL_AT_STATE_BUSY;
b.liu87afc4c2024-08-14 17:33:45 +0800987
b.liub171c9a2024-11-12 19:23:29 +0800988 if(sp_response[port] != NULL)
b.liu87afc4c2024-08-14 17:33:45 +0800989 {
990 err = AT_ERROR_COMMAND_PENDING;
991 goto error;
992 }
993
b.liub171c9a2024-11-12 19:23:29 +0800994 err = writeline (port, command);
b.liu87afc4c2024-08-14 17:33:45 +0800995
996 if (err < 0)
997 {
998 goto error;
999 }
1000
b.liub171c9a2024-11-12 19:23:29 +08001001 s_type[port] = type;
1002 s_responsePrefix[port] = responsePrefix;
1003 s_smsPDU[port] = smspdu;
1004 sp_response[port] = at_response_new();
b.liu87afc4c2024-08-14 17:33:45 +08001005
1006 if(timeoutMsec == 0)
1007 {
1008 timeoutMsec = at_timeout_get(command, &tiemout_close);
1009 }
1010
1011 if (timeoutMsec != 0)
1012 {
1013 setTimespecRelative(&ts, timeoutMsec);
1014 }
1015
b.liub171c9a2024-11-12 19:23:29 +08001016 while (sp_response[port]->finalResponse == NULL && s_readerClosed == 0)
b.liu87afc4c2024-08-14 17:33:45 +08001017 {
1018 //LOGD("AT wait time:%lld",timeoutMsec);
1019 if (timeoutMsec != 0)
1020 {
b.liub171c9a2024-11-12 19:23:29 +08001021 err = pthread_cond_timedwait(&s_commandcond[port], &s_commandmutex[port], &ts);
b.liu87afc4c2024-08-14 17:33:45 +08001022 }
1023 else
1024 {
b.liub171c9a2024-11-12 19:23:29 +08001025 err = pthread_cond_wait(&s_commandcond[port], &s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001026 }
1027
1028 //LOGD("AT continue:err - %d",err);
1029 if (err == ETIMEDOUT)
1030 {
1031 if(tiemout_close)
1032 {
1033 err = AT_ERROR_TIMEOUT_CLOSE;
1034 }
1035 else
1036 {
1037 err = AT_ERROR_TIMEOUT;
1038 }
1039 goto error;
1040 }
1041 }
1042
1043 if (pp_outResponse == NULL)
1044 {
b.liub171c9a2024-11-12 19:23:29 +08001045 at_response_free(sp_response[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001046 }
1047 else
1048 {
1049 /* line reader stores intermediate responses in reverse order */
b.liub171c9a2024-11-12 19:23:29 +08001050 reverseIntermediates(sp_response[port]);
1051 *pp_outResponse = sp_response[port];
b.liu87afc4c2024-08-14 17:33:45 +08001052 }
1053
b.liub171c9a2024-11-12 19:23:29 +08001054 sp_response[port] = NULL;
b.liu87afc4c2024-08-14 17:33:45 +08001055
1056 if(s_readerClosed > 0)
1057 {
1058 err = AT_ERROR_CHANNEL_CLOSED;
1059 goto error;
1060 }
1061
1062 err = 0;
1063error:
b.liub171c9a2024-11-12 19:23:29 +08001064 if(at_state[port] == RIL_AT_STATE_BUSY)
1065 at_state[port] = RIL_AT_STATE_READY;
1066 clearPendingCommand(port);
b.liu87afc4c2024-08-14 17:33:45 +08001067
1068 return err;
1069}
1070
1071/**
1072 * Internal send_command implementation
1073 *
1074 * timeoutMsec == 0 means infinite timeout
1075 */
b.liub171c9a2024-11-12 19:23:29 +08001076static int at_send_command_full (ATPortType_enum port, const char *command, ATCommandType type,
b.liu87afc4c2024-08-14 17:33:45 +08001077 const char *responsePrefix, const char *smspdu,
1078 long long timeoutMsec, ATResponse **pp_outResponse)
1079{
1080 int err;
1081
b.liub171c9a2024-11-12 19:23:29 +08001082 if (0 != pthread_equal(s_tid_reader[port], pthread_self()))
b.liu87afc4c2024-08-14 17:33:45 +08001083 {
1084 /* cannot be called from reader thread */
1085 LOGE("cannot be called from reader thread.");
1086 return AT_ERROR_INVALID_THREAD;
1087 }
1088
1089 // Waitting for previous AT complete.
b.liub171c9a2024-11-12 19:23:29 +08001090 while(at_state[port] == RIL_AT_STATE_BUSY)
b.liu87afc4c2024-08-14 17:33:45 +08001091 {
1092 usleep(10000);
1093 }
1094
b.liub171c9a2024-11-12 19:23:29 +08001095 pthread_mutex_lock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001096
b.liub171c9a2024-11-12 19:23:29 +08001097 err = at_send_command_full_nolock(port, command, type,
b.liu87afc4c2024-08-14 17:33:45 +08001098 responsePrefix, smspdu,
1099 timeoutMsec, pp_outResponse);
1100
b.liub171c9a2024-11-12 19:23:29 +08001101 pthread_mutex_unlock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001102
1103 if (err == AT_ERROR_TIMEOUT_CLOSE && s_onTimeout != NULL)
1104 {
1105 s_onTimeout();
1106 }
1107
1108 return err;
1109}
1110
1111
1112/**
1113 * Issue a single normal AT command with no intermediate response expected
1114 *
1115 * "command" should not include \r
1116 * pp_outResponse can be NULL
1117 *
1118 * if non-NULL, the resulting ATResponse * must be eventually freed with
1119 * at_response_free
1120 */
b.liub171c9a2024-11-12 19:23:29 +08001121int at_send_command (ATPortType_enum port, const char *command, ATResponse **pp_outResponse)
b.liu87afc4c2024-08-14 17:33:45 +08001122{
b.liub171c9a2024-11-12 19:23:29 +08001123 return at_send_command_full (port, command, NO_RESULT, NULL,
b.liu87afc4c2024-08-14 17:33:45 +08001124 NULL, 0, pp_outResponse);
1125}
1126
1127
b.liub171c9a2024-11-12 19:23:29 +08001128int at_send_command_singleline (ATPortType_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001129 const char *responsePrefix,
1130 ATResponse **pp_outResponse)
1131{
1132 int err;
1133
b.liub171c9a2024-11-12 19:23:29 +08001134 err = at_send_command_full (port, command, SINGLELINE, responsePrefix,
b.liu87afc4c2024-08-14 17:33:45 +08001135 NULL, 0, pp_outResponse);
1136
1137 if (err == 0 && pp_outResponse != NULL
1138 && (*pp_outResponse)->success > 0
1139 && (*pp_outResponse)->p_intermediates == NULL
1140 )
1141 {
1142 /* successful command must have an intermediate response */
1143 at_response_free(*pp_outResponse);
1144 *pp_outResponse = NULL;
1145 return AT_ERROR_INVALID_RESPONSE;
1146 }
1147
1148 return err;
1149}
1150
b.liub171c9a2024-11-12 19:23:29 +08001151int at_send_command_singleline_with_timeout (ATPortType_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001152 const char *responsePrefix,
1153 ATResponse **pp_outResponse,long long timeoutMsec)
1154{
1155 int err;
1156
b.liub171c9a2024-11-12 19:23:29 +08001157 err = at_send_command_full (port, command, SINGLELINE, responsePrefix,
b.liu87afc4c2024-08-14 17:33:45 +08001158 NULL, timeoutMsec, pp_outResponse);
1159
1160 if (err == 0 && pp_outResponse != NULL
1161 && (*pp_outResponse)->success > 0
1162 && (*pp_outResponse)->p_intermediates == NULL
1163 )
1164 {
1165 /* successful command must have an intermediate response */
1166 at_response_free(*pp_outResponse);
1167 *pp_outResponse = NULL;
1168 return AT_ERROR_INVALID_RESPONSE;
1169 }
1170
1171 return err;
1172}
1173
1174
1175
b.liub171c9a2024-11-12 19:23:29 +08001176int at_send_command_numeric (ATPortType_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001177 ATResponse **pp_outResponse)
1178{
1179 int err;
1180
b.liub171c9a2024-11-12 19:23:29 +08001181 err = at_send_command_full (port, command, NUMERIC, NULL,
b.liu87afc4c2024-08-14 17:33:45 +08001182 NULL, 0, pp_outResponse);
1183
1184 if (err == 0 && pp_outResponse != NULL
1185 && (*pp_outResponse)->success > 0
1186 && (*pp_outResponse)->p_intermediates == NULL
1187 )
1188 {
1189 /* successful command must have an intermediate response */
1190 at_response_free(*pp_outResponse);
1191 *pp_outResponse = NULL;
1192 return AT_ERROR_INVALID_RESPONSE;
1193 }
1194
1195 return err;
1196}
1197
1198
b.liub171c9a2024-11-12 19:23:29 +08001199int at_send_command_sms (ATPortType_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001200 const char *pdu,
1201 const char *responsePrefix,
1202 ATResponse **pp_outResponse)
1203{
1204 int err;
1205
b.liub171c9a2024-11-12 19:23:29 +08001206 err = at_send_command_full (port, command, SINGLELINE, responsePrefix,
b.liu87afc4c2024-08-14 17:33:45 +08001207 pdu, 0, pp_outResponse);
1208
1209 if (err == 0 && pp_outResponse != NULL
1210 && (*pp_outResponse)->success > 0
1211 && (*pp_outResponse)->p_intermediates == NULL
1212 )
1213 {
1214 /* successful command must have an intermediate response */
1215 at_response_free(*pp_outResponse);
1216 *pp_outResponse = NULL;
1217 return AT_ERROR_INVALID_RESPONSE;
1218 }
1219
1220 return err;
1221}
1222
1223
b.liub171c9a2024-11-12 19:23:29 +08001224int at_send_command_multiline (ATPortType_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001225 const char *responsePrefix,
1226 ATResponse **pp_outResponse)
1227{
1228 int err;
1229
b.liub171c9a2024-11-12 19:23:29 +08001230 err = at_send_command_full (port, command, MULTILINE, responsePrefix,
b.liu87afc4c2024-08-14 17:33:45 +08001231 NULL, 0, pp_outResponse);
1232
1233 return err;
1234}
1235
1236
1237/** This callback is invoked on the command thread */
1238void at_set_on_timeout(void (*onTimeout)(void))
1239{
1240 s_onTimeout = onTimeout;
1241}
1242
1243/**
1244 * This callback is invoked on the reader thread (like ATUnsolHandler)
1245 * when the input stream closes before you call at_close
1246 * (not when you call at_close())
1247 * You should still call at_close()
1248 */
1249
1250void at_set_on_reader_closed(void (*onClose)(void))
1251{
1252 s_onReaderClosed = onClose;
1253}
1254
1255
1256/**
1257 * Periodically issue an AT command and wait for a response.
1258 * Used to ensure channel has start up and is active
1259 */
b.liub171c9a2024-11-12 19:23:29 +08001260int at_handshake(ATPortType_enum port)
b.liu87afc4c2024-08-14 17:33:45 +08001261{
b.liu62240ee2024-11-07 17:52:45 +08001262// int i;
b.liu87afc4c2024-08-14 17:33:45 +08001263 int err = 0;
1264
b.liub171c9a2024-11-12 19:23:29 +08001265 if (0 != pthread_equal(s_tid_reader[port], pthread_self()))
b.liu87afc4c2024-08-14 17:33:45 +08001266 {
1267 /* cannot be called from reader thread */
1268 return AT_ERROR_INVALID_THREAD;
1269 }
b.liub171c9a2024-11-12 19:23:29 +08001270 pthread_mutex_lock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001271
1272#if 0
1273 for (i = 0 ; i < HANDSHAKE_RETRY_COUNT ; i++)
1274 {
1275 /* some stacks start with verbose off */
1276 err = at_send_command_full_nolock("ATE0Q0V1", NO_RESULT,
1277 NULL, NULL, HANDSHAKE_TIMEOUT_MSEC, NULL);
1278
1279 if (err == 0)
1280 {
1281 break;
1282 }
1283 }
1284#else
b.liub171c9a2024-11-12 19:23:29 +08001285 err = at_send_command_full_nolock(port, "ATE0Q0V1", NO_RESULT,
b.liu87afc4c2024-08-14 17:33:45 +08001286 NULL, NULL, 0, NULL);
1287#endif
1288
1289 if (err == 0)
1290 {
1291 /* pause for a bit to let the input buffer drain any unmatched OK's
1292 (they will appear as extraneous unsolicited responses) */
1293 sleepMsec(HANDSHAKE_TIMEOUT_MSEC);
1294 }
1295
b.liub171c9a2024-11-12 19:23:29 +08001296 pthread_mutex_unlock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001297
1298
1299 return err;
1300}
1301
1302/**
1303 * Returns error code from response
1304 * Assumes AT+CMEE=1 (numeric) mode
1305 */
1306int at_get_cme_error(const ATResponse *p_response)
1307{
1308 int ret;
1309 int err;
1310 char *p_cur;
1311
1312 if (p_response->success > 0)
1313 {
1314 return CME_SUCCESS;
1315 }
1316
1317 if (p_response->finalResponse == NULL
1318 || !strStartsWith(p_response->finalResponse, "+CME ERROR:")
1319 )
1320 {
1321 return CME_ERROR_NON_CME;
1322 }
1323
1324 p_cur = p_response->finalResponse;
1325 err = at_tok_start(&p_cur);
1326
1327 if (err < 0)
1328 {
1329 return CME_ERROR_NON_CME;
1330 }
1331
1332 err = at_tok_nextint(&p_cur, &ret);
1333
1334 if (err < 0)
1335 {
1336 return CME_ERROR_NON_CME;
1337 }
1338
1339 return ret;
1340}
1341
b.liub171c9a2024-11-12 19:23:29 +08001342mbtk_ril_at_state_enum at_state_get(ATPortType_enum port)
b.liu87afc4c2024-08-14 17:33:45 +08001343{
b.liub171c9a2024-11-12 19:23:29 +08001344 return at_state[port];
b.liu87afc4c2024-08-14 17:33:45 +08001345}
1346
b.liub171c9a2024-11-12 19:23:29 +08001347void at_state_set(ATPortType_enum port, mbtk_ril_at_state_enum state)
b.liu87afc4c2024-08-14 17:33:45 +08001348{
b.liub171c9a2024-11-12 19:23:29 +08001349 at_state[port] = state;
b.liu87afc4c2024-08-14 17:33:45 +08001350}
1351
1352bool at_rsp_check(ATResponse *p_response)
1353{
1354 if(!p_response || !p_response->success)
1355 return false;
1356
1357 return true;
1358}
1359
b.liub171c9a2024-11-12 19:23:29 +08001360void unused_func(ATPortType_enum port)
b.liu87afc4c2024-08-14 17:33:45 +08001361{
b.liub171c9a2024-11-12 19:23:29 +08001362 isFinalResponse(port, NULL);
b.liu87afc4c2024-08-14 17:33:45 +08001363}
1364