[PATCH v2] broadband-modem: default implementation of the network time interface
Jason Simmons
jsimmons at chromium.org
Fri Mar 13 15:30:58 PDT 2015
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.
---
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
More information about the ModemManager-devel
mailing list