Merge branch 'micropeak-1.1'
[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; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #define _BSD_SOURCE
19 #include <termios.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <poll.h>
25 #include "sky_flash.h"
26 #include <stdio.h>
27 #include <sys/time.h>
28 #include <stdint.h>
29 #include <unistd.h>
30 #include <stdarg.h>
31
32 int     skytraq_verbose = 1;
33
34 int
35 skytraq_setspeed(int fd, int baud)
36 {
37         int     b;
38         int     ret;
39         struct termios  term;
40
41         switch (baud) {
42         case 9600:
43                 b = B9600;
44                 break;
45         case 38400:
46                 b = B38400;
47                 break;
48         case 115200:
49                 b = B115200;
50                 break;
51         default:
52                 fprintf (stderr, "Invalid baudrate %d\n", baud);
53                 return -1;
54         }
55         ret = tcgetattr(fd, &term);
56         cfmakeraw(&term);
57 #ifdef USE_POLL
58         term.c_cc[VMIN] = 1;
59         term.c_cc[VTIME] = 0;
60 #else
61         term.c_cc[VMIN] = 0;
62         term.c_cc[VTIME] = 1;
63 #endif
64
65         cfsetspeed(&term, b);
66
67         ret = tcsetattr(fd, TCSAFLUSH, &term);
68         return ret;
69 }
70
71 int     skytraq_open_time;
72
73 int
74 skytraq_open(const char *path)
75 {
76         int             fd;
77         int             ret;
78
79         fd = open(path, O_RDWR | O_NOCTTY);
80         if (fd < 0) {
81                 perror (path);
82                 return -1;
83         }
84
85         ret = skytraq_setspeed(fd, 9600);
86         if (ret < 0) {
87                 close (fd);
88                 return -1;
89         }
90         skytraq_open_time = skytraq_millis();
91         return fd;
92 }
93
94
95 #define BAUD            57600
96 #define BPS             (BAUD/10 * 9/10)
97 #define US_PER_CHAR     (1000000 / BPS)
98
99 int
100 skytraq_write(int fd, const char *data, int len)
101 {
102         const char *d = data;
103         int             r;
104         int             us;
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                 us = r * US_PER_CHAR;
119                 usleep(r * US_PER_CHAR);
120                 data += r;
121                 len -= r;
122         }
123         skytraq_dbg_newline();
124         return 1;
125 }
126
127 int
128 skytraq_setcomm(int fd, int baudrate)
129 {
130         uint8_t msg[11];
131         int     i;
132         uint8_t cksum;
133
134         int target_baudrate;
135         switch(baudrate)
136         {
137         case 4800:
138                 target_baudrate=0;
139                 break;
140         case 9600:
141                 target_baudrate=1;
142                 break;
143         case 19200:
144                 target_baudrate=2;
145                 break;
146         case 38400:
147                 target_baudrate=3;
148                 break;
149         case 57600:
150                 target_baudrate=4;
151                 break;
152         case 115200:
153                 target_baudrate=5;
154                 break;
155         case 230400:
156                 target_baudrate=6;
157                 break;
158         }
159         msg[0] = 0xa0;  /* header */
160         msg[1] = 0xa1;
161         msg[2] = 0x00;  /* length */
162         msg[3] = 0x04;
163         msg[4] = 0x05;  /* configure serial port */
164         msg[5] = 0x00;  /* COM 1 */
165         msg[6] = target_baudrate;
166         msg[7] = 0x00;  /* update to SRAM only */
167
168         cksum = 0;
169         for (i = 4; i < 8; i++)
170                 cksum ^= msg[i];
171         msg[8] = cksum;
172         msg[9] = 0x0d;
173         msg[10] = 0x0a;
174         return skytraq_write(fd, msg, 11);
175 }
176
177 int
178 skytraq_waitchar(int fd, int timeout)
179 {
180         struct pollfd   fds[1];
181         int             ret;
182         unsigned char   c;
183
184         for (;;) {
185                 fds[0].fd = fd;
186                 fds[0].events = POLLIN;
187                 ret = poll(fds, 1, timeout);
188                 if (ret >= 1) {
189                         if (fds[0].revents & POLLIN) {
190                                 ret = read(fd, &c, 1);
191                                 if (ret == 1) {
192                                         skytraq_dbg_char(1, c);
193                                         return c;
194                                 }
195                         }
196                 } else if (ret == 0)
197                         return -2;
198                 else {
199                         perror("poll");
200                         return -1;
201                 }
202         }
203 }
204
205 int
206 skytraq_waitstatus(int fd, const char *status, int timeout)
207 {
208         const char      *s;
209         int             c;
210
211         for (;;) {
212                 c = skytraq_waitchar(fd, timeout);
213                 if (c < 0) {
214                         skytraq_dbg_newline();
215                         return c;
216                 }
217                 if ((char) c == *status) {
218                         s = status + 1;
219                         for (;;) {
220                                 c = skytraq_waitchar(fd, timeout);
221                                 if (c < 0) {
222                                         skytraq_dbg_newline();
223                                         return c;
224                                 }
225                                 if ((char) c != *s)
226                                         break;
227                                 if (!*s) {
228                                         skytraq_dbg_newline();
229                                         return 0;
230                                 }
231                                 s++;
232                         }
233                 }
234         }
235 }
236
237 void
238 skytraq_flush(int fd)
239 {
240         while (skytraq_waitchar(fd, 1) >= 0)
241                 ;
242 }
243
244 int
245 skytraq_cmd_wait(int fd, const char *message, int len, const char *status, int timeout)
246 {
247         skytraq_flush(fd);
248         skytraq_write(fd, message, len);
249         return skytraq_waitstatus(fd, status, timeout);
250 }
251
252 int
253 skytraq_cmd_nowait(int fd, const char *message, int len)
254 {
255         skytraq_flush(fd);
256         return skytraq_write(fd, message, len);
257 }