All of lore.kernel.org
 help / color / mirror / Atom feed
From: Denis Kenzior <denkenz@gmail.com>
To: ofono@ofono.org
Subject: Re: [PATCH 3/5] ubloxmodem: add the netmon driver
Date: Tue, 29 Nov 2016 11:32:44 -0600	[thread overview]
Message-ID: <583DBBBC.50904@gmail.com> (raw)
In-Reply-To: <1480082415-30822-4-git-send-email-djalal@endocode.com>

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

Hi Djalal,

On 11/25/2016 08:00 AM, djalal(a)endocode.com wrote:
> From: Djalal Harouni <djalal@endocode.com>
>
> This adds a netmon driver for ublox. The driver support both +COPS and
> +CESQ commands to return the previously added ofono netmon types:
>
> RSCP: Received Signal Code Power
> ECN0: Received Energy Ratio
> RSRQ: Reference Signal Received Quality
> RSRP: Reference Signal Received Power
> OPERATOR: the operator
> ---
>   Makefile.am                 |   1 +
>   drivers/ubloxmodem/netmon.c | 339 ++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 340 insertions(+)
>   create mode 100644 drivers/ubloxmodem/netmon.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 3d7774b..07adeab 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -383,6 +383,7 @@ builtin_sources += drivers/atmodem/atutil.h \
>   			drivers/ubloxmodem/ubloxmodem.h \
>   			drivers/ubloxmodem/ubloxmodem.c \
>   			drivers/ubloxmodem/gprs-context.c \
> +			drivers/ubloxmodem/netmon.c \
>   			drivers/ubloxmodem/lte.c
>
>
> diff --git a/drivers/ubloxmodem/netmon.c b/drivers/ubloxmodem/netmon.c
> new file mode 100644
> index 0000000..6b9d74f
> --- /dev/null
> +++ b/drivers/ubloxmodem/netmon.c
> @@ -0,0 +1,339 @@
> +/*
> + *
> + *  oFono - Open Source Telephony
> + *
> + *  Copyright (C) 2016  EndoCode AG. 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 <stdio.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <string.h>
> +#include <errno.h>
> +
> +#include <glib.h>
> +
> +#include <ofono/log.h>
> +#include <ofono/modem.h>
> +#include <ofono/netmon.h>
> +
> +#include "gatchat.h"
> +#include "gatresult.h"
> +
> +#include "common.h"
> +#include "netreg.h"
> +#include "ubloxmodem.h"
> +#include "drivers/atmodem/vendor.h"
> +
> +static const char *cops_prefix[] = { "+COPS:", NULL };
> +static const char *cesq_prefix[] = { "+CESQ:", NULL };
> +
> +struct netmon_driver_data {
> +	GAtChat *modem;
> +	GAtChat *aux;
> +};

Why do you need both the modem and the aux port?  I only see you using 
the aux port.

> +
> +struct req_cb_data {
> +	struct ofono_netmon *netmon;
> +
> +	ofono_netmon_cb_t cb;
> +	void *data;
> +
> +	struct ofono_network_operator op;
> +
> +	int rxlev;	/* CESQ: Received Signal Strength Indication */
> +	int ber;	/* CESQ: Bit Error Rate */
> +	int rscp;	/* CESQ: Received Signal Code Powe */
> +	int rsrp;	/* CESQ: Reference Signal Received Power */
> +	double ecn0;	/* CESQ: Received Energy Ratio */
> +	double rsrq;	/* CESQ: Reference Signal Received Quality */

Why are these doubles?

