@@ -54,6 +54,11 @@ ifdef SLEEP_LED_ENABLE | |||
OPT_DEFS += -DNO_SUSPEND_POWER_DOWN | |||
endif | |||
ifdef BREATHING_LED_ENABLE | |||
SRC += $(COMMON_DIR)/breathing_led.c | |||
OPT_DEFS += -DBREATHING_LED_ENABLE | |||
endif | |||
ifdef BACKLIGHT_ENABLE | |||
SRC += $(COMMON_DIR)/backlight.c | |||
OPT_DEFS += -DBACKLIGHT_ENABLE |
@@ -16,6 +16,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "backlight.h" | |||
#include "breathing_led.h" | |||
#include "eeconfig.h" | |||
#include "debug.h" | |||
@@ -33,7 +34,7 @@ void backlight_init(void) | |||
void backlight_increase(void) | |||
{ | |||
#ifdef BACKLIGHT_CUSTOM | |||
#if defined(BACKLIGHT_CUSTOM) || defined(BREATHING_LED_ENABLE) | |||
if (backlight_config.enable) { | |||
if (backlight_config.level < BACKLIGHT_LEVELS) { | |||
backlight_config.level++; | |||
@@ -42,6 +43,9 @@ void backlight_increase(void) | |||
dprintf("backlight custom increase: %u\n", backlight_config.level); | |||
backlight_set(backlight_config.level); | |||
} | |||
#ifdef BREATHING_LED_ENABLE | |||
breathing_led_increase(); | |||
#endif | |||
#else | |||
if(backlight_config.level < BACKLIGHT_LEVELS) | |||
{ | |||
@@ -56,7 +60,7 @@ void backlight_increase(void) | |||
void backlight_decrease(void) | |||
{ | |||
#ifdef BACKLIGHT_CUSTOM | |||
#if defined(BACKLIGHT_CUSTOM) || defined(BREATHING_LED_ENABLE) | |||
if (backlight_config.enable) { | |||
if(backlight_config.level > 1) | |||
{ | |||
@@ -66,6 +70,9 @@ void backlight_decrease(void) | |||
dprintf("backlight custom decrease: %u\n", backlight_config.level); | |||
backlight_set(backlight_config.level); | |||
} | |||
#ifdef BREATHING_LED_ENABLE | |||
breathing_led_decrease(); | |||
#endif | |||
#else | |||
if(backlight_config.level > 0) | |||
{ | |||
@@ -80,16 +87,37 @@ void backlight_decrease(void) | |||
void backlight_toggle(void) | |||
{ | |||
#ifdef BREATHING_LED_ENABLE | |||
if (breathing_led_is_enabled()) { | |||
breathing_led_disable(); | |||
backlight_disable(); | |||
return; | |||
} | |||
#endif | |||
backlight_config.enable ^= 1; | |||
if (backlight_config.enable) | |||
{ | |||
if (backlight_config.enable) { | |||
#if defined(BACKLIGHT_CUSTOM) || defined(BREATHING_LED_ENABLE) | |||
backlight_enable(); | |||
#endif | |||
if (backlight_config.level == 0) { | |||
backlight_config.level = 1; | |||
} | |||
} | |||
else { | |||
#ifndef BREATHING_LED_ENABLE | |||
#ifdef BACKLIGHT_CUSTOM | |||
backlight_disable(); | |||
#endif | |||
#endif | |||
} | |||
eeconfig_write_backlight(backlight_config.raw); | |||
dprintf("backlight toggle: %u\n", backlight_config.enable); | |||
backlight_set(backlight_config.enable ? backlight_config.level : 0); | |||
#ifdef BREATHING_LED_ENABLE | |||
if (!backlight_config.enable) { | |||
breathing_led_enable(); | |||
} | |||
#endif | |||
} | |||
void backlight_step(void) |
@@ -36,6 +36,9 @@ void backlight_decrease(void); | |||
void backlight_toggle(void); | |||
void backlight_step(void); | |||
void backlight_enable(void); | |||
void backlight_disable(void); | |||
void backlight_set(uint8_t level); | |||
void backlight_set_raw(uint8_t raw); | |||
#endif |
@@ -0,0 +1,106 @@ | |||
#include <avr/io.h> | |||
#include <avr/interrupt.h> | |||
#include <avr/pgmspace.h> | |||
#include "led.h" | |||
#include "breathing_led.h" | |||
#include "backlight.h" | |||
#include "debug.h" | |||
#define BREATHING_LED_TIMER_TOP F_CPU/64 | |||
breathing_led_config_t breathing_led_config; | |||
void breathing_led_init(void) | |||
{ | |||
/* Timer3 setup */ | |||
/* CTC mode */ | |||
TCCR3B |= _BV(WGM12); | |||
/* Clock selelct: clk/1 */ | |||
TCCR3B |= _BV(CS10); | |||
/* Set TOP value */ | |||
uint8_t sreg = SREG; | |||
cli(); | |||
OCR3AH = (BREATHING_LED_TIMER_TOP>>8)&0xff; | |||
OCR3AL = BREATHING_LED_TIMER_TOP&0xff; | |||
SREG = sreg; | |||
} | |||
bool breathing_led_is_enabled(void) | |||
{ | |||
return breathing_led_config.enable; | |||
} | |||
void breathing_led_enable(void) | |||
{ | |||
/* Enable Compare Match Interrupt */ | |||
TIMSK3 |= _BV(OCIE3A); | |||
breathing_led_config.enable = true; | |||
dprintf("breathing led on: %u\n", breathing_led_config.enable); | |||
eeconfig_write_breathing_led(breathing_led_config.raw); | |||
} | |||
void breathing_led_disable(void) | |||
{ | |||
/* Disable Compare Match Interrupt */ | |||
TIMSK3 &= ~_BV(OCIE3A); | |||
breathing_led_config.enable = false; | |||
dprintf("breathing led off: %u\n", breathing_led_config.enable); | |||
eeconfig_write_breathing_led(breathing_led_config.raw); | |||
} | |||
void breathing_led_toggle(void) | |||
{ | |||
/* Disable Compare Match Interrupt */ | |||
TIMSK3 ^= _BV(OCIE3A); | |||
breathing_led_config.enable ^= 1; | |||
dprintf("breathing led toggle: %u\n", breathing_led_config.enable); | |||
eeconfig_write_breathing_led(breathing_led_config.raw); | |||
} | |||
void breathing_led_increase(void) | |||
{ | |||
if (breathing_led_config.enable) { | |||
if (breathing_led_config.level < BREATHING_LED_LEVELS) { | |||
breathing_led_config.level++; | |||
eeconfig_write_breathing_led(breathing_led_config.raw); | |||
} | |||
dprintf("breathing led speed increase: %u\n", breathing_led_config.level); | |||
} | |||
} | |||
void breathing_led_decrease(void) | |||
{ | |||
if (breathing_led_config.enable) { | |||
if (breathing_led_config.level > 0) | |||
{ | |||
breathing_led_config.level--; | |||
eeconfig_write_breathing_led(breathing_led_config.raw); | |||
} | |||
dprintf("breathing led speed decrease: %u\n", breathing_led_config.level); | |||
} | |||
} | |||
/* Breathing LED brighness(PWM On period) table | |||
* (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle | |||
* | |||
* http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63 | |||
* (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i } | |||
*/ | |||
static const uint8_t breathing_table[64] PROGMEM = { | |||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, | |||
15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, | |||
255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, | |||
15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | |||
}; | |||
ISR(TIMER3_COMPA_vect) | |||
{ | |||
uint8_t index = 0; | |||
uint8_t step = 0; | |||
step++; | |||
if (step >= BREATHING_LED_LEVELS - breathing_led_config.level) { | |||
step = 0; | |||
index++; | |||
backlight_set_raw(pgm_read_byte(&breathing_table[index])); | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
#ifndef BREATHING_LED_H | |||
#define BREATHING_LED_H | |||
#ifdef BREATHING_LED_ENABLE | |||
#include <stdint.h> | |||
#include <stdbool.h> | |||
#ifndef BREATHING_LED_LEVEL | |||
#define BREATHING_LED_LEVEL 1 | |||
#endif | |||
typedef union { | |||
uint8_t raw; | |||
struct { | |||
bool enable:1; | |||
uint8_t level:7; | |||
}; | |||
} breathing_led_config_t; | |||
void breathing_led_init(void); | |||
bool breathing_led_is_enabled(void); | |||
void breathing_led_enable(void); | |||
void breathing_led_disable(void); | |||
void breathing_led_toggle(void); | |||
void breathing_led_increase(void); | |||
void breathing_led_decrease(void); | |||
#else | |||
#define breathing_led_init() | |||
#define breathing_led_enable() | |||
#define breathing_led_disable() | |||
#define breathing_led_toggle() | |||
#endif | |||
#endif |
@@ -14,6 +14,9 @@ void eeconfig_init(void) | |||
#ifdef BACKLIGHT_ENABLE | |||
eeprom_write_byte(EECONFIG_BACKLIGHT, 0); | |||
#endif | |||
#ifdef BREATHING_LED_ENABLE | |||
eeprom_write_byte(EECONFIG_BREATHING_LED, 0); | |||
#endif | |||
#ifdef KEYMAP_EX_ENABLE | |||
keymap_ex_init(); | |||
#endif | |||
@@ -50,3 +53,8 @@ void eeconfig_write_keymap(uint8_t val) { eeprom_write_byte(EECONFIG_KEYMAP, val | |||
uint8_t eeconfig_read_backlight(void) { return eeprom_read_byte(EECONFIG_BACKLIGHT); } | |||
void eeconfig_write_backlight(uint8_t val) { eeprom_write_byte(EECONFIG_BACKLIGHT, val); } | |||
#endif | |||
#ifdef BREATHING_LED_ENABLE | |||
uint8_t eeconfig_read_breathing_led(void) { return eeprom_read_byte(EECONFIG_BREATHING_LED); } | |||
void eeconfig_write_breathing_led(uint8_t val) { eeprom_write_byte(EECONFIG_BREATHING_LED, val); } | |||
#endif |
@@ -31,6 +31,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#define EECONFIG_KEYMAP (uint8_t *)4 | |||
#define EECONFIG_MOUSEKEY_ACCEL (uint8_t *)5 | |||
#define EECONFIG_BACKLIGHT (uint8_t *)6 | |||
#define EECONFIG_BREATHING_LED (uint8_t *)7 | |||
/* debug bit */ | |||
@@ -71,4 +72,9 @@ uint8_t eeconfig_read_backlight(void); | |||
void eeconfig_write_backlight(uint8_t val); | |||
#endif | |||
#ifdef BREATHING_LED_ENABLE | |||
uint8_t eeconfig_read_breathing_led(void); | |||
void eeconfig_write_breathing_led(uint8_t val); | |||
#endif | |||
#endif |
@@ -138,7 +138,7 @@ NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA | |||
BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality | |||
KEYMAP_EX_ENABLE = yes # External keymap in eeprom | |||
KEYMAP_SECTION_ENABLE = yes # Fixed address keymap for keymap editor | |||
#LED_MATRIX_ENABLE = yes | |||
BREATHING_LED_ENABLE = yes # Enable breathing backlight | |||
# Optimize size but this may cause error "relocation truncated to fit" | |||
#EXTRALDFLAGS = -Wl,--relax |
@@ -20,7 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#include <avr/pgmspace.h> | |||
#include "backlight.h" | |||
#if defined(GH60_REV_CHN) | |||
static const uint8_t backlight_table[] PROGMEM = { | |||
0, 16, 128, 255 | |||
}; | |||
@@ -28,81 +27,62 @@ static const uint8_t backlight_table[] PROGMEM = { | |||
/* Backlight pin configuration | |||
* PWM: PB7 | |||
*/ | |||
void backlight_set(uint8_t level) | |||
void backlight_enable(void) | |||
{ | |||
if (level > 0) { | |||
// Turn on PWM | |||
cli(); | |||
DDRB |= (1<<PB6); | |||
TCCR1A |= ( (1<<WGM10) | (1<<COM1B1) ); | |||
TCCR1B |= ( (1<<CS11) | (1<<CS10) ); | |||
sei(); | |||
// Set PWM | |||
OCR1B = pgm_read_byte(&backlight_table[level]); | |||
} | |||
else { | |||
// Turn off PWM | |||
cli(); | |||
DDRB &= ~(1<<PB6); | |||
TCCR1A &= ~( (1<<WGM10) | (1<<COM1B1) ); | |||
TCCR1B &= ~( (1<<CS11) | (1<<CS10) ); | |||
sei(); | |||
// Set PWM | |||
OCR1B = 0; | |||
} | |||
#if defined(GH60_REV_CHN) | |||
// Turn on PWM | |||
cli(); | |||
DDRB |= (1<<PB6); | |||
TCCR1A |= ( (1<<WGM10) | (1<<COM1B1) ); | |||
TCCR1B |= ( (1<<CS11) | (1<<CS10) ); | |||
sei(); | |||
#else | |||
DDRF |= (1<<PF7 | 1<<PF6 | 1<<PF5 | 1<<PF4); | |||
PORTF |= (1<<PF7 | 1<<PF6 | 1<<PF5 | 1<<PF4); | |||
cli(); | |||
TCCR1A |= (1<<WGM10); | |||
TCCR1B |= ((1<<CS11) | (1<<CS10)); | |||
TIMSK1 |= ((1<<OCIE1A) | (1<<TOIE1)); | |||
TIFR1 |= (1<<TOV1); | |||
sei(); | |||
#endif | |||
} | |||
#elif defined(GH60_REV_CNY) | |||
static const uint8_t backlight_table[] PROGMEM = { | |||
0, 16, 128, 255 | |||
}; | |||
void backlight_set(uint8_t level) | |||
void backlight_disable(void) | |||
{ | |||
#ifdef LED_MATRIX_ENABLE | |||
if (level > 0) { | |||
led_matrix_disable(); | |||
for (uint8_t row = 0; row < LED_MATRIX_ROWS; row++) { | |||
for (uint8_t col = 0; col < LED_MATRIX_COLS; col++) { | |||
led_matrix_set_value(row, col, pgm_read_byte(&backlight_table[level])); | |||
} | |||
} | |||
led_matrix_enable(); | |||
} | |||
else { | |||
led_matrix_disable(); | |||
} | |||
#if defined(GH60_REV_CHN) | |||
// Turn off PWM | |||
cli(); | |||
DDRB &= ~(1<<PB6); | |||
TCCR1A &= ~( (1<<WGM10) | (1<<COM1B1) ); | |||
TCCR1B &= ~( (1<<CS11) | (1<<CS10) ); | |||
sei(); | |||
OCR1A = 0; | |||
#else | |||
DDRF &= ~(1<<PF7 | 1<<PF6 | 1<<PF5 | 1<<PF4); | |||
cli(); | |||
TCCR1A &= ~(1<<WGM10); | |||
TCCR1B &= ~((1<<CS11) | (1<<CS10)); | |||
TIMSK1 |= ((1<<OCIE1A) | (1<<TOIE1)); | |||
TIFR1 |= (1<<TOV1); | |||
sei(); | |||
OCR1A = 0; | |||
#endif | |||
} | |||
#else | |||
static const uint8_t backlight_table[] PROGMEM = { | |||
0, 16, 128, 255 | |||
}; | |||
void backlight_set(uint8_t level) | |||
{ | |||
if (level > 0) { | |||
DDRF |= (1<<PF7 | 1<<PF6 | 1<<PF5 | 1<<PF4); | |||
PORTF |= (1<<PF7 | 1<<PF6 | 1<<PF5 | 1<<PF4); | |||
cli(); | |||
TCCR1A |= (1<<WGM10); | |||
TCCR1B |= ((1<<CS11) | (1<<CS10)); | |||
TIMSK1 |= ((1<<OCIE1A) | (1<<TOIE1)); | |||
TIFR1 |= (1<<TOV1); | |||
sei(); | |||
OCR1A = pgm_read_byte(&backlight_table[level]); | |||
} | |||
else { | |||
DDRF &= ~(1<<PF7 | 1<<PF6 | 1<<PF5 | 1<<PF4); | |||
cli(); | |||
TCCR1A &= ~(1<<WGM10); | |||
TCCR1B &= ~((1<<CS11) | (1<<CS10)); | |||
TIMSK1 |= ((1<<OCIE1A) | (1<<TOIE1)); | |||
TIFR1 |= (1<<TOV1); | |||
sei(); | |||
OCR1A = 0; | |||
backlight_set_raw(pgm_read_byte(&backlight_table[level])); | |||
} | |||
} | |||
void backlight_set_raw(uint8_t raw) | |||
{ | |||
OCR1A = raw; | |||
} | |||
#ifndef GH60_REV_CHN | |||
ISR(TIMER1_COMPA_vect) | |||
{ | |||
// LED off |
@@ -43,6 +43,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
/* number of backlight levels */ | |||
#define BACKLIGHT_LEVELS 3 | |||
#define BREATHING_LED_LEVELS 4 | |||
#ifdef GH60_REV_CNY | |||
# define LED_MATRIX_ROWS 6 |