summaryrefslogtreecommitdiffhomepage
path: root/digital/dev2/src/common/usb_twi.c
diff options
context:
space:
mode:
Diffstat (limited to 'digital/dev2/src/common/usb_twi.c')
-rw-r--r--digital/dev2/src/common/usb_twi.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/digital/dev2/src/common/usb_twi.c b/digital/dev2/src/common/usb_twi.c
new file mode 100644
index 00000000..e83a94d9
--- /dev/null
+++ b/digital/dev2/src/common/usb_twi.c
@@ -0,0 +1,279 @@
+/* usb_twi.c */
+/* dev2 - Multi-purpose development board using USB and Ethernet. {{{
+ *
+ * Copyright (C) 2010 Nicolas Schodet
+ *
+ * APBTeam:
+ * Web: http://apbteam.org/
+ * Email: team AT apbteam DOT org
+ *
+ * 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.
+ *
+ * }}} */
+#include "common.h"
+
+#include "usb_twi.h"
+#include "descriptors.h"
+
+#include "modules/twi/twi.h"
+#include "modules/usb/usb.h"
+
+/** Parser steps. */
+enum
+{
+ /** Nothing received yet. */
+ PARSER_WAIT_COMMAND,
+ /** Command received, wait address most significant quartet. */
+ PARSER_WAIT_ADDRESS_MSQ,
+ /** First address quartet received, wait second one. */
+ PARSER_WAIT_ADDRESS_LSQ,
+ /** Wait data or end of line. */
+ PARSER_WAIT_DATA_OR_EOL,
+ /** Wait data second quartet. */
+ PARSER_WAIT_DATA_LSQ,
+};
+
+/** Context. */
+struct usb_twi_t
+{
+ /** Buffer used for transmission or reception. */
+ uint8_t buffer[TWI_BUFFER_SIZE];
+ /** Number of bytes in buffer. */
+ uint8_t buffer_tail;
+ /** Number of bytes sent back to USB. */
+ uint8_t buffer_head;
+ /** Command to execute. */
+ char command;
+ /** Slave address. */
+ uint8_t slave;
+ /** Parser step. */
+ uint8_t parser_step;
+ /** Parser first quartet. */
+ uint8_t parser_msq;
+ /** Output buffer (in case of USB not ready). */
+ char output_buffer[4];
+ /** Position in output buffer of next character to send. */
+ uint8_t output_buffer_head;
+};
+
+/** Global context. */
+struct usb_twi_t usb_twi_global;
+#define ctx usb_twi_global
+
+void
+usb_twi_init (void)
+{
+ twi_init (0xfe);
+}
+
+void
+usb_twi_uninit (void)
+{
+ twi_uninit ();
+}
+
+/** Return non zero if there is characters to send. */
+static uint8_t
+usb_twi_poll (void)
+{
+ return ctx.output_buffer[ctx.output_buffer_head];
+}
+
+/** Output byte to output buffer. */
+static void
+usb_twi_ouput_byte (uint8_t p, uint8_t b)
+{
+ uint8_t i;
+ char c;
+ for (i = 0; i < 2; i++)
+ {
+ c = "0123456789abcdef"[b >> 4];
+ ctx.output_buffer[p++] = c;
+ b <<= 4;
+ }
+}
+
+/** Return a character from the output buffer and reload it from buffer if
+ * needed. */
+static char
+usb_twi_getc (void)
+{
+ char c;
+ uint8_t p;
+ /* Take a character in output buffer. */
+ c = ctx.output_buffer[ctx.output_buffer_head];
+ ctx.output_buffer_head++;
+ /* Reload from buffer if needed. */
+ if (!ctx.output_buffer[ctx.output_buffer_head]
+ && ctx.buffer_head != ctx.buffer_tail)
+ {
+ ctx.output_buffer_head = 0;
+ p = 0;
+ usb_twi_ouput_byte (p, ctx.buffer[ctx.buffer_head++]);
+ p += 2;
+ if (ctx.buffer_head == ctx.buffer_tail)
+ ctx.output_buffer[p++] = '\r';
+ ctx.output_buffer[p] = '\0';
+ }
+ return c;
+}
+
+static uint8_t
+usb_twi_get_hex (char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ else
+ return 0xff;
+}
+
+static uint8_t
+usb_twi_exec (void)
+{
+ uint8_t r, p, l;
+ if (ctx.command == 's')
+ {
+ twi_master_send (ctx.slave, ctx.buffer, ctx.buffer_tail);
+ r = twi_master_wait ();
+ ctx.buffer[0] = r;
+ ctx.buffer_head = 0;
+ ctx.buffer_tail = 1;
+ ctx.output_buffer_head = 0;
+ p = 0;
+ ctx.output_buffer[p++] = 'S';
+ ctx.output_buffer[p++] = '\0';
+ return 1;
+ }
+ else if (ctx.command == 'r' && ctx.buffer_tail == 1)
+ {
+ l = ctx.buffer[0];
+ twi_master_recv (ctx.slave, ctx.buffer, l);
+ r = twi_master_wait ();
+ ctx.buffer_head = 0;
+ ctx.buffer_tail = r;
+ ctx.output_buffer_head = 0;
+ p = 0;
+ ctx.output_buffer[p++] = 'R';
+ if (r == 0)
+ ctx.output_buffer[p++] = '\r';
+ ctx.output_buffer[p++] = '\0';
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static void
+usb_twi_accept (char c)
+{
+ uint8_t q;
+ /* Purge output buffer. */
+ ctx.output_buffer_head = 0;
+ ctx.output_buffer[0] = '\0';
+ /* Accept FSM. */
+ switch (ctx.parser_step)
+ {
+ case PARSER_WAIT_COMMAND:
+ if (c == 's' || c == 'r')
+ {
+ ctx.command = c;
+ ctx.buffer_tail = 0;
+ ctx.parser_step++;
+ return;
+ }
+ break;
+ case PARSER_WAIT_ADDRESS_MSQ:
+ q = usb_twi_get_hex (c);
+ if (q != 0xff)
+ {
+ ctx.parser_msq = q;
+ ctx.parser_step++;
+ return;
+ }
+ break;
+ case PARSER_WAIT_ADDRESS_LSQ:
+ q = usb_twi_get_hex (c);
+ if (q != 0xff)
+ {
+ ctx.slave = ctx.parser_msq << 4 | q;
+ ctx.parser_step++;
+ return;
+ }
+ break;
+ case PARSER_WAIT_DATA_OR_EOL:
+ if (c == '\r')
+ {
+ ctx.parser_step = PARSER_WAIT_COMMAND;
+ if (usb_twi_exec ())
+ return;
+ }
+ else if (ctx.buffer_tail < TWI_BUFFER_SIZE)
+ {
+ q = usb_twi_get_hex (c);
+ if (q != 0xff)
+ {
+ ctx.parser_msq = q;
+ ctx.parser_step++;
+ return;
+ }
+ }
+ break;
+ case PARSER_WAIT_DATA_LSQ:
+ q = usb_twi_get_hex (c);
+ if (q != 0xff)
+ {
+ ctx.buffer[ctx.buffer_tail++] = ctx.parser_msq << 4 | q;
+ ctx.parser_step--;
+ return;
+ }
+ break;
+ }
+ /* If here, there was an error. */
+ ctx.buffer_tail = ctx.buffer_head = 0;
+ ctx.output_buffer_head = 0;
+ ctx.output_buffer[0] = '!';
+ ctx.output_buffer[1] = '\r';
+ ctx.output_buffer[2] = '\0';
+ ctx.parser_step = PARSER_WAIT_COMMAND;
+}
+
+void
+usb_twi_task (void)
+{
+ Endpoint_SelectEndpoint (TWI_RX_EPNUM);
+ /* If data is available from USB: */
+ if (Endpoint_ReadWriteAllowed ())
+ {
+ /* Read as much as possible, and clear endpoint. */
+ do {
+ usb_twi_accept (Endpoint_Read_Byte ());
+ } while (Endpoint_ReadWriteAllowed ());
+ Endpoint_ClearCurrentBank ();
+ }
+ /* If data is available from uart and there is room in the TX endpoint: */
+ Endpoint_SelectEndpoint (TWI_TX_EPNUM);
+ if (usb_twi_poll () && Endpoint_ReadWriteAllowed ())
+ {
+ do {
+ Endpoint_Write_Byte (usb_twi_getc ());
+ } while (usb_twi_poll () && Endpoint_ReadWriteAllowed ());
+ Endpoint_ClearCurrentBank ();
+ }
+}
+