2 * Copyright Droids Corporation (2009)
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.
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.
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
18 * Revision : $Id: i2c_protocol.c,v 1.8 2009-11-08 17:24:33 zer0 Exp $
25 #include <aversive/pgmspace.h>
26 #include <aversive/wait.h>
27 #include <aversive/error.h>
32 #include "../common/i2c_commands.h"
33 #include "i2c_protocol.h"
37 #define I2C_STATE_MAX 2
38 #define I2C_PERIOD_MS 50
40 #define I2C_TIMEOUT 100 /* ms */
41 #define I2C_MAX_ERRORS 40
43 #define IMUBOARD_BEEP_PERIOD_MS 2000
45 static volatile uint8_t i2c_poll_num = 0;
46 static volatile uint8_t i2c_state = 0;
47 static volatile uint8_t i2c_rx_count = 0;
48 static volatile uint8_t i2c_tx_count = 0;
49 static volatile uint16_t i2c_errors = 0;
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 */
55 static volatile uint8_t running_op = OP_READY;
58 static uint8_t error_log = 0;
60 static struct callout i2c_timer;
61 static struct callout imuboard_beep_timer;
63 static int8_t i2c_req_imuboard_status(void);
65 /* latest received imuboard_status */
66 struct i2c_ans_imuboard_status imuboard_status;
68 /* used for commands */
69 uint8_t command_buf[I2C_SEND_BUFFER_SIZE];
70 volatile int8_t command_dest=-1;
71 volatile uint8_t command_size=0;
73 static uint8_t i2c_enabled = 0;
75 #define I2C_ERROR(args...) do { \
76 if (error_log < I2C_MAX_LOG) { \
77 ERROR(E_USER_I2C_PROTO, args); \
79 if (error_log == I2C_MAX_LOG) { \
80 ERROR(E_USER_I2C_PROTO, \
81 "i2c logs are now warnings"); \
85 WARNING(E_USER_I2C_PROTO, args); \
88 void i2c_protocol_debug(void)
90 printf_P(PSTR("I2C protocol debug infos:\r\n"));
91 printf_P(PSTR(" i2c_send=%d\r\n"), i2c_tx_count);
92 printf_P(PSTR(" i2c_recv=%d\r\n"), i2c_rx_count);
93 printf_P(PSTR(" i2c_state=%d\r\n"), i2c_state);
94 printf_P(PSTR(" i2c_errors=%d\r\n"), i2c_errors);
95 printf_P(PSTR(" running_op=%d\r\n"), running_op);
96 printf_P(PSTR(" command_size=%d\r\n"), command_size);
97 printf_P(PSTR(" command_dest=%d\r\n"), command_dest);
98 printf_P(PSTR(" i2c_status=%x\r\n"), i2c_status());
101 static void i2cproto_next_state(uint8_t inc)
104 if (i2c_state >= I2C_STATE_MAX) {
110 void i2cproto_wait_update(void)
113 poll_num = i2c_poll_num;
115 //WAIT_COND_OR_TIMEOUT((i2c_poll_num-poll_num) > 1, 150); /* XXX todo */
118 static void imuboard_beep_cb(struct callout_mgr *cm, struct callout *tim, void *arg)
124 if (i2c_enabled == 0)
127 if ((imuboard_status.flags & I2C_IMUBOARD_STATUS_SDCARD_OK) == 0) {
132 if ((imuboard_status.flags & I2C_IMUBOARD_STATUS_BOOT_OK) == 0) {
138 if ((imuboard_status.flags & I2C_IMUBOARD_STATUS_GPS_OK) == 0) {
146 callout_reschedule(cm, tim, IMUBOARD_BEEP_PERIOD_MS);
150 /* called periodically : the goal of this 'thread' is to send requests
151 * and read answers on i2c slaves in the correct order. */
152 static void i2c_poll_slaves(struct callout_mgr *cm, struct callout *tim, void *arg)
162 static uint8_t a = 0;
169 if (i2c_enabled == 0)
172 /* already running */
174 if (running_op != OP_READY) {
179 /* if a command is ready to be sent, so send it */
182 err = i2c_send(command_dest, command_buf, command_size,
190 /* no command, so do the polling */
191 running_op = OP_POLL;
195 /* poll status of imuboard */
196 #define I2C_REQ_IMUBOARD 0
197 case I2C_REQ_IMUBOARD:
198 if ((err = i2c_req_imuboard_status()))
202 #define I2C_ANS_IMUBOARD 1
203 case I2C_ANS_IMUBOARD:
204 if ((err = i2c_recv(I2C_IMUBOARD_ADDR,
205 sizeof(struct i2c_ans_imuboard_status),
210 /* sync with I2C_STATE_MAX */
212 /* nothing, go to the first request */
215 running_op = OP_READY;
222 running_op = OP_READY;
225 if (i2c_errors > I2C_MAX_ERRORS) {
226 I2C_ERROR("I2C send is_cmd=%d proto_state=%d "
227 "err=%d i2c_status=%x", !!command_size, i2c_state, err, i2c_status());
234 callout_reschedule(cm, tim, I2C_PERIOD_MS);
237 /* called when the xmit is finished */
238 void i2c_sendevent(int8_t size)
241 if (running_op == OP_POLL) {
242 i2cproto_next_state(1);
250 NOTICE(E_USER_I2C_PROTO, "send error state=%d size=%d "
251 "op=%d", i2c_state, size, running_op);
252 if (i2c_errors > I2C_MAX_ERRORS) {
253 I2C_ERROR("I2C error, slave not ready");
258 if (running_op == OP_POLL) {
259 /* skip associated answer */
260 i2cproto_next_state(2);
263 running_op = OP_READY;
266 /* called rx event */
267 void i2c_recvevent(uint8_t * buf, int8_t size)
269 if (running_op == OP_POLL)
270 i2cproto_next_state(1);
272 /* recv is only trigged after a poll */
273 running_op = OP_READY;
283 case I2C_ANS_IMUBOARD_STATUS: {
284 struct i2c_ans_imuboard_status *ans =
285 (struct i2c_ans_imuboard_status *)buf;
287 if (size != sizeof (*ans))
290 /* copy status in a global struct */
291 memcpy(&imuboard_status, ans, sizeof(imuboard_status));
303 NOTICE(E_USER_I2C_PROTO, "recv error state=%d op=%d",
304 i2c_state, running_op);
305 if (i2c_errors > I2C_MAX_ERRORS) {
306 I2C_ERROR("I2C error, slave not ready");
312 void i2c_recvbyteevent(uint8_t hwstatus, uint8_t i, uint8_t c)
319 /* ******** ******** ******** ******** */
321 /* ******** ******** ******** ******** */
325 i2c_send_command(uint8_t addr, uint8_t * buf, uint8_t size)
328 uint16_t ms = get_time_ms();
330 while ((get_time_ms() - ms) < I2C_TIMEOUT) {
332 if (command_size == 0) {
333 memcpy(command_buf, buf, size);
341 /* this should not happen... except if we are called from an
342 * interrupt context, but it's forbidden */
343 I2C_ERROR("I2C command send failed");
347 static int8_t i2c_req_imuboard_status(void)
349 struct i2c_req_imuboard_status buf;
352 buf.hdr.cmd = I2C_REQ_IMUBOARD_STATUS;
353 err = i2c_send(I2C_IMUBOARD_ADDR, (uint8_t*)&buf,
354 sizeof(buf), I2C_CTRL_GENERIC);
359 int8_t i2c_led_control(uint8_t addr, uint8_t led, uint8_t state)
361 struct i2c_cmd_led_control buf;
362 buf.hdr.cmd = I2C_CMD_GENERIC_LED_CONTROL;
365 return i2c_send_command(addr, (uint8_t*)&buf, sizeof(buf));
368 void i2c_protocol_enable(uint8_t enable)
370 i2c_enabled = enable;
373 void i2c_protocol_init(void)
375 callout_init(&i2c_timer, i2c_poll_slaves, NULL, I2C_PRIO);
376 callout_schedule(&xbeeboard.intr_cm, &i2c_timer, I2C_PERIOD_MS);
377 callout_init(&imuboard_beep_timer, imuboard_beep_cb, NULL, I2C_PRIO); // prio ok ? XXX
378 callout_schedule(&xbeeboard.intr_cm, &imuboard_beep_timer,
379 IMUBOARD_BEEP_PERIOD_MS);