---
src/cell-info.c | 537 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 537 insertions(+), 0 deletions(-)
create mode 100644 src/cell-info.c
diff --git a/src/cell-info.c b/src/cell-info.c
new file mode 100644
index 0000000..13ae03c
--- /dev/null
+++ b/src/cell-info.c
@@ -0,0 +1,537 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gdbus.h>
+#include <sys/time.h>
+
+#include "ofono.h"
+
+#include "common.h"
+#include "util.h"
+#include "ofono/cell-info.h"
+
+#define OFONO_MAX_NMR_COUNT 15
+#define OFONO_MAX_MEASURED_CELL_COUNT 32
+#define OFONO_MAX_MEAS_RES_LIST_COUNT 8
+
+
+enum ofono_cell_type {
+ OFONO_CELL_TYPE_GERAN,
+ OFONO_CELL_TYPE_UTRA_FDD
+};
+
+enum UTRA_MEAS_TYPE {
+ UTRA_MEAS_TYPE_INTER_FREQ,
+ UTRA_MEAS_TYPE_INTRA_FREQ,
+};
+
+struct gsm {
+ int lac;
+ int ci;
+ int ta;
+ int no_cells;
+ struct {
+ int arfcn;
+ int bsic;
+ int rxlev;
+
+ } nmr[OFONO_MAX_NMR_COUNT];
+};
+
+struct cell_measured_results {
+ int ucid;
+ int sc;
+ int ecn0;
+ int rscp;
+ int pathloss;
+};
+
+struct measured_results_list {
+ int dl_freq;
+ int ul_freq;
+ int rssi;
+ int no_cells;
+ struct cell_measured_results cmr[OFONO_MAX_MEASURED_CELL_COUNT];
+};
+
+struct wcdma {
+ int ucid;
+ int dl_freq;
+ int ul_freq;
+ int sc;
+ int no_freq;
+ struct measured_results_list mrl[OFONO_MAX_MEAS_RES_LIST_COUNT];
+
+};
+
+struct ofono_cell_info_results {
+ enum ofono_cell_type rat;
+ int mcc;
+ int mnc;
+ union {
+ struct gsm gsm;
+ struct wcdma wcdma;
+ };
+
+};
+
+struct ofono_cell_info {
+ DBusMessage *pending;
+ struct ofono_atom *atom;
+ const struct ofono_cell_info_driver *driver;
+ struct ofono_cell_info_results cir;
+ void *driver_data;
+};
+
+
+static DBusMessage *ci_get_cells(DBusConnection *, DBusMessage *, void *);
+
+static GSList *g_drivers = NULL;
+
+static GDBusMethodTable ci_methods[] = {
+ { "GetProperties", "", "a{sv}aa{sv}", ci_get_cells },
+ { }
+};
+
+static GDBusSignalTable ci_signals[] = {
+ { }
+};
+
+int ofono_cell_info_driver_register(struct ofono_cell_info_driver *driver)
+{
+ DBG("driver: %p, name: %s", driver, driver->name);
+
+ if (driver->probe == NULL)
+ return -EINVAL;
+
+ g_drivers = g_slist_prepend(g_drivers, (void *) driver);
+
+ return 0;
+}
+
+void ofono_cell_info_driver_unregister(struct ofono_cell_info_driver *driver)
+{
+ DBG("driver: %p, name: %s", driver, driver->name);
+
+ g_drivers = g_slist_remove(g_drivers, (void *) driver);
+}
+
+void ofono_cell_info_remove(struct ofono_cell_info *ci)
+{
+ __ofono_atom_free(ci->atom);
+}
+
+static void cell_info_unregister(struct ofono_atom *atom)
+{
+ struct ofono_cell_info *ci = __ofono_atom_get_data(atom);
+ const char *path = __ofono_atom_get_path(ci->atom);
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_modem *modem = __ofono_atom_get_modem(ci->atom);
+
+ ofono_modem_remove_interface(modem, OFONO_CELL_INFO_INTERFACE);
+
+ if(!g_dbus_unregister_interface(conn, path, OFONO_CELL_INFO_INTERFACE))
+ ofono_error("Failed to unregister interface %s",
+ OFONO_CELL_INFO_INTERFACE);
+}
+
+static void cell_info_remove(struct ofono_atom *atom)
+{
+ struct ofono_cell_info *ci = __ofono_atom_get_data(atom);
+ DBG("atom: %p", atom);
+
+ if (ci == NULL)
+ return;
+
+ if (ci->driver && ci->driver->remove)
+ ci->driver->remove(ci);
+
+ g_free(ci);
+}
+
+void ofono_cell_info_register(struct ofono_cell_info *ci)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_modem *modem = __ofono_atom_get_modem(ci->atom);
+ const char *path = __ofono_atom_get_path(ci->atom);
+
+ if (!g_dbus_register_interface(conn, path,
+ OFONO_CELL_INFO_INTERFACE,
+ ci_methods, ci_signals, NULL,
+ ci, NULL)) {
+ ofono_error("Could not create %s interface",
+ OFONO_CELL_INFO_INTERFACE);
+
+ return;
+ }
+
+ ofono_modem_add_interface(modem, OFONO_CELL_INFO_INTERFACE);
+
+ __ofono_atom_register(ci->atom, cell_info_unregister);
+}
+
+struct ofono_cell_info *ofono_cell_info_create(struct ofono_modem *modem,
+ unsigned int vendor,
+ const char *driver,
+ void *data)
+{
+ struct ofono_cell_info *ci;
+ GSList *l;
+
+ if (driver == NULL)
+ return NULL;
+
+ ci = g_try_new0(struct ofono_cell_info, 1);
+ if (ci == NULL)
+ return NULL;
+
+ ci->atom = __ofono_modem_add_atom(modem,
+ OFONO_ATOM_TYPE_CELL_INFO,
+ cell_info_remove, ci);
+
+ for (l = g_drivers; l; l = l->next) {
+ const struct ofono_cell_info_driver *drv = l->data;
+
+ if (g_strcmp0(drv->name, driver))
+ continue;
+
+ if (drv->probe(ci, vendor, data) < 0)
+ continue;
+
+ ci->driver = drv;
+ break;
+ }
+
+ return ci;
+}
+
+void *ofono_cell_info_get_data(struct ofono_cell_info *ci)
+{
+ return ci->driver_data;
+}
+
+void ofono_cell_info_set_data(struct ofono_cell_info *ci, void *cid)
+{
+ ci->driver_data = cid;
+}
+
+static int append_geran_meta_data(DBusMessageIter *iter,
+ struct ofono_cell_info_results *ci)
+{
+ DBusMessageIter iter_array;
+ const char *type = "GERAN";
+ dbus_message_iter_open_container(iter,
+ DBUS_TYPE_ARRAY,
+ "{sv}",
+ &iter_array);
+
+ ofono_dbus_dict_append(&iter_array,
+ "Type",
+ DBUS_TYPE_STRING,
+ &type);
+ ofono_dbus_dict_append(&iter_array,
+ "MNC",
+ DBUS_TYPE_INT32,
+ &ci->mnc);
+ ofono_dbus_dict_append(&iter_array,
+ "MCC",
+ DBUS_TYPE_UINT32,
+ &ci->mcc);
+ ofono_dbus_dict_append(&iter_array,
+ "LAC",
+ DBUS_TYPE_UINT32,
+ &ci->gsm.lac);
+ ofono_dbus_dict_append(&iter_array,
+ "CI",
+ DBUS_TYPE_UINT32,
+ &ci->gsm.ci);
+
+ if (ci->gsm.ta != -1)
+ ofono_dbus_dict_append(&iter_array,
+ "TA",
+ DBUS_TYPE_UINT32,
+ &ci->gsm.ta);
+
+ dbus_message_iter_close_container(iter, &iter_array);
+
+ return 0;
+
+}
+
+static int fill_geran_cell_info(DBusMessage *msg,
+ struct ofono_cell_info_results *ci)
+{
+ DBusMessageIter iter, iter_array, iter_array_array;
+
+ int i;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ append_geran_meta_data(&iter, ci);
+
+ dbus_message_iter_close_container(&iter, &iter_array);
+
+ dbus_message_iter_open_container(&iter,
+ DBUS_TYPE_ARRAY,
+ "a{sv}",
+ &iter_array);
+
+ for (i = 0; i < ci->gsm.no_cells; ++i) {
+ dbus_message_iter_open_container(&iter_array,
+ DBUS_TYPE_ARRAY,
+ "{sv}",
+ &iter_array_array);
+ ofono_dbus_dict_append(&iter_array_array,
+ "ARFCN",
+ DBUS_TYPE_UINT32,
+ &ci->gsm.nmr[i].arfcn);
+ ofono_dbus_dict_append(&iter_array_array,
+ "BSIC",
+ DBUS_TYPE_UINT32,
+ &ci->gsm.nmr[i].bsic);
+ ofono_dbus_dict_append(&iter_array_array,
+ "RXLEV",
+ DBUS_TYPE_UINT32,
+ &ci->gsm.nmr[i].rxlev);
+
+ dbus_message_iter_close_container(&iter_array,
+ &iter_array_array);
+ }
+
+ dbus_message_iter_close_container(&iter, &iter_array);
+
+ return 0;
+}
+
+static int append_utra_cell_list(DBusMessageIter *iter,
+ struct cell_measured_results *cmr, int no_cells)
+{
+ int j;
+
+ for (j = 0; j < no_cells; ++j) {
+
+ ofono_dbus_dict_append(iter,
+ "SC",
+ DBUS_TYPE_UINT32,
+ &cmr[j].sc);
+
+ if (cmr[j].ucid != -1)
+ ofono_dbus_dict_append(iter,
+ "UCID",
+ DBUS_TYPE_UINT32,
+ &cmr[j].ucid);
+
+ if (cmr[j].ecn0 != -1)
+ ofono_dbus_dict_append(iter,
+ "ECN0",
+ DBUS_TYPE_UINT32,
+ &cmr[j].ecn0);
+
+ if (cmr[j].rscp != -1)
+ ofono_dbus_dict_append(iter,
+ "RSCP",
+ DBUS_TYPE_UINT32,
+ &cmr[j].rscp);
+
+ if (cmr[j].pathloss != -1)
+ ofono_dbus_dict_append(iter,
+ "Pathloss",
+ DBUS_TYPE_UINT32,
+ &cmr[j].rscp);
+
+ }
+
+ return 0;
+}
+
+static int append_utra_freq_info(DBusMessageIter *iter,
+ struct measured_results_list *mrl)
+{
+ ofono_dbus_dict_append(iter,
+ "RSSI",
+ DBUS_TYPE_INT32,
+ &mrl->rssi);
+
+ ofono_dbus_dict_append(iter,
+ "UARFCN-DL",
+ DBUS_TYPE_UINT32,
+ &mrl->dl_freq);
+
+ ofono_dbus_dict_append(iter,
+ "UARFCN-UL",
+ DBUS_TYPE_INT32,
+ &mrl->ul_freq);
+ return 0;
+}
+
+static int append_utra_neigh_info(DBusMessageIter *iter,
+ struct wcdma *wcdma)
+{
+ DBusMessageIter iter_array, iter_array_array;
+ int i;
+
+ dbus_message_iter_open_container(iter,
+ DBUS_TYPE_ARRAY,
+ "a{sv}",
+ &iter_array);
+
+ for (i = 0; i < wcdma->no_freq; ++i) {
+ dbus_message_iter_open_container(&iter_array,
+ DBUS_TYPE_ARRAY,
+ "{sv}",
+ &iter_array_array);
+ append_utra_freq_info(&iter_array_array, &wcdma->mrl[i]);
+ append_utra_cell_list(&iter_array_array, wcdma->mrl[i].cmr,
+ wcdma->mrl[i].no_cells);
+
+ dbus_message_iter_close_container(&iter_array,
+ &iter_array_array);
+ }
+
+ dbus_message_iter_close_container(iter, &iter_array);
+
+ return 0;
+}
+
+static int fill_utra_cell_info(DBusMessage *msg,
+ struct ofono_cell_info_results *ci)
+{
+ DBusMessageIter iter, iter_array;
+ const char *type = "UTRA-FDD";
+
+ dbus_message_iter_init_append(msg, &iter);
+ dbus_message_iter_open_container(&iter,
+ DBUS_TYPE_ARRAY,
+ "{sv}",
+ &iter_array);
+
+ ofono_dbus_dict_append(&iter_array,
+ "Type",
+ DBUS_TYPE_STRING,
+ &type);
+ ofono_dbus_dict_append(&iter_array,
+ "MNC",
+ DBUS_TYPE_INT32,
+ &ci->mnc);
+ ofono_dbus_dict_append(&iter_array,
+ "MCC",
+ DBUS_TYPE_UINT32,
+ &ci->mcc);
+ ofono_dbus_dict_append(&iter_array,
+ "UCID",
+ DBUS_TYPE_UINT32,
+ &ci->wcdma.ucid);
+ ofono_dbus_dict_append(&iter_array,
+ "SC",
+ DBUS_TYPE_UINT32,
+ &ci->wcdma.sc);
+ ofono_dbus_dict_append(&iter_array,
+ "UARFCN-DL",
+ DBUS_TYPE_UINT32,
+ &ci->wcdma.dl_freq);
+
+ if (ci->wcdma.ul_freq != -1) {
+ ofono_dbus_dict_append(&iter_array,
+ "UARFCN-UL",
+ DBUS_TYPE_UINT32,
+ &ci->wcdma.ul_freq);
+ }
+
+ dbus_message_iter_close_container(&iter, &iter_array);
+
+ append_utra_neigh_info(&iter, &ci->wcdma);
+
+ return 0;
+}
+
+void ofono_cell_info_query_cb(const struct ofono_error *error,
+ void *data)
+{
+ struct ofono_cell_info *ci = data;
+ struct ofono_cell_info_results *ci_results = &ci->cir;
+ DBusMessage *msg = ci->pending;
+ DBusMessage *reply;
+ int status;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ ofono_error("Neighbor cell info query failed");
+ goto error;
+ }
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL) {
+ ofono_error("Failed to create response");
+ goto error;
+ }
+
+ if (ci_results->rat == OFONO_CELL_TYPE_GERAN) {
+ ofono_debug("GSM CELL INFO RECEIVED");
+
+ status = fill_geran_cell_info(msg, ci_results);
+ if (status != 0) {
+ ofono_error("Failed to fill geran info");
+ goto error;
+ }
+
+ } else if (ci_results->rat == OFONO_CELL_TYPE_UTRA_FDD) {
+ ofono_debug("WCDMA CELL INFO RECEIVED");
+
+ status = fill_utra_cell_info(msg, ci_results);
+ if (status != 0) {
+ ofono_error("Failed to fill utra info");
+ goto error;
+ }
+
+ } else {
+ ofono_error("Unrecognized cell type.");
+ goto error;
+ }
+
+ __ofono_dbus_pending_reply(&msg, reply);
+ return;
+
+error:
+ reply = __ofono_error_failed(msg);
+ __ofono_dbus_pending_reply(&msg, reply);
+ return;
+
+}
+
+static DBusMessage *ci_get_cells(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct ofono_cell_info *ci = data;
+
+ ci->pending = dbus_message_ref(msg);
+ ci->driver->query(ci, ofono_cell_info_query_cb, ci->driver_data);
+
+ return NULL;
+}
+
--
1.7.1