--- /dev/null
+/*
+ * Copyright Droids Corporation (2009)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Revision : $Id: i2c_protocol.c,v 1.8 2009-11-08 17:24:33 zer0 Exp $
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <aversive/pgmspace.h>
+#include <aversive/wait.h>
+#include <aversive/error.h>
+
+#include <callout.h>
+#include <i2c.h>
+
+#include "../fpv-common/i2c_commands.h"
+#include "main.h"
+#include "i2c_protocol.h"
+
+#define I2C_STATE_MAX 2
+#define I2C_PERIOD_MS 50
+
+#define I2C_TIMEOUT 100 /* ms */
+#define I2C_MAX_ERRORS 40
+
+uint8_t imuboard = 0; /* XXX test */
+
+static volatile uint8_t i2c_poll_num = 0;
+static volatile uint8_t i2c_state = 0;
+static volatile uint16_t i2c_errors = 0;
+
+#define OP_READY 0 /* no i2c op running */
+#define OP_POLL 1 /* a user command is running */
+#define OP_CMD 2 /* a polling (req / ans) is running */
+
+static volatile uint8_t running_op = OP_READY;
+
+#define I2C_MAX_LOG 3
+static uint8_t error_log = 0;
+
+static struct callout i2c_timer;
+
+static int8_t i2c_req_imuboard_status(void);
+
+/* used for commands */
+uint8_t command_buf[I2C_SEND_BUFFER_SIZE];
+volatile int8_t command_dest=-1;
+volatile uint8_t command_size=0;
+
+#define I2C_ERROR(args...) do { \
+ if (error_log < I2C_MAX_LOG) { \
+ ERROR(E_USER_I2C_PROTO, args); \
+ error_log ++; \
+ if (error_log == I2C_MAX_LOG) { \
+ ERROR(E_USER_I2C_PROTO, \
+ "i2c logs are now warnings"); \
+ } \
+ } \
+ else \
+ WARNING(E_USER_I2C_PROTO, args); \
+ } while(0)
+
+void i2c_protocol_debug(void)
+{
+ printf_P(PSTR("I2C protocol debug infos:\r\n"));
+ printf_P(PSTR(" i2c_state=%d\r\n"), i2c_state);
+ printf_P(PSTR(" i2c_errors=%d\r\n"), i2c_errors);
+ printf_P(PSTR(" running_op=%d\r\n"), running_op);
+ printf_P(PSTR(" command_size=%d\r\n"), command_size);
+ printf_P(PSTR(" command_dest=%d\r\n"), command_dest);
+ printf_P(PSTR(" i2c_status=%x\r\n"), i2c_status());
+}
+
+static void i2cproto_next_state(uint8_t inc)
+{
+ i2c_state += inc;
+ if (i2c_state >= I2C_STATE_MAX) {
+ i2c_state = 0;
+ i2c_poll_num ++;
+ }
+}
+
+void i2cproto_wait_update(void)
+{
+ uint8_t poll_num;
+ poll_num = i2c_poll_num;
+ (void)poll_num;
+ //WAIT_COND_OR_TIMEOUT((i2c_poll_num-poll_num) > 1, 150); /* XXX todo */
+}
+
+/* called periodically : the goal of this 'thread' is to send requests
+ * and read answers on i2c slaves in the correct order. */
+static void i2c_poll_slaves(struct callout_mgr *cm, struct callout *tim, void *arg)
+{
+ uint8_t flags;
+ int8_t err;
+
+ (void)cm;
+ (void)tim;
+ (void)arg;
+
+#if 0
+ static uint8_t a = 0;
+
+ a++;
+ if (a & 0x4)
+ LED2_TOGGLE();
+#endif
+
+ /* already running */
+ IRQ_LOCK(flags);
+ if (running_op != OP_READY) {
+ IRQ_UNLOCK(flags);
+ goto reschedule;
+ }
+
+ /* if a command is ready to be sent, so send it */
+ if (command_size) {
+ running_op = OP_CMD;
+ err = i2c_send(command_dest, command_buf, command_size,
+ I2C_CTRL_GENERIC);
+ if (err < 0)
+ goto error;
+ IRQ_UNLOCK(flags);
+ goto reschedule;
+ }
+
+ /* no command, so do the polling */
+ running_op = OP_POLL;
+
+ switch(i2c_state) {
+
+ /* poll status of imuboard */
+#define I2C_REQ_IMUBOARD 0
+ case I2C_REQ_IMUBOARD:
+ if ((err = i2c_req_imuboard_status()))
+ goto error;
+ break;
+
+#define I2C_ANS_IMUBOARD 1
+ case I2C_ANS_IMUBOARD:
+ if ((err = i2c_recv(I2C_IMUBOARD_ADDR,
+ sizeof(struct i2c_ans_imuboard_status),
+ I2C_CTRL_GENERIC)))
+ goto error;
+ break;
+
+ /* sync with I2C_STATE_MAX */
+
+ /* nothing, go to the first request */
+ default:
+ i2c_state = 0;
+ running_op = OP_READY;
+ }
+ IRQ_UNLOCK(flags);
+
+ goto reschedule;
+
+ error:
+ running_op = OP_READY;
+ IRQ_UNLOCK(flags);
+ i2c_errors++;
+ if (i2c_errors > I2C_MAX_ERRORS) {
+ I2C_ERROR("I2C send is_cmd=%d proto_state=%d "
+ "err=%d i2c_status=%x", !!command_size, i2c_state, err, i2c_status());
+ i2c_reset();
+ i2c_errors = 0;
+ }
+
+ reschedule:
+ /* reschedule */
+ callout_reschedule(cm, tim, I2C_PERIOD_MS);
+}
+
+/* called when the xmit is finished */
+void i2c_sendevent(int8_t size)
+{
+ if (size > 0) {
+ if (running_op == OP_POLL) {
+ i2cproto_next_state(1);
+ }
+ else
+ command_size = 0;
+ }
+ else {
+ i2c_errors++;
+ NOTICE(E_USER_I2C_PROTO, "send error state=%d size=%d "
+ "op=%d", i2c_state, size, running_op);
+ if (i2c_errors > I2C_MAX_ERRORS) {
+ I2C_ERROR("I2C error, slave not ready");
+ i2c_reset();
+ i2c_errors = 0;
+ }
+
+ if (running_op == OP_POLL) {
+ /* skip associated answer */
+ i2cproto_next_state(2);
+ }
+ }
+ running_op = OP_READY;
+}
+
+/* called rx event */
+void i2c_recvevent(uint8_t * buf, int8_t size)
+{
+ if (running_op == OP_POLL)
+ i2cproto_next_state(1);
+
+ /* recv is only trigged after a poll */
+ running_op = OP_READY;
+
+ if (size < 0) {
+ goto error;
+ }
+
+ switch (buf[0]) {
+
+ case I2C_ANS_IMUBOARD_STATUS: {
+ struct i2c_ans_imuboard_status * ans =
+ (struct i2c_ans_imuboard_status *)buf;
+
+ if (size != sizeof (*ans))
+ goto error;
+
+ /* status */
+ imuboard = ans->test;
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return;
+ error:
+ i2c_errors++;
+ NOTICE(E_USER_I2C_PROTO, "recv error state=%d op=%d",
+ i2c_state, running_op);
+ if (i2c_errors > I2C_MAX_ERRORS) {
+ I2C_ERROR("I2C error, slave not ready");
+ i2c_reset();
+ i2c_errors = 0;
+ }
+}
+
+void i2c_recvbyteevent(uint8_t hwstatus, uint8_t i, uint8_t c)
+{
+ (void)hwstatus;
+ (void)i;
+ (void)c;
+}
+
+/* ******** ******** ******** ******** */
+/* commands */
+/* ******** ******** ******** ******** */
+
+
+static int8_t
+i2c_send_command(uint8_t addr, uint8_t * buf, uint8_t size)
+{
+ uint8_t flags;
+ uint16_t ms = get_time_ms();
+
+ while ((get_time_ms() - ms) < I2C_TIMEOUT) {
+ IRQ_LOCK(flags);
+ if (command_size == 0) {
+ memcpy(command_buf, buf, size);
+ command_size = size;
+ command_dest = addr;
+ IRQ_UNLOCK(flags);
+ return 0;
+ }
+ IRQ_UNLOCK(flags);
+ }
+ /* this should not happen... except if we are called from an
+ * interrupt context, but it's forbidden */
+ I2C_ERROR("I2C command send failed");
+ return -EBUSY;
+}
+
+static int8_t i2c_req_imuboard_status(void)
+{
+ struct i2c_req_imuboard_status buf;
+ int8_t err;
+
+ buf.hdr.cmd = I2C_REQ_IMUBOARD_STATUS;
+ err = i2c_send(I2C_IMUBOARD_ADDR, (uint8_t*)&buf,
+ sizeof(buf), I2C_CTRL_GENERIC);
+
+ return err;
+}
+
+int8_t i2c_led_control(uint8_t addr, uint8_t led, uint8_t state)
+{
+ struct i2c_cmd_led_control buf;
+ buf.hdr.cmd = I2C_CMD_GENERIC_LED_CONTROL;
+ buf.led_num = led;
+ buf.state = state;
+ return i2c_send_command(addr, (uint8_t*)&buf, sizeof(buf));
+}
+
+void i2c_protocol_init(void)
+{
+ callout_init(&i2c_timer, i2c_poll_slaves, NULL, I2C_PRIO);
+ callout_schedule(&xbeeboard.intr_cm, &i2c_timer, I2C_PERIOD_MS);
+}
--- /dev/null
+/*
+ * Copyright Droids Corporation (2009)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Revision : $Id: i2c_protocol.h,v 1.6 2009-11-08 17:24:33 zer0 Exp $
+ *
+ */
+
+#ifndef _I2C_PROTOCOL_H_
+#define _I2C_PROTOCOL_H_
+
+void i2c_protocol_init(void);
+void i2c_protocol_debug(void);
+
+void i2cproto_wait_update(void);
+
+
+void i2c_recvevent(uint8_t *buf, int8_t size);
+void i2c_recvbyteevent(uint8_t hwstatus, uint8_t i, uint8_t c);
+void i2c_sendevent(int8_t size);
+
+int8_t i2c_led_control(uint8_t addr, uint8_t led, uint8_t state);
+
+
+#endif