aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-03-27 11:21:06 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-03-29 09:17:53 +0200
commita0b3663274f9e22a9a74267c0b1748613bc34999 (patch)
tree1e7f758ffcf3fd1cb43bd5d8e410e62c0202ac2f
parent2bd321489dc2dd51ee0de7784be00e0f31a1f848 (diff)
gps-serial-port: new type to handle read-only serial ports with GPS traces
-rw-r--r--src/Makefile.am4
-rw-r--r--src/mm-gps-serial-port.c218
-rw-r--r--src/mm-gps-serial-port.h57
3 files changed, 278 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 416f5c76..53b77b76 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -70,7 +70,9 @@ libserial_la_SOURCES = \
mm-at-serial-port.c \
mm-at-serial-port.h \
mm-qcdm-serial-port.c \
- mm-qcdm-serial-port.h
+ mm-qcdm-serial-port.h \
+ mm-gps-serial-port.c \
+ mm-gps-serial-port.h
# Daemon specific enum types
DAEMON_ENUMS = \
diff --git a/src/mm-gps-serial-port.c b/src/mm-gps-serial-port.c
new file mode 100644
index 00000000..cfd653c4
--- /dev/null
+++ b/src/mm-gps-serial-port.c
@@ -0,0 +1,218 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "mm-gps-serial-port.h"
+#include "mm-log.h"
+
+G_DEFINE_TYPE (MMGpsSerialPort, mm_gps_serial_port, MM_TYPE_SERIAL_PORT)
+
+struct _MMGpsSerialPortPrivate {
+ /* Trace handler data */
+ MMGpsSerialTraceFn callback;
+ gpointer user_data;
+ GDestroyNotify notify;
+
+ /* Regex for all known traces */
+ GRegex *known_traces_regex;
+};
+
+/*****************************************************************************/
+
+void
+mm_gps_serial_port_add_trace_handler (MMGpsSerialPort *self,
+ MMGpsSerialTraceFn callback,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ g_return_if_fail (MM_IS_GPS_SERIAL_PORT (self));
+
+ if (self->priv->notify)
+ self->priv->notify (self->priv->user_data);
+
+ self->priv->callback = callback;
+ self->priv->user_data = user_data;
+ self->priv->notify = notify;
+}
+
+/*****************************************************************************/
+
+static gboolean
+remove_eval_cb (const GMatchInfo *match_info,
+ GString *result,
+ gpointer user_data)
+{
+ int *result_len = (int *) user_data;
+ int start;
+ int end;
+
+ if (g_match_info_fetch_pos (match_info, 0, &start, &end))
+ *result_len -= (end - start);
+
+ return FALSE;
+}
+
+static gboolean
+parse_response (MMSerialPort *port,
+ GByteArray *response,
+ GError **error)
+{
+ MMGpsSerialPort *self = MM_GPS_SERIAL_PORT (port);
+ gboolean matches;
+ GMatchInfo *match_info;
+ gchar *str;
+ gint result_len;
+ guint i;
+
+ for (i = 0; i < response->len; i++) {
+ /* If there is any content before the first $,
+ * assume it's garbage, and skip it */
+ if (response->data[i] == '$') {
+ if (i > 0)
+ g_byte_array_remove_range (response, 0, i);
+ /* else, good, we're already started with $ */
+ break;
+ }
+ }
+
+ matches = g_regex_match_full (self->priv->known_traces_regex,
+ (const gchar *) response->data,
+ response->len,
+ 0, 0, &match_info, NULL);
+
+ if (self->priv->callback) {
+ while (g_match_info_matches (match_info)) {
+ gchar *trace;
+
+ trace = g_match_info_fetch (match_info, 0);
+ if (trace) {
+ self->priv->callback (self, trace, self->priv->user_data);
+ g_free (trace);
+ }
+ g_match_info_next (match_info, NULL);
+ }
+ }
+
+ g_match_info_free (match_info);
+
+ if (!matches)
+ return FALSE;
+
+ /* Remove matches */
+ result_len = response->len;
+ str = g_regex_replace_eval (self->priv->known_traces_regex,
+ (const char *) response->data,
+ response->len,
+ 0, 0,
+ remove_eval_cb, &result_len, NULL);
+
+ g_byte_array_remove_range (response, 0, response->len);
+ g_byte_array_append (response, (const guint8 *) str, result_len);
+ g_free (str);
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+static void
+debug_log (MMSerialPort *port, const char *prefix, const char *buf, gsize len)
+{
+ static GString *debug = NULL;
+ const char *s;
+
+ if (!debug)
+ debug = g_string_sized_new (256);
+
+ g_string_append (debug, prefix);
+ g_string_append (debug, " '");
+
+ s = buf;
+ while (len--) {
+ if (g_ascii_isprint (*s))
+ g_string_append_c (debug, *s);
+ else if (*s == '\r')
+ g_string_append (debug, "<CR>");
+ else if (*s == '\n')
+ g_string_append (debug, "<LF>");
+ else
+ g_string_append_printf (debug, "\\%u", (guint8) (*s & 0xFF));
+
+ s++;
+ }
+
+ g_string_append_c (debug, '\'');
+ mm_dbg ("(%s): %s", mm_port_get_device (MM_PORT (port)), debug->str);
+ g_string_truncate (debug, 0);
+}
+
+/*****************************************************************************/
+
+MMGpsSerialPort *
+mm_gps_serial_port_new (const char *name)
+{
+ return MM_GPS_SERIAL_PORT (g_object_new (MM_TYPE_GPS_SERIAL_PORT,
+ MM_PORT_DEVICE, name,
+ MM_PORT_SUBSYS, MM_PORT_SUBSYS_TTY,
+ MM_PORT_TYPE, MM_PORT_TYPE_GPS,
+ NULL));
+}
+
+static void
+mm_gps_serial_port_init (MMGpsSerialPort *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
+ MM_TYPE_GPS_SERIAL_PORT,
+ MMGpsSerialPortPrivate);
+
+ /* We'll assume that all traces start with the dollar sign and end with \r\n */
+ self->priv->known_traces_regex =
+ g_regex_new ("\\$.*\\r\\n",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE,
+ 0,
+ NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+ MMGpsSerialPort *self = MM_GPS_SERIAL_PORT (object);
+
+ if (self->priv->notify)
+ self->priv->notify (self->priv->user_data);
+
+ g_regex_unref (self->priv->known_traces_regex);
+
+ G_OBJECT_CLASS (mm_gps_serial_port_parent_class)->finalize (object);
+}
+
+static void
+mm_gps_serial_port_class_init (MMGpsSerialPortClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMSerialPortClass *port_class = MM_SERIAL_PORT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMGpsSerialPortPrivate));
+
+ /* Virtual methods */
+ object_class->finalize = finalize;
+
+ port_class->parse_response = parse_response;
+ port_class->debug_log = debug_log;
+}
diff --git a/src/mm-gps-serial-port.h b/src/mm-gps-serial-port.h
new file mode 100644
index 00000000..5a7c23b1
--- /dev/null
+++ b/src/mm-gps-serial-port.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2012 - Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#ifndef MM_GPS_SERIAL_PORT_H
+#define MM_GPS_SERIAL_PORT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "mm-serial-port.h"
+
+#define MM_TYPE_GPS_SERIAL_PORT (mm_gps_serial_port_get_type ())
+#define MM_GPS_SERIAL_PORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_GPS_SERIAL_PORT, MMGpsSerialPort))
+#define MM_GPS_SERIAL_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_GPS_SERIAL_PORT, MMGpsSerialPortClass))
+#define MM_IS_GPS_SERIAL_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_GPS_SERIAL_PORT))
+#define MM_IS_GPS_SERIAL_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_GPS_SERIAL_PORT))
+#define MM_GPS_SERIAL_PORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_GPS_SERIAL_PORT, MMGpsSerialPortClass))
+
+typedef struct _MMGpsSerialPort MMGpsSerialPort;
+typedef struct _MMGpsSerialPortClass MMGpsSerialPortClass;
+typedef struct _MMGpsSerialPortPrivate MMGpsSerialPortPrivate;
+
+typedef void (*MMGpsSerialTraceFn) (MMGpsSerialPort *port,
+ const gchar *trace,
+ gpointer user_data);
+
+struct _MMGpsSerialPort {
+ MMSerialPort parent;
+ MMGpsSerialPortPrivate *priv;
+};
+
+struct _MMGpsSerialPortClass {
+ MMSerialPortClass parent;
+};
+
+GType mm_gps_serial_port_get_type (void);
+
+MMGpsSerialPort *mm_gps_serial_port_new (const char *name);
+
+void mm_gps_serial_port_add_trace_handler (MMGpsSerialPort *self,
+ MMGpsSerialTraceFn callback,
+ gpointer user_data,
+ GDestroyNotify notify);
+
+#endif /* MM_GPS_SERIAL_PORT_H */