blob: b2096dadcf1b56023d60fb1a589ead8024cb2d95 [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.liu7ca612c2025-04-25 09:23:36 +080041static pthread_t s_tid_reader[ATPORTID_NUM];
42static int s_at_fd[ATPORTID_NUM] = {-1}; /* fd of the AT channel */
43static int s_uart_fd[MBTK_SIM_NUM] = {-1}; /* fd of the UART channel */
b.liu87afc4c2024-08-14 17:33:45 +080044
b.liu7ca612c2025-04-25 09:23:36 +080045static ATUnsolHandler s_unsolHandler[MBTK_SIM_NUM];
b.liu87afc4c2024-08-14 17:33:45 +080046
47/* for input buffering */
48
b.liu7ca612c2025-04-25 09:23:36 +080049static char s_ATBuffer[ATPORTID_NUM][MAX_AT_RESPONSE+1];
50static char *s_ATBufferCur[ATPORTID_NUM] = {s_ATBuffer[ATPORTID_SIM1_0], s_ATBuffer[ATPORTID_SIM1_0], s_ATBuffer[ATPORTID_SIM1_0],
51 s_ATBuffer[ATPORTID_SIM2_0], s_ATBuffer[ATPORTID_SIM2_0], s_ATBuffer[ATPORTID_SIM2_0]};
52static char s_UartBuffer[MBTK_SIM_NUM][MAX_AT_RESPONSE+1];
53static char *s_UartBufferCur[MBTK_SIM_NUM] = {s_UartBuffer[MBTK_SIM_1], s_UartBuffer[MBTK_SIM_2]};
b.liu87afc4c2024-08-14 17:33:45 +080054
b.liu7ca612c2025-04-25 09:23:36 +080055static mbtk_ril_at_state_enum at_state[ATPORTID_NUM] = {RIL_AT_STATE_CLOSED};
b.liu87afc4c2024-08-14 17:33:45 +080056
57#if AT_DEBUG
58void AT_DUMP(const char* prefix, const char* buff, int len)
59{
60 if (len < 0)
61 len = strlen(buff);
62 LOGD("%.*s", len, buff);
63}
64#endif
65
66/*
67 * There is one reader thread |s_tid_reader| and potentially multiple writer
68 * threads. |s_commandmutex| and |s_commandcond| are used to maintain the
69 * condition that the writer thread will not read from |sp_response| until the
70 * reader thread has signaled itself is finished, etc. |s_writeMutex| is used to
71 * prevent multiple writer threads from calling at_send_command_full_nolock
72 * function at the same time.
73 */
74
75// "Wait" when AT process...
b.liu7ca612c2025-04-25 09:23:36 +080076static pthread_mutex_t s_commandmutex[ATPORTID_NUM] = {PTHREAD_MUTEX_INITIALIZER};
77static pthread_cond_t s_commandcond[ATPORTID_NUM] = {PTHREAD_COND_INITIALIZER};
b.liu87afc4c2024-08-14 17:33:45 +080078
b.liu7ca612c2025-04-25 09:23:36 +080079static ATCommandType s_type[ATPORTID_NUM];
80static const char *s_responsePrefix[ATPORTID_NUM] = {NULL};
81static const char *s_smsPDU[ATPORTID_NUM] = {NULL};
82static ATResponse *sp_response[ATPORTID_NUM] = {NULL};
83static char s_curr_at[ATPORTID_NUM][AT_BUFF_MAX];
b.liu87afc4c2024-08-14 17:33:45 +080084
85static void (*s_onTimeout)(void) = NULL;
86static void (*s_onReaderClosed)(void) = NULL;
87static int s_readerClosed;
88
b.liu7ca612c2025-04-25 09:23:36 +080089static void onReaderClosed(ATPortId_enum port);
90static int writeCtrlZ (ATPortId_enum port, const char *s);
91static int writeline (ATPortId_enum port, const char *s);
b.liu87afc4c2024-08-14 17:33:45 +080092
93typedef struct
94{
95 char *at_command;
96 long long timeout; // ms
97 bool timeout_close; // Close AT or not while AT response timeout.
98} at_timeout_t;
99
100static at_timeout_t at_timeout_list[] =
101{
102 {"AT+CRSM", 10000, false},
103// {"AT+COPS", 60000, false}
104};
105
106#define NS_PER_S 1000000000
107static void setTimespecRelative(struct timespec *p_ts, long long msec)
108{
109 struct timeval tv;
110
111 gettimeofday(&tv, (struct timezone *) NULL);
112
113 p_ts->tv_sec = tv.tv_sec + (msec / 1000);
114 p_ts->tv_nsec = (tv.tv_usec + (msec % 1000) * 1000L ) * 1000L;
115 /* assuming tv.tv_usec < 10^6 */
116 if (p_ts->tv_nsec >= NS_PER_S)
117 {
118 p_ts->tv_sec++;
119 p_ts->tv_nsec -= NS_PER_S;
120 }
121}
122
123static void sleepMsec(long long msec)
124{
125 struct timespec ts;
126 int err;
127
128 ts.tv_sec = (msec / 1000);
129 ts.tv_nsec = (msec % 1000) * 1000 * 1000;
130
131 do
132 {
133 err = nanosleep (&ts, &ts);
134 }
135 while (err < 0 && errno == EINTR);
136}
137
138
139
140/** add an intermediate response to sp_response*/
b.liu7ca612c2025-04-25 09:23:36 +0800141static void addIntermediate(ATPortId_enum port, const char *line)
b.liu87afc4c2024-08-14 17:33:45 +0800142{
143 ATLine *p_new;
144
145 p_new = (ATLine *) malloc(sizeof(ATLine));
146
147 p_new->line = strdup(line);
148
149// LOGD("line:%s", line);
150// LOGD("line-1:%s", p_new->line);
151
152 /* note: this adds to the head of the list, so the list
153 will be in reverse order of lines received. the order is flipped
154 again before passing on to the command issuer */
b.liub171c9a2024-11-12 19:23:29 +0800155 p_new->p_next = sp_response[port]->p_intermediates;
156 sp_response[port]->p_intermediates = p_new;
b.liu87afc4c2024-08-14 17:33:45 +0800157}
158
159
160/**
161 * returns 1 if line is a final response indicating error
162 * See 27.007 annex B
163 * WARNING: NO CARRIER and others are sometimes unsolicited
164 */
165static const char * s_finalResponsesError[] =
166{
167 "ERROR",
168 "+CMS ERROR:",
169 "+CME ERROR:",
170// "NO CARRIER", /* sometimes! */ // Only for ATD ?
171 "NO ANSWER",
172 "NO DIALTONE",
173};
b.liu7ca612c2025-04-25 09:23:36 +0800174static int isFinalResponseError(ATPortId_enum port, const char *line)
b.liu87afc4c2024-08-14 17:33:45 +0800175{
176 size_t i;
177
178 for (i = 0 ; i < ARRAY_SIZE(s_finalResponsesError) ; i++)
179 {
180 if (strStartsWith(line, s_finalResponsesError[i]))
181 {
182 return 1;
183 }
184 }
185
b.liub171c9a2024-11-12 19:23:29 +0800186 if(!strncasecmp(s_curr_at[port], "ATD", 3) && strStartsWith(line, "NO CARRIER"))
b.liu87afc4c2024-08-14 17:33:45 +0800187 {
188 return 1;
189 }
190
191 return 0;
192}
193
194/**
195 * returns 1 if line is a final response indicating success
196 * See 27.007 annex B
197 * WARNING: NO CARRIER and others are sometimes unsolicited
198 */
199static const char * s_finalResponsesSuccess[] =
200{
201 "OK",
202// "CONNECT" /* some stacks start up data on another channel */
203};
204static int isFinalResponseSuccess(const char *line)
205{
206 size_t i;
207
208 for (i = 0 ; i < ARRAY_SIZE(s_finalResponsesSuccess) ; i++)
209 {
210 if (strStartsWith(line, s_finalResponsesSuccess[i]))
211 {
212 return 1;
213 }
214 }
215
216 return 0;
217}
218
219/**
220 * returns 1 if line is a final response, either error or success
221 * See 27.007 annex B
222 * WARNING: NO CARRIER and others are sometimes unsolicited
223 */
b.liu7ca612c2025-04-25 09:23:36 +0800224static int isFinalResponse(ATPortId_enum port, const char *line)
b.liu87afc4c2024-08-14 17:33:45 +0800225{
b.liub171c9a2024-11-12 19:23:29 +0800226 return isFinalResponseSuccess(line) || isFinalResponseError(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800227}
228
229/**
230 * returns 1 if line is the first line in (what will be) a two-line
231 * SMS unsolicited response
232 */
233static const char * s_smsUnsoliciteds[] =
234{
235 "+CMT:",
236 "+CDS:",
237 "+CBM:"
238};
239static int isSMSUnsolicited(const char *line)
240{
241 size_t i;
242
243 for (i = 0 ; i < ARRAY_SIZE(s_smsUnsoliciteds) ; i++)
244 {
245 if (strStartsWith(line, s_smsUnsoliciteds[i]))
246 {
247 return 1;
248 }
249 }
250
251 return 0;
252}
253
254
255/** assumes s_commandmutex is held */
b.liu7ca612c2025-04-25 09:23:36 +0800256static void handleFinalResponse(ATPortId_enum port, const char *line)
b.liu87afc4c2024-08-14 17:33:45 +0800257{
b.liub171c9a2024-11-12 19:23:29 +0800258 sp_response[port]->finalResponse = strdup(line);
b.liu87afc4c2024-08-14 17:33:45 +0800259
260 //LOGD("AT complete (pthread_cond_signal): %s",line);
b.liub171c9a2024-11-12 19:23:29 +0800261 pthread_cond_signal(&s_commandcond[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800262}
263
b.liu7ca612c2025-04-25 09:23:36 +0800264static void handleUnsolicited(ATPortId_enum port, const char *line)
b.liu87afc4c2024-08-14 17:33:45 +0800265{
b.liu7ca612c2025-04-25 09:23:36 +0800266 if (s_unsolHandler[port < ATPORTID_SIM2_0 ? MBTK_SIM_1 : MBTK_SIM_2] != NULL)
b.liu87afc4c2024-08-14 17:33:45 +0800267 {
b.liu7ca612c2025-04-25 09:23:36 +0800268 s_unsolHandler[port < ATPORTID_SIM2_0 ? MBTK_SIM_1 : MBTK_SIM_2](line, NULL);
b.liu87afc4c2024-08-14 17:33:45 +0800269 }
270}
271
b.liu7ca612c2025-04-25 09:23:36 +0800272static void processLine(ATPortId_enum port, const char *line)
b.liu87afc4c2024-08-14 17:33:45 +0800273{
q.huanged004222025-09-26 21:33:56 +0800274 LOGD("lynq read process begin process line port %d %s", port,line);
b.liub171c9a2024-11-12 19:23:29 +0800275 pthread_mutex_lock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800276// LOGD("LINE : %s", line);
q.huanged004222025-09-26 21:33:56 +0800277 LOGD("lynq read process get lock port %d", port);
278
b.liub171c9a2024-11-12 19:23:29 +0800279 if (sp_response[port] == NULL)
b.liu87afc4c2024-08-14 17:33:45 +0800280 {
q.huanged004222025-09-26 21:33:56 +0800281 LOGD("lynq read 2 port %d", port);
b.liu87afc4c2024-08-14 17:33:45 +0800282 /* no command pending */
b.liu7ca612c2025-04-25 09:23:36 +0800283 handleUnsolicited(port, line);
q.huanged004222025-09-26 21:33:56 +0800284
b.liu87afc4c2024-08-14 17:33:45 +0800285 }
286 else if (isFinalResponseSuccess(line))
287 {
q.huanged004222025-09-26 21:33:56 +0800288 LOGD("lynq read 3 port %d", port);
b.liub171c9a2024-11-12 19:23:29 +0800289 sp_response[port]->success = 1;
290 handleFinalResponse(port, line);
q.huanged004222025-09-26 21:33:56 +0800291
b.liu87afc4c2024-08-14 17:33:45 +0800292 }
b.liub171c9a2024-11-12 19:23:29 +0800293 else if (isFinalResponseError(port, line))
b.liu87afc4c2024-08-14 17:33:45 +0800294 {
q.huanged004222025-09-26 21:33:56 +0800295 LOGD("lynq read 4 port %d", port);
b.liub171c9a2024-11-12 19:23:29 +0800296 sp_response[port]->success = 0;
297 handleFinalResponse(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800298 }
b.liub171c9a2024-11-12 19:23:29 +0800299 else if (s_smsPDU[port] != NULL && 0 == strcmp(line, "> "))
b.liu87afc4c2024-08-14 17:33:45 +0800300 {
q.huanged004222025-09-26 21:33:56 +0800301 LOGD("lynq read 5 port %d", port);
b.liu87afc4c2024-08-14 17:33:45 +0800302 // See eg. TS 27.005 4.3
303 // Commands like AT+CMGS have a "> " prompt
b.liub171c9a2024-11-12 19:23:29 +0800304 writeCtrlZ(port, s_smsPDU[port]);
305 s_smsPDU[port] = NULL;
b.liu87afc4c2024-08-14 17:33:45 +0800306 }
b.liub171c9a2024-11-12 19:23:29 +0800307 else switch (s_type[port])
b.liu87afc4c2024-08-14 17:33:45 +0800308 {
309 case NO_RESULT:
q.huanged004222025-09-26 21:33:56 +0800310 LOGD("lynq read 6 port %d", port);
b.liu7ca612c2025-04-25 09:23:36 +0800311 handleUnsolicited(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800312 break;
313 case NUMERIC:
q.huanged004222025-09-26 21:33:56 +0800314 LOGD("lynq read 7 port %d", port);
b.liub171c9a2024-11-12 19:23:29 +0800315 if (sp_response[port]->p_intermediates == NULL
b.liu87afc4c2024-08-14 17:33:45 +0800316 && isdigit(line[0])
317 )
318 {
b.liub171c9a2024-11-12 19:23:29 +0800319 addIntermediate(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800320 }
321 else
322 {
323 /* either we already have an intermediate response or
324 the line doesn't begin with a digit */
b.liu7ca612c2025-04-25 09:23:36 +0800325 handleUnsolicited(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800326 }
327 break;
328 case SINGLELINE:
q.huanged004222025-09-26 21:33:56 +0800329 LOGD("lynq read 8 port %d", port);
b.liub171c9a2024-11-12 19:23:29 +0800330 if (sp_response[port]->p_intermediates == NULL
331 && strStartsWith (line, s_responsePrefix[port])
b.liu87afc4c2024-08-14 17:33:45 +0800332 )
333 {
334 if(*line == '"')
335 {
336 char *line_temp = strdup(line);
b.liudeb8e422024-12-14 17:36:56 +0800337 char *free_ptr = line_temp;
b.liu87afc4c2024-08-14 17:33:45 +0800338 line_temp++;
339 if(strlen(line_temp) > 0)
340 {
341 char *ptr = line_temp + strlen(line_temp) - 1;
342 while(ptr >= line_temp && *ptr == '"')
343 {
344 *ptr = '\0';
345 ptr--;
346 }
347 }
b.liub171c9a2024-11-12 19:23:29 +0800348 addIntermediate(port, line_temp);
b.liudeb8e422024-12-14 17:36:56 +0800349 free(free_ptr);
b.liu87afc4c2024-08-14 17:33:45 +0800350 }
351 else
352 {
b.liub171c9a2024-11-12 19:23:29 +0800353 addIntermediate(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800354 }
355 }
356 else
357 {
358 /* we already have an intermediate response */
b.liu7ca612c2025-04-25 09:23:36 +0800359 handleUnsolicited(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800360 }
361 break;
362 case MULTILINE:
q.huanged004222025-09-26 21:33:56 +0800363 LOGD("lynq read 9 port %d", port);
b.liub171c9a2024-11-12 19:23:29 +0800364 if (strStartsWith (line, s_responsePrefix[port]))
b.liu87afc4c2024-08-14 17:33:45 +0800365 {
q.huanged004222025-09-26 21:33:56 +0800366 LOGD("lynq read 10 port %d", port);
b.liub171c9a2024-11-12 19:23:29 +0800367 addIntermediate(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800368 }
369 else
370 {
b.liu7ca612c2025-04-25 09:23:36 +0800371 handleUnsolicited(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800372 }
373 break;
374
375 default: /* this should never be reached */
q.huanged004222025-09-26 21:33:56 +0800376 LOGD("lynq read 11 port %d", port);
b.liub171c9a2024-11-12 19:23:29 +0800377 LOGE("Unsupported AT command type %d\n", s_type[port]);
b.liu7ca612c2025-04-25 09:23:36 +0800378 handleUnsolicited(port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800379 break;
380 }
q.huanged004222025-09-26 21:33:56 +0800381 LOGD("lynq read 12 port %d", port);
b.liub171c9a2024-11-12 19:23:29 +0800382 pthread_mutex_unlock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800383}
384
385
386/**
387 * Returns a pointer to the end of the next line
388 * special-cases the "> " SMS prompt
389 *
390 * returns NULL if there is no complete line
391 */
392static char * findNextEOL(char *cur)
393{
394 if (cur[0] == '>' && cur[1] == ' ' && cur[2] == '\0')
395 {
396 /* SMS prompt character...not \r terminated */
397 return cur+2;
398 }
399
400 // Find next newline
401 while (*cur != '\0' && *cur != '\r' && *cur != '\n') cur++;
402
403 return *cur == '\0' ? NULL : cur;
404}
405
406
407/**
408 * Reads a line from the AT channel, returns NULL on timeout.
409 * Assumes it has exclusive read access to the FD
410 *
411 * This line is valid only until the next call to readline
412 *
413 * This function exists because as of writing, android libc does not
414 * have buffered stdio.
415 */
416
b.liu7ca612c2025-04-25 09:23:36 +0800417static const char *readline(ATPortId_enum port)
b.liu87afc4c2024-08-14 17:33:45 +0800418{
419 ssize_t count;
420
421 char *p_read = NULL;
422 char *p_eol = NULL;
423 char *ret;
424
425 /* this is a little odd. I use *s_ATBufferCur == 0 to
426 * mean "buffer consumed completely". If it points to a character, than
427 * the buffer continues until a \0
428 */
b.liub171c9a2024-11-12 19:23:29 +0800429 if (*s_ATBufferCur[port] == '\0')
b.liu87afc4c2024-08-14 17:33:45 +0800430 {
431 /* empty buffer */
b.liub171c9a2024-11-12 19:23:29 +0800432 s_ATBufferCur[port] = s_ATBuffer[port];
433 *s_ATBufferCur[port] = '\0';
434 p_read = s_ATBuffer[port];
b.liu87afc4c2024-08-14 17:33:45 +0800435 }
436 else /* *s_ATBufferCur != '\0' */
437 {
438 /* there's data in the buffer from the last read */
439
440 // skip over leading newlines
b.liub171c9a2024-11-12 19:23:29 +0800441 while (*s_ATBufferCur[port] == '\r' || *s_ATBufferCur[port] == '\n')
442 s_ATBufferCur[port]++;
b.liu87afc4c2024-08-14 17:33:45 +0800443
b.liub171c9a2024-11-12 19:23:29 +0800444 p_eol = findNextEOL(s_ATBufferCur[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800445
446 if (p_eol == NULL)
447 {
448 /* a partial line. move it up and prepare to read more */
449 size_t len;
450
b.liub171c9a2024-11-12 19:23:29 +0800451 len = strlen(s_ATBufferCur[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800452
b.liub171c9a2024-11-12 19:23:29 +0800453 memmove(s_ATBuffer[port], s_ATBufferCur[port], len + 1);
454 p_read = s_ATBuffer[port] + len;
455 s_ATBufferCur[port] = s_ATBuffer[port];
b.liu87afc4c2024-08-14 17:33:45 +0800456 }
457 /* Otherwise, (p_eol !- NULL) there is a complete line */
458 /* that will be returned the while () loop below */
459 }
460
461 while (p_eol == NULL)
462 {
b.liub171c9a2024-11-12 19:23:29 +0800463 if (0 == MAX_AT_RESPONSE - (p_read - s_ATBuffer[port]))
b.liu87afc4c2024-08-14 17:33:45 +0800464 {
465 LOGE("ERROR: Input line exceeded buffer\n");
466 /* ditch buffer and start over again */
b.liub171c9a2024-11-12 19:23:29 +0800467 s_ATBufferCur[port] = s_ATBuffer[port];
468 *s_ATBufferCur[port] = '\0';
469 p_read = s_ATBuffer[port];
b.liu87afc4c2024-08-14 17:33:45 +0800470 }
471
472 do
473 {
b.liub171c9a2024-11-12 19:23:29 +0800474 count = read(s_at_fd[port], p_read,
475 MAX_AT_RESPONSE - (p_read - s_ATBuffer[port]));
b.liu87afc4c2024-08-14 17:33:45 +0800476 usleep(10000);
477 }
478 while (count < 0 && errno == EINTR);
479
480 if (count > 0)
481 {
482 AT_DUMP( "<< ", p_read, count );
483
484 p_read[count] = '\0';
485
486 // skip over leading newlines
b.liub171c9a2024-11-12 19:23:29 +0800487 while (*s_ATBufferCur[port] == '\r' || *s_ATBufferCur[port] == '\n')
488 s_ATBufferCur[port]++;
b.liu87afc4c2024-08-14 17:33:45 +0800489
b.liub171c9a2024-11-12 19:23:29 +0800490 p_eol = findNextEOL(s_ATBufferCur[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800491 p_read += count;
492 }
493 else if (count <= 0)
494 {
495 /* read error encountered or EOF reached */
496 if(count == 0)
497 {
b.liufd87baf2024-11-15 15:30:38 +0800498 LOGD("atchannel[Port-%d]: EOF reached", port);
b.liu87afc4c2024-08-14 17:33:45 +0800499 }
500 else
501 {
b.liufd87baf2024-11-15 15:30:38 +0800502 LOGD("atchannel[Port-%d]: read error %s", port, strerror(errno));
b.liu87afc4c2024-08-14 17:33:45 +0800503 }
504 return NULL;
505 }
506 }
507
508 /* a full line in the buffer. Place a \0 over the \r and return */
509
b.liub171c9a2024-11-12 19:23:29 +0800510 ret = s_ATBufferCur[port];
b.liu87afc4c2024-08-14 17:33:45 +0800511 *p_eol = '\0';
b.liub171c9a2024-11-12 19:23:29 +0800512 s_ATBufferCur[port] = p_eol + 1; /* this will always be <= p_read, */
b.liu87afc4c2024-08-14 17:33:45 +0800513 /* and there will be a \0 at *p_read */
514
b.liufd87baf2024-11-15 15:30:38 +0800515 LOGD("[Port-%d]AT< %s", port, ret);
b.liu87afc4c2024-08-14 17:33:45 +0800516 return ret;
517}
518
b.liu7ca612c2025-04-25 09:23:36 +0800519static const char *readlineUrc(ATPortId_enum port)
b.liu87afc4c2024-08-14 17:33:45 +0800520{
521 ssize_t count;
522
523 char *p_read = NULL;
524 char *p_eol = NULL;
525 char *ret;
526
b.liu7ca612c2025-04-25 09:23:36 +0800527 mbtk_sim_type_enum sim_id = port < ATPORTID_SIM2_0 ? MBTK_SIM_1 : MBTK_SIM_2;
528
529
b.liu87afc4c2024-08-14 17:33:45 +0800530 /* this is a little odd. I use *s_ATBufferCur == 0 to
531 * mean "buffer consumed completely". If it points to a character, than
532 * the buffer continues until a \0
533 */
b.liu7ca612c2025-04-25 09:23:36 +0800534 if (*s_UartBufferCur[sim_id] == '\0')
b.liu87afc4c2024-08-14 17:33:45 +0800535 {
536 /* empty buffer */
b.liu7ca612c2025-04-25 09:23:36 +0800537 s_UartBufferCur[sim_id] = s_UartBuffer[sim_id];
538 *s_UartBufferCur[sim_id] = '\0';
539 p_read = s_UartBuffer[sim_id];
b.liu87afc4c2024-08-14 17:33:45 +0800540 }
541 else /* *s_ATBufferCur != '\0' */
542 {
543 /* there's data in the buffer from the last read */
544
545 // skip over leading newlines
b.liu7ca612c2025-04-25 09:23:36 +0800546 while (*s_UartBufferCur[sim_id] == '\r' || *s_UartBufferCur[sim_id] == '\n')
547 s_UartBufferCur[sim_id]++;
b.liu87afc4c2024-08-14 17:33:45 +0800548
b.liu7ca612c2025-04-25 09:23:36 +0800549 p_eol = findNextEOL(s_UartBufferCur[sim_id]);
b.liu87afc4c2024-08-14 17:33:45 +0800550
551 if (p_eol == NULL)
552 {
553 /* a partial line. move it up and prepare to read more */
554 size_t len;
555
b.liu7ca612c2025-04-25 09:23:36 +0800556 len = strlen(s_UartBufferCur[sim_id]);
b.liu87afc4c2024-08-14 17:33:45 +0800557
b.liu7ca612c2025-04-25 09:23:36 +0800558 memmove(s_UartBuffer[sim_id], s_UartBufferCur[sim_id], len + 1);
559 p_read = s_UartBuffer[sim_id] + len;
560 s_UartBufferCur[sim_id] = s_UartBuffer[sim_id];
b.liu87afc4c2024-08-14 17:33:45 +0800561 }
562 /* Otherwise, (p_eol !- NULL) there is a complete line */
563 /* that will be returned the while () loop below */
564 }
565
566 while (p_eol == NULL)
567 {
b.liu7ca612c2025-04-25 09:23:36 +0800568 if (0 == MAX_AT_RESPONSE - (p_read - s_UartBuffer[sim_id]))
b.liu87afc4c2024-08-14 17:33:45 +0800569 {
570 LOGE("ERROR: Input line exceeded buffer\n");
571 /* ditch buffer and start over again */
b.liu7ca612c2025-04-25 09:23:36 +0800572 s_UartBufferCur[sim_id] = s_UartBuffer[sim_id];
573 *s_UartBufferCur[sim_id] = '\0';
574 p_read = s_UartBuffer[sim_id];
b.liu87afc4c2024-08-14 17:33:45 +0800575 }
576
577 do
578 {
b.liu7ca612c2025-04-25 09:23:36 +0800579 count = read(s_uart_fd[sim_id], p_read,
580 MAX_AT_RESPONSE - (p_read - s_UartBuffer[sim_id]));
b.liu87afc4c2024-08-14 17:33:45 +0800581 usleep(10000);
582 }
583 while (count < 0 && errno == EINTR);
584
585 if (count > 0)
586 {
587 AT_DUMP( "<< ", p_read, count );
588
589 p_read[count] = '\0';
590
591 // skip over leading newlines
b.liu7ca612c2025-04-25 09:23:36 +0800592 while (*s_UartBufferCur[sim_id] == '\r' || *s_UartBufferCur[sim_id] == '\n')
593 s_UartBufferCur[sim_id]++;
b.liu87afc4c2024-08-14 17:33:45 +0800594
b.liu7ca612c2025-04-25 09:23:36 +0800595 p_eol = findNextEOL(s_UartBufferCur[sim_id]);
b.liu87afc4c2024-08-14 17:33:45 +0800596 p_read += count;
597 }
598 else if (count <= 0)
599 {
600 /* read error encountered or EOF reached */
601 if(count == 0)
602 {
603 LOGD("atchannel: EOF reached");
604 }
605 else
606 {
607 LOGD("atchannel: read error %s", strerror(errno));
608 }
609 return NULL;
610 }
611 }
612
613 /* a full line in the buffer. Place a \0 over the \r and return */
614
b.liu7ca612c2025-04-25 09:23:36 +0800615 ret = s_UartBufferCur[sim_id];
b.liu87afc4c2024-08-14 17:33:45 +0800616 *p_eol = '\0';
b.liu7ca612c2025-04-25 09:23:36 +0800617 s_UartBufferCur[sim_id] = p_eol + 1; /* this will always be <= p_read, */
b.liu87afc4c2024-08-14 17:33:45 +0800618 /* and there will be a \0 at *p_read */
619
b.liu7ca612c2025-04-25 09:23:36 +0800620 LOGD("[Sim-%d,Port-%d]URC< %s", sim_id, port, ret);
b.liu87afc4c2024-08-14 17:33:45 +0800621 return ret;
622}
623
624
b.liu7ca612c2025-04-25 09:23:36 +0800625static void onReaderClosed(ATPortId_enum port)
b.liu87afc4c2024-08-14 17:33:45 +0800626{
627 LOGD("onReaderClosed()");
628 if (s_onReaderClosed != NULL && s_readerClosed == 0)
629 {
630
b.liub171c9a2024-11-12 19:23:29 +0800631 pthread_mutex_lock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800632
633 s_readerClosed = 1;
634
b.liub171c9a2024-11-12 19:23:29 +0800635 pthread_cond_signal(&s_commandcond[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800636
b.liub171c9a2024-11-12 19:23:29 +0800637 pthread_mutex_unlock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800638
639 s_onReaderClosed();
640 }
641}
642
b.liu06559f62024-11-01 18:48:22 +0800643typedef struct
644{
645 int cid;
646 bool act;
647 bool waitting;
648} info_cgact_wait_t;
649extern info_cgact_wait_t cgact_wait;
650
b.liu87afc4c2024-08-14 17:33:45 +0800651static void *readerLoop(void *arg)
652{
653 UNUSED(arg);
b.liu7ca612c2025-04-25 09:23:36 +0800654 ATPortId_enum *port = (ATPortId_enum*)arg;
b.liu87afc4c2024-08-14 17:33:45 +0800655 for (;;)
656 {
657 const char * line;
658
b.liub171c9a2024-11-12 19:23:29 +0800659 line = readline(*port);
b.liu87afc4c2024-08-14 17:33:45 +0800660
661 if (line == NULL)
662 {
b.liufd87baf2024-11-15 15:30:38 +0800663 //usleep(50000);
664 //continue;
q.huanged004222025-09-26 21:33:56 +0800665 LOGD("lynq read 1 port %d", *port);
b.liu87afc4c2024-08-14 17:33:45 +0800666 break;
667 }
668
669 if(strStartsWith(line, "MBTK_AT_READY")) {
670 //handleUnsolicited(line);
671 continue;
b.liu06559f62024-11-01 18:48:22 +0800672 } else if(strStartsWith(line, "CONNECT")) {
673 if(cgact_wait.waitting && cgact_wait.act) {
674 cgact_wait.waitting = false;
675 }
b.liu87afc4c2024-08-14 17:33:45 +0800676 }
677
678 if(isSMSUnsolicited(line))
679 {
680 char *line1;
681 const char *line2;
682
683 // The scope of string returned by 'readline()' is valid only
684 // till next call to 'readline()' hence making a copy of line
685 // before calling readline again.
686 line1 = strdup(line);
b.liub171c9a2024-11-12 19:23:29 +0800687 line2 = readline(*port);
b.liu87afc4c2024-08-14 17:33:45 +0800688
689 if (line2 == NULL)
690 {
691 free(line1);
692 break;
693 }
694
b.liu7ca612c2025-04-25 09:23:36 +0800695 if (s_unsolHandler[*port < ATPORTID_SIM2_0 ? MBTK_SIM_1 : MBTK_SIM_2] != NULL)
b.liu87afc4c2024-08-14 17:33:45 +0800696 {
b.liu7ca612c2025-04-25 09:23:36 +0800697 s_unsolHandler[*port < ATPORTID_SIM2_0 ? MBTK_SIM_1 : MBTK_SIM_2] (line1, line2);
b.liu87afc4c2024-08-14 17:33:45 +0800698 }
699 free(line1);
700 }
701 else
702 {
b.liub171c9a2024-11-12 19:23:29 +0800703 processLine(*port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800704 }
705 }
706
b.liub171c9a2024-11-12 19:23:29 +0800707 onReaderClosed(*port);
708
709 free(port);
b.liu87afc4c2024-08-14 17:33:45 +0800710
711 return NULL;
712}
713
714static void *readerUrcLoop(void *arg)
715{
716 UNUSED(arg);
b.liu7ca612c2025-04-25 09:23:36 +0800717 ATPortId_enum *port = (ATPortId_enum*)arg;
b.liu87afc4c2024-08-14 17:33:45 +0800718 for (;;)
719 {
720 const char *line;
721
b.liufd87baf2024-11-15 15:30:38 +0800722 line = readlineUrc(*port);
b.liu87afc4c2024-08-14 17:33:45 +0800723
724 if (line == NULL)
725 {
726 break;
727 }
728
b.liu7ca612c2025-04-25 09:23:36 +0800729 handleUnsolicited(*port, line);
b.liu87afc4c2024-08-14 17:33:45 +0800730 }
731
b.liub171c9a2024-11-12 19:23:29 +0800732 onReaderClosed(*port);
733
734 free(port);
b.liu87afc4c2024-08-14 17:33:45 +0800735
736 return NULL;
737}
738
739
740/**
741 * Sends string s to the radio with a \r appended.
742 * Returns AT_ERROR_* on error, 0 on success
743 *
744 * This function exists because as of writing, android libc does not
745 * have buffered stdio.
746 */
b.liu7ca612c2025-04-25 09:23:36 +0800747static int writeline (ATPortId_enum port, const char *s)
b.liu87afc4c2024-08-14 17:33:45 +0800748{
749 size_t cur = 0;
750 size_t len = strlen(s);
751 ssize_t written;
752
b.liub171c9a2024-11-12 19:23:29 +0800753 if (s_at_fd[port] < 0 || s_readerClosed > 0)
b.liu87afc4c2024-08-14 17:33:45 +0800754 {
q.huanged004222025-09-26 21:33:56 +0800755 LOGE("lynq 12, port %d %d %d",port,s_at_fd[port],s_readerClosed);
b.liu87afc4c2024-08-14 17:33:45 +0800756 return AT_ERROR_CHANNEL_CLOSED;
757 }
758
b.liufd87baf2024-11-15 15:30:38 +0800759 LOGD("[Port-%d]AT> %s", port, s);
b.liu87afc4c2024-08-14 17:33:45 +0800760
761 AT_DUMP( ">> ", s, strlen(s) );
762
b.liub171c9a2024-11-12 19:23:29 +0800763 memset(s_curr_at[port], 0x0, AT_BUFF_MAX);
764 memcpy(s_curr_at[port], s, strlen(s));
b.liu87afc4c2024-08-14 17:33:45 +0800765
766 /* the main string */
767 while (cur < len)
768 {
769 do
770 {
b.liub171c9a2024-11-12 19:23:29 +0800771 written = write (s_at_fd[port], s + cur, len - cur);
b.liu87afc4c2024-08-14 17:33:45 +0800772 }
773 while (written < 0 && errno == EINTR);
774
775 if (written < 0)
776 {
777 return AT_ERROR_GENERIC;
778 }
779
780 cur += written;
781 }
782
783 /* the \r */
784
785 do
786 {
b.liub171c9a2024-11-12 19:23:29 +0800787 written = write (s_at_fd[port], "\r", 1);
b.liu87afc4c2024-08-14 17:33:45 +0800788 }
789 while ((written < 0 && errno == EINTR) || (written == 0));
790
791 if (written < 0)
792 {
793 return AT_ERROR_GENERIC;
794 }
795
796 return 0;
797}
798
b.liu7ca612c2025-04-25 09:23:36 +0800799static int writeCtrlZ (ATPortId_enum port, const char *s)
b.liu87afc4c2024-08-14 17:33:45 +0800800{
801 size_t cur = 0;
802 size_t len = strlen(s);
803 ssize_t written;
804
b.liub171c9a2024-11-12 19:23:29 +0800805 if (s_at_fd[port] < 0 || s_readerClosed > 0)
b.liu87afc4c2024-08-14 17:33:45 +0800806 {
807 return AT_ERROR_CHANNEL_CLOSED;
808 }
809
810 LOGD("AT> %s^Z\n", s);
811
812 AT_DUMP( ">* ", s, strlen(s) );
813
814 /* the main string */
815 while (cur < len)
816 {
817 do
818 {
b.liub171c9a2024-11-12 19:23:29 +0800819 written = write (s_at_fd[port], s + cur, len - cur);
b.liu87afc4c2024-08-14 17:33:45 +0800820 }
821 while (written < 0 && errno == EINTR);
822
823 if (written < 0)
824 {
825 return AT_ERROR_GENERIC;
826 }
827
828 cur += written;
829 }
830
831 /* the ^Z */
832
833 do
834 {
b.liub171c9a2024-11-12 19:23:29 +0800835 written = write (s_at_fd[port], "\032", 1);
b.liu87afc4c2024-08-14 17:33:45 +0800836 }
837 while ((written < 0 && errno == EINTR) || (written == 0));
838
839 if (written < 0)
840 {
841 return AT_ERROR_GENERIC;
842 }
843
844 return 0;
845}
846
b.liu7ca612c2025-04-25 09:23:36 +0800847static void clearPendingCommand(ATPortId_enum port)
b.liu87afc4c2024-08-14 17:33:45 +0800848{
b.liub171c9a2024-11-12 19:23:29 +0800849 if (sp_response[port] != NULL)
b.liu87afc4c2024-08-14 17:33:45 +0800850 {
b.liub171c9a2024-11-12 19:23:29 +0800851 at_response_free(sp_response[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800852 }
853
b.liub171c9a2024-11-12 19:23:29 +0800854 sp_response[port] = NULL;
855 s_responsePrefix[port] = NULL;
856 s_smsPDU[port] = NULL;
b.liu87afc4c2024-08-14 17:33:45 +0800857}
858
859
860/**
861 * Starts AT handler on stream "fd'
862 * returns 0 on success, -1 on error
863 */
b.liu7ca612c2025-04-25 09:23:36 +0800864int at_open(ATPortId_enum port, int at_fd, int uart_fd, ATUnsolHandler h)
b.liu87afc4c2024-08-14 17:33:45 +0800865{
866 int ret;
867 pthread_attr_t attr;
868
b.liub171c9a2024-11-12 19:23:29 +0800869 s_at_fd[port] = at_fd;
b.liu7ca612c2025-04-25 09:23:36 +0800870 s_uart_fd[port < ATPORTID_SIM2_0 ? MBTK_SIM_1 : MBTK_SIM_2] = uart_fd;
871 s_unsolHandler[port < ATPORTID_SIM2_0 ? MBTK_SIM_1 : MBTK_SIM_2] = h;
b.liu87afc4c2024-08-14 17:33:45 +0800872 s_readerClosed = 0;
b.liub171c9a2024-11-12 19:23:29 +0800873 s_responsePrefix[port] = NULL;
874 s_smsPDU[port] = NULL;
875 sp_response[port] = NULL;
q.huanged004222025-09-26 21:33:56 +0800876 pthread_mutex_init(&s_commandmutex[port], NULL);
877 pthread_cond_init(&(s_commandcond[port]), NULL);
878 at_state_set(port,RIL_AT_STATE_READY);
b.liub171c9a2024-11-12 19:23:29 +0800879
b.liu7ca612c2025-04-25 09:23:36 +0800880 ATPortId_enum *at_port_ptr = (ATPortId_enum*)malloc(sizeof(ATPortId_enum));
881 ATPortId_enum *urc_port_ptr = (ATPortId_enum*)malloc(sizeof(ATPortId_enum));
b.liub171c9a2024-11-12 19:23:29 +0800882 *at_port_ptr = port;
883 *urc_port_ptr = port;
b.liu87afc4c2024-08-14 17:33:45 +0800884
885 pthread_attr_init (&attr);
886 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
b.liub171c9a2024-11-12 19:23:29 +0800887 ret = pthread_create(&s_tid_reader[port], &attr, readerLoop, at_port_ptr);
b.liu87afc4c2024-08-14 17:33:45 +0800888 if (ret < 0)
889 {
890 LOGE("AT thread create fail.");
891 return -1;
892 }
893
b.liu7ca612c2025-04-25 09:23:36 +0800894 if(port == ATPORTID_SIM1_0 || port == ATPORTID_SIM2_0) { // URC only for ATPORTTYPE_0
b.liufd87baf2024-11-15 15:30:38 +0800895 pthread_t uart_tid_reader;
896 ret = pthread_create(&uart_tid_reader, &attr, readerUrcLoop, urc_port_ptr);
897 if (ret < 0)
898 {
899 LOGE("Uart thread create fail.");
900 return -1;
901 }
b.liu87afc4c2024-08-14 17:33:45 +0800902 }
903
904 return 0;
905}
906
907/* FIXME is it ok to call this from the reader and the command thread? */
b.liu7ca612c2025-04-25 09:23:36 +0800908void at_close(ATPortId_enum port)
b.liu87afc4c2024-08-14 17:33:45 +0800909{
910 LOGD("at_close()");
b.liub171c9a2024-11-12 19:23:29 +0800911 if (s_at_fd[port] >= 0)
b.liu87afc4c2024-08-14 17:33:45 +0800912 {
b.liub171c9a2024-11-12 19:23:29 +0800913 close(s_at_fd[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800914 }
b.liu7ca612c2025-04-25 09:23:36 +0800915 if (s_uart_fd[port < ATPORTID_SIM2_0 ? MBTK_SIM_1 : MBTK_SIM_2] >= 0)
b.liu87afc4c2024-08-14 17:33:45 +0800916 {
b.liu7ca612c2025-04-25 09:23:36 +0800917 close(s_uart_fd[port < ATPORTID_SIM2_0 ? MBTK_SIM_1 : MBTK_SIM_2]);
b.liu87afc4c2024-08-14 17:33:45 +0800918 }
b.liub171c9a2024-11-12 19:23:29 +0800919 s_at_fd[port] = -1;
b.liu7ca612c2025-04-25 09:23:36 +0800920 s_uart_fd[port < ATPORTID_SIM2_0 ? MBTK_SIM_1 : MBTK_SIM_2] = -1;
b.liu87afc4c2024-08-14 17:33:45 +0800921
b.liub171c9a2024-11-12 19:23:29 +0800922 pthread_mutex_lock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800923 s_readerClosed = 1;
b.liub171c9a2024-11-12 19:23:29 +0800924 pthread_cond_signal(&s_commandcond[port]);
925 pthread_mutex_unlock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +0800926 /* the reader thread should eventually die */
927
b.liub171c9a2024-11-12 19:23:29 +0800928 at_state[port] = RIL_AT_STATE_CLOSED;
b.liu87afc4c2024-08-14 17:33:45 +0800929}
930
931static ATResponse * at_response_new()
932{
933 return (ATResponse *) calloc(1, sizeof(ATResponse));
934}
935
936void at_response_free(ATResponse *p_response)
937{
938 ATLine *p_line;
939
940 if (p_response == NULL) return;
941
942 p_line = p_response->p_intermediates;
943
944 while (p_line != NULL)
945 {
946 ATLine *p_toFree;
947
948 p_toFree = p_line;
949 p_line = p_line->p_next;
950
951 free(p_toFree->line);
952 free(p_toFree);
953 }
954
955 free (p_response->finalResponse);
956 free (p_response);
957}
958
959/**
960 * The line reader places the intermediate responses in reverse order
961 * here we flip them back
962 */
963static void reverseIntermediates(ATResponse *p_response)
964{
965 ATLine *pcur,*pnext;
966
967 pcur = p_response->p_intermediates;
968 p_response->p_intermediates = NULL;
969
970 while (pcur != NULL)
971 {
972 pnext = pcur->p_next;
973 pcur->p_next = p_response->p_intermediates;
974 p_response->p_intermediates = pcur;
975 pcur = pnext;
976 }
977}
978
979static long long at_timeout_get(const char *at_command, bool *timeout_close)
980{
q.huangda36fec2025-09-29 20:04:19 +0800981 long long timeout = 0;
b.liu87afc4c2024-08-14 17:33:45 +0800982 int i;
983 for(i = 0; i < ARRAY_SIZE(at_timeout_list); i++)
984 {
985 if(!strncasecmp(at_command, at_timeout_list[i].at_command, strlen(at_timeout_list[i].at_command)))
986 {
987 timeout = at_timeout_list[i].timeout;
988 *timeout_close = at_timeout_list[i].timeout_close;
989 break;
990 }
991 }
992
993 return timeout;
994}
995
996/**
997 * Internal send_command implementation
998 * Doesn't lock or call the timeout callback
999 *
1000 * timeoutMsec == 0 means infinite timeout
1001 */
b.liu7ca612c2025-04-25 09:23:36 +08001002static int at_send_command_full_nolock (ATPortId_enum port, const char *command, ATCommandType type,
b.liu87afc4c2024-08-14 17:33:45 +08001003 const char *responsePrefix, const char *smspdu,
1004 long long timeoutMsec, ATResponse **pp_outResponse)
1005{
1006 int err = 0;
1007 bool tiemout_close = true;
1008 struct timespec ts;
q.huanged004222025-09-26 21:33:56 +08001009
1010 LOGD("lynq 9, port %d %d",port,at_state[port]);
1011 if(sp_response[port] != NULL)
1012 {
1013 LOGE("lynq 10, port %d %p",port,sp_response[port]);
1014 err = AT_ERROR_COMMAND_PENDING;
1015 return err;
1016 }
1017
b.liub171c9a2024-11-12 19:23:29 +08001018 if(at_state[port] == RIL_AT_STATE_READY)
1019 at_state[port] = RIL_AT_STATE_BUSY;
b.liu87afc4c2024-08-14 17:33:45 +08001020
q.huanged004222025-09-26 21:33:56 +08001021 LOGD("lynq 11, port %d",port);
b.liu87afc4c2024-08-14 17:33:45 +08001022
b.liub171c9a2024-11-12 19:23:29 +08001023 s_type[port] = type;
1024 s_responsePrefix[port] = responsePrefix;
1025 s_smsPDU[port] = smspdu;
1026 sp_response[port] = at_response_new();
b.liu87afc4c2024-08-14 17:33:45 +08001027
1028 if(timeoutMsec == 0)
1029 {
1030 timeoutMsec = at_timeout_get(command, &tiemout_close);
1031 }
q.huanged004222025-09-26 21:33:56 +08001032 err = writeline (port, command);
1033
1034 if (err < 0)
1035 {
1036 goto error;
1037 }
b.liu87afc4c2024-08-14 17:33:45 +08001038
1039 if (timeoutMsec != 0)
1040 {
1041 setTimespecRelative(&ts, timeoutMsec);
1042 }
1043
q.huanged004222025-09-26 21:33:56 +08001044 LOGD("lynq before loop, port %d %d",port,s_readerClosed);
b.liub171c9a2024-11-12 19:23:29 +08001045 while (sp_response[port]->finalResponse == NULL && s_readerClosed == 0)
b.liu87afc4c2024-08-14 17:33:45 +08001046 {
1047 //LOGD("AT wait time:%lld",timeoutMsec);
1048 if (timeoutMsec != 0)
1049 {
q.huanged004222025-09-26 21:33:56 +08001050 LOGD("lynq 12, port %d %lld",port,timeoutMsec);
b.liub171c9a2024-11-12 19:23:29 +08001051 err = pthread_cond_timedwait(&s_commandcond[port], &s_commandmutex[port], &ts);
b.liu87afc4c2024-08-14 17:33:45 +08001052 }
1053 else
1054 {
q.huanged004222025-09-26 21:33:56 +08001055 LOGD("lynq 13, port %d",port);
b.liub171c9a2024-11-12 19:23:29 +08001056 err = pthread_cond_wait(&s_commandcond[port], &s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001057 }
1058
1059 //LOGD("AT continue:err - %d",err);
1060 if (err == ETIMEDOUT)
1061 {
1062 if(tiemout_close)
1063 {
q.huanged004222025-09-26 21:33:56 +08001064 LOGE("lynq 15, port %d",port);
b.liu87afc4c2024-08-14 17:33:45 +08001065 err = AT_ERROR_TIMEOUT_CLOSE;
1066 }
1067 else
1068 {
q.huanged004222025-09-26 21:33:56 +08001069 LOGE("lynq 16, port %d",port);
b.liu87afc4c2024-08-14 17:33:45 +08001070 err = AT_ERROR_TIMEOUT;
1071 }
1072 goto error;
1073 }
1074 }
1075
1076 if (pp_outResponse == NULL)
1077 {
q.huanged004222025-09-26 21:33:56 +08001078 LOGD("lynq 18, port %d",port);
b.liub171c9a2024-11-12 19:23:29 +08001079 at_response_free(sp_response[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001080 }
1081 else
1082 {
q.huanged004222025-09-26 21:33:56 +08001083 LOGD("lynq 19, port %d",port);
b.liu87afc4c2024-08-14 17:33:45 +08001084 /* line reader stores intermediate responses in reverse order */
b.liub171c9a2024-11-12 19:23:29 +08001085 reverseIntermediates(sp_response[port]);
1086 *pp_outResponse = sp_response[port];
b.liu87afc4c2024-08-14 17:33:45 +08001087 }
1088
q.huanged004222025-09-26 21:33:56 +08001089
b.liub171c9a2024-11-12 19:23:29 +08001090 sp_response[port] = NULL;
b.liu87afc4c2024-08-14 17:33:45 +08001091
1092 if(s_readerClosed > 0)
1093 {
q.huanged004222025-09-26 21:33:56 +08001094
1095 LOGE("lynq 21, port %d %d",port,s_readerClosed);
b.liu87afc4c2024-08-14 17:33:45 +08001096 err = AT_ERROR_CHANNEL_CLOSED;
1097 goto error;
1098 }
q.huanged004222025-09-26 21:33:56 +08001099 LOGD("lynq 22, port %d",port);
b.liu87afc4c2024-08-14 17:33:45 +08001100
1101 err = 0;
1102error:
b.liub171c9a2024-11-12 19:23:29 +08001103 if(at_state[port] == RIL_AT_STATE_BUSY)
1104 at_state[port] = RIL_AT_STATE_READY;
q.huanged004222025-09-26 21:33:56 +08001105 LOGD("lynq 23, port %d %d",port, at_state[port]);
b.liub171c9a2024-11-12 19:23:29 +08001106 clearPendingCommand(port);
b.liu87afc4c2024-08-14 17:33:45 +08001107 return err;
1108}
1109
1110/**
1111 * Internal send_command implementation
1112 *
1113 * timeoutMsec == 0 means infinite timeout
1114 */
b.liu7ca612c2025-04-25 09:23:36 +08001115static int at_send_command_full (ATPortId_enum port, const char *command, ATCommandType type,
b.liu87afc4c2024-08-14 17:33:45 +08001116 const char *responsePrefix, const char *smspdu,
1117 long long timeoutMsec, ATResponse **pp_outResponse)
1118{
1119 int err;
1120
q.huanged004222025-09-26 21:33:56 +08001121
1122 LOGD("lynq 0, port %d,%lld,%s",port,timeoutMsec,command);
b.liub171c9a2024-11-12 19:23:29 +08001123 if (0 != pthread_equal(s_tid_reader[port], pthread_self()))
b.liu87afc4c2024-08-14 17:33:45 +08001124 {
1125 /* cannot be called from reader thread */
1126 LOGE("cannot be called from reader thread.");
1127 return AT_ERROR_INVALID_THREAD;
1128 }
1129
q.huanged004222025-09-26 21:33:56 +08001130 LOGD("lynq 1, port %d",port);
1131
b.liu87afc4c2024-08-14 17:33:45 +08001132 // Waitting for previous AT complete.
q.huanged004222025-09-26 21:33:56 +08001133 int count=0;
b.liub171c9a2024-11-12 19:23:29 +08001134 while(at_state[port] == RIL_AT_STATE_BUSY)
b.liu87afc4c2024-08-14 17:33:45 +08001135 {
q.huanged004222025-09-26 21:33:56 +08001136 sleep(1);
1137 count++;
1138 if(count%2==0)
1139 {
1140 LOGE("lynq 2, port %d",port);
1141 }
1142
1143 if(count==8)
1144 {
1145 err= AT_ERROR_COMMAND_PENDING;
1146 goto out;
1147 }
b.liu87afc4c2024-08-14 17:33:45 +08001148 }
1149
q.huanged004222025-09-26 21:33:56 +08001150 LOGD("lynq 3, port %d",port);
b.liub171c9a2024-11-12 19:23:29 +08001151 pthread_mutex_lock(&s_commandmutex[port]);
q.huanged004222025-09-26 21:33:56 +08001152 LOGD("lynq 4, port %d",port);
b.liu87afc4c2024-08-14 17:33:45 +08001153
b.liub171c9a2024-11-12 19:23:29 +08001154 err = at_send_command_full_nolock(port, command, type,
b.liu87afc4c2024-08-14 17:33:45 +08001155 responsePrefix, smspdu,
1156 timeoutMsec, pp_outResponse);
1157
q.huanged004222025-09-26 21:33:56 +08001158 LOGD("lynq 5, port %d",port);
b.liub171c9a2024-11-12 19:23:29 +08001159 pthread_mutex_unlock(&s_commandmutex[port]);
q.huanged004222025-09-26 21:33:56 +08001160 LOGD("lynq 6, port %d",port);
b.liu87afc4c2024-08-14 17:33:45 +08001161
1162 if (err == AT_ERROR_TIMEOUT_CLOSE && s_onTimeout != NULL)
1163 {
q.huanged004222025-09-26 21:33:56 +08001164 LOGE("lynq 7, port %d",port);
b.liu87afc4c2024-08-14 17:33:45 +08001165 s_onTimeout();
1166 }
q.huanged004222025-09-26 21:33:56 +08001167 LOGD("lynq 8, port %d",port);
b.liu87afc4c2024-08-14 17:33:45 +08001168
q.huanged004222025-09-26 21:33:56 +08001169out:
b.liu87afc4c2024-08-14 17:33:45 +08001170 return err;
1171}
1172
1173
1174/**
1175 * Issue a single normal AT command with no intermediate response expected
1176 *
1177 * "command" should not include \r
1178 * pp_outResponse can be NULL
1179 *
1180 * if non-NULL, the resulting ATResponse * must be eventually freed with
1181 * at_response_free
1182 */
b.liu7ca612c2025-04-25 09:23:36 +08001183int at_send_command (ATPortId_enum port, const char *command, ATResponse **pp_outResponse)
b.liu87afc4c2024-08-14 17:33:45 +08001184{
b.liub171c9a2024-11-12 19:23:29 +08001185 return at_send_command_full (port, command, NO_RESULT, NULL,
b.liu87afc4c2024-08-14 17:33:45 +08001186 NULL, 0, pp_outResponse);
1187}
1188
1189
b.liu7ca612c2025-04-25 09:23:36 +08001190int at_send_command_singleline (ATPortId_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001191 const char *responsePrefix,
1192 ATResponse **pp_outResponse)
1193{
1194 int err;
1195
b.liub171c9a2024-11-12 19:23:29 +08001196 err = at_send_command_full (port, command, SINGLELINE, responsePrefix,
b.liu87afc4c2024-08-14 17:33:45 +08001197 NULL, 0, pp_outResponse);
1198
1199 if (err == 0 && pp_outResponse != NULL
1200 && (*pp_outResponse)->success > 0
1201 && (*pp_outResponse)->p_intermediates == NULL
1202 )
1203 {
1204 /* successful command must have an intermediate response */
1205 at_response_free(*pp_outResponse);
1206 *pp_outResponse = NULL;
1207 return AT_ERROR_INVALID_RESPONSE;
1208 }
1209
1210 return err;
1211}
1212
b.liu7ca612c2025-04-25 09:23:36 +08001213int at_send_command_singleline_with_timeout (ATPortId_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001214 const char *responsePrefix,
1215 ATResponse **pp_outResponse,long long timeoutMsec)
1216{
1217 int err;
1218
b.liub171c9a2024-11-12 19:23:29 +08001219 err = at_send_command_full (port, command, SINGLELINE, responsePrefix,
b.liu87afc4c2024-08-14 17:33:45 +08001220 NULL, timeoutMsec, pp_outResponse);
1221
1222 if (err == 0 && pp_outResponse != NULL
1223 && (*pp_outResponse)->success > 0
1224 && (*pp_outResponse)->p_intermediates == NULL
1225 )
1226 {
1227 /* successful command must have an intermediate response */
1228 at_response_free(*pp_outResponse);
1229 *pp_outResponse = NULL;
1230 return AT_ERROR_INVALID_RESPONSE;
1231 }
1232
1233 return err;
1234}
1235
1236
1237
b.liu7ca612c2025-04-25 09:23:36 +08001238int at_send_command_numeric (ATPortId_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001239 ATResponse **pp_outResponse)
1240{
1241 int err;
1242
b.liub171c9a2024-11-12 19:23:29 +08001243 err = at_send_command_full (port, command, NUMERIC, NULL,
b.liu87afc4c2024-08-14 17:33:45 +08001244 NULL, 0, pp_outResponse);
1245
1246 if (err == 0 && pp_outResponse != NULL
1247 && (*pp_outResponse)->success > 0
1248 && (*pp_outResponse)->p_intermediates == NULL
1249 )
1250 {
1251 /* successful command must have an intermediate response */
1252 at_response_free(*pp_outResponse);
1253 *pp_outResponse = NULL;
1254 return AT_ERROR_INVALID_RESPONSE;
1255 }
1256
1257 return err;
1258}
1259
1260
b.liu7ca612c2025-04-25 09:23:36 +08001261int at_send_command_sms (ATPortId_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001262 const char *pdu,
1263 const char *responsePrefix,
1264 ATResponse **pp_outResponse)
1265{
1266 int err;
1267
b.liub171c9a2024-11-12 19:23:29 +08001268 err = at_send_command_full (port, command, SINGLELINE, responsePrefix,
b.liu87afc4c2024-08-14 17:33:45 +08001269 pdu, 0, pp_outResponse);
1270
1271 if (err == 0 && pp_outResponse != NULL
1272 && (*pp_outResponse)->success > 0
1273 && (*pp_outResponse)->p_intermediates == NULL
1274 )
1275 {
1276 /* successful command must have an intermediate response */
1277 at_response_free(*pp_outResponse);
1278 *pp_outResponse = NULL;
1279 return AT_ERROR_INVALID_RESPONSE;
1280 }
1281
1282 return err;
1283}
1284
1285
b.liu7ca612c2025-04-25 09:23:36 +08001286int at_send_command_multiline (ATPortId_enum port, const char *command,
b.liu87afc4c2024-08-14 17:33:45 +08001287 const char *responsePrefix,
1288 ATResponse **pp_outResponse)
1289{
1290 int err;
1291
b.liub171c9a2024-11-12 19:23:29 +08001292 err = at_send_command_full (port, command, MULTILINE, responsePrefix,
b.liu87afc4c2024-08-14 17:33:45 +08001293 NULL, 0, pp_outResponse);
1294
1295 return err;
1296}
1297
1298
1299/** This callback is invoked on the command thread */
1300void at_set_on_timeout(void (*onTimeout)(void))
1301{
1302 s_onTimeout = onTimeout;
1303}
1304
1305/**
1306 * This callback is invoked on the reader thread (like ATUnsolHandler)
1307 * when the input stream closes before you call at_close
1308 * (not when you call at_close())
1309 * You should still call at_close()
1310 */
1311
1312void at_set_on_reader_closed(void (*onClose)(void))
1313{
1314 s_onReaderClosed = onClose;
1315}
1316
1317
1318/**
1319 * Periodically issue an AT command and wait for a response.
1320 * Used to ensure channel has start up and is active
1321 */
b.liu7ca612c2025-04-25 09:23:36 +08001322int at_handshake(ATPortId_enum port)
b.liu87afc4c2024-08-14 17:33:45 +08001323{
b.liu62240ee2024-11-07 17:52:45 +08001324// int i;
b.liu87afc4c2024-08-14 17:33:45 +08001325 int err = 0;
1326
b.liub171c9a2024-11-12 19:23:29 +08001327 if (0 != pthread_equal(s_tid_reader[port], pthread_self()))
b.liu87afc4c2024-08-14 17:33:45 +08001328 {
1329 /* cannot be called from reader thread */
1330 return AT_ERROR_INVALID_THREAD;
1331 }
b.liub171c9a2024-11-12 19:23:29 +08001332 pthread_mutex_lock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001333
1334#if 0
1335 for (i = 0 ; i < HANDSHAKE_RETRY_COUNT ; i++)
1336 {
1337 /* some stacks start with verbose off */
1338 err = at_send_command_full_nolock("ATE0Q0V1", NO_RESULT,
1339 NULL, NULL, HANDSHAKE_TIMEOUT_MSEC, NULL);
1340
1341 if (err == 0)
1342 {
1343 break;
1344 }
1345 }
1346#else
b.liub171c9a2024-11-12 19:23:29 +08001347 err = at_send_command_full_nolock(port, "ATE0Q0V1", NO_RESULT,
b.liu87afc4c2024-08-14 17:33:45 +08001348 NULL, NULL, 0, NULL);
1349#endif
1350
1351 if (err == 0)
1352 {
1353 /* pause for a bit to let the input buffer drain any unmatched OK's
1354 (they will appear as extraneous unsolicited responses) */
1355 sleepMsec(HANDSHAKE_TIMEOUT_MSEC);
1356 }
1357
b.liub171c9a2024-11-12 19:23:29 +08001358 pthread_mutex_unlock(&s_commandmutex[port]);
b.liu87afc4c2024-08-14 17:33:45 +08001359
1360
1361 return err;
1362}
1363
1364/**
1365 * Returns error code from response
1366 * Assumes AT+CMEE=1 (numeric) mode
1367 */
b.liudeb8e422024-12-14 17:36:56 +08001368AT_CME_Error at_get_cme_error(const ATResponse *p_response)
b.liu87afc4c2024-08-14 17:33:45 +08001369{
1370 int ret;
1371 int err;
1372 char *p_cur;
1373
b.liub6180902025-07-02 18:48:23 +08001374 if (p_response == NULL)
1375 {
1376 return CME_ERROR_NON_CME;
1377 }
1378
b.liu87afc4c2024-08-14 17:33:45 +08001379 if (p_response->success > 0)
1380 {
1381 return CME_SUCCESS;
1382 }
1383
1384 if (p_response->finalResponse == NULL
1385 || !strStartsWith(p_response->finalResponse, "+CME ERROR:")
1386 )
1387 {
1388 return CME_ERROR_NON_CME;
1389 }
1390
1391 p_cur = p_response->finalResponse;
1392 err = at_tok_start(&p_cur);
1393
1394 if (err < 0)
1395 {
1396 return CME_ERROR_NON_CME;
1397 }
1398
1399 err = at_tok_nextint(&p_cur, &ret);
1400
1401 if (err < 0)
1402 {
1403 return CME_ERROR_NON_CME;
1404 }
1405
1406 return ret;
1407}
1408
b.liu7ca612c2025-04-25 09:23:36 +08001409mbtk_ril_at_state_enum at_state_get(ATPortId_enum port)
b.liu87afc4c2024-08-14 17:33:45 +08001410{
b.liub171c9a2024-11-12 19:23:29 +08001411 return at_state[port];
b.liu87afc4c2024-08-14 17:33:45 +08001412}
1413
b.liu7ca612c2025-04-25 09:23:36 +08001414void at_state_set(ATPortId_enum port, mbtk_ril_at_state_enum state)
b.liu87afc4c2024-08-14 17:33:45 +08001415{
b.liub171c9a2024-11-12 19:23:29 +08001416 at_state[port] = state;
b.liu87afc4c2024-08-14 17:33:45 +08001417}
1418
1419bool at_rsp_check(ATResponse *p_response)
1420{
1421 if(!p_response || !p_response->success)
1422 return false;
1423
1424 return true;
1425}
1426
b.liu7ca612c2025-04-25 09:23:36 +08001427void unused_func(ATPortId_enum port)
b.liu87afc4c2024-08-14 17:33:45 +08001428{
b.liub171c9a2024-11-12 19:23:29 +08001429 isFinalResponse(port, NULL);
b.liu87afc4c2024-08-14 17:33:45 +08001430}
1431