diff --git a/firmware/keyboard.h b/firmware/keyboard.h index a545776..33eec9c 100644 --- a/firmware/keyboard.h +++ b/firmware/keyboard.h @@ -45,6 +45,14 @@ void kb__led__set (uint8_t led, float n); // ------- bool kb__led__read (uint8_t led); // ------- +#ifdef ENABLE_LEFT_LED +uint8_t kb__led__flicker (uint8_t led); +uint8_t kb__led__flicker_peek (uint8_t led); +#endif +#ifdef ENABLE_TEENSY_LED +uint8_t kb__led__dbg_blink (uint8_t blinks); +#endif +// ------- void kb__led__all_on (void); void kb__led__all_off (void); void kb__led__all_set (float percent); diff --git a/firmware/keyboard/ergodox/controller/mcp23018.c b/firmware/keyboard/ergodox/controller/mcp23018.c index 7b78714..3a20cd0 100644 --- a/firmware/keyboard/ergodox/controller/mcp23018.c +++ b/firmware/keyboard/ergodox/controller/mcp23018.c @@ -66,6 +66,12 @@ #define TWI_ADDR_WRITE ( (TWI_ADDR<<1) | TW_WRITE ) #define TWI_ADDR_READ ( (TWI_ADDR<<1) | TW_READ ) +#ifdef ENABLE_LEFT_LED +#define LED_11_BIT_SHIFT 7 // in B +#define LED_12_BIT_SHIFT 6 // in B +#define LED_13_BIT_SHIFT 7 // in A +#endif + // ---------------------------------------------------------------------------- /** functions/mcp23018__init/description @@ -91,11 +97,21 @@ uint8_t mcp23018__init(void) { if (ret) goto out; // make sure we got an ACK twi__send(IODIRA); #if OPT__MCP23018__DRIVE_ROWS +#ifndef ENABLE_LEFT_LED twi__send(0b11111111); // IODIRA twi__send(0b11000000); // IODIRB +#else + twi__send(0b01111111); // IODIRA + twi__send(0b00000000); // IODIRB +#endif #elif OPT__MCP23018__DRIVE_COLUMNS +#ifndef ENABLE_LEFT_LED twi__send(0b10000000); // IODIRA twi__send(0b11111111); // IODIRB +#else + twi__send(0b00000000); // IODIRA + twi__send(0b00111111); // IODIRB +#endif #endif twi__stop(); @@ -108,11 +124,21 @@ uint8_t mcp23018__init(void) { if (ret) goto out; // make sure we got an ACK twi__send(GPPUA); #if OPT__MCP23018__DRIVE_ROWS +#ifndef ENABLE_LEFT_LED twi__send(0b11111111); // GPPUA twi__send(0b11000000); // GPPUB +#else + twi__send(0b01111111); // GPPUA + twi__send(0b00000000); // GPPUB +#endif #elif OPT__MCP23018__DRIVE_COLUMNS +#ifndef ENABLE_LEFT_LED twi__send(0b10000000); // GPPUA twi__send(0b11111111); // GPPUB +#else + twi__send(0b00000000); // GPPUA + twi__send(0b00111111); // GPPUB +#endif #endif twi__stop(); @@ -124,8 +150,14 @@ uint8_t mcp23018__init(void) { ret = twi__send(TWI_ADDR_WRITE); if (ret) goto out; // make sure we got an ACK twi__send(OLATA); +#ifndef ENABLE_LEFT_LED twi__send(0b11111111); //OLATA twi__send(0b11111111); //OLATB +#else + twi__send(0b11111111 & ~(kb__led__flicker(13)< #include #include +#ifdef ENABLE_LEFT_LED +#include "./controller/mcp23018.h" +#endif // ---------------------------------------------------------------------------- @@ -27,6 +30,38 @@ // ---------------------------------------------------------------------------- +#ifdef ENABLE_LEFT_LED +#define L_TOP 11 // red +#define L_MID 12 // yellow +#define L_BOT 13 // green + +#define L_MIN L_TOP // first LED +#define L_MAX L_BOT // last LED + +#define L_IDX(x) (x-L_MIN) + +#define L_STEPS 5 // 0%, 25%, 50%, 75%, 100% (zero is NOT off, just dimmest) + +// during power up there is no polling of the mcp23018 so no way to control +// brightness - it's just on/off + +static bool _l_startup; + +// state + +static bool _l_on[L_MAX-L_MIN+1]; + +// bright values are 0-(L_STEPS-1) + +static uint8_t _l_bright[L_MAX-L_MIN+1]; + +// cyclic counters for brightness + +static uint8_t _l_flicker[L_MAX-L_MIN+1]; +#endif + +// ---------------------------------------------------------------------------- + void kb__led__on(uint8_t led) { switch(led) { case 1: (DDRB |= (1<<5)); break; // topmost @@ -34,6 +69,18 @@ void kb__led__on(uint8_t led) { case 3: (DDRB |= (1<<7)); break; // bottommost case 4: break; case 5: break; +#ifdef ENABLE_TEENSY_LED + case 6: (PORTD |= (1<<6)); break; +#endif +#ifdef ENABLE_LEFT_LED + case L_TOP: + case L_MID: + case L_BOT: + _l_on[L_IDX(led)] = 1; + if (_l_startup) + mcp23018__init(); + break; +#endif }; } @@ -44,6 +91,18 @@ void kb__led__off(uint8_t led) { case 3: (DDRB &= ~(1<<7)); break; // bottommost case 4: break; case 5: break; +#ifdef ENABLE_TEENSY_LED + case 6: (PORTD &= ~(1<<6)); break; +#endif +#ifdef ENABLE_LEFT_LED + case L_TOP: + case L_MID: + case L_BOT: + _l_on[L_IDX(led)] = 0; + if (_l_startup) + mcp23018__init(); + break; +#endif }; } @@ -54,6 +113,13 @@ void kb__led__set(uint8_t led, float n) { case 3: (OCR1C = (uint8_t)((n) * 0xFF)); break; // bottommost case 4: break; case 5: break; +#ifdef ENABLE_LEFT_LED + case L_TOP: + case L_MID: + case L_BOT: + _l_bright[L_IDX(led)] = (uint8_t)((n) * (L_STEPS-1)); + break; +#endif }; } @@ -66,46 +132,162 @@ bool kb__led__read(uint8_t led) { case 3: return (PINB & (1<<7)); // bottommost case 4: ; case 5: ; +#ifdef ENABLE_TEENSY_LED + case 6: return (PIND & (1<<6)); +#endif +#ifdef ENABLE_LEFT_LED + case L_TOP: + case L_MID: + case L_BOT: + return(_l_on[L_IDX(led)]); +#endif }; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#ifdef ENABLE_LEFT_LED +static uint8_t kb__led__flicker_peek_bare(uint8_t led) +{ + // Light the led every Nth cycle. N is 1 to L_STEPS. + + switch(led) { + case L_TOP: + case L_MID: + case L_BOT: + return((_l_flicker[L_IDX(led)] % (L_STEPS - _l_bright[L_IDX(led)] + 1)) == 0 ? 1 : 0); + default: return(1); + }; +} + +uint8_t kb__led__flicker_peek(uint8_t led) +{ + // See if this is currently a cycle to be lit. + // It is called by mcp23018__update_matrix to refresh lit value as it scans the + // other bits. At the top of mcp23018__update_matrix, mcp23018__init is called + // so the flicker counters have already been incremented for this cycle. + + if (_l_startup) + return(kb__led__read(led)); + + if (!kb__led__read(led)) + return(0); + + return(kb__led__flicker_peek_bare(led)); +} + +uint8_t kb__led__flicker(uint8_t led) +{ + // mcp23018__init calls this once for each led. mcp23018__init is called every + // scanning cycle. *_flicker is incremented on each call wrapping after 251 times. + // Then we see if it is time to light. + + if (_l_startup) + return(kb__led__read(led)); + + if (!kb__led__read(led)) + return(0); + + switch(led) { + case L_TOP: + case L_MID: + case L_BOT: + if (_l_flicker[L_IDX(led)]++ == 255) _l_flicker[L_IDX(led)] = 0; break; + }; + + return(kb__led__flicker_peek_bare(led)); +} +#endif + +#ifdef ENABLE_TEENSY_LED +uint8_t kb__led__dbg_blink(uint8_t blinks) +{ + _delay_ms(500); + + for (uint8_t i = blinks; i; i--) { + _delay_ms(250); + kb__led__on(6); + _delay_ms(250); + kb__led__off(6); + } + + return(0); +} +#endif + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + void kb__led__all_on(void) { for(int8_t i=1; i<=3; i++) kb__led__on(i); +#ifdef ENABLE_TEENSY_LED + kb__led__on(6); +#endif +#ifdef ENABLE_LEFT_LED + if (!_l_startup) + for(uint8_t i=L_MIN; i<=L_MAX; i++) + kb__led__on(i); +#endif } void kb__led__all_off(void) { for(int8_t i=1; i<=3; i++) kb__led__off(i); +#ifdef ENABLE_TEENSY_LED + kb__led__off(6); +#endif +#ifdef ENABLE_LEFT_LED + for(uint8_t i=L_MIN; i<=L_MAX; i++) + kb__led__off(i); +#endif } void kb__led__all_set(float n) { for(int8_t i=1; i<=3; i++) kb__led__set(i, n); +#ifdef ENABLE_LEFT_LED + for(uint8_t i=L_MIN; i<=L_MAX; i++) + kb__led__set(i, n); +#endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void kb__led__state__power_on(void) { +#ifdef ENABLE_LEFT_LED + _l_startup = 1; +#endif kb__led__all_set( OPT__LED_BRIGHTNESS / 10 ); kb__led__all_on(); } void kb__led__state__ready(void) { +#ifdef ENABLE_LEFT_LED + _l_startup = 0; +#endif kb__led__all_off(); kb__led__all_set( OPT__LED_BRIGHTNESS ); } void kb__led__delay__usb_init(void) { +#ifdef ENABLE_TEENSY_LED + kb__led__off(6); +#endif // need to delay for a total of ~1 second kb__led__set( 1, OPT__LED_BRIGHTNESS ); +#ifdef ENABLE_LEFT_LED + kb__led__on( L_TOP ); +#endif _delay_ms(333); kb__led__set( 2, OPT__LED_BRIGHTNESS ); +#ifdef ENABLE_LEFT_LED + kb__led__on( L_MID ); +#endif _delay_ms(333); kb__led__set( 3, OPT__LED_BRIGHTNESS ); +#ifdef ENABLE_LEFT_LED + kb__led__on( L_BOT ); +#endif _delay_ms(333); } - diff --git a/firmware/makefile b/firmware/makefile index c829ea8..5468b2a 100644 --- a/firmware/makefile +++ b/firmware/makefile @@ -64,6 +64,7 @@ SRC += $(wildcard $(CURDIR)/main.c) # ----------------------------------------------------------------------------- +CFLAGS += -DENABLE_TEENSY_LED -DENABLE_LEFT_LED -DENABLE_LEFT_LED_LAYERS CFLAGS += -mmcu=$(MCU) # processor type; must match real life CFLAGS += -DF_CPU=$(F_CPU) # processor frequency; must match initialization # in source