SIM: Completed SIM status handling
authorPaul Kocialkowski <contact@paulk.fr>
Fri, 27 Jul 2012 22:51:08 +0000 (00:51 +0200)
committerPaul Kocialkowski <contact@paulk.fr>
Fri, 27 Jul 2012 22:51:08 +0000 (00:51 +0200)
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
at.c
hayes-ril.c
hayes-ril.h
power.c
sim.c

diff --git a/at.c b/at.c
index 7a02458..b1d7b58 100644 (file)
--- a/at.c
+++ b/at.c
@@ -49,6 +49,17 @@ int at_strings_compare(char *major, char *minor)
                return 0;
 }
 
+int at_strings_raw_compare(char *major, char *minor)
+{
+       int major_length = strlen(major);
+
+       // Only consider major length (minor might not have \0)
+       if(strncmp(major, minor, major_length) == 0)
+               return 1;
+       else
+               return 0;
+}
+
 // Major is response string, minor is request (reference) string
 int at_commands_compare(char *major, char *minor)
 {
index e049664..bebd802 100644 (file)
@@ -27,9 +27,7 @@
 struct ril_device *ril_device;
 struct ril_globals ril_globals;
 
-struct ril_dispatch_unsol ril_dispatch_unsol[] = {
-       { "AT+CPIN",    at_cpin }
-};
+struct ril_dispatch_unsol ril_dispatch_unsol[] = {};
 
 void ril_on_request(int request, void *data, size_t length, RIL_Token t)
 {
@@ -38,6 +36,10 @@ void ril_on_request(int request, void *data, size_t length, RIL_Token t)
                case RIL_REQUEST_RADIO_POWER:
                        ril_request_radio_power(t, data, length);
                        break;
+               // SIM
+               case RIL_REQUEST_GET_SIM_STATUS:
+                       ril_request_get_sim_status(t, data, length);
+                       break;
                // Call
                case RIL_REQUEST_GET_CURRENT_CALLS:
                        ril_request_get_current_calls(t, data, length);
index e6f92d8..55368d5 100644 (file)
@@ -145,6 +145,7 @@ void ril_request_get_current_calls(RIL_Token t, void *data, size_t length);
 void ril_request_radio_power(RIL_Token t, void *data, size_t length);
 
 // SIM
-void at_cpin(struct at_response *response);
+int at_cpin_expect(struct at_response *response, void *data, RIL_Token t);
+void ril_request_get_sim_status(RIL_Token t, void *data, size_t length);
 
 #endif
diff --git a/power.c b/power.c
index 62a8d80..a497629 100644 (file)
--- a/power.c
+++ b/power.c
@@ -107,8 +107,8 @@ void ril_request_radio_power(RIL_Token t, void *data, size_t length)
                ril_power_off();
        }
 
-       // Send AT+CPIN, response will fall unsol and update status
-       at_send_command("AT+CPIN?");
+       // Send AT+CPIN
+       at_send_expect_to_func("AT+CPIN?", NULL, NULL, 0x0000, at_cpin_expect);
 
        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
 }
diff --git a/sim.c b/sim.c
index ae9c6e7..1f1237a 100644 (file)
--- a/sim.c
+++ b/sim.c
 
 #include <hayes-ril.h>
 
