From 36435592ceb7a09b9d9d5d313fc5fd29ab1aa733 Mon Sep 17 00:00:00 2001 From: Philippe Nunes Date: Tue, 23 Oct 2012 18:27:42 +0200 Subject: [PATCH] Better support of glib-IO-Channels 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 | 6 +- src/desc_imc_pr3.c | 232 ++++++++++++++++++++++++++++++++++++----------------- src/util_imc.c | 88 ++++++++++---------- 3 files changed, 202 insertions(+), 124 deletions(-) diff --git a/include/util_imc.h b/include/util_imc.h index b8282e2..1191e25 100644 --- a/include/util_imc.h +++ b/include/util_imc.h @@ -24,10 +24,8 @@ #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); diff --git a/src/desc_imc_pr3.c b/src/desc_imc_pr3.c index b40698d..0998e0c 100644 --- a/src/desc_imc_pr3.c +++ b/src/desc_imc_pr3.c @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -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; } diff --git a/src/util_imc.c b/src/util_imc.c index 3dda67a..3a413a6 100644 --- a/src/util_imc.c +++ b/src/util_imc.c @@ -30,45 +30,44 @@ #include #include +#include + #include #include -#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) -- 2.7.4