strat db + avoid
[aversive.git] / projects / microb2010 / mainboard / 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 <ax12.h>
30 #include <uart.h>
31 #include <pwm_ng.h>
32 #include <i2c.h>
33 #include <clock_time.h>
34
35 #include <pid.h>
36 #include <quadramp.h>
37 #include <control_system_manager.h>
38 #include <trajectory_manager.h>
39 #include <vect_base.h>
40 #include <lines.h>
41 #include <polygon.h>
42 #include <obstacle_avoidance.h>
43 #include <blocking_detection_manager.h>
44 #include <robot_system.h>
45 #include <position_manager.h>
46
47 #include <rdline.h>
48 #include <parse.h>
49 #include <parse_string.h>
50 #include <parse_num.h>
51
52 #include "../common/i2c_commands.h"
53 #include "main.h"
54 #include "sensor.h"
55 #include "i2c_protocol.h"
56 #ifdef HOST_VERSION
57 #include "robotsim.h"
58 #endif
59
60 #define I2C_STATE_MAX 4
61
62 #define I2C_TIMEOUT 100 /* ms */
63 #define I2C_MAX_ERRORS 40
64
65 static volatile uint8_t i2c_poll_num = 0;
66 static volatile uint8_t i2c_state = 0;
67 static volatile uint16_t i2c_errors = 0;
68
69 #define OP_READY 0 /* no i2c op running */
70 #define OP_POLL  1 /* a user command is running */
71 #define OP_CMD   2 /* a polling (req / ans) is running */
72
73 static volatile uint8_t running_op = OP_READY;
74
75 #define I2C_MAX_LOG 3
76 #ifndef HOST_VERSION
77 static uint8_t error_log = 0;
78
79 static int8_t i2c_req_cobboard_status(void);
80 static int8_t i2c_req_ballboard_status(void);
81
82 #endif
83
84 /* used for commands */
85 uint8_t command_buf[I2C_SEND_BUFFER_SIZE];
86 volatile int8_t command_dest=-1;
87 volatile uint8_t command_size=0;
88
89 #define I2C_ERROR(args...) do {                                         \
90                 if (error_log < I2C_MAX_LOG) {                          \
91                         ERROR(E_USER_I2C_PROTO, args);                  \
92                         error_log ++;                                   \
93                         if (error_log == I2C_MAX_LOG) {                 \
94                                 ERROR(E_USER_I2C_PROTO,                 \
95                                       "i2c logs are now warnings");     \
96                         }                                               \
97                 }                                                       \
98                 else                                                    \
99                         WARNING(E_USER_I2C_PROTO, args);                \
100         } while(0)
101
102 void i2c_protocol_init(void)
103 {
104 }
105
106 void i2c_protocol_debug(void)
107 {
108 #ifdef HOST_VERSION
109         return;
110 #else
111         printf_P(PSTR("I2C protocol debug infos:\r\n"));
112         printf_P(PSTR("  i2c_state=%d\r\n"), i2c_state);
113         printf_P(PSTR("  i2c_errors=%d\r\n"), i2c_errors);
114         printf_P(PSTR("  running_op=%d\r\n"), running_op);
115         printf_P(PSTR("  command_size=%d\r\n"), command_size);
116         printf_P(PSTR("  command_dest=%d\r\n"), command_dest);
117         printf_P(PSTR("  i2c_status=%x\r\n"), i2c_status());
118 #endif
119 }
120
121 #ifndef HOST_VERSION
122 static void i2cproto_next_state(uint8_t inc)
123 {
124         i2c_state += inc;
125         if (i2c_state >= I2C_STATE_MAX) {
126                 i2c_state = 0;
127                 i2c_poll_num ++;
128         }
129 }
130
131 void i2cproto_wait_update(void)
132 {
133         uint8_t poll_num;
134         poll_num = i2c_poll_num;
135         WAIT_COND_OR_TIMEOUT((i2c_poll_num-poll_num) > 1, 150);
136 }
137
138 /* called periodically : the goal of this 'thread' is to send requests
139  * and read answers on i2c slaves in the correct order. */
140 void i2c_poll_slaves(void *dummy)
141 {
142         uint8_t flags;
143         int8_t err;
144         static uint8_t a = 0;
145
146         a++;
147         if (a & 0x4)
148                 LED2_TOGGLE();
149
150         /* already running */
151         IRQ_LOCK(flags);
152         if (running_op != OP_READY) {
153                 IRQ_UNLOCK(flags);
154                 return;
155         }
156
157         /* if a command is ready to be sent, so send it */
158         if (command_size) {
159                 running_op = OP_CMD;
160                 err = i2c_send(command_dest, command_buf, command_size,
161                              I2C_CTRL_GENERIC);
162                 if (err < 0)
163                         goto error;
164                 IRQ_UNLOCK(flags);
165                 return;
166         }
167
168         /* no command, so do the polling */
169         running_op = OP_POLL;
170
171         switch(i2c_state) {
172
173         /* poll status of cobboard */
174 #define I2C_REQ_COBBOARD 0
175         case I2C_REQ_COBBOARD:
176                 if ((err = i2c_req_cobboard_status()))
177                         goto error;
178                 break;
179
180 #define I2C_ANS_COBBOARD 1
181         case I2C_ANS_COBBOARD:
182                 if ((err = i2c_recv(I2C_COBBOARD_ADDR,
183                                     sizeof(struct i2c_ans_cobboard_status),
184                                     I2C_CTRL_GENERIC)))
185                         goto error;
186                 break;
187
188         /* poll status of ballboard */
189 #define I2C_REQ_BALLBOARD 2
190         case I2C_REQ_BALLBOARD:
191                 if ((err = i2c_req_ballboard_status()))
192                         goto error;
193                 break;
194
195 #define I2C_ANS_BALLBOARD 3
196         case I2C_ANS_BALLBOARD:
197                 if ((err = i2c_recv(I2C_BALLBOARD_ADDR,
198                                     sizeof(struct i2c_ans_ballboard_status),
199                                     I2C_CTRL_GENERIC)))
200                         goto error;
201                 break;
202
203         /* nothing, go to the first request */
204         default:
205                 i2c_state = 0;
206                 running_op = OP_READY;
207         }
208         IRQ_UNLOCK(flags);
209
210         return;
211
212  error:
213         running_op = OP_READY;
214         IRQ_UNLOCK(flags);
215         i2c_errors++;
216         if (i2c_errors > I2C_MAX_ERRORS) {
217                 I2C_ERROR("I2C send is_cmd=%d proto_state=%d "
218                       "err=%d i2c_status=%x", !!command_size, i2c_state, err, i2c_status());
219                 i2c_reset();
220                 i2c_errors = 0;
221         }
222 }
223
224 /* called when the xmit is finished */
225 void i2c_sendevent(int8_t size)
226 {
227         if (size > 0) {
228                 if (running_op == OP_POLL) {
229                         i2cproto_next_state(1);
230                 }
231                 else
232                         command_size = 0;
233         }
234         else {
235                 i2c_errors++;
236                 NOTICE(E_USER_I2C_PROTO, "send error state=%d size=%d "
237                         "op=%d", i2c_state, size, running_op);
238                 if (i2c_errors > I2C_MAX_ERRORS) {
239                         I2C_ERROR("I2C error, slave not ready");
240                         i2c_reset();
241                         i2c_errors = 0;
242                 }
243
244                 if (running_op == OP_POLL) {
245                         /* skip associated answer */
246                         i2cproto_next_state(2);
247                 }
248         }
249         running_op = OP_READY;
250 }
251
252 /* called rx event */
253 void i2c_recvevent(uint8_t * buf, int8_t size)
254 {
255         if (running_op == OP_POLL)
256                 i2cproto_next_state(1);
257
258         /* recv is only trigged after a poll */
259         running_op = OP_READY;
260
261         if (size < 0) {
262                 goto error;
263         }
264
265         switch (buf[0]) {
266
267         case I2C_ANS_COBBOARD_STATUS: {
268                 struct i2c_ans_cobboard_status * ans =
269                         (struct i2c_ans_cobboard_status *)buf;
270
271                 if (size != sizeof (*ans))
272                         goto error;
273
274                 /* status */
275                 //cobboard.mode = ans->mode;
276                 cobboard.status = ans->status;
277                 cobboard.left_cobroller_speed = ans->left_cobroller_speed;
278                 cs_set_consign(&mainboard.left_cobroller.cs, cobboard.left_cobroller_speed);
279                 cobboard.right_cobroller_speed = ans->right_cobroller_speed;
280                 cs_set_consign(&mainboard.right_cobroller.cs, cobboard.right_cobroller_speed);
281
282                 break;
283         }
284
285         case I2C_ANS_BALLBOARD_STATUS: {
286                 struct i2c_ans_ballboard_status * ans =
287                         (struct i2c_ans_ballboard_status *)buf;
288
289                 if (size != sizeof (*ans))
290                         goto error;
291                 ballboard.mode = ans->mode;
292                 ballboard.status = ans->status;
293                 ballboard.ball_count = ans->ball_count;
294                 break;
295         }
296
297         default:
298                 break;
299         }
300
301         return;
302  error:
303         i2c_errors++;
304         NOTICE(E_USER_I2C_PROTO, "recv error state=%d op=%d",
305                i2c_state, running_op);
306         if (i2c_errors > I2C_MAX_ERRORS) {
307                 I2C_ERROR("I2C error, slave not ready");
308                 i2c_reset();
309                 i2c_errors = 0;
310         }
311 }
312
313 void i2c_recvbyteevent(uint8_t hwstatus, uint8_t i, uint8_t c)
314 {
315 }
316 #endif /* !HOST_VERSION */
317
318 /* ******** ******** ******** ******** */
319 /* commands */
320 /* ******** ******** ******** ******** */
321
322
323 static int8_t
324 i2c_send_command(uint8_t addr, uint8_t * buf, uint8_t size)
325 {
326 #ifdef HOST_VERSION
327         return robotsim_i2c(addr, buf, size);
328 #else
329         uint8_t flags;
330         microseconds us = time_get_us2();
331
332         while ((time_get_us2() - us) < (I2C_TIMEOUT)*1000L) {
333                 IRQ_LOCK(flags);
334                 if (command_size == 0) {
335                         memcpy(command_buf, buf, size);
336                         command_size = size;
337                         command_dest = addr;
338                         IRQ_UNLOCK(flags);
339                         return 0;
340                 }
341                 IRQ_UNLOCK(flags);
342         }
343         /* this should not happen... except if we are called from an
344          * interrupt context, but it's forbidden */
345         I2C_ERROR("I2C command send failed");
346         return -EBUSY;
347 #endif
348 }
349
350 #ifndef HOST_VERSION
351 static int8_t i2c_req_cobboard_status(void)
352 {
353         struct i2c_req_cobboard_status buf;
354         int8_t err;
355
356         buf.hdr.cmd = I2C_REQ_COBBOARD_STATUS;
357         buf.mode = cobboard.mode;
358         err = i2c_send(I2C_COBBOARD_ADDR, (uint8_t*)&buf,
359                         sizeof(buf), I2C_CTRL_GENERIC);
360
361         return err;
362 }
363
364 static int8_t i2c_req_ballboard_status(void)
365 {
366         struct i2c_req_ballboard_status buf;
367
368         buf.hdr.cmd = I2C_REQ_BALLBOARD_STATUS;
369         return i2c_send(I2C_BALLBOARD_ADDR, (uint8_t*)&buf,
370                         sizeof(buf), I2C_CTRL_GENERIC);
371 }
372 #endif /* !HOST_VERSION */
373
374 int8_t i2c_set_color(uint8_t addr, uint8_t color)
375 {
376         struct i2c_cmd_generic_color buf;
377
378         if (addr == I2C_BALLBOARD_ADDR)
379                 return 0; /* XXX disabled for now */
380         buf.hdr.cmd = I2C_CMD_GENERIC_SET_COLOR;
381         buf.color = color;
382         return i2c_send_command(addr, (uint8_t*)&buf, sizeof(buf));
383 }
384
385 int8_t i2c_led_control(uint8_t addr, uint8_t led, uint8_t state)
386 {
387         struct i2c_cmd_led_control buf;
388         buf.hdr.cmd = I2C_CMD_GENERIC_LED_CONTROL;
389         buf.led_num = led;
390         buf.state = state;
391         return i2c_send_command(addr, (uint8_t*)&buf, sizeof(buf));
392 }
393
394 static int8_t i2c_cobboard_set_mode(uint8_t mode)
395 {
396 #ifdef HOST_VERSION
397         return robotsim_i2c_cobboard_set_mode(mode);
398 #else
399         cobboard.mode = mode;
400         return 0;
401 #endif
402
403 #if 0 /* old */
404         struct i2c_cmd_cobboard_set_mode buf;
405         buf.hdr.cmd = I2C_CMD_COBBOARD_SET_MODE;
406         buf.mode = cobboard.mode | I2C_COBBOARD_MODE_EJECT;
407         return i2c_send_command(I2C_COBBOARD_ADDR, (uint8_t*)&buf, sizeof(buf));
408 #endif
409 }
410
411 int8_t i2c_cobboard_mode_eject(void)
412 {
413         /* XXXXXXXXX bad bad bad */
414         uint8_t mode = cobboard.mode | I2C_COBBOARD_MODE_EJECT;
415         i2c_cobboard_set_mode(mode);
416         time_wait_ms(500);
417         mode = cobboard.mode & (~I2C_COBBOARD_MODE_EJECT);
418         i2c_cobboard_set_mode(mode);
419         return 0;
420 }
421
422 int8_t i2c_cobboard_mode_harvest(uint8_t side)
423 {
424         uint8_t mode = cobboard.mode;
425
426         if (side == I2C_LEFT_SIDE) {
427                 mode |= I2C_COBBOARD_MODE_L_DEPLOY;
428                 mode |= I2C_COBBOARD_MODE_L_HARVEST;
429         }
430         else {
431                 mode |= I2C_COBBOARD_MODE_R_DEPLOY;
432                 mode |= I2C_COBBOARD_MODE_R_HARVEST;
433         }
434         return i2c_cobboard_set_mode(mode);
435 }
436
437 int8_t i2c_cobboard_mode_deploy(uint8_t side)
438 {
439         uint8_t mode = cobboard.mode;
440
441         if (side == I2C_LEFT_SIDE) {
442                 mode &= ~(I2C_COBBOARD_MODE_L_DEPLOY | I2C_COBBOARD_MODE_L_HARVEST);
443                 mode |= I2C_COBBOARD_MODE_L_DEPLOY;
444         }
445         else {
446                 mode &= ~(I2C_COBBOARD_MODE_R_DEPLOY | I2C_COBBOARD_MODE_R_HARVEST);
447                 mode |= I2C_COBBOARD_MODE_R_DEPLOY;
448         }
449         return i2c_cobboard_set_mode(mode);
450 }
451
452 int8_t i2c_cobboard_mode_pack(uint8_t side)
453 {
454         uint8_t mode = cobboard.mode;
455
456         if (side == I2C_LEFT_SIDE)
457                 mode &= ~(I2C_COBBOARD_MODE_L_DEPLOY | I2C_COBBOARD_MODE_L_HARVEST);
458         else
459                 mode &= ~(I2C_COBBOARD_MODE_R_DEPLOY | I2C_COBBOARD_MODE_R_HARVEST);
460         return i2c_cobboard_set_mode(mode);
461 }
462
463 int8_t i2c_cobboard_mode_init(void)
464 {
465         return i2c_cobboard_set_mode(I2C_COBBOARD_MODE_INIT);
466 }
467
468 int8_t i2c_ballboard_set_mode(uint8_t mode)
469 {
470         struct i2c_cmd_ballboard_set_mode buf;
471         buf.hdr.cmd = I2C_CMD_BALLBOARD_SET_MODE;
472         buf.mode = mode;
473         return i2c_send_command(I2C_BALLBOARD_ADDR, (uint8_t*)&buf, sizeof(buf));
474 }
475