Logo Search packages:      
Sourcecode: telepathy-blue version File versions

tp-blue-at-controller.c

/*
 *  Copyright (C) 2006, Raphaƫl Slinckx <raphael@slinckx.net>
 *
 *  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, 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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *  $Id$
 */

#include "tp-blue-at-controller.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>

#define TP_BLUE_AT_CONTROLLER_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), TP_BLUE_TYPE_AT_CONTROLLER, TpBlueAtControllerPrivate))

#define BTADDR "00:16:20:80:9D:05"
#define BTCHAN 2

struct _TpBlueAtControllerPrivate
{
      GIOChannel *rfcomm;
};

enum
{
      RESPONSE_RECEIVED,
      ERROR_RECEIVED,
      DISCONNECTED,
      LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };


G_DEFINE_TYPE(TpBlueAtController, tp_blue_at_controller, G_TYPE_OBJECT)

static void tp_blue_at_controller_class_init          (TpBlueAtControllerClass *klass);
static void tp_blue_at_controller_init          (TpBlueAtController *obj);
static void tp_blue_at_controller_finalize            (GObject *object);



static void
tp_blue_at_controller_class_init (TpBlueAtControllerClass *class)
{
      GObjectClass *object_class = G_OBJECT_CLASS (class);
      object_class->finalize = tp_blue_at_controller_finalize;
      

      /* Install properties and signals here */
      signals[RESPONSE_RECEIVED] =
            g_signal_new ("response-received",
                        G_OBJECT_CLASS_TYPE (object_class),
                        G_SIGNAL_RUN_LAST,
                        G_STRUCT_OFFSET (TpBlueAtControllerClass, response_received),
                        NULL, NULL,
                        g_cclosure_marshal_VOID__STRING,
                        G_TYPE_NONE,
                        1,
                        G_TYPE_STRING);
                        
      signals[ERROR_RECEIVED] =
            g_signal_new ("error-received",
                        G_OBJECT_CLASS_TYPE (object_class),
                        G_SIGNAL_RUN_LAST,
                        G_STRUCT_OFFSET (TpBlueAtControllerClass, error_received),
                        NULL, NULL,
                        g_cclosure_marshal_VOID__VOID,
                        G_TYPE_NONE,
                        0);
                        
      signals[DISCONNECTED] =
            g_signal_new ("disconnected",
                        G_OBJECT_CLASS_TYPE (object_class),
                        G_SIGNAL_RUN_LAST,
                        G_STRUCT_OFFSET (TpBlueAtControllerClass, disconnected),
                        NULL, NULL,
                        g_cclosure_marshal_VOID__VOID,
                        G_TYPE_NONE,
                        0);
                        
      g_type_class_add_private (object_class, sizeof (TpBlueAtControllerPrivate));
}


static void
tp_blue_at_controller_finalize (GObject *object)
{
      /*TpBlueAtController *obj = TP_BLUE_AT_CONTROLLER (object);
      TpBlueAtControllerPrivate *priv = obj->priv;*/
      
      G_OBJECT_CLASS (tp_blue_at_controller_parent_class)->finalize (object);
}


TpBlueAtController *
tp_blue_at_controller_new (void)
{
      return TP_BLUE_AT_CONTROLLER (g_object_new (TP_BLUE_TYPE_AT_CONTROLLER, NULL));
}

static GIOStatus
tp_blue_at_controller_write (TpBlueAtController *tbac, gchar *msg)
{
      GIOStatus io_status;
      gsize length;
      GError *err = NULL;

      io_status = g_io_channel_write_chars (tbac->priv->rfcomm, msg, -1, &length, &err);
      if (err != NULL)
      {
            g_message ("Unable Write '%ss': %s", msg, err->message);
            g_error_free (err);
      }
      else
      {
            g_io_channel_flush (tbac->priv->rfcomm, NULL);
            g_message ("Wrote '%s' (%d)", msg, length);
      }
      
      return io_status;
}

static gchar *
tp_blue_at_controller_read_chars (TpBlueAtController *tbac, gsize expect)
{
      GIOStatus io_status;
      gchar read[50];
      gsize length;
      GError *err = NULL;
      
      if (expect+2 >= sizeof(read))
      {
            g_warning ("Message too long to be read: %d", expect);
            return NULL;
      }
            
      /* We expect a string, but have to deal with the \r\r from the command */
      io_status = g_io_channel_read_chars (tbac->priv->rfcomm, read, expect+2, &length, &err);
      if (err != NULL)
      {
            g_message ("Unable Read: %s", err->message);
            g_error_free (err);
            return NULL;
      }
      
      if (length == 0)
            return NULL;
      
      /* Null terminate the answer */
      read[length] = '\0';

      return g_strstrip (g_strdup (read));
}

static gchar *
tp_blue_at_controller_read (TpBlueAtController *tbac)
{
      GIOStatus io_status;
      gchar *read = NULL;
      GError *err = NULL;
      
      while (TRUE)
      {
            g_message ("--Reading line");
            io_status = g_io_channel_read_line (tbac->priv->rfcomm, &read, NULL, NULL, &err);
            if (err != NULL)
            {
                  g_message ("Unable Read: %s", err->message);
                  g_error_free (err);
                  break;
            }
            g_message ("Got line: '%s'", read);
            
            /* String is NULL, then return, nothing more to read */
            if (read == NULL)
                  break;
            
            /* String is empty, then read again */
            read = g_strstrip(read);
            if (strcmp (read, "") == 0)
                  continue;
            
            /* Stripped string ahead, deliver */
            g_message ("Read: '%s'", read);
            return read;
      }
      
      return NULL;
}

