Honeycomb and 3G

788 views
Skip to first unread message

Nicolas

unread,
Dec 28, 2011, 10:35:38 AM12/28/11
to andro...@googlegroups.com
Hello, I am trying to understand the state of 3G support in Honeycomb.

I have a Huawei E1800 external USB modem and a tegav2 image with 3.2.2. After I disabled the cd-rom functionality, the modem was detected by android. I have /dev/ttyUSB0, /dev/ttyUSB1 and /dev/ttyUSB2 present on my device. All are owned by radio.radio.

I cannot find any networks. Logcat shows a stack dump for rild every 3 seconds or so.

What do I need to do to get 3G to work?

Thank you for the great work!

Nic

unread,
Dec 28, 2011, 12:46:07 PM12/28/11
to andro...@googlegroups.com
Browsing the android sources, I came across the following commit log entry:

----

Port RIL v4 to gingerbread from master.

Version 4 is backwards compatible with versions 2 and 3, so
this will not affect passion.

Bug: 3333633
Change-Id: If2e48e9dd37e17e9955563d2cd2cb94ccb2a8efe

----

So I guess it should be possible to take the ics versions of rild/libril/libreference-ril and compile against honeycomb.

Nic

unread,
Dec 28, 2011, 9:19:45 PM12/28/11
to andro...@googlegroups.com
As a matter of fact, the ics sources of ril indeed compile under 3.2.2 with minimal changes (revert the qemud pipe commit).

Then it seems from init.rc that rild is in the "late_start" class -- and never actually started. So there are no sockets, which is what causes rild to terminate (seen by running strace on rild). I changed the init.rc to reflect what ics has set for ril-daemon, ie. class main. This results in the sockets being created and rild starting up.

Nic

unread,
Dec 29, 2011, 7:37:55 AM12/29/11
to andro...@googlegroups.com
After disabling the SIM PIN, I was able to at least show a valid list of APN for my provider. So I guess the basic functionality is there.

Now I am stuck with a number of issues:

- Android does not ask for PIN when it is required.
- The 3G connection is not displayed anywhere, and so I cannot connect.
- Logcat shows "invalid response length" when requesting SIGNAL_STRENGTH from the modem,

Nic

unread,
Dec 29, 2011, 12:58:49 PM12/29/11
to andro...@googlegroups.com
One last time: I managed to get most problems solved.

The signal strength error is, afaict, a bug/inconsistency in android: The reference-ril reports signal strength as 2 integers. This is marked as deprecated in responseRilSignalStrength() in libril/ril.cpp of the version 2 sources, and this part has just been removed in the ics source. When I put it back in, the error disappeared.

Then I patched a RIL for generic Huawei devices I found on the web to work with the 4.0 sources. When I built this, I was able to see the local list of networks.

Now the final question: How to tell Android that it is on a device with 3G? After all this trouble, what I need is to activate the part of the system/UI/whatever that allows me to connect to my provider.

Chih-Wei Huang

unread,
Dec 29, 2011, 9:12:29 PM12/29/11
to andro...@googlegroups.com
Glad to hear you have good progress.
Please send me patches once you think it's ready.
Thanks!

2011/12/30 Nic <n.te...@gmail.com>:

--
Chih-Wei
Android-x86 project
http://www.android-x86.org

Nic

unread,
Dec 30, 2011, 4:38:50 AM12/30/11
to andro...@googlegroups.com
Sure. This is the patch against the head of android's own hardware/ril.git.

I had to fix the reference ril quite a bit, to add in missing parts like network selection. I took those parts almost unmodified from the ril posted at https://github.com/aferre/u300-ril/ -- so maybe someone should add a note about that.

There is a bug somewhere which I cannot locate: the available networks are queried, the result is stored, but then the whole process fails somewhere and GENERIC_FAILURE is sent.

It would be great to start a generic-ril for AT modems using parts from the reference ril and the ril mentioned above. This one looks quite polished, I think it is the official Sony Ericsson one.

What follows is the output of git diff.

----

diff --git a/reference-ril/at_tok.c b/reference-ril/at_tok.c
index 204a69e..d994093 100644
--- a/reference-ril/at_tok.c
+++ b/reference-ril/at_tok.c
@@ -187,4 +187,24 @@ int at_tok_hasmore(char **p_cur)
     return ! (*p_cur == NULL || **p_cur == '\0');
 }
 
