diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2013-02-20 12:15:19 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2013-02-20 15:54:54 +0100 |
commit | 000bb642255ecfefe10f7b6629493c34877399c7 (patch) | |
tree | 1092294d763744a3512fc51e05871a047a37043f /src/mm-serial-port.c | |
parent | 9a6fce0a086f28aafda7d963e8661e98a4d44ef6 (diff) |
serial-port: allow specifying some wait time between closing and reopening
We will now by default wait some time (1s) between port getting fully closed and
the port being reopened again. This logic seems to work for multiple modems
where there is a single port for both AT and data, like my Nokia C7 and Iridium
modems. If this wait time is not applied, the port ends up returning EAGAIN for
every write that we try to do afterwards.
Diffstat (limited to 'src/mm-serial-port.c')
-rw-r--r-- | src/mm-serial-port.c | 97 |
1 files changed, 85 insertions, 12 deletions
diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c index 2eab4a94..57820c14 100644 --- a/src/mm-serial-port.c +++ b/src/mm-serial-port.c @@ -98,6 +98,7 @@ typedef struct { guint n_consecutive_timeouts; guint flash_id; + guint reopen_id; guint connected_id; } MMSerialPortPrivate; @@ -871,9 +872,17 @@ mm_serial_port_open (MMSerialPort *self, GError **error) g_return_val_if_fail (MM_IS_SERIAL_PORT (self), FALSE); priv = MM_SERIAL_PORT_GET_PRIVATE (self); - device = mm_port_get_device (MM_PORT (self)); + if (priv->reopen_id) { + g_set_error (error, + MM_SERIAL_ERROR, + MM_SERIAL_ERROR_OPEN_FAILED, + "Could not open serial device %s: reopen operation in progress", + device); + return FALSE; + } + if (priv->open_count) { /* Already open */ goto success; @@ -1204,32 +1213,95 @@ mm_serial_port_queue_command_cached (MMSerialPort *self, internal_queue_command (self, command, take_command, TRUE, timeout_seconds, cancellable, callback, user_data); } +typedef struct { + MMSerialPort *port; + guint initial_open_count; + MMSerialReopenFn callback; + gpointer user_data; +} ReopenInfo; + +static void +serial_port_reopen_cancel (MMSerialPort *self) +{ + MMSerialPortPrivate *priv; + + g_return_if_fail (MM_IS_SERIAL_PORT (self)); + + priv = MM_SERIAL_PORT_GET_PRIVATE (self); + + if (priv->reopen_id > 0) { + g_source_remove (priv->reopen_id); + priv->reopen_id = 0; + } +} + +static gboolean +reopen_do (gpointer data) +{ + ReopenInfo *info = (ReopenInfo *) data; + MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (info->port); + GError *error = NULL; + guint i; + + priv->reopen_id = 0; + + for (i = 0; i < info->initial_open_count; i++) { + if (!mm_serial_port_open (info->port, &error)) { + g_prefix_error (&error, "Couldn't reopen port (%u): ", i); + break; + } + } + + info->callback (info->port, error, info->user_data); + if (error) + g_error_free (error); + g_slice_free (ReopenInfo, info); + return FALSE; +} + gboolean mm_serial_port_reopen (MMSerialPort *self, - GError **error) + guint32 reopen_time, + MMSerialReopenFn callback, + gpointer user_data) { + ReopenInfo *info; MMSerialPortPrivate *priv; - guint initial_open_count; guint i; g_return_val_if_fail (MM_IS_SERIAL_PORT (self), FALSE); + priv = MM_SERIAL_PORT_GET_PRIVATE (self); + + if (priv->reopen_id > 0) { + GError *error; + + error = g_error_new_literal (MM_CORE_ERROR, + MM_CORE_ERROR_IN_PROGRESS, + "Modem is already being reopened."); + callback (self, error, user_data); + g_error_free (error); + return FALSE; + } + + info = g_slice_new0 (ReopenInfo); + info->port = self; + info->callback = callback; + info->user_data = user_data; priv = MM_SERIAL_PORT_GET_PRIVATE (self); - initial_open_count = priv->open_count; + info->initial_open_count = priv->open_count; mm_dbg ("(%s) reopening port (%u)", mm_port_get_device (MM_PORT (self)), - initial_open_count); + info->initial_open_count); - for (i = 0; i < initial_open_count; i++) + for (i = 0; i < info->initial_open_count; i++) mm_serial_port_close (self); - for (i = 0; i < initial_open_count; i++) { - if (!mm_serial_port_open (self, error)) { - g_prefix_error (error, "Couldn't reopen port (%u): ", i); - return FALSE; - } - } + if (reopen_time > 0) + priv->reopen_id = g_timeout_add (reopen_time, reopen_do, info); + else + priv->reopen_id = g_idle_add (reopen_do, info); return TRUE; } @@ -1603,6 +1675,7 @@ dispose (GObject *object) mm_serial_port_close_force (MM_SERIAL_PORT (object)); + serial_port_reopen_cancel (MM_SERIAL_PORT (object)); mm_serial_port_flash_cancel (MM_SERIAL_PORT (object)); G_OBJECT_CLASS (mm_serial_port_parent_class)->dispose (object); |