aboutsummaryrefslogtreecommitdiff
path: root/src/mm-serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mm-serial.c')
-rw-r--r--src/mm-serial.c708
1 files changed, 227 insertions, 481 deletions
diff --git a/src/mm-serial.c b/src/mm-serial.c
index 284db4d2..f941feff 100644
--- a/src/mm-serial.c
+++ b/src/mm-serial.c
@@ -2,6 +2,8 @@
#define _GNU_SOURCE /* for strcasestr() */
+#include <stdio.h>
+#include <stdlib.h>
#include <termio.h>
#include <unistd.h>
#include <sys/types.h>
@@ -12,6 +14,10 @@
#include <string.h>
#include "mm-serial.h"
+#include "mm-errors.h"
+#include "mm-options.h"
+
+static gboolean mm_serial_queue_process (gpointer data);
G_DEFINE_TYPE (MMSerial, mm_serial, G_TYPE_OBJECT)
@@ -27,7 +33,6 @@ enum {
LAST_PROP
};
-#define MM_DEBUG_SERIAL 1
#define SERIAL_BUF_SIZE 2048
#define MM_SERIAL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_SERIAL, MMSerialPrivate))
@@ -35,6 +40,15 @@ enum {
typedef struct {
int fd;
GIOChannel *channel;
+ GQueue *queue;
+ GString *command;
+ GString *response;
+
+ /* Response parser data */
+ MMSerialResponseParserFn response_parser_fn;
+ gpointer response_parser_user_data;
+ GDestroyNotify response_parser_notify;
+
struct termios old_t;
char *device;
@@ -44,7 +58,8 @@ typedef struct {
guint stopbits;
guint64 send_delay;
- guint pending_id;
+ guint watch_id;
+ guint timeout_id;
} MMSerialPrivate;
const char *
@@ -189,86 +204,6 @@ parse_stopbits (guint i)
return stopbits;
}
-#ifdef MM_DEBUG_SERIAL
-static inline void
-serial_debug (const char *prefix, const char *data, int len)
-{
- GString *str;
- int i;
-
- str = g_string_sized_new (len);
- for (i = 0; i < len; i++) {
- if (data[i] == '\0')
- g_string_append_c (str, ' ');
- else if (data[i] == '\r')
- g_string_append_c (str, '\n');
- else
- g_string_append_c (str, data[i]);
- }
-
- g_debug ("%s '%s'", prefix, str->str);
- g_string_free (str, TRUE);
-}
-#else
-static inline void
-serial_debug (const char *prefix, const char *data, int len)
-{
-}
-#endif /* MM_DEBUG_SERIAL */
-
-/* Pending data reading */
-
-static gboolean
-mm_serial_timed_out (gpointer data)
-{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (data);
-
- /* Cancel data reading */
- if (priv->pending_id)
- g_source_remove (priv->pending_id);
-
- return FALSE;
-}
-
-static guint
-mm_serial_set_pending (MMSerial *self,
- guint timeout,
- GIOFunc callback,
- gpointer user_data,
- GDestroyNotify notify)
-{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- GSource *source;
-
- if (G_UNLIKELY (priv->pending_id)) {
- /* FIXME: Probably should queue up pending calls instead? */
- /* Multiple pending calls on the same GIOChannel doesn't work, so let's cancel the previous one. */
- g_warning ("Adding new pending call while previous one isn't finished.");
- g_warning ("Cancelling the previous pending call.");
- g_source_remove (priv->pending_id);
- }
-
- priv->pending_id = g_io_add_watch_full (priv->channel,
- G_PRIORITY_DEFAULT,
- G_IO_IN | G_IO_ERR | G_IO_HUP,
- callback, user_data, notify);
-
- source = g_timeout_source_new (timeout * 100);
- g_source_set_closure (source, g_cclosure_new_object (G_CALLBACK (mm_serial_timed_out), G_OBJECT (self)));
- g_source_attach (source, NULL);
- g_source_unref (source);
-
- return priv->pending_id;
-}
-
-static void
-mm_serial_pending_done (MMSerial *self)
-{
- MM_SERIAL_GET_PRIVATE (self)->pending_id = 0;
-}
-
-/****/
-
static gboolean
config_fd (MMSerial *self)
{
@@ -305,312 +240,203 @@ config_fd (MMSerial *self)
return TRUE;
}
-gboolean
-mm_serial_open (MMSerial *self)
+static void
+serial_debug (const char *prefix, const char *buf, int len)
{
- MMSerialPrivate *priv;
-
- g_return_val_if_fail (MM_IS_SERIAL (self), FALSE);
-
- priv = MM_SERIAL_GET_PRIVATE (self);
+ const char *s;
- if (priv->fd)
- /* Already open */
- return TRUE;
+ if (!mm_options_debug ())
+ return;
- g_debug ("(%s) opening serial device...", priv->device);
- priv->fd = open (priv->device, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
+ if (len < 0)
+ len = strlen (buf);
- if (priv->fd < 0) {
- g_warning ("(%s) cannot open device: %s", priv->device, strerror (errno));
- return FALSE;
- }
+ g_print ("%s '", prefix);
- if (ioctl (priv->fd, TCGETA, &priv->old_t) < 0) {
- g_warning ("(%s) cannot control device (errno %d)", priv->device, errno);
- close (priv->fd);
- return FALSE;
- }
+ s = buf;
+ while (len--) {
+ if (g_ascii_isprint (*s))
+ g_print ("%c", *s);
+ else if (*s == '\r')
+ g_print ("<CR>");
+ else if (*s == '\n')
+ g_print ("<LF>");
+ else
+ g_print ("\\%d", *s);
- if (!config_fd (self)) {
- close (priv->fd);
- priv->fd = 0;
- return FALSE;
+ s++;
}
- priv->channel = g_io_channel_unix_new (priv->fd);
-
- return TRUE;
-}
-
-void
-mm_serial_close (MMSerial *self)
-{
- MMSerialPrivate *priv;
-
- g_return_if_fail (MM_IS_SERIAL (self));
-
- priv = MM_SERIAL_GET_PRIVATE (self);
-
- if (priv->pending_id)
- g_source_remove (priv->pending_id);
-
- if (priv->fd) {
- g_message ("Closing device '%s'", priv->device);
-
- if (priv->channel) {
- g_io_channel_unref (priv->channel);
- priv->channel = NULL;
- }
-
- ioctl (priv->fd, TCSETA, &priv->old_t);
- close (priv->fd);
- priv->fd = 0;
- }
+ g_print ("'\n");
}
-gboolean
-mm_serial_send_command (MMSerial *self, GByteArray *command)
+static gboolean
+mm_serial_send_command (MMSerial *self, const char *command)
{
- MMSerialPrivate *priv;
- int fd;
- int i;
- ssize_t status;
-
- g_return_val_if_fail (MM_IS_SERIAL (self), FALSE);
- g_return_val_if_fail (command != NULL, FALSE);
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ const char *s;
+ int status;
- priv = MM_SERIAL_GET_PRIVATE (self);
+ g_string_truncate (priv->command, g_str_has_prefix (command, "AT") ? 0 : 2);
+ g_string_append (priv->command, command);
- fd = priv->fd;
+ if (command[strlen (command)] != '\r')
+ g_string_append_c (priv->command, '\r');
- serial_debug ("Sending:", (char *) command->data, command->len);
+ serial_debug ("-->", priv->command->str, -1);
- for (i = 0; i < command->len; i++) {
+ s = priv->command->str;
+ while (*s) {
again:
- status = write (fd, command->data + i, 1);
-
+ status = write (priv->fd, s, 1);
if (status < 0) {
if (errno == EAGAIN)
goto again;
-
- g_warning ("Error in writing (errno %d)", errno);
- return FALSE;
+ else {
+ g_warning ("Error writing to serial device: %s", strerror (errno));
+ break;
+ }
}
if (priv->send_delay)
usleep (priv->send_delay);
- }
- return TRUE;
-}
-
-gboolean
-mm_serial_send_command_string (MMSerial *self, const char *str)
-{
- GByteArray *command;
- gboolean ret;
-
- g_return_val_if_fail (MM_IS_SERIAL (self), FALSE);
- g_return_val_if_fail (str != NULL, FALSE);
-
- command = g_byte_array_new ();
- g_byte_array_append (command, (guint8 *) str, strlen (str));
- g_byte_array_append (command, (guint8 *) "\r", 1);
-
- ret = mm_serial_send_command (self, command);
- g_byte_array_free (command, TRUE);
+ s++;
+ }
- return ret;
+ return *s == '\0';
}
typedef struct {
- MMSerial *serial;
- char *terminators;
- GString *result;
- MMSerialGetReplyFn callback;
+ char *command;
+ MMSerialResponseFn callback;
gpointer user_data;
-} GetReplyInfo;
+ guint32 timeout;
+} MMQueueData;
static void
-get_reply_done (gpointer data)
+mm_serial_got_response (MMSerial *self, GError *error)
{
- GetReplyInfo *info = (GetReplyInfo *) data;
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMQueueData *info;
- mm_serial_pending_done (info->serial);
+ if (priv->timeout_id)
+ g_source_remove (priv->timeout_id);
- /* Call the callback */
- info->callback (info->serial, info->result->str, info->user_data);
+ info = (MMQueueData *) g_queue_pop_head (priv->queue);
+ if (info) {
+ if (info->callback)
+ info->callback (self, priv->response, error, info->user_data);
- /* Free info */
- g_free (info->terminators);
- g_string_free (info->result, TRUE);
+ g_free (info->command);
+ g_slice_free (MMQueueData, info);
+ }
+
+ if (error)
+ g_error_free (error);
- g_slice_free (GetReplyInfo, info);
+ g_string_truncate (priv->response, 0);
+ if (!g_queue_is_empty (priv->queue))
+ g_idle_add (mm_serial_queue_process, self);
}
static gboolean
-get_reply_got_data (GIOChannel *source,
- GIOCondition condition,
- gpointer data)
+mm_serial_timed_out (gpointer data)
{
- GetReplyInfo *info = (GetReplyInfo *) data;
- gsize bytes_read;
- char buf[SERIAL_BUF_SIZE + 1];
- GIOStatus status;
- gboolean done = FALSE;
- int i;
+ MMSerial *self = MM_SERIAL (data);
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ GError *error;
- if (condition & G_IO_HUP || condition & G_IO_ERR) {
- g_string_truncate (info->result, 0);
- return FALSE;
- }
+ priv->timeout_id = 0;
- do {
- GError *err = NULL;
+ error = g_error_new (MM_SERIAL_ERROR,
+ MM_SERIAL_RESPONSE_TIMEOUT,
+ "%s", "Serial command timed out");
+ /* FIXME: This is not completely correct - if the response finally arrives and there's
+ some other command waiting for response right now, the other command will
+ get the output of the timed out command. Maybe flashing would help here? */
+ mm_serial_got_response (self, error);
- status = g_io_channel_read_chars (source, buf, SERIAL_BUF_SIZE, &bytes_read, &err);
- if (status == G_IO_STATUS_ERROR) {
- g_warning ("%s", err->message);
- g_error_free (err);
- err = NULL;
- }
+ return FALSE;
+}
- if (bytes_read > 0) {
- char *p;
-
- serial_debug ("Got:", buf, bytes_read);
-
- p = &buf[0];
- for (i = 0; i < bytes_read && !done; i++, p++) {
- int j;
- gboolean is_terminator = FALSE;
-
- for (j = 0; j < strlen (info->terminators); j++) {
- if (*p == info->terminators[j]) {
- is_terminator = TRUE;
- break;
- }
- }
-
- if (is_terminator) {
- /* Ignore terminators in the beginning of the output */
- if (info->result->len > 0)
- done = TRUE;
- } else
- g_string_append_c (info->result, *p);
- }
- }
+static gboolean
+mm_serial_queue_process (gpointer data)
+{
+ MMSerial *self = MM_SERIAL (data);
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMQueueData *info;
- /* Limit the size of the buffer */
- if (info->result->len > SERIAL_BUF_SIZE) {
- g_warning ("%s (%s): response buffer filled before repsonse received",
- __func__, MM_SERIAL_GET_PRIVATE (info->serial)->device);
- g_string_truncate (info->result, 0);
- done = TRUE;
- }
- } while (!done || bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN);
+ info = (MMQueueData *) g_queue_peek_head (priv->queue);
+ if (!info)
+ return FALSE;
- return !done;
-}
+ if (mm_serial_send_command (self, info->command)) {
+ GSource *source;
-guint
-mm_serial_get_reply (MMSerial *self,
- guint timeout,
- const char *terminators,
- MMSerialGetReplyFn callback,
- gpointer user_data)
-{
- GetReplyInfo *info;
+ source = g_timeout_source_new (info->timeout);
+ g_source_set_closure (source, g_cclosure_new_object (G_CALLBACK (mm_serial_timed_out), G_OBJECT (self)));
+ g_source_attach (source, NULL);
+ priv->timeout_id = g_source_get_id (source);
+ g_source_unref (source);
+ } else {
+ GError *error;
- g_return_val_if_fail (MM_IS_SERIAL (self), 0);
- g_return_val_if_fail (terminators != NULL, 0);
- g_return_val_if_fail (callback != NULL, 0);
+ error = g_error_new (MM_SERIAL_ERROR,
+ MM_SERIAL_SEND_FAILED,
+ "%s", "Sending command failed");
- info = g_slice_new0 (GetReplyInfo);
- info->serial = self;
- info->terminators = g_strdup (terminators);
- info->result = g_string_new (NULL);
- info->callback = callback;
- info->user_data = user_data;
+ mm_serial_got_response (self, error);
+ }
- return mm_serial_set_pending (self, timeout, get_reply_got_data, info, get_reply_done);
+ return FALSE;
}
-typedef struct {
- MMSerial *serial;
- char **str_needles;
- char **terminators;
- GString *result;
- MMSerialWaitForReplyFn callback;
- gpointer user_data;
- int reply_index;
- guint timeout;
- time_t start;
-} WaitForReplyInfo;
-
-static void
-wait_for_reply_done (gpointer data)
+void
+mm_serial_set_response_parser (MMSerial *self,
+ MMSerialResponseParserFn fn,
+ gpointer user_data,
+ GDestroyNotify notify)
{
- WaitForReplyInfo *info = (WaitForReplyInfo *) data;
-
- mm_serial_pending_done (info->serial);
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- /* Call the callback */
- info->callback (info->serial, info->reply_index, info->user_data);
+ g_return_if_fail (MM_IS_SERIAL (self));
- /* Free info */
- if (info->result)
- g_string_free (info->result, TRUE);
+ if (priv->response_parser_notify)
+ priv->response_parser_notify (priv->response_parser_user_data);
- g_strfreev (info->str_needles);
- g_strfreev (info->terminators);
- g_slice_free (WaitForReplyInfo, info);
+ priv->response_parser_fn = fn;
+ priv->response_parser_user_data = user_data;
+ priv->response_parser_notify = notify;
}
static gboolean
-find_terminator (const char *line, char **terminators)
+parse_response (MMSerial *self,
+ GString *response,
+ GError **error)
{
- int i;
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- for (i = 0; terminators[i]; i++) {
- if (!strncasecmp (line, terminators[i], strlen (terminators[i])))
- return TRUE;
- }
- return FALSE;
-}
+ g_return_val_if_fail (priv->response_parser_fn != NULL, FALSE);
-static gboolean
-find_response (const char *line, char **responses, gint *idx)
-{
- int i;
-
- /* Don't look for a result again if we got one previously */
- for (i = 0; responses[i]; i++) {
- if (strcasestr (line, responses[i])) {
- *idx = i;
- return TRUE;
- }
- }
- return FALSE;
+ return priv->response_parser_fn (priv->response_parser_user_data, response, error);
}
-#define RESPONSE_LINE_MAX 128
-
static gboolean
-wait_for_reply_got_data (GIOChannel *source,
- GIOCondition condition,
- gpointer data)
+data_available (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
{
- WaitForReplyInfo *info = (WaitForReplyInfo *) data;
- gchar buf[SERIAL_BUF_SIZE + 1];
+ MMSerial *self = MM_SERIAL (data);
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ char buf[SERIAL_BUF_SIZE + 1];
gsize bytes_read;
GIOStatus status;
- gboolean got_response = FALSE;
- gboolean done = FALSE;
- if (condition & G_IO_HUP || condition & G_IO_ERR)
- return FALSE;
+ if (condition & G_IO_HUP || condition & G_IO_ERR) {
+ g_string_truncate (priv->response, 0);
+ return TRUE;
+ }
do {
GError *err = NULL;
@@ -623,185 +449,112 @@ wait_for_reply_got_data (GIOChannel *source,
}
if (bytes_read > 0) {
- buf[bytes_read] = 0;
- g_string_append (info->result, buf);
-
- serial_debug ("Got:", info->result->str, info->result->len);
+ serial_debug ("<--", buf, bytes_read);
+ g_string_append_len (priv->response, buf, bytes_read);
}
- /* Look for needles and terminators */
- if ((bytes_read > 0) && info->result->str) {
- char *p = info->result->str;
-
- /* Break the response up into lines and process each one */
- while ( (p < info->result->str + strlen (info->result->str))
- && !(done && got_response)) {
- char line[RESPONSE_LINE_MAX] = { '\0', };
- char *tmp;
- int i;
- gboolean got_something = FALSE;
-
- for (i = 0; *p && (i < RESPONSE_LINE_MAX - 1); p++) {
- /* Ignore front CR/LF */
- if ((*p == '\n') || (*p == '\r')) {
- if (got_something)
- break;
- } else {
- line[i++] = *p;
- got_something = TRUE;
- }
- }
- line[i] = '\0';
-
- tmp = g_strstrip (line);
- if (tmp && strlen (tmp)) {
- done = find_terminator (tmp, info->terminators);
- if (info->reply_index == -1)
- got_response = find_response (tmp, info->str_needles, &(info->reply_index));
- }
- }
-
- if (done && got_response)
- break;
- }
+ if (parse_response (self, priv->response, &err))
+ mm_serial_got_response (self, err);
- /* Limit the size of the buffer */
- if (info->result->len > SERIAL_BUF_SIZE) {
- g_warning ("%s (%s): response buffer filled before repsonse received",
- __func__, MM_SERIAL_GET_PRIVATE (info->serial)->device);
- done = TRUE;
- break;
- }
+ } while (bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN);
- /* Make sure we don't go over the timeout, in addition to the timeout
- * handler that's been scheduled. If for some reason this loop doesn't
- * terminate (terminator not found, whatever) then this should make
- * sure that we don't spin the CPU forever.
- */
- if (time (NULL) - info->start > info->timeout + 1) {
- done = TRUE;
- break;
- } else
- g_usleep (50);
- } while (!done || bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN);
-
- return !done;
+ return TRUE;
}
-guint
-mm_serial_wait_for_reply (MMSerial *self,
- guint timeout,
- char **responses,
- char **terminators,
- MMSerialWaitForReplyFn callback,
- gpointer user_data)
+gboolean
+mm_serial_open (MMSerial *self, GError **error)
{
- WaitForReplyInfo *info;
+ MMSerialPrivate *priv;
- g_return_val_if_fail (MM_IS_SERIAL (self), 0);
- g_return_val_if_fail (responses != NULL, 0);
- g_return_val_if_fail (callback != NULL, 0);
+ g_return_val_if_fail (MM_IS_SERIAL (self), FALSE);
- info = g_slice_new0 (WaitForReplyInfo);
- info->serial = self;
- info->str_needles = g_strdupv (responses);
- info->terminators = g_strdupv (terminators);
- info->result = g_string_new (NULL);
- info->callback = callback;
- info->user_data = user_data;
- info->reply_index = -1;
- info->timeout = timeout;
- info->start = time (NULL);
+ priv = MM_SERIAL_GET_PRIVATE (self);
- return mm_serial_set_pending (self, timeout, wait_for_reply_got_data, info, wait_for_reply_done);
-}
+ if (priv->fd)
+ /* Already open */
+ return TRUE;
-#if 0
-typedef struct {
- MMSerial *serial;
- gboolean timed_out;
- MMSerialWaitQuietFn callback;
- gpointer user_data;
-} WaitQuietInfo;
+ g_debug ("(%s) opening serial device...", priv->device);
+ priv->fd = open (priv->device, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
-static void
-wait_quiet_done (gpointer data)
-{
- WaitQuietInfo *info = (WaitQuietInfo *) data;
+ if (priv->fd < 0) {
+ g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_OPEN_FAILED,
+ "Could not open serial device %s: %s", priv->device, strerror (errno));
+ return FALSE;
+ }
- mm_serial_pending_done (info->serial);
+ if (ioctl (priv->fd, TCGETA, &priv->old_t) < 0) {
+ g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_OPEN_FAILED,
+ "Could not open serial device %s: %s", priv->device, strerror (errno));
+ close (priv->fd);
+ return FALSE;
+ }
- /* Call the callback */
- info->callback (info->serial, info->timed_out, info->user_data);
+ if (!config_fd (self)) {
+ g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_OPEN_FAILED,
+ "Could not open serial device %s: %s", priv->device, strerror (errno));
+ close (priv->fd);
+ priv->fd = 0;
+ return FALSE;
+ }
+
+ priv->channel = g_io_channel_unix_new (priv->fd);
+ priv->watch_id = g_io_add_watch (priv->channel,
+ G_IO_IN | G_IO_ERR | G_IO_HUP,
+ data_available, self);
- /* Free info */
- g_slice_free (WaitQuietInfo, info);
+ return TRUE;
}
-static gboolean
-wait_quiet_quiettime (gpointer data)
+void
+mm_serial_close (MMSerial *self)
{
- WaitQuietInfo *info = (WaitQuietInfo *) data;
-
- info->timed_out = FALSE;
- g_source_remove (MM_SERIAL_GET_PRIVATE (info->serial)->pending);
+ MMSerialPrivate *priv;
- return FALSE;
-}
+ g_return_if_fail (MM_IS_SERIAL (self));
-static gboolean
-wait_quiet_got_data (GIOChannel *source,
- GIOCondition condition,
- gpointer data)
-{
- WaitQuietInfo *info = (WaitQuietInfo *) data;
- gsize bytes_read;
- char buf[4096];
- GIOStatus status;
+ priv = MM_SERIAL_GET_PRIVATE (self);
- if (condition & G_IO_HUP || condition & G_IO_ERR)
- return FALSE;
+ if (priv->fd) {
+ g_message ("Closing device '%s'", priv->device);
- if (condition & G_IO_IN) {
- do {
- status = g_io_channel_read_chars (source, buf, 4096, &bytes_read, NULL);
+ if (priv->channel) {
+ g_source_remove (priv->watch_id);
+ g_io_channel_shutdown (priv->channel, TRUE, NULL);
+ g_io_channel_unref (priv->channel);
+ priv->channel = NULL;
+ }
- if (bytes_read) {
- /* Reset the quiet time timeout */
- g_source_remove (info->quiet_id);
- info->quiet_id = g_timeout_add (info->quiet_time, wait_quiet_quiettime, info);
- }
- } while (bytes_read == 4096 || status == G_IO_STATUS_AGAIN);
+ ioctl (priv->fd, TCSETA, &priv->old_t);
+ close (priv->fd);
+ priv->fd = 0;
}
-
- return TRUE;
}
void
-mm_serial_wait_quiet (MMSerial *self,
- guint timeout,
- guint quiet_time,
- MMSerialWaitQuietFn callback,
- gpointer user_data)
+mm_serial_queue_command (MMSerial *self,
+ const char *command,
+ guint32 timeout_seconds,
+ MMSerialResponseFn callback,
+ gpointer user_data)
{
- WaitQuietInfo *info;
+ MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMQueueData *info;
g_return_if_fail (MM_IS_SERIAL (self));
- g_return_if_fail (callback != NULL);
+ g_return_if_fail (command != NULL);
- info = g_slice_new0 (WaitQuietInfo);
- info->serial = self;
- info->timed_out = TRUE;
+ info = g_slice_new0 (MMQueueData);
+ info->command = g_strdup (command);
+ info->timeout = timeout_seconds * 1000;
info->callback = callback;
info->user_data = user_data;
- info->quiet_id = g_timeout_add (quiet_time,
- wait_quiet_timeout,
- info);
- return mm_serial_set_pending (self, timeout, wait_quiet_got_data, info, wait_quiet_done);
-}
+ g_queue_push_tail (priv->queue, info);
-#endif
+ if (g_queue_get_length (priv->queue) == 1)
+ g_idle_add (mm_serial_queue_process, self);
+}
typedef struct {
MMSerial *serial;
@@ -841,8 +594,6 @@ flash_done (gpointer data)
{
FlashInfo *info = (FlashInfo *) data;
- MM_SERIAL_GET_PRIVATE (info->serial)->pending_id = 0;
-
info->callback (info->serial, info->user_data);
g_slice_free (FlashInfo, info);
@@ -884,25 +635,9 @@ mm_serial_flash (MMSerial *self,
info,
flash_done);
- MM_SERIAL_GET_PRIVATE (self)->pending_id = id;
-
return id;
}
-GIOChannel *
-mm_serial_get_io_channel (MMSerial *self)
-{
- MMSerialPrivate *priv;
-
- g_return_val_if_fail (MM_IS_SERIAL (self), NULL);
-
- priv = MM_SERIAL_GET_PRIVATE (self);
- if (priv->channel)
- return g_io_channel_ref (priv->channel);
-
- return NULL;
-}
-
/*****************************************************************************/
static void
@@ -915,6 +650,10 @@ mm_serial_init (MMSerial *self)
priv->parity = 'n';
priv->stopbits = 1;
priv->send_delay = 0;
+
+ priv->queue = g_queue_new ();
+ priv->command = g_string_new_len ("AT", SERIAL_BUF_SIZE);
+ priv->response = g_string_sized_new (SERIAL_BUF_SIZE);
}
static GObject*
@@ -1012,8 +751,15 @@ finalize (GObject *object)
MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
mm_serial_close (self);
+
+ g_queue_free (priv->queue);
+ g_string_free (priv->command, TRUE);
+ g_string_free (priv->response, TRUE);
g_free (priv->device);
+ if (priv->response_parser_notify)
+ priv->response_parser_notify (priv->response_parser_user_data);
+
G_OBJECT_CLASS (mm_serial_parent_class)->finalize (object);
}