From 6b91b3563b56070f4461c2916932284495729aab Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Thu, 10 Sep 2009 16:11:08 -0500 Subject: [PATCH] Add atmodem cell broadcast driver --- Makefile.am | 1 + drivers/atmodem/atmodem.c | 2 + drivers/atmodem/atmodem.h | 3 + drivers/atmodem/cbs.c | 201 ++++++++++++++++++++++++++++++++++++++ drivers/atmodem/sms.c | 17 ---- 5 files changed, 207 insertions(+), 17 deletions(-) create mode 100644 drivers/atmodem/cbs.c diff --git a/Makefile.am b/Makefile.am index 4ba6f696..395247d9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -91,6 +91,7 @@ builtin_sources += $(gatchat_sources) \ drivers/atmodem/atmodem.c \ drivers/atmodem/call-settings.c \ drivers/atmodem/sms.c \ + drivers/atmodem/cbs.c \ drivers/atmodem/call-forwarding.c \ drivers/atmodem/call-meter.c \ drivers/atmodem/network-registration.c \ diff --git a/drivers/atmodem/atmodem.c b/drivers/atmodem/atmodem.c index c707b2c6..13957bf3 100644 --- a/drivers/atmodem/atmodem.c +++ b/drivers/atmodem/atmodem.c @@ -46,6 +46,7 @@ static int atmodem_init(void) at_sms_init(); at_sim_init(); at_netreg_init(); + at_cbs_init(); return 0; } @@ -64,6 +65,7 @@ static void atmodem_exit(void) at_netreg_exit(); at_devinfo_exit(); at_voicecall_exit(); + at_cbs_exit(); } OFONO_PLUGIN_DEFINE(atmodem, "AT modem driver", VERSION, diff --git a/drivers/atmodem/atmodem.h b/drivers/atmodem/atmodem.h index c57069bb..73a5ebd3 100644 --- a/drivers/atmodem/atmodem.h +++ b/drivers/atmodem/atmodem.h @@ -56,3 +56,6 @@ extern void at_ssn_exit(); extern void at_devinfo_init(); extern void at_devinfo_exit(); + +extern void at_cbs_init(); +extern void at_cbs_exit(); diff --git a/drivers/atmodem/cbs.c b/drivers/atmodem/cbs.c new file mode 100644 index 00000000..3d3b6621 --- /dev/null +++ b/drivers/atmodem/cbs.c @@ -0,0 +1,201 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2008-2009 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 +#endif + +#define _GNU_SOURCE +#include + +#include + +#include +#include +#include +#include "util.h" + +#include "gatchat.h" +#include "gatresult.h" + +#include "atmodem.h" + +static const char *none_prefix[] = { NULL }; + +static void at_cbm_notify(GAtResult *result, gpointer user_data) +{ + struct ofono_cbs *cbs = user_data; + const char *hexpdu; + int pdulen; + GAtResultIter iter; + unsigned char pdu[88]; + long hexpdulen; + + dump_response("at_cbm_notify", TRUE, result); + + g_at_result_iter_init(&iter, result); + + if (!g_at_result_iter_next(&iter, "+CBM:")) + return; + + if (!g_at_result_iter_next_number(&iter, &pdulen)) + return; + + hexpdu = g_at_result_pdu(result); + + if (!hexpdu) { + ofono_error("Got a CBM, but no PDU. Are we in text mode?"); + return; + } + + ofono_debug("Got new Cell Broadcast via CBM: %s, %d", hexpdu, pdulen); + + if (decode_hex_own_buf(hexpdu, -1, &hexpdulen, 0, pdu) == NULL) { + ofono_error("Unable to hex-decode the PDU"); + return; + } + + if (hexpdulen != pdulen) { + ofono_error("hexpdu length not equal to reported pdu length"); + return; + } + + ofono_cbs_notify(cbs, pdu, pdulen); +} + +static void at_cscb_set_cb(gboolean ok, GAtResult *result, gpointer user_data) +{ + struct cb_data *cbd = user_data; + ofono_cbs_set_cb_t cb = cbd->cb; + struct ofono_error error; + + dump_response("cscb_set_cb", ok, result); + decode_at_error(&error, g_at_result_final_response(result)); + + cb(&error, cbd->data); +} + +static void at_cbs_set_topics(struct ofono_cbs *cbs, const char *topics, + ofono_cbs_set_cb_t cb, void *user_data) +{ + GAtChat *chat = ofono_cbs_get_data(cbs); + struct cb_data *cbd = cb_data_new(cb, user_data); + char *buf; + unsigned int id; + + if (!cbd) + goto error; + + buf = g_strdup_printf("AT+CSCB=0,\"%s\"", topics); + + id = g_at_chat_send(chat, buf, none_prefix, + at_cscb_set_cb, cbd, g_free); + + g_free(buf); + + if (id > 0) + return; + +error: + if (cbd) + g_free(cbd); + + { + DECLARE_FAILURE(error); + cb(&error, user_data); + } +} + +static void at_cbs_clear_topics(struct ofono_cbs *cbs, + ofono_cbs_set_cb_t cb, void *user_data) +{ + GAtChat *chat = ofono_cbs_get_data(cbs); + struct cb_data *cbd = cb_data_new(cb, user_data); + + if (!cbd) + goto error; + + if (g_at_chat_send(chat, "AT+CSCB=1,\"0-65535\"", none_prefix, + at_cscb_set_cb, cbd, g_free) > 0) + return; + +error: + if (cbd) + g_free(cbd); + + { + DECLARE_FAILURE(error); + cb(&error, user_data); + } +} + +static gboolean at_cbs_register(gpointer user) +{ + struct ofono_cbs *cbs = user; + GAtChat *chat = ofono_cbs_get_data(cbs); + + /* This driver assumes that something else will properly setup + * CNMI notifications to deliver CBS broadcasts via +CBM. We do + * not setup CNMI string ourselves here to avoid race conditions + * with the SMS driver which will also be setting the CNMI itself + * + * The default SMS driver will setup the CNMI for +CBM delivery + * appropriately for us + */ + g_at_chat_register(chat, "+CBM:", at_cbm_notify, TRUE, cbs, NULL); + + ofono_cbs_register(cbs); + + return FALSE; +} + +static int at_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor, + void *data) +{ + GAtChat *chat = data; + + ofono_cbs_set_data(cbs, chat); + g_idle_add(at_cbs_register, cbs); + + return 0; +} + +static void at_cbs_remove(struct ofono_cbs *cbs) +{ +} + +static struct ofono_cbs_driver driver = { + .name = "atmodem", + .probe = at_cbs_probe, + .remove = at_cbs_remove, + .set_topics = at_cbs_set_topics, + .clear_topics = at_cbs_clear_topics, +}; + +void at_cbs_init() +{ + ofono_cbs_driver_register(&driver); +} + +void at_cbs_exit() +{ + ofono_cbs_driver_unregister(&driver); +} diff --git a/drivers/atmodem/sms.c b/drivers/atmodem/sms.c index 11d2ff20..fc8f30a1 100644 --- a/drivers/atmodem/sms.c +++ b/drivers/atmodem/sms.c @@ -295,21 +295,6 @@ static gboolean at_parse_pdu_common(GAtResult *result, const char *prefix, return TRUE; } -static void at_cbm_notify(GAtResult *result, gpointer user_data) -{ - int pdulen; - const char *pdu; - - dump_response("at_cbm_notify", TRUE, result); - - if (!at_parse_pdu_common(result, "+CBM:", &pdu, &pdulen)) { - ofono_error("Unable to parse CBM notification"); - return; - } - - ofono_debug("Got new Cell Broadcast via CBM: %s, %d", pdu, pdulen); -} - static void at_cds_notify(GAtResult *result, gpointer user_data) { struct ofono_sms *sms = user_data; @@ -628,8 +613,6 @@ static void at_sms_initialized(struct ofono_sms *sms) sms, NULL); g_at_chat_register(data->chat, "+CDS:", at_cds_notify, TRUE, sms, NULL); - g_at_chat_register(data->chat, "+CBM:", at_cbm_notify, TRUE, - sms, NULL); /* We treat CMGR just like a notification */ g_at_chat_register(data->chat, "+CMGR:", at_cmgr_notify, TRUE,