From c4b1dd425e044f8d4061e68cc653188266728441 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Tue, 6 Sep 2011 04:10:37 -0300 Subject: [PATCH] labsw/fw/: added EP0 commands; main loop now toggles --- labsw/fw/Makefile | 4 +- labsw/fw/config.h | 2 +- labsw/fw/ep0.c | 160 ++++++++++++++++++++++++++ labsw/fw/include/labsw/ep0.h | 122 ++++++++++++++++++++ labsw/fw/{ => include/labsw}/usb-id.h | 0 labsw/fw/labsw.c | 129 ++++++++++++++++----- 6 files changed, 383 insertions(+), 34 deletions(-) create mode 100644 labsw/fw/ep0.c create mode 100644 labsw/fw/include/labsw/ep0.h rename labsw/fw/{ => include/labsw}/usb-id.h (100%) diff --git a/labsw/fw/Makefile b/labsw/fw/Makefile index 255aaeb..fec099c 100644 --- a/labsw/fw/Makefile +++ b/labsw/fw/Makefile @@ -12,14 +12,14 @@ MAIN = labsw -OBJS = $(MAIN) usb descr version # ep0 +OBJS = $(MAIN) usb descr version ep0 F32XBASE = ../../../f32xbase include $(F32XBASE)/fw/common/Makefile.system include $(F32XBASE)/fw/common/Makefile.common -CFLAGS += -I../common -I../include +CFLAGS += -Iinclude LDFLAGS += --code-size $(PAYLOAD_SIZE) --code-loc $(PAYLOAD_START) USB_ID = $(shell \ diff --git a/labsw/fw/config.h b/labsw/fw/config.h index 165f2d6..2f2ed0e 100644 --- a/labsw/fw/config.h +++ b/labsw/fw/config.h @@ -1,2 +1,2 @@ -#include "usb-id.h" +#include "labsw/usb-id.h" #include "io-parts.h" diff --git a/labsw/fw/ep0.c b/labsw/fw/ep0.c new file mode 100644 index 0000000..809d9ad --- /dev/null +++ b/labsw/fw/ep0.c @@ -0,0 +1,160 @@ +/* + * labsw/ep0.c - EP0 extension protocol + * + * Written 2008-2011 by Werner Almesberger + * Copyright 2008-2011 Werner Almesberger + * + * 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. + */ + + +#include + +#ifndef NULL +#define NULL 0 +#endif + +#include "regs.h" +#include "usb.h" +#include "labsw/ep0.h" +#include "io.h" +#include "version.h" + + +extern int local; + + +/* + * SDCC 2.8.0 had a number of code generation bugs that appeared in the big + * switch statement of my_setup. SDCC_FORCE_UPDATE forced the value of the + * "size" variable to be written to memory. This work-around doesn't seem + * to be necessary with 2.9.0, but we keep it around, just in case. + * + * Unfortunately, the setup->bRequest garbling bug is still with us. Without + * the evaluation forced with SDCC_FORCE_EVAL, sdcc gets confused about the + * value of setup->bRequest and then rejects all SETUP requests. + */ + +#define SDCC_FORCE_EVAL(type, value) \ + do { \ + static volatile type foo; \ + foo = value; \ + } while (0) + +#define SDCC_FORCE_UPDATE(type, var) \ + do { \ + volatile type foo; \ + foo = var; \ + var = foo; \ + } while (0) + + +static uint8_t id[3] = { + EP0LABSW_MAJOR, EP0LABSW_MINOR, + /* hw type is set at run time */ +}; + +static __xdata uint8_t buf[128]; + + +#define BUILD_OFFSET 7 /* '#' plus "65535" plus ' ' */ + + +static __bit my_setup(struct setup_request *setup) __reentrant +{ + uint32_t tmp; + uint8_t size, i; + + switch (setup->bmRequestType | setup->bRequest << 8) { + case LABSW_FROM_DEV(LABSW_ID): + size = setup->wLength; + if (size > 3) + size = 3; + id[2] = 0; /* hardware type */ + usb_send(&ep0, id, size, NULL, NULL); + return 1; + case LABSW_FROM_DEV(LABSW_BUILD): + tmp = build_number; + for (i = BUILD_OFFSET-2; tmp; i--) { + buf[i] = (tmp % 10)+'0'; + tmp /= 10; + } + buf[i] = '#'; + buf[BUILD_OFFSET-1] = ' '; + for (size = 0; build_date[size]; size++) + buf[BUILD_OFFSET+size] = build_date[size]; + size += BUILD_OFFSET-i+1; + SDCC_FORCE_EVAL(uint8_t, setup->bRequest); + if (size > setup->wLength) + return 0; + usb_send(&ep0, buf+i, size, NULL, NULL); + return 1; + + case LABSW_TO_DEV(LABSW_RESET): + RSTSRC = SWRSF; + while (1); + + case LABSW_FROM_DEV(LABSW_GET): + size = setup->wLength; + if (size > 2) + size = 2; + buf[0] = + (IN_1 ? 0 : LABSW_IN1) | + (IN_2 ? 0 : LABSW_IN2) | + (IN_3 ? 0 : LABSW_IN3) | + (IN_4 ? 0 : LABSW_IN4); + buf[1] = + (BUT_MAIN ? 0 : LABSW_BUT_MAIN) | + (BUT_CH1 ? 0 : LABSW_BUT_CH1) | + (BUT_CH2 ? 0 : LABSW_BUT_CH2); + usb_send(&ep0, buf, size, NULL, NULL); + return 1; + + case LABSW_TO_DEV(LABSW_SET): + local = !setup->wIndex; + + if (setup->wIndex & LABSW_CH1_RELAY) + CH1_RELAY = setup->wValue & LABSW_CH1_RELAY ? 1 : 0; + if (setup->wIndex & LABSW_CH1_OPT) + CH1_OPT = setup->wValue & LABSW_CH1_OPT ? 0 : 1; + if (setup->wIndex & LABSW_CH2_RELAY) + CH2_RELAY = setup->wValue & LABSW_CH2_RELAY ? 1 : 0; + if (setup->wIndex & LABSW_CH2_OPT) + CH2_OPT = setup->wValue & LABSW_CH2_OPT ? 0 : 1; + + if (setup->wIndex & LABSW_OUT1) + OUT_1 = setup->wValue & LABSW_OUT1 ? 0 : 1; + if (setup->wIndex & LABSW_OUT2) + OUT_2 = setup->wValue & LABSW_OUT2 ? 0 : 1; + if (setup->wIndex & LABSW_OUT3) + OUT_3 = setup->wValue & LABSW_OUT3 ? 0 : 1; + if (setup->wIndex & LABSW_OUT4) + OUT_4 = setup->wValue & LABSW_OUT4 ? 0 : 1; + + if (setup->wIndex & LABSW_MAIN_R) + LED_MAIN_R = setup->wValue & LABSW_MAIN_R ? 1 : 0; + if (setup->wIndex & LABSW_MAIN_G) + LED_MAIN_G = setup->wValue & LABSW_MAIN_G ? 1 : 0; + if (setup->wIndex & LABSW_CH1_R) + LED_CH1_R = setup->wValue & LABSW_CH1_R ? 1 : 0; + if (setup->wIndex & LABSW_CH1_G) + LED_CH1_G = setup->wValue & LABSW_CH1_G ? 1 : 0; + if (setup->wIndex & LABSW_CH2_R) + LED_CH2_R = setup->wValue & LABSW_CH2_R ? 1 : 0; + if (setup->wIndex & LABSW_CH2_G) + LED_CH2_G = setup->wValue & LABSW_CH2_G ? 1 : 0; + return 1; + + default: + return 0; + } +} + + +void ep0_init(void) +{ + user_setup = my_setup; +} diff --git a/labsw/fw/include/labsw/ep0.h b/labsw/fw/include/labsw/ep0.h new file mode 100644 index 0000000..302316a --- /dev/null +++ b/labsw/fw/include/labsw/ep0.h @@ -0,0 +1,122 @@ +/* + * include/labsw/ep0.h - EP0 extension protocol + * + * Written 2011 by Werner Almesberger + * Copyright 2011 Werner Almesberger + * + * 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. + */ + + +#ifndef EP0_H +#define EP0_H + +/* + * Direction bRequest wValue wIndex wLength + * + * ->host LABSW_ID - - 3 + * ->host LABSW_BUILD - - #bytes + * host-> LABSW_RESET - - 0 + * + * ->host LABSW_GET - - 2 + * host-> LABSW_SET values mask 0 + */ + +/* + * EP0 protocol: + * + * 0.0 initial release + */ + +#define EP0LABSW_MAJOR 0 /* EP0 protocol, major revision */ +#define EP0LABSW_MINOR 0 /* EP0 protocol, minor revision */ + +/* + * bmRequestType: + * + * D7 D6..5 D4...0 + * | | | + * direction (0 = host->dev) + * type (2 = vendor) + * recipient (0 = device) + */ + + +#define LABSW_TO_DEV(req) (0x40 | (req) << 8) +#define LABSW_FROM_DEV(req) (0xc0 | (req) << 8) + + +enum cntr_requests { + LABSW_ID = 0x00, + LABSW_BUILD, + LABSW_RESET, + LABSW_GET = 0x10, + LABSW_SET, +}; + +/* + * LABSW_GET encoding: + * + * byte 0 byte 1 + * 76543210 76543210 + * 0000|||IN_1 00000||BUT_MAIN + * ||IN_2 |BUT_CH1 + * |IN_3 BUT_CH2 + * IN_4 + * + * LABSW_SET encoding: + * + * value/mask + * fedc.ba98.7654.3210 + * 00|| |||| |||| |||CH1_RELAY + * || |||| |||| ||CH1_OPT + * || |||| |||| |CH2_RELAY + * || |||| |||| CH2_OPT + * || |||| |||OUT_1 + * || |||| ||OUT_2 + * || |||| |OUT_3 + * || |||| OUT_4 + * || |||LED_MAIN_R + * || ||LED_MAIN_G + * || |LED_CH1_R + * || LED_CH1_G + * |LED_CH2_R + * LED_CH2_G + */ + +enum labsw_bit_get0 { + LABSW_IN1 = 1, + LABSW_IN2 = 2, + LABSW_IN3 = 4, + LABSW_IN4 = 8, +}; + +enum labsw_bit_get1 { + LABSW_BUT_MAIN = 1, + LABSW_BUT_CH1 = 2, + LABSW_BUT_CH2 = 4, +}; + +enum labsw_bit_set { + LABSW_CH1_RELAY = 0x0001, + LABSW_CH1_OPT = 0x0002, + LABSW_CH2_RELAY = 0x0004, + LABSW_CH2_OPT = 0x0008, + LABSW_OUT1 = 0x0010, + LABSW_OUT2 = 0x0020, + LABSW_OUT3 = 0x0040, + LABSW_OUT4 = 0x0080, + LABSW_MAIN_R = 0x0100, + LABSW_MAIN_G = 0x0200, + LABSW_CH1_R = 0x0400, + LABSW_CH1_G = 0x0800, + LABSW_CH2_R = 0x1000, + LABSW_CH2_G = 0x2000, +}; + +void ep0_init(void); + +#endif /* !EP0_H */ diff --git a/labsw/fw/usb-id.h b/labsw/fw/include/labsw/usb-id.h similarity index 100% rename from labsw/fw/usb-id.h rename to labsw/fw/include/labsw/usb-id.h diff --git a/labsw/fw/labsw.c b/labsw/fw/labsw.c index 459e667..d92fa1f 100644 --- a/labsw/fw/labsw.c +++ b/labsw/fw/labsw.c @@ -18,6 +18,39 @@ #include "config.h" #include "io.h" +#include "labsw/ep0.h" + + +int local = 1; + + +#define DEBOUNCE_CYCLES 10 + + +#define IS_ON(ch) (CH##ch##_RELAY || !CH##ch##_OPT) + +#define LED_R_COLOR_R 1 +#define LED_R_COLOR_G 0 +#define LED_R_COLOR_OFF 0 +#define LED_G_COLOR_R 0 +#define LED_G_COLOR_G 1 +#define LED_G_COLOR_OFF 0 + +#define LED(ch, color) \ + do { \ + LED_##ch##_R = LED_R_COLOR_##color; \ + LED_##ch##_G = LED_G_COLOR_##color; \ + } while (0) + +#define TURN(ch, on) \ + do { \ + CH##ch##_RELAY = on; \ + CH##ch##_OPT = !on; \ + if (on) \ + LED(CH##ch, R); \ + else \ + LED(CH##ch, G); \ + } while (0) static void init_io(void) @@ -26,60 +59,94 @@ static void init_io(void) P1SKIP = 0xff; P2SKIP = 0xff; + /* @@@ we need this while using the boot loader of cntr */ + P0MDOUT = 0; + P1MDOUT = 0; + P2MDOUT = 0; + LED_MAIN_R_MODE |= 1 << LED_MAIN_R_BIT; LED_MAIN_G_MODE |= 1 << LED_MAIN_G_BIT; LED_CH1_R_MODE |= 1 << LED_CH1_R_BIT; LED_CH1_G_MODE |= 1 << LED_CH1_G_BIT; LED_CH2_R_MODE |= 1 << LED_CH2_R_BIT; LED_CH2_G_MODE |= 1 << LED_CH2_G_BIT; + CH1_RELAY = 0; CH2_RELAY = 0; CH1_RELAY_MODE |= 1 << CH1_RELAY_BIT; CH2_RELAY_MODE |= 1 << CH2_RELAY_BIT; - - /* @@@ we need this while using the boot loader of cntr */ - CH1_OPT_MODE &= ~(1 << CH1_OPT_BIT); - CH2_OPT_MODE &= ~(1 << CH2_OPT_BIT); } void main(void) { + int debounce_main = 0, last_main = 0, but_main = 0; + int debounce_ch1 = 0, last_ch1 = 0, but_ch1 = 0; + int debounce_ch2 = 0, last_ch2 = 0, but_ch2 = 0; init_io(); usb_init(); -// ep0_init(); + ep0_init(); + + LED(MAIN, G); + TURN(1, 0); + TURN(2, 0); while (1) { - if (!BUT_MAIN) { - LED_MAIN_R = 1; - LED_MAIN_G = 0; - } else { - LED_MAIN_R = 0; - LED_MAIN_G = 1; + if (debounce_main) + debounce_main--; + else { + last_main = but_main; + but_main = !BUT_MAIN; + if (last_main != but_main) + debounce_main = DEBOUNCE_CYCLES; } - if (!BUT_CH1) { - LED_CH1_R = 1; - LED_CH1_G = 0; - CH1_RELAY = 1; - CH1_OPT = 0; - } else { - LED_CH1_R = 0; - LED_CH1_G = 1; - CH1_RELAY = 0; - CH1_OPT = 1; + + if (debounce_ch1) + debounce_ch1--; + else { + last_ch1 = but_ch1; + but_ch1 = !BUT_CH1; + if (last_ch1 != but_ch1) + debounce_ch1 = DEBOUNCE_CYCLES; } - if (!BUT_CH2) { - LED_CH2_R = 1; - LED_CH2_G = 0; - CH2_RELAY = 1; - CH2_OPT = 0; - } else { - LED_CH2_R = 0; - LED_CH2_G = 1; - CH2_RELAY = 0; - CH2_OPT = 1; + + if (debounce_ch2) + debounce_ch2--; + else { + last_ch2 = but_ch2; + but_ch2 = !BUT_CH2; + if (last_ch2 != but_ch2) + debounce_ch2 = DEBOUNCE_CYCLES; } + + if (but_main && !last_main) { + if (local) { + TURN(1, 0); + TURN(2, 0); + } + local = 1; + } + + if (local) { + LED(MAIN, G); + if (IS_ON(1)) + TURN(1, 1); + else + TURN(1, 0); + if (IS_ON(2)) + TURN(2, 1); + else + TURN(2, 0); + } + + if (local) { + if (but_ch1 && !last_ch1) + TURN(1, !IS_ON(1)); + if (but_ch2 && !last_ch2) + TURN(2, !IS_ON(2)); + } + usb_poll(); } }