diff options
author | Jason Simmons <jsimmons@chromium.org> | 2015-03-13 15:30:58 -0700 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2015-03-23 11:31:32 +0100 |
commit | 3ad64c8f5aed43697bf289fce277bde48f208051 (patch) | |
tree | 58cdbad518e592df883d8b2db681ad7a32aaf76b /src | |
parent | a92566ec0e01bc606fd3673276eb5f7ece3b8291 (diff) |
broadband-modem: default implementation of the network time interface
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-broadband-modem.c | 96 | ||||
-rw-r--r-- | src/mm-modem-helpers.c | 75 | ||||
-rw-r--r-- | src/mm-modem-helpers.h | 9 | ||||
-rw-r--r-- | src/tests/test-modem-helpers.c | 73 |
4 files changed, 253 insertions, 0 deletions
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c index 17c128ce..feebbc6e 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 d40082dd..9f0feeac 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 0ec59aff..2e5d8e48 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 b493e6bc..9fd25016 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); |