> +};
> +
> +/*
> + * Returns the appropriate radio access technology.
> + *
> + * If we can not resolve to a specific radio access technolgy
> + * we return OFONO_NETMON_CELL_TYPE_GSM by default.
> + */
> +static int ublox_map_radio_access_technology(int tech)
> +{
> +	switch (tech) {
> +	case ACCESS_TECHNOLOGY_GSM:
> +	case ACCESS_TECHNOLOGY_GSM_COMPACT:
> +		return OFONO_NETMON_CELL_TYPE_GSM;
> +	case ACCESS_TECHNOLOGY_UTRAN:
> +	case ACCESS_TECHNOLOGY_UTRAN_HSDPA:
> +	case ACCESS_TECHNOLOGY_UTRAN_HSUPA:
> +	case ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA:
> +		return OFONO_NETMON_CELL_TYPE_UMTS;
> +	case ACCESS_TECHNOLOGY_EUTRAN:
> +		return OFONO_NETMON_CELL_TYPE_LTE;
> +	}
> +
> +	return OFONO_NETMON_CELL_TYPE_GSM;
> +}
> +
> +static inline struct req_cb_data *req_cb_data_new0(void *cb, void *data, void *user)
> +{
> +	struct req_cb_data *ret = g_new0(struct req_cb_data, 1);
> +	if (ret == NULL)
> +		return NULL;
> +
> +
> +	ret->cb = cb;
> +	ret->data = data;
> +	ret->netmon = user;
> +	ret->rxlev = -1;
> +	ret->ber = -1;
> +	ret->rscp = -1;
> +	ret->rsrp = -1;
> +	ret->ecn0 = -1;
> +	ret->rsrq = -1;
> +
> +	return ret;
> +}
> +
> +static gboolean ublox_delayed_register(gpointer user_data)
> +{
> +	struct ofono_netmon *netmon = user_data;
> +
> +	ofono_netmon_register(netmon);
> +
> +	return FALSE;
> +}
> +
> +static void cesq_cb(gboolean ok, GAtResult *result, gpointer user_data)
> +{
> +	enum cesq_ofono_netmon_info {
> +		CESQ_RXLEV,
> +		CESQ_BER,
> +		CESQ_RSCP,
> +		CESQ_ECN0,
> +		CESQ_RSRQ,
> +		CESQ_RSRP,
> +		_MAX,
> +	};
> +
> +	struct req_cb_data *cbd = user_data;
> +	struct ofono_netmon *nm = cbd->netmon;
> +	struct ofono_error error;
> +	GAtResultIter iter;
> +	int idx, number;
> +
> +	DBG("ok %d", ok);
> +
> +	decode_at_error(&error, g_at_result_final_response(result));
> +
> +	if (!ok) {
> +		goto error;
> +	}

No need for parentheses

> +
> +	g_at_result_iter_init(&iter, result);
> +
> +	if (!g_at_result_iter_next(&iter, "+CESQ:"))
> +		return;

What happens to memory used by cbd? :)

