ifxmodem: Add modem driver to support Neighbor Cell Info
RFC 1/3 ifxmodem: Add modem driver to support Neighbor Cell Info
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
drivers/ifxmodem/cell-info.c new file +398 -0
@@ -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); +}
Signature · 1 line
1.7.2.3