static void
tp_blue_at_controller_disable_echo (TpBlueAtController *tbac)
{
      GIOStatus io_status;
      gchar *read;
      
      g_message ("Writing AT");
      io_status = tp_blue_at_controller_write(tbac, "AT\r");
      
      read = tp_blue_at_controller_read (tbac);
      if (strcmp (read, "AT") != 0)
      {
            g_message ("Unexpected reply: expect AT: %s", read);
            g_free (read);
            return;
      }
      g_free (read);
      
      read = tp_blue_at_controller_read (tbac);
      if (strcmp (read, "OK") != 0)
      {
            g_message ("Unexpected reply: expect AT->OK: %s", read);
            g_free (read);
            return;
      }
      g_free (read);
      
      g_message ("Writing ATE0");
      io_status = tp_blue_at_controller_write(tbac, "ATE0\r");
      
      g_message ("Reading echo suppression answer");
      read = tp_blue_at_controller_read (tbac);
      if (strcmp (read, "ATE0") != 0)
      {
            g_message ("Unexpected reply: expect ATE0: %s", read);
            g_free (read);
            return;
      }
      g_free (read);
      
      read = tp_blue_at_controller_read (tbac);
      if (strcmp (read, "OK") != 0)
      {
            g_message ("Unexpected reply: expect ATE0->OK: %s", read);
            g_free (read);
            return;
      }
      g_free (read);
}

gboolean
tp_blue_at_controller_on_readable_data (GIOChannel *source,
                              GIOCondition condition,
                              TpBlueAtController *tbac)
{


      TpBlueAtControllerPrivate *priv;
      GIOStatus status;
      gchar *read;
      gsize length;
      gsize terminator_pos;
      GError *err = NULL;
      
      priv = TP_BLUE_AT_CONTROLLER_GET_PRIVATE (tbac);

      g_message ("Readable data !");
      while (TRUE)
      {
            read = tp_blue_at_controller_read (tbac);
            if (read == NULL)
                  break;
                  
            g_signal_emit_by_name(tbac, "response-received", read);
            g_free (read);
      }
      
      return TRUE;
}

gboolean
tp_blue_at_controller_on_error_data (GIOChannel *source,
                              GIOCondition condition,
                              TpBlueAtController *tbac)
{
      g_message ("Error received!");
      g_signal_emit_by_name (tbac, "error-received");
      tp_blue_at_controller_disconnect (tbac);
      
      return TRUE;
}

static void
tp_blue_at_controller_init (TpBlueAtController *tbac)
{
      tbac->priv = TP_BLUE_AT_CONTROLLER_GET_PRIVATE (tbac);
}

void
tp_blue_at_controller_disconnect (TpBlueAtController *self)
{
      if (self->priv->rfcomm != NULL)
      {
            g_io_channel_shutdown (self->priv->rfcomm, TRUE, NULL);
            g_io_channel_unref (self->priv->rfcomm);
            g_signal_emit_by_name (self, "disconnected");
            self->priv->rfcomm = NULL;
      }
}

gboolean
tp_blue_at_controller_connect (TpBlueAtController *self, gchar *bt_address, guint bt_channel)
{
      struct sockaddr_rc addr = { 0 };
      gint rfcomm_fd;
      
      rfcomm_fd = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
      if (rfcomm_fd < 0)
      {
            g_message ("Unable to create BT socket");
            return FALSE;
      }

      addr.rc_family = AF_BLUETOOTH;
      addr.rc_channel = bt_channel;
      str2ba (bt_address, &addr.rc_bdaddr);

      if (connect(rfcomm_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
      {
            g_message ("Unable to connect BT socket");
            return FALSE;
      }

      g_message ("Opening rfcomm device");
      self->priv->rfcomm = g_io_channel_unix_new (rfcomm_fd);
      g_io_channel_set_encoding (self->priv->rfcomm, "ISO-8859-1", NULL);
      
      tp_blue_at_controller_disable_echo (self);
      
      g_io_channel_set_flags (self->priv->rfcomm, G_IO_FLAG_NONBLOCK, NULL);
      
      g_io_add_watch (self->priv->rfcomm, G_IO_IN|G_IO_PRI , (GIOFunc) tp_blue_at_controller_on_readable_data, self);
      g_io_add_watch (self->priv->rfcomm, G_IO_ERR|G_IO_HUP|G_IO_NVAL , (GIOFunc) tp_blue_at_controller_on_error_data, self);
      
      return TRUE;
}

gboolean
tp_blue_at_controller_send (TpBlueAtController  *tbac, gchar *message, gchar *expect, gboolean readline, gchar **answer)
{
      GIOStatus io_status;
      gchar *read;
      gboolean match = TRUE;
      
      /* Set to blocking mode for this message */
      g_io_channel_set_flags (tbac->priv->rfcomm, 0, NULL);
      if (message != NULL)
      {
            g_message ("Sending Text: %s", message);
            io_status = tp_blue_at_controller_write(tbac, message);
      }
      
      if (readline)
            read = tp_blue_at_controller_read (tbac);
      else
            read = tp_blue_at_controller_read_chars (tbac, strlen(expect));

      if (expect != NULL && strcmp (read, expect) != 0)
      {
            g_message ("Unexpected reply: '%s' expect : '%s'", read, expect);
            match = FALSE;
      }
      
      if (answer != NULL)
            *answer = read;
      else
            g_free (read);
      
      /* Restore non-blocking mode */
      g_io_channel_set_flags (tbac->priv->rfcomm, G_IO_FLAG_NONBLOCK, NULL);
      
      return match;
}

Generated by  Doxygen 1.6.0   Back to index