Hi Jonas,

Den tis 24 sep. 2019 kl 18:01 skrev Jonas Bonn <[email protected]>:

> uBlox devices present their USB interfaces well before those interfaces
> are ready to respond to any commands.  The documentation says to monitor
> the 'greeting text' to detect readiness, but this 'greeting text' is not
> actually specified for any device other than the TOBY L4.
>
> What seems to work is to probe the device with 'AT' commands until the
> device responds, and then to wait an additional second before
> proceeding.  The TOBY L4 reliably sends its 'greeting text' (+AT: READY)
> within this interval.
>
> It would be more rigorous to actually wait for the 'READY' indication
> for the TOBY L4, but that would require knowing the device model before
> the device model is actually queried.  This is doable via the USB
> product ID, but overkill when the above heuristic seems to work
> reliably.
>
> Before this patch, the ublox plugin was trying to achieve something like
> the above with the g_at_chat_set_wakeup_command() function, but that had
> some issues:
>
> i)  it did not work reliably, in particular failing badly on the TOBY L4
> with responses getting out of sync with commands
> ii) it was an inappropriate use of the wakeup_command which is intended
> for devices that may sleep when there is no communication during some
> interval
>
> This patch adds an init sequence that probes the device for readiness
> before continuing with initialization.
> ---
>
> Changed in v2:
> - drop return statement
> - drop superfluous empty line
>
>  plugins/ublox.c | 119 ++++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 105 insertions(+), 14 deletions(-)
>
> diff --git a/plugins/ublox.c b/plugins/ublox.c
> index 9ee38a6b..5be9d4cc 100644
> --- a/plugins/ublox.c
> +++ b/plugins/ublox.c
> @@ -29,6 +29,7 @@
>  #include <glib.h>
>  #include <gatchat.h>
>  #include <gattty.h>
> +#include <ell/ell.h>
>
>  #define OFONO_API_SUBJECT_TO_CHANGE
>  #include <ofono/plugin.h>
> @@ -66,6 +67,10 @@ struct ublox_data {
>
>         const struct ublox_model *model;
>         int flags;
> +
> +       struct l_timeout *init_timeout;
>

Shouldn't this should be removed in disable in case its still available..


> +       int init_count;
> +       guint init_cmd;
>  };
>
>  static void ublox_debug(const char *str, void *user_data)
> @@ -223,6 +228,80 @@ fail:
>         ofono_modem_set_powered(modem, FALSE);
>  }
>
> +static void init_cmd_cb(gboolean ok, GAtResult *result, void *user_data)
> +{
> +       struct ofono_modem *modem = user_data;
> +       struct ublox_data *data = ofono_modem_get_data(modem);
> +
> +       DBG("%p", modem);
> +
> +       if (!ok)
> +               goto fail;
> +
> +       /* When the 'init command' succeeds, we insert an additional
> +        * delay of 1 second before proceeding with the actual
> +        * intialization of the device.  We reuse the init_timeout
> +        * instance for this, just clearing the command to indicate
> +        * that additional retries aren't necessary.
> +        */
> +       data->init_cmd = 0;
> +       data->init_count = 0;
> +       l_timeout_modify_ms(data->init_timeout, 1000);
> +
> +       return;
> +
> +fail:
> +       l_timeout_remove(data->init_timeout);
> +       data->init_timeout = NULL;
> +
> +       g_at_chat_unref(data->aux);
> +       data->aux = NULL;
> +       g_at_chat_unref(data->modem);
> +       data->modem = NULL;
> +       ofono_modem_set_powered(modem, FALSE);
> +}
> +
> +static void init_timeout_cb(struct l_timeout *timeout, void *user_data)
> +{
> +       struct ofono_modem *modem = user_data;
> +       struct ublox_data *data = ofono_modem_get_data(modem);
> +
> +       DBG("%p", modem);
> +
> +       /* As long as init_cmd is set we need to either keep retrying
> +        * or fail everything after excessive retries
> +        */
> +       if (data->init_cmd && data->init_count++ < 20) {
> +               g_at_chat_retry(data->aux, data->init_cmd);
> +               l_timeout_modify_ms(timeout, 1000);
> +               return;
> +       }
> +
> +       l_timeout_remove(data->init_timeout);
> +       data->init_timeout = NULL;
> +
> +       if (data->init_cmd) {
> +               ofono_error("failed to init modem after 20 attempts");
> +               goto fail;
> +       }
> +
> +       g_at_chat_send(data->aux, "ATE0", none_prefix,
> +                                       NULL, NULL, NULL);
> +       g_at_chat_send(data->aux, "AT+CMEE=1", none_prefix,
> +                                       NULL, NULL, NULL);
> +
> +       if (g_at_chat_send(data->aux, "AT+CGMM", NULL,
> +                               query_model_cb, modem, NULL) > 0)
> +               return;
> +
> +fail:
> +       g_at_chat_unref(data->aux);
> +       data->aux = NULL;
> +       g_at_chat_unref(data->modem);
> +       data->modem = NULL;
> +       ofono_modem_set_powered(modem, FALSE);
> +}
> +
>  static int ublox_enable(struct ofono_modem *modem)
>  {
>         struct ublox_data *data = ofono_modem_get_data(modem);
> @@ -250,22 +329,34 @@ static int ublox_enable(struct ofono_modem *modem)
>                 g_at_chat_send(data->modem, "AT&C0", NULL, NULL, NULL,
> NULL);
>         }
>
> -       /* The modem can take a while to wake up if just powered on. */
> -       g_at_chat_set_wakeup_command(data->aux, "AT\r", 1000, 11000);
> -
> -       g_at_chat_send(data->aux, "ATE0", none_prefix,
> -                                       NULL, NULL, NULL);
> -       g_at_chat_send(data->aux, "AT+CMEE=1", none_prefix,
> -                                       NULL, NULL, NULL);
> -
> -       if (g_at_chat_send(data->aux, "AT+CGMM", NULL,
> -                               query_model_cb, modem, NULL) > 0)
> -               return -EINPROGRESS;
> +       /*
> +        * uBlox devices present their USB interfaces well before those
> +        * interfaces are actually ready to use.  The specs say to monitor
> +        * the 'greeting text' to detect whether the device is ready to
> use;
> +        * unfortunately, other than for the TOBY L4, the greeting text is
> +        * not actually specified.
> +        *
> +        * What has been determined experimentally to work is to probe with
> +        * an 'AT' command until it responds and then wait an additional
> +        * second before continuing with device initialization.  Even for
> +        * the TOBY L4 where one should wait for the '+AT: READY' URC
> +        * before intialization, this seems to be sufficient; the 'READY'
> +        * indication always arrives within this time.
> +        *
> +        * (It would be more rigorous to actually wait for the 'READY'
> +        * indication, but that would require knowing the device model
> +        * before the device model is actually queried.  Do-able via
> +        * USB Product ID, but overkill when the above seems to work
> +        * reliably.)
> +        */
>
> -       g_at_chat_unref(data->aux);
> -       data->aux = NULL;
> +       data->init_count = 0;
> +       data->init_cmd = g_at_chat_send(data->aux, "AT", none_prefix,
> +                                       init_cmd_cb, modem, NULL);
> +       data->init_timeout = l_timeout_create_ms(500, init_timeout_cb,
> modem,
> +                                                       NULL);
>

Is 500ms enough? What happens if the modem buffers the at commands for a
while
and sends out two "OK"? Won't the second be in the queue and considered
being
the response to the next command?


>
> -       return -EINVAL;
> +       return -EINPROGRESS;
>  }
>
>  static void cfun_disable(gboolean ok, GAtResult *result, gpointer
> user_data)
> --
> 2.20.1
>
> _______________________________________________
> ofono mailing list
> [email protected]
> https://lists.ofono.org/mailman/listinfo/ofono
>
_______________________________________________
ofono mailing list
[email protected]
https://lists.ofono.org/mailman/listinfo/ofono

Reply via email to