beep when GPS ready
[protos/xbee-avr.git] / i2c_protocol.c
1 /*
2  *  Copyright Droids Corporation (2009)
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,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  *  Revision : $Id: i2c_protocol.c,v 1.8 2009-11-08 17:24:33 zer0 Exp $
19  *
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24
25 #include <aversive/pgmspace.h>
26 #include <aversive/wait.h>
27 #include <aversive/error.h>
28
29 #include <callout.h>
30 #include <i2c.h>
31
32 #include "../fpv-common/i2c_commands.h"
33 #include "i2c_protocol.h"
34 #include "beep.h"
35 #include "main.h"
36
37 #define I2C_STATE_MAX 2
38 #define I2C_PERIOD_MS 50
39
40 #define I2C_TIMEOUT 100 /* ms */
41 #define I2C_MAX_ERRORS 40
42
43 static volatile uint8_t i2c_poll_num = 0;
44 static volatile uint8_t i2c_state = 0;
45 static volatile uint8_t i2c_rx_count = 0;
46 static volatile uint8_t i2c_tx_count = 0;
47 static volatile uint16_t i2c_errors = 0;
48
49 static uint8_t gps_ok = 0;
50
51 #define OP_READY 0 /* no i2c op running */
52 #define OP_POLL  1 /* a user command is running */
53 #define OP_CMD   2 /* a polling (req / ans) is running */
54
55 static volatile uint8_t running_op = OP_READY;
56
57 #define I2C_MAX_LOG 3
58 static uint8_t error_log = 0;
59
60 static struct callout i2c_timer;
61
62 static int8_t i2c_req_imuboard_status(void);
63
64 /* latest received imuboard_status */
65 struct i2c_ans_imuboard_status imuboard_status;
66
67 /* used for commands */
68 uint8_t command_buf[I2C_SEND_BUFFER_SIZE];
69 volatile int8_t command_dest=-1;
70 volatile uint8_t command_size=0;
71
72 #define I2C_ERROR(args...) do {                                         \
73                 if (error_log < I2C_MAX_LOG) {                          \
74                         ERROR(E_USER_I2C_PROTO, args);                  \
75                         error_log ++;                                   \
76                         if (error_log == I2C_MAX_LOG) {                 \
77                                 ERROR(E_USER_I2C_PROTO,                 \
78                                       "i2c logs are now warnings");     \
79                         }                                               \
80                 }                                                       \
81                 else                                                    \
82                         WARNING(E_USER_I2C_PROTO, args);                \
83         } while(0)
84
85 void i2c_protocol_debug(void)
86 {
87         printf_P(PSTR("I2C protocol debug infos:\r\n"));
88         printf_P(PSTR("  i2c_send=%d\r\n"), i2c_tx_count);
89         printf_P(PSTR("  i2c_recv=%d\r\n"), i2c_rx_count);
90         printf_P(PSTR("  i2c_state=%d\r\n"), i2c_state);
91         printf_P(PSTR("  i2c_errors=%d\r\n"), i2c_errors);
92         printf_P(PSTR("  running_op=%d\r\n"), running_op);
93         printf_P(PSTR("  command_size=%d\r\n"), command_size);
94         printf_P(PSTR("  command_dest=%d\r\n"), command_dest);
95         printf_P(PSTR("  i2c_status=%x\r\n"), i2c_status());
96 }
97
98 static void i2cproto_next_state(uint8_t inc)
99 {
100         i2c_state += inc;
101         if (i2c_state >= I2C_STATE_MAX) {
102                 i2c_state = 0;
103                 i2c_poll_num ++;
104         }
105 }
106
107 void i2cproto_wait_update(void)
108 {
109         uint8_t poll_num;
110         poll_num = i2c_poll_num;
111         (void)poll_num;
112         //WAIT_COND_OR_TIMEOUT((i2c_poll_num-poll_num) > 1, 150); /* XXX todo */
113 }
114
115 /* called periodically : the goal of this 'thread' is to send requests
116  * and read answers on i2c slaves in the correct order. */
117 static void i2c_poll_slaves(struct callout_mgr *cm, struct callout *tim, void *arg)
118 {
119         uint8_t flags;
120         int8_t err;
121
122         (void)cm;
123         (void)tim;
124         (void)arg;
125
126 #if 0
127         static uint8_t a = 0;
128
129         a++;
130         if (a & 0x4)
131                 LED2_TOGGLE();
132 #endif
133
134         /* already running */
135         IRQ_LOCK(flags);
136         if (running_op != OP_READY) {
137                 IRQ_UNLOCK(flags);
138                 goto reschedule;
139         }
140
141         /* if a command is ready to be sent, so send it */
142         if (command_size) {
143                 running_op = OP_CMD;
144                 err = i2c_send(command_dest, command_buf, command_size,
145                              I2C_CTRL_GENERIC);
146                 if (err < 0)
147                         goto error;
148                 IRQ_UNLOCK(flags);
149                 goto reschedule;
150         }
151
152         /* no command, so do the polling */
153         running_op = OP_POLL;
154
155         switch(i2c_state) {
156
157         /* poll status of imuboard */
158 #define I2C_REQ_IMUBOARD 0
159         case I2C_REQ_IMUBOARD:
160                 if ((err = i2c_req_imuboard_status()))
161                         goto error;
162                 break;
163
164 #define I2C_ANS_IMUBOARD 1
165         case I2C_ANS_IMUBOARD:
166                 if ((err = i2c_recv(I2C_IMUBOARD_ADDR,
167                                     sizeof(struct i2c_ans_imuboard_status),
168                                     I2C_CTRL_GENERIC)))
169                         goto error;
170                 break;
171
172         /* sync with I2C_STATE_MAX */
173
174         /* nothing, go to the first request */
175         default:
176                 i2c_state = 0;
177                 running_op = OP_READY;
178         }
179         IRQ_UNLOCK(flags);
180
181         goto reschedule;
182
183  error:
184         running_op = OP_READY;
185         IRQ_UNLOCK(flags);
186         i2c_errors++;
187         if (i2c_errors > I2C_MAX_ERRORS) {
188                 I2C_ERROR("I2C send is_cmd=%d proto_state=%d "
189                       "err=%d i2c_status=%x", !!command_size, i2c_state, err, i2c_status());
190                 i2c_reset();
191                 i2c_errors = 0;
192         }
193
194  reschedule:
195         /* reschedule */
196         callout_reschedule(cm, tim, I2C_PERIOD_MS);
197 }
198
199 /* called when the xmit is finished */
200 void i2c_sendevent(int8_t size)
201 {
202         if (size > 0) {
203                 if (running_op == OP_POLL) {
204                         i2cproto_next_state(1);
205                 }
206                 else
207                         command_size = 0;
208                 i2c_tx_count++;
209         }
210         else {
211                 i2c_errors++;
212                 NOTICE(E_USER_I2C_PROTO, "send error state=%d size=%d "
213                         "op=%d", i2c_state, size, running_op);
214                 if (i2c_errors > I2C_MAX_ERRORS) {
215                         I2C_ERROR("I2C error, slave not ready");
216                         i2c_reset();
217                         i2c_errors = 0;
218                 }
219
220                 if (running_op == OP_POLL) {
221                         /* skip associated answer */
222                         i2cproto_next_state(2);
223                 }
224         }
225         running_op = OP_READY;
226 }
227
228 /* called rx event */
229 void i2c_recvevent(uint8_t * buf, int8_t size)
230 {
231         if (running_op == OP_POLL)
232                 i2cproto_next_state(1);
233
234         /* recv is only trigged after a poll */
235         running_op = OP_READY;
236
237         if (size < 0) {
238                 goto error;
239         }
240
241         i2c_rx_count++;
242
243         switch (buf[0]) {
244
245         case I2C_ANS_IMUBOARD_STATUS: {
246                 struct i2c_ans_imuboard_status *ans =
247                         (struct i2c_ans_imuboard_status *)buf;
248
249                 if (size != sizeof (*ans))
250                         goto error;
251
252                 /* copy status in a global struct */
253                 memcpy(&imuboard_status, ans, sizeof(imuboard_status));
254
255                 if (gps_ok == 0 &&
256                         (imuboard_status.flags & IMUBOARD_STATUS_GPS_OK)) {
257                         gps_ok = 1;
258                         beep(0, 1, 1);
259                         beep(0, 1, 1);
260                 }
261
262                 break;
263         }
264
265         default:
266                 break;
267         }
268
269         return;
270  error:
271         i2c_errors++;
272         NOTICE(E_USER_I2C_PROTO, "recv error state=%d op=%d",
273                i2c_state, running_op);
274         if (i2c_errors > I2C_MAX_ERRORS) {
275                 I2C_ERROR("I2C error, slave not ready");
276                 i2c_reset();
277                 i2c_errors = 0;
278         }
279 }
280
281 void i2c_recvbyteevent(uint8_t hwstatus, uint8_t i, uint8_t c)
282 {
283         (void)hwstatus;
284         (void)i;
285         (void)c;
286 }
287
288 /* ******** ******** ******** ******** */
289 /* commands */
290 /* ******** ******** ******** ******** */
291
292
293 static int8_t
294 i2c_send_command(uint8_t addr, uint8_t * buf, uint8_t size)
295 {
296         uint8_t flags;
297         uint16_t ms = get_time_ms();
298
299         while ((get_time_ms() - ms) < I2C_TIMEOUT) {
300                 IRQ_LOCK(flags);
301                 if (command_size == 0) {
302                         memcpy(command_buf, buf, size);
303                         command_size = size;
304                         command_dest = addr;
305                         IRQ_UNLOCK(flags);
306                         return 0;
307                 }
308                 IRQ_UNLOCK(flags);
309         }
310         /* this should not happen... except if we are called from an
311          * interrupt context, but it's forbidden */
312         I2C_ERROR("I2C command send failed");
313         return -EBUSY;
314 }
315
316 static int8_t i2c_req_imuboard_status(void)
317 {
318         struct i2c_req_imuboard_status buf;
319         int8_t err;
320
321         buf.hdr.cmd = I2C_REQ_IMUBOARD_STATUS;
322         err = i2c_send(I2C_IMUBOARD_ADDR, (uint8_t*)&buf,
323                         sizeof(buf), I2C_CTRL_GENERIC);
324
325         return err;
326 }
327
328 int8_t i2c_led_control(uint8_t addr, uint8_t led, uint8_t state)
329 {
330         struct i2c_cmd_led_control buf;
331         buf.hdr.cmd = I2C_CMD_GENERIC_LED_CONTROL;
332         buf.led_num = led;
333         buf.state = state;
334         return i2c_send_command(addr, (uint8_t*)&buf, sizeof(buf));
335 }
336
337 void i2c_protocol_init(void)
338 {
339         callout_init(&i2c_timer, i2c_poll_slaves, NULL, I2C_PRIO);
340         callout_schedule(&xbeeboard.intr_cm, &i2c_timer, I2C_PERIOD_MS);
341 }