94b0b156502149e171f041258e50de764cc733ae
[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 _BSD_SOURCE
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 char *data, int len)
102 {
103         const char *d = data;
104         int             r;
105         int             us;
106
107         skytraq_dbg_printf (0, "%4d: ", len);
108         if (len < 70)
109                 skytraq_dbg_buf(0, data, len);
110         while (len) {
111                 int     this_time = len;
112                 if (this_time > 128)
113                         this_time = 128;
114                 skytraq_dbg_printf(0, ".");
115                 fflush(stdout);
116                 r = write(fd, data, this_time);
117                 if (r <= 0)
118                         return r;
119                 us = r * US_PER_CHAR;
120                 usleep(r * US_PER_CHAR);
121                 data += r;
122                 len -= r;
123         }
124         skytraq_dbg_newline();
125         return 1;
126 }
127
128 int
129 skytraq_setcomm(int fd, int baudrate)
130 {
131         uint8_t msg[11];
132         int     i;
133         uint8_t cksum;
134
135         int target_baudrate;
136         switch(baudrate)
137         {
138         case 4800:
139                 target_baudrate=0;
140                 break;
141         case 9600:
142                 target_baudrate=1;
143                 break;
144         case 19200:
145                 target_baudrate=2;
146                 break;
147         case 38400:
148                 target_baudrate=3;
149                 break;
150         case 57600:
151                 target_baudrate=4;
152                 break;
153         case 115200:
154                 target_baudrate=5;
155                 break;
156         case 230400:
157                 target_baudrate=6;
158                 break;
159         }
160         msg[0] = 0xa0;  /* header */
161         msg[1] = 0xa1;
162         msg[2] = 0x00;  /* length */
163         msg[3] = 0x04;
164         msg[4] = 0x05;  /* configure serial port */
165         msg[5] = 0x00;  /* COM 1 */
166         msg[6] = target_baudrate;
167         msg[7] = 0x00;  /* update to SRAM only */
168
169         cksum = 0;
170         for (i = 4; i < 8; i++)
171                 cksum ^= msg[i];
172         msg[8] = cksum;
173         msg[9] = 0x0d;
174         msg[10] = 0x0a;
175         return skytraq_write(fd, msg, 11);
176 }
177
178 int
179 skytraq_waitchar(int fd, int timeout)
180 {
181         struct pollfd   fds[1];
182         int             ret;
183         unsigned char   c;
184
185         for (;;) {
186                 fds[0].fd = fd;
187                 fds[0].events = POLLIN;
188                 ret = poll(fds, 1, timeout);
189                 if (ret >= 1) {
190                         if (fds[0].revents & POLLIN) {
191                                 ret = read(fd, &c, 1);
192                                 if (ret == 1) {
193                                         skytraq_dbg_char(1, c);
194                                         return c;
195                                 }
196                         }
197                 } else if (ret == 0)
198                         return -2;
199                 else {
200                         perror("poll");
201                         return -1;
202                 }
203         }
204 }
205
206 int
207 skytraq_waitstatus(int fd, const char *status, int timeout)
208 {
209         const char      *s;
210         int             c;
211
212         for (;;) {
213                 c = skytraq_waitchar(fd, timeout);
214                 if (c < 0) {
215                         skytraq_dbg_newline();
216                         return c;
217                 }
218                 if ((char) c == *status) {
219                         s = status + 1;
220                         for (;;) {
221                                 c = skytraq_waitchar(fd, timeout);
222                                 if (c < 0) {
223                                         skytraq_dbg_newline();
224                                         return c;
225                                 }
226                                 if ((char) c != *s)
227                                         break;
228                                 if (!*s) {
229                                         skytraq_dbg_newline();
230                                         return 0;
231                                 }
232                                 s++;
233                         }
234                 }
235         }
236 }
237
238 void
239 skytraq_flush(int fd)
240 {
241         while (skytraq_waitchar(fd, 1) >= 0)
242                 ;
243 }
244
245 int
246 skytraq_cmd_wait(int fd, const char *message, int len, const char *status, int timeout)
247 {
248         skytraq_flush(fd);
249         skytraq_write(fd, message, len);
250         return skytraq_waitstatus(fd, status, timeout);
251 }
252
253 int
254 skytraq_cmd_nowait(int fd, const char *message, int len)
255 {
256         skytraq_flush(fd);
257         return skytraq_write(fd, message, len);
258 }