<div dir="ltr"><div>Moved this into the base broadband modem object. Please take another look.</div><div><br></div><div><br></div><div>Add support for querying the real-time clock to the Telit plugin.</div><div>Tested with a Telit HE910 modem.</div><div>---</div><div> src/mm-broadband-modem.c | 96 ++++++++++++++++++++++++++++++++++++++++++</div><div> src/mm-modem-helpers.c | 75 +++++++++++++++++++++++++++++++++</div><div> src/mm-modem-helpers.h | 9 ++++</div><div> src/tests/test-modem-helpers.c | 73 ++++++++++++++++++++++++++++++++</div><div> 4 files changed, 253 insertions(+)</div><div><br></div><div>diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c</div><div>index 17c128c..feebbc6 100644</div><div>--- a/src/mm-broadband-modem.c</div><div>+++ b/src/mm-broadband-modem.c</div><div>@@ -7511,6 +7511,96 @@ enable_location_gathering (MMIfaceModemLocation *self,</div><div> }</div><div> </div><div> /*****************************************************************************/</div><div>+/* Load network time (Time interface) */</div><div>+</div><div>+static gchar *</div><div>+modem_time_load_network_time_finish (MMIfaceModemTime *self,</div><div>+ GAsyncResult *res,</div><div>+ GError **error)</div><div>+{</div><div>+ const gchar *response;</div><div>+ gchar *result = NULL;</div><div>+</div><div>+ response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);</div><div>+ if (response)</div><div>+ mm_parse_cclk_response (response, &result, NULL, error);</div><div>+ return result;</div><div>+}</div><div>+</div><div>+static void</div><div>+modem_time_load_network_time (MMIfaceModemTime *self,</div><div>+ GAsyncReadyCallback callback,</div><div>+ gpointer user_data)</div><div>+{</div><div>+ mm_base_modem_at_command (MM_BASE_MODEM (self),</div><div>+ "+CCLK?",</div><div>+ 3,</div><div>+ FALSE,</div><div>+ callback,</div><div>+ user_data);</div><div>+}</div><div>+</div><div>+/*****************************************************************************/</div><div>+/* Load network timezone (Time interface) */</div><div>+</div><div>+static MMNetworkTimezone *</div><div>+modem_time_load_network_timezone_finish (MMIfaceModemTime *self,</div><div>+ GAsyncResult *res,</div><div>+ GError **error)</div><div>+{</div><div>+ const gchar *response;</div><div>+ MMNetworkTimezone *tz = NULL;</div><div>+</div><div>+ response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, NULL);</div><div>+ if (response)</div><div>+ mm_parse_cclk_response (response, NULL, &tz, error);</div><div>+ return tz;</div><div>+}</div><div>+</div><div>+static void</div><div>+modem_time_load_network_timezone (MMIfaceModemTime *self,</div><div>+ GAsyncReadyCallback callback,</div><div>+ gpointer user_data)</div><div>+{</div><div>+ mm_base_modem_at_command (MM_BASE_MODEM (self),</div><div>+ "+CCLK?",</div><div>+ 3,</div><div>+ FALSE,</div><div>+ callback,</div><div>+ user_data);</div><div>+}</div><div>+</div><div>+/*****************************************************************************/</div><div>+/* Check support (Time interface) */</div><div>+</div><div>+static const MMBaseModemAtCommand time_check_sequence[] = {</div><div>+ { "+CTZU=1", 3, TRUE, mm_base_modem_response_processor_no_result_continue },</div><div>+ { "+CCLK?", 3, TRUE, mm_base_modem_response_processor_string },</div><div>+ { NULL }</div><div>+};</div><div>+</div><div>+static gboolean</div><div>+modem_time_check_support_finish (MMIfaceModemTime *self,</div><div>+ GAsyncResult *res,</div><div>+ GError **error)</div><div>+{</div><div>+ return !!mm_base_modem_at_sequence_finish (MM_BASE_MODEM (self), res, NULL, error);</div><div>+}</div><div>+</div><div>+static void</div><div>+modem_time_check_support (MMIfaceModemTime *self,</div><div>+ GAsyncReadyCallback callback,</div><div>+ gpointer user_data)</div><div>+{</div><div>+ mm_base_modem_at_sequence (MM_BASE_MODEM (self),</div><div>+ time_check_sequence,</div><div>+ NULL, /* response_processor_context */</div><div>+ NULL, /* response_processor_context_free */</div><div>+ callback,</div><div>+ user_data);</div><div>+}</div><div>+</div><div>+/*****************************************************************************/</div><div> </div><div> static const gchar *primary_init_sequence[] = {</div><div> /* Ensure echo is off */</div><div>@@ -9824,6 +9914,12 @@ iface_modem_messaging_init (MMIfaceModemMessaging *iface)</div><div> static void</div><div> iface_modem_time_init (MMIfaceModemTime *iface)</div><div> {</div><div>+ iface->check_support = modem_time_check_support;</div><div>+ iface->check_support_finish = modem_time_check_support_finish;</div><div>+ iface->load_network_time = modem_time_load_network_time;</div><div>+ iface->load_network_time_finish = modem_time_load_network_time_finish;</div><div>+ iface->load_network_timezone = modem_time_load_network_timezone;</div><div>+ iface->load_network_timezone_finish = modem_time_load_network_timezone_finish;</div><div> }</div><div> </div><div> static void</div><div>diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c</div><div>index d40082d..9f0feea 100644</div><div>--- a/src/mm-modem-helpers.c</div><div>+++ b/src/mm-modem-helpers.c</div><div>@@ -2621,3 +2621,78 @@ mm_parse_gsn (const char *gsn,</div><div> </div><div> return success;</div><div> }</div><div>+</div><div>+/*****************************************************************************/</div><div>+/* +CCLK response parser */</div><div>+</div><div>+gboolean</div><div>+mm_parse_cclk_response (const char *response,</div><div>+ gchar **iso8601p,</div><div>+ MMNetworkTimezone **tzp,</div><div>+ GError **error)</div><div>+{</div><div>+ GRegex *r;</div><div>+ GMatchInfo *match_info = NULL;</div><div>+ GError *match_error = NULL;</div><div>+ guint year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;</div><div>+ gint tz = 0;</div><div>+ gboolean ret = FALSE;</div><div>+</div><div>+ g_assert (iso8601p || tzp); /* at least one */</div><div>+</div><div>+ /* Sample reply: +CCLK: "15/03/05,14:14:26-32" */</div><div>+ r = g_regex_new ("[+]CCLK: \"(\\d+)/(\\d+)/(\\d+),(\\d+):(\\d+):(\\d+)([-+]\\d+)\"", 0, 0, NULL);</div><div>+ g_assert (r != NULL);</div><div>+</div><div>+ if (!g_regex_match_full (r, response, -1, 0, 0, &match_info, &match_error)) {</div><div>+ if (match_error) {</div><div>+ g_propagate_error (error, match_error);</div><div>+ g_prefix_error (error, "Could not parse +CCLK results: ");</div><div>+ } else {</div><div>+ g_set_error_literal (error,</div><div>+ MM_CORE_ERROR,</div><div>+ MM_CORE_ERROR_FAILED,</div><div>+ "Couldn't match +CCLK reply");</div><div>+ }</div><div>+ } else {</div><div>+ /* Remember that g_match_info_get_match_count() includes match #0 */</div><div>+ g_assert (g_match_info_get_match_count (match_info) >= 8);</div><div>+</div><div>+ if (mm_get_uint_from_match_info (match_info, 1, &year) &&</div><div>+ mm_get_uint_from_match_info (match_info, 2, &month) &&</div><div>+ mm_get_uint_from_match_info (match_info, 3, &day) &&</div><div>+ mm_get_uint_from_match_info (match_info, 4, &hour) &&</div><div>+ mm_get_uint_from_match_info (match_info, 5, &minute) &&</div><div>+ mm_get_uint_from_match_info (match_info, 6, &second) &&</div><div>+ mm_get_int_from_match_info (match_info, 7, &tz)) {</div><div>+ /* adjust year */</div><div>+ year += 2000;</div><div>+ /*</div><div>+ * tz = timezone offset in 15 minute intervals</div><div>+ */</div><div>+ if (iso8601p) {</div><div>+ /* Return ISO-8601 format date/time string */</div><div>+ *iso8601p = mm_new_iso8601_time (year, month, day, hour,</div><div>+ minute, second,</div><div>+ TRUE, (tz * 15));</div><div>+ }</div><div>+ if (tzp) {</div><div>+ *tzp = mm_network_timezone_new ();</div><div>+ mm_network_timezone_set_offset (*tzp, tz * 15);</div><div>+ }</div><div>+</div><div>+ ret = TRUE;</div><div>+ } else {</div><div>+ g_set_error_literal (error,</div><div>+ MM_CORE_ERROR,</div><div>+ MM_CORE_ERROR_FAILED,</div><div>+ "Failed to parse +CCLK reply");</div><div>+ }</div><div>+ }</div><div>+</div><div>+ if (match_info)</div><div>+ g_match_info_free (match_info);</div><div>+ g_regex_unref (r);</div><div>+</div><div>+ return ret;</div><div>+}</div><div>diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h</div><div>index 0ec59af..2e5d8e4 100644</div><div>--- a/src/mm-modem-helpers.h</div><div>+++ b/src/mm-modem-helpers.h</div><div>@@ -20,6 +20,9 @@</div><div> </div><div> #include <ModemManager.h></div><div> </div><div>+#define _LIBMM_INSIDE_MM</div><div>+#include <libmm-glib.h></div><div>+</div><div> #include "glib-object.h"</div><div> #include "mm-charsets.h"</div><div> </div><div>@@ -246,4 +249,10 @@ gboolean mm_parse_gsn (const char *gsn,</div><div> gchar **out_meid,</div><div> gchar **out_esn);</div><div> </div><div>+/* +CCLK response parser */</div><div>+gboolean mm_parse_cclk_response (const gchar *response,</div><div>+ gchar **iso8601p,</div><div>+ MMNetworkTimezone **tzp,</div><div>+ GError **error);</div><div>+</div><div> #endif /* MM_MODEM_HELPERS_H */</div><div>diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c</div><div>index b493e6b..9fd2501 100644</div><div>--- a/src/tests/test-modem-helpers.c</div><div>+++ b/src/tests/test-modem-helpers.c</div><div>@@ -2341,6 +2341,77 @@ test_supported_capability_filter (void *f, gpointer d)</div><div> }</div><div> </div><div> /*****************************************************************************/</div><div>+/* Test +CCLK responses */</div><div>+</div><div>+typedef struct {</div><div>+ const gchar *str;</div><div>+ gboolean ret;</div><div>+ gboolean test_iso8601;</div><div>+ gboolean test_tz;</div><div>+ gchar *iso8601;</div><div>+ gint32 offset;</div><div>+} CclkTest;</div><div>+</div><div>+static const CclkTest cclk_tests[] = {</div><div>+ { "+CCLK: \"14/08/05,04:00:21+40\"", TRUE, TRUE, FALSE,</div><div>+ "2014-08-05T04:00:21+10:00", 600 },</div><div>+ { "+CCLK: \"14/08/05,04:00:21+40\"", TRUE, FALSE, TRUE,</div><div>+ "2014-08-05T04:00:21+10:00", 600 },</div><div>+ { "+CCLK: \"14/08/05,04:00:21+40\"", TRUE, TRUE, TRUE,</div><div>+ "2014-08-05T04:00:21+10:00", 600 },</div><div>+</div><div>+ { "+CCLK: \"15/02/28,20:30:40-32\"", TRUE, TRUE, FALSE,</div><div>+ "2015-02-28T20:30:40-08:00", -480 },</div><div>+ { "+CCLK: \"15/02/28,20:30:40-32\"", TRUE, FALSE, TRUE,</div><div>+ "2015-02-28T20:30:40-08:00", -480 },</div><div>+ { "+CCLK: \"15/02/28,20:30:40-32\"", TRUE, TRUE, TRUE,</div><div>+ "2015-02-28T20:30:40-08:00", -480 },</div><div>+</div><div>+ { "+CCLK: \"XX/XX/XX,XX:XX:XX+XX\"", FALSE, TRUE, FALSE,</div><div>+ NULL, MM_NETWORK_TIMEZONE_OFFSET_UNKNOWN },</div><div>+</div><div>+ { NULL, FALSE, FALSE, FALSE, NULL, MM_NETWORK_TIMEZONE_OFFSET_UNKNOWN }</div><div>+};</div><div>+</div><div>+static void</div><div>+test_cclk_response (void)</div><div>+{</div><div>+ guint i;</div><div>+</div><div>+ for (i = 0; cclk_tests[i].str; i++) {</div><div>+ GError *error = NULL;</div><div>+ gchar *iso8601 = NULL;</div><div>+ MMNetworkTimezone *tz = NULL;</div><div>+ gboolean ret;</div><div>+</div><div>+ ret = mm_parse_cclk_response (cclk_tests[i].str,</div><div>+ cclk_tests[i].test_iso8601 ? &iso8601 : NULL,</div><div>+ cclk_tests[i].test_tz ? &tz : NULL,</div><div>+ &error);</div><div>+</div><div>+ g_assert (ret == cclk_tests[i].ret);</div><div>+ g_assert (ret == (error ? FALSE : TRUE));</div><div>+</div><div>+ g_clear_error (&error);</div><div>+</div><div>+ if (cclk_tests[i].test_iso8601)</div><div>+ g_assert_cmpstr (cclk_tests[i].iso8601, ==, iso8601);</div><div>+</div><div>+ if (cclk_tests[i].test_tz) {</div><div>+ g_assert (mm_network_timezone_get_offset (tz) == cclk_tests[i].offset);</div><div>+ g_assert (mm_network_timezone_get_dst_offset (tz) == MM_NETWORK_TIMEZONE_OFFSET_UNKNOWN);</div><div>+ g_assert (mm_network_timezone_get_leap_seconds (tz) == MM_NETWORK_TIMEZONE_LEAP_SECONDS_UNKNOWN);</div><div>+ }</div><div>+</div><div>+ if (iso8601)</div><div>+ g_free (iso8601);</div><div>+</div><div>+ if (tz)</div><div>+ g_object_unref (tz);</div><div>+ }</div><div>+}</div><div>+</div><div>+/*****************************************************************************/</div><div> </div><div> void</div><div> _mm_log (const char *loc,</div><div>@@ -2501,6 +2572,8 @@ int main (int argc, char **argv)</div><div> </div><div> g_test_suite_add (suite, TESTCASE (test_supported_capability_filter, NULL));</div><div> </div><div>+ g_test_suite_add (suite, TESTCASE (test_cclk_response, NULL));</div><div>+</div><div> result = g_test_run ();</div><div> </div><div> reg_test_data_free (reg_data);</div><div>-- </div><div>2.2.0.rc0.207.ga3a616c</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Mar 12, 2015 at 11:42 AM, Aleksander Morgado <span dir="ltr"><<a href="mailto:aleksander@aleksander.es" target="_blank">aleksander@aleksander.es</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Thu, Mar 12, 2015 at 6:39 PM, Jason Simmons <<a href="mailto:jsimmons@chromium.org">jsimmons@chromium.org</a>> wrote:<br>
> The Telit modem supports AT+CTZU=1 but doesn't seem to require it. When I<br>
> start up the system, the modem has CTZU=0 by default, but queries to<br>
> AT+CCLK? yield the correct time and time zone.<br>
><br>
> I'll try moving the MMIfaceModemTime implementation from this patch up to<br>
> src/mm-broadband-modem.c<br>
><br>
> Also, I don't have an environment for testing with anything besides the<br>
> Telit modem, so I might need some help verifying that a generic<br>
> implementation does not cause problems for other modems.<br>
<br>
</span>We'll take care of that, np. :)<br>
<span class="HOEnZb"><font color="#888888"><br>
--<br>
Aleksander<br>
<a href="https://aleksander.es" target="_blank">https://aleksander.es</a><br>
</font></span></blockquote></div><br></div>