> +
> +	for (idx = 0; idx < _MAX; idx++) {
> +
> +		ok = g_at_result_iter_next_number(&iter, &number);
> +		if (!ok) {
> +			DBG(" error at idx: %d", idx);
> +			goto error;
> +		}
> +
> +		switch (idx) {
> +		case CESQ_RXLEV:
> +			cbd->rxlev = number != 99 ? number:cbd->rxlev;
> +			break;
> +		case CESQ_BER:
> +			cbd->ber = number != 99 ? number:cbd->ber;
> +			break;
> +		case CESQ_RSCP:
> +			cbd->rscp= number != 255 ? number:cbd->rscp;
> +			break;
> +		case CESQ_ECN0:
> +			cbd->ecn0= number != 255 ? number:cbd->ecn0;
> +			break;
> +		case CESQ_RSRQ:
> +			cbd->rsrq= number != 255 ? number:cbd->rsrq;
> +			break;
> +		case CESQ_RSRP:
> +			cbd->rsrp= number != 255 ? number:cbd->rsrp;
> +			break;

space before / after equal sign.  See doc/coding-style.txt

> +		}
> +	}
> +
> +	DBG(" RXLEV	%d ", cbd->rxlev);
> +	DBG(" BER	%d ", cbd->ber);
> +	DBG(" RSCP	%d ", cbd->rscp);
> +	DBG(" ECN0	%f ", cbd->ecn0);
> +	DBG(" RSRQ	%f ", cbd->rsrq);
> +	DBG(" RSRP	%d ", cbd->rsrp);
> +
> +	ofono_netmon_serving_cell_notify(nm,
> +					 cbd->op.tech,
> +					 OFONO_NETMON_INFO_OPERATOR, cbd->op.name,
> +					 OFONO_NETMON_INFO_RXLEV, cbd->rxlev,
> +					 OFONO_NETMON_INFO_BER, cbd->ber,
> +					 OFONO_NETMON_INFO_RSCP, cbd->rscp,
> +					 OFONO_NETMON_INFO_ECN0, cbd->ecn0,
> +					 OFONO_NETMON_INFO_RSRQ, cbd->rsrq,
> +					 OFONO_NETMON_INFO_RSRP, cbd->rsrp,
> +					 OFONO_NETMON_INFO_INVALID);
> +
> +	CALLBACK_WITH_SUCCESS(cbd->cb, cbd->data);
> +	g_free(cbd);
> +	return;
> +
> +error:
> +	CALLBACK_WITH_FAILURE(cbd->cb, cbd->data);
> +	g_free(cbd);
> +}
> +
> +static void cops_cb(gboolean ok, GAtResult *result, gpointer user_data)
> +{
> +	struct req_cb_data *cbd = user_data;
> +	struct ofono_netmon *nm = cbd->netmon;
> +	struct netmon_driver_data *nmd = ofono_netmon_get_data(nm);
> +	struct ofono_error error;
> +	GAtResultIter iter;
> +	int tech;
> +	const char *name;
> +
> +	DBG("ok %d", ok);
> +
> +	decode_at_error(&error, g_at_result_final_response(result));
> +
> +	if (!ok) {
> +		goto error;
> +	}

No need for parentheses

> +
> +	g_at_result_iter_init(&iter, result);
> +
> +	if (!g_at_result_iter_next(&iter, "+COPS:"))
> +		return;

What happens to memory used by cbd?

> +
> +	g_at_result_iter_skip_next(&iter);
> +	g_at_result_iter_skip_next(&iter);
> +
> +	if (g_at_result_iter_next_string(&iter, &name) == FALSE)
> +		goto error;
> +
> +	strncpy(cbd->op.name, name, OFONO_MAX_OPERATOR_NAME_LENGTH);
> +	cbd->op.name[OFONO_MAX_OPERATOR_NAME_LENGTH] = '\0';
> +

As mentioned before, not sure string representation of the operator is 
useful...

> +	/* Ignored for now. TODO: maybe read format but value
> +	 * wouldn't be forwarder anywhere
> +	 */
> +	cbd->op.mcc[0] = '\0';
> +	cbd->op.mnc[0] = '\0';
> +
> +	/* Default to GSM */
> +	if (g_at_result_iter_next_number(&iter, &tech) == FALSE)
> +		cbd->op.tech = ublox_map_radio_access_technology(ACCESS_TECHNOLOGY_GSM);
> +	else
> +		cbd->op.tech = ublox_map_radio_access_technology(tech);
> +
> +	if (g_at_chat_send(nmd->aux, "AT+CESQ", cesq_prefix,
> +			   cesq_cb, cbd, NULL)) {
> +		return;
> +	}
> +
> +error:
> +	CALLBACK_WITH_FAILURE(cbd->cb, cbd->data);
> +	g_free(cbd);
> +}
> +
> +

double empty line

