From 78db63e992134c3ec72324b38641801093f46350 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Wed, 27 Mar 2013 23:44:04 +0100 Subject: digital/dev2/src: add gpio binary protocol --- digital/dev2/src/common/gpio.c | 172 +++++++++++++++++++++++++++++++---- digital/dev2/src/common/gpio_proto.h | 57 ++++++++++++ 2 files changed, 213 insertions(+), 16 deletions(-) create mode 100644 digital/dev2/src/common/gpio_proto.h (limited to 'digital/dev2/src') diff --git a/digital/dev2/src/common/gpio.c b/digital/dev2/src/common/gpio.c index 53cd8eda..b40b5ad7 100644 --- a/digital/dev2/src/common/gpio.c +++ b/digital/dev2/src/common/gpio.c @@ -26,15 +26,37 @@ #include "io.h" #include "gpio.h" +#include "gpio_proto.h" #include "descriptors.h" #include "modules/usb/usb.h" +#include "modules/utils/utils.h" + +/* Context. */ +struct gpio_t +{ + /* Whether binary mode is activated. */ + uint8_t bin; + /* Currently handled operation, or 0 if none. */ + uint8_t op; + /* Arguments being received. */ + uint8_t args[5]; + /* Number of arguments to receive. */ + uint8_t args_nb; + /* Number of received arguments. */ + uint8_t args_index; + /* Data was sent on TX endpoint, need ZLP or last packet finalisation. */ + uint8_t data_sent; +}; + +static struct gpio_t ctx; void gpio_init (void) { PORTD = 0; DDRD = 0; + ctx.bin = 0; } void @@ -43,31 +65,149 @@ gpio_uninit (void) gpio_init (); } +static void +gpio_bin_send (uint8_t c) +{ + Endpoint_SelectEndpoint (GPIO_TX_EPNUM); + while (!Endpoint_ReadWriteAllowed ()) + ; + Endpoint_Write_Byte (c); + if (!Endpoint_ReadWriteAllowed ()) + Endpoint_ClearCurrentBank (); + Endpoint_SelectEndpoint (GPIO_RX_EPNUM); + ctx.data_sent = 1; +} + +static void +gpio_bin_accept (uint8_t c) +{ + if (!ctx.op) + { + uint8_t op_args[][2] = { + { GPIO_OP_RESET_SYNC, 0 }, + { GPIO_OP_SETUP, 5 }, + { GPIO_OP_DIR, 1 }, + { GPIO_OP_DIR_OUT, 1 }, + { GPIO_OP_DIR_IN, 1 }, + { GPIO_OP_OUT, 1 }, + { GPIO_OP_OUT_SET, 1 }, + { GPIO_OP_OUT_RESET, 1 }, + { GPIO_OP_OUT_TOGGLE, 1 }, + { GPIO_OP_OUT_CHANGE, 2 }, + { GPIO_OP_IN, 0 }, + }; + uint8_t i; + ctx.op = 0; + ctx.args_nb = 0; + ctx.args_index = 0; + for (i = 0; i < UTILS_COUNT (op_args); i++) + { + if (op_args[i][0] == c) + { + ctx.op = c; + ctx.args_nb = op_args[i][1]; + break; + } + } + } + else + { + ctx.args[ctx.args_index++] = c; + } + if (ctx.op && ctx.args_index == ctx.args_nb) + { + switch (ctx.op) + { + case GPIO_OP_RESET_SYNC: + PORTD = 0; + DDRD = 0; + break; + case GPIO_OP_SETUP: + /* Ignore arguments for the moment. */ + break; + case GPIO_OP_DIR: + DDRD = ctx.args[0]; + break; + case GPIO_OP_DIR_OUT: + DDRD |= ctx.args[0]; + break; + case GPIO_OP_DIR_IN: + DDRD &= ~ctx.args[0]; + break; + case GPIO_OP_OUT: + PORTD = ctx.args[0]; + break; + case GPIO_OP_OUT_SET: + PORTD |= ctx.args[0]; + break; + case GPIO_OP_OUT_RESET: + PORTD &= ~ctx.args[0]; + break; + case GPIO_OP_OUT_TOGGLE: + PORTD ^= ctx.args[0]; + break; + case GPIO_OP_OUT_CHANGE: + PORTD = (PORTD & ~ctx.args[0]) | ctx.args[1]; + break; + case GPIO_OP_IN: + gpio_bin_send (PIND); + break; + } + ctx.op = 0; + } +} + void gpio_task (void) { - Endpoint_SelectEndpoint (GPIO_RX_EPNUM); - /* If data is available from USB: */ - if (Endpoint_ReadWriteAllowed ()) + if (!ctx.bin) { - /* Read as much as possible, and clear endpoint. */ - do { - Endpoint_Discard_Byte (); - } while (Endpoint_ReadWriteAllowed ()); - Endpoint_ClearCurrentBank (); - /* Now, print current GPIO state if possible. */ - Endpoint_SelectEndpoint (GPIO_TX_EPNUM); + Endpoint_SelectEndpoint (GPIO_RX_EPNUM); + /* If data is available from USB: */ if (Endpoint_ReadWriteAllowed ()) { - uint8_t i, pin; - pin = PIND; - for (i = 0; i < 8; i++) + /* Read as much as possible, and clear endpoint. */ + do { + uint8_t c = Endpoint_Read_Byte (); + if (c == GPIO_OP_RESET_SYNC) + { + ctx.bin = 1; + gpio_task (); + return; + } + } while (Endpoint_ReadWriteAllowed ()); + Endpoint_ClearCurrentBank (); + /* Now, print current GPIO state if possible. */ + Endpoint_SelectEndpoint (GPIO_TX_EPNUM); + if (Endpoint_ReadWriteAllowed ()) { - Endpoint_Write_Byte (pin & 0x80 ? '1' : '0'); - pin <<= 1; + uint8_t i, pin; + pin = PIND; + for (i = 0; i < 8; i++) + { + Endpoint_Write_Byte (pin & 0x80 ? '1' : '0'); + pin <<= 1; + } + Endpoint_Write_Byte ('\r'); + Endpoint_ClearCurrentBank (); } - Endpoint_Write_Byte ('\r'); + } + } + else + { + Endpoint_SelectEndpoint (GPIO_RX_EPNUM); + if (Endpoint_ReadWriteAllowed ()) + { + do { + gpio_bin_accept (Endpoint_Read_Byte ()); + } while (Endpoint_ReadWriteAllowed ()); + Endpoint_ClearCurrentBank (); + } + if (ctx.data_sent) + { + Endpoint_SelectEndpoint (GPIO_TX_EPNUM); Endpoint_ClearCurrentBank (); + ctx.data_sent = 0; } } } diff --git a/digital/dev2/src/common/gpio_proto.h b/digital/dev2/src/common/gpio_proto.h new file mode 100644 index 00000000..5252480e --- /dev/null +++ b/digital/dev2/src/common/gpio_proto.h @@ -0,0 +1,57 @@ +#ifndef gpio_proto_h +#define gpio_proto_h +/* gpio_proto.h */ +/* dev2 - Multi-purpose development board using USB and Ethernet. {{{ + * + * Copyright (C) 2013 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. + * + * }}} */ + +/* All communications are big endian. */ + +/* Reset communication and set all pins as input. */ +#define GPIO_OP_RESET_SYNC 0xa5 +/* Set port width (1 byte argument) and period (4 bytes, in ns unit). + * Port width will determine the size of a port argument (1 byte for 8, 2 + * bytes for 16...). Period is the pause between two output changes, 0 means + * as fast as possible. */ +#define GPIO_OP_SETUP 0xaa + +/* Set complete port direction, 1 is output. */ +#define GPIO_OP_DIR 0xb0 +/* Set direction as output for selected pins. */ +#define GPIO_OP_DIR_OUT 0xb1 +/* Set direction as input for selected pins. */ +#define GPIO_OP_DIR_IN 0xb2 +/* Set complete output port value. */ +#define GPIO_OP_OUT 0xb4 +/* Set pins in output port. */ +#define GPIO_OP_OUT_SET 0xb5 +/* Reset pins in output port. */ +#define GPIO_OP_OUT_RESET 0xb6 +/* Toggle pins in output port. */ +#define GPIO_OP_OUT_TOGGLE 0xb7 +/* Change pins (mask as first argument, value as second argument). */ +#define GPIO_OP_OUT_CHANGE 0xb8 +/* Request port input. */ +#define GPIO_OP_IN 0xb9 + +#endif /* gpio_proto_h */ -- cgit v1.2.3