LED patterns, minor improvements

This commit is contained in:
William Toohey
2016-12-11 22:56:23 +10:00
parent 03515b622c
commit 4141f5f008
11 changed files with 331 additions and 48 deletions
+6 -3
View File
@@ -7,9 +7,6 @@
// For ease of code sharing with the OsuPad
#define SWITCH_COUNT 7
// essentially sizeof the config type + 1 for some reason
// TODO: what is the reason
#define CONFIG_BYTES (SWITCH_COUNT + 4)
#define MAGIC_RESET_NUMBER 42
#define FIRMWARE_VERSION 1
@@ -19,8 +16,14 @@ typedef struct {
bool ledsOn;
uint8_t debounce;
uint8_t version;
// used to reboot into programming mode
uint8_t reboot;
} sdvx_config_t;
// + 1 for some reason
// TODO: what is the reason
#define CONFIG_BYTES sizeof(sdvx_config_t)
extern sdvx_config_t sdvxConfig;
extern void InitConfig(void);
+29 -2
View File
@@ -22,6 +22,7 @@
import sys
from pywinusb import hid
from intelhex import IntelHex
import time
# Device information table
@@ -50,6 +51,25 @@ def get_hid_device_handle():
else:
return valid_hid_devices[0]
def bootloader_boot():
hid_device_filter = hid.HidDeviceFilter(vendor_id=0x16D0,
product_id=0x0A6D,
product_name="Pocket Voltex Config")
valid_hid_devices = hid_device_filter.get_devices()
if len(valid_hid_devices) is 0:
return False
else:
try:
hid_device = valid_hid_devices[0]
hid_device.open()
output_report_data = [0,0,0,0,0,0,0,0,0,0,0,42]
hid_device.send_output_report(output_report_data)
finally:
hid_device.close()
return True
def send_page_data(hid_device, address, data):
# Bootloader page data should be the HID Report ID (always zero) followed
@@ -66,8 +86,15 @@ def program_device(hex_data, device_info):
hid_device = get_hid_device_handle()
if hid_device is None:
print("No valid HID device found.")
sys.exit(1)
if not bootloader_boot():
print("No valid HID device found.")
sys.exit(1)
print("Rebooted to bootloader")
time.sleep(6)
hid_device = get_hid_device_handle()
if hid_device is None:
print("No valid HID device found.")
sys.exit(1)
try:
hid_device.open()
+6 -5
View File
@@ -38,26 +38,27 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM LEDReport[] =
{
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
HID_RI_USAGE(8, 0x00), /* Undefined */
HID_RI_COLLECTION(8, 0x01), /* Application */
// Global Items
HID_RI_COLLECTION(8, 0x01), /* Application */
// Globals
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
// Locals repeated for INPUT/OUTPUT
// Locals
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_USAGE_MAXIMUM(8, LED_TOTAL_COUNT), // LED 8 + buttons
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
//HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
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_USAGE_MAXIMUM(8, LED_TOTAL_COUNT), // LED 8 + buttons
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
HID_RI_END_COLLECTION(0),
};
+1 -1
View File
@@ -110,7 +110,7 @@
#define LED_EPADDR (ENDPOINT_DIR_IN | 4)
#define KEYBOARD_EPSIZE 8
#define KEYBOARD_EPSIZE SWITCH_COUNT + 2
#define MOUSE_EPSIZE 8
#define GENERIC_EPSIZE CONFIG_BYTES
#define LED_EPSIZE LED_TOTAL_COUNT
+29
View File
@@ -0,0 +1,29 @@
BRIGHTNESS_LEVELS = 64
STAGES = 3
LEDS = 8
RING = [0,2,4,6,7,5,3,1]
TOTAL = STAGES * BRIGHTNESS_LEVELS
INTERVAL = TOTAL / LEDS
RISE = range(0,BRIGHTNESS_LEVELS)
FALL = range(BRIGHTNESS_LEVELS-1,-1,-1)
OFF = [0]*BRIGHTNESS_LEVELS
R = FALL + OFF + RISE
Rdir = [0, 0, 1]
G = RISE + FALL + OFF
Gdir = [1, 0, 0]
B = OFF + RISE + FALL
Bdir = [0, 1, 0]
print "// Generated by FollowerGen.py"
print "static const uint8_t followStart[][4] = {"
for i in range(LEDS):
# map to the different order in the board
actualIndex = RING.index(i)
offset = INTERVAL * actualIndex
dirOffset = offset / BRIGHTNESS_LEVELS
dir = Rdir[dirOffset] | Gdir[dirOffset] << 1 | Bdir[dirOffset] << 2
print "\t{%d, %d, %d, %s}," % (R[offset], G[offset], B[offset],'{:#05b}'.format(dir))
print "};"
+29 -27
View File
@@ -2,8 +2,15 @@
#include "Config.h"
#include "Encoder.h"
#include "LED.h"
#include "LEDPatterns.h"
#define READ_SWITCH(x) (!(*pins[switches[x].switchPort] & _BV(switches[x].switchPin)))
#define MAGIC_BOOT_KEY 0xDEADBE7A
// offset * word size
#define BOOTLOADER_START_ADDRESS (0x1c00 * 2)
// How long to wait before moving to internal lighting
#define HID_LED_TIMEOUT 5000
typedef struct
{
@@ -127,10 +134,10 @@ static switch_t switches[SWITCH_COUNT] = {
};
static uint8_t switchesChanged = 1;
// Set to max already so we have our init flash
static uint16_t hidTimeout = HID_LED_TIMEOUT;
uint32_t Boot_Key ATTR_NO_INIT;
#define MAGIC_BOOT_KEY 0xDEADBE7A
// offset * word size
#define BOOTLOADER_START_ADDRESS (0x1c00 * 2)
void Bootloader_Jump_Check(void) ATTR_INIT_SECTION(3);
void Bootloader_Jump_Check(void)
@@ -178,25 +185,7 @@ int main(void)
GlobalInterruptEnable();
// Blink to show we're not in bootloader
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();
led_anim_flash();
for (;;)
{
@@ -235,6 +224,8 @@ void SetupHardware()
/* Hardware Initialization */
encoder_init();
led_init();
USB_Init();
}
/** HID class driver callback function for the creation of HID reports to the host.
@@ -287,6 +278,8 @@ bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDIn
MouseReport->X = encoder_get(0);
MouseReport->Y = -encoder_get(1);
led_knobs_update(MouseReport->X, MouseReport->Y);
encoder_set(0, 0);
encoder_set(1, 0);
@@ -297,12 +290,12 @@ 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) {
}/* 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;
@@ -329,6 +322,9 @@ 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) {
// reset our timeout
hidTimeout = 0;
LED_Report_t* LEDReport = (LED_Report_t*)ReportData;
memcpy((uint8_t*)leds, LEDReport->mainLights, LED_RAW_COUNT);
@@ -384,10 +380,16 @@ void EVENT_USB_Device_ControlRequest(void)
/** Event handler for the USB device Start Of Frame event. */
void EVENT_USB_Device_StartOfFrame(void)
{
HID_Device_MillisecondElapsed(&Keyboard_HID_Interface);
HID_Device_MillisecondElapsed(&Keyboard_HID_Interface);
HID_Device_MillisecondElapsed(&Mouse_HID_Interface);
HID_Device_MillisecondElapsed(&Generic_HID_Interface);
HID_Device_MillisecondElapsed(&LED_HID_Interface);
HID_Device_MillisecondElapsed(&Generic_HID_Interface);
HID_Device_MillisecondElapsed(&LED_HID_Interface);
if(hidTimeout > HID_LED_TIMEOUT) {
led_frame();
} else {
hidTimeout++;
}
for(int i = 0; i < SWITCH_COUNT; i++) {
if(switches[i].debounce) {
+22 -6
View File
@@ -15,6 +15,10 @@
#define LED_DDR DDRB
#define LED_MASK (0b111111 << 2)
#define UPDATE_HZ 50
// prescaler is the div8
#define TIMER_COMPARE ((F_CPU / 8 / UPDATE_HZ / GND_COUNT / BRIGHTNESS_LEVELS)-1)
#define R 2
#define G 1
#define B 0
@@ -38,10 +42,7 @@ void led_init() {
TCCR0A = _BV(WGM01);
// clk/8 prescaler
TCCR0B = _BV(CS01);
// 0.16% error on above calculation
//OCR0A = 64; // 60Hz
OCR0A = 77; // 50Hz
//OCR0A = 48; // 80Hz
OCR0A = TIMER_COMPARE;
// Enable interrupt on OCR0A
TIMSK0 = _BV(OCIE0A);
// Clear interrupt
@@ -55,6 +56,22 @@ void led_set(uint8_t num, uint8_t r, uint8_t g, uint8_t b) {
leds[offset+B] = b;
}
void led_set_max(uint8_t num, uint8_t r, uint8_t g, uint8_t b) {
uint8_t offset = num * 3;
if(r > leds[offset+R])
leds[offset+R] = r;
if(g > leds[offset+G])
leds[offset+G] = g;
if(b > leds[offset+B])
leds[offset+B] = b;
}
void led_set_all(uint8_t r, uint8_t g, uint8_t b) {
for(uint8_t i = 0; i < LED_COUNT; i++) {
led_set(i, r, g, b);
}
}
void led_set_indiv(uint8_t num, uint8_t val) {
leds[num] = val;
}
@@ -115,8 +132,7 @@ ISR(TIMER0_COMPA_vect) {
// Turn off before switch
LED_PORT &= ~LED_MASK;
GND_DDR &= ~GND_MASK;
// Enable new ground
GND_DDR |= currentGndMask;
GND_DDR = (GND_DDR & ~GND_MASK) | currentGndMask;
LED_PORT |= out;
}
+15 -2
View File
@@ -13,8 +13,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];
@@ -23,8 +21,23 @@ volatile uint8_t leds[LED_RAW_COUNT];
// Order is BT-1-4, FX-L, FX-R
static const uint8_t ledMap[] = {2, 0, 1, 3, 6, 7};
// map LEDs to run in a circle
static const uint8_t ledCircleMap[] = {0, 2, 4, 6, 7, 5, 3, 1};
void led_init(void);
void led_set(uint8_t num, uint8_t r, uint8_t g, uint8_t b);
void led_set_max(uint8_t num, uint8_t r, uint8_t g, uint8_t b);
void led_set_all(uint8_t r, uint8_t g, uint8_t b);
void led_set_indiv(uint8_t num, uint8_t val);
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};
#endif
+171
View File
@@ -0,0 +1,171 @@
#include "LEDPatterns.h"
static enum LEDMode animMode = NONE;
static uint8_t frameCounter = 0;
// various things for the different modes
static int8_t flash;
static int8_t flashDirection;
typedef struct {
uint8_t value[3];
uint8_t direction;
} RGBFader;
static RGBFader followers[LED_COUNT];
typedef struct {
const uint8_t rgb[3];
uint8_t leds[2];
uint8_t levels[2];
} KnobLights;
static KnobLights knobs[2] = {
// Aqua, top left LEDs
{{0,1,1}, {0,1}, {BRIGHTNESS_LEVELS-1, 0}},
// Pink, top right LEDs
{{1,0,1}, {6,7}, {0, BRIGHTNESS_LEVELS-1}}
};
// Called every 1ms
void led_frame(void) {
if(++frameCounter < LED_MS_PER_FRAME) {
return;
}
frameCounter = 0;
uint8_t followDir;
RGBFader* follow;
switch(animMode) {
case INIT_FLASH:
if(flashDirection) {
flash+=3;
if(flash >= BRIGHTNESS_LEVELS - 1) {
flash = BRIGHTNESS_LEVELS - 1;
flashDirection = 0;
}
} else {
flash-=3;
if(flash <= 0) {
//animMode = NONE;
led_anim_follower();
flash = 0;
}
}
uint8_t bright = ledLogCurve[flash];
led_set_all(bright, bright/2, 0);
break;
case FOLLOWER:
/*for(uint8_t led = 0; led < LED_COUNT; led++) {
follow = followers + led;
followDir = follow->direction;
for(uint8_t i = 0; i < 3; i++) {
if(followDir & 1) {
if(follow->value[i]++ >= BRIGHTNESS_LEVELS - 1) {
follow->value[i] = BRIGHTNESS_LEVELS - 1;
follow->direction <<= 1;
if(follow->direction == 0b1000) {
follow->direction = 0b001;
}
}
} else {
if(follow->value[i] > 0) {
follow->value[i]--;
}
}
followDir >>= 1;
}
led_set(led, follow->value[0], follow->value[1], follow->value[2]);
}*/
break;
case BREATHE:
default:
break;
}
led_set_all(0,0,0);
for(uint8_t i = 0; i < 2; i++) {
for(uint8_t led = 0; led < 2; led++) {
uint8_t r = knobs[i].levels[led] * knobs[i].rgb[0];
uint8_t g = knobs[i].levels[led] * knobs[i].rgb[1];
uint8_t b = knobs[i].levels[led] * knobs[i].rgb[2];
led_set_max(ledCircleMap[knobs[i].leds[led]], r, g, b);
}
}
}
void led_knob_indiv(KnobLights* knob, int8_t value) {
/* This is annoying and repetitive but don't think there's a nicer way */
if(value > 0) {
knob->levels[0] += value;
if(value > knob->levels[1]) {
// Not properly doing rollover since the knob doesn't spin that fast
knob->levels[1] = 0;
} else {
knob->levels[1] -= value;
}
if(knob->levels[0] > BRIGHTNESS_LEVELS) {
knob->levels[0] = 0;
knob->levels[1] = BRIGHTNESS_LEVELS - 1;
knob->leds[1] = knob->leds[0];
if(knob->leds[0] > 0) {
knob->leds[0]--;
} else {
knob->leds[0] = LED_COUNT - 1;
}
}
} else if(value < 0) {
if(-value > knob->levels[0]) {
knob->levels[0] = 0;
} else {
knob->levels[0] += value;
}
knob->levels[1] -= value;
if(knob->levels[1] > BRIGHTNESS_LEVELS) {
knob->levels[0] = BRIGHTNESS_LEVELS - 1;
knob->levels[1] = 0;
knob->leds[0] = knob->leds[1];
knob->leds[1]++;
knob->leds[1] %= LED_COUNT;
}
}
}
void led_knobs_update(int8_t left, int8_t right) {
led_knob_indiv(&knobs[0], left*2);
led_knob_indiv(&knobs[1], right*2);
}
void led_anim_flash(void) {
animMode = INIT_FLASH;
// starting at 2 stops us getting a frame of red
flash = 2;
flashDirection = 1;
}
void led_anim_follower(void) {
// Generated by FollowerGen.py
static const uint8_t followStart[][4] = {
{63, 0, 0, 0b010},
{40, 0, 23, 0b001},
{39, 24, 0, 0b010},
{16, 0, 47, 0b001},
{15, 48, 0, 0b010},
{0, 7, 56, 0b100},
{0, 55, 8, 0b100},
{0, 31, 32, 0b100},
};
animMode = FOLLOWER;
for(uint8_t i = 0; i < LED_COUNT; i++) {
for(uint8_t j = 0; j < 3; j++) {
followers[i].value[j] = followStart[i][j];
}
followers[i].direction = followStart[i][3];
}
}
+22
View File
@@ -0,0 +1,22 @@
#ifndef _LED_PATTERNS_H
#define _LED_PATTERNS_H
#include <stdint.h>
#include "LED.h"
#define LED_FRAMERATE 30
#define LED_MS_PER_FRAME (1000 / LED_FRAMERATE)
enum LEDMode {
NONE = 0,
INIT_FLASH,
FOLLOWER,
BREATHE,
};
void led_frame(void);
void led_anim_flash(void);
void led_anim_follower(void);
void led_knobs_update(int8_t left, int8_t right);
#endif
+1 -2
View File
@@ -18,7 +18,7 @@ F_CPU = 8000000
F_USB = $(F_CPU)
OPTIMIZATION = s
TARGET = Keyboard
SRC = $(TARGET).c Descriptors.c Config.c Encoder.c LED.c $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS)
SRC = $(TARGET).c Descriptors.c Config.c Encoder.c LED.c LEDPatterns.c $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS)
LUFA_PATH = ../LUFA
CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/
LD_FLAGS =
@@ -65,5 +65,4 @@ flashboot:
$(AVRDUDE) -U flash:w:DFU/BootloaderHID.hex:i
flash: all
sleep 1
python DFU/hid_bootloader_loader.py atmega16u2 Keyboard.hex