From 6e3b494227b89790ab0e0de61f12d87a9cd66396 Mon Sep 17 00:00:00 2001 From: Yang Gu Date: Fri, 11 Sep 2009 14:59:32 +0800 Subject: [PATCH] Read Preferred PLMN list --- drivers/atmodem/network-registration.c | 120 ++++++++++++++++++++++++++++++++ include/netreg.h | 18 ++++- src/network.c | 50 +++++++++++++ 3 files changed, 185 insertions(+), 3 deletions(-) diff --git a/drivers/atmodem/network-registration.c b/drivers/atmodem/network-registration.c index 43a3f7d..69613dc 100644 --- a/drivers/atmodem/network-registration.c +++ b/drivers/atmodem/network-registration.c @@ -44,6 +44,8 @@ static const char *none_prefix[] = { NULL }; static const char *creg_prefix[] = { "+CREG:", NULL }; static const char *cops_prefix[] = { "+COPS:", NULL }; static const char *csq_prefix[] = { "+CSQ:", NULL }; +static const char *cpol_prefix[] = { "+CPOL:", NULL }; + struct netreg_data { GAtChat *chat; @@ -608,6 +610,123 @@ error: } } +static void at_list_pref_oper_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct cb_data *cbd = user_data; + ofono_netreg_pref_oper_list_cb_t cb = cbd->cb; + GAtResultIter iter; + struct ofono_error error; + int num = 0; + int i; + struct ofono_preferred_operator *list = NULL; + + decode_at_error(&error, g_at_result_final_response(result)); + if (!ok) + goto error; + + g_at_result_iter_init(&iter, result); + while (g_at_result_iter_next(&iter, "+CPOL:")) + num += 1; + if (num < 1) + goto error; + + list = g_new(struct ofono_preferred_operator, num); + g_at_result_iter_init(&iter, result); + for (num = 0; g_at_result_iter_next(&iter, "+CPOL:"); num++) { + int format; + const char *oper_temp = NULL; + + g_at_result_iter_skip_next(&iter); + + g_at_result_iter_next_number(&iter, &format); + g_assert(format == 2); + + if (!g_at_result_iter_next_string(&iter, &oper_temp)) + continue; + list[num].mccmnc = g_strdup(oper_temp); + } + + cb(&error, num, list, cbd->data); + + for (i = 0; i < num; i++) + g_free(list[i].mccmnc); + g_free(list); + + return; + +error: + cb(&error, 0, NULL, cbd->data); + return; +} + +static void at_change_oper_format_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct cb_data *cbd = user_data; + struct ofono_netreg *netreg = cbd->user; + struct netreg_data *nd = ofono_netreg_get_data(netreg); + + if (!ok) + goto error; + + if (g_at_chat_send(nd->chat, "AT+CPOL?", cpol_prefix, + at_list_pref_oper_cb, cbd, g_free) > 0) + return; + + error: + { + ofono_netreg_pref_oper_list_cb_t cb = cbd->cb; + DECLARE_FAILURE(error); + cb(&error, 0, NULL, cbd->data); + } +} + +static void at_select_plmn_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct cb_data *cbd = user_data; + struct ofono_netreg *netreg = cbd->user; + struct netreg_data *nd = ofono_netreg_get_data(netreg); + + if (!ok) + goto error; + + if (g_at_chat_send(nd->chat, "AT+CPOL=,2", none_prefix, + at_change_oper_format_cb, cbd, NULL) > 0) + return; + + error: + { + ofono_netreg_pref_oper_list_cb_t cb = cbd->cb; + DECLARE_FAILURE(error); + cb(&error, 0, NULL, cbd->data); + } +} + +static void at_list_pref_oper(struct ofono_netreg *netreg, + ofono_netreg_pref_oper_list_cb_t cb, void *data) +{ + struct netreg_data *nd = ofono_netreg_get_data(netreg); + struct cb_data *cbd = cb_data_new(cb, data); + + if (!cbd) + goto error; + + cbd->user = netreg; + if (g_at_chat_send(nd->chat, "AT+CPLS=0", none_prefix, + at_select_plmn_cb, cbd, NULL) > 0) + return; +error: + if (cbd) + g_free(cbd); + + { + DECLARE_FAILURE(error); + cb(&error, 0, NULL, data); + } +} + static void creg_notify(GAtResult *result, gpointer user_data) { struct ofono_netreg *netreg = user_data; @@ -706,6 +825,7 @@ static struct ofono_netreg_driver driver = { .register_manual = at_register_manual, .deregister = at_deregister, .strength = at_signal_strength, + .list_pref_oper = at_list_pref_oper, }; void at_netreg_init() diff --git a/include/netreg.h b/include/netreg.h index 9e99200..107728e 100644 --- a/include/netreg.h +++ b/include/netreg.h @@ -43,6 +43,10 @@ struct ofono_network_operator { int tech; }; +struct ofono_preferred_operator { + char *mccmnc; +}; + typedef void (*ofono_netreg_operator_cb_t)(const struct ofono_error *error, const struct ofono_network_operator *op, void *data); @@ -51,9 +55,9 @@ typedef void (*ofono_netreg_register_cb_t)(const struct ofono_error *error, void *data); typedef void (*ofono_netreg_operator_list_cb_t)(const struct ofono_error *error, - int total, - const struct ofono_network_operator *list, - void *data); + int total, + const struct ofono_network_operator *list, + void *data); typedef void (*ofono_netreg_status_cb_t)(const struct ofono_error *error, int status, int lac, int ci, int tech, @@ -62,6 +66,12 @@ typedef void (*ofono_netreg_status_cb_t)(const struct ofono_error *error, typedef void (*ofono_netreg_strength_cb_t)(const struct ofono_error *error, int strength, void *data); +typedef void (*ofono_netreg_pref_oper_list_cb_t)( + const struct ofono_error *error, + int total, + const struct ofono_preferred_operator *list, + void *data); + /* Network related functions, including registration status, operator selection * and signal strength indicators. * @@ -88,6 +98,8 @@ struct ofono_netreg_driver { ofono_netreg_register_cb_t cb, void *data); void (*strength)(struct ofono_netreg *netreg, ofono_netreg_strength_cb_t, void *data); + void (*list_pref_oper)(struct ofono_netreg *netreg, + ofono_netreg_pref_oper_list_cb_t cb, void *data); }; void ofono_netreg_strength_notify(struct ofono_netreg *netreg, int strength); diff --git a/src/network.c b/src/network.c index 7139e60..1aac668 100644 --- a/src/network.c +++ b/src/network.c @@ -80,6 +80,7 @@ struct ofono_netreg { const struct ofono_netreg_driver *driver; void *driver_data; struct ofono_atom *atom; + GSList *pref_oper_list; }; static void operator_list_callback(const struct ofono_error *error, int total, @@ -658,6 +659,9 @@ static DBusMessage *network_get_properties(DBusConnection *conn, DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; + char **list; + GSList *l; + int i; const char *status = registration_status_to_string(netreg->status); const char *operator; @@ -713,6 +717,16 @@ static DBusMessage *network_get_properties(DBusConnection *conn, &strength); } + /* Preferred networks */ + list = g_new0(char *, g_slist_length(netreg->pref_oper_list) + 1); + + for (i = 0, l = netreg->pref_oper_list; l; l = l->next, i++) + list[i] = g_strdup(l->data); + + ofono_dbus_dict_append_array(&dict, "PreferredNetworks", + DBUS_TYPE_STRING, &list); + g_strfreev(list); + dbus_message_iter_close_container(&iter, &dict); return reply; @@ -1395,6 +1409,12 @@ static void netreg_remove(struct ofono_atom *atom) if (netreg->spname) g_free(netreg->spname); + if (netreg->pref_oper_list) { + g_slist_foreach(netreg->pref_oper_list, (GFunc)g_free, NULL); + g_slist_free(netreg->pref_oper_list); + netreg->pref_oper_list = NULL; + } + g_free(netreg); } @@ -1439,6 +1459,33 @@ struct ofono_netreg *ofono_netreg_create(struct ofono_modem *modem, return netreg; } +static gboolean in_pref_oper_list(char *mccmnc, GSList *list) +{ + GSList *l; + for (l = list; l; l = l->next) + if (!strcmp(mccmnc, l->data)) + return TRUE; + return FALSE; +} + +static void list_pref_oper_cb(const struct ofono_error *error, + int total, + const struct ofono_preferred_operator *list, + void *userdata) +{ + struct ofono_netreg *netreg = userdata; + int i; + + for (i = 0; i < total; i++) { + if (!in_pref_oper_list(list[i].mccmnc, netreg->pref_oper_list)) + netreg->pref_oper_list = + g_slist_prepend(netreg->pref_oper_list, + g_strdup(list[i].mccmnc)); + } + + netreg->pref_oper_list = g_slist_reverse(netreg->pref_oper_list); +} + static void netreg_sim_ready(void *userdata) { struct ofono_netreg *netreg = userdata; @@ -1454,6 +1501,9 @@ static void netreg_sim_ready(void *userdata) netreg->driver->registration_status(netreg, init_registration_status, netreg); + if (netreg->driver->list_pref_oper) + netreg->driver->list_pref_oper(netreg, + list_pref_oper_cb, netreg); } static void netreg_sim_watch(struct ofono_atom *atom, -- 1.6.0.6