Hi Denis, list,

Sorry for my late response, was traveling. I'll address all the
comments and fix the delayed register this week. Thanks again.

On 19 December 2016 at 17:59, Denis Kenzior <denk...@gmail.com> wrote:
> Hi Djalal,
>
> On 12/16/2016 04:05 AM, Djalal Harouni wrote:
>>
>> This adds support for +UCGED mode 2 and for now we collect only
>> EARFCN, EBAND and CQI. Later we will follow up with +UCGED mode 3.
>>
>> Some ublox modems supports +UCGED mode 2 and others only +UCGED mode 3
>> depending on the firmware.
>> ---
>>  drivers/ubloxmodem/netmon.c | 210
>> +++++++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 206 insertions(+), 4 deletions(-)
>>
>
> This looks good.  Just a couple of small nitpicks:
>
>> diff --git a/drivers/ubloxmodem/netmon.c b/drivers/ubloxmodem/netmon.c
>> index 0749078..6fc3bad 100644
>> --- a/drivers/ubloxmodem/netmon.c
>> +++ b/drivers/ubloxmodem/netmon.c
>> @@ -46,6 +46,20 @@
>>
>>  static const char *cops_prefix[] = { "+COPS:", NULL };
>>  static const char *cesq_prefix[] = { "+CESQ:", NULL };
>> +static const char *ucged_prefix[] = { "+UCGED:", NULL };
>> +
>> +/*
>> + * Generic function that should point to number or hexstring result
>> + * parsers. Result should be returned as an int.
>> + */
>> +typedef gboolean (*ucged_g_at_result_iter_next)(GAtResultIter *iter,
>> +                                               int *result);
>> +
>
>
> Maybe ucged_parse_field_t?  However, I'm not sure about the function
> signature here.  g_at_result_iter_next_hexstring returns a guint8 * and
> gsize value.
>
>> +/* Field from +UCGED response */
>> +typedef struct ublox_ucged_value {
>> +       int offset;     /* Offset at response */
>> +       ucged_g_at_result_iter_next ucged_g_at_result_iter_next_field;
>
>
> The name is unnecessarily long.  Maybe parse_field?
>
>
>> +} ublox_ucged_value;
>>
>>  struct netmon_driver_data {
>>         GAtChat *chat;
>> @@ -67,6 +81,10 @@ struct req_cb_data {
>>         int rsrp;       /* CESQ: Reference Signal Received Power */
>>         int ecn0;       /* CESQ: Received Energy Ratio */
>>         int rsrq;       /* CESQ: Reference Signal Received Quality */
>> +
>> +       int earfcn;     /* UCGED: E-UTRA ARFCN */
>> +       int eband;      /* UCGED: E-UTRA Band */
>> +       int cqi;        /* UCGED: Channel Quality Indicator */
>>  };
>>
>>  /*
>> @@ -102,6 +120,7 @@ static inline struct req_cb_data
>> *req_cb_data_new0(void *cb, void *data,
>>         ret->cb = cb;
>>         ret->data = data;
>>         ret->netmon = user;
>> +
>>         ret->rxlev = -1;
>>         ret->ber = -1;
>>         ret->rscp = -1;
>> @@ -109,6 +128,10 @@ static inline struct req_cb_data
>> *req_cb_data_new0(void *cb, void *data,
>>         ret->ecn0 = -1;
>>         ret->rsrq = -1;
>>
>> +       ret->earfcn = -1;
>> +       ret->eband = -1;
>> +       ret->cqi = -1;
>> +
>>         return ret;
>>  }
>>
>> @@ -157,11 +180,165 @@ static void ublox_netmon_finish_success(struct
>> req_cb_data *cbd)
>>                                         OFONO_NETMON_INFO_ECN0, cbd->ecn0,
>>                                         OFONO_NETMON_INFO_RSRQ, cbd->rsrq,
>>                                         OFONO_NETMON_INFO_RSRP, cbd->rsrp,
>> +                                       OFONO_NETMON_INFO_EARFCN,
>> cbd->earfcn,
>> +                                       OFONO_NETMON_INFO_EBAND,
>> cbd->eband,
>> +                                       OFONO_NETMON_INFO_CQI, cbd->cqi,
>>                                         OFONO_NETMON_INFO_INVALID);
>>
>>         CALLBACK_WITH_SUCCESS(cbd->cb, cbd->data);
>>  }
>>
>> +static void ucged_parse_4g(struct req_cb_data *cbd, GAtResultIter *iter)
>> +{
>> +       /* Offset of values in returned response */
>> +       enum ucged_mode2_rat4_offsets {
>> +               UCGED_EARFCN            = 0,
>> +               UCGED_EBAND             = 1,
>> +               UCGED_CQI               = 15,
>> +       };
>> +
>> +       ublox_ucged_value ucged_values[] = {
>> +               { UCGED_EARFCN, g_at_result_iter_next_number },
>> +               { UCGED_EBAND,  g_at_result_iter_next_number },
>> +               { UCGED_CQI,    g_at_result_iter_next_number },
>> +               { -1,           NULL }, /* End of Array */
>> +       };
>> +
>> +       gboolean ok;
>> +       unsigned i;
>> +       ublox_ucged_value *cur;
>> +
>> +       /* Skip to next */
>> +       ok = g_at_result_iter_next(iter, NULL);
>> +       if (!ok) {
>> +               DBG(" UCGED:response: failed to go to next line ");
>> +               return;
>> +       }
>> +
>> +       i = 0;
>> +       cur = &ucged_values[0];
>> +       while (cur->offset >= 0) {
>> +               int number;
>> +
>
>
> If you declare number as unsigned int you won't need the ugly cast below.
>
>
>> +               /* Skip values that we do not want */
>> +               while (i != (unsigned) cur->offset) {
>> +                       ok = g_at_result_iter_skip_next(iter);
>> +                       if (!ok) {
>> +                               DBG(" UCGED: error skip idx: %d ", i);
>> +                               return;
>> +                       }
>> +                       i++;
>> +               }
>> +
>> +               ok = cur->ucged_g_at_result_iter_next_field(iter,
>> &number);
>> +               if (!ok) {
>> +                       DBG(" UCGED: error parsing at idx: %d ", i);
>> +                       return;
>> +               }
>> +
>> +               switch (i) {
>> +               case UCGED_EARFCN:
>> +                       cbd->earfcn = number != 65535 ? number :
>> cbd->earfcn;
>> +                       break;
>> +               case UCGED_EBAND:
>> +                       cbd->eband = number != 255 ? number : cbd->eband;
>> +                       break;
>> +               case UCGED_CQI:
>> +                       cbd->cqi = number != 255 ? number : cbd->cqi;
>> +                       break;
>> +               }
>> +
>> +               i++;
>> +               cur++;
>> +       }
>> +
>> +       /*
>> +        * Sample output for +UCGED MODE 2 will be:
>> +        *
>> +        *      UCGED: MODE 2 RAT = 4G  EARFCN = 1300
>> +        *      UCGED: MODE 2 RAT = 4G  EBAND = 3
>> +        *      UCGED: MODE 2 RAT = 4G  CQI = -1
>
>
> When I asked for sample output, I meant from the modem, not from this
> function
>
>
>> +        *
>> +        * Check the networkmonitor-api documentation and the related
>> +        * references for mode details.
>> +        */
>> +       DBG(" UCGED: MODE 2 RAT = 4G    EARFCN = %d ", cbd->earfcn);
>> +       DBG(" UCGED: MODE 2 RAT = 4G    EBAND = %d ", cbd->eband);
>> +       DBG(" UCGED: MODE 2 RAT = 4G    CQI = %d ", cbd->cqi);
>> +}
>> +
>> +static void ucged_collect_mode2_data(struct req_cb_data *cbd,
>> +                                       GAtResultIter *iter)
>> +{
>> +       int rat;
>> +       gboolean ok;
>> +
>> +       ok = g_at_result_iter_next(iter, NULL);
>> +       if (!ok) {
>> +               DBG(" UCGED:response: failed to go to next line ");
>> +               return;
>> +       }
>> +
>> +       ok = g_at_result_iter_next_number(iter, &rat);
>> +       if (!ok) {
>> +               DBG(" UCGED: error parsing 'RAT' ");
>> +               return;
>> +       }
>> +
>> +       /* For now we support only RAT 4 */
>> +       if (rat != 4) {
>> +               DBG(" UCGED: 'RAT' is %d, nothing to do. ", rat);
>> +               return;
>> +       }
>> +
>> +       DBG(" UCGED: 'RAT' is %d ", rat);
>> +       ucged_parse_4g(cbd, iter);
>> +}
>> +
>> +static void ucged_query_mode2_cb(gboolean ok, GAtResult *result,
>> +                                       gpointer user_data)
>> +{
>> +       struct req_cb_data *cbd = user_data;
>> +       struct ofono_error error;
>> +       GAtResultIter iter;
>> +       int mode;
>> +
>> +       DBG("ok %d", ok);
>> +
>> +       decode_at_error(&error, g_at_result_final_response(result));
>> +
>> +       if (!ok) {
>> +               DBG(" UCGED: failed ");
>> +               goto out;
>> +       }
>> +
>> +       g_at_result_iter_init(&iter, result);
>> +
>> +       if (!g_at_result_iter_next(&iter, "+UCGED:")) {
>> +               DBG(" UCGED: no result ");
>> +               goto out;
>> +       }
>> +
>> +       ok = g_at_result_iter_next_number(&iter, &mode);
>> +       if (!ok) {
>> +               DBG(" UCGED: error parsing 'mode' ");
>> +               goto out;
>> +       }
>> +
>> +       DBG(" UCGED:  report mode is %d ", mode);
>> +
>> +       /* mode 2 collect +UCGED data */
>> +       if (mode == 2)
>> +               ucged_collect_mode2_data(cbd, &iter);
>> +
>> +       /*
>> +        * We never fail at this point we always send what we collected so
>> +        * far
>> +        */
>> +out:
>> +       ublox_netmon_finish_success(cbd);
>> +}
>> +
>>  static void cesq_cb(gboolean ok, GAtResult *result, gpointer user_data)
>>  {
>>         enum cesq_ofono_netmon_info {
>> @@ -175,6 +352,8 @@ static void cesq_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 idx, number;
>> @@ -233,10 +412,17 @@ static void cesq_cb(gboolean ok, GAtResult *result,
>> gpointer user_data)
>>         DBG(" RSRQ      %d ", cbd->rsrq);
>>         DBG(" RSRP      %d ", cbd->rsrp);
>>
>> -       /*
>> -        * We never fail at this point we always send what we collected so
>> -        * far
>> -        */
>> +       cbd = req_cb_data_ref(cbd);
>> +       if (g_at_chat_send(nmd->chat, "AT+UCGED?", NULL,
>> +                       ucged_query_mode2_cb, cbd, req_cb_data_unref) ==
>> 0) {
>> +               /* We never fail, we always send what we collected so far
>> */
>> +               ofono_error("%s: send +UCGED failed", __func__);
>> +               req_cb_data_unref(cbd);
>> +               goto out;
>> +       }
>> +
>> +       return;
>> +
>>  out:
>>         ublox_netmon_finish_success(cbd);
>>  }
>> @@ -320,6 +506,22 @@ static int ublox_netmon_probe(struct ofono_netmon
>> *netmon,
>>
>>         g_idle_add(ublox_delayed_register, netmon);
>>
>
> I still think we should remove ublox_delayed_register and move the
> ofono_netmon_register call into the UCGED=2 callback below.
>
>> +       /*
>> +        * We set +UCGED=2 mode as early as possible so we are able to
>> handle
>> +        * the following:
>> +        * 1) In case the modem supports only +UCGED mode 2 then we have
>> +        *    already set the appropriate mode and we can query the
>> information
>> +        *    later.
>> +        * 2) In case the modem supports only +UCGED mode 3, then to set
>> mode 3
>> +        *    the modem has to be first in +UCGED mode 2. Setting the mode
>> here
>> +        *    allows later to query the information and on errors we
>> fallback
>> +        *    to mode 3.
>> +        *
>> +        * This should handle current firmware versions of ublox modems.
>> +        */
>> +       g_at_chat_send(nmd->chat, "AT+UCGED=2", ucged_prefix,
>> +                       NULL, NULL, NULL);
>> +
>>         return 0;
>>  }
>>
>>
>
> Regards,
> -Denis
_______________________________________________
ofono mailing list
ofono@ofono.org
https://lists.ofono.org/mailman/listinfo/ofono

Reply via email to