blob: 7abba8a0b1a03669b039b8c4f3e43c33a1a1af7c [file] [log] [blame]
/* Copyright Statement:
*
* This software/firmware and related documentation ("MediaTek Software") are
* protected under relevant copyright laws. The information contained herein
* is confidential and proprietary to MediaTek Inc. and/or its licensors.
* Without the prior written permission of MediaTek inc. and/or its licensors,
* any reproduction, modification, use or disclosure of MediaTek Software,
* and information contained herein, in whole or in part, shall be strictly prohibited.
*
* MediaTek Inc. (C) 2016. All rights reserved.
*
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* The following software/firmware and/or related documentation ("MediaTek Software")
* have been modified by MediaTek Inc. All revisions are subject to any receiver's
* applicable license agreements with MediaTek Inc.
*/
#include "../util/AtLine.h"
#include <assert.h>
#include "../util/Misc.h"
#define RFX_LOG_TAG "RfxAtLine"
static const char *s_finalResponsesSuccess[] = { "OK", "CONNECT" /* some stacks start up data on another channel */
};
/**
* returns 1 if line is a final response indicating error
* See 27.007 annex B
* WARNING: NO CARRIER and others are sometimes unsolicited
*/
static const char *s_finalResponsesError[] = { "ERROR", "+CMS ERROR:",
"+CME ERROR:", "NO CARRIER", /* sometimes! */
"NO ANSWER", "NO DIALTONE", "+C2K ERROR:", "+EC2KCME ERROR", /* for distinguish CME error between MD1 and MD3 */
};
/**
* returns 1 if line is a intermediate response
* Such as
* AT+CMGW <CR>
* >XXXXXX <CTRL+Z> or <ESC>
* OK
* WARNING: NO CARRIER and others are sometimes unsolicited
*/
static const char *s_IntermediatePattern[] = { "> ", };
static const char *s_finalResponsesSuccessInNumeric[] = { "0", "1", };
static const char *s_finalResponsesErrorInNumeric[] = { "2", "3", "4", "6", "7",
"8", "+CMS ERROR:", "+CME ERROR:", "+C2K ERROR:", };
static const char *s_ackResponse[] = { "ACK" };
AtLine::AtLine(const AtLine &other) {
// Only copy THIS node
assert(other.m_pNext == NULL);
m_line = (char *) calloc(strlen(other.m_line) + 1, sizeof(char));
if (m_line == NULL) {
//RFX_LOG_E(RFX_LOG_TAG, "OOM");
m_pNext = NULL;
m_pCur = NULL;
return;
}
memcpy(m_line, other.m_line, strlen(other.m_line));
m_line[strlen(other.m_line)] = '\0';
m_pNext = NULL;
// initialize p_cur
m_pCur = m_line;
}
AtLine::AtLine(const char* line, AtLine* next) {
m_line = (char *) calloc(strlen(line) + 1, sizeof(char));
if (m_line == NULL) {
//RFX_LOG_E(RFX_LOG_TAG, "OOM");
m_pNext = NULL;
m_pCur = NULL;
return;
}
memcpy(m_line, line, strlen(line));
m_line[strlen(line)] = '\0';
m_pNext = next;
// initialize p_cur
m_pCur = m_line;
}
AtLine::~AtLine() {
if (m_pNext) {
delete (m_pNext);
}
m_pCur = NULL;
if (m_line) {
free(m_line);
}
}
/**
* Starts tokenizing an AT response string
* Set err to -1 if this is not a valid response string, 0 on success.
* updates m_pCur with current position
*/
void AtLine::atTokStart(int *err) {
*err = 0;
m_pCur = m_line;
if (m_pCur == NULL) {
*err = -1;
return;
}
// skip prefix
// consume "^[^:]:"
m_pCur = strchr(m_pCur, ':');
if (m_pCur == NULL) {
*err = -1;
return;
}
m_pCur++;
}
char* AtLine::atTokChar(int *err) {
*err = 0;
if (m_pCur == NULL) {
*err = -1;
return NULL;
}
m_pCur = strchr(m_pCur, '(');
if (m_pCur == NULL) {
*err = -1;
return NULL;
}
return (m_pCur++);
}
void AtLine::skipWhiteSpace() {
if (m_pCur == NULL)
return;
while (*m_pCur != '\0' && isspace(*m_pCur)) {
m_pCur++;
}
}
void AtLine::skipNextComma() {
if (m_pCur == NULL)
return;
while (*m_pCur != '\0' && *m_pCur != ',') {
m_pCur++;
}
if (*m_pCur == ',') {
m_pCur++;
}
}
char* AtLine::nextTok() {
char *ret;
skipWhiteSpace();
if (m_pCur == NULL) {
ret = NULL;
} else if (*m_pCur == '"') {
m_pCur++;
ret = strsep(&m_pCur, "\"");
skipNextComma();
} else if (*m_pCur == '(' && *(m_pCur + 1) == '"') {
m_pCur = m_pCur + 2;
ret = strsep(&m_pCur, "\"");
skipNextComma();
} else {
ret = strsep(&m_pCur, ",");
}
return ret;
}
/**
* Parses the next integer in the AT response line and places it in *p_out
* Set err to 0 on success and -1 on fail
* updates m_pCur
* "base" is the same as the base param in strtol
*/
int AtLine::atTokNextintBase(int base, int uns, int *err) {
int out;
char *ret;
*err = 0;
if (m_pCur == NULL) {
*err = -1;
return 0;
}
ret = nextTok();
if (ret == NULL) {
*err = -1;
return 0;
} else {
long l;
char *end;
if (uns)
l = strtoul(ret, &end, base);
else
l = strtol(ret, &end, base);
out = (int) l;
if (end == ret) {
*err = -1;
return 0;
}
return out;
}
}
/**
* Parses the next base 10 integer in the AT response line
* and places it in *p_out
* Set err to 0 on success and -1 on fail
* updates m_pCur
*/
int AtLine::atTokNextint(int *err) {
return atTokNextintBase(10, 0, err);
}
/**
* Parses the next base 16 integer in the AT response line
* and places it in *p_out
* Set err to 0 on success and -1 on fail
* updates m_pCur
*/
int AtLine::atTokNexthexint(int *err) {
return atTokNextintBase(16, 1, err);
}
bool AtLine::atTokNextbool(int *err) {
int result;
result = atTokNextint(err);
if (*err < 0) {
*err = -1;
return false;
}
// booleans should be 0 or 1
if (!(result == 0 || result == 1)) {
*err = -1;
return false;
}
return result ? true : false;
}
char* AtLine::atTokNextstr(int *err) {
*err = 0;
if (m_pCur == NULL) {
*err = -1;
return NULL;
}
return nextTok();
}
/** returns 1 on "has more tokens" and 0 if no */
int AtLine::atTokHasmore() {
return !(m_pCur == NULL || *m_pCur == '\0');
}
/// M: eMBMS feature
void AtLine::atTokEqual(int *err) {
*err = 0;
m_pCur = m_line;
if (m_pCur == NULL) {
*err = -1;
return;
}
// skip prefix
// consume "^[^=]:"
m_pCur = strchr(m_pCur, '=');
if (m_pCur == NULL) {
*err = -1;
return;
}
m_pCur++;
}
/**
* Parses the next long long in the AT response line and places it in *p_out
* Set err to 0 on success and -1 on fail
* updates m_pCur
* "base" is the same as the base param in strtoll
*/
long long AtLine::atTokNextlonglongBase(int base, int uns, int *err) {
char *ret;
long long out;
*err = 0;
if (m_pCur == NULL) {
*err = -1;
return 0;
}
ret = nextTok();
if (ret == NULL) {
*err = -1;
return 0;
} else {
long long ll;
char *end;
if (uns)
ll = strtoull(ret, &end, base);
else
ll = strtoll(ret, &end, base);
out = ll;
if (end == ret) {
*err = -1;
return 0;
}
}
return out;
}
/**
* Parse the next base 10 long long in the AT response line
* and places it in *p_out
* Set err to 0 on success and -1 on fail
* updates m_pCur
*/
long long AtLine::atTokNextlonglong(int *err) {
return atTokNextlonglongBase(10, 0, err);
}
int AtLine::isFinalResponseSuccess() {
for (size_t i = 0; i < NUM_ELEMS(s_finalResponsesSuccess); i++) {
if (Misc::strStartsWith(m_line, s_finalResponsesSuccess[i])) {
return 1;
}
}
return 0;
}
int AtLine::isFinalResponseErrorEx(int channel_id) {
size_t i;
// int j=0;
// for(j=0; j<RfxRilUtils::getSimCount(); j++){
// if( (channel_id == (int)(RIL_URC+j*RIL_CHANNEL_OFFSET)) &&
// (RfxMisc::strStartsWith(m_line, "NO CARRIER")) ){
// // [ALPS01225455]NO CARRIER in URC channel is URC, not final response for mediatek modem
// return 0;
// }
// }
for (i = 0; i < NUM_ELEMS(s_finalResponsesError); i++) {
if (Misc::strStartsWith(m_line, s_finalResponsesError[i])) {
return 1;
}
}
return 0;
}
int AtLine::isIntermediatePattern() {
size_t i;
for (i = 0; i < NUM_ELEMS(s_IntermediatePattern); i++) {
if (!strcmp(m_line, s_IntermediatePattern[i])) {
return 1;
}
}
return 0;
}
bool AtLine::isFinalResponseSuccessInNumeric() {
for (size_t i = 0; i < NUM_ELEMS(s_finalResponsesSuccessInNumeric); i++) {
if (!strcmp(m_line, s_finalResponsesSuccessInNumeric[i])) {
return 1;
}
}
return 0;
}
bool AtLine::isFinalResponseErrorInNumeric() {
for (size_t i = 0; i < NUM_ELEMS(s_finalResponsesErrorInNumeric); i++) {
if (!strncmp(m_line, s_finalResponsesErrorInNumeric[i],
strlen(s_finalResponsesErrorInNumeric[i]))) {
return 1;
}
}
return 0;
}
bool AtLine::isAckResponse() {
for (size_t i = 0; i < NUM_ELEMS(s_ackResponse); i++) {
if (!strncmp(m_line, s_ackResponse[i], strlen(s_ackResponse[i]))) {
return true;
}
}
return false;
}