-RIL_RadioState at2ril_cme_pin_status(int code)
+RIL_RadioState at2ril_sim_status(int status, char *error, char **data, int data_count)
 {
-       switch(code) {
-               case AT_CME_ERROR_PH_SIM_PIN_REQD:
-               case AT_CME_ERROR_PH_SIM_PUK_REQD:
-               case AT_CME_ERROR_PH_FSIM_PIN_REQD:
-               case AT_CME_ERROR_PH_FSIM_PUK_REQD:
-               case AT_CME_ERROR_SIM_NOT_INSERTED:
-               case AT_CME_ERROR_SIM_PIN_REQD:
-               case AT_CME_ERROR_SIM_PUK_REQD:
-               case AT_CME_ERROR_SIM_PIN2_REQD:
-               case AT_CME_ERROR_SIM_PUK2_REQD:
-               case AT_CME_ERROR_SIM_BLOCKED:
-                       return RADIO_STATE_SIM_LOCKED_OR_ABSENT;
-               case AT_CME_ERROR_SIM_FAILURE:
-               case AT_CME_ERROR_SIM_BUSY:
-               case AT_CME_ERROR_SIM_WRONG:
-               case AT_CME_ERROR_SIM_POWERED_DOWN:
-               default:
-                       return RADIO_STATE_SIM_NOT_READY;
+       int code = 0;
+       int i;
+
+       if(status == AT_STATUS_CME_ERROR && error != NULL) {
+               code = atoi(error);
+               switch(code) {
+                       case AT_CME_ERROR_PH_SIM_PIN_REQD:
+                       case AT_CME_ERROR_PH_SIM_PUK_REQD:
+                       case AT_CME_ERROR_PH_FSIM_PIN_REQD:
+                       case AT_CME_ERROR_PH_FSIM_PUK_REQD:
+                       case AT_CME_ERROR_SIM_NOT_INSERTED:
+                       case AT_CME_ERROR_SIM_PIN_REQD:
+                       case AT_CME_ERROR_SIM_PUK_REQD:
+                       case AT_CME_ERROR_SIM_PIN2_REQD:
+                       case AT_CME_ERROR_SIM_PUK2_REQD:
+                       case AT_CME_ERROR_SIM_BLOCKED:
+                               return RADIO_STATE_SIM_LOCKED_OR_ABSENT;
+                       case AT_CME_ERROR_SIM_FAILURE:
+                       case AT_CME_ERROR_SIM_BUSY:
+                       case AT_CME_ERROR_SIM_WRONG:
+                       case AT_CME_ERROR_SIM_POWERED_DOWN:
+                       default:
+                               return RADIO_STATE_SIM_NOT_READY;
+               }
+       } else if(status == AT_STATUS_OK) {
+               if(data != NULL && data_count > 0) {
+                       for(i=0 ; i < data_count ; i++) {
+                               if(at_strings_raw_compare("SIM PIN", data[i])) {
+                                       return RADIO_STATE_SIM_LOCKED_OR_ABSENT;
+                               } else if(at_strings_raw_compare("SIM PUK", data[i])) {
+                                       return RADIO_STATE_SIM_LOCKED_OR_ABSENT;
+                               } else if(at_strings_raw_compare("READY", data[i])) {
+                                       return RADIO_STATE_SIM_READY;
+                               }
+                       }
+               }
+
+               // Fallback
+               return RADIO_STATE_SIM_NOT_READY;
+       } else {
+               // Various error codes, not helping here, don't change anything
+               return ril_globals.radio_state;
        }
+
 }
 
-void at_cpin(struct at_response *response)
+RIL_RadioState at2ril_card_status(RIL_CardStatus *card_status, int status, char *error, char **data, int data_count)
 {
+       RIL_RadioState radio_state;
        int code = 0;
 
-       if(response->status == AT_STATUS_UNDEF)
-               return;
+       int app_status_array_length = 0;
+       int app_index = -1;
+       int i;
 
-       if(response->status == AT_STATUS_CME_ERROR && response->error != NULL) {
-               code = atoi(response->error);
-               if(code != 0) {
-                       LOGD("Updating radio state!");
-                       ril_globals.radio_state = at2ril_cme_pin_status(code);
-                       RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0);
+       static RIL_AppStatus app_status_array[] = {
+               // SIM_ABSENT = 0
+               { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
+               NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+               // SIM_NOT_READY = 1
+               { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
+               NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+               // SIM_READY = 2
+               { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
+               NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+               // SIM_PIN = 3
+               { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
+               NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+               // SIM_PUK = 4
+               { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
+               NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
+               // SIM_BLOCKED = 5
+               { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
+               NULL, NULL, 0, RIL_PINSTATE_ENABLED_PERM_BLOCKED, RIL_PINSTATE_UNKNOWN },
+               // SIM_NETWORK_PERSO = 6
+               { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
+               NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+               // SIM_NETWORK_SUBSET_PERSO = 7
+               { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET,
+               NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+               // SIM_CORPORATE_PERSO = 8
+               { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_CORPORATE,
+               NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+               // SIM_SERVICE_PROVIDER_PERSO = 9
+               { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER,
+               NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+       };
+
+       app_status_array_length = sizeof(app_status_array) / sizeof(RIL_AppStatus);
+
+       if(app_status_array_length > RIL_CARD_MAX_APPS)
+               app_status_array_length = RIL_CARD_MAX_APPS;
+
+       radio_state = at2ril_sim_status(status, error, data, data_count);
+
+       if(status == AT_STATUS_CME_ERROR && error != NULL) {
+               code = atoi(error);
+
+               switch(code) {
+                       case AT_CME_ERROR_SIM_NOT_INSERTED:
+                               card_status->card_state = RIL_CARDSTATE_ABSENT;
+                               card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
+                               app_index = 0;
+                               break;
+                       case AT_CME_ERROR_PH_SIM_PIN_REQD:
+                       case AT_CME_ERROR_PH_FSIM_PIN_REQD:
+                       case AT_CME_ERROR_SIM_PIN_REQD:
+                               card_status->card_state = RIL_CARDSTATE_PRESENT;
+                               card_status->universal_pin_state = RIL_PINSTATE_ENABLED_NOT_VERIFIED;
+                               app_index = 3;
+                               break;
+                       case AT_CME_ERROR_PH_SIM_PUK_REQD:
+                       case AT_CME_ERROR_PH_FSIM_PUK_REQD:
+                       case AT_CME_ERROR_SIM_PUK_REQD:
+                               card_status->card_state = RIL_CARDSTATE_PRESENT;
+                               card_status->universal_pin_state = RIL_PINSTATE_ENABLED_BLOCKED;
+                               app_index = 4;
+                               break;
+                       case AT_CME_ERROR_SIM_PIN2_REQD:
+                       case AT_CME_ERROR_SIM_PUK2_REQD:
+                       case AT_CME_ERROR_SIM_BLOCKED:
+                               card_status->card_state = RIL_CARDSTATE_PRESENT;
+                               card_status->universal_pin_state = RIL_PINSTATE_ENABLED_PERM_BLOCKED;
+                               app_index = 5;
+                               break;
+                       case AT_CME_ERROR_SIM_FAILURE:
+                       case AT_CME_ERROR_SIM_BUSY:
+                       case AT_CME_ERROR_SIM_WRONG:
+                       case AT_CME_ERROR_SIM_POWERED_DOWN:
+                       default:
+                               card_status->card_state = RIL_CARDSTATE_PRESENT;
+                               card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
+                               app_index = 1;
+                               break;
+               }
+       } else if(status == AT_STATUS_OK) {
+               if(data != NULL && data_count > 0) {
+                       for(i=0 ; i < data_count ; i++) {
+                               if(at_strings_raw_compare("SIM PIN", data[i])) {
+                                       card_status->card_state = RIL_CARDSTATE_PRESENT;
+                                       card_status->universal_pin_state = RIL_PINSTATE_ENABLED_NOT_VERIFIED;
+                                       app_index = 3;
+                               } else if(at_strings_raw_compare("SIM PUK", data[i])) {
+                                       card_status->card_state = RIL_CARDSTATE_PRESENT;
+                                       card_status->universal_pin_state = RIL_PINSTATE_ENABLED_BLOCKED;
+                                       app_index = 4;
+                               } else if(at_strings_raw_compare("READY", data[i])) {
+                                       card_status->card_state = RIL_CARDSTATE_PRESENT;
+                                       card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
+                                       app_index = 2;
+                               }
+                       }
                }
+       }
 
-               // TODO: gather more infos for ril_globals
-       } else if(response->status == AT_STATUS_OK) {
-               ril_globals.radio_state = RADIO_STATE_SIM_READY;
-               RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0);
-               // TODO: gather more infos for ril_globals
-       } else {
-               // Various error codes, not helping here
-               return;
+       // Fallback
+       if(app_index == -1) {
+               card_status->card_state = RIL_CARDSTATE_PRESENT;
+               card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
+               app_index = 1;
        }
 
-       // TODO: Store the data we have in ril_globals (pointer alloc here?), then call UNSOL
+       // Initialize the apps
+       for (i = 0 ; i < app_status_array_length ; i++) {
+               memcpy((void *) &(card_status->applications[i]), (void *) &(app_status_array[i]), sizeof(RIL_AppStatus));
+       }
+       for(i = app_status_array_length ; i < RIL_CARD_MAX_APPS ; i++) {
+               memset((void *) &(card_status->applications[i]), 0, sizeof(RIL_AppStatus));
+       }
+
+       card_status->gsm_umts_subscription_app_index = app_index;
+       card_status->cdma_subscription_app_index = app_index;
+       card_status->num_applications = app_status_array_length;
+
+       LOGD("Selecting application #%d on %d", app_index, app_status_array_length);
+
+       return radio_state;
+}
+
+int at_cpin_expect(struct at_response *response, void *data, RIL_Token t)
+{
+       RIL_CardStatus card_status;
+       RIL_RadioState radio_state;
+
+       if(response->status == AT_STATUS_UNDEF)
+               return AT_RESPONSE_UNHANDELD_REASON_STATUS;
+
+       if(t != (RIL_Token) 0x0000) {
+               radio_state = at2ril_card_status(&card_status, response->status, response->error, response->data, response->data_count);
+               ril_globals.radio_state = radio_state;
+
+               RIL_onRequestComplete(t, RIL_E_SUCCESS, &card_status, sizeof(card_status));
+       } else {
+               radio_state = at2ril_sim_status(response->status, response->error, response->data, response->data_count);
+               if(ril_globals.radio_state != radio_state) {
+                       ril_globals.radio_state = radio_state;
+                       RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0);
+               }
+       }
 
        LOGD("Handled AT+CPIN response");
+
+       return AT_RESPONSE_HANDLED_OK;
+}
+
+void ril_request_get_sim_status(RIL_Token t, void *data, size_t length)
+{
+       at_send_expect_to_func("AT+CPIN?", NULL, NULL, t, at_cpin_expect);
 }