Working LEDs

This commit is contained in:
William Toohey
2016-10-30 02:09:42 +10:00
parent e79de98ac5
commit 35f8c52169
6 changed files with 144 additions and 83 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#define MAGIC_NUMBER 43
#define MAGIC_NUMBER 42
static sdvx_config_t defaults PROGMEM = {
.switches = {
+72 -59
View File
@@ -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;
+6 -4
View File
@@ -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,
+45 -10
View File
@@ -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);
}
}
}
}
+4 -9
View File
@@ -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
+16
View File
@@ -4,8 +4,24 @@
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>
#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);