From 35f8c5216985096a665dae75e0276e0086fb256b Mon Sep 17 00:00:00 2001 From: William Toohey Date: Sun, 30 Oct 2016 02:09:42 +1000 Subject: [PATCH] Working LEDs --- Firmware/Keyboard/Config.c | 2 +- Firmware/Keyboard/Descriptors.c | 131 ++++++++++++++++++-------------- Firmware/Keyboard/Descriptors.h | 10 ++- Firmware/Keyboard/Keyboard.c | 55 +++++++++++--- Firmware/Keyboard/LED.c | 13 +--- Firmware/Keyboard/LED.h | 16 ++++ 6 files changed, 144 insertions(+), 83 deletions(-) diff --git a/Firmware/Keyboard/Config.c b/Firmware/Keyboard/Config.c index 100e7c3..254e3d7 100644 --- a/Firmware/Keyboard/Config.c +++ b/Firmware/Keyboard/Config.c @@ -3,7 +3,7 @@ #include #include -#define MAGIC_NUMBER 43 +#define MAGIC_NUMBER 42 static sdvx_config_t defaults PROGMEM = { .switches = { diff --git a/Firmware/Keyboard/Descriptors.c b/Firmware/Keyboard/Descriptors.c index 085cc1d..95dcfe9 100644 --- a/Firmware/Keyboard/Descriptors.c +++ b/Firmware/Keyboard/Descriptors.c @@ -18,77 +18,48 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM GenericReport[] = HID_RI_USAGE_PAGE(16, 0xFFDC), /* Vendor Page 0xDC */ HID_RI_USAGE(8, 0xFB), /* Vendor Usage 0xFB */ HID_RI_COLLECTION(8, 0x01), /* Vendor Usage 1 */ - HID_RI_USAGE(8, 0x02), /* Vendor Usage 2 */ + // Global Items HID_RI_LOGICAL_MINIMUM(8, 0x00), HID_RI_LOGICAL_MAXIMUM(8, 0xFF), HID_RI_REPORT_SIZE(8, 8), HID_RI_REPORT_COUNT(8, CONFIG_BYTES), + + // Write config + HID_RI_USAGE(8, 0x02), /* Vendor Usage 2 */ HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), + // Read config HID_RI_USAGE(8, 0x02), /* Vendor Usage 2 */ - HID_RI_LOGICAL_MINIMUM(8, 0x00), - HID_RI_LOGICAL_MAXIMUM(8, 0xFF), - HID_RI_REPORT_SIZE(8, 8), - HID_RI_REPORT_COUNT(8, CONFIG_BYTES), HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), HID_RI_END_COLLECTION(0), }; const USB_Descriptor_HIDReport_Datatype_t PROGMEM LEDReport[] = { - HID_RI_USAGE_PAGE(16, 0xFFDE), /* Vendor Page 0xDC */ - HID_RI_USAGE(8, 0xFE), /* Vendor Usage 0xFB */ - HID_RI_COLLECTION(8, 0x03), /* Vendor Usage 1 */ - HID_RI_USAGE(8, 0x04), /* Vendor Usage 2 */ - HID_RI_LOGICAL_MINIMUM(8, 0x00), - HID_RI_LOGICAL_MAXIMUM(8, 0xFF), - HID_RI_REPORT_SIZE(8, 8), - HID_RI_REPORT_COUNT(8, CONFIG_BYTES), - HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), + HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */ + HID_RI_USAGE(8, 0x00), /* Undefined */ + HID_RI_COLLECTION(8, 0x01), /* Application */ + // Global Items + HID_RI_REPORT_COUNT(8, LED_TOTAL_COUNT), + HID_RI_REPORT_SIZE(8, 8), + HID_RI_LOGICAL_MINIMUM(8, 0), + HID_RI_LOGICAL_MAXIMUM(8, BRIGHTNESS_LEVELS-1), + HID_RI_USAGE_PAGE(8, 0x0A), // Ordinals - HID_RI_USAGE(8, 0x04), /* Vendor Usage 2 */ - HID_RI_LOGICAL_MINIMUM(8, 0x00), - HID_RI_LOGICAL_MAXIMUM(8, 0xFF), - HID_RI_REPORT_SIZE(8, 8), - HID_RI_REPORT_COUNT(8, CONFIG_BYTES), - HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), - HID_RI_END_COLLECTION(0), - //HID_RI_USAGE_PAGE(16, 0xFF00), - // HID_RI_USAGE(8, 0x01), - // HID_RI_COLLECTION(8, 0x01), - // HID_RI_USAGE(8, 0x02), - // HID_RI_LOGICAL_MINIMUM(8, 0), - // HID_RI_LOGICAL_MAXIMUM(8, 64), - // HID_RI_REPORT_SIZE(8, 8), - // HID_RI_REPORT_COUNT(8, 1), - // HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), - // - // HID_RI_USAGE(8, 0x02), - // HID_RI_LOGICAL_MINIMUM(8, 0), - // HID_RI_LOGICAL_MAXIMUM(8, 64), - // HID_RI_REPORT_SIZE(8, 8), - // HID_RI_REPORT_COUNT(8, 1), - // HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), - // HID_RI_END_COLLECTION(0) - //HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */ - //HID_RI_USAGE(8, 0x4b), /* Generic indicator */ - //HID_RI_COLLECTION(8, 0x01), /* Application */ - // // Lights aren't the full 256 shades - // HID_RI_USAGE(8, 0x4B), /* Generic indicator 1 */ - // HID_RI_LOGICAL_MINIMUM(8, 0), - // HID_RI_LOGICAL_MAXIMUM(8, 64), - // HID_RI_USAGE_PAGE(8, 0x0A), /* Ordinals */ - // - // HID_RI_USAGE(8, 1), /* Instance 1 */ - // HID_RI_COLLECTION(8, 0x02), /* Logical */ - // HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */ - // - // HID_RI_REPORT_SIZE(8, 8), - // HID_RI_REPORT_COUNT(8, 8), - // HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), - // HID_RI_END_COLLECTION(0), - // - //HID_RI_END_COLLECTION(0), + // Locals repeated for INPUT/OUTPUT + 0x79, STRING_ID_LED_INDIV, //HID_RI_STRING_MINIMUM(8, STRING_ID_LED_INDIV), + 0x89, STRING_ID_LED_INDIV + LED_TOTAL_COUNT, //HID_RI_STRING_MAXIMUM(8, STRING_ID_LED_INDIV + LED_COUNT), + HID_RI_USAGE_MINIMUM(8, 1), // LED 1 + HID_RI_USAGE_MAXIMUM(8, LED_TOTAL_COUNT), // LED 8 + HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), + + // INPUT is also needed to be recognised by Bemanitools + 0x79, STRING_ID_LED_INDIV, //HID_RI_STRING_MINIMUM(8, STRING_ID_LED_INDIV), + 0x89, STRING_ID_LED_INDIV + LED_TOTAL_COUNT, //HID_RI_STRING_MAXIMUM(8, STRING_ID_LED_INDIV + LED_COUNT), + HID_RI_USAGE_MINIMUM(8, 1), // LED 1 + HID_RI_USAGE_MAXIMUM(8, LED_TOTAL_COUNT), // LED 8 + HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), + HID_RI_END_COLLECTION(0), }; /** HID class report descriptor. This is a special descriptor constructed with values from the @@ -224,7 +195,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .SubClass = HID_CSCP_BootSubclass, .Protocol = HID_CSCP_MouseBootProtocol, - .InterfaceStrIndex = NO_DESCRIPTOR + .InterfaceStrIndex = STRING_ID_KNOB }, .HID2_MouseHID = @@ -312,7 +283,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .HIDReportLength = sizeof(LEDReport) }, - .HID4_ReportOUTEndpoint = + .HID4_ReportINEndpoint = { .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, @@ -342,6 +313,39 @@ const USB_Descriptor_String_t PROGMEM ManufacturerString = USB_STRING_DESCRIPTOR const USB_Descriptor_String_t PROGMEM ProductString = USB_STRING_DESCRIPTOR(L"Pocket Voltex"); const USB_Descriptor_String_t PROGMEM ConfigString = USB_STRING_DESCRIPTOR(L"Pocket Voltex Config"); const USB_Descriptor_String_t PROGMEM LEDString = USB_STRING_DESCRIPTOR(L"Pocket Voltex LEDs"); +const USB_Descriptor_String_t PROGMEM KnobString = USB_STRING_DESCRIPTOR(L"Pocket Voltex Knobs"); +const USB_Descriptor_String_t PROGMEM LEDString_indiv[] = { + USB_STRING_DESCRIPTOR(L"L1-B"), + USB_STRING_DESCRIPTOR(L"L1-G"), + USB_STRING_DESCRIPTOR(L"L1-R"), + USB_STRING_DESCRIPTOR(L"L2-B"), + USB_STRING_DESCRIPTOR(L"L2-G"), + USB_STRING_DESCRIPTOR(L"L2-R"), + USB_STRING_DESCRIPTOR(L"L3-B"), + USB_STRING_DESCRIPTOR(L"L3-G"), + USB_STRING_DESCRIPTOR(L"L3-R"), + USB_STRING_DESCRIPTOR(L"L4-B"), + USB_STRING_DESCRIPTOR(L"L4-G"), + USB_STRING_DESCRIPTOR(L"L4-R"), + USB_STRING_DESCRIPTOR(L"L5-B"), + USB_STRING_DESCRIPTOR(L"L5-G"), + USB_STRING_DESCRIPTOR(L"L5-R"), + USB_STRING_DESCRIPTOR(L"L6-B"), + USB_STRING_DESCRIPTOR(L"L6-G"), + USB_STRING_DESCRIPTOR(L"L6-R"), + USB_STRING_DESCRIPTOR(L"L7-B"), + USB_STRING_DESCRIPTOR(L"L7-G"), + USB_STRING_DESCRIPTOR(L"L7-R"), + USB_STRING_DESCRIPTOR(L"L8-B"), + USB_STRING_DESCRIPTOR(L"L8-G"), + USB_STRING_DESCRIPTOR(L"L8-R"), + USB_STRING_DESCRIPTOR(L"BT-A"), + USB_STRING_DESCRIPTOR(L"BT-B"), + USB_STRING_DESCRIPTOR(L"BT-C"), + USB_STRING_DESCRIPTOR(L"BT-D"), + USB_STRING_DESCRIPTOR(L"FX-L"), + USB_STRING_DESCRIPTOR(L"FX-R"), +}; /** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" * documentation) by the application code so that the address and size of a requested descriptor can be given @@ -392,6 +396,15 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, Address = &LEDString; Size = pgm_read_byte(&LEDString.Header.Size); break; + case STRING_ID_KNOB: + Address = &KnobString; + Size = pgm_read_byte(&KnobString.Header.Size); + break; + default: + if(DescriptorNumber >= STRING_ID_LED_INDIV) { + Address = &(LEDString_indiv[STRING_ID_LED_INDIV - DescriptorNumber]); + Size = pgm_read_byte(&LEDString_indiv[STRING_ID_LED_INDIV - DescriptorNumber].Header.Size); + } } break; diff --git a/Firmware/Keyboard/Descriptors.h b/Firmware/Keyboard/Descriptors.h index 84f2e03..375809e 100644 --- a/Firmware/Keyboard/Descriptors.h +++ b/Firmware/Keyboard/Descriptors.h @@ -71,7 +71,7 @@ // LED HID Interface for pretty lights USB_Descriptor_Interface_t HID4_Interface; USB_HID_Descriptor_HID_t HID4_LEDHID; - USB_Descriptor_Endpoint_t HID4_ReportOUTEndpoint; + USB_Descriptor_Endpoint_t HID4_ReportINEndpoint; } USB_Descriptor_Configuration_t; /** Enum for the device interface descriptor IDs within the device. Each interface descriptor @@ -96,7 +96,9 @@ STRING_ID_Manufacturer = 1, /**< Manufacturer string ID */ STRING_ID_Product = 2, /**< Product string ID */ STRING_ID_Config = 3, /**< Config string ID */ - STRING_ID_LED = 4 /**< LED string ID */ + STRING_ID_KNOB = 4, + STRING_ID_LED = 5, /**< LED string ID */ + STRING_ID_LED_INDIV = 6, }; /* Macros: */ @@ -106,12 +108,12 @@ #define GENERIC_EPADDR (ENDPOINT_DIR_IN | 3) - #define LED_EPADDR (ENDPOINT_DIR_OUT | 4) + #define LED_EPADDR (ENDPOINT_DIR_IN | 4) #define KEYBOARD_EPSIZE 8 #define MOUSE_EPSIZE 8 #define GENERIC_EPSIZE CONFIG_BYTES - #define LED_EPSIZE LED_COUNT + #define LED_EPSIZE LED_TOTAL_COUNT /* Function Prototypes: */ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, diff --git a/Firmware/Keyboard/Keyboard.c b/Firmware/Keyboard/Keyboard.c index 3c8264a..4b3efad 100644 --- a/Firmware/Keyboard/Keyboard.c +++ b/Firmware/Keyboard/Keyboard.c @@ -12,11 +12,17 @@ typedef struct uint8_t KeyCode[SWITCH_COUNT]; // Length determined by the number of keys that can be reported } Keyboard_Report_t; +typedef struct +{ + uint8_t mainLights[LED_RAW_COUNT]; + uint8_t btFx[6]; +} LED_Report_t; + /** Buffer to hold the previously generated Keyboard HID report, for comparison purposes inside the HID class driver. */ static uint8_t PrevKeyboardHIDReportBuffer[sizeof(Keyboard_Report_t)]; static uint8_t PrevMouseHIDReportBuffer[sizeof(USB_MouseReport_Data_t)]; -static uint8_t PrevGenericHIDReportBuffer[CONFIG_BYTES]; -static uint8_t PrevLEDHIDReportBuffer[LED_COUNT]; +static uint8_t PrevGenericHIDReportBuffer[sizeof(sdvx_config_t)]; +static uint8_t PrevLEDHIDReportBuffer[sizeof(LED_Report_t)]; /** LUFA HID Class driver interface configuration and state information. This structure is * passed to all HID Class driver functions, so that multiple instances of the same class @@ -172,11 +178,22 @@ int main(void) GlobalInterruptEnable(); // Blink to show we're not in bootloader - for(uint8_t i = 0; i < LED_COUNT; i++) { - led_set(i, 32, 0, 0); - _delay_ms(100); - led_set(i, 0, 0, 0); + for(uint8_t flash = 0; flash < BRIGHTNESS_LEVELS; flash++) { + for(uint8_t i = 0; i < LED_COUNT; i++) { + uint8_t bright = ledLogCurve[flash]; + led_set(i, bright, bright/2, 0); + _delay_us(500); + } } + // NOTE: signed + for(int8_t flash = BRIGHTNESS_LEVELS; flash >= 0; flash--) { + for(uint8_t i = 0; i < LED_COUNT; i++) { + uint8_t bright = ledLogCurve[flash]; + led_set(i, bright, bright/2, 0); + _delay_us(500); + } + } + // Not in SetupHardware so we don't time out USB_Init(); @@ -280,6 +297,11 @@ bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDIn memcpy(ConfigReport, &sdvxConfig, sizeof(sdvx_config_t)); *ReportSize = CONFIG_BYTES; return true; + } else if(HIDInterfaceInfo == &LED_HID_Interface) { + uint8_t* LEDReport = (uint8_t*)ReportData; + memcpy(LEDReport, (uint8_t*)leds, LED_TOTAL_COUNT); + *ReportSize = LED_TOTAL_COUNT; + return true; } *ReportSize = 0; return false; @@ -298,8 +320,7 @@ void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDI const uint8_t ReportID, const uint8_t ReportType, const void* ReportData, - const uint16_t ReportSize) -{ + const uint16_t ReportSize) { if(HIDInterfaceInfo == &Generic_HID_Interface && ReportType == HID_REPORT_ITEM_Out) { uint8_t* ConfigReport = (uint8_t*)ReportData; // So we can upgrade firmware without having to hit the button @@ -308,8 +329,22 @@ void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDI } SetConfig(ConfigReport); } else if(HIDInterfaceInfo == &LED_HID_Interface && ReportType == HID_REPORT_ITEM_Out) { - uint8_t* LEDReport = (uint8_t*)ReportData; - led_set_indiv(0, LEDReport[0]); + LED_Report_t* LEDReport = (LED_Report_t*)ReportData; + memcpy((uint8_t*)leds, LEDReport->mainLights, LED_RAW_COUNT); + + // Keep normal lights but override when we get flashes on BT or FX + // BT LEDs flash pure white + for(uint8_t i = 0; i < 4; i++) { + if(LEDReport->btFx[i]) { + led_set(ledMap[i], BRIGHTNESS_LEVELS, BRIGHTNESS_LEVELS, BRIGHTNESS_LEVELS); + } + } + // FX LEDs flash orange + for(uint8_t i = 4; i < 6; i++) { + if(LEDReport->btFx[i]) { + led_set(ledMap[i], BRIGHTNESS_LEVELS, BRIGHTNESS_LEVELS/4, 0); + } + } } } diff --git a/Firmware/Keyboard/LED.c b/Firmware/Keyboard/LED.c index 3bd1a03..c95cbaf 100644 --- a/Firmware/Keyboard/LED.c +++ b/Firmware/Keyboard/LED.c @@ -1,6 +1,5 @@ #include "LED.h" -#define BRIGHTNESS_LEVELS 64 #define GND_COUNT 4 // RGB * 2 #define LED_PINS 6 @@ -20,10 +19,6 @@ #define G 1 #define B 0 -// Arranged left to right, top to bottom -// LED order is BGR...BGR -static volatile uint8_t leds[LED_COUNT * 3]; - void led_init() { // all GNDs low level for high impedence or gnd GND_PORT &= ~GND_MASK; @@ -35,9 +30,7 @@ void led_init() { // all LEDs output LED_DDR |= LED_MASK; - for(uint8_t i = 0; i < LED_COUNT * 3; i++) { - leds[i] = 0; - } + memset((uint8_t*)leds, 0, LED_RAW_COUNT); // 64 light levels * 60Hz update * 4 different GND pins = 15360Hz // 520 clock cycles for our interrupt handler @@ -46,7 +39,9 @@ void led_init() { // clk/8 prescaler TCCR0B = _BV(CS01); // 0.16% error on above calculation - OCR0A = 64; + //OCR0A = 64; // 60Hz + OCR0A = 77; // 50Hz + //OCR0A = 48; // 80Hz // Enable interrupt on OCR0A TIMSK0 = _BV(OCIE0A); // Clear interrupt diff --git a/Firmware/Keyboard/LED.h b/Firmware/Keyboard/LED.h index 346b8fc..dfeddd6 100644 --- a/Firmware/Keyboard/LED.h +++ b/Firmware/Keyboard/LED.h @@ -4,8 +4,24 @@ #include #include #include +#include #define LED_COUNT 8 +#define LED_RAW_COUNT (LED_COUNT*3) +// BT + FX +#define LED_VIRTUAL_COUNT 6 +#define LED_TOTAL_COUNT (LED_RAW_COUNT + LED_VIRTUAL_COUNT) +#define BRIGHTNESS_LEVELS 64 + +const static uint8_t ledLogCurve[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 17, 20, 23, 25, 28, 31, 34, 37, 40, 43, 45, 48, 50, 52, 53, 55, 56, 57, 58, 59, 60, 60, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63, 63}; + +// Arranged left to right, top to bottom +// LED order is BGR...BGR +volatile uint8_t leds[LED_RAW_COUNT]; + +// Maps BT/FX keys to their associated LED +// Order is BT-1-4, FX-L, FX-R +static const uint8_t ledMap[] = {2, 0, 1, 3, 6, 7}; void led_init(void); void led_set(uint8_t num, uint8_t r, uint8_t g, uint8_t b);