blob: 7abba8a0b1a03669b039b8c4f3e43c33a1a1af7c [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/* Copyright Statement:
2 *
3 * This software/firmware and related documentation ("MediaTek Software") are
4 * protected under relevant copyright laws. The information contained herein
5 * is confidential and proprietary to MediaTek Inc. and/or its licensors.
6 * Without the prior written permission of MediaTek inc. and/or its licensors,
7 * any reproduction, modification, use or disclosure of MediaTek Software,
8 * and information contained herein, in whole or in part, shall be strictly prohibited.
9 *
10 * MediaTek Inc. (C) 2016. All rights reserved.
11 *
12 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
13 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
14 * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
15 * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
18 * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
19 * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
20 * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
21 * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
22 * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
23 * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
24 * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
25 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
26 * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
27 * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
28 * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
29 * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
30 *
31 * The following software/firmware and/or related documentation ("MediaTek Software")
32 * have been modified by MediaTek Inc. All revisions are subject to any receiver's
33 * applicable license agreements with MediaTek Inc.
34 */
35
36#include "../util/AtLine.h"
37
38#include <assert.h>
39
40#include "../util/Misc.h"
41
42#define RFX_LOG_TAG "RfxAtLine"
43
44static const char *s_finalResponsesSuccess[] = { "OK", "CONNECT" /* some stacks start up data on another channel */
45};
46
47/**
48 * returns 1 if line is a final response indicating error
49 * See 27.007 annex B
50 * WARNING: NO CARRIER and others are sometimes unsolicited
51 */
52static const char *s_finalResponsesError[] = { "ERROR", "+CMS ERROR:",
53 "+CME ERROR:", "NO CARRIER", /* sometimes! */
54 "NO ANSWER", "NO DIALTONE", "+C2K ERROR:", "+EC2KCME ERROR", /* for distinguish CME error between MD1 and MD3 */
55};
56
57/**
58 * returns 1 if line is a intermediate response
59 * Such as
60 * AT+CMGW <CR>
61 * >XXXXXX <CTRL+Z> or <ESC>
62 * OK
63 * WARNING: NO CARRIER and others are sometimes unsolicited
64 */
65static const char *s_IntermediatePattern[] = { "> ", };
66
67static const char *s_finalResponsesSuccessInNumeric[] = { "0", "1", };
68
69static const char *s_finalResponsesErrorInNumeric[] = { "2", "3", "4", "6", "7",
70 "8", "+CMS ERROR:", "+CME ERROR:", "+C2K ERROR:", };
71
72static const char *s_ackResponse[] = { "ACK" };
73
74AtLine::AtLine(const AtLine &other) {
75 // Only copy THIS node
76 assert(other.m_pNext == NULL);
77
78 m_line = (char *) calloc(strlen(other.m_line) + 1, sizeof(char));
79 if (m_line == NULL) {
80 //RFX_LOG_E(RFX_LOG_TAG, "OOM");
81 m_pNext = NULL;
82 m_pCur = NULL;
83 return;
84 }
85 memcpy(m_line, other.m_line, strlen(other.m_line));
86 m_line[strlen(other.m_line)] = '\0';
87 m_pNext = NULL;
88
89 // initialize p_cur
90 m_pCur = m_line;
91}
92
93AtLine::AtLine(const char* line, AtLine* next) {
94 m_line = (char *) calloc(strlen(line) + 1, sizeof(char));
95 if (m_line == NULL) {
96 //RFX_LOG_E(RFX_LOG_TAG, "OOM");
97 m_pNext = NULL;
98 m_pCur = NULL;
99 return;
100 }
101 memcpy(m_line, line, strlen(line));
102 m_line[strlen(line)] = '\0';
103 m_pNext = next;
104
105 // initialize p_cur
106 m_pCur = m_line;
107}
108
109AtLine::~AtLine() {
110 if (m_pNext) {
111 delete (m_pNext);
112 }
113
114 m_pCur = NULL;
115 if (m_line) {
116 free(m_line);
117 }
118}
119
120/**
121 * Starts tokenizing an AT response string
122 * Set err to -1 if this is not a valid response string, 0 on success.
123 * updates m_pCur with current position
124 */
125void AtLine::atTokStart(int *err) {
126 *err = 0;
127 m_pCur = m_line;
128 if (m_pCur == NULL) {
129 *err = -1;
130 return;
131 }
132
133 // skip prefix
134 // consume "^[^:]:"
135
136 m_pCur = strchr(m_pCur, ':');
137
138 if (m_pCur == NULL) {
139 *err = -1;
140 return;
141 }
142
143 m_pCur++;
144}
145
146char* AtLine::atTokChar(int *err) {
147 *err = 0;
148 if (m_pCur == NULL) {
149 *err = -1;
150 return NULL;
151 }
152 m_pCur = strchr(m_pCur, '(');
153
154 if (m_pCur == NULL) {
155 *err = -1;
156 return NULL;
157 }
158
159 return (m_pCur++);
160}
161
162void AtLine::skipWhiteSpace() {
163 if (m_pCur == NULL)
164 return;
165
166 while (*m_pCur != '\0' && isspace(*m_pCur)) {
167 m_pCur++;
168 }
169}
170
171void AtLine::skipNextComma() {
172 if (m_pCur == NULL)
173 return;
174
175 while (*m_pCur != '\0' && *m_pCur != ',') {
176 m_pCur++;
177 }
178
179 if (*m_pCur == ',') {
180 m_pCur++;
181 }
182}
183
184char* AtLine::nextTok() {
185 char *ret;
186
187 skipWhiteSpace();
188
189 if (m_pCur == NULL) {
190 ret = NULL;
191 } else if (*m_pCur == '"') {
192 m_pCur++;
193 ret = strsep(&m_pCur, "\"");
194 skipNextComma();
195 } else if (*m_pCur == '(' && *(m_pCur + 1) == '"') {
196 m_pCur = m_pCur + 2;
197 ret = strsep(&m_pCur, "\"");
198 skipNextComma();
199 } else {
200 ret = strsep(&m_pCur, ",");
201 }
202
203 return ret;
204}
205
206/**
207 * Parses the next integer in the AT response line and places it in *p_out
208 * Set err to 0 on success and -1 on fail
209 * updates m_pCur
210 * "base" is the same as the base param in strtol
211 */
212
213int AtLine::atTokNextintBase(int base, int uns, int *err) {
214 int out;
215 char *ret;
216 *err = 0;
217
218 if (m_pCur == NULL) {
219 *err = -1;
220 return 0;
221 }
222
223 ret = nextTok();
224
225 if (ret == NULL) {
226 *err = -1;
227 return 0;
228 } else {
229 long l;
230 char *end;
231
232 if (uns)
233 l = strtoul(ret, &end, base);
234 else
235 l = strtol(ret, &end, base);
236
237 out = (int) l;
238
239 if (end == ret) {
240 *err = -1;
241 return 0;
242 }
243 return out;
244 }
245}
246
247/**
248 * Parses the next base 10 integer in the AT response line
249 * and places it in *p_out
250 * Set err to 0 on success and -1 on fail
251 * updates m_pCur
252 */
253int AtLine::atTokNextint(int *err) {
254 return atTokNextintBase(10, 0, err);
255}
256
257/**
258 * Parses the next base 16 integer in the AT response line
259 * and places it in *p_out
260 * Set err to 0 on success and -1 on fail
261 * updates m_pCur
262 */
263int AtLine::atTokNexthexint(int *err) {
264 return atTokNextintBase(16, 1, err);
265}
266
267bool AtLine::atTokNextbool(int *err) {
268 int result;
269
270 result = atTokNextint(err);
271
272 if (*err < 0) {
273 *err = -1;
274 return false;
275 }
276
277 // booleans should be 0 or 1
278 if (!(result == 0 || result == 1)) {
279 *err = -1;
280 return false;
281 }
282
283 return result ? true : false;
284}
285
286char* AtLine::atTokNextstr(int *err) {
287 *err = 0;
288 if (m_pCur == NULL) {
289 *err = -1;
290 return NULL;
291 }
292
293 return nextTok();
294}
295
296/** returns 1 on "has more tokens" and 0 if no */
297int AtLine::atTokHasmore() {
298 return !(m_pCur == NULL || *m_pCur == '\0');
299}
300
301/// M: eMBMS feature
302void AtLine::atTokEqual(int *err) {
303 *err = 0;
304 m_pCur = m_line;
305 if (m_pCur == NULL) {
306 *err = -1;
307 return;
308 }
309
310 // skip prefix
311 // consume "^[^=]:"
312
313 m_pCur = strchr(m_pCur, '=');
314
315 if (m_pCur == NULL) {
316 *err = -1;
317 return;
318 }
319
320 m_pCur++;
321}
322
323/**
324 * Parses the next long long in the AT response line and places it in *p_out
325 * Set err to 0 on success and -1 on fail
326 * updates m_pCur
327 * "base" is the same as the base param in strtoll
328 */
329
330long long AtLine::atTokNextlonglongBase(int base, int uns, int *err) {
331 char *ret;
332 long long out;
333 *err = 0;
334
335 if (m_pCur == NULL) {
336 *err = -1;
337 return 0;
338 }
339
340 ret = nextTok();
341
342 if (ret == NULL) {
343 *err = -1;
344 return 0;
345 } else {
346 long long ll;
347 char *end;
348
349 if (uns)
350 ll = strtoull(ret, &end, base);
351 else
352 ll = strtoll(ret, &end, base);
353
354 out = ll;
355
356 if (end == ret) {
357 *err = -1;
358 return 0;
359 }
360 }
361
362 return out;
363}
364
365/**
366 * Parse the next base 10 long long in the AT response line
367 * and places it in *p_out
368 * Set err to 0 on success and -1 on fail
369 * updates m_pCur
370 */
371long long AtLine::atTokNextlonglong(int *err) {
372 return atTokNextlonglongBase(10, 0, err);
373}
374
375int AtLine::isFinalResponseSuccess() {
376 for (size_t i = 0; i < NUM_ELEMS(s_finalResponsesSuccess); i++) {
377 if (Misc::strStartsWith(m_line, s_finalResponsesSuccess[i])) {
378 return 1;
379 }
380 }
381
382 return 0;
383}
384
385int AtLine::isFinalResponseErrorEx(int channel_id) {
386 size_t i;
387
388// int j=0;
389// for(j=0; j<RfxRilUtils::getSimCount(); j++){
390// if( (channel_id == (int)(RIL_URC+j*RIL_CHANNEL_OFFSET)) &&
391// (RfxMisc::strStartsWith(m_line, "NO CARRIER")) ){
392// // [ALPS01225455]NO CARRIER in URC channel is URC, not final response for mediatek modem
393// return 0;
394// }
395// }
396
397 for (i = 0; i < NUM_ELEMS(s_finalResponsesError); i++) {
398 if (Misc::strStartsWith(m_line, s_finalResponsesError[i])) {
399 return 1;
400 }
401 }
402 return 0;
403}
404
405int AtLine::isIntermediatePattern() {
406 size_t i;
407 for (i = 0; i < NUM_ELEMS(s_IntermediatePattern); i++) {
408 if (!strcmp(m_line, s_IntermediatePattern[i])) {
409 return 1;
410 }
411 }
412 return 0;
413}
414
415bool AtLine::isFinalResponseSuccessInNumeric() {
416 for (size_t i = 0; i < NUM_ELEMS(s_finalResponsesSuccessInNumeric); i++) {
417 if (!strcmp(m_line, s_finalResponsesSuccessInNumeric[i])) {
418 return 1;
419 }
420 }
421 return 0;
422}
423
424bool AtLine::isFinalResponseErrorInNumeric() {
425 for (size_t i = 0; i < NUM_ELEMS(s_finalResponsesErrorInNumeric); i++) {
426 if (!strncmp(m_line, s_finalResponsesErrorInNumeric[i],
427 strlen(s_finalResponsesErrorInNumeric[i]))) {
428 return 1;
429 }
430 }
431 return 0;
432}
433
434bool AtLine::isAckResponse() {
435 for (size_t i = 0; i < NUM_ELEMS(s_ackResponse); i++) {
436 if (!strncmp(m_line, s_ackResponse[i], strlen(s_ackResponse[i]))) {
437 return true;
438 }
439 }
440 return false;
441}