+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * 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; version 2 of the License.
- *
- * 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.
- */
-
-#include "aoview.h"
-#include <termios.h>
-
-#define AOVIEW_SERIAL_IN_BUF 64
-#define AOVIEW_SERIAL_OUT_BUF 64
-
-struct aoview_buf {
- char *buf;
- int off;
- int count;
- int size;
-};
-
-static int
-aoview_buf_write(struct aoview_buf *buf, char *data, int len)
-{
- if (buf->count + len > buf->size) {
- int new_size = buf->size * 2;
- if (new_size == 0)
- new_size = 1024;
- if (buf->buf)
- buf->buf = realloc (buf->buf, new_size);
- else
- buf->buf = malloc (new_size);
- buf->size = new_size;
- }
- memcpy(buf->buf + buf->count, data, len);
- buf->count += len;
- return len;
-}
-
-static int
-aoview_buf_read(struct aoview_buf *buf, char *data, int len)
-{
- if (len > buf->count - buf->off)
- len = buf->count - buf->off;
- memcpy (data, buf->buf + buf->off, len);
- buf->off += len;
- if (buf->off == buf->count)
- buf->off = buf->count = 0;
- return len;
-}
-
-static int
-aoview_buf_getc(struct aoview_buf *buf)
-{
- char b;
- int r;
-
- r = aoview_buf_read(buf, &b, 1);
- if (r == 1)
- return (int) b;
- return -1;
-}
-
-static void
-aoview_buf_flush(struct aoview_buf *buf, int fd)
-{
- int ret;
-
- if (buf->count > buf->off) {
- ret = write(fd, buf->buf + buf->off, buf->count - buf->off);
- if (ret > 0) {
- buf->off += ret;
- if (buf->off == buf->count)
- buf->off = buf->count = 0;
- }
- }
-}
-
-static void
-aoview_buf_fill(struct aoview_buf *buf, int fd)
-{
- int ret;
-
- while (buf->count >= buf->size) {
- int new_size = buf->size * 2;
- buf->buf = realloc (buf->buf, new_size);
- buf->size = new_size;
- }
-
- ret = read(fd, buf->buf + buf->count, buf->size - buf->count);
- if (ret > 0)
- buf->count += ret;
-}
-
-static void
-aoview_buf_init(struct aoview_buf *buf)
-{
- buf->buf = malloc (buf->size = 1024);
- buf->count = 0;
-}
-
-static void
-aoview_buf_fini(struct aoview_buf *buf)
-{
- free(buf->buf);
-}
-
-struct aoview_serial {
- GSource source;
- int fd;
- struct termios save_termios;
- struct aoview_buf in_buf;
- struct aoview_buf out_buf;
- GPollFD poll_fd;
-};
-
-
-void
-aoview_serial_printf(struct aoview_serial *serial, char *format, ...)
-{
- char buf[1024];
- va_list ap;
- int ret;
-
- /* sprintf to a local buffer */
- va_start(ap, format);
- ret = vsnprintf(buf, sizeof(buf), format, ap);
- va_end(ap);
- if (ret > sizeof(buf)) {
- fprintf(stderr, "printf overflow for format %s\n",
- format);
- }
-
- /* flush local buffer to the wire */
- aoview_buf_write(&serial->out_buf, buf, ret);
- aoview_buf_flush(&serial->out_buf, serial->fd);
-}
-
-int
-aoview_serial_read(struct aoview_serial *serial, char *buf, int len)
-{
- return aoview_buf_read(&serial->in_buf, buf, len);
-}
-
-int
-aoview_serial_getc(struct aoview_serial *serial)
-{
- return aoview_buf_getc(&serial->in_buf);
-}
-
-static gboolean
-serial_prepare(GSource *source, gint *timeout)
-{
- struct aoview_serial *serial = (struct aoview_serial *) source;
- *timeout = -1;
-
- if (serial->out_buf.count)
- serial->poll_fd.events |= G_IO_OUT;
- else
- serial->poll_fd.events &= ~G_IO_OUT;
- return FALSE;
-}
-
-static gboolean
-serial_check(GSource *source)
-{
- struct aoview_serial *serial = (struct aoview_serial *) source;
- gint revents = serial->poll_fd.revents;
-
- if (revents & G_IO_NVAL)
- return FALSE;
- if (revents & G_IO_IN)
- return TRUE;
- if (revents & G_IO_OUT)
- return TRUE;
- return FALSE;
-}
-
-static gboolean
-serial_dispatch(GSource *source,
- GSourceFunc callback,
- gpointer user_data)
-{
- struct aoview_serial *serial = (struct aoview_serial *) source;
- aoview_serial_callback func = (aoview_serial_callback) callback;
- gint revents = serial->poll_fd.revents;
-
- if (revents & G_IO_IN)
- aoview_buf_fill(&serial->in_buf, serial->fd);
-
- if (revents & G_IO_OUT)
- aoview_buf_flush(&serial->out_buf, serial->fd);
-
- if (func)
- (*func)(user_data, serial, revents);
- return TRUE;
-}
-
-static void
-serial_finalize(GSource *source)
-{
- struct aoview_serial *serial = (struct aoview_serial *) source;
-
- aoview_buf_fini(&serial->in_buf);
- aoview_buf_fini(&serial->out_buf);
- tcsetattr(serial->fd, TCSAFLUSH, &serial->save_termios);
- close (serial->fd);
-}
-
-static GSourceFuncs serial_funcs = {
- serial_prepare,
- serial_check,
- serial_dispatch,
- serial_finalize
-};
-
-struct aoview_serial *
-aoview_serial_open(const char *tty)
-{
- struct aoview_serial *serial;
- struct termios termios;
-
- serial = (struct aoview_serial *) g_source_new(&serial_funcs, sizeof (struct aoview_serial));
- aoview_buf_init(&serial->in_buf);
- aoview_buf_init(&serial->out_buf);
- serial->fd = open (tty, O_RDWR | O_NONBLOCK);
- if (serial->fd < 0) {
- g_source_destroy(&serial->source);
- return NULL;
- }
- tcgetattr(serial->fd, &termios);
- serial->save_termios = termios;
- cfmakeraw(&termios);
- tcsetattr(serial->fd, TCSAFLUSH, &termios);
-
- aoview_serial_printf(serial, "E 0\n");
- tcdrain(serial->fd);
- usleep(15*1000);
- tcflush(serial->fd, TCIFLUSH);
- serial->poll_fd.fd = serial->fd;
- serial->poll_fd.events = G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR;
- g_source_attach(&serial->source, NULL);
- g_source_add_poll(&serial->source,&serial->poll_fd);
- aoview_serial_set_callback(serial, NULL);
- return serial;
-}
-
-void
-aoview_serial_close(struct aoview_serial *serial)
-{
- g_source_remove_poll(&serial->source, &serial->poll_fd);
- close(serial->fd);
- g_source_destroy(&serial->source);
-}
-
-void
-aoview_serial_set_callback(struct aoview_serial *serial,
- aoview_serial_callback func)
-{
- g_source_set_callback(&serial->source, (GSourceFunc) func, serial, NULL);
-}