Network: Added registration state (both SOL and UNSOL) support
authorPaul Kocialkowski <contact@paulk.fr>
Tue, 31 Jul 2012 19:09:40 +0000 (21:09 +0200)
committerPaul Kocialkowski <contact@paulk.fr>
Tue, 31 Jul 2012 19:09:40 +0000 (21:09 +0200)
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
hayes-ril.c
hayes-ril.h
network.c

index fac4877..8cbe064 100644 (file)
@@ -27,7 +27,9 @@
 struct ril_device *ril_device;
 struct ril_globals ril_globals;
 
-struct ril_dispatch_unsol ril_dispatch_unsol[] = {};
+struct ril_dispatch_unsol ril_dispatch_unsol[] = {
+       { "AT+CREG", at_creg_unexpect }
+};
 
 void ril_on_request(int request, void *data, size_t length, RIL_Token t)
 {
@@ -50,6 +52,9 @@ void ril_on_request(int request, void *data, size_t length, RIL_Token t)
                case RIL_REQUEST_SIGNAL_STRENGTH:
                        ril_request_signal_strength(t, data, length);
                        break;
+               case RIL_REQUEST_REGISTRATION_STATE:
+                       ril_request_registration_state(t, data, length);
+                       break;
                // Call
                case RIL_REQUEST_GET_CURRENT_CALLS:
                        ril_request_get_current_calls(t, data, length);
index f162d9a..9f36697 100644 (file)
@@ -108,6 +108,9 @@ struct ril_globals {
 
        // Power
        RIL_RadioState radio_state;
+
+       // Network
+       char **registration_state;
 };
 
 /*
@@ -152,5 +155,7 @@ void ril_request_sim_io(RIL_Token t, void *data, size_t length);
 
 // Network
 void ril_request_signal_strength(RIL_Token t, void *data, size_t length);
+void at_creg_unexpect(struct at_response *response);
+void ril_request_registration_state(RIL_Token t, void *data, size_t length);
 
 #endif
index d47545e..349d7a9 100644 (file)
--- a/network.c
+++ b/network.c
 
 #include <hayes-ril.h>
 
+/*
+ * Signal Strength
+ */
+
 void at2ril_signal_strength(RIL_SignalStrength *ss, int *values)
 {
        const int dbm_table[8] = {135,125,115,105,95,85,75,70};
@@ -86,7 +90,9 @@ int at_csq_expect(struct at_response *response, void *data, RIL_Token t)
        return AT_RESPONSE_HANDLED_OK;
 
 error_data:
-       LOGE("No valid data fiven to AT+CSQ response!");
+       LOGE("No valid data given to AT+CSQ response!");
+
+       RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
 
        at_response_data_free(response_data, response_data_count);
        return AT_RESPONSE_HANDLED_ERROR;
@@ -96,3 +102,199 @@ void ril_request_signal_strength(RIL_Token t, void *data, size_t length)
 {
        at_send_expect_to_func("AT+CSQ", NULL, NULL, t, at_csq_expect);
 }
+
+/*
+ * Network registration
+ */
+
+int at_creg_handle(char **registration_state, struct at_response_data **response_data, int response_data_count)
+{
+       int state = 0;
+       char *lac = NULL;
+       char *cid = NULL;
+
+       if(registration_state == NULL || response_data == NULL || response_data_count <= 0)
+               return -1;
+
+       /*
+        * 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
+        *
+        * 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]]
+        */
+
+       // Only handle CREG responses
+       switch(response_data_count) {
+               case 1: // UNSOL response, unregistered
+                       if(response_data[0]->type != AT_RESPONSE_DATA_NUMERIC)
+                               return -1;
+                       state = response_data[0]->value.n;
+
+                       break;
+               case 2: // SOL response, unregistered
+                       // Skip first argument
+                       if(response_data[1]->type != AT_RESPONSE_DATA_NUMERIC)
+                               return -1;
+                       state = response_data[1]->value.n;
+
+                       break;
+               case 3: // UNSOL response, registered
+                       if(response_data[0]->type != AT_RESPONSE_DATA_NUMERIC)
+                               return -1;
+                       state = response_data[0]->value.n;
+
+                       if(response_data[1]->type != AT_RESPONSE_DATA_STRING)
+                               return -1;
+                       lac = response_data[1]->value.s;
+
+                       if(response_data[2]->type != AT_RESPONSE_DATA_STRING)
+                               return -1;
+                       cid = response_data[2]->value.s;
+
+                       break;
+               case 4: // SOL response, registered
+                       if(response_data[1]->type != AT_RESPONSE_DATA_NUMERIC)
+                               return -1;
+                       state = response_data[1]->value.n;
+
+                       if(response_data[2]->type != AT_RESPONSE_DATA_STRING)
+                               return -1;
+                       lac = response_data[2]->value.s;
+
+                       if(response_data[3]->type != AT_RESPONSE_DATA_STRING)
+                               return -1;
+                       cid = response_data[3]->value.s;
+
+                       break;
+               default:
+                       return -1;
+       }
+
+       asprintf(&(registration_state[0]), "%d", state);
+       registration_state[1] = strdup(lac);
+       registration_state[2] = strdup(cid);
+
+       return 0;
+}
+
+void ril_registration_state_free(char **registration_state)
+{
+       int i;
+
+       for(i=0 ; i < 14 ; i++) {
+               if(registration_state[i] != NULL)
+                       free(registration_state[i]);
+       }
+
+
+       free(registration_state);
+}
+
+int at_creg_expect(struct at_response *response, void *data, RIL_Token t)
+{
+       struct at_response_data **response_data = NULL;
+       int response_data_count = 0;
+
+       char **registration_state = NULL;
+       int rc;
+
+       if(response->status == AT_STATUS_UNDEF)
+               return AT_RESPONSE_UNHANDELD_REASON_STATUS;
+
+       if(response->data == NULL || response->data_count <= 0) {
+               LOGE("No data given to AT+CREG response!");
+               return AT_RESPONSE_HANDLED_ERROR;
+       }
+
+       LOGE("Caught valid AT+CREG response!");
+
+       response_data_count = at_response_data_process(&response_data, response->data[0], strlen(response->data[0]));
+       if(response_data_count <= 0)
+               goto error_data;
+
+       registration_state = calloc(1, sizeof(char *) * 15);
+       rc = at_creg_handle(registration_state, response_data, response_data_count);
+       if(rc < 0) {
+               ril_registration_state_free(registration_state);
+               goto error_data;
+       }
+
+       RIL_onRequestComplete(t, RIL_E_SUCCESS, registration_state,  sizeof(char *) * 15);
+
+       ril_registration_state_free(registration_state);
+       at_response_data_free(response_data, response_data_count);
+
+       return AT_RESPONSE_HANDLED_OK;
+
+error_data:
+       LOGE("No valid data given to AT+CREG response!");
+
+       RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+       at_response_data_free(response_data, response_data_count);
+
+       return AT_RESPONSE_HANDLED_ERROR;
+}
+
+void at_creg_unexpect(struct at_response *response)
+{
+       struct at_response_data **response_data = NULL;
+       int response_data_count = 0;
+
+       char **registration_state = NULL;
+       int rc;
+
+       if(response->data == NULL || response->data_count <= 0) {
+               LOGE("No data given to AT+CREG unsol!");
+               return;
+       }
+
+       LOGE("Caught valid AT+CREG unsol!");
+
+       response_data_count = at_response_data_process(&response_data, response->data[0], strlen(response->data[0]));
+       if(response_data_count <= 0)
+               goto error_data;
+
+       registration_state = calloc(1, sizeof(char *) * 15);
+       rc = at_creg_handle(registration_state, response_data, response_data_count);
+       if(rc < 0) {
+               ril_registration_state_free(registration_state);
+               goto error_data;
+       }
+
+       if(ril_globals.registration_state != NULL)
+               ril_registration_state_free(ril_globals.registration_state);
+
+       ril_globals.registration_state = registration_state;
+
+       RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0);
+
+error_data:
+       LOGE("No valid data given to AT+CREG unsol!");
+
+       at_response_data_free(response_data, response_data_count);
+}
+
+void ril_request_registration_state(RIL_Token t, void *data, size_t length)
+{
+       if(ril_globals.registration_state != NULL) {
+               // There is UNSOL data there
+               RIL_onRequestComplete(t, RIL_E_SUCCESS, ril_globals.registration_state,  sizeof(char *) * 15);
+
+               ril_registration_state_free(ril_globals.registration_state);
+               ril_globals.registration_state = NULL;
+       } else {
+               at_send_expect_to_func("AT+CREG?", NULL, NULL, t, at_creg_expect);
+       }
+}