> +static void ublox_netmon_request_update(struct ofono_netmon *netmon,
> +					ofono_netmon_cb_t cb, void *data)
> +{
> +	struct netmon_driver_data *nmd = ofono_netmon_get_data(netmon);
> +	struct req_cb_data *cbd;
> +
> +	DBG("ublox netmon request update");
> +
> +	cbd = req_cb_data_new0(cb, data, netmon);
> +	if (!cbd) {
> +		CALLBACK_WITH_FAILURE(cb, data);
> +		return;
> +	}
> +
> +	if (g_at_chat_send(nmd->aux, "AT+COPS?", cops_prefix,
> +			   cops_cb, cbd, NULL) == 0) {

You should be providing a destructor for cbd.  E.g. last argument to 
g_at_chat_send.  Avoids memory leaks if the modem gets hot-unplugged for 
example.  I think some of the drivers still get this wrong when 
implementing multiple-command transactions.

Might be safer to simply issue AT+COPS;+CESQ and write a single callback 
that parses both responses.

> +		CALLBACK_WITH_FAILURE(cb, data);
> +		g_free(cbd);
> +	}
> +}
> +
> +static int ublox_netmon_probe(struct ofono_netmon *netmon,
> +			      unsigned int vendor, void *user)
> +{
> +	struct netmon_driver_data *n = user;

This is evil and is going to bite you at some point.  In 
ofono_netmon_create inside ublox.c you pass in ublox_data.  So if 
someone changes this structure or ublox_data, things will explode.

> +	struct netmon_driver_data *nmd;
> +
> +	DBG("ublox netmon probe");
> +
> +	nmd = g_try_new0(struct netmon_driver_data, 1);
> +	if (nmd == NULL)
> +		return -ENOMEM;
> +
> +	nmd->modem = g_at_chat_clone(n->modem);
> +	nmd->aux = g_at_chat_clone(n->aux);

If you truly need both ports, use the g_at_chat_set_slave functionality.

> +
> +	ofono_netmon_set_data(netmon, nmd);
> +
> +	g_idle_add(ublox_delayed_register, netmon);
> +
> +	return 0;
> +}
> +
> +static void ublox_netmon_remove(struct ofono_netmon *netmon)
> +{
> +	struct netmon_driver_data *nmd = ofono_netmon_get_data(netmon);
> +
> +	DBG("ublox netmon remove");
> +
> +	ofono_netmon_set_data(netmon, NULL);
> +
> +	g_at_chat_unref(nmd->modem);
> +	g_at_chat_unref(nmd->aux);
> +
> +	g_free(nmd);
> +}
> +
> +static struct ofono_netmon_driver driver = {
> +	.name			= UBLOXMODEM,
> +	.probe			= ublox_netmon_probe,
> +	.remove			= ublox_netmon_remove,
> +	.request_update		= ublox_netmon_request_update,
> +};
> +
> +void ublox_netmon_init(void)
> +{
> +	ofono_netmon_driver_register(&driver);
> +}
> +
> +void ublox_netmon_exit(void)
> +{
> +	ofono_netmon_driver_unregister(&driver);
> +}
>

Regards,
-Denis

  reply	other threads:[~2016-11-29 17:32 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-11-25 14:00 [PATCH 0/5] RFC: ubloxmodem add netmon interface djalal
2016-11-25 14:00 ` [PATCH 1/5] netmon: add OFONO_NETMON_INFO_{RSCP|ECN0|RSRQ|RSRP|OPERATOR} djalal
2016-11-29 16:43   ` Denis Kenzior
2016-11-30 11:45     ` Djalal Harouni
2016-11-25 14:00 ` [PATCH 2/5] netmon: handle OFONO_NETMON_INFO_{RSCP|ECN0|RSRQ|RSRP|OPERATOR} in D-Bus djalal
2016-11-29 16:49   ` Denis Kenzior
2016-11-30 11:48     ` Djalal Harouni
2016-11-25 14:00 ` [PATCH 3/5] ubloxmodem: add the netmon driver djalal
2016-11-29 17:32   ` Denis Kenzior [this message]
2016-11-30 12:05     ` Djalal Harouni
2016-11-25 14:00 ` [PATCH 4/5] ubloxmodem: intialize and register " djalal
2016-11-29 16:53   ` Denis Kenzior
2016-11-30 11:49     ` Djalal Harouni
2016-11-25 14:00 ` [PATCH 5/5] test: support OFONO_NETMON_INFO_{RSCP|ECN0|RSRQ|RSRP|OPERATOR} djalal

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=583DBBBC.50904@gmail.com \
    --to=denkenz@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.