Sure. This is the patch against the head of android's own hardware/ril.git.
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);