altos: Remove unused ao_adc_get from ao_adc_stm.c
[fw/altos] / ao-tools / ao-view / aoview_serial.c
1 /*
2  * Copyright © 2009 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include "aoview.h"
20 #include <termios.h>
21
22 #define AOVIEW_SERIAL_IN_BUF    64
23 #define AOVIEW_SERIAL_OUT_BUF   64
24
25 struct aoview_buf {
26         char            *buf;
27         int             off;
28         int             count;
29         int             size;
30 };
31
32 static int
33 aoview_buf_write(struct aoview_buf *buf, char *data, int len)
34 {
35         if (buf->count + len > buf->size) {
36                 int     new_size = buf->size * 2;
37                 if (new_size == 0)
38                         new_size = 1024;
39                 if (buf->buf)
40                         buf->buf = realloc (buf->buf, new_size);
41                 else
42                         buf->buf = malloc (new_size);
43                 buf->size = new_size;
44         }
45         memcpy(buf->buf + buf->count, data, len);
46         buf->count += len;
47         return len;
48 }
49
50 static int
51 aoview_buf_read(struct aoview_buf *buf, char *data, int len)
52 {
53         if (len > buf->count - buf->off)
54                 len = buf->count - buf->off;
55         memcpy (data, buf->buf + buf->off, len);
56         buf->off += len;
57         if (buf->off == buf->count)
58                 buf->off = buf->count = 0;
59         return len;
60 }
61
62 static int
63 aoview_buf_getc(struct aoview_buf *buf)
64 {
65         char    b;
66         int     r;
67
68         r = aoview_buf_read(buf, &b, 1);
69         if (r == 1)
70                 return (int) b;
71         return -1;
72 }
73
74 static void
75 aoview_buf_flush(struct aoview_buf *buf, int fd)
76 {
77         int     ret;
78
79         if (buf->count > buf->off) {
80                 ret = write(fd, buf->buf + buf->off, buf->count - buf->off);
81                 if (ret > 0) {
82                         buf->off += ret;
83                         if (buf->off == buf->count)
84                                 buf->off = buf->count = 0;
85                 }
86         }
87 }
88
89 static void
90 aoview_buf_fill(struct aoview_buf *buf, int fd)
91 {
92         int ret;
93
94         while (buf->count >= buf->size) {
95                 int new_size = buf->size * 2;
96                 buf->buf = realloc (buf->buf, new_size);
97                 buf->size = new_size;
98         }
99
100         ret = read(fd, buf->buf + buf->count, buf->size - buf->count);
101         if (ret > 0)
102                 buf->count += ret;
103 }
104
105 static void
106 aoview_buf_init(struct aoview_buf *buf)
107 {
108         buf->buf = malloc (buf->size = 1024);
109         buf->count = 0;
110 }
111
112 static void
113 aoview_buf_fini(struct aoview_buf *buf)
114 {
115         free(buf->buf);
116 }
117
118 struct aoview_serial {
119         GSource                 source;
120         int                     fd;
121         struct termios          save_termios;
122         struct aoview_buf       in_buf;
123         struct aoview_buf       out_buf;
124         GPollFD                 poll_fd;
125 };
126
127
128 void
129 aoview_serial_printf(struct aoview_serial *serial, char *format, ...)
130 {
131         char    buf[1024];
132         va_list ap;
133         int     ret;
134
135         /* sprintf to a local buffer */
136         va_start(ap, format);
137         ret = vsnprintf(buf, sizeof(buf), format, ap);
138         va_end(ap);
139         if (ret > sizeof(buf)) {
140                 fprintf(stderr, "printf overflow for format %s\n",
141                         format);
142         }
143
144         /* flush local buffer to the wire */
145         aoview_buf_write(&serial->out_buf, buf, ret);
146         aoview_buf_flush(&serial->out_buf, serial->fd);
147 }
148
149 int
150 aoview_serial_read(struct aoview_serial *serial, char *buf, int len)
151 {
152         return aoview_buf_read(&serial->in_buf, buf, len);
153 }
154
155 int
156 aoview_serial_getc(struct aoview_serial *serial)
157 {
158         return aoview_buf_getc(&serial->in_buf);
159 }
160
161 static gboolean
162 serial_prepare(GSource *source, gint *timeout)
163 {
164         struct aoview_serial *serial = (struct aoview_serial *) source;
165         *timeout = -1;
166
167         if (serial->out_buf.count)
168                 serial->poll_fd.events |= G_IO_OUT;
169         else
170                 serial->poll_fd.events &= ~G_IO_OUT;
171         return FALSE;
172 }
173
174 static gboolean
175 serial_check(GSource *source)
176 {
177         struct aoview_serial *serial = (struct aoview_serial *) source;
178         gint revents = serial->poll_fd.revents;
179
180         if (revents & G_IO_NVAL)
181                 return FALSE;
182         if (revents & G_IO_IN)
183                 return TRUE;
184         if (revents & G_IO_OUT)
185                 return TRUE;
186         return FALSE;
187 }
188
189 static gboolean
190 serial_dispatch(GSource *source,
191                 GSourceFunc callback,
192                 gpointer user_data)
193 {
194         struct aoview_serial *serial = (struct aoview_serial *) source;
195         aoview_serial_callback func = (aoview_serial_callback) callback;
196         gint revents = serial->poll_fd.revents;
197
198         if (revents & G_IO_IN)
199                 aoview_buf_fill(&serial->in_buf, serial->fd);
200
201         if (revents & G_IO_OUT)
202                 aoview_buf_flush(&serial->out_buf, serial->fd);
203
204         if (func)
205                 (*func)(user_data, serial, revents);
206         return TRUE;
207 }
208
209 static void
210 serial_finalize(GSource *source)
211 {
212         struct aoview_serial *serial = (struct aoview_serial *) source;
213
214         aoview_buf_fini(&serial->in_buf);
215         aoview_buf_fini(&serial->out_buf);
216         tcsetattr(serial->fd, TCSAFLUSH, &serial->save_termios);
217         close (serial->fd);
218 }
219
220 static GSourceFuncs serial_funcs = {
221         serial_prepare,
222         serial_check,
223         serial_dispatch,
224         serial_finalize
225 };
226
227 struct aoview_serial *
228 aoview_serial_open(const char *tty)
229 {
230         struct aoview_serial    *serial;
231         struct termios  termios;
232
233         serial = (struct aoview_serial *) g_source_new(&serial_funcs, sizeof (struct aoview_serial));
234         aoview_buf_init(&serial->in_buf);
235         aoview_buf_init(&serial->out_buf);
236         serial->fd = open (tty, O_RDWR | O_NONBLOCK);
237         if (serial->fd < 0) {
238                 g_source_destroy(&serial->source);
239                 return NULL;
240         }
241         tcgetattr(serial->fd, &termios);
242         serial->save_termios = termios;
243         cfmakeraw(&termios);
244         tcsetattr(serial->fd, TCSAFLUSH, &termios);
245
246         aoview_serial_printf(serial, "E 0\n");
247         tcdrain(serial->fd);
248         usleep(15*1000);
249         tcflush(serial->fd, TCIFLUSH);
250         serial->poll_fd.fd = serial->fd;
251         serial->poll_fd.events = G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR;
252         g_source_attach(&serial->source, NULL);
253         g_source_add_poll(&serial->source,&serial->poll_fd);
254         aoview_serial_set_callback(serial, NULL);
255         return serial;
256 }
257
258 void
259 aoview_serial_close(struct aoview_serial *serial)
260 {
261         g_source_remove_poll(&serial->source, &serial->poll_fd);
262         close(serial->fd);
263         g_source_destroy(&serial->source);
264 }
265
266 void
267 aoview_serial_set_callback(struct aoview_serial *serial,
268                            aoview_serial_callback func)
269 {
270         g_source_set_callback(&serial->source, (GSourceFunc) func, serial, NULL);
271 }