From: Jun Wei <[email protected]>

---
 drivers/ifxmodem/cell-info.c |  398 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 398 insertions(+), 0 deletions(-)
 create mode 100644 drivers/ifxmodem/cell-info.c

diff --git a/drivers/ifxmodem/cell-info.c b/drivers/ifxmodem/cell-info.c
new file mode 100644
index 0000000..471d248
--- /dev/null
+++ b/drivers/ifxmodem/cell-info.c
@@ -0,0 +1,398 @@
+/*
+ *
+ *  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
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/cell-info.h>
+
+#include "gatchat.h"
+#include "gatresult.h"
+
+#include "ifxmodem.h"
+
+#define OFONO_MAX_NEIGHBOUR_CELL_NUMBER 15
+
+static const char *none_prefix[] = { NULL };
+static const char *xcellinfo_prefix[] = { "+XCELLINFO:", NULL };
+
+struct cell_info_data {
+       GAtChat *chat;
+};
+
+static gboolean handle_gsm_servingcell_info(GAtResultIter *iter,
+               struct ofono_cell_info_results *sc)
+{
+       int mcc, mnc, lac, ci, rxlev, bsic, bcch_car, true_freq, t_advance;
+
+       DBG("");
+
+       if (!g_at_result_iter_next_number(iter, &mcc)) {
+               ofono_error("Fail to parse mcc");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &mnc)) {
+               ofono_error("Fail to parse mnc");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &lac)) {
+               ofono_error("Fail to parse lac");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &ci)) {
+               ofono_error("Fail to parse ci");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &rxlev)) {
+               ofono_error("Fail to parse rxlev");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &bsic)) {
+               ofono_error("Fail to parse bsic");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &bcch_car)) {
+               ofono_error("Fail to parse bcch_car");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &true_freq)) {
+               ofono_error("Fail to parse true_freq");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &t_advance)) {
+               ofono_error("Fail to parse t_advance");
+               return FALSE;
+       }
+
+       sc->geran.serving_cell.lac = lac;
+       sc->geran.serving_cell.ci = ci;
+       sc->geran.serving_cell.arfcn = bcch_car;
+       sc->geran.serving_cell.bsic = bsic;
+       sc->geran.serving_cell.rxlev = rxlev;
+       sc->geran.serving_cell.ta = t_advance;
+       sc->geran.serving_cell.true_freq = true_freq;
+
+       snprintf(sc->mcc, sizeof(sc->mcc), "%d", mcc);
+       snprintf(sc->mnc, sizeof(sc->mnc), "%d", mnc);
+
+       return TRUE;
+}
+
+static gboolean handle_gsm_neighbourcell_info(GAtResultIter *iter,
+               struct ofono_cell_info_results *nc, int index)
+{
+       int lac, ci, rxlev, bsic, bcch_car;
+
+       DBG("");
+
+       if (!g_at_result_iter_next_number(iter, &lac)) {
+               ofono_error("Fail to parse lac");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &ci)) {
+               ofono_error("Fail to parse ci");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &rxlev)) {
+               ofono_error("Fail to parse rxlev");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &bsic)) {
+               ofono_error("Fail to parse bsic");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &bcch_car)) {
+               ofono_error("Fail to parse bcch_car");
+               return FALSE;
+       }
+
+       nc->geran.nmr[index].lac = lac;
+       nc->geran.nmr[index].ci = ci;
+       nc->geran.nmr[index].arfcn = bcch_car;
+       nc->geran.nmr[index].bsic = bsic;
+       nc->geran.nmr[index].rxlev = rxlev;
+
+       return TRUE;
+}
+
+static gboolean handle_umts_fdd_servingcell_info(GAtResultIter *iter,
+                               struct ofono_cell_info_results  *sc)
+{
+       int mcc, mnc, lac, uci, dl_freq, ul_freq, scrambling_code;
+
+       DBG("");
+
+       if (!g_at_result_iter_next_number(iter, &mcc)) {
+               ofono_error("Fail to parse mcc");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &mnc)) {
+               ofono_error("Fail to parse mnc");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &lac)) {
+               ofono_error("Fail to parse lac");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &uci)) {
+               ofono_error("Fail to parse uci");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &scrambling_code)) {
+               ofono_error("Fail to parse scrambling code");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &dl_freq)) {
+               ofono_error("Fail to parse dl freq");
+               return FALSE;
+       }
+
+       if (!g_at_result_iter_next_number(iter, &ul_freq)) {
+               ofono_error("Fail to parse ul freq");
+               return FALSE;
+       }
+
+       sc->utra_fdd.serving_cell.lac = lac;
+       sc->utra_fdd.serving_cell.uc = uci;
+       sc->utra_fdd.serving_cell.scrambling_code = scrambling_code;
+       sc->utra_fdd.serving_cell.dl_frequency = dl_freq;
+       sc->utra_fdd.serving_cell.ul_frequency = ul_freq;
+
+       snprintf(sc->mcc, sizeof(sc->mcc), "%d", mcc);
+       snprintf(sc->mnc, sizeof(sc->mnc), "%d", mnc);
+
+       return TRUE;
+}
+
+static void xcellinfo_query_cb(gboolean ok, GAtResult *result,
+                               gpointer user_data)
+{
+       struct cb_data *cbd = user_data;
+       ofono_cell_info_query_cb_t cb = cbd->cb;
+       struct ofono_error error;
+       GAtResultIter iter;
+       struct ofono_cell_info_results cellinfo;
+       gboolean gsm_servingcell_found = FALSE;
+       gboolean umts_fdd_servingcell_found = FALSE;
+       int num = 0;
+
+       decode_at_error(&error, g_at_result_final_response(result));
+
+       if (!ok) {
+               cb(&error, cellinfo, cbd->data);
+               return;
+       }
+
+       g_at_result_iter_init(&iter, result);
+
+       while (g_at_result_iter_next(&iter, "+XCELLINFO:")) {
+               int type;
+
+               if (!g_at_result_iter_next_number(&iter, &type)) {
+                       ofono_warn("Fail to parse cell type info");
+                       continue;
+               }
+
+               switch (type) {
+               case 0:
+                       /* GSM serving cell */
+                       if (gsm_servingcell_found) {
+                               ofono_warn("More than 1 GSM serving cell 
found!");
+                               continue;
+                       }
+
+                       gsm_servingcell_found = TRUE;
+                       cellinfo.rat = OFONO_CELL_INFO_GERAN;
+
+                       if (!handle_gsm_servingcell_info(&iter, &cellinfo)) {
+                               ofono_warn("Wrong GSM serving cell info");
+                               continue;
+                       }
+
+                       break;
+               case 1:
+                       /* GSM neighbour cell */
+                       num++;
+
+                       if (num > OFONO_MAX_NEIGHBOUR_CELL_NUMBER) {
+                               ofono_error("Wrong number of GSM neighbour 
cell");
+                               continue;
+                       }
+
+                       cellinfo.rat = OFONO_CELL_INFO_GERAN;
+
+                       if (!handle_gsm_neighbourcell_info(&iter, &cellinfo, 
(num - 1))) {
+                               ofono_warn("Wrong GSM neighbour cell info");
+                               continue;
+                       }
+
+                       cellinfo.geran.no_cells = num;
+
+                       break;
+               case 2:
+                       /* UMTS FDD serving cell */
+                       if (umts_fdd_servingcell_found) {
+                               ofono_warn("More than 1 UMTS FDD serving cell 
found!");
+                               continue;
+                       }
+
+                       umts_fdd_servingcell_found = TRUE;
+                       cellinfo.rat = OFONO_CELL_INFO_UTRA_FDD;
+
+                       if (!handle_umts_fdd_servingcell_info(&iter, 
&cellinfo)) {
+                               ofono_warn("Wrong UMTS FDD serving cell info");
+                               continue;
+                       }
+
+                       break;
+               case 3:
+                       /* UMTS FDD neighbour cell */
+                       cellinfo.rat = OFONO_CELL_INFO_UTRA_FDD;
+
+                       /*
+                       * TODO: wait for the clarification from modem vendor
+                       * on the neighbour cell info of UMTS FDD network
+                       * handle_umts_fdd_neighbourcell_info(&iter, &cellinfo);
+                       */
+
+                       ofono_warn("UMTS FDD NBR cell is not supported");
+                       continue;
+
+               default:
+                       /* Other types are not supported */
+                       ofono_error("Cell type %d is not supported", type);
+                       CALLBACK_WITH_FAILURE(cb, cellinfo, cbd->data);
+                       return;
+               }
+
+       }
+
+       cb(&error, cellinfo, cbd->data);
+}
+
+static void ifx_cell_info_query(struct ofono_cell_info *ci,
+                        ofono_cell_info_query_cb_t cb,
+                        void *data)
+{
+       struct cell_info_data *cid = ofono_cell_info_get_data(ci);
+       struct cb_data *cbd = cb_data_new(cb, data);
+       struct ofono_cell_info_results cellinfo;
+
+       DBG("");
+
+       if (!cbd)
+               goto error;
+
+       if (g_at_chat_send(cid->chat, "AT+XCELLINFO?", xcellinfo_prefix,
+               xcellinfo_query_cb, cbd, g_free) > 0)
+               return;
+
+error:
+       g_free(cbd);
+       CALLBACK_WITH_FAILURE(cb, cellinfo, data);
+
+}
+
+static void xcellinfo_support_cb(gboolean ok, GAtResult *result, gpointer 
user_data)
+{
+       struct ofono_cell_info *ci = user_data;
+
+       if (!ok)
+               return;
+
+       ofono_cell_info_register(ci);
+}
+
+static int ifx_cell_info_probe(struct ofono_cell_info *ci,
+                       unsigned int vendor, void *data)
+{
+       GAtChat *chat = data;
+       struct cell_info_data *cid;
+
+       cid = g_try_new0(struct cell_info_data, 1);
+
+       if (!cid)
+               return -ENOMEM;
+
+       cid->chat = g_at_chat_clone(chat);
+
+       ofono_cell_info_set_data(ci, cid);
+
+       g_at_chat_send(cid->chat, "AT+XCELLINFO=?", none_prefix,
+                       xcellinfo_support_cb, ci, NULL);
+
+       return 0;
+}
+
+static void ifx_cell_info_remove(struct ofono_cell_info *ci)
+{
+       struct cell_info_data *cid = ofono_cell_info_get_data(ci);
+
+       ofono_cell_info_set_data(ci, NULL);
+
+       g_at_chat_unref(cid->chat);
+       g_free(cid);
+}
+
+static struct ofono_cell_info_driver driver = {
+       .name           = "ifxmodem",
+       .probe          = ifx_cell_info_probe,
+       .remove         = ifx_cell_info_remove,
+       .query          = ifx_cell_info_query,
+};
+
+void ifx_cell_info_init()
+{
+       ofono_cell_info_driver_register(&driver);
+}
+
+void ifx_cell_info_exit()
+{
+       ofono_cell_info_driver_unregister(&driver);
+}
-- 
1.7.2.3

_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono

Reply via email to