[PATCH v2] broadband-modem: default implementation of the network time interface

Aleksander Morgado aleksander at aleksander.es
Mon Mar 23 03:38:32 PDT 2015


On Fri, Mar 13, 2015 at 11:30 PM, Jason Simmons <jsimmons at chromium.org> wrote:
> Add a default implementation that queries the real-time clock using the
> AT+CCLK? command.  Also set AT+CTZU=1 in case a modem requires it.
> ---

Patch looks good, so pushed to git master. Didn't test it with all my
modems, though, we should look at this with detail when doing the
tests for the next major release, whenever that is.,


>  src/mm-broadband-modem.c       | 96 ++++++++++++++++++++++++++++++++++++++++++
>  src/mm-modem-helpers.c         | 75 +++++++++++++++++++++++++++++++++
>  src/mm-modem-helpers.h         |  9 ++++
>  src/tests/test-modem-helpers.c | 73 ++++++++++++++++++++++++++++++++
>  4 files changed, 253 insertions(+)
>
> diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
> index 17c128c..feebbc6 100644
> --- a/src/mm-broadband-modem.c
> +++ b/src/mm-broadband-modem.c
> @@ -7511,6 +7511,96 @@ enable_location_gathering (MMIfaceModemLocation *self,
>  }
>
>  /*****************************************************************************/
> +/* Load network time (Time interface) */
> +
> +static gchar *
> +modem_time_load_network_time_finish (MMIfaceModemTime *self,
> +                                     GAsyncResult *res,
> +                                     GError **error)
> +{
> +    const gchar *response;
> +    gchar *result = NULL;
> +
> +    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
> +    if (response)
> +        mm_parse_cclk_response (response, &result, NULL, error);
> +    return result;
> +}
> +
> +static void
> +modem_time_load_network_time (MMIfaceModemTime *self,
> +                              GAsyncReadyCallback callback,
> +                              gpointer user_data)
> +{
> +    mm_base_modem_at_command (MM_BASE_MODEM (self),
> +                              "+CCLK?",
> +                              3,
> +                              FALSE,
> +                              callback,
> +                              user_data);
> +}
> +
> +/*****************************************************************************/
> +/* Load network timezone (Time interface) */
> +
> +static MMNetworkTimezone *
> +modem_time_load_network_timezone_finish (MMIfaceModemTime *self,
> +                                         GAsyncResult *res,
> +                                         GError **error)
> +{
> +    const gchar *response;
> +    MMNetworkTimezone *tz = NULL;
> +
> +    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, NULL);
> +    if (response)
> +        mm_parse_cclk_response (response, NULL, &tz, error);
> +    return tz;
> +}
> +
> +static void
> +modem_time_load_network_timezone (MMIfaceModemTime *self,
> +                                  GAsyncReadyCallback callback,
> +                                  gpointer user_data)
> +{
> +    mm_base_modem_at_command (MM_BASE_MODEM (self),
> +                              "+CCLK?",
> +                              3,
> +                              FALSE,
> +                              callback,
> +                              user_data);
> +}
> +
> +/*****************************************************************************/
> +/* Check support (Time interface) */
> +
> +static const MMBaseModemAtCommand time_check_sequence[] = {
> +    { "+CTZU=1",  3, TRUE, mm_base_modem_response_processor_no_result_continue },
> +    { "+CCLK?",   3, TRUE, mm_base_modem_response_processor_string },
> +    { NULL }
> +};
> +
> +static gboolean
> +modem_time_check_support_finish (MMIfaceModemTime *self,
> +                                 GAsyncResult *res,
> +                                 GError **error)
> +{
> +    return !!mm_base_modem_at_sequence_finish (MM_BASE_MODEM (self), res, NULL, error);
> +}
> +
> +static void
> +modem_time_check_support (MMIfaceModemTime *self,
> +                          GAsyncReadyCallback callback,
> +                          gpointer user_data)
> +{
> +    mm_base_modem_at_sequence (MM_BASE_MODEM (self),
> +                               time_check_sequence,
> +                               NULL, /* response_processor_context */
> +                               NULL, /* response_processor_context_free */
> +                               callback,
> +                               user_data);
> +}
> +
> +/*****************************************************************************/
>
>  static const gchar *primary_init_sequence[] = {
>      /* Ensure echo is off */
> @@ -9824,6 +9914,12 @@ iface_modem_messaging_init (MMIfaceModemMessaging *iface)
>  static void
>  iface_modem_time_init (MMIfaceModemTime *iface)
>  {
> +    iface->check_support = modem_time_check_support;
> +    iface->check_support_finish = modem_time_check_support_finish;
> +    iface->load_network_time = modem_time_load_network_time;
> +    iface->load_network_time_finish = modem_time_load_network_time_finish;
> +    iface->load_network_timezone = modem_time_load_network_timezone;
> +    iface->load_network_timezone_finish = modem_time_load_network_timezone_finish;
>  }
>
>  static void
> diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
> index d40082d..9f0feea 100644
> --- a/src/mm-modem-helpers.c
> +++ b/src/mm-modem-helpers.c
> @@ -2621,3 +2621,78 @@ mm_parse_gsn (const char *gsn,
>
>      return success;
>  }
> +
> +/*****************************************************************************/
> +/* +CCLK response parser */
> +
> +gboolean
> +mm_parse_cclk_response (const char *response,
> +                        gchar **iso8601p,
> +                        MMNetworkTimezone **tzp,
> +                        GError **error)
> +{
> +    GRegex *r;
> +    GMatchInfo *match_info = NULL;
> +    GError *match_error = NULL;
> +    guint year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
> +    gint tz = 0;
> +    gboolean ret = FALSE;
> +
> +    g_assert (iso8601p || tzp); /* at least one */
> +
> +    /* Sample reply: +CCLK: "15/03/05,14:14:26-32" */
> +    r = g_regex_new ("[+]CCLK: \"(\\d+)/(\\d+)/(\\d+),(\\d+):(\\d+):(\\d+)([-+]\\d+)\"", 0, 0, NULL);
> +    g_assert (r != NULL);
> +
> +    if (!g_regex_match_full (r, response, -1, 0, 0, &match_info, &match_error)) {
> +        if (match_error) {
> +            g_propagate_error (error, match_error);
> +            g_prefix_error (error, "Could not parse +CCLK results: ");
> +        } else {
> +            g_set_error_literal (error,
> +                                 MM_CORE_ERROR,
> +                                 MM_CORE_ERROR_FAILED,
> +                                 "Couldn't match +CCLK reply");
> +        }
> +    } else {
> +        /* Remember that g_match_info_get_match_count() includes match #0 */
> +        g_assert (g_match_info_get_match_count (match_info) >= 8);
> +
> +        if (mm_get_uint_from_match_info (match_info, 1, &year) &&
> +            mm_get_uint_from_match_info (match_info, 2, &month) &&
> +            mm_get_uint_from_match_info (match_info, 3, &day) &&
> +            mm_get_uint_from_match_info (match_info, 4, &hour) &&
> +            mm_get_uint_from_match_info (match_info, 5, &minute) &&
> +            mm_get_uint_from_match_info (match_info, 6, &second) &&
> +            mm_get_int_from_match_info  (match_info, 7, &tz)) {
> +            /* adjust year */
> +            year += 2000;
> +            /*
> +             * tz = timezone offset in 15 minute intervals
> +             */
> +            if (iso8601p) {
> +                /* Return ISO-8601 format date/time string */
> +                *iso8601p = mm_new_iso8601_time (year, month, day, hour,
> +                                                 minute, second,
> +                                                 TRUE, (tz * 15));
> +            }
> +            if (tzp) {
> +                *tzp = mm_network_timezone_new ();
> +                mm_network_timezone_set_offset (*tzp, tz * 15);
> +            }
> +
> +            ret = TRUE;
> +        } else {
> +            g_set_error_literal (error,
> +                                 MM_CORE_ERROR,
> +                                 MM_CORE_ERROR_FAILED,
> +                                 "Failed to parse +CCLK reply");
> +        }
> +    }
> +
> +    if (match_info)
> +        g_match_info_free (match_info);
> +    g_regex_unref (r);
> +
> +    return ret;
> +}
> diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
> index 0ec59af..2e5d8e4 100644
> --- a/src/mm-modem-helpers.h
> +++ b/src/mm-modem-helpers.h
> @@ -20,6 +20,9 @@
>
>  #include <ModemManager.h>
>
> +#define _LIBMM_INSIDE_MM
> +#include <libmm-glib.h>
> +
>  #include "glib-object.h"
>  #include "mm-charsets.h"
>
> @@ -246,4 +249,10 @@ gboolean mm_parse_gsn (const char *gsn,
>                         gchar **out_meid,
>                         gchar **out_esn);
>
> +/* +CCLK response parser */
> +gboolean mm_parse_cclk_response (const gchar *response,
> +                                 gchar **iso8601p,
> +                                 MMNetworkTimezone **tzp,
> +                                 GError **error);
> +
>  #endif  /* MM_MODEM_HELPERS_H */
> diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c
> index b493e6b..9fd2501 100644
> --- a/src/tests/test-modem-helpers.c
> +++ b/src/tests/test-modem-helpers.c
> @@ -2341,6 +2341,77 @@ test_supported_capability_filter (void *f, gpointer d)
>  }
>
>  /*****************************************************************************/
> +/* Test +CCLK responses */
> +
> +typedef struct {
> +    const gchar *str;
> +    gboolean ret;
> +    gboolean test_iso8601;
> +    gboolean test_tz;
> +    gchar *iso8601;
> +    gint32 offset;
> +} CclkTest;
> +
> +static const CclkTest cclk_tests[] = {
> +    { "+CCLK: \"14/08/05,04:00:21+40\"", TRUE, TRUE, FALSE,
> +        "2014-08-05T04:00:21+10:00", 600 },
> +    { "+CCLK: \"14/08/05,04:00:21+40\"", TRUE, FALSE, TRUE,
> +        "2014-08-05T04:00:21+10:00", 600 },
> +    { "+CCLK: \"14/08/05,04:00:21+40\"", TRUE, TRUE, TRUE,
> +        "2014-08-05T04:00:21+10:00", 600 },
> +
> +    { "+CCLK: \"15/02/28,20:30:40-32\"", TRUE, TRUE, FALSE,
> +        "2015-02-28T20:30:40-08:00", -480 },
> +    { "+CCLK: \"15/02/28,20:30:40-32\"", TRUE, FALSE, TRUE,
> +        "2015-02-28T20:30:40-08:00", -480 },
> +    { "+CCLK: \"15/02/28,20:30:40-32\"", TRUE, TRUE, TRUE,
> +        "2015-02-28T20:30:40-08:00", -480 },
> +
> +    { "+CCLK: \"XX/XX/XX,XX:XX:XX+XX\"", FALSE, TRUE, FALSE,
> +        NULL, MM_NETWORK_TIMEZONE_OFFSET_UNKNOWN },
> +
> +    { NULL, FALSE, FALSE, FALSE, NULL, MM_NETWORK_TIMEZONE_OFFSET_UNKNOWN }
> +};
> +
> +static void
> +test_cclk_response (void)
> +{
> +    guint i;
> +
> +    for (i = 0; cclk_tests[i].str; i++) {
> +        GError *error = NULL;
> +        gchar *iso8601 = NULL;
> +        MMNetworkTimezone *tz = NULL;
> +        gboolean ret;
> +
> +        ret = mm_parse_cclk_response (cclk_tests[i].str,
> +                                      cclk_tests[i].test_iso8601 ? &iso8601 : NULL,
> +                                      cclk_tests[i].test_tz ? &tz : NULL,
> +                                      &error);
> +
> +        g_assert (ret == cclk_tests[i].ret);
> +        g_assert (ret == (error ? FALSE : TRUE));
> +
> +        g_clear_error (&error);
> +
> +        if (cclk_tests[i].test_iso8601)
> +            g_assert_cmpstr (cclk_tests[i].iso8601, ==, iso8601);
> +
> +        if (cclk_tests[i].test_tz) {
> +            g_assert (mm_network_timezone_get_offset (tz) == cclk_tests[i].offset);
> +            g_assert (mm_network_timezone_get_dst_offset (tz) == MM_NETWORK_TIMEZONE_OFFSET_UNKNOWN);
> +            g_assert (mm_network_timezone_get_leap_seconds (tz) == MM_NETWORK_TIMEZONE_LEAP_SECONDS_UNKNOWN);
> +        }
> +
> +        if (iso8601)
> +            g_free (iso8601);
> +
> +        if (tz)
> +            g_object_unref (tz);
> +    }
> +}
> +
> +/*****************************************************************************/
>
>  void
>  _mm_log (const char *loc,
> @@ -2501,6 +2572,8 @@ int main (int argc, char **argv)
>
>      g_test_suite_add (suite, TESTCASE (test_supported_capability_filter, NULL));
>
> +    g_test_suite_add (suite, TESTCASE (test_cclk_response, NULL));
> +
>      result = g_test_run ();
>
>      reg_test_data_free (reg_data);
> --
> 2.2.0.rc0.207.ga3a616c
>
> _______________________________________________
> ModemManager-devel mailing list
> ModemManager-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/modemmanager-devel



-- 
Aleksander
https://aleksander.es


More information about the ModemManager-devel mailing list