rjw | 1f88458 | 2022-01-06 17:20:42 +0800 | [diff] [blame^] | 1 | /* 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 | |
| 44 | static 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 | */ |
| 52 | static 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 | */ |
| 65 | static const char *s_IntermediatePattern[] = { "> ", }; |
| 66 | |
| 67 | static const char *s_finalResponsesSuccessInNumeric[] = { "0", "1", }; |
| 68 | |
| 69 | static const char *s_finalResponsesErrorInNumeric[] = { "2", "3", "4", "6", "7", |
| 70 | "8", "+CMS ERROR:", "+CME ERROR:", "+C2K ERROR:", }; |
| 71 | |
| 72 | static const char *s_ackResponse[] = { "ACK" }; |
| 73 | |
| 74 | AtLine::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 | |
| 93 | AtLine::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 | |
| 109 | AtLine::~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 | */ |
| 125 | void 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 | |
| 146 | char* 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 | |
| 162 | void AtLine::skipWhiteSpace() { |
| 163 | if (m_pCur == NULL) |
| 164 | return; |
| 165 | |
| 166 | while (*m_pCur != '\0' && isspace(*m_pCur)) { |
| 167 | m_pCur++; |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | void 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 | |
| 184 | char* 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 | |
| 213 | int 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 | */ |
| 253 | int 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 | */ |
| 263 | int AtLine::atTokNexthexint(int *err) { |
| 264 | return atTokNextintBase(16, 1, err); |
| 265 | } |
| 266 | |
| 267 | bool 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 | |
| 286 | char* 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 */ |
| 297 | int AtLine::atTokHasmore() { |
| 298 | return !(m_pCur == NULL || *m_pCur == '\0'); |
| 299 | } |
| 300 | |
| 301 | /// M: eMBMS feature |
| 302 | void 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 | |
| 330 | long 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 | */ |
| 371 | long long AtLine::atTokNextlonglong(int *err) { |
| 372 | return atTokNextlonglongBase(10, 0, err); |
| 373 | } |
| 374 | |
| 375 | int 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 | |
| 385 | int 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 | |
| 405 | int 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 | |
| 415 | bool 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 | |
| 424 | bool 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 | |
| 434 | bool 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 | } |