Better support of glib-IO-Channels
authorPhilippe Nunes <philippe.nunes@linux.intel.com>
Tue, 23 Oct 2012 16:27:42 +0000 (18:27 +0200)
committerAuke Kok <auke-jan.h.kok@intel.com>
Fri, 8 Feb 2013 20:25:55 +0000 (12:25 -0800)
The GIOChannel is set in nonblocking mode and the encoding for the
input/output of the channel is set to NULL (safe to use with binary data).
The GIOChannel is  used in a generic manner with the functions
 g_io_channel_read_chars(), g_io_channel_write_chars().

include/util_imc.h
src/desc_imc_pr3.c
src/util_imc.c

index b8282e2..1191e25 100644 (file)
 #ifndef __TTY_IMC_DUMP_H__
 #define __TTY_IMC_DUMP_H__
 
-int tty_open (void);
-
-int fd_read(int nFd, void* buf, size_t nbytes);
-int fd_write(int nFd, void* buf, size_t nbytes);
+size_t channel_read(GIOChannel *channel, void* buf, size_t nbytes);
+size_t channel_write(GIOChannel *channel, void* buf, size_t nbytes);
 
 void util_hex_dump(char *pad, int size, const void *data);
 
index b40698d..0998e0c 100644 (file)
@@ -29,6 +29,7 @@
 #include <net/if.h>
 #include <linux/if_tun.h>
 #include <fcntl.h>
+#include <termios.h>
 
 #include <glib.h>
 
@@ -50,6 +51,8 @@
 
 #define CHANNEL_MAX 8
 
+#define DEVICE_IFX "/dev/ttyIFX0"
+
 #define CHANNEL_MODEM          3
 #define CHANNEL_CALL           1
 #define CHANNEL_SIM            1
@@ -63,7 +66,7 @@
 #define CHANNEL_NONE           -1
 
 struct custom_data {
-       int hal_fd;
+       GIOChannel *channel;
        guint watch_id;
        void *cb;
        void *cb_data;
@@ -91,6 +94,75 @@ static TcoreHal *get_object_hal(const char *obj_name)
        return NULL;
 }
 
