mirror of
https://github.com/mon/PocketVoltex.git
synced 2026-09-22 22:57:58 +03:00
Much improved LEDs and persistant knob LEDs
This commit is contained in:
@@ -28,6 +28,8 @@
|
||||
#define G 1
|
||||
#define B 0
|
||||
|
||||
static volatile uint8_t leds_frontbuffer[LED_PHYSICAL_COUNT];
|
||||
|
||||
void led_init() {
|
||||
// all GNDs low level for high impedence or gnd
|
||||
GND_PORT &= ~GND_MASK;
|
||||
@@ -39,7 +41,8 @@ void led_init() {
|
||||
// all LEDs output
|
||||
LED_DDR |= LED_MASK;
|
||||
|
||||
memset((uint8_t*)leds, 0, LED_PHYSICAL_COUNT);
|
||||
memset(leds, 0, LED_PHYSICAL_COUNT);
|
||||
memset((uint8_t*)leds_frontbuffer, 0, LED_PHYSICAL_COUNT);
|
||||
|
||||
// 64 light levels * 60Hz update * 4 different GND pins = 15360Hz
|
||||
// 520 clock cycles for our interrupt handler
|
||||
@@ -54,6 +57,10 @@ void led_init() {
|
||||
TIFR0 = _BV(OCF0A);
|
||||
}
|
||||
|
||||
void led_commit(void) {
|
||||
memcpy((uint8_t*)leds_frontbuffer, leds, LED_PHYSICAL_COUNT);
|
||||
}
|
||||
|
||||
void led_set(uint8_t num, uint8_t r, uint8_t g, uint8_t b) {
|
||||
uint8_t offset = num * 3;
|
||||
leds[offset+R] = r;
|
||||
@@ -71,6 +78,33 @@ void led_set_max(uint8_t num, uint8_t r, uint8_t g, uint8_t b) {
|
||||
leds[offset+B] = b;
|
||||
}
|
||||
|
||||
// Applies a crossfade between the current colour and an overlay colour with a given strength
|
||||
void led_fade_over(uint8_t num, uint8_t r, uint8_t g, uint8_t b, uint8_t strength) {
|
||||
uint8_t offset = num * 3;
|
||||
// going outside max val for a signed int8
|
||||
int16_t scales[3];
|
||||
// get colour distances
|
||||
scales[R] = r - leds[offset+R];
|
||||
scales[G] = g - leds[offset+G];
|
||||
scales[B] = b - leds[offset+B];
|
||||
for(uint8_t i = 0; i < 3; i++) {
|
||||
// perform scaling with div0 check
|
||||
if(scales[i] == 0) {
|
||||
scales[i] = BRIGHTNESS_LEVELS;
|
||||
} else {
|
||||
// won't ever be 0, don't check later
|
||||
scales[i] = BRIGHTNESS_LEVELS / scales[i];
|
||||
}
|
||||
int16_t new = leds[offset+i] + strength/scales[i];
|
||||
// Integer division strikes again
|
||||
if(new > BRIGHTNESS_MAX)
|
||||
new = BRIGHTNESS_MAX;
|
||||
if(new < 0)
|
||||
new = 0;
|
||||
leds[offset+i] = new;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -111,7 +145,7 @@ ISR(TIMER0_COMPA_vect) {
|
||||
// This saves us doing a costly dynamic _BV()
|
||||
static uint8_t currentGndMask = 0;
|
||||
static uint8_t brightness = BRIGHTNESS_LEVELS - BRIGHTNESS_INCREMENT;
|
||||
static volatile uint8_t* offset = &leds[0];
|
||||
static volatile uint8_t* offset = &leds_frontbuffer[0];
|
||||
|
||||
uint8_t out = 0;
|
||||
|
||||
@@ -121,7 +155,7 @@ ISR(TIMER0_COMPA_vect) {
|
||||
currentGnd = 0;
|
||||
// Because we work backwards start at the high end and shift down
|
||||
currentGndMask = _BV(7);
|
||||
offset = &leds[0];
|
||||
offset = &leds_frontbuffer[0];
|
||||
brightness += BRIGHTNESS_INCREMENT;
|
||||
// brightness rolls over cleanly due to being a multiple
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ typedef struct {
|
||||
|
||||
// Arranged left to right, top to bottom
|
||||
// LED order is BGR...BGR
|
||||
volatile uint8_t leds[LED_PHYSICAL_COUNT];
|
||||
uint8_t leds[LED_PHYSICAL_COUNT];
|
||||
|
||||
// Maps BT/FX keys to their associated LED
|
||||
// Order is BT-1-4, FX-L, FX-R
|
||||
@@ -37,8 +37,10 @@ static const PROGMEM uint8_t ledLeftCircleMap[] = {0, 2, 4, 6};
|
||||
static const PROGMEM uint8_t ledRightCircleMap[] = {7, 5, 3, 1};
|
||||
|
||||
void led_init(void);
|
||||
void led_commit(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_fade_over(uint8_t num, uint8_t r, uint8_t g, uint8_t b, uint8_t strength);
|
||||
void led_set_all(uint8_t r, uint8_t g, uint8_t b);
|
||||
void led_set_indiv(uint8_t num, uint8_t val);
|
||||
|
||||
|
||||
@@ -41,19 +41,19 @@ typedef struct {
|
||||
// OPTIONS SHOULD BE: blue, pink, green, yellow
|
||||
static KnobLights knobs[2] = {
|
||||
// Aqua, mid left LEDs
|
||||
{{0,1,1}, {2,3}, {BRIGHTNESS_LEVELS/2, BRIGHTNESS_LEVELS/2}},
|
||||
{{0,BRIGHTNESS_MAX,BRIGHTNESS_MAX}, {2,3}, {BRIGHTNESS_LEVELS/2, BRIGHTNESS_LEVELS/2}},
|
||||
// Pink, mid right LEDs
|
||||
{{1,0,1}, {0,1}, {BRIGHTNESS_LEVELS/2, BRIGHTNESS_LEVELS/2}}
|
||||
{{BRIGHTNESS_MAX,0,BRIGHTNESS_MAX}, {0,1}, {BRIGHTNESS_LEVELS/2, BRIGHTNESS_LEVELS/2}}
|
||||
};
|
||||
|
||||
void led_knob_light_indiv(KnobLights* knob, const uint8_t* map);
|
||||
|
||||
uint8_t led_on_frame(void) {
|
||||
return ++frameCounter >= LED_MS_PER_FRAME;
|
||||
}
|
||||
|
||||
// Called every 1ms
|
||||
void led_frame(void) {
|
||||
if(++frameCounter < LED_MS_PER_FRAME) {
|
||||
return;
|
||||
}
|
||||
|
||||
void led_animate(void) {
|
||||
frameCounter = 0;
|
||||
|
||||
switch(animMode) {
|
||||
@@ -113,19 +113,17 @@ void led_frame(void) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Knob lights, what shall I do with you?
|
||||
led_set_all(0,0,0);
|
||||
led_knob_light_indiv(&knobs[0], ledLeftCircleMap);
|
||||
led_knob_light_indiv(&knobs[1], ledRightCircleMap);
|
||||
}
|
||||
|
||||
void led_knob_light_indiv(KnobLights* knob, const uint8_t* map) {
|
||||
for(uint8_t led = 0; led < 2; led++) {
|
||||
uint8_t r = knob->levels[led] * knob->rgb[0];
|
||||
uint8_t g = knob->levels[led] * knob->rgb[1];
|
||||
uint8_t b = knob->levels[led] * knob->rgb[2];
|
||||
uint8_t r = knob->rgb[0];
|
||||
uint8_t g = knob->rgb[1];
|
||||
uint8_t b = knob->rgb[2];
|
||||
//led_set_max(ledCircleMap[knobs[i].leds[led]], r, g, b);
|
||||
led_set(pgm_read_byte(&map[knob->leds[led]]), r, g, b);
|
||||
led_fade_over(pgm_read_byte(&map[knob->leds[led]]), r, g, b, knob->levels[led]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ enum LEDMode {
|
||||
BREATHE,
|
||||
};
|
||||
|
||||
void led_frame(void);
|
||||
uint8_t led_on_frame(void);
|
||||
void led_animate(void);
|
||||
void led_anim_flash(void);
|
||||
void led_anim_follower(void);
|
||||
void led_knobs_update(int8_t left, int8_t right);
|
||||
|
||||
@@ -38,6 +38,7 @@ static uint8_t PrevInputsHIDReportBuffer[MAX(sizeof(Keyboard_Report_t), sizeof(U
|
||||
static uint8_t PrevLEDHIDReportBuffer[sizeof(LED_Report_t)];
|
||||
|
||||
static uint8_t sendKeyboard = 0;
|
||||
static uint8_t updateLEDs = 1;
|
||||
|
||||
/** 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
|
||||
@@ -181,6 +182,12 @@ int main(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(updateLEDs) {
|
||||
updateLEDs = 0;
|
||||
led_animate();
|
||||
led_commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,7 +319,7 @@ void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDI
|
||||
uint8_t offset = i+2;
|
||||
for(uint8_t j = 0; j < 3; j++) {
|
||||
// cast away the volatile for faster ops
|
||||
((uint8_t*)leds)[i++] = LEDReport->mainLights[offset--];
|
||||
leds[i++] = LEDReport->mainLights[offset--];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,6 +350,7 @@ void EVENT_USB_Device_Connect(void)
|
||||
void EVENT_USB_Device_Disconnect(void)
|
||||
{
|
||||
led_set_all(0,0,0);
|
||||
led_commit();
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Configuration Changed event. */
|
||||
@@ -371,7 +379,11 @@ void EVENT_USB_Device_StartOfFrame(void)
|
||||
HID_Device_MillisecondElapsed(&LED_HID_Interface);
|
||||
|
||||
if(hidTimeout > HID_LED_TIMEOUT) {
|
||||
led_frame();
|
||||
// we use a sentinel since this is actually inside an interrupt!
|
||||
// less LED flicker if ran outside
|
||||
if(led_on_frame()) {
|
||||
updateLEDs = 1;
|
||||
}
|
||||
} else {
|
||||
hidTimeout++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user