ao-tools: Fix warnings in ao-tools
[fw/altos] / ao-tools / ao-sky-flash / sky_serial.c
1 /*
2  * Copyright © 2012 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 #define _DEFAULT_SOURCE 1
20 #include <termios.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <poll.h>
26 #include "sky_flash.h"
27 #include <stdio.h>
28 #include <sys/time.h>
29 #include <stdint.h>
30 #include <unistd.h>
31 #include <stdarg.h>
32
33 int     skytraq_verbose = 1;
34
35 int
36 skytraq_setspeed(int fd, int baud)
37 {
38         int     b;
39         int     ret;
40         struct termios  term;
41
42         switch (baud) {
43         case 9600:
44                 b = B9600;
45                 break;
46         case 38400:
47                 b = B38400;
48                 break;
49         case 115200:
50                 b = B115200;
51                 break;
52         default:
53                 fprintf (stderr, "Invalid baudrate %d\n", baud);
54                 return -1;
55         }
56         ret = tcgetattr(fd, &term);
57         cfmakeraw(&term);
58 #ifdef USE_POLL
59         term.c_cc[VMIN] = 1;
60         term.c_cc[VTIME] = 0;
61 #else
62         term.c_cc[VMIN] = 0;
63         term.c_cc[VTIME] = 1;
64 #endif
65
66         cfsetspeed(&term, b);
67
68         ret = tcsetattr(fd, TCSAFLUSH, &term);
69         return ret;
70 }
71
72 int     skytraq_open_time;
73
74 int
75 skytraq_open(const char *path)
76 {
77         int             fd;
78         int             ret;
79
80         fd = open(path, O_RDWR | O_NOCTTY);
81         if (fd < 0) {
82                 perror (path);
83                 return -1;
84         }
85
86         ret = skytraq_setspeed(fd, 9600);
87         if (ret < 0) {
88                 close (fd);
89                 return -1;
90         }
91         skytraq_open_time = skytraq_millis();
92         return fd;
93 }
94
95
96 #define BAUD            57600
97 #define BPS             (BAUD/10 * 9/10)
98 #define US_PER_CHAR     (1000000 / BPS)
99
100 int
101 skytraq_write(int fd, const void *d, int len)
102 {
103         const char *data = d;
104         int             r;
105
106         skytraq_dbg_printf (0, "%4d: ", len);
107         if (len < 70)
108                 skytraq_dbg_buf(0, data, len);
109         while (len) {
110                 int     this_time = len;
111                 if (this_time > 128)
112                         this_time = 128;
113                 skytraq_dbg_printf(0, ".");
114                 fflush(stdout);
115                 r = write(fd, data, this_time);
116                 if (r <= 0)
117                         return r;
118                 usleep(r * US_PER_CHAR);
119                 data += r;
120                 len -= r;
121         }
122         skytraq_dbg_newline();
123         return 1;
124 }
125
126 int
127 skytraq_setcomm(int fd, int baudrate)
128 {
129         uint8_t msg[11];
130         int     i;
131         uint8_t cksum;
132
133         int target_baudrate = 0;
134         switch(baudrate)
135         {
136         case 4800:
137                 target_baudrate=0;
138                 break;
139         case 9600:
140                 target_baudrate=1;
141                 break;
142         case 19200:
143                 target_baudrate=2;
144                 break;
145         case 38400:
146                 target_baudrate=3;
147                 break;
148         case 57600:
149                 target_baudrate=4;
150                 break;
151         case 115200:
152                 target_baudrate=5;
153                 break;
154         case 230400:
155                 target_baudrate=6;
156                 break;
157         }
158         msg[0] = 0xa0;  /* header */
159         msg[1] = 0xa1;
160         msg[2] = 0x00;  /* length */
161         msg[3] = 0x04;
162         msg[4] = 0x05;  /* configure serial port */
163         msg[5] = 0x00;  /* COM 1 */
164         msg[6] = target_baudrate;
165         msg[7] = 0x00;  /* update to SRAM only */
166
167         cksum = 0;
168         for (i = 4; i < 8; i++)
169                 cksum ^= msg[i];
170         msg[8] = cksum;
171         msg[9] = 0x0d;
172         msg[10] = 0x0a;
173         return skytraq_write(fd, msg, 11);
174 }
175
176 int
177 skytraq_waitchar(int fd, int timeout)
178 {
179         struct pollfd   fds[1];
180         int             ret;
181         unsigned char   c;
182
183         for (;;) {
184                 fds[0].fd = fd;
185                 fds[0].events = POLLIN;
186                 ret = poll(fds, 1, timeout);
187                 if (ret >= 1) {
188                         if (fds[0].revents & POLLIN) {
189                                 ret = read(fd, &c, 1);
190                                 if (ret == 1) {
191                                         skytraq_dbg_char(1, c);
192                                         return c;
193                                 }
194                         }
195                 } else if (ret == 0)
196                         return -2;
197                 else {
198                         perror("poll");
199                         return -1;
200                 }
201         }
202 }
203
204 int
205 skytraq_waitstatus(int fd, const char *status, int timeout)
206 {
207         const char      *s;
208         int             c;
209
210         for (;;) {
211                 c = skytraq_waitchar(fd, timeout);
212                 if (c < 0) {
213                         skytraq_dbg_newline();
214                         return c;
215                 }
216                 if ((char) c == *status) {
217                         s = status + 1;
218                         for (;;) {
219                                 c = skytraq_waitchar(fd, timeout);
220                                 if (c < 0) {
221                                         skytraq_dbg_newline();
222                                         return c;
223                                 }
224                                 if ((char) c != *s)
225                                         break;
226                                 if (!*s) {
227                                         skytraq_dbg_newline();
228                                         return 0;
229                                 }
230                                 s++;
231                         }
232                 }
233         }
234 }
235
236 void
237 skytraq_flush(int fd)
238 {
239         while (skytraq_waitchar(fd, 1) >= 0)
240                 ;
241 }
242
243 int
244 skytraq_cmd_wait(int fd, const char *message, int len, const char *status, int timeout)
245 {
246         skytraq_flush(fd);
247         skytraq_write(fd, message, len);
248         return skytraq_waitstatus(fd, status, timeout);
249 }
250
251 int
252 skytraq_cmd_nowait(int fd, const char *message, int len)
253 {
254         skytraq_flush(fd);
255         return skytraq_write(fd, message, len);
256 }