+static gboolean setup_channel(GIOChannel *io)
+{
+       GIOFlags io_flags;
+
+       if (g_io_channel_set_encoding(io, NULL, NULL) != G_IO_STATUS_NORMAL)
+               return FALSE;
+
+       g_io_channel_set_buffered(io, FALSE);
+       io_flags = g_io_channel_get_flags(io);
+       io_flags |= (G_IO_FLAG_NONBLOCK & G_IO_FLAG_SET_MASK);
+
+       if (g_io_channel_set_flags(io, io_flags, NULL) != G_IO_STATUS_NORMAL)
+                       return FALSE;
+
+       g_io_channel_set_close_on_unref(io, TRUE);
+
+       return TRUE;
+}
+
+static void set_termio(int fd)
+{
+       struct termios newtio;
+
+       /* Switch TTY to raw mode */
+       memset(&newtio, 0, sizeof(newtio));
+       cfmakeraw(&newtio);
+
+       /* Line is local */
+       newtio.c_cflag |= CLOCAL;
+
+       tcflush(fd, TCIFLUSH);
+       tcsetattr(fd, TCSANOW, &newtio);
+}
+
+static int open_device(const char *tty)
+{
+       int fd;
+
+       fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK);
+       if (fd < 0)
+               return -1;
+
+       set_termio(fd);
+
+       return fd;
+}
+
+static GIOChannel *tty_open(const char *tty)
+{
+       GIOChannel *channel;
+       int fd;
+
+       fd = open_device(tty);
+       if (fd < 0)
+               return NULL;
+
+       dbg("fd =%d ", fd);
+
+       channel = g_io_channel_unix_new(fd);
+       if (channel == NULL) {
+               close(fd);
+               return NULL;
+       }
+
+       setup_channel(channel);
+
+       return channel;
+}
+
 static void on_cmux_init(void *user_data)
 {
        TcoreHal *hal = user_data;
@@ -127,9 +199,9 @@ static void on_response_setupmux(TcorePending *p, int data_len,
 static TReturn hal_power(TcoreHal *hal, gboolean flag,
                                TcoreHalPowerCallBack func, void *user_data)
 {
-       struct custom_data *cdata;
+       struct custom_data *cdata = tcore_hal_ref_user_data(hal);
 
-       cdata = tcore_hal_ref_user_data(hal);
+       dbg("Entry");
 
        /* power on */
        if (flag == TRUE) {
@@ -155,7 +227,7 @@ static TReturn hal_power(TcoreHal *hal, gboolean flag,
                tcore_cmux_close();
 
                g_source_remove(cdata->watch_id);
-               close(cdata->hal_fd);
+               g_io_channel_unref(cdata->channel);
 
                g_free(cdata);
 
@@ -170,24 +242,24 @@ static TReturn hal_power(TcoreHal *hal, gboolean flag,
 
 static TReturn hal_send(TcoreHal *hal, unsigned int data_len, void *data)
 {
-       int ret;
-       struct custom_data *user_data;
+       size_t bytes_written;
+       struct custom_data *cdata;
 
        if (tcore_hal_get_power_state(hal) == FALSE)
                return TCORE_RETURN_FAILURE;
 
-       user_data = tcore_hal_ref_user_data(hal);
-       if (!user_data)
+       cdata = tcore_hal_ref_user_data(hal);
+       if (!cdata)
                return TCORE_RETURN_FAILURE;
 
-       ret = fd_write(user_data->hal_fd, data, data_len);
-       if(ret < 0) {
-               err("fd_write failed");
+       bytes_written = channel_write(cdata->channel, data, data_len);
+       if(bytes_written != data_len) {
+               err("channel_write failed");
 
                return TCORE_RETURN_FAILURE;
        }
 
-       dbg("fd_write success ret=%d (fd=%d, len=%d)", ret, user_data->hal_fd, data_len);
+       dbg("channel_write success (channel=%p, len=%d)", cdata->channel, bytes_written);
 
        return TCORE_RETURN_SUCCESS;
 }
@@ -198,6 +270,8 @@ static TReturn hal_link_object_channel(CoreObject *object)
        TcoreHal *hal;
        TReturn ret;
 
+       dbg("Entry");
+
        hal = get_object_hal(name);
        if (hal == NULL)
                return TCORE_RETURN_EINVAL;
@@ -207,23 +281,20 @@ static TReturn hal_link_object_channel(CoreObject *object)
        return ret;
 }
 
-static guint register_gio_watch(TcoreHal *h, int fd, void *callback)
+static guint register_gio_watch(GIOChannel *channel, void *callback, TcoreHal *h)
 {
-       GIOChannel *channel = NULL;
        guint source;
 
-       if (fd < 0 || !callback)
+       if (channel == NULL || !callback)
                return 0;
 
-       channel = g_io_channel_unix_new(fd);
        source = g_io_add_watch(channel, G_IO_IN, (GIOFunc) callback, h);
        g_io_channel_unref(channel);
-       channel = NULL;
 
        return source;
 }
 
-static int create_tun(const char **interface)
+static GIOChannel *create_tun(const char **interface)
 {
        GIOChannel *channel;
        struct ifreq ifr;
@@ -231,7 +302,7 @@ static int create_tun(const char **interface)
 
        fd = open("/dev/net/tun", O_RDWR);
        if (fd < 0)
-               return fd;
+               return NULL;
 
        memset(&ifr, 0, sizeof(ifr));
        ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
@@ -240,7 +311,7 @@ static int create_tun(const char **interface)
        err = ioctl(fd, TUNSETIFF, (void *) &ifr);
        if (err < 0) {
                close(fd);
-               return -1;
+               return NULL;
        }
 
        *interface = g_strdup(ifr.ifr_name);
@@ -248,10 +319,10 @@ static int create_tun(const char **interface)
        channel = g_io_channel_unix_new(fd);
        if (channel == NULL) {
                close(fd);
-               return -1;
+               return NULL;
        }
 
-       return fd;
+       return channel;
 }
 
 /*
@@ -261,24 +332,21 @@ static int create_tun(const char **interface)
 static gboolean on_recv_data_message(GIOChannel *channel, GIOCondition condition, gpointer data)
 {
        TcoreHal *hal = data;
-       struct custom_data *custom;
-       char buf[BUF_LEN_MAX];
-       int n = 0;
-
-       custom = tcore_hal_ref_user_data(hal);
-       memset(buf, 0, BUF_LEN_MAX);
-       n = fd_read(custom->hal_fd, buf, BUF_LEN_MAX);
-       if (n < 0) {
-               err("fd_read error. return_valute = %d", n);
-               return TRUE;
+       char read_buffer[BUF_LEN_MAX];
+       size_t bytes_read;
+
+       bytes_read = channel_read(channel, read_buffer, BUF_LEN_MAX);
+       if (bytes_read == 0) {
+               err("channel_read error.");
+               return FALSE;
        }
 
        msg("=== TX %s data DUMP =====", tcore_hal_get_name(hal));
-       util_hex_dump("          ", n, buf);
+       util_hex_dump("          ", bytes_read, read_buffer);
        msg("=== TX %s data DUMP =====", tcore_hal_get_name(hal));
 
        /* Send to cmux data channel for encoding */
-       tcore_hal_send_data(hal, n, buf);
+       tcore_hal_send_data(hal, bytes_read, read_buffer);
 
        return TRUE;
 }
@@ -289,21 +357,22 @@ static gboolean on_recv_data_message(GIOChannel *channel, GIOCondition condition
  */
 static void on_hal_recv(TcoreHal *hal, unsigned int data_len, const void *data, void *user_data)
 {
-       int ret;
-       struct custom_data *cdata;
-       cdata = tcore_hal_ref_user_data(hal);
+       struct custom_data *cdata = tcore_hal_ref_user_data(hal);
+       size_t bytes_written;
+
+       dbg("Entry");
 
        if (!cdata) {
                err("hal user data is NULL");
                return;
        }
 
-       ret = fd_write(cdata->hal_fd, (void *)data, data_len);
-       if(ret < 0)
-               err("fd_write failed");
+       bytes_written = channel_write(cdata->channel, (void *)data, data_len);
+       if(bytes_written != data_len)
+               err("channel_write failed");
 
        msg("=== RX %s data DUMP =====", tcore_hal_get_name(hal));
-       util_hex_dump("          ", data_len, data);
+       util_hex_dump("          ", bytes_written, data);
        msg("=== RX %s data DUMP =====", tcore_hal_get_name(hal));
 }
 
@@ -316,13 +385,13 @@ static void on_response_setup_pdp(TcorePending *p, int data_len, const void *dat
        CoreObject *co = tcore_pending_ref_core_object(p);
        TcoreHalSetupPDPCallBack func = (TcoreHalSetupPDPCallBack)cdata->cb;
 
-       dbg("Entered");
+       dbg("Entry");
 
        if (resp->success) {
                dbg("Response Ok");
 
-               cdata->hal_fd = create_tun(&interface);
-               if (cdata->hal_fd < 0) {
+               cdata->channel = create_tun(&interface);
+               if (cdata->channel == NULL) {
                        func(co, NULL, cdata->cb_data);
 
                        g_free(cdata);
@@ -331,9 +400,11 @@ static void on_response_setup_pdp(TcorePending *p, int data_len, const void *dat
                        return;
                }
 
+               setup_channel(cdata->channel);
+
                dbg("interface: %s", interface);
 
-               cdata->watch_id= register_gio_watch(hal, cdata->hal_fd, on_recv_data_message);
+               cdata->watch_id= register_gio_watch(cdata->channel, on_recv_data_message, hal);
                tcore_hal_set_mode(hal, TCORE_HAL_MODE_DATA);
                tcore_hal_add_recv_callback(hal, on_hal_recv, NULL);
 
@@ -358,7 +429,7 @@ static TReturn hal_setup_pdp(CoreObject *co, TcoreHalSetupPDPCallBack func,
        char *cmd_str = NULL;
        struct custom_data *cdata;
 
-       dbg("entry");
+       dbg("Entry");
 
        if (cid == 1)
                hal = tcore_cmux_get_hal_channel(CHANNEL_DATA_1);
@@ -378,19 +449,17 @@ static TReturn hal_setup_pdp(CoreObject *co, TcoreHalSetupPDPCallBack func,
        if (tcore_hal_get_mode(hal) == TCORE_HAL_MODE_DATA) {
                cdata = tcore_hal_ref_user_data(hal);
 
-               if (cdata->hal_fd) {
-                       close(cdata->hal_fd);
-                       cdata->hal_fd = -1;
-               }
+               if (cdata->channel) {
+                       g_source_remove(cdata->watch_id);
+                       g_io_channel_unref(cdata->channel);
 
-               g_source_remove(cdata->watch_id);
-               g_free(cdata);
-               cdata = NULL;
+                       g_free(cdata);
+                       cdata = NULL;
+               }
 
                dbg("Set MODE_AT");
                tcore_hal_set_mode(hal, TCORE_HAL_MODE_AT);
-               dbg("Remove old reveice cb");
+               dbg("Remove old receive cb");
                tcore_hal_remove_recv_callback(hal, on_hal_recv);
         }
 
@@ -430,22 +499,21 @@ static struct tcore_hal_operations hops =
 static gboolean on_recv_tty_message(GIOChannel *channel, GIOCondition condition, gpointer data)
 {
        TcoreHal *hal = data;
-       struct custom_data *custom;
-       char buf[BUF_LEN_MAX];
-       int n = 0;
-
-       custom = tcore_hal_ref_user_data(hal);
-       memset(buf, 0, BUF_LEN_MAX);
-       n = fd_read(custom->hal_fd, buf, BUF_LEN_MAX);
-       if (n < 0) {
-               err("fd_read error. return_valute = %d", n);
-               return TRUE;
+       char read_buffer[BUF_LEN_MAX];
+       size_t bytes_read;
+
+       dbg("Entry");
+
+       bytes_read = channel_read(channel, read_buffer, BUF_LEN_MAX);
+       if (bytes_read == 0) {
+               err("channel_read error.");
+               return FALSE;
        }
 
-       dbg("tty recv (ret = %d)", n);
-       tcore_hal_emit_recv_callback(hal, n, buf);
+       dbg("bytes_read = %d", bytes_read);
+       tcore_hal_emit_recv_callback(hal, bytes_read, read_buffer);
 
-       tcore_hal_dispatch_response_data(hal, 0, n, buf);
+       tcore_hal_dispatch_response_data(hal, 0, bytes_read, read_buffer);
 
        return TRUE;
 }
@@ -470,24 +538,40 @@ static gboolean on_init(TcorePlugin *plugin)
        /* Phonet init */
        data = g_new0(struct custom_data, 1);
 
-       data->hal_fd = tty_open();
-       if (data->hal_fd < 0) {
+       data->channel = tty_open(DEVICE_IFX);
+       if (data->channel == NULL) {
+               err("Failed to open tty port - [%s]", strerror(errno));
                g_free(data);
                return FALSE;
        }
 
+       dbg("tty port (%s) opened successfully", DEVICE_IFX);
+
        /* HAL init */
        hal = tcore_hal_new(plugin, "imc-pr3", &hops, TCORE_HAL_MODE_AT);
-       tcore_hal_link_user_data(hal, data);
+       if (hal == NULL){
+               err("Failed to create HAL");
+               g_free(data);
+               return FALSE;
+       }
+
+       data->watch_id = register_gio_watch(data->channel, on_recv_tty_message, hal);
 
-       data->watch_id= register_gio_watch(hal, data->hal_fd, on_recv_tty_message);
+       if (data->watch_id == 0){
+               err("Failed to register gio watch ");
+               free(data);
+               tcore_hal_free(hal);
+               g_io_channel_unref(data->channel);
+               return FALSE;
+       }
 
-       dbg("hal_fd = %d, watch_id=%d ", data->hal_fd, data->watch_id);
+       tcore_hal_link_user_data(hal, data);
+
+       dbg("HAL is imc-pr3: channel = %p, watch_id=%d ", data->channel, data->watch_id);
 
        if (pr3_audio_init() != TRUE)
                err("Error in audio initialization")
 
-
        return TRUE;
 }
 
index 3dda67a..3a413a6 100644 (file)
 #include <unistd.h>
 #include <fcntl.h>
 
+#include <glib.h>
+
 #include <log.h>
 #include <util_imc.h>
 
-#define TTY_OPEN_PATH "/dev/ttyIFX0"
+#define MAX_READ_ATTEMPTS      4
+#define MAX_WRITE_ATTEMPTS     10
 
-int tty_open(void)
+/* Read data from a GIOChannel */
+size_t channel_read(GIOChannel *channel, void* buf, size_t nbytes)
 {
-       int fd = -1;
-
-       dbg("Function Enter");
+       GIOStatus status;
+       size_t rbytes;
+       size_t toread = nbytes;
+       size_t bytes_read = 0;
+       unsigned int read_count = 0;
 
-       fd = open(TTY_OPEN_PATH, O_RDWR);
-
-       if (fd < 0) {
-               err("Failed to open tty port %x", errno);
+       do {
+               rbytes = 0;
 
-               return -1;
-       } else
-               dbg("tty port opened successfully. fd:%d, path:%s",
-                       fd, TTY_OPEN_PATH);
+               status = g_io_channel_read_chars(channel, buf, toread, &rbytes, NULL);
 
-       return fd;
+               read_count++;
 
-}
+               err("g_io_channel_read_chars.. status[%d] rbytes =%d read_count = %d", status, rbytes, read_count);
 
-int fd_read(int nFd, void* buf, size_t nbytes)
-{
-       int actual = 0;
+               bytes_read += rbytes;
+               toread -= rbytes;
 
-       dbg("Function Enter");
+               if (rbytes > 0)
+                       buf+=rbytes;
 
-       actual = read(nFd, buf, nbytes);
-       if (actual < 0) {
-               dbg("fd_read failed.");
+               if (toread == 0)
+                       break;
 
-               return actual;
-       }
+       } while (status == G_IO_STATUS_NORMAL && rbytes > 0 && read_count < MAX_READ_ATTEMPTS);
 
-       return actual;
+       return bytes_read;
 }
 
 static void __selectsleep(int sec,int msec)
@@ -83,24 +82,23 @@ static void __selectsleep(int sec,int msec)
        return;
 }
 
-/* Write data to imc tty port */
-int fd_write(int nFd, void* buf, size_t nbytes)
+/* Write data to a GIOChannel */
+size_t channel_write(GIOChannel *channel, void* buf, size_t nbytes)
 {
-       int ret;
-       size_t actual = 0;
-       int retry = 0;
+       GIOStatus status;
+       size_t tbytes = 0;
+       size_t bytes_written = 0;
+       unsigned int retry = 0;
 
        do {
-               ret = write(nFd, (unsigned char* )buf, nbytes - actual);
+               status = g_io_channel_write_chars(channel, (const gchar*)buf, nbytes - bytes_written, &tbytes, NULL);
 
-               if ((ret < 0 && errno == EAGAIN) ||
-                               (ret < 0 && errno == EBUSY)) {
-                       err("write failed. retry.. ret[%d] with errno[%d]",
-                               ret, errno);
+               if (status == G_IO_STATUS_AGAIN) {
+                       err("write failed. Retry.. status[%d] Nb attempt[%d]", status, retry);
 
                        __selectsleep(0,50);
 
-                       if (retry == 10)
+                       if (retry == MAX_WRITE_ATTEMPTS)
                                return 0;
 
                        retry = retry + 1;
@@ -108,21 +106,19 @@ int fd_write(int nFd, void* buf, size_t nbytes)
                        continue;
                }
 
-               if (ret < 0) {
-                   if (actual != nbytes)
-                               err("write failed.ret[%d]",ret);
-
-                       err("errno [%d]",errno);
+               if (status != G_IO_STATUS_NORMAL) {
+                       if (bytes_written != nbytes)
+                               err("write failed. status[%d] with errno[%d]", status, errno);
 
-                       return actual;
+                       return bytes_written;
                }
 
-               actual += ret;
-               buf += ret;
+               bytes_written += tbytes;
+               buf += tbytes;
 
-       } while (actual < nbytes);
+       } while (bytes_written < nbytes);
 
-       return actual;
+       return bytes_written;
 }
 
 void util_hex_dump(char *pad, int size, const void *data)