+/** *p_out returns count of given character (needle) in given string (p_in). */
+int at_tok_charcounter(char *p_in, char needle, int *p_out)
+{
+    char *p_cur = p_in;
+    int num_found = 0;
+
+    if (p_in == NULL)
+        return -1;
+
+    while (*p_cur != '\0') {
+        if (*p_cur == needle) {
+            num_found++;
+        }
+
+        p_cur++;
+    }
+
+    *p_out = num_found;
+    return 0;
+}
 
diff --git a/reference-ril/at_tok.h b/reference-ril/at_tok.h
index a85ea63..729dda0 100644
--- a/reference-ril/at_tok.h
+++ b/reference-ril/at_tok.h
@@ -27,4 +27,6 @@ int at_tok_nextstr(char **p_cur, char **out);
 
 int at_tok_hasmore(char **p_cur);
 
+int at_tok_charcounter(char *p_in, char needle, int *p_out);
+
 #endif /*AT_TOK_H */
diff --git a/reference-ril/misc.c b/reference-ril/misc.c
index e4b8d72..f2be6b8 100644
--- a/reference-ril/misc.c
+++ b/reference-ril/misc.c
@@ -15,6 +15,8 @@
 ** limitations under the License.
 */
 
+#include <stdlib.h>
+
 /** returns 1 if line starts with prefix, 0 if it does not */
 int strStartsWith(const char *line, const char *prefix)
 {
@@ -27,3 +29,58 @@ int strStartsWith(const char *line, const char *prefix)
     return *prefix == '\0';
 }
 
+/**
+ * Very simple function that extract and returns whats between ElementBeginTag
+ * and ElementEndTag.
+ *
+ * Optional ppszRemainingDocument that can return a pointer to the remaining
+ * of the document to be "scanned". This can be used if subsequent
+ * scanning/searching is desired.
+ *
+ * This function is used to extract the parameters from the XML result
+ * returned by U3xx during a PDP Context setup, and used to parse the
+ * tuples of operators returned from AT+COPS.
+ *
+ *  const char* document        - Document to be scanned
+ *  const char* elementBeginTag - Begin tag to scan for, return whats
+ *                                between begin/end tags
+ *  const char* elementEndTag   - End tag to scan for, return whats
+ *                                between begin/end tags
+ *  char** remainingDocumen t   - Can return the a pointer to the remaining
+ *                                of pszDocument, this parameter is optional
+ *
+ *  return char* containing whats between begin/end tags, allocated on the
+ *               heap, need to free this.
+ *               return NULL if nothing is found.
+ */
+char *getFirstElementValue(const char *document,
+                           const char *elementBeginTag,
+                           const char *elementEndTag,
+                           char **remainingDocument)
+{
+    char *value = NULL;
+    char *start = NULL;
+    char *end = NULL;
+
+    if (document != NULL && elementBeginTag != NULL
+        && elementEndTag != NULL) {
+        start = strstr(document, elementBeginTag);
+        if (start != NULL) {
+            end = strstr(start, elementEndTag);
+            if (end != NULL) {
+                int n = strlen(elementBeginTag);
+                int m = end - (start + n);
+                value = (char *) malloc((m + 1) * sizeof(char));
+                strncpy(value, (start + n), m);
+                value[m] = (char) 0;
+
+                /* Optional, return a pointer to the remaining document,
+                   to be used when document contains many tags with same name. */
+                if (remainingDocument != NULL)
+                    *remainingDocument = end + strlen(elementEndTag);
+            }
+        }
+    }
+    return value;
+}
+
diff --git a/reference-ril/misc.h b/reference-ril/misc.h
index 7044a07..41af99e 100644
--- a/reference-ril/misc.h
+++ b/reference-ril/misc.h
@@ -17,3 +17,9 @@
 
 /** returns 1 if line starts with prefix, 0 if it does not */
 int strStartsWith(const char *line, const char *prefix);
