Open Source Telephony
 help / color / mirror / Atom feed
From: jun.wei@intel.com
To: ofono@ofono.org
Subject: [RFC 1/3] ifxmodem: Add modem driver to support Neighbor Cell Info
Date: Tue, 23 Nov 2010 13:12:05 +0800	[thread overview]
Message-ID: <1290489125-11876-1-git-send-email-jun.wei@intel.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 10331 bytes --]

From: Jun Wei <jun.wei@intel.com>

---
 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


                 reply	other threads:[~2010-11-23  5:12 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1290489125-11876-1-git-send-email-jun.wei@intel.com \
    --to=jun.wei@intel.com \
    --cc=ofono@ofono.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox