blob: 8a19159b24ed633582fcd92766597f8dc90c57c1 [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 {
481 LOGD("atchannel: EOF reached");
482 }
483 else
484 {
485 LOGD("atchannel: read error %s", strerror(errno));
486 }
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
498 LOGD("AT< %s", ret);
499 return ret;
500}
501
502static const char *readlineUrc()
503{
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
600 LOGD("URC< %s", ret);
601 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 {
644 break;
645 }
646
647 if(strStartsWith(line, "MBTK_AT_READY")) {
648 //handleUnsolicited(line);
649 continue;
b.liu06559f62024-11-01 18:48:22 +0800650 } else if(strStartsWith(line, "CONNECT")) {
651 if(cgact_wait.waitting && cgact_wait.act) {
652 cgact_wait.waitting = false;
653 }
b.liu87afc4c2024-08-14 17:33:45 +0800654 }
655
656 if(isSMSUnsolicited(line))
657 {
658 char *line1;
659 const char *line2;
660
661 // The scope of string returned by 'readline()' is valid only
662 // till next call to 'readline()' hence making a copy of line
663 // before calling readline again.
664 line1 = strdup(line);
b.liub171c9a2024-11-12 19:23:29 +0800665 line2 = readline(*port);
b.liu87afc4c2024-08-14 17:33:45 +0800666
667 if (line2 == NULL)
668 {
669 free(line1);
670 break;
671 }
672
673 if (s_unsolHandler != NULL)
674 {
675 s_unsolHandler (line1, line2);
676 }
677 free(line1);
678 }
679 else
680 {
b.liub171c9a2024-11-12 19:23:29 +0800681 processLine(*port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800682 }
683 }
684
b.liub171c9a2024-11-12 19:23:29 +0800685 onReaderClosed(*port);
686
687 free(port);
b.liu87afc4c2024-08-14 17:33:45 +0800688
689 return NULL;
690}
691
692static void *readerUrcLoop(void *arg)
693{
694 UNUSED(arg);
b.liub171c9a2024-11-12 19:23:29 +0800695 ATPortType_enum *port = (ATPortType_enum*)arg;
b.liu87afc4c2024-08-14 17:33:45 +0800696 for (;;)
697 {
698 const char *line;
699
700 line = readlineUrc();
701
702 if (line == NULL)
703 {
704 break;
705 }
706
707 handleUnsolicited(line);
708 }
709
b.liub171c9a2024-11-12 19:23:29 +0800710 onReaderClosed(*port);
711
712 free(port);
b.liu87afc4c2024-08-14 17:33:45 +0800713
714 return NULL;
715}
716
717
718/**
719 * Sends string s to the radio with a \r appended.
720 * Returns AT_ERROR_* on error, 0 on success
721 *
722 * This function exists because as of writing, android libc does not
723 * have buffered stdio.
724 */
b.liub171c9a2024-11-12 19:23:29 +0800725static int writeline (ATPortType_enum port, const char *s)
b.liu87afc4c2024-08-14 17:33:45 +0800726{
727 size_t cur = 0;
728 size_t len = strlen(s);
729 ssize_t written;
730
b.liub171c9a2024-11-12 19:23:29 +0800731 if (s_at_fd[port] < 0 || s_readerClosed > 0)
b.liu87afc4c2024-08-14 17:33:45 +0800732 {
733 return AT_ERROR_CHANNEL_CLOSED;
734 }
735
736 LOGD("AT> %s", s);
737
738 AT_DUMP( ">> ", s, strlen(s) );
739
b.liub171c9a2024-11-12 19:23:29 +0800740 memset(s_curr_at[port], 0x0, AT_BUFF_MAX);
741 memcpy(s_curr_at[port], s, strlen(s));
b.liu87afc4c2024-08-14 17:33:45 +0800742
743 /* the main string */
744 while (cur < len)
745 {
746 do
747 {
b.liub171c9a2024-11-12 19:23:29 +0800748 written = write (s_at_fd[port], s + cur, len - cur);
b.liu87afc4c2024-08-14 17:33:45 +0800749 }
750 while (written < 0 && errno == EINTR);
751
752 if (written < 0)
753 {
754 return AT_ERROR_GENERIC;
755 }
756
757 cur += written;
758 }
759
760 /* the \r */
761
762 do
763 {
b.liub171c9a2024-11-12 19:23:29 +0800764 written = write (s_at_fd[port], "\r", 1);
b.liu87afc4c2024-08-14 17:33:45 +0800765 }
766 while ((written < 0 && errno == EINTR) || (written == 0));
767
768 if (written < 0)
769 {
770 return AT_ERROR_GENERIC;
771 }
772
773 return 0;
774}
775
b.liub171c9a2024-11-12 19:23:29 +0800776static int writeCtrlZ (ATPortType_enum port, const char *s)
b.liu87afc4c2024-08-14 17:33:45 +0800777{
778 size_t cur = 0;
779 size_t len = strlen(s);
780 ssize_t written;
781
b.liub171c9a2024-11-12 19:23:29 +0800782 if (s_at_fd[port] < 0 || s_readerClosed > 0)
b.liu87afc4c2024-08-14 17:33:45 +0800783 {
784 return AT_ERROR_CHANNEL_CLOSED;
785 }
786
787 LOGD("AT> %s^Z\n", s);
788
789 AT_DUMP( ">* ", s, strlen(s) );
790
791 /* the main string */
792 while (cur < len)
793 {
794 do
795 {
b.liub171c9a2024-11-12 19:23:29 +0800796 written = write (s_at_fd[port], s + cur, len - cur);
b.liu87afc4c2024-08-14 17:33:45 +0800797 }
798 while (written < 0 && errno == EINTR);
799
800 if (written < 0)
801 {
802 return AT_ERROR_GENERIC;
803 }
804
805 cur += written;
806 }
807
808 /* the ^Z */
809
810 do
811 {
b.liub171c9a2024-11-12 19:23:29 +0800812 written = write (s_at_fd[port], "\032", 1);
b.liu87afc4c2024-08-14 17:33:45 +0800813 }
814 while ((written < 0 && errno == EINTR) || (written == 0));
815
816 if (written < 0)
817 {
818 return AT_ERROR_GENERIC;
819 }
820
821 return 0;
822}
823
b.liub171c9a2024-11-12 19:23:29 +0800824static void clearPendingCommand(ATPortType_enum port)
b.liu87afc4c2024-08-14 17:33:45 +0800825{
b.liub171c9a2024-11-12 19:23:29 +0800826 if (sp_response[port] != NULL)
b.liu87afc4c2024-08-14 17:33:45 +0800827 {
b.liub171c9a2024-11-12 19:23:29 +0800828 at_response_free(sp_response[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800829 }
830
b.liub171c9a2024-11-12 19:23:29 +0800831 sp_response[port] = NULL;
832 s_responsePrefix[port] = NULL;
833 s_smsPDU[port] = NULL;
b.liu87afc4c2024-08-14 17:33:45 +0800834}
835
836
837/**
838 * Starts AT handler on stream "fd'
839 * returns 0 on success, -1 on error
840 */
b.liub171c9a2024-11-12 19:23:29 +0800841int at_open(ATPortType_enum port, int at_fd, int uart_fd, ATUnsolHandler h)
b.liu87afc4c2024-08-14 17:33:45 +0800842{
843 int ret;
844 pthread_attr_t attr;
845
b.liub171c9a2024-11-12 19:23:29 +0800846 s_at_fd[port] = at_fd;
b.liu87afc4c2024-08-14 17:33:45 +0800847 s_uart_fd = uart_fd;
848 s_unsolHandler = h;
849 s_readerClosed = 0;
b.liub171c9a2024-11-12 19:23:29 +0800850 s_responsePrefix[port] = NULL;
851 s_smsPDU[port] = NULL;
852 sp_response[port] = NULL;
853
854 ATPortType_enum *at_port_ptr = (ATPortType_enum*)malloc(sizeof(ATPortType_enum));
855 ATPortType_enum *urc_port_ptr = (ATPortType_enum*)malloc(sizeof(ATPortType_enum));
856 *at_port_ptr = port;
857 *urc_port_ptr = port;
b.liu87afc4c2024-08-14 17:33:45 +0800858
859 pthread_attr_init (&attr);
860 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
b.liub171c9a2024-11-12 19:23:29 +0800861 ret = pthread_create(&s_tid_reader[port], &attr, readerLoop, at_port_ptr);
b.liu87afc4c2024-08-14 17:33:45 +0800862 if (ret < 0)
863 {
864 LOGE("AT thread create fail.");
865 return -1;
866 }
867
868 pthread_t uart_tid_reader;
b.liub171c9a2024-11-12 19:23:29 +0800869 ret = pthread_create(&uart_tid_reader, &attr, readerUrcLoop, urc_port_ptr);
b.liu87afc4c2024-08-14 17:33:45 +0800870 if (ret < 0)
871 {
872 LOGE("Uart thread create fail.");
873 return -1;
874 }
875
876 return 0;
877}
878
879/* FIXME is it ok to call this from the reader and the command thread? */
b.liub171c9a2024-11-12 19:23:29 +0800880void at_close(ATPortType_enum port)
b.liu87afc4c2024-08-14 17:33:45 +0800881{
882 LOGD("at_close()");
b.liub171c9a2024-11-12 19:23:29 +0800883 if (s_at_fd[port] >= 0)
b.liu87afc4c2024-08-14 17:33:45 +0800884 {
b.liub171c9a2024-11-12 19:23:29 +0800885 close(s_at_fd[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800886 }
887 if (s_uart_fd >= 0)
888 {
889 close(s_uart_fd);
890 }
b.liub171c9a2024-11-12 19:23:29 +0800891 s_at_fd[port] = -1;
b.liu87afc4c2024-08-14 17:33:45 +0800892 s_uart_fd = -1;
893
b.liub171c9a2024-11-12 19:23:29 +0800894 pthread_mutex_lock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800895 s_readerClosed = 1;
b.liub171c9a2024-11-12 19:23:29 +0800896 pthread_cond_signal(&s_commandcond[port]);
897 pthread_mutex_unlock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800898 /* the reader thread should eventually die */
899
b.liub171c9a2024-11-12 19:23:29 +0800900 at_state[port] = RIL_AT_STATE_CLOSED;
b.liu87afc4c2024-08-14 17:33:45 +0800901}
902
903static ATResponse * at_response_new()
904{
905 return (ATResponse *) calloc(1, sizeof(ATResponse));
906}
907
908void at_response_free(ATResponse *p_response)
909{
910 ATLine *p_line;
911
912 if (p_response == NULL) return;
913
914 p_line = p_response->p_intermediates;
915
916 while (p_line != NULL)
917 {
918 ATLine *p_toFree;
919
920 p_toFree = p_line;
921 p_line = p_line->p_next;
922
923 free(p_toFree->line);
924 free(p_toFree);
925 }
926
927 free (p_response->finalResponse);
928 free (p_response);
929}
930
931/**
932 * The line reader places the intermediate responses in reverse order
933 * here we flip them back
934 */
935static void reverseIntermediates(ATResponse *p_response)
936{
937 ATLine *pcur,*pnext;
938
939 pcur = p_response->p_intermediates;
940 p_response->p_intermediates = NULL;
941
942 while (pcur != NULL)
943 {
944 pnext = pcur->p_next;
945 pcur->p_next = p_response->p_intermediates;
946 p_response->p_intermediates = pcur;
947 pcur = pnext;
948 }
949}
950
951static long long at_timeout_get(const char *at_command, bool *timeout_close)
952{
953 long long timeout = 0;
954 int i;
955 for(i = 0; i < ARRAY_SIZE(at_timeout_list); i++)
956 {
957 if(!strncasecmp(at_command, at_timeout_list[i].at_command, strlen(at_timeout_list[i].at_command)))
958 {
959 timeout = at_timeout_list[i].timeout;
960 *timeout_close = at_timeout_list[i].timeout_close;
961 break;
962 }
963 }
964
965 return timeout;
966}
967
968/**
969 * Internal send_command implementation
970 * Doesn't lock or call the timeout callback
971 *
972 * timeoutMsec == 0 means infinite timeout
973 */
b.liub171c9a2024-11-12 19:23:29 +0800974static int at_send_command_full_nolock (ATPortType_enum port, const char *command, ATCommandType type,
b.liu87afc4c2024-08-14 17:33:45 +0800975 const char *responsePrefix, const char *smspdu,
976 long long timeoutMsec, ATResponse **pp_outResponse)
977{
978 int err = 0;
979 bool tiemout_close = true;
980 struct timespec ts;
b.liub171c9a2024-11-12 19:23:29 +0800981 if(at_state[port] == RIL_AT_STATE_READY)
982 at_state[port] = RIL_AT_STATE_BUSY;
b.liu87afc4c2024-08-14 17:33:45 +0800983
b.liub171c9a2024-11-12 19:23:29 +0800984 if(sp_response[port] != NULL)
b.liu87afc4c2024-08-14 17:33:45 +0800985 {
986 err = AT_ERROR_COMMAND_PENDING;
987 goto error;
988 }
989
b.liub171c9a2024-11-12 19:23:29 +0800990 err = writeline (port, command);
b.liu87afc4c2024-08-14 17:33:45 +0800991
992 if (err < 0)
993 {
994 goto error;
995 }
996
b.liub171c9a2024-11-12 19:23:29 +0800997 s_type[port] = type;
998 s_responsePrefix[port] = responsePrefix;
999 s_smsPDU[port] = smspdu;
1000 sp_response[port] = at_response_new();
b.liu87afc4c2024-08-14 17:33:45 +08001001
1002 if(timeoutMsec == 0)
1003 {
1004 timeoutMsec = at_timeout_get(command, &tiemout_close);
1005 }
1006
1007 if (timeoutMsec != 0)
1008 {
1009 setTimespecRelative(&ts, timeoutMsec);
1010 }
1011
b.liub171c9a2024-11-12 19:23:29 +08001012 while (sp_response[port]->finalResponse == NULL && s_readerClosed == 0)
b.liu87afc4c2024-08-14 17:33:45 +08001013 {
1014 //LOGD("AT wait time:%lld",timeoutMsec);
1015 if (timeoutMsec != 0)
1016 {
b.liub171c9a2024-11-12 19:23:29 +08001017 err = pthread_cond_timedwait(&s_commandcond[port], &s_commandmutex[port], &ts);
b.liu87afc4c2024-08-14 17:33:45 +08001018 }
1019 else
1020 {
b.liub171c9a2024-11-12 19:23:29 +08001021 err = pthread_cond_wait(&s_commandcond[port], &s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001022 }
1023
1024 //LOGD("AT continue:err - %d",err);
1025 if (err == ETIMEDOUT)
1026 {
1027 if(tiemout_close)
1028 {
1029 err = AT_ERROR_TIMEOUT_CLOSE;
1030 }
1031 else
1032 {
1033 err = AT_ERROR_TIMEOUT;
1034 }
1035 goto error;
1036 }
1037 }
1038
1039 if (pp_outResponse == NULL)
1040 {
b.liub171c9a2024-11-12 19:23:29 +08001041 at_response_free(sp_response[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001042 }
1043 else
1044 {
1045 /* line reader stores intermediate responses in reverse order */
b.liub171c9a2024-11-12 19:23:29 +08001046 reverseIntermediates(sp_response[port]);
1047 *pp_outResponse = sp_response[port];
b.liu87afc4c2024-08-14 17:33:45 +08001048 }
1049
b.liub171c9a2024-11-12 19:23:29 +08001050 sp_response[port] = NULL;
b.liu87afc4c2024-08-14 17:33:45 +08001051
1052 if(s_readerClosed > 0)
1053 {
1054 err = AT_ERROR_CHANNEL_CLOSED;
1055 goto error;
1056 }
1057
1058 err = 0;
1059error:
b.liub171c9a2024-11-12 19:23:29 +08001060 if(at_state[port] == RIL_AT_STATE_BUSY)
1061 at_state[port] = RIL_AT_STATE_READY;
1062 clearPendingCommand(port);
b.liu87afc4c2024-08-14 17:33:45 +08001063
1064 return err;
1065}
1066
1067/**
1068 * Internal send_command implementation
1069 *
1070 * timeoutMsec == 0 means infinite timeout
1071 */
b.liub171c9a2024-11-12 19:23:29 +08001072static int at_send_command_full (ATPortType_enum port, const char *command, ATCommandType type,
b.liu87afc4c2024-08-14 17:33:45 +08001073 const char *responsePrefix, const char *smspdu,
1074 long long timeoutMsec, ATResponse **pp_outResponse)
1075{
1076 int err;
1077
b.liub171c9a2024-11-12 19:23:29 +08001078 if (0 != pthread_equal(s_tid_reader[port], pthread_self()))
b.liu87afc4c2024-08-14 17:33:45 +08001079 {
1080 /* cannot be called from reader thread */
1081 LOGE("cannot be called from reader thread.");
1082 return AT_ERROR_INVALID_THREAD;
1083 }
1084
1085 // Waitting for previous AT complete.
b.liub171c9a2024-11-12 19:23:29 +08001086 while(at_state[port] == RIL_AT_STATE_BUSY)
b.liu87afc4c2024-08-14 17:33:45 +08001087 {
1088 usleep(10000);
1089 }
1090
b.liub171c9a2024-11-12 19:23:29 +08001091 pthread_mutex_lock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001092
b.liub171c9a2024-11-12 19:23:29 +08001093 err = at_send_command_full_nolock(port, command, type,
b.liu87afc4c2024-08-14 17:33:45 +08001094 responsePrefix, smspdu,
1095 timeoutMsec, pp_outResponse);
1096
b.liub171c9a2024-11-12 19:23:29 +08001097 pthread_mutex_unlock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001098
1099 if (err == AT_ERROR_TIMEOUT_CLOSE && s_onTimeout != NULL)
1100 {
1101 s_onTimeout();
1102 }
1103
1104 return err;
1105}
1106
1107
1108/**
1109 * Issue a single normal AT command with no intermediate response expected
1110 *
1111 * "command" should not include \r
1112 * pp_outResponse can be NULL
1113 *
1114 * if non-NULL, the resulting ATResponse * must be eventually freed with
1115 * at_response_free
1116 */
b.liub171c9a2024-11-12 19:23:29 +08001117int at_send_command (ATPortType_enum port, const char *command, ATResponse **pp_outResponse)
b.liu87afc4c2024-08-14 17:33:45 +08001118{
b.liub171c9a2024-11-12 19:23:29 +08001119 return at_send_command_full (port, command, NO_RESULT, NULL,
b.liu87afc4c2024-08-14 17:33:45 +08001120 NULL, 0, pp_outResponse);
1121}
1122
1123
b.liub171c9a2024-11-12 19:23:29 +08001124int at_send_command_singleline (ATPortType_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001125 const char *responsePrefix,
1126 ATResponse **pp_outResponse)
1127{
1128 int err;
1129
b.liub171c9a2024-11-12 19:23:29 +08001130 err = at_send_command_full (port, command, SINGLELINE, responsePrefix,
b.liu87afc4c2024-08-14 17:33:45 +08001131 NULL, 0, pp_outResponse);
1132
1133 if (err == 0 && pp_outResponse != NULL
1134 && (*pp_outResponse)->success > 0
1135 && (*pp_outResponse)->p_intermediates == NULL
1136 )
1137 {
1138 /* successful command must have an intermediate response */
1139 at_response_free(*pp_outResponse);
1140 *pp_outResponse = NULL;
1141 return AT_ERROR_INVALID_RESPONSE;
1142 }
1143
1144 return err;
1145}
1146
b.liub171c9a2024-11-12 19:23:29 +08001147int at_send_command_singleline_with_timeout (ATPortType_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001148 const char *responsePrefix,
1149 ATResponse **pp_outResponse,long long timeoutMsec)
1150{
1151 int err;
1152
b.liub171c9a2024-11-12 19:23:29 +08001153 err = at_send_command_full (port, command, SINGLELINE, responsePrefix,
b.liu87afc4c2024-08-14 17:33:45 +08001154 NULL, timeoutMsec, pp_outResponse);
1155
1156 if (err == 0 && pp_outResponse != NULL
1157 && (*pp_outResponse)->success > 0
1158 && (*pp_outResponse)->p_intermediates == NULL
1159 )
1160 {
1161 /* successful command must have an intermediate response */
1162 at_response_free(*pp_outResponse);
1163 *pp_outResponse = NULL;
1164 return AT_ERROR_INVALID_RESPONSE;
1165 }
1166
1167 return err;
1168}
1169
1170
1171
b.liub171c9a2024-11-12 19:23:29 +08001172int at_send_command_numeric (ATPortType_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001173 ATResponse **pp_outResponse)
1174{
1175 int err;
1176
b.liub171c9a2024-11-12 19:23:29 +08001177 err = at_send_command_full (port, command, NUMERIC, NULL,
b.liu87afc4c2024-08-14 17:33:45 +08001178 NULL, 0, pp_outResponse);
1179
1180 if (err == 0 && pp_outResponse != NULL
1181 && (*pp_outResponse)->success > 0
1182 && (*pp_outResponse)->p_intermediates == NULL
1183 )
1184 {
1185 /* successful command must have an intermediate response */
1186 at_response_free(*pp_outResponse);
1187 *pp_outResponse = NULL;
1188 return AT_ERROR_INVALID_RESPONSE;
1189 }
1190
1191 return err;
1192}
1193
1194
b.liub171c9a2024-11-12 19:23:29 +08001195int at_send_command_sms (ATPortType_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001196 const char *pdu,
1197 const char *responsePrefix,
1198 ATResponse **pp_outResponse)
1199{
1200 int err;
1201
b.liub171c9a2024-11-12 19:23:29 +08001202 err = at_send_command_full (port, command, SINGLELINE, responsePrefix,
b.liu87afc4c2024-08-14 17:33:45 +08001203 pdu, 0, pp_outResponse);
1204
1205 if (err == 0 && pp_outResponse != NULL
1206 && (*pp_outResponse)->success > 0
1207 && (*pp_outResponse)->p_intermediates == NULL
1208 )
1209 {
1210 /* successful command must have an intermediate response */
1211 at_response_free(*pp_outResponse);
1212 *pp_outResponse = NULL;
1213 return AT_ERROR_INVALID_RESPONSE;
1214 }
1215
1216 return err;
1217}
1218
1219
b.liub171c9a2024-11-12 19:23:29 +08001220int at_send_command_multiline (ATPortType_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001221 const char *responsePrefix,
1222 ATResponse **pp_outResponse)
1223{
1224 int err;
1225
b.liub171c9a2024-11-12 19:23:29 +08001226 err = at_send_command_full (port, command, MULTILINE, responsePrefix,
b.liu87afc4c2024-08-14 17:33:45 +08001227 NULL, 0, pp_outResponse);
1228
1229 return err;
1230}
1231
1232
1233/** This callback is invoked on the command thread */
1234void at_set_on_timeout(void (*onTimeout)(void))
1235{
1236 s_onTimeout = onTimeout;
1237}
1238
1239/**
1240 * This callback is invoked on the reader thread (like ATUnsolHandler)
1241 * when the input stream closes before you call at_close
1242 * (not when you call at_close())
1243 * You should still call at_close()
1244 */
1245
1246void at_set_on_reader_closed(void (*onClose)(void))
1247{
1248 s_onReaderClosed = onClose;
1249}
1250
1251
1252/**
1253 * Periodically issue an AT command and wait for a response.
1254 * Used to ensure channel has start up and is active
1255 */
b.liub171c9a2024-11-12 19:23:29 +08001256int at_handshake(ATPortType_enum port)
b.liu87afc4c2024-08-14 17:33:45 +08001257{
b.liu62240ee2024-11-07 17:52:45 +08001258// int i;
b.liu87afc4c2024-08-14 17:33:45 +08001259 int err = 0;
1260
b.liub171c9a2024-11-12 19:23:29 +08001261 if (0 != pthread_equal(s_tid_reader[port], pthread_self()))
b.liu87afc4c2024-08-14 17:33:45 +08001262 {
1263 /* cannot be called from reader thread */
1264 return AT_ERROR_INVALID_THREAD;
1265 }
b.liub171c9a2024-11-12 19:23:29 +08001266 pthread_mutex_lock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001267
1268#if 0
1269 for (i = 0 ; i < HANDSHAKE_RETRY_COUNT ; i++)
1270 {
1271 /* some stacks start with verbose off */
1272 err = at_send_command_full_nolock("ATE0Q0V1", NO_RESULT,
1273 NULL, NULL, HANDSHAKE_TIMEOUT_MSEC, NULL);
1274
1275 if (err == 0)
1276 {
1277 break;
1278 }
1279 }
1280#else
b.liub171c9a2024-11-12 19:23:29 +08001281 err = at_send_command_full_nolock(port, "ATE0Q0V1", NO_RESULT,
b.liu87afc4c2024-08-14 17:33:45 +08001282 NULL, NULL, 0, NULL);
1283#endif
1284
1285 if (err == 0)
1286 {
1287 /* pause for a bit to let the input buffer drain any unmatched OK's
1288 (they will appear as extraneous unsolicited responses) */
1289 sleepMsec(HANDSHAKE_TIMEOUT_MSEC);
1290 }
1291
b.liub171c9a2024-11-12 19:23:29 +08001292 pthread_mutex_unlock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001293
1294
1295 return err;
1296}
1297
1298/**
1299 * Returns error code from response
1300 * Assumes AT+CMEE=1 (numeric) mode
1301 */
1302int at_get_cme_error(const ATResponse *p_response)
1303{
1304 int ret;
1305 int err;
1306 char *p_cur;
1307
1308 if (p_response->success > 0)
1309 {
1310 return CME_SUCCESS;
1311 }
1312
1313 if (p_response->finalResponse == NULL
1314 || !strStartsWith(p_response->finalResponse, "+CME ERROR:")
1315 )
1316 {
1317 return CME_ERROR_NON_CME;
1318 }
1319
1320 p_cur = p_response->finalResponse;
1321 err = at_tok_start(&p_cur);
1322
1323 if (err < 0)
1324 {
1325 return CME_ERROR_NON_CME;
1326 }
1327
1328 err = at_tok_nextint(&p_cur, &ret);
1329
1330 if (err < 0)
1331 {
1332 return CME_ERROR_NON_CME;
1333 }
1334
1335 return ret;
1336}
1337
b.liub171c9a2024-11-12 19:23:29 +08001338mbtk_ril_at_state_enum at_state_get(ATPortType_enum port)
b.liu87afc4c2024-08-14 17:33:45 +08001339{
b.liub171c9a2024-11-12 19:23:29 +08001340 return at_state[port];
b.liu87afc4c2024-08-14 17:33:45 +08001341}
1342
b.liub171c9a2024-11-12 19:23:29 +08001343void at_state_set(ATPortType_enum port, mbtk_ril_at_state_enum state)
b.liu87afc4c2024-08-14 17:33:45 +08001344{
b.liub171c9a2024-11-12 19:23:29 +08001345 at_state[port] = state;
b.liu87afc4c2024-08-14 17:33:45 +08001346}
1347
1348bool at_rsp_check(ATResponse *p_response)
1349{
1350 if(!p_response || !p_response->success)
1351 return false;
1352
1353 return true;
1354}
1355
b.liub171c9a2024-11-12 19:23:29 +08001356void unused_func(ATPortType_enum port)
b.liu87afc4c2024-08-14 17:33:45 +08001357{
b.liub171c9a2024-11-12 19:23:29 +08001358 isFinalResponse(port, NULL);
b.liu87afc4c2024-08-14 17:33:45 +08001359}
1360