diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:48 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:48 -0800 |
commit | c2efc51d848d68147320a5983954f9c76428885c (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /reference-ril | |
parent | 31f41943663ccc71bef87d42585b04afb23f6754 (diff) | |
download | android_hardware_ril-c2efc51d848d68147320a5983954f9c76428885c.tar.gz android_hardware_ril-c2efc51d848d68147320a5983954f9c76428885c.tar.bz2 android_hardware_ril-c2efc51d848d68147320a5983954f9c76428885c.zip |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'reference-ril')
-rw-r--r-- | reference-ril/Android.mk | 48 | ||||
-rw-r--r-- | reference-ril/MODULE_LICENSE_APACHE2 | 0 | ||||
-rw-r--r-- | reference-ril/NOTICE | 190 | ||||
-rw-r--r-- | reference-ril/at_tok.c | 190 | ||||
-rw-r--r-- | reference-ril/at_tok.h | 30 | ||||
-rw-r--r-- | reference-ril/atchannel.c | 1018 | ||||
-rw-r--r-- | reference-ril/atchannel.h | 124 | ||||
-rw-r--r-- | reference-ril/misc.c | 29 | ||||
-rw-r--r-- | reference-ril/misc.h | 19 | ||||
-rw-r--r-- | reference-ril/reference-ril.c | 2052 |
10 files changed, 0 insertions, 3700 deletions
diff --git a/reference-ril/Android.mk b/reference-ril/Android.mk deleted file mode 100644 index 7ec1f97..0000000 --- a/reference-ril/Android.mk +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2006 The Android Open Source Project - -# XXX using libutils for simulator build only... -# -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - reference-ril.c \ - atchannel.c \ - misc.c \ - at_tok.c - -LOCAL_SHARED_LIBRARIES := \ - libcutils libutils libril - - # for asprinf -LOCAL_CFLAGS := -D_GNU_SOURCE - -LOCAL_C_INCLUDES := $(KERNEL_HEADERS) - -ifeq ($(TARGET_DEVICE),sooner) - LOCAL_CFLAGS += -DOMAP_CSMI_POWER_CONTROL -DUSE_TI_COMMANDS -endif - -ifeq ($(TARGET_DEVICE),surf) - LOCAL_CFLAGS += -DPOLL_CALL_STATE -DUSE_QMI -endif - -ifeq ($(TARGET_DEVICE),dream) - LOCAL_CFLAGS += -DPOLL_CALL_STATE -DUSE_QMI -endif - -ifeq (foo,foo) - #build shared library - LOCAL_SHARED_LIBRARIES += \ - libcutils libutils - LOCAL_LDLIBS += -lpthread - LOCAL_CFLAGS += -DRIL_SHLIB - LOCAL_MODULE:= libreference-ril - include $(BUILD_SHARED_LIBRARY) -else - #build executable - LOCAL_SHARED_LIBRARIES += \ - libril - LOCAL_MODULE:= reference-ril - include $(BUILD_EXECUTABLE) -endif diff --git a/reference-ril/MODULE_LICENSE_APACHE2 b/reference-ril/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29..0000000 --- a/reference-ril/MODULE_LICENSE_APACHE2 +++ /dev/null diff --git a/reference-ril/NOTICE b/reference-ril/NOTICE deleted file mode 100644 index c5b1efa..0000000 --- a/reference-ril/NOTICE +++ /dev/null @@ -1,190 +0,0 @@ - - Copyright (c) 2005-2008, The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - diff --git a/reference-ril/at_tok.c b/reference-ril/at_tok.c deleted file mode 100644 index 11e0cba..0000000 --- a/reference-ril/at_tok.c +++ /dev/null @@ -1,190 +0,0 @@ -/* //device/system/reference-ril/at_tok.c -** -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#include "at_tok.h" -#include <string.h> -#include <ctype.h> -#include <stdlib.h> - -/** - * Starts tokenizing an AT response string - * returns -1 if this is not a valid response string, 0 on success. - * updates *p_cur with current position - */ -int at_tok_start(char **p_cur) -{ - if (*p_cur == NULL) { - return -1; - } - - // skip prefix - // consume "^[^:]:" - - *p_cur = strchr(*p_cur, ':'); - - if (*p_cur == NULL) { - return -1; - } - - (*p_cur)++; - - return 0; -} - -static void skipWhiteSpace(char **p_cur) -{ - if (*p_cur == NULL) return; - - while (**p_cur != '\0' && isspace(**p_cur)) { - (*p_cur)++; - } -} - -static void skipNextComma(char **p_cur) -{ - if (*p_cur == NULL) return; - - while (**p_cur != '\0' && **p_cur != ',') { - (*p_cur)++; - } - - if (**p_cur == ',') { - (*p_cur)++; - } -} - -static char * nextTok(char **p_cur) -{ - char *ret = NULL; - - skipWhiteSpace(p_cur); - - if (*p_cur == NULL) { - ret = NULL; - } else if (**p_cur == '"') { - (*p_cur)++; - ret = strsep(p_cur, "\""); - skipNextComma(p_cur); - } else { - ret = strsep(p_cur, ","); - } - - return ret; -} - - -/** - * Parses the next integer in the AT response line and places it in *p_out - * returns 0 on success and -1 on fail - * updates *p_cur - * "base" is the same as the base param in strtol - */ - -static int at_tok_nextint_base(char **p_cur, int *p_out, int base, int uns) -{ - char *ret; - - if (*p_cur == NULL) { - return -1; - } - - ret = nextTok(p_cur); - - if (ret == NULL) { - return -1; - } else { - long l; - char *end; - - if (uns) - l = strtoul(ret, &end, base); - else - l = strtol(ret, &end, base); - - *p_out = (int)l; - - if (end == ret) { - return -1; - } - } - - return 0; -} - -/** - * Parses the next base 10 integer in the AT response line - * and places it in *p_out - * returns 0 on success and -1 on fail - * updates *p_cur - */ -int at_tok_nextint(char **p_cur, int *p_out) -{ - return at_tok_nextint_base(p_cur, p_out, 10, 0); -} - -/** - * Parses the next base 16 integer in the AT response line - * and places it in *p_out - * returns 0 on success and -1 on fail - * updates *p_cur - */ -int at_tok_nexthexint(char **p_cur, int *p_out) -{ - return at_tok_nextint_base(p_cur, p_out, 16, 1); -} - -int at_tok_nextbool(char **p_cur, char *p_out) -{ - int ret; - int result; - - ret = at_tok_nextint(p_cur, &result); - - if (ret < 0) { - return -1; - } - - // booleans should be 0 or 1 - if (!(result == 0 || result == 1)) { - return -1; - } - - if (p_out != NULL) { - *p_out = (char)result; - } - - return ret; -} - -int at_tok_nextstr(char **p_cur, char **p_out) -{ - if (*p_cur == NULL) { - return -1; - } - - *p_out = nextTok(p_cur); - - return 0; -} - -/** returns 1 on "has more tokens" and 0 if no */ -int at_tok_hasmore(char **p_cur) -{ - return ! (*p_cur == NULL || **p_cur == '\0'); -} - - diff --git a/reference-ril/at_tok.h b/reference-ril/at_tok.h deleted file mode 100644 index 42bb4c9..0000000 --- a/reference-ril/at_tok.h +++ /dev/null @@ -1,30 +0,0 @@ -/* //device/system/reference-ril/at_tok.h -** -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#ifndef AT_TOK_H -#define AT_TOK_H 1 - -int at_tok_start(char **p_cur); -int at_tok_nextint(char **p_cur, int *p_out); -int at_tok_nexthexint(char **p_cur, int *p_out); - -int at_tok_nextbool(char **p_cur, char *p_out); -int at_tok_nextstr(char **p_cur, char **out); - -int at_tok_hasmore(char **p_cur); - -#endif /*AT_TOK_H */ diff --git a/reference-ril/atchannel.c b/reference-ril/atchannel.c deleted file mode 100644 index f878b35..0000000 --- a/reference-ril/atchannel.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* //device/system/reference-ril/atchannel.c -** -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#include "atchannel.h" -#include "at_tok.h" - -#include <stdio.h> -#include <string.h> -#include <pthread.h> -#include <ctype.h> -#include <stdlib.h> -#include <errno.h> -#include <fcntl.h> -#include <sys/time.h> -#include <time.h> -#include <unistd.h> - -#define LOG_NDEBUG 0 -#define LOG_TAG "AT" -#include <utils/Log.h> - -#ifdef HAVE_ANDROID_OS -/* for IOCTL's */ -#include <linux/omap_csmi.h> -#endif /*HAVE_ANDROID_OS*/ - -#include "misc.h" - -#ifdef HAVE_ANDROID_OS -#define USE_NP 1 -#endif /* HAVE_ANDROID_OS */ - - -#define NUM_ELEMS(x) (sizeof(x)/sizeof(x[0])) - -#define MAX_AT_RESPONSE (8 * 1024) -#define HANDSHAKE_RETRY_COUNT 8 -#define HANDSHAKE_TIMEOUT_MSEC 250 - -static pthread_t s_tid_reader; -static int s_fd = -1; /* fd of the AT channel */ -static ATUnsolHandler s_unsolHandler; - -/* for input buffering */ - -static char s_ATBuffer[MAX_AT_RESPONSE+1]; -static char *s_ATBufferCur = s_ATBuffer; - -static int s_ackPowerIoctl; /* true if TTY has android byte-count - handshake for low power*/ -static int s_readCount = 0; - -#if AT_DEBUG -void AT_DUMP(const char* prefix, const char* buff, int len) -{ - if (len < 0) - len = strlen(buff); - LOGD("%.*s", len, buff); -} -#endif - -/* - * for current pending command - * these are protected by s_commandmutex - */ - -static pthread_mutex_t s_commandmutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t s_commandcond = PTHREAD_COND_INITIALIZER; - -static ATCommandType s_type; -static const char *s_responsePrefix = NULL; -static const char *s_smsPDU = NULL; -static ATResponse *sp_response = NULL; - -static void (*s_onTimeout)(void) = NULL; -static void (*s_onReaderClosed)(void) = NULL; -static int s_readerClosed; - -static void onReaderClosed(); -static int writeCtrlZ (const char *s); -static int writeline (const char *s); - -#ifndef USE_NP -static void setTimespecRelative(struct timespec *p_ts, long long msec) -{ - struct timeval tv; - - gettimeofday(&tv, (struct timezone *) NULL); - - /* what's really funny about this is that I know - pthread_cond_timedwait just turns around and makes this - a relative time again */ - p_ts->tv_sec = tv.tv_sec + (msec / 1000); - p_ts->tv_nsec = (tv.tv_usec + (msec % 1000) * 1000L ) * 1000L; -} -#endif /*USE_NP*/ - -static void sleepMsec(long long msec) -{ - struct timespec ts; - int err; - - ts.tv_sec = (msec / 1000); - ts.tv_nsec = (msec % 1000) * 1000 * 1000; - - do { - err = nanosleep (&ts, &ts); - } while (err < 0 && errno == EINTR); -} - - - -/** add an intermediate response to sp_response*/ -static void addIntermediate(const char *line) -{ - ATLine *p_new; - - p_new = (ATLine *) malloc(sizeof(ATLine)); - - p_new->line = strdup(line); - - /* note: this adds to the head of the list, so the list - will be in reverse order of lines received. the order is flipped - again before passing on to the command issuer */ - p_new->p_next = sp_response->p_intermediates; - sp_response->p_intermediates = p_new; -} - - -/** - * 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", -}; -static int isFinalResponseError(const char *line) -{ - size_t i; - - for (i = 0 ; i < NUM_ELEMS(s_finalResponsesError) ; i++) { - if (strStartsWith(line, s_finalResponsesError[i])) { - return 1; - } - } - - return 0; -} - -/** - * returns 1 if line is a final response indicating success - * See 27.007 annex B - * WARNING: NO CARRIER and others are sometimes unsolicited - */ -static const char * s_finalResponsesSuccess[] = { - "OK", - "CONNECT" /* some stacks start up data on another channel */ -}; -static int isFinalResponseSuccess(const char *line) -{ - size_t i; - - for (i = 0 ; i < NUM_ELEMS(s_finalResponsesSuccess) ; i++) { - if (strStartsWith(line, s_finalResponsesSuccess[i])) { - return 1; - } - } - - return 0; -} - -/** - * returns 1 if line is a final response, either error or success - * See 27.007 annex B - * WARNING: NO CARRIER and others are sometimes unsolicited - */ -static int isFinalResponse(const char *line) -{ - return isFinalResponseSuccess(line) || isFinalResponseError(line); -} - - -/** - * returns 1 if line is the first line in (what will be) a two-line - * SMS unsolicited response - */ -static const char * s_smsUnsoliciteds[] = { - "+CMT:", - "+CDS:", - "+CBM:" -}; -static int isSMSUnsolicited(const char *line) -{ - size_t i; - - for (i = 0 ; i < NUM_ELEMS(s_smsUnsoliciteds) ; i++) { - if (strStartsWith(line, s_smsUnsoliciteds[i])) { - return 1; - } - } - - return 0; -} - - -/** assumes s_commandmutex is held */ -static void handleFinalResponse(const char *line) -{ - sp_response->finalResponse = strdup(line); - - pthread_cond_signal(&s_commandcond); -} - -static void handleUnsolicited(const char *line) -{ - if (s_unsolHandler != NULL) { - s_unsolHandler(line, NULL); - } -} - -static void processLine(const char *line) -{ - pthread_mutex_lock(&s_commandmutex); - - if (sp_response == NULL) { - /* no command pending */ - handleUnsolicited(line); - } else if (isFinalResponseSuccess(line)) { - sp_response->success = 1; - handleFinalResponse(line); - } else if (isFinalResponseError(line)) { - sp_response->success = 0; - handleFinalResponse(line); - } else if (s_smsPDU != NULL && 0 == strcmp(line, "> ")) { - // See eg. TS 27.005 4.3 - // Commands like AT+CMGS have a "> " prompt - writeCtrlZ(s_smsPDU); - s_smsPDU = NULL; - } else switch (s_type) { - case NO_RESULT: - handleUnsolicited(line); - break; - case NUMERIC: - if (sp_response->p_intermediates == NULL - && isdigit(line[0]) - ) { - addIntermediate(line); - } else { - /* either we already have an intermediate response or - the line doesn't begin with a digit */ - handleUnsolicited(line); - } - break; - case SINGLELINE: - if (sp_response->p_intermediates == NULL - && strStartsWith (line, s_responsePrefix) - ) { - addIntermediate(line); - } else { - /* we already have an intermediate response */ - handleUnsolicited(line); - } - break; - case MULTILINE: - if (strStartsWith (line, s_responsePrefix)) { - addIntermediate(line); - } else { - handleUnsolicited(line); - } - break; - - default: /* this should never be reached */ - LOGE("Unsupported AT command type %d\n", s_type); - handleUnsolicited(line); - break; - } - - pthread_mutex_unlock(&s_commandmutex); -} - - -/** - * Returns a pointer to the end of the next line - * special-cases the "> " SMS prompt - * - * returns NULL if there is no complete line - */ -static char * findNextEOL(char *cur) -{ - if (cur[0] == '>' && cur[1] == ' ' && cur[2] == '\0') { - /* SMS prompt character...not \r terminated */ - return cur+2; - } - - // Find next newline - while (*cur != '\0' && *cur != '\r' && *cur != '\n') cur++; - - return *cur == '\0' ? NULL : cur; -} - - -/** - * Reads a line from the AT channel, returns NULL on timeout. - * Assumes it has exclusive read access to the FD - * - * This line is valid only until the next call to readline - * - * This function exists because as of writing, android libc does not - * have buffered stdio. - */ - -static const char *readline() -{ - ssize_t count; - - char *p_read = NULL; - char *p_eol = NULL; - char *ret; - - /* this is a little odd. I use *s_ATBufferCur == 0 to - * mean "buffer consumed completely". If it points to a character, than - * the buffer continues until a \0 - */ - if (*s_ATBufferCur == '\0') { - /* empty buffer */ - s_ATBufferCur = s_ATBuffer; - *s_ATBufferCur = '\0'; - p_read = s_ATBuffer; - } else { /* *s_ATBufferCur != '\0' */ - /* there's data in the buffer from the last read */ - - // skip over leading newlines - while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n') - s_ATBufferCur++; - - p_eol = findNextEOL(s_ATBufferCur); - - if (p_eol == NULL) { - /* a partial line. move it up and prepare to read more */ - size_t len; - - len = strlen(s_ATBufferCur); - - memmove(s_ATBuffer, s_ATBufferCur, len + 1); - p_read = s_ATBuffer + len; - s_ATBufferCur = s_ATBuffer; - } - /* Otherwise, (p_eol !- NULL) there is a complete line */ - /* that will be returned the while () loop below */ - } - - while (p_eol == NULL) { - if (0 == MAX_AT_RESPONSE - (p_read - s_ATBuffer)) { - LOGE("ERROR: Input line exceeded buffer\n"); - /* ditch buffer and start over again */ - s_ATBufferCur = s_ATBuffer; - *s_ATBufferCur = '\0'; - p_read = s_ATBuffer; - } - - do { - count = read(s_fd, p_read, - MAX_AT_RESPONSE - (p_read - s_ATBuffer)); - } while (count < 0 && errno == EINTR); - - if (count > 0) { - AT_DUMP( "<< ", p_read, count ); - s_readCount += count; - - p_read[count] = '\0'; - - // skip over leading newlines - while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n') - s_ATBufferCur++; - - p_eol = findNextEOL(s_ATBufferCur); - p_read += count; - } else if (count <= 0) { - /* read error encountered or EOF reached */ - if(count == 0) { - LOGD("atchannel: EOF reached"); - } else { - LOGD("atchannel: read error %s", strerror(errno)); - } - return NULL; - } - } - - /* a full line in the buffer. Place a \0 over the \r and return */ - - ret = s_ATBufferCur; - *p_eol = '\0'; - s_ATBufferCur = p_eol + 1; /* this will always be <= p_read, */ - /* and there will be a \0 at *p_read */ - - LOGD("AT< %s\n", ret); - return ret; -} - - -static void onReaderClosed() -{ - if (s_onReaderClosed != NULL && s_readerClosed == 0) { - - pthread_mutex_lock(&s_commandmutex); - - s_readerClosed = 1; - - pthread_cond_signal(&s_commandcond); - - pthread_mutex_unlock(&s_commandmutex); - - s_onReaderClosed(); - } -} - - -static void *readerLoop(void *arg) -{ - for (;;) { - const char * line; - - line = readline(); - - if (line == NULL) { - break; - } - - if(isSMSUnsolicited(line)) { - char *line1; - const char *line2; - - // The scope of string returned by 'readline()' is valid only - // till next call to 'readline()' hence making a copy of line - // before calling readline again. - line1 = strdup(line); - line2 = readline(); - - if (line2 == NULL) { - break; - } - - if (s_unsolHandler != NULL) { - s_unsolHandler (line1, line2); - } - free(line1); - } else { - processLine(line); - } - -#ifdef HAVE_ANDROID_OS - if (s_ackPowerIoctl > 0) { - /* acknowledge that bytes have been read and processed */ - ioctl(s_fd, OMAP_CSMI_TTY_ACK, &s_readCount); - s_readCount = 0; - } -#endif /*HAVE_ANDROID_OS*/ - } - - onReaderClosed(); - - return NULL; -} - -/** - * Sends string s to the radio with a \r appended. - * Returns AT_ERROR_* on error, 0 on success - * - * This function exists because as of writing, android libc does not - * have buffered stdio. - */ -static int writeline (const char *s) -{ - size_t cur = 0; - size_t len = strlen(s); - ssize_t written; - - if (s_fd < 0 || s_readerClosed > 0) { - return AT_ERROR_CHANNEL_CLOSED; - } - - LOGD("AT> %s\n", s); - - AT_DUMP( ">> ", s, strlen(s) ); - - /* the main string */ - while (cur < len) { - do { - written = write (s_fd, s + cur, len - cur); - } while (written < 0 && errno == EINTR); - - if (written < 0) { - return AT_ERROR_GENERIC; - } - - cur += written; - } - - /* the \r */ - - do { - written = write (s_fd, "\r" , 1); - } while ((written < 0 && errno == EINTR) || (written == 0)); - - if (written < 0) { - return AT_ERROR_GENERIC; - } - - return 0; -} -static int writeCtrlZ (const char *s) -{ - size_t cur = 0; - size_t len = strlen(s); - ssize_t written; - - if (s_fd < 0 || s_readerClosed > 0) { - return AT_ERROR_CHANNEL_CLOSED; - } - - LOGD("AT> %s^Z\n", s); - - AT_DUMP( ">* ", s, strlen(s) ); - - /* the main string */ - while (cur < len) { - do { - written = write (s_fd, s + cur, len - cur); - } while (written < 0 && errno == EINTR); - - if (written < 0) { - return AT_ERROR_GENERIC; - } - - cur += written; - } - - /* the ^Z */ - - do { - written = write (s_fd, "\032" , 1); - } while ((written < 0 && errno == EINTR) || (written == 0)); - - if (written < 0) { - return AT_ERROR_GENERIC; - } - - return 0; -} - -static void clearPendingCommand() -{ - if (sp_response != NULL) { - at_response_free(sp_response); - } - - sp_response = NULL; - s_responsePrefix = NULL; - s_smsPDU = NULL; -} - - -/** - * Starts AT handler on stream "fd' - * returns 0 on success, -1 on error - */ -int at_open(int fd, ATUnsolHandler h) -{ - int ret; - pthread_t tid; - pthread_attr_t attr; - - s_fd = fd; - s_unsolHandler = h; - s_readerClosed = 0; - - s_responsePrefix = NULL; - s_smsPDU = NULL; - sp_response = NULL; - - /* Android power control ioctl */ -#ifdef HAVE_ANDROID_OS -#ifdef OMAP_CSMI_POWER_CONTROL - ret = ioctl(fd, OMAP_CSMI_TTY_ENABLE_ACK); - if(ret == 0) { - int ack_count; - int read_count; - int old_flags; - char sync_buf[256]; - old_flags = fcntl(fd, F_GETFL, 0); - fcntl(fd, F_SETFL, old_flags | O_NONBLOCK); - do { - ioctl(fd, OMAP_CSMI_TTY_READ_UNACKED, &ack_count); - read_count = 0; - do { - ret = read(fd, sync_buf, sizeof(sync_buf)); - if(ret > 0) - read_count += ret; - } while(ret > 0 || (ret < 0 && errno == EINTR)); - ioctl(fd, OMAP_CSMI_TTY_ACK, &ack_count); - } while(ack_count > 0 || read_count > 0); - fcntl(fd, F_SETFL, old_flags); - s_readCount = 0; - s_ackPowerIoctl = 1; - } - else - s_ackPowerIoctl = 0; - -#else // OMAP_CSMI_POWER_CONTROL - s_ackPowerIoctl = 0; - -#endif // OMAP_CSMI_POWER_CONTROL -#endif /*HAVE_ANDROID_OS*/ - - pthread_attr_init (&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr); - - if (ret < 0) { - perror ("pthread_create"); - return -1; - } - - - return 0; -} - -/* FIXME is it ok to call this from the reader and the command thread? */ -void at_close() -{ - if (s_fd >= 0) { - close(s_fd); - } - s_fd = -1; - - pthread_mutex_lock(&s_commandmutex); - - s_readerClosed = 1; - - pthread_cond_signal(&s_commandcond); - - pthread_mutex_unlock(&s_commandmutex); - - /* the reader thread should eventually die */ -} - -static ATResponse * at_response_new() -{ - return (ATResponse *) calloc(1, sizeof(ATResponse)); -} - -void at_response_free(ATResponse *p_response) -{ - ATLine *p_line; - - if (p_response == NULL) return; - - p_line = p_response->p_intermediates; - - while (p_line != NULL) { - ATLine *p_toFree; - - p_toFree = p_line; - p_line = p_line->p_next; - - free(p_toFree->line); - free(p_toFree); - } - - free (p_response->finalResponse); - free (p_response); -} - -/** - * The line reader places the intermediate responses in reverse order - * here we flip them back - */ -static void reverseIntermediates(ATResponse *p_response) -{ - ATLine *pcur,*pnext; - - pcur = p_response->p_intermediates; - p_response->p_intermediates = NULL; - - while (pcur != NULL) { - pnext = pcur->p_next; - pcur->p_next = p_response->p_intermediates; - p_response->p_intermediates = pcur; - pcur = pnext; - } -} - -/** - * Internal send_command implementation - * Doesn't lock or call the timeout callback - * - * timeoutMsec == 0 means infinite timeout - */ - -static int at_send_command_full_nolock (const char *command, ATCommandType type, - const char *responsePrefix, const char *smspdu, - long long timeoutMsec, ATResponse **pp_outResponse) -{ - int err = 0; -#ifndef USE_NP - struct timespec ts; -#endif /*USE_NP*/ - - if(sp_response != NULL) { - err = AT_ERROR_COMMAND_PENDING; - goto error; - } - - err = writeline (command); - - if (err < 0) { - goto error; - } - - s_type = type; - s_responsePrefix = responsePrefix; - s_smsPDU = smspdu; - sp_response = at_response_new(); - -#ifndef USE_NP - if (timeoutMsec != 0) { - setTimespecRelative(&ts, timeoutMsec); - } -#endif /*USE_NP*/ - - while (sp_response->finalResponse == NULL && s_readerClosed == 0) { - if (timeoutMsec != 0) { -#ifdef USE_NP - err = pthread_cond_timeout_np(&s_commandcond, &s_commandmutex, timeoutMsec); -#else - err = pthread_cond_timedwait(&s_commandcond, &s_commandmutex, &ts); -#endif /*USE_NP*/ - } else { - err = pthread_cond_wait(&s_commandcond, &s_commandmutex); - } - - if (err == ETIMEDOUT) { - err = AT_ERROR_TIMEOUT; - goto error; - } - } - - if (pp_outResponse == NULL) { - at_response_free(sp_response); - } else { - /* line reader stores intermediate responses in reverse order */ - reverseIntermediates(sp_response); - *pp_outResponse = sp_response; - } - - sp_response = NULL; - - if(s_readerClosed > 0) { - err = AT_ERROR_CHANNEL_CLOSED; - goto error; - } - - err = 0; -error: - clearPendingCommand(); - - return err; -} - -/** - * Internal send_command implementation - * - * timeoutMsec == 0 means infinite timeout - */ -static int at_send_command_full (const char *command, ATCommandType type, - const char *responsePrefix, const char *smspdu, - long long timeoutMsec, ATResponse **pp_outResponse) -{ - int err; - - if (0 != pthread_equal(s_tid_reader, pthread_self())) { - /* cannot be called from reader thread */ - return AT_ERROR_INVALID_THREAD; - } - - pthread_mutex_lock(&s_commandmutex); - - err = at_send_command_full_nolock(command, type, - responsePrefix, smspdu, - timeoutMsec, pp_outResponse); - - pthread_mutex_unlock(&s_commandmutex); - - if (err == AT_ERROR_TIMEOUT && s_onTimeout != NULL) { - s_onTimeout(); - } - - return err; -} - - -/** - * Issue a single normal AT command with no intermediate response expected - * - * "command" should not include \r - * pp_outResponse can be NULL - * - * if non-NULL, the resulting ATResponse * must be eventually freed with - * at_response_free - */ -int at_send_command (const char *command, ATResponse **pp_outResponse) -{ - int err; - - err = at_send_command_full (command, NO_RESULT, NULL, - NULL, 0, pp_outResponse); - - return err; -} - - -int at_send_command_singleline (const char *command, - const char *responsePrefix, - ATResponse **pp_outResponse) -{ - int err; - - err = at_send_command_full (command, SINGLELINE, responsePrefix, - NULL, 0, pp_outResponse); - - if (err == 0 && pp_outResponse != NULL - && (*pp_outResponse)->success > 0 - && (*pp_outResponse)->p_intermediates == NULL - ) { - /* successful command must have an intermediate response */ - at_response_free(*pp_outResponse); - *pp_outResponse = NULL; - return AT_ERROR_INVALID_RESPONSE; - } - - return err; -} - - -int at_send_command_numeric (const char *command, - ATResponse **pp_outResponse) -{ - int err; - - err = at_send_command_full (command, NUMERIC, NULL, - NULL, 0, pp_outResponse); - - if (err == 0 && pp_outResponse != NULL - && (*pp_outResponse)->success > 0 - && (*pp_outResponse)->p_intermediates == NULL - ) { - /* successful command must have an intermediate response */ - at_response_free(*pp_outResponse); - *pp_outResponse = NULL; - return AT_ERROR_INVALID_RESPONSE; - } - - return err; -} - - -int at_send_command_sms (const char *command, - const char *pdu, - const char *responsePrefix, - ATResponse **pp_outResponse) -{ - int err; - - err = at_send_command_full (command, SINGLELINE, responsePrefix, - pdu, 0, pp_outResponse); - - if (err == 0 && pp_outResponse != NULL - && (*pp_outResponse)->success > 0 - && (*pp_outResponse)->p_intermediates == NULL - ) { - /* successful command must have an intermediate response */ - at_response_free(*pp_outResponse); - *pp_outResponse = NULL; - return AT_ERROR_INVALID_RESPONSE; - } - - return err; -} - - -int at_send_command_multiline (const char *command, - const char *responsePrefix, - ATResponse **pp_outResponse) -{ - int err; - - err = at_send_command_full (command, MULTILINE, responsePrefix, - NULL, 0, pp_outResponse); - - return err; -} - - -/** This callback is invoked on the command thread */ -void at_set_on_timeout(void (*onTimeout)(void)) -{ - s_onTimeout = onTimeout; -} - -/** - * This callback is invoked on the reader thread (like ATUnsolHandler) - * when the input stream closes before you call at_close - * (not when you call at_close()) - * You should still call at_close() - */ - -void at_set_on_reader_closed(void (*onClose)(void)) -{ - s_onReaderClosed = onClose; -} - - -/** - * Periodically issue an AT command and wait for a response. - * Used to ensure channel has start up and is active - */ - -int at_handshake() -{ - int i; - int err = 0; - - if (0 != pthread_equal(s_tid_reader, pthread_self())) { - /* cannot be called from reader thread */ - return AT_ERROR_INVALID_THREAD; - } - - pthread_mutex_lock(&s_commandmutex); - - for (i = 0 ; i < HANDSHAKE_RETRY_COUNT ; i++) { - /* some stacks start with verbose off */ - err = at_send_command_full_nolock ("ATE0Q0V1", NO_RESULT, - NULL, NULL, HANDSHAKE_TIMEOUT_MSEC, NULL); - - if (err == 0) { - break; - } - } - - if (err == 0) { - /* pause for a bit to let the input buffer drain any unmatched OK's - (they will appear as extraneous unsolicited responses) */ - - sleepMsec(HANDSHAKE_TIMEOUT_MSEC); - } - - pthread_mutex_unlock(&s_commandmutex); - - return err; -} - -/** - * Returns error code from response - * Assumes AT+CMEE=1 (numeric) mode - */ -AT_CME_Error at_get_cme_error(const ATResponse *p_response) -{ - int ret; - int err; - char *p_cur; - - if (p_response->success > 0) { - return CME_SUCCESS; - } - - if (p_response->finalResponse == NULL - || !strStartsWith(p_response->finalResponse, "+CME ERROR:") - ) { - return CME_ERROR_NON_CME; - } - - p_cur = p_response->finalResponse; - err = at_tok_start(&p_cur); - - if (err < 0) { - return CME_ERROR_NON_CME; - } - - err = at_tok_nextint(&p_cur, &ret); - - if (err < 0) { - return CME_ERROR_NON_CME; - } - - return (AT_CME_Error) ret; -} - diff --git a/reference-ril/atchannel.h b/reference-ril/atchannel.h deleted file mode 100644 index cfd49d5..0000000 --- a/reference-ril/atchannel.h +++ /dev/null @@ -1,124 +0,0 @@ -/* //device/system/reference-ril/atchannel.h -** -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#ifndef ATCHANNEL_H -#define ATCHANNEL_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* define AT_DEBUG to send AT traffic to /tmp/radio-at.log" */ -#define AT_DEBUG 0 - -#if AT_DEBUG -extern void AT_DUMP(const char* prefix, const char* buff, int len); -#else -#define AT_DUMP(prefix,buff,len) do{}while(0) -#endif - -#define AT_ERROR_GENERIC -1 -#define AT_ERROR_COMMAND_PENDING -2 -#define AT_ERROR_CHANNEL_CLOSED -3 -#define AT_ERROR_TIMEOUT -4 -#define AT_ERROR_INVALID_THREAD -5 /* AT commands may not be issued from - reader thread (or unsolicited response - callback */ -#define AT_ERROR_INVALID_RESPONSE -6 /* eg an at_send_command_singleline that - did not get back an intermediate - response */ - - -typedef enum { - NO_RESULT, /* no intermediate response expected */ - NUMERIC, /* a single intermediate response starting with a 0-9 */ - SINGLELINE, /* a single intermediate response starting with a prefix */ - MULTILINE /* multiple line intermediate response - starting with a prefix */ -} ATCommandType; - -/** a singly-lined list of intermediate responses */ -typedef struct ATLine { - struct ATLine *p_next; - char *line; -} ATLine; - -/** Free this with at_response_free() */ -typedef struct { - int success; /* true if final response indicates - success (eg "OK") */ - char *finalResponse; /* eg OK, ERROR */ - ATLine *p_intermediates; /* any intermediate responses */ -} ATResponse; - -/** - * a user-provided unsolicited response handler function - * this will be called from the reader thread, so do not block - * "s" is the line, and "sms_pdu" is either NULL or the PDU response - * for multi-line TS 27.005 SMS PDU responses (eg +CMT:) - */ -typedef void (*ATUnsolHandler)(const char *s, const char *sms_pdu); - -int at_open(int fd, ATUnsolHandler h); -void at_close(); - -/* This callback is invoked on the command thread. - You should reset or handshake here to avoid getting out of sync */ -void at_set_on_timeout(void (*onTimeout)(void)); -/* This callback is invoked on the reader thread (like ATUnsolHandler) - when the input stream closes before you call at_close - (not when you call at_close()) - You should still call at_close() - It may also be invoked immediately from the current thread if the read - channel is already closed */ -void at_set_on_reader_closed(void (*onClose)(void)); - -int at_send_command_singleline (const char *command, - const char *responsePrefix, - ATResponse **pp_outResponse); - -int at_send_command_numeric (const char *command, - ATResponse **pp_outResponse); - -int at_send_command_multiline (const char *command, - const char *responsePrefix, - ATResponse **pp_outResponse); - - -int at_handshake(); - -int at_send_command (const char *command, ATResponse **pp_outResponse); - -int at_send_command_sms (const char *command, const char *pdu, - const char *responsePrefix, - ATResponse **pp_outResponse); - -void at_response_free(ATResponse *p_response); - -typedef enum { - CME_ERROR_NON_CME = -1, - CME_SUCCESS = 0, - CME_SIM_NOT_INSERTED = 10 -} AT_CME_Error; - -AT_CME_Error at_get_cme_error(const ATResponse *p_response); - -#ifdef __cplusplus -} -#endif - -#endif /*ATCHANNEL_H*/ diff --git a/reference-ril/misc.c b/reference-ril/misc.c deleted file mode 100644 index 7945e75..0000000 --- a/reference-ril/misc.c +++ /dev/null @@ -1,29 +0,0 @@ -/* //device/system/reference-ril/misc.c -** -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/** returns 1 if line starts with prefix, 0 if it does not */ -int strStartsWith(const char *line, const char *prefix) -{ - for ( ; *line != '\0' && *prefix != '\0' ; line++, prefix++) { - if (*line != *prefix) { - return 0; - } - } - - return *prefix == '\0'; -} - diff --git a/reference-ril/misc.h b/reference-ril/misc.h deleted file mode 100644 index bafe7df..0000000 --- a/reference-ril/misc.h +++ /dev/null @@ -1,19 +0,0 @@ -/* //device/system/reference-ril/misc.h -** -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/** returns 1 if line starts with prefix, 0 if it does not */ -int strStartsWith(const char *line, const char *prefix); diff --git a/reference-ril/reference-ril.c b/reference-ril/reference-ril.c deleted file mode 100644 index ccb5b62..0000000 --- a/reference-ril/reference-ril.c +++ /dev/null @@ -1,2052 +0,0 @@ -/* //device/system/reference-ril/reference-ril.c -** -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#include <telephony/ril.h> -#include <stdio.h> -#include <assert.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <pthread.h> -#include <alloca.h> -#include "atchannel.h" -#include "at_tok.h" -#include "misc.h" -#include <getopt.h> -#include <sys/socket.h> -#include <cutils/sockets.h> -#include <termios.h> - -#define LOG_TAG "RIL" -#include <utils/Log.h> - -#define MAX_AT_RESPONSE 0x1000 - -/* pathname returned from RIL_REQUEST_SETUP_DEFAULT_PDP */ -#define PPP_TTY_PATH "/dev/omap_csmi_tty1" - -#ifdef USE_TI_COMMANDS - -// Enable a workaround -// 1) Make incoming call, do not answer -// 2) Hangup remote end -// Expected: call should disappear from CLCC line -// Actual: Call shows as "ACTIVE" before disappearing -#define WORKAROUND_ERRONEOUS_ANSWER 1 - -// Some varients of the TI stack do not support the +CGEV unsolicited -// response. However, they seem to send an unsolicited +CME ERROR: 150 -#define WORKAROUND_FAKE_CGEV 1 -#endif - -static void onRequest (int request, void *data, size_t datalen, RIL_Token t); -static RIL_RadioState currentState(); -static int onSupports (int requestCode); -static void onCancel (RIL_Token t); -static const char *getVersion(); -static int isRadioOn(); -static int getSIMStatus(); -static void onPDPContextListChanged(void *param); - -extern const char * requestToString(int request); - -/*** Static Variables ***/ -static const RIL_RadioFunctions s_callbacks = { - RIL_VERSION, - onRequest, - currentState, - onSupports, - onCancel, - getVersion -}; - -#ifdef RIL_SHLIB -static const struct RIL_Env *s_rilenv; - -#define RIL_onRequestComplete(t, e, response, responselen) s_rilenv->OnRequestComplete(t,e, response, responselen) -#define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c) -#define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c) -#endif - -static RIL_RadioState sState = RADIO_STATE_UNAVAILABLE; - -static pthread_mutex_t s_state_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t s_state_cond = PTHREAD_COND_INITIALIZER; - -static int s_port = -1; -static const char * s_device_path = NULL; -static int s_device_socket = 0; - -/* trigger change to this with s_state_cond */ -static int s_closed = 0; - -static int sFD; /* file desc of AT channel */ -static char sATBuffer[MAX_AT_RESPONSE+1]; -static char *sATBufferCur = NULL; - -static const struct timeval TIMEVAL_SIMPOLL = {1,0}; -static const struct timeval TIMEVAL_CALLSTATEPOLL = {0,500000}; -static const struct timeval TIMEVAL_0 = {0,0}; - -#ifdef WORKAROUND_ERRONEOUS_ANSWER -// Max number of times we'll try to repoll when we think -// we have a AT+CLCC race condition -#define REPOLL_CALLS_COUNT_MAX 4 - -// Line index that was incoming or waiting at last poll, or -1 for none -static int s_incomingOrWaitingLine = -1; -// Number of times we've asked for a repoll of AT+CLCC -static int s_repollCallsCount = 0; -// Should we expect a call to be answered in the next CLCC? -static int s_expectAnswer = 0; -#endif /* WORKAROUND_ERRONEOUS_ANSWER */ - -static void pollSIMState (void *param); -static void setRadioState(RIL_RadioState newState); - -static int clccStateToRILState(int state, RIL_CallState *p_state) - -{ - switch(state) { - case 0: *p_state = RIL_CALL_ACTIVE; return 0; - case 1: *p_state = RIL_CALL_HOLDING; return 0; - case 2: *p_state = RIL_CALL_DIALING; return 0; - case 3: *p_state = RIL_CALL_ALERTING; return 0; - case 4: *p_state = RIL_CALL_INCOMING; return 0; - case 5: *p_state = RIL_CALL_WAITING; return 0; - default: return -1; - } -} - -/** - * Note: directly modified line and has *p_call point directly into - * modified line - */ -static int callFromCLCCLine(char *line, RIL_Call *p_call) -{ - //+CLCC: 1,0,2,0,0,\"+18005551212\",145 - // index,isMT,state,mode,isMpty(,number,TOA)? - - int err; - int state; - int mode; - - err = at_tok_start(&line); - if (err < 0) goto error; - - err = at_tok_nextint(&line, &(p_call->index)); - if (err < 0) goto error; - - err = at_tok_nextbool(&line, &(p_call->isMT)); - if (err < 0) goto error; - - err = at_tok_nextint(&line, &state); - if (err < 0) goto error; - - err = clccStateToRILState(state, &(p_call->state)); - if (err < 0) goto error; - - err = at_tok_nextint(&line, &mode); - if (err < 0) goto error; - - p_call->isVoice = (mode == 0); - - err = at_tok_nextbool(&line, &(p_call->isMpty)); - if (err < 0) goto error; - - if (at_tok_hasmore(&line)) { - err = at_tok_nextstr(&line, &(p_call->number)); - - /* tolerate null here */ - if (err < 0) return 0; - - // Some lame implementations return strings - // like "NOT AVAILABLE" in the CLCC line - if (p_call->number != NULL - && 0 == strspn(p_call->number, "+0123456789") - ) { - p_call->number = NULL; - } - - err = at_tok_nextint(&line, &p_call->toa); - if (err < 0) goto error; - } - - return 0; - -error: - LOGE("invalid CLCC line\n"); - return -1; -} - - -/** do post-AT+CFUN=1 initialization */ -static void onRadioPowerOn() -{ -#ifdef USE_TI_COMMANDS - /* Must be after CFUN=1 */ - /* TI specific -- notifications for CPHS things such */ - /* as CPHS message waiting indicator */ - - at_send_command("AT%CPHS=1", NULL); - - /* TI specific -- enable NITZ unsol notifs */ - at_send_command("AT%CTZV=1", NULL); -#endif - - pollSIMState(NULL); -} - -/** do post- SIM ready initialization */ -static void onSIMReady() -{ - at_send_command_singleline("AT+CSMS=1", "+CSMS:", NULL); - /* - * Always send SMS messages directly to the TE - * - * mode = 1 // discard when link is reserved (link should never be - * reserved) - * mt = 2 // most messages routed to TE - * bm = 2 // new cell BM's routed to TE - * ds = 1 // Status reports routed to TE - * bfr = 1 // flush buffer - */ - at_send_command("AT+CNMI=1,2,2,1,1", NULL); -} - -static void requestRadioPower(void *data, size_t datalen, RIL_Token t) -{ - int onOff; - - int err; - ATResponse *p_response = NULL; - - assert (datalen >= sizeof(int *)); - onOff = ((int *)data)[0]; - - if (onOff == 0 && sState != RADIO_STATE_OFF) { - err = at_send_command("AT+CFUN=0", &p_response); - if (err < 0 || p_response->success == 0) goto error; - setRadioState(RADIO_STATE_OFF); - } else if (onOff > 0 && sState == RADIO_STATE_OFF) { - err = at_send_command("AT+CFUN=1", &p_response); - if (err < 0|| p_response->success == 0) { - // Some stacks return an error when there is no SIM, - // but they really turn the RF portion on - // So, if we get an error, let's check to see if it - // turned on anyway - - if (isRadioOn() != 1) { - goto error; - } - } - setRadioState(RADIO_STATE_SIM_NOT_READY); - } - - at_response_free(p_response); - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); - return; -error: - at_response_free(p_response); - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} - -static void requestOrSendPDPContextList(RIL_Token *t); - -static void onPDPContextListChanged(void *param) -{ - requestOrSendPDPContextList(NULL); -} - -static void requestPDPContextList(void *data, size_t datalen, RIL_Token t) -{ - requestOrSendPDPContextList(&t); -} - -static void requestOrSendPDPContextList(RIL_Token *t) -{ - ATResponse *p_response; - ATLine *p_cur; - int err; - int n = 0; - char *out; - - err = at_send_command_multiline ("AT+CGACT?", "+CGACT:", &p_response); - if (err != 0 || p_response->success == 0) { - if (t != NULL) - RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0); - else - RIL_onUnsolicitedResponse(RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED, - NULL, 0); - return; - } - - for (p_cur = p_response->p_intermediates; p_cur != NULL; - p_cur = p_cur->p_next) - n++; - - RIL_PDP_Context_Response *responses = - alloca(n * sizeof(RIL_PDP_Context_Response)); - - int i; - for (i = 0; i < n; i++) { - responses[i].cid = -1; - responses[i].active = -1; - responses[i].type = ""; - responses[i].apn = ""; - responses[i].address = ""; - } - - RIL_PDP_Context_Response *response = responses; - for (p_cur = p_response->p_intermediates; p_cur != NULL; - p_cur = p_cur->p_next) { - char *line = p_cur->line; - - err = at_tok_start(&line); - if (err < 0) - goto error; - - err = at_tok_nextint(&line, &response->cid); - if (err < 0) - goto error; - - err = at_tok_nextint(&line, &response->active); - if (err < 0) - goto error; - - response++; - } - - at_response_free(p_response); - - err = at_send_command_multiline ("AT+CGDCONT?", "+CGDCONT:", &p_response); - if (err != 0 || p_response->success == 0) { - if (t != NULL) - RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0); - else - RIL_onUnsolicitedResponse(RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED, - NULL, 0); - return; - } - - for (p_cur = p_response->p_intermediates; p_cur != NULL; - p_cur = p_cur->p_next) { - char *line = p_cur->line; - int cid; - char *type; - char *apn; - char *address; - - - err = at_tok_start(&line); - if (err < 0) - goto error; - - err = at_tok_nextint(&line, &cid); - if (err < 0) - goto error; - - for (i = 0; i < n; i++) { - if (responses[i].cid == cid) - break; - } - - if (i >= n) { - /* details for a context we didn't hear about in the last request */ - continue; - } - - err = at_tok_nextstr(&line, &out); - if (err < 0) - goto error; - - responses[i].type = alloca(strlen(out) + 1); - strcpy(responses[i].type, out); - - err = at_tok_nextstr(&line, &out); - if (err < 0) - goto error; - - responses[i].apn = alloca(strlen(out) + 1); - strcpy(responses[i].apn, out); - - err = at_tok_nextstr(&line, &out); - if (err < 0) - goto error; - - responses[i].address = alloca(strlen(out) + 1); - strcpy(responses[i].address, out); - } - - at_response_free(p_response); - - if (t != NULL) - RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses, - n * sizeof(RIL_PDP_Context_Response)); - else - RIL_onUnsolicitedResponse(RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED, - responses, - n * sizeof(RIL_PDP_Context_Response)); - - return; - -error: - if (t != NULL) - RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0); - else - RIL_onUnsolicitedResponse(RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED, - NULL, 0); - - at_response_free(p_response); -} - -static void requestQueryNetworkSelectionMode( - void *data, size_t datalen, RIL_Token t) -{ - int err; - ATResponse *p_response = NULL; - int response = 0; - char *line; - - err = at_send_command_singleline("AT+COPS?", "+COPS:", &p_response); - - if (err < 0 || p_response->success == 0) { - goto error; - } - - line = p_response->p_intermediates->line; - - err = at_tok_start(&line); - - if (err < 0) { - goto error; - } - - err = at_tok_nextint(&line, &response); - - if (err < 0) { - goto error; - } - - RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int)); - at_response_free(p_response); - return; -error: - at_response_free(p_response); - LOGE("requestQueryNetworkSelectionMode must never return error when radio is on"); - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} - -static void sendCallStateChanged(void *param) -{ - RIL_onUnsolicitedResponse ( - RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, - NULL, 0); -} - -static void requestGetCurrentCalls(void *data, size_t datalen, RIL_Token t) -{ - int err; - ATResponse *p_response; - ATLine *p_cur; - int countCalls; - int countValidCalls; - RIL_Call *p_calls; - RIL_Call **pp_calls; - int i; - int needRepoll = 0; - -#ifdef WORKAROUND_ERRONEOUS_ANSWER - int prevIncomingOrWaitingLine; - - prevIncomingOrWaitingLine = s_incomingOrWaitingLine; - s_incomingOrWaitingLine = -1; -#endif /*WORKAROUND_ERRONEOUS_ANSWER*/ - - err = at_send_command_multiline ("AT+CLCC", "+CLCC:", &p_response); - - if (err != 0 || p_response->success == 0) { - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - return; - } - - /* count the calls */ - for (countCalls = 0, p_cur = p_response->p_intermediates - ; p_cur != NULL - ; p_cur = p_cur->p_next - ) { - countCalls++; - } - - /* yes, there's an array of pointers and then an array of structures */ - - pp_calls = (RIL_Call **)alloca(countCalls * sizeof(RIL_Call *)); - p_calls = (RIL_Call *)alloca(countCalls * sizeof(RIL_Call)); - memset (p_calls, 0, countCalls * sizeof(RIL_Call)); - - /* init the pointer array */ - for(i = 0; i < countCalls ; i++) { - pp_calls[i] = &(p_calls[i]); - } - - for (countValidCalls = 0, p_cur = p_response->p_intermediates - ; p_cur != NULL - ; p_cur = p_cur->p_next - ) { - err = callFromCLCCLine(p_cur->line, p_calls + countValidCalls); - - if (err != 0) { - continue; - } - -#ifdef WORKAROUND_ERRONEOUS_ANSWER - if (p_calls[countValidCalls].state == RIL_CALL_INCOMING - || p_calls[countValidCalls].state == RIL_CALL_WAITING - ) { - s_incomingOrWaitingLine = p_calls[countValidCalls].index; - } -#endif /*WORKAROUND_ERRONEOUS_ANSWER*/ - - if (p_calls[countValidCalls].state != RIL_CALL_ACTIVE - && p_calls[countValidCalls].state != RIL_CALL_HOLDING - ) { - needRepoll = 1; - } - - countValidCalls++; - } - -#ifdef WORKAROUND_ERRONEOUS_ANSWER - // Basically: - // A call was incoming or waiting - // Now it's marked as active - // But we never answered it - // - // This is probably a bug, and the call will probably - // disappear from the call list in the next poll - if (prevIncomingOrWaitingLine >= 0 - && s_incomingOrWaitingLine < 0 - && s_expectAnswer == 0 - ) { - for (i = 0; i < countValidCalls ; i++) { - - if (p_calls[i].index == prevIncomingOrWaitingLine - && p_calls[i].state == RIL_CALL_ACTIVE - && s_repollCallsCount < REPOLL_CALLS_COUNT_MAX - ) { - LOGI( - "Hit WORKAROUND_ERRONOUS_ANSWER case." - " Repoll count: %d\n", s_repollCallsCount); - s_repollCallsCount++; - goto error; - } - } - } - - s_expectAnswer = 0; - s_repollCallsCount = 0; -#endif /*WORKAROUND_ERRONEOUS_ANSWER*/ - - RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls, - countValidCalls * sizeof (RIL_Call *)); - - at_response_free(p_response); - -#ifdef POLL_CALL_STATE - if (countValidCalls) { // We don't seem to get a "NO CARRIER" message from - // smd, so we're forced to poll until the call ends. -#else - if (needRepoll) { -#endif - RIL_requestTimedCallback (sendCallStateChanged, NULL, &TIMEVAL_CALLSTATEPOLL); - } - - return; -error: - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - at_response_free(p_response); -} - -static void requestDial(void *data, size_t datalen, RIL_Token t) -{ - RIL_Dial *p_dial; - char *cmd; - const char *clir; - int ret; - - p_dial = (RIL_Dial *)data; - - switch (p_dial->clir) { - case 1: clir = "I"; break; /*invocation*/ - case 2: clir = "i"; break; /*suppression*/ - default: - case 0: clir = ""; break; /*subscription default*/ - } - - asprintf(&cmd, "ATD%s%s;", p_dial->address, clir); - - ret = at_send_command(cmd, NULL); - - free(cmd); - - /* success or failure is ignored by the upper layer here. - it will call GET_CURRENT_CALLS and determine success that way */ - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); -} - -static void requestWriteSmsToSim(void *data, size_t datalen, RIL_Token t) -{ - RIL_SMS_WriteArgs *p_args; - char *cmd; - int length; - int err; - ATResponse *p_response = NULL; - - p_args = (RIL_SMS_WriteArgs *)data; - - length = strlen(p_args->pdu)/2; - asprintf(&cmd, "AT+CMGW=%d,%d", length, p_args->status); - - err = at_send_command_sms(cmd, p_args->pdu, "+CMGW:", &p_response); - - if (err != 0 || p_response->success == 0) goto error; - - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); - at_response_free(p_response); - - return; -error: - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - at_response_free(p_response); -} - -static void requestHangup(void *data, size_t datalen, RIL_Token t) -{ - int *p_line; - - int ret; - char *cmd; - - p_line = (int *)data; - - // 3GPP 22.030 6.5.5 - // "Releases a specific active call X" - asprintf(&cmd, "AT+CHLD=1%d", p_line[0]); - - ret = at_send_command(cmd, NULL); - - free(cmd); - - /* success or failure is ignored by the upper layer here. - it will call GET_CURRENT_CALLS and determine success that way */ - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); -} - -static void requestSignalStrength(void *data, size_t datalen, RIL_Token t) -{ - ATResponse *p_response = NULL; - int err; - int response[2]; - char *line; - - err = at_send_command_singleline("AT+CSQ", "+CSQ:", &p_response); - - if (err < 0 || p_response->success == 0) { - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - goto error; - } - - line = p_response->p_intermediates->line; - - err = at_tok_start(&line); - if (err < 0) goto error; - - err = at_tok_nextint(&line, &(response[0])); - if (err < 0) goto error; - - err = at_tok_nextint(&line, &(response[1])); - if (err < 0) goto error; - - RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response)); - - at_response_free(p_response); - return; - -error: - LOGE("requestSignalStrength must never return an error when radio is on"); - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - at_response_free(p_response); -} - -static void requestRegistrationState(int request, void *data, - size_t datalen, RIL_Token t) -{ - int err; - int response[4]; - char * responseStr[4]; - ATResponse *p_response = NULL; - const char *cmd; - const char *prefix; - char *line, *p; - int commas; - int skip; - int count = 3; - - - if (request == RIL_REQUEST_REGISTRATION_STATE) { - cmd = "AT+CREG?"; - prefix = "+CREG:"; - } else if (request == RIL_REQUEST_GPRS_REGISTRATION_STATE) { - cmd = "AT+CGREG?"; - prefix = "+CGREG:"; - } else { - assert(0); - goto error; - } - - err = at_send_command_singleline(cmd, prefix, &p_response); - - if (err != 0) goto error; - - line = p_response->p_intermediates->line; - - err = at_tok_start(&line); - if (err < 0) goto error; - - /* Ok you have to be careful here - * The solicited version of the CREG response is - * +CREG: n, stat, [lac, cid] - * and the unsolicited version is - * +CREG: stat, [lac, cid] - * The <n> parameter is basically "is unsolicited creg on?" - * which it should always be - * - * Now we should normally get the solicited version here, - * but the unsolicited version could have snuck in - * so we have to handle both - * - * Also since the LAC and CID are only reported when registered, - * we can have 1, 2, 3, or 4 arguments here - * - * finally, a +CGREG: answer may have a fifth value that corresponds - * to the network type, as in; - * - * +CGREG: n, stat [,lac, cid [,networkType]] - */ - - /* count number of commas */ - commas = 0; - for (p = line ; *p != '\0' ;p++) { - if (*p == ',') commas++; - } - - switch (commas) { - case 0: /* +CREG: <stat> */ - err = at_tok_nextint(&line, &response[0]); - if (err < 0) goto error; - response[1] = -1; - response[2] = -1; - break; - - case 1: /* +CREG: <n>, <stat> */ - err = at_tok_nextint(&line, &skip); - if (err < 0) goto error; - err = at_tok_nextint(&line, &response[0]); - if (err < 0) goto error; - response[1] = -1; - response[2] = -1; - if (err < 0) goto error; - break; - - case 2: /* +CREG: <stat>, <lac>, <cid> */ - err = at_tok_nextint(&line, &response[0]); - if (err < 0) goto error; - err = at_tok_nexthexint(&line, &response[1]); - if (err < 0) goto error; - err = at_tok_nexthexint(&line, &response[2]); - if (err < 0) goto error; - break; - case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */ - err = at_tok_nextint(&line, &skip); - if (err < 0) goto error; - err = at_tok_nextint(&line, &response[0]); - if (err < 0) goto error; - err = at_tok_nexthexint(&line, &response[1]); - if (err < 0) goto error; - err = at_tok_nexthexint(&line, &response[2]); - if (err < 0) goto error; - break; - /* special case for CGREG, there is a fourth parameter - * that is the network type (unknown/gprs/edge/umts) - */ - case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <networkType> */ - err = at_tok_nextint(&line, &skip); - if (err < 0) goto error; - err = at_tok_nextint(&line, &response[0]); - if (err < 0) goto error; - err = at_tok_nexthexint(&line, &response[1]); - if (err < 0) goto error; - err = at_tok_nexthexint(&line, &response[2]); - if (err < 0) goto error; - err = at_tok_nexthexint(&line, &response[3]); - if (err < 0) goto error; - count = 4; - break; - default: - goto error; - } - - asprintf(&responseStr[0], "%d", response[0]); - asprintf(&responseStr[1], "%d", response[1]); - asprintf(&responseStr[2], "%d", response[2]); - - if (count > 3) - asprintf(&responseStr[3], "%d", response[3]); - - RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*)); - at_response_free(p_response); - - return; -error: - LOGE("requestRegistrationState must never return an error when radio is on"); - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - at_response_free(p_response); -} - -static void requestOperator(void *data, size_t datalen, RIL_Token t) -{ - int err; - int i; - int skip; - ATLine *p_cur; - char *response[3]; - - memset(response, 0, sizeof(response)); - - ATResponse *p_response = NULL; - - err = at_send_command_multiline( - "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?", - "+COPS:", &p_response); - - /* we expect 3 lines here: - * +COPS: 0,0,"T - Mobile" - * +COPS: 0,1,"TMO" - * +COPS: 0,2,"310170" - */ - - if (err != 0) goto error; - - for (i = 0, p_cur = p_response->p_intermediates - ; p_cur != NULL - ; p_cur = p_cur->p_next, i++ - ) { - char *line = p_cur->line; - - err = at_tok_start(&line); - if (err < 0) goto error; - - err = at_tok_nextint(&line, &skip); - if (err < 0) goto error; - - // If we're unregistered, we may just get - // a "+COPS: 0" response - if (!at_tok_hasmore(&line)) { - response[i] = NULL; - continue; - } - - err = at_tok_nextint(&line, &skip); - if (err < 0) goto error; - - // a "+COPS: 0, n" response is also possible - if (!at_tok_hasmore(&line)) { - response[i] = NULL; - continue; - } - - err = at_tok_nextstr(&line, &(response[i])); - if (err < 0) goto error; - } - - if (i != 3) { - /* expect 3 lines exactly */ - goto error; - } - - RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response)); - at_response_free(p_response); - - return; -error: - LOGE("requestOperator must not return error when radio is on"); - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - at_response_free(p_response); -} - -static void requestSendSMS(void *data, size_t datalen, RIL_Token t) -{ - int err; - const char *smsc; - const char *pdu; - int tpLayerLength; - char *cmd1, *cmd2; - RIL_SMS_Response response; - ATResponse *p_response = NULL; - - smsc = ((const char **)data)[0]; - pdu = ((const char **)data)[1]; - - tpLayerLength = strlen(pdu)/2; - - // "NULL for default SMSC" - if (smsc == NULL) { - smsc= "00"; - } - - asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength); - asprintf(&cmd2, "%s%s", smsc, pdu); - - err = at_send_command_sms(cmd1, cmd2, "+CMGS:", &p_response); - - if (err != 0 || p_response->success == 0) goto error; - - memset(&response, 0, sizeof(response)); - - /* FIXME fill in messageRef and ackPDU */ - - RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response)); - at_response_free(p_response); - - return; -error: - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - at_response_free(p_response); -} - -static void requestSetupDefaultPDP(void *data, size_t datalen, RIL_Token t) -{ - const char *apn; - char *cmd; - int err; - ATResponse *p_response = NULL; - char *response[2] = { "1", PPP_TTY_PATH }; - - apn = ((const char **)data)[0]; - -#ifdef USE_TI_COMMANDS - // Config for multislot class 10 (probably default anyway eh?) - err = at_send_command("AT%CPRIM=\"GMM\",\"CONFIG MULTISLOT_CLASS=<10>\"", - NULL); - - err = at_send_command("AT%DATA=2,\"UART\",1,,\"SER\",\"UART\",0", NULL); -#endif /* USE_TI_COMMANDS */ - - int fd, qmistatus; - size_t cur = 0; - size_t len; - ssize_t written, rlen; - char status[32] = {0}; - int retry = 10; - - LOGD("requesting data connection to APN '%s'", apn); - - fd = open ("/dev/qmi", O_RDWR); - if (fd >= 0) { /* the device doesn't exist on the emulator */ - - LOGD("opened the qmi device\n"); - asprintf(&cmd, "up:%s", apn); - len = strlen(cmd); - - while (cur < len) { - do { - written = write (fd, cmd + cur, len - cur); - } while (written < 0 && errno == EINTR); - - if (written < 0) { - LOGE("### ERROR writing to /dev/qmi"); - close(fd); - goto error; - } - - cur += written; - } - - // wait for interface to come online - - do { - sleep(1); - do { - rlen = read(fd, status, 31); - } while (rlen < 0 && errno == EINTR); - - if (rlen < 0) { - LOGE("### ERROR reading from /dev/qmi"); - close(fd); - goto error; - } else { - status[rlen] = '\0'; - LOGD("### status: %s", status); - } - } while (strncmp(status, "STATE=up", 8) && strcmp(status, "online") && --retry); - - close(fd); - - if (retry == 0) { - LOGE("### Failed to get data connection up\n"); - goto error; - } - - qmistatus = system("netcfg rmnet0 dhcp"); - - LOGD("netcfg rmnet0 dhcp: status %d\n", qmistatus); - - if (qmistatus < 0) goto error; - - } else { - - asprintf(&cmd, "AT+CGDCONT=1,\"IP\",\"%s\",,0,0", apn); - //FIXME check for error here - err = at_send_command(cmd, NULL); - free(cmd); - - // Set required QoS params to default - err = at_send_command("AT+CGQREQ=1", NULL); - - // Set minimum QoS params to default - err = at_send_command("AT+CGQMIN=1", NULL); - - // packet-domain event reporting - err = at_send_command("AT+CGEREP=1,0", NULL); - - // Hangup anything that's happening there now - err = at_send_command("AT+CGACT=1,0", NULL); - - // Start data on PDP context 1 - err = at_send_command("ATD*99***1#", &p_response); - - if (err < 0 || p_response->success == 0) { - goto error; - } - } - - RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response)); - at_response_free(p_response); - - return; -error: - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - at_response_free(p_response); - -} - -static void requestSMSAcknowledge(void *data, size_t datalen, RIL_Token t) -{ - int ackSuccess; - int err; - - ackSuccess = ((int *)data)[0]; - - if (ackSuccess == 1) { - err = at_send_command("AT+CNMA=1", NULL); - } else if (ackSuccess == 0) { - err = at_send_command("AT+CNMA=2", NULL); - } else { - LOGE("unsupported arg to RIL_REQUEST_SMS_ACKNOWLEDGE\n"); - goto error; - } - - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); -error: - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - -} - -static void requestSIM_IO(void *data, size_t datalen, RIL_Token t) -{ - ATResponse *p_response = NULL; - RIL_SIM_IO_Response sr; - int err; - char *cmd = NULL; - RIL_SIM_IO *p_args; - char *line; - - memset(&sr, 0, sizeof(sr)); - - p_args = (RIL_SIM_IO *)data; - - /* FIXME handle pin2 */ - - if (p_args->data == NULL) { - asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d", - p_args->command, p_args->fileid, - p_args->p1, p_args->p2, p_args->p3); - } else { - asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d,%s", - p_args->command, p_args->fileid, - p_args->p1, p_args->p2, p_args->p3, p_args->data); - } - - err = at_send_command_singleline(cmd, "+CRSM:", &p_response); - - if (err < 0 || p_response->success == 0) { - goto error; - } - - line = p_response->p_intermediates->line; - - err = at_tok_start(&line); - if (err < 0) goto error; - - err = at_tok_nextint(&line, &(sr.sw1)); - if (err < 0) goto error; - - err = at_tok_nextint(&line, &(sr.sw2)); - if (err < 0) goto error; - - if (at_tok_hasmore(&line)) { - err = at_tok_nextstr(&line, &(sr.simResponse)); - if (err < 0) goto error; - } - - RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr)); - at_response_free(p_response); - free(cmd); - - return; -error: - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - at_response_free(p_response); - free(cmd); - -} - -static void requestEnterSimPin(void* data, size_t datalen, RIL_Token t) -{ - ATResponse *p_response = NULL; - int err; - char* cmd = NULL; - const char** strings = (const char**)data;; - - if ( datalen == sizeof(char*) ) { - asprintf(&cmd, "AT+CPIN=%s", strings[0]); - } else if ( datalen == 2*sizeof(char*) ) { - asprintf(&cmd, "AT+CPIN=%s,%s", strings[0], strings[1]); - } else - goto error; - - err = at_send_command_singleline(cmd, "+CPIN:", &p_response); - free(cmd); - - if (err < 0 || p_response->success == 0) { -error: - RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, NULL, 0); - } else { - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); - } - at_response_free(p_response); -} - - -static void requestSendUSSD(void *data, size_t datalen, RIL_Token t) -{ - const char *ussdRequest; - - ussdRequest = (char *)(data); - - - RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0); - -// @@@ TODO - -} - - -/*** Callback methods from the RIL library to us ***/ - -/** - * Call from RIL to us to make a RIL_REQUEST - * - * Must be completed with a call to RIL_onRequestComplete() - * - * RIL_onRequestComplete() may be called from any thread, before or after - * this function returns. - * - * Will always be called from the same thread, so returning here implies - * that the radio is ready to process another command (whether or not - * the previous command has completed). - */ -static void -onRequest (int request, void *data, size_t datalen, RIL_Token t) -{ - ATResponse *p_response; - int err; - - LOGD("onRequest: %s", requestToString(request)); - - /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS - * when RADIO_STATE_UNAVAILABLE. - */ - if (sState == RADIO_STATE_UNAVAILABLE - && request != RIL_REQUEST_GET_SIM_STATUS - ) { - RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0); - return; - } - - /* Ignore all non-power requests when RADIO_STATE_OFF - * (except RIL_REQUEST_GET_SIM_STATUS) - */ - if (sState == RADIO_STATE_OFF - && !(request == RIL_REQUEST_RADIO_POWER - || request == RIL_REQUEST_GET_SIM_STATUS) - ) { - RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0); - return; - } - - switch (request) { - case RIL_REQUEST_GET_SIM_STATUS: { - int simStatus; - - simStatus = getSIMStatus(); - - RIL_onRequestComplete(t, RIL_E_SUCCESS, &simStatus, sizeof(simStatus)); - break; - } - case RIL_REQUEST_GET_CURRENT_CALLS: - requestGetCurrentCalls(data, datalen, t); - break; - case RIL_REQUEST_DIAL: - requestDial(data, datalen, t); - break; - case RIL_REQUEST_HANGUP: - requestHangup(data, datalen, t); - break; - case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: - // 3GPP 22.030 6.5.5 - // "Releases all held calls or sets User Determined User Busy - // (UDUB) for a waiting call." - at_send_command("AT+CHLD=0", NULL); - - /* success or failure is ignored by the upper layer here. - it will call GET_CURRENT_CALLS and determine success that way */ - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); - break; - case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: - // 3GPP 22.030 6.5.5 - // "Releases all active calls (if any exist) and accepts - // the other (held or waiting) call." - at_send_command("AT+CHLD=1", NULL); - - /* success or failure is ignored by the upper layer here. - it will call GET_CURRENT_CALLS and determine success that way */ - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); - break; - case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: - // 3GPP 22.030 6.5.5 - // "Places all active calls (if any exist) on hold and accepts - // the other (held or waiting) call." - at_send_command("AT+CHLD=2", NULL); - -#ifdef WORKAROUND_ERRONEOUS_ANSWER - s_expectAnswer = 1; -#endif /* WORKAROUND_ERRONEOUS_ANSWER */ - - /* success or failure is ignored by the upper layer here. - it will call GET_CURRENT_CALLS and determine success that way */ - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); - break; - case RIL_REQUEST_ANSWER: - at_send_command("ATA", NULL); - -#ifdef WORKAROUND_ERRONEOUS_ANSWER - s_expectAnswer = 1; -#endif /* WORKAROUND_ERRONEOUS_ANSWER */ - - /* success or failure is ignored by the upper layer here. - it will call GET_CURRENT_CALLS and determine success that way */ - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); - break; - case RIL_REQUEST_CONFERENCE: - // 3GPP 22.030 6.5.5 - // "Adds a held call to the conversation" - at_send_command("AT+CHLD=3", NULL); - - /* success or failure is ignored by the upper layer here. - it will call GET_CURRENT_CALLS and determine success that way */ - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); - break; - case RIL_REQUEST_UDUB: - /* user determined user busy */ - /* sometimes used: ATH */ - at_send_command("ATH", NULL); - - /* success or failure is ignored by the upper layer here. - it will call GET_CURRENT_CALLS and determine success that way */ - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); - break; - - case RIL_REQUEST_SEPARATE_CONNECTION: - { - char cmd[12]; - int party = ((int*)data)[0]; - - // Make sure that party is in a valid range. - // (Note: The Telephony middle layer imposes a range of 1 to 7. - // It's sufficient for us to just make sure it's single digit.) - if (party > 0 && party < 10) { - sprintf(cmd, "AT+CHLD=2%d", party); - at_send_command(cmd, NULL); - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); - } else { - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - } - } - break; - - case RIL_REQUEST_SIGNAL_STRENGTH: - requestSignalStrength(data, datalen, t); - break; - case RIL_REQUEST_REGISTRATION_STATE: - case RIL_REQUEST_GPRS_REGISTRATION_STATE: - requestRegistrationState(request, data, datalen, t); - break; - case RIL_REQUEST_OPERATOR: - requestOperator(data, datalen, t); - break; - case RIL_REQUEST_RADIO_POWER: - requestRadioPower(data, datalen, t); - break; - case RIL_REQUEST_DTMF: { - char c = ((char *)data)[0]; - char *cmd; - asprintf(&cmd, "AT+VTS=%c", (int)c); - at_send_command(cmd, NULL); - free(cmd); - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); - break; - } - case RIL_REQUEST_SEND_SMS: - requestSendSMS(data, datalen, t); - break; - case RIL_REQUEST_SETUP_DEFAULT_PDP: - requestSetupDefaultPDP(data, datalen, t); - break; - case RIL_REQUEST_SMS_ACKNOWLEDGE: - requestSMSAcknowledge(data, datalen, t); - break; - - case RIL_REQUEST_GET_IMSI: - p_response = NULL; - err = at_send_command_numeric("AT+CIMI", &p_response); - - if (err < 0 || p_response->success == 0) { - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - } else { - RIL_onRequestComplete(t, RIL_E_SUCCESS, - p_response->p_intermediates->line, sizeof(char *)); - } - at_response_free(p_response); - break; - - case RIL_REQUEST_GET_IMEI: - p_response = NULL; - err = at_send_command_numeric("AT+CGSN", &p_response); - - if (err < 0 || p_response->success == 0) { - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - } else { - RIL_onRequestComplete(t, RIL_E_SUCCESS, - p_response->p_intermediates->line, sizeof(char *)); - } - at_response_free(p_response); - break; - - case RIL_REQUEST_SIM_IO: - requestSIM_IO(data,datalen,t); - break; - - case RIL_REQUEST_SEND_USSD: - requestSendUSSD(data, datalen, t); - break; - - case RIL_REQUEST_CANCEL_USSD: - p_response = NULL; - err = at_send_command_numeric("AT+CUSD=2", &p_response); - - if (err < 0 || p_response->success == 0) { - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - } else { - RIL_onRequestComplete(t, RIL_E_SUCCESS, - p_response->p_intermediates->line, sizeof(char *)); - } - at_response_free(p_response); - break; - - case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: - at_send_command("AT+COPS=0", NULL); - break; - - case RIL_REQUEST_PDP_CONTEXT_LIST: - requestPDPContextList(data, datalen, t); - break; - - case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: - requestQueryNetworkSelectionMode(data, datalen, t); - break; - - case RIL_REQUEST_OEM_HOOK_RAW: - // echo back data - RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen); - break; - - - case RIL_REQUEST_OEM_HOOK_STRINGS: { - int i; - const char ** cur; - - LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen); - - - for (i = (datalen / sizeof (char *)), cur = (const char **)data ; - i > 0 ; cur++, i --) { - LOGD("> '%s'", *cur); - } - - // echo back strings - RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen); - break; - } - - case RIL_REQUEST_WRITE_SMS_TO_SIM: - requestWriteSmsToSim(data, datalen, t); - break; - - case RIL_REQUEST_DELETE_SMS_ON_SIM: { - char * cmd; - p_response = NULL; - asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]); - err = at_send_command(cmd, &p_response); - free(cmd); - if (err < 0 || p_response->success == 0) { - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); - } else { - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); - } - at_response_free(p_response); - break; - } - - case RIL_REQUEST_ENTER_SIM_PIN: - case RIL_REQUEST_ENTER_SIM_PUK: - case RIL_REQUEST_ENTER_SIM_PIN2: - case RIL_REQUEST_ENTER_SIM_PUK2: - case RIL_REQUEST_CHANGE_SIM_PIN: - case RIL_REQUEST_CHANGE_SIM_PIN2: - requestEnterSimPin(data, datalen, t); - break; - - default: - RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0); - break; - } -} - -/** - * Synchronous call from the RIL to us to return current radio state. - * RADIO_STATE_UNAVAILABLE should be the initial state. - */ -static RIL_RadioState -currentState() -{ - return sState; -} -/** - * Call from RIL to us to find out whether a specific request code - * is supported by this implementation. - * - * Return 1 for "supported" and 0 for "unsupported" - */ - -static int -onSupports (int requestCode) -{ - //@@@ todo - - return 1; -} - -static void onCancel (RIL_Token t) -{ - //@@@todo - -} - -static const char * getVersion(void) -{ - return "android reference-ril 1.0"; -} - -static void -setRadioState(RIL_RadioState newState) -{ - RIL_RadioState oldState; - - pthread_mutex_lock(&s_state_mutex); - - oldState = sState; - - if (s_closed > 0) { - // If we're closed, the only reasonable state is - // RADIO_STATE_UNAVAILABLE - // This is here because things on the main thread - // may attempt to change the radio state after the closed - // event happened in another thread - newState = RADIO_STATE_UNAVAILABLE; - } - - if (sState != newState || s_closed > 0) { - sState = newState; - - pthread_cond_broadcast (&s_state_cond); - } - - pthread_mutex_unlock(&s_state_mutex); - - - /* do these outside of the mutex */ - if (sState != oldState) { - RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, - NULL, 0); - - /* FIXME onSimReady() and onRadioPowerOn() cannot be called - * from the AT reader thread - * Currently, this doesn't happen, but if that changes then these - * will need to be dispatched on the request thread - */ - if (sState == RADIO_STATE_SIM_READY) { - onSIMReady(); - } else if (sState == RADIO_STATE_SIM_NOT_READY) { - onRadioPowerOn(); - } - } -} - -/** returns one of RIM_SIM_*. Returns RIL_SIM_NOT_READY on error */ -static int -getSIMStatus() -{ - ATResponse *p_response = NULL; - int err; - int ret; - char *cpinLine; - char *cpinResult; - - if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) { - ret = RIL_SIM_NOT_READY; - goto done; - } - - err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response); - - if (err != 0) { - ret = RIL_SIM_NOT_READY; - goto done; - } - - switch (at_get_cme_error(p_response)) { - case CME_SUCCESS: - break; - - case CME_SIM_NOT_INSERTED: - ret = RIL_SIM_ABSENT; - goto done; - - default: - ret = RIL_SIM_NOT_READY; - goto done; - } - - /* CPIN? has succeeded, now look at the result */ - - cpinLine = p_response->p_intermediates->line; - err = at_tok_start (&cpinLine); - - if (err < 0) { - ret = RIL_SIM_NOT_READY; - goto done; - } - - err = at_tok_nextstr(&cpinLine, &cpinResult); - - if (err < 0) { - ret = RIL_SIM_NOT_READY; - goto done; - } - - if (0 == strcmp (cpinResult, "SIM PIN")) { - ret = RIL_SIM_PIN; - goto done; - } else if (0 == strcmp (cpinResult, "SIM PUK")) { - ret = RIL_SIM_PUK; - goto done; - } else if (0 == strcmp (cpinResult, "PH-NET PIN")) { - return RIL_SIM_NETWORK_PERSONALIZATION; - } else if (0 != strcmp (cpinResult, "READY")) { - /* we're treating unsupported lock types as "sim absent" */ - ret = RIL_SIM_ABSENT; - goto done; - } - - at_response_free(p_response); - p_response = NULL; - cpinResult = NULL; - - ret = RIL_SIM_READY; - -done: - at_response_free(p_response); - return ret; -} - - -/** - * SIM ready means any commands that access the SIM will work, including: - * AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM - * (all SMS-related commands) - */ - -static void pollSIMState (void *param) -{ - ATResponse *p_response; - int ret; - - if (sState != RADIO_STATE_SIM_NOT_READY) { - // no longer valid to poll - return; - } - - switch(getSIMStatus()) { - case RIL_SIM_ABSENT: - case RIL_SIM_PIN: - case RIL_SIM_PUK: - case RIL_SIM_NETWORK_PERSONALIZATION: - default: - setRadioState(RADIO_STATE_SIM_LOCKED_OR_ABSENT); - return; - - case RIL_SIM_NOT_READY: - RIL_requestTimedCallback (pollSIMState, NULL, &TIMEVAL_SIMPOLL); - return; - - case RIL_SIM_READY: - setRadioState(RADIO_STATE_SIM_READY); - return; - } -} - -/** returns 1 if on, 0 if off, and -1 on error */ -static int isRadioOn() -{ - ATResponse *p_response = NULL; - int err; - char *line; - char ret; - - err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &p_response); - - if (err < 0 || p_response->success == 0) { - // assume radio is off - goto error; - } - - line = p_response->p_intermediates->line; - - err = at_tok_start(&line); - if (err < 0) goto error; - - err = at_tok_nextbool(&line, &ret); - if (err < 0) goto error; - - at_response_free(p_response); - - return (int)ret; - -error: - - at_response_free(p_response); - return -1; -} - -/** - * Initialize everything that can be configured while we're still in - * AT+CFUN=0 - */ -static void initializeCallback(void *param) -{ - ATResponse *p_response = NULL; - int err; - - setRadioState (RADIO_STATE_OFF); - - at_handshake(); - - /* note: we don't check errors here. Everything important will - be handled in onATTimeout and onATReaderClosed */ - - /* atchannel is tolerant of echo but it must */ - /* have verbose result codes */ - at_send_command("ATE0Q0V1", NULL); - - /* No auto-answer */ - at_send_command("ATS0=0", NULL); - - /* Extended errors */ - at_send_command("AT+CMEE=1", NULL); - - /* Network registration events */ - err = at_send_command("AT+CREG=2", &p_response); - - /* some handsets -- in tethered mode -- don't support CREG=2 */ - if (err < 0 || p_response->success == 0) { - at_send_command("AT+CREG=1", NULL); - } - - at_response_free(p_response); - - /* GPRS registration events */ - at_send_command("AT+CGREG=1", NULL); - - /* Call Waiting notifications */ - at_send_command("AT+CCWA=1", NULL); - - /* Alternating voice/data off */ - at_send_command("AT+CMOD=0", NULL); - - /* Not muted */ - at_send_command("AT+CMUT=0", NULL); - - /* +CSSU unsolicited supp service notifications */ - at_send_command("AT+CSSN=0,1", NULL); - - /* no connected line identification */ - at_send_command("AT+COLP=0", NULL); - - /* HEX character set */ - at_send_command("AT+CSCS=\"HEX\"", NULL); - - /* USSD unsolicited */ - at_send_command("AT+CUSD=1", NULL); - - /* Enable +CGEV GPRS event notifications, but don't buffer */ - at_send_command("AT+CGEREP=1,0", NULL); - - /* SMS PDU mode */ - at_send_command("AT+CMGF=0", NULL); - -#ifdef USE_TI_COMMANDS - - at_send_command("AT%CPI=3", NULL); - - /* TI specific -- notifications when SMS is ready (currently ignored) */ - at_send_command("AT%CSTAT=1", NULL); - -#endif /* USE_TI_COMMANDS */ - - - /* assume radio is off on error */ - if (isRadioOn() > 0) { - setRadioState (RADIO_STATE_SIM_NOT_READY); - } -} - -static void waitForClose() -{ - pthread_mutex_lock(&s_state_mutex); - - while (s_closed == 0) { - pthread_cond_wait(&s_state_cond, &s_state_mutex); - } - - pthread_mutex_unlock(&s_state_mutex); -} - -/** - * Called by atchannel when an unsolicited line appears - * This is called on atchannel's reader thread. AT commands may - * not be issued here - */ -static void onUnsolicited (const char *s, const char *sms_pdu) -{ - char *line = NULL; - int err; - - /* Ignore unsolicited responses until we're initialized. - * This is OK because the RIL library will poll for initial state - */ - if (sState == RADIO_STATE_UNAVAILABLE) { - return; - } - - if (strStartsWith(s, "%CTZV:")) { - /* TI specific -- NITZ time */ - char *response; - - line = strdup(s); - at_tok_start(&line); - - err = at_tok_nextstr(&line, &response); - - if (err != 0) { - LOGE("invalid NITZ line %s\n", s); - } else { - RIL_onUnsolicitedResponse ( - RIL_UNSOL_NITZ_TIME_RECEIVED, - response, strlen(response)); - } - } else if (strStartsWith(s,"+CRING:") - || strStartsWith(s,"RING") - || strStartsWith(s,"NO CARRIER") - || strStartsWith(s,"+CCWA") - ) { - RIL_onUnsolicitedResponse ( - RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, - NULL, 0); -#ifdef WORKAROUND_FAKE_CGEV - RIL_requestTimedCallback (onPDPContextListChanged, NULL, NULL); -#endif /* WORKAROUND_FAKE_CGEV */ - } else if (strStartsWith(s,"+CREG:") - || strStartsWith(s,"+CGREG:") - ) { - RIL_onUnsolicitedResponse ( - RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, - NULL, 0); -#ifdef WORKAROUND_FAKE_CGEV - RIL_requestTimedCallback (onPDPContextListChanged, NULL, NULL); -#endif /* WORKAROUND_FAKE_CGEV */ - } else if (strStartsWith(s, "+CMT:")) { - RIL_onUnsolicitedResponse ( - RIL_UNSOL_RESPONSE_NEW_SMS, - sms_pdu, strlen(sms_pdu)); - } else if (strStartsWith(s, "+CDS:")) { - RIL_onUnsolicitedResponse ( - RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, - sms_pdu, strlen(sms_pdu)); - } else if (strStartsWith(s, "+CGEV:")) { - /* Really, we can ignore NW CLASS and ME CLASS events here, - * but right now we don't since extranous - * RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED calls are tolerated - */ - /* can't issue AT commands here -- call on main thread */ - RIL_requestTimedCallback (onPDPContextListChanged, NULL, NULL); -#ifdef WORKAROUND_FAKE_CGEV - } else if (strStartsWith(s, "+CME ERROR: 150")) { - RIL_requestTimedCallback (onPDPContextListChanged, NULL, NULL); -#endif /* WORKAROUND_FAKE_CGEV */ - } -} - -/* Called on command or reader thread */ -static void onATReaderClosed() -{ - LOGI("AT channel closed\n"); - at_close(); - s_closed = 1; - - setRadioState (RADIO_STATE_UNAVAILABLE); -} - -/* Called on command thread */ -static void onATTimeout() -{ - LOGI("AT channel timeout; closing\n"); - at_close(); - - s_closed = 1; - - /* FIXME cause a radio reset here */ - - setRadioState (RADIO_STATE_UNAVAILABLE); -} - -static void usage(char *s) -{ -#ifdef RIL_SHLIB - fprintf(stderr, "reference-ril requires: -p <tcp port> or -d /dev/tty_device\n"); -#else - fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device]\n", s); - exit(-1); -#endif -} - -static void * -mainLoop(void *param) -{ - int fd; - int ret; - - AT_DUMP("== ", "entering mainLoop()", -1 ); - at_set_on_reader_closed(onATReaderClosed); - at_set_on_timeout(onATTimeout); - - for (;;) { - fd = -1; - while (fd < 0) { - if (s_port > 0) { - fd = socket_loopback_client(s_port, SOCK_STREAM); - } else if (s_device_socket) { - fd = socket_local_client( s_device_path, - ANDROID_SOCKET_NAMESPACE_FILESYSTEM, - SOCK_STREAM ); - } else if (s_device_path != NULL) { - fd = open (s_device_path, O_RDWR); - if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) { - /* disable echo on serial ports */ - struct termios ios; - tcgetattr( fd, &ios ); - ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */ - tcsetattr( fd, TCSANOW, &ios ); - } - } - - if (fd < 0) { - perror ("opening AT interface. retrying..."); - sleep(10); - /* never returns */ - } - } - - s_closed = 0; - ret = at_open(fd, onUnsolicited); - - if (ret < 0) { - LOGE ("AT error %d on at_open\n", ret); - return 0; - } - - RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0); - - // Give initializeCallback a chance to dispatched, since - // we don't presently have a cancellation mechanism - sleep(1); - - waitForClose(); - LOGI("Re-opening after close"); - } -} - -#ifdef RIL_SHLIB - -pthread_t s_tid_mainloop; - -const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv) -{ - int ret; - int fd = -1; - int opt; - pthread_attr_t attr; - - s_rilenv = env; - - while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) { - switch (opt) { - case 'p': - s_port = atoi(optarg); - if (s_port == 0) { - usage(argv[0]); - return NULL; - } - LOGI("Opening loopback port %d\n", s_port); - break; - - case 'd': - s_device_path = optarg; - LOGI("Opening tty device %s\n", s_device_path); - break; - - case 's': - s_device_path = optarg; - s_device_socket = 1; - LOGI("Opening socket %s\n", s_device_path); - break; - - default: - usage(argv[0]); - return NULL; - } - } - - if (s_port < 0 && s_device_path == NULL) { - usage(argv[0]); - return NULL; - } - - pthread_attr_init (&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL); - - return &s_callbacks; -} -#else /* RIL_SHLIB */ -int main (int argc, char **argv) -{ - int ret; - int fd = -1; - int opt; - - while ( -1 != (opt = getopt(argc, argv, "p:d:"))) { - switch (opt) { - case 'p': - s_port = atoi(optarg); - if (s_port == 0) { - usage(argv[0]); - } - LOGI("Opening loopback port %d\n", s_port); - break; - - case 'd': - s_device_path = optarg; - LOGI("Opening tty device %s\n", s_device_path); - break; - - case 's': - s_device_path = optarg; - s_device_socket = 1; - LOGI("Opening socket %s\n", s_device_path); - break; - - default: - usage(argv[0]); - } - } - - if (s_port < 0 && s_device_path == NULL) { - usage(argv[0]); - } - - RIL_register(&s_callbacks); - - mainLoop(NULL); - - return 0; -} - -#endif /* RIL_SHLIB */ |