+
+char *getFirstElementValue(const char *document,
+                           const char *elementBeginTag,
+                           const char *elementEndTag,
+                           char **remainingDocument);
+
diff --git a/reference-ril/reference-ril.c b/reference-ril/reference-ril.c
index 02a7e12..ec2c7db 100644
--- a/reference-ril/reference-ril.c
+++ b/reference-ril/reference-ril.c
@@ -729,13 +729,13 @@ static void requestSignalStrength(void *data, size_t datalen, RIL_Token t)
 {
     ATResponse *p_response = NULL;
     int err;
-    int response[2];
+    int signal[2];
+    RIL_SignalStrength_v6 response;
     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;
     }
 
@@ -744,13 +744,27 @@ static void requestSignalStrength(void *data, size_t datalen, RIL_Token t)
     err = at_tok_start(&line);
     if (err < 0) goto error;
 
-    err = at_tok_nextint(&line, &(response[0]));
+    err = at_tok_nextint(&line, &(signal[0]));
     if (err < 0) goto error;
 
-    err = at_tok_nextint(&line, &(response[1]));
+    err = at_tok_nextint(&line, &(signal[1]));
     if (err < 0) goto error;
-
-    RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
+    
+    response.GW_SignalStrength.signalStrength = signal[0];
+    response.GW_SignalStrength.bitErrorRate = signal[1];
+    
+    response.CDMA_SignalStrength.dbm = 0;
+    response.CDMA_SignalStrength.ecio = 0;
+    response.EVDO_SignalStrength.dbm = 0;
+    response.EVDO_SignalStrength.ecio = 0;
+    response.EVDO_SignalStrength.signalNoiseRatio = 0;
+    response.LTE_SignalStrength.signalStrength = 0;
+    response.LTE_SignalStrength.rsrp = 0;
+    response.LTE_SignalStrength.rsrq = 0;
+    response.LTE_SignalStrength.rssnr = 0;
+    response.LTE_SignalStrength.cqi = 0;
+    
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(RIL_SignalStrength_v6));
 
     at_response_free(p_response);
     return;
@@ -1251,6 +1265,351 @@ static void  requestSendUSSD(void *data, size_t datalen, RIL_Token t)
 
 }
 
+/**
+ * RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC
+ *
+ * Specify that the network should be selected automatically.
+ */
+void requestSetNetworkSelectionAutomatic(void *data, size_t datalen,
+                                         RIL_Token t)
+{
+    int err = 0;
+
+    err = at_send_command("AT+COPS=0", NULL);
+    if (err < 0)
+        goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    return;
+}
+
+/**
+ * RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL
+ *
+ * Manually select a specified network.
+ *
+ * The radio baseband/RIL implementation will try to camp on the manually
+ * selected network regardless of coverage, i.e. there is no fallback to
+ * automatic network selection.
+ */
+void requestSetNetworkSelectionManual(void *data, size_t datalen,
+                                      RIL_Token t)
+{
+    /*
+     * AT+COPS=[<mode>[,<format>[,<oper>[,<AcT>]]]]
+     *    <mode>   = 1 = Manual (<oper> field shall be present and AcT
+     *                   optionally)
+     *    <format> = 2 = Numeric <oper>, the number has structure:
+     *                   (country code digit 3)(country code digit 2)
+     *                   (country code digit 1)(network code digit 2)
+     *                   (network code digit 1)
+     */
+
+    int err = 0;
+    char *cmd = NULL;
+    ATResponse *atresponse = NULL;
+    const char *mccMnc = (const char *) data;
+
+    /* Check inparameter. */
+    if (mccMnc == NULL)
+        goto error;
+    /* Build and send command. */
+    asprintf(&cmd, "AT+COPS=1,2,\"%s\"", mccMnc);
+    err = at_send_command(cmd, &atresponse);
+    if (err < 0 || atresponse->success == 0)
+        goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+finally:
+
+    at_response_free(atresponse);
+
+    if (cmd != NULL)
+        free(cmd);
+
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    goto finally;
+}
+
+/*
+ * The parameters of the response to RIL_REQUEST_QUERY_AVAILABLE_NETWORKS are
+ * defined in ril.h
+ */
+#define QUERY_NW_NUM_PARAMS 4
+
+/**
+ * RIL_REQUEST_QUERY_AVAILABLE_NETWORKS
+ *
+ * Scans for available networks.
+ */
+void requestQueryAvailableNetworks(void *data, size_t datalen, RIL_Token t)
+{
+    /*
+     * AT+COPS=?
+     *   +COPS: [list of supported (<stat>,long alphanumeric <oper>
+     *           ,short alphanumeric <oper>,numeric <oper>[,<AcT>])s]
+     *          [,,(list of supported <mode>s),(list of supported <format>s)]
+     *
+     *   <stat>
+     *     0 = unknown
+     *     1 = available
+     *     2 = current
+     *     3 = forbidden
+     */
+
+    int err = 0;
+    ATResponse *atresponse = NULL;
+    const char *statusTable[] =
+    { "unknown", "available", "current", "forbidden" };
+    char **responseArray = NULL;
+    char *p;
+    int n = 0, i = 0, j = 0, numStoredNetworks = 0;
+    char *s = NULL;
+
+    err = at_send_command_multiline("AT+COPS=?", "+COPS:",
+                                                 &atresponse);
+    if (err < 0 ||
+        atresponse->success == 0 || atresponse->p_intermediates == NULL)
+        goto error;
+
+    p = atresponse->p_intermediates->line;
+
+    /* count number of '('. */
+    err = at_tok_charcounter(p, '(', &n);
+    if (err < 0) goto error;
+
+    /* Allocate array of strings, blocks of 4 strings. */
+    responseArray = alloca(n * QUERY_NW_NUM_PARAMS * sizeof(char *));
+
+    /* Loop and collect response information into the response array. */
+    for (i = 0; i < n; i++) {
+        int status = 0;
+        char *line = NULL;
+        char *longAlphaNumeric = NULL;
+        char *shortAlphaNumeric = NULL;
+        char *numeric = NULL;
+        char *remaining = NULL;
+        int continueOuterLoop = 0;
+
+        s = line = getFirstElementValue(p, "(", ")", &remaining);
+        p = remaining;
+
+        if (line == NULL) {
+            LOGE("Null pointer while parsing COPS response. This should not "
+                 "happen.");
+            goto error;
+        }
+        /* <stat> */
+        err = at_tok_nextint(&line, &status);
+        if (err < 0)
+            goto error;
+
+        /* long alphanumeric <oper> */
+        err = at_tok_nextstr(&line, &longAlphaNumeric);
+        if (err < 0)
+            goto error;
+
+        /* short alphanumeric <oper> */
+        err = at_tok_nextstr(&line, &shortAlphaNumeric);
+        if (err < 0)
+            goto error;
+
+        /* numeric <oper> */
+        err = at_tok_nextstr(&line, &numeric);
+        if (err < 0)
+            goto error;
+
+        /*
+         * The response of AT+COPS=? returns GSM networks and WCDMA networks as
+         * separate network search hits. The RIL API does not support network
+         * type parameter and the RIL must prevent duplicates.
+         */
+        for (j = numStoredNetworks - 1; j >= 0; j--)
+            if (strcmp(responseArray[j * QUERY_NW_NUM_PARAMS + 2],
+                       numeric) == 0) {
+                LOGD("%s(): Skipped storing duplicate operator: %s.",
+                     __func__, longAlphaNumeric);
+                continueOuterLoop = 1;
+                break;
+            }
+
+        if (continueOuterLoop) {
+            free(s);
+            s = NULL;
+            continue; /* Skip storing this duplicate operator */
+        }
+
+        responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 0] =
+            alloca(strlen(longAlphaNumeric) + 1);
+        strcpy(responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 0],
+                             longAlphaNumeric);
+
+        responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 1] =
+            alloca(strlen(shortAlphaNumeric) + 1);
+        strcpy(responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 1],
+                             shortAlphaNumeric);
+
+        responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 2] =
+            alloca(strlen(numeric) + 1);
+        strcpy(responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 2],
+               numeric);
+
+        /* Fill long alpha with MNC/MCC if it is empty */
+        if (responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 0] &&
+            strlen(responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 0])
+            == 0) {
+            responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 0] =
+                alloca(strlen(responseArray[numStoredNetworks *
+                QUERY_NW_NUM_PARAMS + 2]) + 1);
+            strcpy(responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 0],
+                   responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 2]);
+        }
+        /* Fill short alpha with MNC/MCC if it is empty */
+        if (responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 1]
+            && strlen(responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS
+            + 1]) == 0) {
+            responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 1] =
+                alloca(strlen(responseArray[numStoredNetworks *
+                QUERY_NW_NUM_PARAMS + 2]) + 1);
+            strcpy(responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 1],
+                   responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 2]);
+        }
+
+        /* Add status */
+        responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 3] =
+            alloca(strlen(statusTable[status]) + 1);
+        sprintf(responseArray[numStoredNetworks * QUERY_NW_NUM_PARAMS + 3],
+                "%s", statusTable[status]);
+
+        numStoredNetworks++;
+        free(s);
+        s = NULL;
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, responseArray, numStoredNetworks *
+                          QUERY_NW_NUM_PARAMS * sizeof(char *));
+
+finally:
+    at_response_free(atresponse);
+    return;
+
+error:
+    free(s);
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    goto finally;
+}
+
+/**
+ * RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE
+ *
+ * Requests to set the preferred network type for searching and registering
+ * (CS/PS domain, RAT, and operation mode).
+ */
+void requestSetPreferredNetworkType(void *data, size_t datalen,
+                                    RIL_Token t)
+{
+    ATResponse *atresponse = NULL;
+    int err = 0;
+    int rat;
+    int arg;
+    char *cmd = NULL;
+    RIL_Errno rilErr = RIL_E_GENERIC_FAILURE;
+
+    rat = ((int *) data)[0];
+
+    switch (rat) {
+    case 0:
+        arg = 1;
+        break;
+    case 1:
+        arg = 5;
+        break;
+    case 2:
+        arg = 6;
+        break;
+    default:
+        errno = RIL_E_MODE_NOT_SUPPORTED;
+        goto error;
+    }
+
+    asprintf(&cmd, "AT+CFUN=%d", arg);
+
+    err = at_send_command(cmd, &atresponse);
+    free(cmd);
+    if (err < 0 || atresponse->success == 0)
+        goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+
+finally:
+    at_response_free(atresponse);
+    return;
+
+error:
+    RIL_onRequestComplete(t, rilErr, NULL, 0);
+    goto finally;
+}
+
+/**
+ * RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE
+ *
+ * Query the preferred network type (CS/PS domain, RAT, and operation mode)
+ * for searching and registering.
+ */
+void requestGetPreferredNetworkType(void *data, size_t datalen,
+                                    RIL_Token t)
+{
+    int err = 0;
+    int response = 0;
+    int cfun;
+    char *line;
+    ATResponse *atresponse;
+
+    err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &atresponse);
+    if (err < 0)
+        goto error;
+
+    line = atresponse->p_intermediates->line;
+
+    err = at_tok_start(&line);
+    if (err < 0)
+        goto error;
+
+    err = at_tok_nextint(&line, &cfun);
+    if (err < 0)
+        goto error;
+
+    assert(cfun >= 0 && cfun < 7);
+
+    switch (cfun) {
+    case 5:
+        response = 1;
+        break;
+    case 6:
+        response = 2;
+        break;
+    default:
+        response = 0;
+        break;
+    }
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
+
+finally:
+    at_response_free(atresponse);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    goto finally;
+}
 
 /*** Callback methods from the RIL library to us ***/
 
@@ -1484,7 +1843,11 @@ onRequest (int request, void *data, size_t datalen, RIL_Token t)
             break;
 
         case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
-            at_send_command("AT+COPS=0", NULL);
+            requestSetNetworkSelectionAutomatic(data, datalen, t);
+            break;
+
+        case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL:
+            requestSetNetworkSelectionManual(data, datalen, t);
             break;
 
         case RIL_REQUEST_DATA_CALL_LIST:
@@ -1495,6 +1858,18 @@ onRequest (int request, void *data, size_t datalen, RIL_Token t)
             requestQueryNetworkSelectionMode(data, datalen, t);
             break;
 
+    case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS:
+    requestQueryAvailableNetworks(data, datalen, t);
+    break;
+
+    case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
+    requestGetPreferredNetworkType(data, datalen, t);
+    break;
+
+    case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
+    requestSetPreferredNetworkType(data, datalen, t);
+    break;
+
         case RIL_REQUEST_OEM_HOOK_RAW:
             // echo back data
             RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);

Reply all
Reply to author
Forward
0 new messages