summary refs log tree commit diff
path: root/quantum
diff options
context:
space:
mode:
authorPriyadi Iman Nurcahyo <priyadi@priyadi.net>2016-12-04 23:57:47 +0700
committerPriyadi Iman Nurcahyo <priyadi@priyadi.net>2016-12-04 23:57:47 +0700
commitfc80aa9974faad146837cd26d9264b5a6c74dd4b (patch)
tree893e6f573c2753a51f67ed3636110850036405c7 /quantum
parenta8e5f6180585f46684d713976ad05d4d81b11ab1 (diff)
parentf39e1b5dfe7552f01dbc6eab95c268f41a9d98e2 (diff)
Merge branch 'master' into promethium
Diffstat (limited to 'quantum')
-rw-r--r--quantum/api.c178
-rw-r--r--quantum/api.h59
-rw-r--r--quantum/api/api_sysex.c29
-rw-r--r--quantum/api/api_sysex.h10
-rw-r--r--quantum/config_common.h101
-rw-r--r--quantum/keymap.h4
-rw-r--r--quantum/keymap_extras/keymap_nordic.h2
-rwxr-xr-xquantum/light_ws2812.c151
-rwxr-xr-xquantum/light_ws2812.h21
-rw-r--r--quantum/pincontrol.h37
-rw-r--r--quantum/process_keycode/process_printer.c254
-rw-r--r--quantum/process_keycode/process_printer.h8
-rw-r--r--quantum/process_keycode/process_printer_bb.c260
-rw-r--r--quantum/process_keycode/process_unicode.h1
-rw-r--r--quantum/quantum.c48
-rw-r--r--quantum/quantum.h11
-rw-r--r--quantum/rgblight.c145
-rw-r--r--quantum/rgblight.h15
18 files changed, 1218 insertions, 116 deletions
diff --git a/quantum/api.c b/quantum/api.c
new file mode 100644
index 0000000000..4ca3b96762
--- /dev/null
+++ b/quantum/api.c
@@ -0,0 +1,178 @@
+#include "api.h"
+#include "quantum.h"
+
+void dword_to_bytes(uint32_t dword, uint8_t * bytes) {
+    bytes[0] = (dword >> 24) & 0xFF;
+    bytes[1] = (dword >> 16) & 0xFF; 
+    bytes[2] = (dword >> 8) & 0xFF; 
+    bytes[3] = (dword >> 0) & 0xFF; 
+}
+
+uint32_t bytes_to_dword(uint8_t * bytes, uint8_t index) {
+    return ((uint32_t)bytes[index + 0] << 24) | ((uint32_t)bytes[index + 1] << 16) | ((uint32_t)bytes[index + 2] << 8) | (uint32_t)bytes[index + 3];
+}
+
+__attribute__ ((weak))
+bool process_api_quantum(uint8_t length, uint8_t * data) {
+    return process_api_keyboard(length, data);
+}
+
+__attribute__ ((weak))
+bool process_api_keyboard(uint8_t length, uint8_t * data) {
+    return process_api_user(length, data);
+}
+
+__attribute__ ((weak))
+bool process_api_user(uint8_t length, uint8_t * data) {
+    return true;
+}
+
+void process_api(uint16_t length, uint8_t * data) {
+    // SEND_STRING("\nRX: ");
+    // for (uint8_t i = 0; i < length; i++) {
+    //     send_byte(data[i]);
+    //     SEND_STRING(" ");
+    // }
+    if (!process_api_quantum(length, data))
+        return;
+
+    switch (data[0]) {
+        case MT_SET_DATA:
+            switch (data[1]) {
+                case DT_DEFAULT_LAYER: {
+                    eeconfig_update_default_layer(data[2]);
+                    default_layer_set((uint32_t)(data[2]));
+                    break;
+                }
+                case DT_KEYMAP_OPTIONS: {
+                    eeconfig_update_keymap(data[2]);
+                    break;
+                }
+                case DT_RGBLIGHT: {
+                    #ifdef RGBLIGHT_ENABLE
+                        uint32_t rgblight = bytes_to_dword(data, 2);
+                        rgblight_update_dword(rgblight);
+                    #endif
+                    break;
+                }
+            }
+        case MT_GET_DATA:
+            switch (data[1]) {
+                case DT_HANDSHAKE: {
+                    MT_GET_DATA_ACK(DT_HANDSHAKE, NULL, 0);
+                    break;
+                }
+                case DT_DEBUG: {
+                    uint8_t debug_bytes[1] = { eeprom_read_byte(EECONFIG_DEBUG) };
+                    MT_GET_DATA_ACK(DT_DEBUG, debug_bytes, 1);
+                    break;
+                }
+                case DT_DEFAULT_LAYER: {
+                    uint8_t default_bytes[1] = { eeprom_read_byte(EECONFIG_DEFAULT_LAYER) };
+                    MT_GET_DATA_ACK(DT_DEFAULT_LAYER, default_bytes, 1);
+                    break;
+                }
+                case DT_CURRENT_LAYER: {
+                    uint8_t layer_state_bytes[4];
+                    dword_to_bytes(layer_state, layer_state_bytes);
+                    MT_GET_DATA_ACK(DT_CURRENT_LAYER, layer_state_bytes, 4);
+                    break;
+                }
+                case DT_AUDIO: {
+                    #ifdef AUDIO_ENABLE
+                        uint8_t audio_bytes[1] = { eeprom_read_byte(EECONFIG_AUDIO) };
+                        MT_GET_DATA_ACK(DT_AUDIO, audio_bytes, 1);
+                    #else
+                        MT_GET_DATA_ACK(DT_AUDIO, NULL, 0);
+                    #endif
+                    break;
+                }
+                case DT_BACKLIGHT: {
+                    #ifdef BACKLIGHT_ENABLE
+                        uint8_t backlight_bytes[1] = { eeprom_read_byte(EECONFIG_BACKLIGHT) };
+                        MT_GET_DATA_ACK(DT_BACKLIGHT, backlight_bytes, 1);
+                    #else
+                        MT_GET_DATA_ACK(DT_BACKLIGHT, NULL, 0);
+                    #endif
+                    break;
+                }
+                case DT_RGBLIGHT: {
+                    #ifdef RGBLIGHT_ENABLE
+                        uint8_t rgblight_bytes[4];
+                        dword_to_bytes(eeconfig_read_rgblight(), rgblight_bytes);
+                        MT_GET_DATA_ACK(DT_RGBLIGHT, rgblight_bytes, 4);
+                    #else
+                        MT_GET_DATA_ACK(DT_RGBLIGHT, NULL, 0);
+                    #endif
+                    break;
+                }
+                case DT_KEYMAP_OPTIONS: {
+                    uint8_t keymap_bytes[1] = { eeconfig_read_keymap() };
+                    MT_GET_DATA_ACK(DT_KEYMAP_OPTIONS, keymap_bytes, 1);
+                    break;
+                }
+                case DT_KEYMAP_SIZE: {
+                    uint8_t keymap_size[2] = {MATRIX_ROWS, MATRIX_COLS};
+                    MT_GET_DATA_ACK(DT_KEYMAP_SIZE, keymap_size, 2);
+                    break;
+                }
+                case DT_KEYMAP: {
+                    uint8_t keymap_data[MATRIX_ROWS * MATRIX_COLS * 4 + 3];
+                    keymap_data[0] = data[2];
+                    keymap_data[1] = MATRIX_ROWS;
+                    keymap_data[2] = MATRIX_COLS;
+                    for (int i = 0; i < MATRIX_ROWS; i++) {
+                        for (int j = 0; j < MATRIX_COLS; j++) {
+                            keymap_data[3 + (i*MATRIX_COLS*2) + (j*2)] = pgm_read_word(&keymaps[data[2]][i][j]) >> 8;
+                            keymap_data[3 + (i*MATRIX_COLS*2) + (j*2) + 1] = pgm_read_word(&keymaps[data[2]][i][j]) & 0xFF;
+                        }
+                    }
+                    MT_GET_DATA_ACK(DT_KEYMAP, keymap_data, MATRIX_ROWS * MATRIX_COLS * 4 + 3);
+                    // uint8_t keymap_data[5];
+                    // keymap_data[0] = data[2];
+                    // keymap_data[1] = data[3];
+                    // keymap_data[2] = data[4];
+                    // keymap_data[3] = pgm_read_word(&keymaps[data[2]][data[3]][data[4]]) >> 8;
+                    // keymap_data[4] = pgm_read_word(&keymaps[data[2]][data[3]][data[4]]) & 0xFF;
+
+                    // MT_GET_DATA_ACK(DT_KEYMAP, keymap_data, 5);
+                    break;
+                }
+                default:
+                    break;
+            }
+            break;
+        case MT_SET_DATA_ACK:
+        case MT_GET_DATA_ACK:
+            break;
+        case MT_SEND_DATA:
+            break;
+        case MT_SEND_DATA_ACK:
+            break;
+        case MT_EXE_ACTION:
+            break;
+        case MT_EXE_ACTION_ACK:
+            break;
+        case MT_TYPE_ERROR:
+            break;
+        default: ; // command not recognised
+            SEND_BYTES(MT_TYPE_ERROR, DT_NONE, data, length);
+            break;
+
+        // #ifdef RGBLIGHT_ENABLE
+        // case 0x27: ; // RGB LED functions
+        //     switch (*data++) {
+        //         case 0x00: ; // Update HSV
+        //             rgblight_sethsv((data[0] << 8 | data[1]) % 360, data[2], data[3]);
+        //             break;
+        //         case 0x01: ; // Update RGB
+        //             break;
+        //         case 0x02: ; // Update mode
+        //             rgblight_mode(data[0]);
+        //             break;
+        //     }
+        //     break;
+        // #endif
+    }
+
+}
\ No newline at end of file
diff --git a/quantum/api.h b/quantum/api.h
new file mode 100644
index 0000000000..00dcdb8954
--- /dev/null
+++ b/quantum/api.h
@@ -0,0 +1,59 @@
+#ifndef _API_H_
+#define _API_H_
+
+#include "lufa.h"
+
+enum MESSAGE_TYPE {
+    MT_GET_DATA =      0x10, // Get data from keyboard
+    MT_GET_DATA_ACK =  0x11, // returned data to process (ACK)
+    MT_SET_DATA =      0x20, // Set data on keyboard
+    MT_SET_DATA_ACK =  0x21, // returned data to confirm (ACK)
+    MT_SEND_DATA =     0x30, // Sending data/action from keyboard
+    MT_SEND_DATA_ACK = 0x31, // returned data/action confirmation (ACK)
+    MT_EXE_ACTION =    0x40, // executing actions on keyboard
+    MT_EXE_ACTION_ACK =0x41, // return confirmation/value (ACK)
+    MT_TYPE_ERROR =    0x80 // type not recofgnised (ACK)
+};
+
+enum DATA_TYPE {
+    DT_NONE = 0x00,
+    DT_HANDSHAKE,
+    DT_DEFAULT_LAYER,
+    DT_CURRENT_LAYER,
+    DT_KEYMAP_OPTIONS,
+    DT_BACKLIGHT,
+    DT_RGBLIGHT,
+    DT_UNICODE,
+    DT_DEBUG,
+    DT_AUDIO,
+    DT_QUANTUM_ACTION,
+    DT_KEYBOARD_ACTION,
+    DT_USER_ACTION,
+    DT_KEYMAP_SIZE,
+    DT_KEYMAP
+};
+
+void dword_to_bytes(uint32_t dword, uint8_t * bytes);
+uint32_t bytes_to_dword(uint8_t * bytes, uint8_t index);
+
+#define MT_GET_DATA(data_type, data, length) SEND_BYTES(MT_GET_DATA, data_type, data, length)
+#define MT_GET_DATA_ACK(data_type, data, length) SEND_BYTES(MT_GET_DATA_ACK, data_type, data, length)
+#define MT_SET_DATA(data_type, data, length) SEND_BYTES(MT_SET_DATA, data_type, data, length)
+#define MT_SET_DATA_ACK(data_type, data, length) SEND_BYTES(MT_SET_DATA_ACK, data_type, data, length)
+#define MT_SEND_DATA(data_type, data, length) SEND_BYTES(MT_SEND_DATA, data_type, data, length)
+#define MT_SEND_DATA_ACK(data_type, data, length) SEND_BYTES(MT_SEND_DATA_ACK, data_type, data, length)
+#define MT_EXE_ACTION(data_type, data, length) SEND_BYTES(MT_EXE_ACTION, data_type, data, length)
+#define MT_EXE_ACTION_ACK(data_type, data, length) SEND_BYTES(MT_EXE_ACTION_ACK, data_type, data, length)
+
+void process_api(uint16_t length, uint8_t * data);
+
+__attribute__ ((weak))
+bool process_api_quantum(uint8_t length, uint8_t * data);
+
+__attribute__ ((weak))
+bool process_api_keyboard(uint8_t length, uint8_t * data);
+
+__attribute__ ((weak))
+bool process_api_user(uint8_t length, uint8_t * data);
+
+#endif
\ No newline at end of file
diff --git a/quantum/api/api_sysex.c b/quantum/api/api_sysex.c
new file mode 100644
index 0000000000..a4a554e764
--- /dev/null
+++ b/quantum/api/api_sysex.c
@@ -0,0 +1,29 @@
+#include "api_sysex.h"
+
+void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes, uint16_t length) {
+    // SEND_STRING("\nTX: ");
+    // for (uint8_t i = 0; i < length; i++) {
+    //     send_byte(bytes[i]);
+    //     SEND_STRING(" ");
+    // }
+    uint8_t * precode = malloc(sizeof(uint8_t) * (length + 2));
+    precode[0] = message_type;
+    precode[1] = data_type;
+    memcpy(precode + 2, bytes, length);
+    uint8_t * encoded = malloc(sizeof(uint8_t) * (sysex_encoded_length(length + 2)));
+    uint16_t encoded_length = sysex_encode(encoded, precode, length + 2);
+    uint8_t * array = malloc(sizeof(uint8_t) * (encoded_length + 5));
+    array[0] = 0xF0;
+    array[1] = 0x00;
+    array[2] = 0x00;
+    array[3] = 0x00;
+    array[encoded_length + 4] = 0xF7;
+    memcpy(array + 4, encoded, encoded_length);
+    midi_send_array(&midi_device, encoded_length + 5, array);
+
+    // SEND_STRING("\nTD: ");
+    // for (uint8_t i = 0; i < encoded_length + 5; i++) {
+    //     send_byte(array[i]);
+    //     SEND_STRING(" ");
+    // }
+}
\ No newline at end of file
diff --git a/quantum/api/api_sysex.h b/quantum/api/api_sysex.h
new file mode 100644
index 0000000000..b947b60e54
--- /dev/null
+++ b/quantum/api/api_sysex.h
@@ -0,0 +1,10 @@
+#ifndef _API_SYSEX_H_
+#define _API_SYSEX_H_
+
+#include "api.h"
+
+void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes, uint16_t length);
+
+#define SEND_BYTES(mt, dt, b, l) send_bytes_sysex(mt, dt, b, l)
+
+#endif
\ No newline at end of file
diff --git a/quantum/config_common.h b/quantum/config_common.h
index 4d3939dae1..17c11faeb6 100644
--- a/quantum/config_common.h
+++ b/quantum/config_common.h
@@ -5,55 +5,56 @@
 #define COL2ROW 0
 #define ROW2COL 1
 /* I/O pins */
-#define B0 0x30
-#define B1 0x31
-#define B2 0x32
-#define B3 0x33
-#define B4 0x34
-#define B5 0x35
-#define B6 0x36
-#define B7 0x37
-#define C0 0x60
-#define C1 0x61
-#define C2 0x62
-#define C3 0x63
-#define C4 0x64
-#define C5 0x65
-#define C6 0x66
-#define C7 0x67
-#define D0 0x90
-#define D1 0x91
-#define D2 0x92
-#define D3 0x93
-#define D4 0x94
-#define D5 0x95
-#define D6 0x96
-#define D7 0x97
-#define E0 0xC0
-#define E1 0xC1
-#define E2 0xC2
-#define E3 0xC3
-#define E4 0xC4
-#define E5 0xC5
-#define E6 0xC6
-#define E7 0xC7
-#define F0 0xF0
-#define F1 0xF1
-#define F2 0xF2
-#define F3 0xF3
-#define F4 0xF4
-#define F5 0xF5
-#define F6 0xF6
-#define F7 0xF7
-#define A0 0x00
-#define A1 0x01
-#define A2 0x02
-#define A3 0x03
-#define A4 0x04
-#define A5 0x05
-#define A6 0x06
-#define A7 0x07
-
+#ifndef F0
+    #define B0 0x30
+    #define B1 0x31
+    #define B2 0x32
+    #define B3 0x33
+    #define B4 0x34
+    #define B5 0x35
+    #define B6 0x36
+    #define B7 0x37
+    #define C0 0x60
+    #define C1 0x61
+    #define C2 0x62
+    #define C3 0x63
+    #define C4 0x64
+    #define C5 0x65
+    #define C6 0x66
+    #define C7 0x67
+    #define D0 0x90
+    #define D1 0x91
+    #define D2 0x92
+    #define D3 0x93
+    #define D4 0x94
+    #define D5 0x95
+    #define D6 0x96
+    #define D7 0x97
+    #define E0 0xC0
+    #define E1 0xC1
+    #define E2 0xC2
+    #define E3 0xC3
+    #define E4 0xC4
+    #define E5 0xC5
+    #define E6 0xC6
+    #define E7 0xC7
+    #define F0 0xF0
+    #define F1 0xF1
+    #define F2 0xF2
+    #define F3 0xF3
+    #define F4 0xF4
+    #define F5 0xF5
+    #define F6 0xF6
+    #define F7 0xF7
+    #define A0 0x00
+    #define A1 0x01
+    #define A2 0x02
+    #define A3 0x03
+    #define A4 0x04
+    #define A5 0x05
+    #define A6 0x06
+    #define A7 0x07
+#endif
 
 /* USART configuration */
 #ifdef BLUETOOTH_ENABLE
@@ -79,4 +80,4 @@
 #   endif
 #endif
 
-#endif
\ No newline at end of file
+#endif
diff --git a/quantum/keymap.h b/quantum/keymap.h
index a01bbfbd14..ae56d16c75 100644
--- a/quantum/keymap.h
+++ b/quantum/keymap.h
@@ -178,6 +178,10 @@ enum quantum_keycodes {
     // Right shift, close paren
     KC_RSPC,
 
+    // Printing
+    PRINT_ON,
+    PRINT_OFF,
+
     // always leave at the end
     SAFE_RANGE
 };
diff --git a/quantum/keymap_extras/keymap_nordic.h b/quantum/keymap_extras/keymap_nordic.h
index da5c829757..9b0ef35ca9 100644
--- a/quantum/keymap_extras/keymap_nordic.h
+++ b/quantum/keymap_extras/keymap_nordic.h
@@ -13,7 +13,7 @@
 #define NO_ACUT	KC_EQL
 
 #define NO_AM	KC_LBRC
-#define NO_QUOT	KC_RBRC
+#define NO_QUOT	KC_RBRC // this is the "umlaut" char on Nordic keyboards, Apple layout
 #define NO_AE	KC_SCLN
 #define NO_OSLH	KC_QUOT
 #define	NO_APOS	KC_NUHS
diff --git a/quantum/light_ws2812.c b/quantum/light_ws2812.c
index 401845e855..a883b13884 100755
--- a/quantum/light_ws2812.c
+++ b/quantum/light_ws2812.c
@@ -16,14 +16,128 @@
 #include <util/delay.h>
 #include "debug.h"
 
+#ifdef RGBW_BB_TWI
+
+// Port for the I2C
+#define I2C_DDR DDRD
+#define I2C_PIN PIND
+#define I2C_PORT PORTD
+
+// Pins to be used in the bit banging
+#define I2C_CLK 0
+#define I2C_DAT 1
+
+#define I2C_DATA_HI()\
+I2C_DDR &= ~ (1 << I2C_DAT);\
+I2C_PORT |= (1 << I2C_DAT);
+#define I2C_DATA_LO()\
+I2C_DDR |= (1 << I2C_DAT);\
+I2C_PORT &= ~ (1 << I2C_DAT);
+
+#define I2C_CLOCK_HI()\
+I2C_DDR &= ~ (1 << I2C_CLK);\
+I2C_PORT |= (1 << I2C_CLK);
+#define I2C_CLOCK_LO()\
+I2C_DDR |= (1 << I2C_CLK);\
+I2C_PORT &= ~ (1 << I2C_CLK);
+
+#define I2C_DELAY 1
+
+void I2C_WriteBit(unsigned char c)
+{
+    if (c > 0)
+    {
+        I2C_DATA_HI();
+    }
+    else
+    {
+        I2C_DATA_LO();
+    }
+
+    I2C_CLOCK_HI();
+    _delay_us(I2C_DELAY);
+
+    I2C_CLOCK_LO();
+    _delay_us(I2C_DELAY);
+
+    if (c > 0)
+    {
+        I2C_DATA_LO();
+    }
+
+    _delay_us(I2C_DELAY);
+}
+
+// Inits bitbanging port, must be called before using the functions below
+//
+void I2C_Init()
+{
+    I2C_PORT &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK));
+
+    I2C_CLOCK_HI();
+    I2C_DATA_HI();
+
+    _delay_us(I2C_DELAY);
+}
+
+// Send a START Condition
+//
+void I2C_Start()
+{
+    // set both to high at the same time
+    I2C_DDR &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK));
+    _delay_us(I2C_DELAY);
+
+    I2C_DATA_LO();
+    _delay_us(I2C_DELAY);
+
+    I2C_CLOCK_LO();
+    _delay_us(I2C_DELAY);
+}
+
+// Send a STOP Condition
+//
+void I2C_Stop()
+{
+    I2C_CLOCK_HI();
+    _delay_us(I2C_DELAY);
+
+    I2C_DATA_HI();
+    _delay_us(I2C_DELAY);
+}
+
+// write a byte to the I2C slave device
+//
+unsigned char I2C_Write(unsigned char c)
+{
+    for (char i = 0; i < 8; i++)
+    {
+        I2C_WriteBit(c & 128);
+
+        c <<= 1;
+    }
+
+    
+    I2C_WriteBit(0);
+    _delay_us(I2C_DELAY);
+    _delay_us(I2C_DELAY);
+  
+    // _delay_us(I2C_DELAY);
+    //return I2C_ReadBit();
+    return 0;
+}
+
+
+#endif
+
 // Setleds for standard RGB
-void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds)
+void inline ws2812_setleds(LED_TYPE *ledarray, uint16_t leds)
 {
    // ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin));
    ws2812_setleds_pin(ledarray,leds, _BV(RGB_DI_PIN & 0xF));
 }
 
-void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask)
+void inline ws2812_setleds_pin(LED_TYPE *ledarray, uint16_t leds, uint8_t pinmask)
 {
   // ws2812_DDRREG |= pinmask; // Enable DDR
   // new universal format (DDR)
@@ -34,14 +148,41 @@ void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pin
 }
 
 // Setleds for SK6812RGBW
-void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds)
+void inline ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t leds)
 {
+
+  #ifdef RGBW_BB_TWI
+    uint8_t sreg_prev, twcr_prev;
+    sreg_prev=SREG;
+    twcr_prev=TWCR;
+    cli();
+    TWCR &= ~(1<<TWEN);
+    I2C_Init();
+    I2C_Start();
+    I2C_Write(0x84);
+    uint16_t datlen = leds<<2;
+    uint8_t curbyte;
+    uint8_t * data = (uint8_t*)ledarray;
+    while (datlen--) {
+      curbyte=*data++;
+      I2C_Write(curbyte);
+    }
+    I2C_Stop();
+    SREG=sreg_prev;
+    TWCR=twcr_prev;
+  #endif
+
+
   // ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR
   // new universal format (DDR)
   _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= _BV(RGB_DI_PIN & 0xF);
 
   ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(RGB_DI_PIN & 0xF));
-  _delay_us(80);
+
+
+  #ifndef RGBW_BB_TWI
+    _delay_us(80);
+  #endif
 }
 
 void ws2812_sendarray(uint8_t *data,uint16_t datlen)
@@ -123,7 +264,7 @@ void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi)
   cli();
 
   while (datlen--) {
-    curbyte=*data++;
+    curbyte=(*data++);
 
     asm volatile(
     "       ldi   %0,8  \n\t"
diff --git a/quantum/light_ws2812.h b/quantum/light_ws2812.h
index 54eef22d9e..9498e550e9 100755
--- a/quantum/light_ws2812.h
+++ b/quantum/light_ws2812.h
@@ -16,6 +16,21 @@
 #include <avr/io.h>
 #include <avr/interrupt.h>
 //#include "ws2812_config.h"
+//#include "i2cmaster.h"
+
+#define LIGHT_I2C 1
+#define LIGHT_I2C_ADDR        0x84
+#define LIGHT_I2C_ADDR_WRITE  ( (LIGHT_I2C_ADDR<<1) | I2C_WRITE )
+#define LIGHT_I2C_ADDR_READ   ( (LIGHT_I2C_ADDR<<1) | I2C_READ  )
+
+#define RGBW 1
+
+#ifdef RGBW
+  #define LED_TYPE struct cRGBW
+#else
+  #define LED_TYPE struct cRGB
+#endif
+
 
 /*
  *  Structure of the LED array
@@ -42,9 +57,9 @@ struct cRGBW { uint8_t g; uint8_t r; uint8_t b; uint8_t w;};
  *         - Wait 50�s to reset the LEDs
  */
 
-void ws2812_setleds     (struct cRGB  *ledarray, uint16_t number_of_leds);
-void ws2812_setleds_pin (struct cRGB  *ledarray, uint16_t number_of_leds,uint8_t pinmask);
-void ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t number_of_leds);
+void ws2812_setleds     (LED_TYPE *ledarray, uint16_t number_of_leds);
+void ws2812_setleds_pin (LED_TYPE *ledarray, uint16_t number_of_leds,uint8_t pinmask);
+void ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t number_of_leds);
 
 /*
  * Old interface / Internal functions
diff --git a/quantum/pincontrol.h b/quantum/pincontrol.h
new file mode 100644
index 0000000000..36ce29ef22
--- /dev/null
+++ b/quantum/pincontrol.h
@@ -0,0 +1,37 @@
+#pragma once
+// Some helpers for controlling gpio pins
+#include <avr/io.h>
+
+enum {
+  PinDirectionInput = 0,
+  PinDirectionOutput = 1,
+  PinLevelHigh = 1,
+  PinLevelLow = 0,
+};
+
+// ex: pinMode(B0, PinDirectionOutput);
+static inline void pinMode(uint8_t pin, int mode) {
+  uint8_t bv = _BV(pin & 0xf);
+  if (mode == PinDirectionOutput) {
+    _SFR_IO8((pin >> 4) + 1) |= bv;
+  } else {
+    _SFR_IO8((pin >> 4) + 1) &= ~bv;
+    _SFR_IO8((pin >> 4) + 2) &= ~bv;
+  }
+}
+
+// ex: digitalWrite(B0, PinLevelHigh);
+static inline void digitalWrite(uint8_t pin, int mode) {
+  uint8_t bv = _BV(pin & 0xf);
+  if (mode == PinLevelHigh) {
+    _SFR_IO8((pin >> 4) + 2) |= bv;
+  } else {
+    _SFR_IO8((pin >> 4) + 2) &= ~bv;
+  }
+}
+
+// Return true if the pin is HIGH
+// digitalRead(B0)
+static inline bool digitalRead(uint8_t pin) {
+  return _SFR_IO8(pin >> 4) & _BV(pin & 0xf);
+}
diff --git a/quantum/process_keycode/process_printer.c b/quantum/process_keycode/process_printer.c
new file mode 100644
index 0000000000..2e11dd366c
--- /dev/null
+++ b/quantum/process_keycode/process_printer.c
@@ -0,0 +1,254 @@
+#include "process_printer.h"
+#include "action_util.h"
+
+bool printing_enabled = false;
+uint8_t character_shift = 0;
+
+void enabled_printing() {
+	printing_enabled = true;
+	serial_init();
+}
+
+void disable_printing() {
+	printing_enabled = false;
+}
+
+uint8_t shifted_numbers[10] = {0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29};
+
+// uint8_t keycode_to_ascii[0xFF][2];
+
+// keycode_to_ascii[KC_MINS] = {0x2D, 0x5F};
+
+void print_char(char c) {
+	USB_Disable();
+	serial_send(c);
+	USB_Init();
+}
+
+void print_box_string(uint8_t text[]) {
+	uint8_t len = strlen(text);
+	uint8_t out[len * 3 + 8];
+	out[0] = 0xDA;
+	for (uint8_t i = 0; i < len; i++) {
+		out[i+1] = 0xC4;
+	}
+	out[len + 1] = 0xBF;
+	out[len + 2] = '\n';
+
+	out[len + 3] = 0xB3;
+	for (uint8_t i = 0; i < len; i++) {
+		out[len + 4 + i] = text[i];
+	}
+	out[len * 2 + 4] = 0xB3;
+	out[len * 2 + 5] = '\n';
+
+
+	out[len * 2 + 6] = 0xC0;
+	for (uint8_t i = 0; i < len; i++) {
+		out[len * 2 + 7 + i] = 0xC4;
+	}
+	out[len * 3 + 7] = 0xD9;
+	out[len * 3 + 8] = '\n';
+
+	print_string(out); 
+}
+
+void print_string(char c[]) {
+	for(uint8_t i = 0; i < strlen(c); i++)
+		print_char(c[i]);
+}
+
+bool process_printer(uint16_t keycode, keyrecord_t *record) {
+	if (keycode == PRINT_ON) {
+		enabled_printing();
+		return false;
+	}
+	if (keycode == PRINT_OFF) {
+		disable_printing();
+		return false;
+	}
+
+	if (printing_enabled) {
+		switch(keycode) {
+			case KC_EXLM ... KC_RPRN:
+			case KC_UNDS:
+			case KC_PLUS:
+			case KC_LCBR:
+			case KC_RCBR:
+			case KC_PIPE:
+			case KC_TILD:
+				keycode &= 0xFF;
+			case KC_LSFT:
+			case KC_RSFT:
+				if (record->event.pressed) {
+					character_shift++;
+				} else {
+					character_shift--;
+				}
+				return false;
+			break;
+		}
+
+		switch(keycode) {
+			case KC_F1:
+				if (record->event.pressed) {
+					print_box_string("This is a line of text!");
+				}
+				return false;
+			case KC_ESC:
+				if (record->event.pressed) {
+					print_char(0x1B);
+				}
+				return false;
+			break;
+			case KC_SPC:
+				if (record->event.pressed) {
+					print_char(0x20);
+				}
+				return false;
+			break;
+			case KC_A ... KC_Z:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x41 + (keycode - KC_A));
+					} else {
+						print_char(0x61 + (keycode - KC_A));
+					}
+				}
+				return false;
+			break;
+			case KC_1 ... KC_0:
+				if (record->event.pressed) {
+					if (character_shift) {
+							print_char(shifted_numbers[keycode - KC_1]);
+					} else {
+							print_char(0x30 + ((keycode - KC_1 + 1) % 10));
+					}
+				}
+				return false;
+			break;
+			case KC_ENT:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x0C);
+					} else {
+						print_char(0x0A);
+					}
+				}
+				return false;
+			break;
+			case KC_BSPC:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x18);
+					} else {
+						print_char(0x1A);
+					}
+				}
+				return false;
+			break;
+			case KC_DOT:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x3E);
+					} else {
+						print_char(0x2E);
+					}
+				}
+				return false;
+			break;
+			case KC_COMM:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x3C);
+					} else {
+						print_char(0x2C);
+					}
+				}
+				return false;
+			break;
+			case KC_SLSH:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x3F);
+					} else {
+						print_char(0x2F);
+					}
+				}
+				return false;
+			break;
+			case KC_QUOT:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x22);
+					} else {
+						print_char(0x27);
+					}
+				}
+				return false;
+			break;
+			case KC_GRV:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x7E);
+					} else {
+						print_char(0x60);
+					}
+				}
+				return false;
+			break;
+			case KC_MINS:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x5F);
+					} else {
+						print_char(0x2D);
+					}
+				}
+				return false;
+			break;
+			case KC_EQL:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x2B);
+					} else {
+						print_char(0x3D);
+					}
+				}
+				return false;
+			break;
+			case KC_LBRC:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x7B);
+					} else {
+						print_char(0x5B);
+					}
+				}
+				return false;
+			break;
+			case KC_RBRC:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x7D);
+					} else {
+						print_char(0x5D);
+					}
+				}
+				return false;
+			break;
+			case KC_BSLS:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x7C);
+					} else {
+						print_char(0x5C);
+					}
+				}
+				return false;
+			break;
+		}
+	}
+	return true;
+
+}
\ No newline at end of file
diff --git a/quantum/process_keycode/process_printer.h b/quantum/process_keycode/process_printer.h
new file mode 100644
index 0000000000..fdd36d75a8
--- /dev/null
+++ b/quantum/process_keycode/process_printer.h
@@ -0,0 +1,8 @@
+#ifndef PROCESS_PRINTER_H
+#define PROCESS_PRINTER_H
+
+#include "quantum.h"
+
+#include "protocol/serial.h"
+
+#endif
\ No newline at end of file
diff --git a/quantum/process_keycode/process_printer_bb.c b/quantum/process_keycode/process_printer_bb.c
new file mode 100644
index 0000000000..1924d03774
--- /dev/null
+++ b/quantum/process_keycode/process_printer_bb.c
@@ -0,0 +1,260 @@
+#include "process_printer.h"
+#include "action_util.h"
+
+bool printing_enabled = false;
+uint8_t character_shift = 0;
+
+#define SERIAL_PIN_DDR DDRD
+#define SERIAL_PIN_PORT PORTD
+#define SERIAL_PIN_MASK _BV(PD3)
+#define SERIAL_DELAY 52
+
+inline static
+void serial_delay(void) {
+  _delay_us(SERIAL_DELAY);
+}
+
+inline static
+void serial_high(void) {
+  SERIAL_PIN_PORT |= SERIAL_PIN_MASK;
+}
+
+inline static
+void serial_low(void) {
+  SERIAL_PIN_PORT &= ~SERIAL_PIN_MASK;
+}
+
+inline static
+void serial_output(void) {
+  SERIAL_PIN_DDR |= SERIAL_PIN_MASK;
+}
+
+
+void enabled_printing() {
+	printing_enabled = true;
+	serial_output();
+	serial_high();
+}
+
+void disable_printing() {
+	printing_enabled = false;
+}
+
+uint8_t shifted_numbers[10] = {0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29};
+
+// uint8_t keycode_to_ascii[0xFF][2];
+
+// keycode_to_ascii[KC_MINS] = {0x2D, 0x5F};
+
+void print_char(char c) {
+  uint8_t b = 8;
+  serial_output();
+  while( b-- ) {
+    if(c & (1 << b)) {
+      serial_high();
+    } else {
+      serial_low();
+    }
+    serial_delay();
+  }
+}
+
+void print_string(char c[]) {
+	for(uint8_t i = 0; i < strlen(c); i++)
+		print_char(c[i]);
+}
+
+bool process_printer(uint16_t keycode, keyrecord_t *record) {
+	if (keycode == PRINT_ON) {
+		enabled_printing();
+		return false;
+	}
+	if (keycode == PRINT_OFF) {
+		disable_printing();
+		return false;
+	}
+
+	if (printing_enabled) {
+		switch(keycode) {
+			case KC_EXLM ... KC_RPRN:
+			case KC_UNDS:
+			case KC_PLUS:
+			case KC_LCBR:
+			case KC_RCBR:
+			case KC_PIPE:
+			case KC_TILD:
+				keycode &= 0xFF;
+			case KC_LSFT:
+			case KC_RSFT:
+				if (record->event.pressed) {
+					character_shift++;
+				} else {
+					character_shift--;
+				}
+				return false;
+			break;
+		}
+
+		switch(keycode) {
+			case KC_F1:
+				if (record->event.pressed) {
+					print_string("This is a line of text!\n\n\n");
+				}
+				return false;
+			case KC_ESC:
+				if (record->event.pressed) {
+					print_char(0x1B);
+				}
+				return false;
+			break;
+			case KC_SPC:
+				if (record->event.pressed) {
+					print_char(0x20);
+				}
+				return false;
+			break;
+			case KC_A ... KC_Z:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x41 + (keycode - KC_A));
+					} else {
+						print_char(0x61 + (keycode - KC_A));
+					}
+				}
+				return false;
+			break;
+			case KC_1 ... KC_0:
+				if (record->event.pressed) {
+					if (character_shift) {
+							print_char(shifted_numbers[keycode - KC_1]);
+					} else {
+							print_char(0x30 + ((keycode - KC_1 + 1) % 10));
+					}
+				}
+				return false;
+			break;
+			case KC_ENT:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x0C);
+					} else {
+						print_char(0x0A);
+					}
+				}
+				return false;
+			break;
+			case KC_BSPC:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x18);
+					} else {
+						print_char(0x1A);
+					}
+				}
+				return false;
+			break;
+			case KC_DOT:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x3E);
+					} else {
+						print_char(0x2E);
+					}
+				}
+				return false;
+			break;
+			case KC_COMM:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x3C);
+					} else {
+						print_char(0x2C);
+					}
+				}
+				return false;
+			break;
+			case KC_SLSH:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x3F);
+					} else {
+						print_char(0x2F);
+					}
+				}
+				return false;
+			break;
+			case KC_QUOT:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x22);
+					} else {
+						print_char(0x27);
+					}
+				}
+				return false;
+			break;
+			case KC_GRV:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x7E);
+					} else {
+						print_char(0x60);
+					}
+				}
+				return false;
+			break;
+			case KC_MINS:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x5F);
+					} else {
+						print_char(0x2D);
+					}
+				}
+				return false;
+			break;
+			case KC_EQL:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x2B);
+					} else {
+						print_char(0x3D);
+					}
+				}
+				return false;
+			break;
+			case KC_LBRC:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x7B);
+					} else {
+						print_char(0x5B);
+					}
+				}
+				return false;
+			break;
+			case KC_RBRC:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x7D);
+					} else {
+						print_char(0x5D);
+					}
+				}
+				return false;
+			break;
+			case KC_BSLS:
+				if (record->event.pressed) {
+					if (character_shift) {
+						print_char(0x7C);
+					} else {
+						print_char(0x5C);
+					}
+				}
+				return false;
+			break;
+		}
+	}
+	return true;
+
+}
\ No newline at end of file
diff --git a/quantum/process_keycode/process_unicode.h b/quantum/process_keycode/process_unicode.h
index 065eeb5f6a..f17cfa6cf2 100644
--- a/quantum/process_keycode/process_unicode.h
+++ b/quantum/process_keycode/process_unicode.h
@@ -22,6 +22,7 @@ void register_hex(uint16_t hex);
 bool process_unicode(uint16_t keycode, keyrecord_t *record);
 
 #ifdef UNICODEMAP_ENABLE
+void unicode_map_input_error(void);
 bool process_unicode_map(uint16_t keycode, keyrecord_t *record);
 #endif
 
diff --git a/quantum/quantum.c b/quantum/quantum.c
index b5e2d60b9d..f653564a67 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -134,6 +134,9 @@ bool process_record_quantum(keyrecord_t *record) {
   #ifdef UCIS_ENABLE
     process_ucis(keycode, record) &&
   #endif
+  #ifdef PRINTING_ENABLE
+    process_printer(keycode, record) &&
+  #endif
   #ifdef UNICODEMAP_ENABLE
     process_unicode_map(keycode, record) &&
   #endif
@@ -806,6 +809,51 @@ void backlight_set(uint8_t level)
 #endif // backlight
 
 
+// Functions for spitting out values
+//
+
+void send_dword(uint32_t number) { // this might not actually work
+    uint16_t word = (number >> 16);
+    send_word(word);
+    send_word(number & 0xFFFFUL);
+}
+
+void send_word(uint16_t number) {
+    uint8_t byte = number >> 8;
+    send_byte(byte);
+    send_byte(number & 0xFF);
+}
+
+void send_byte(uint8_t number) {
+    uint8_t nibble = number >> 4;
+    send_nibble(nibble);
+    send_nibble(number & 0xF);
+}
+
+void send_nibble(uint8_t number) {
+    switch (number) {
+        case 0:
+            register_code(KC_0);
+            unregister_code(KC_0);
+            break;
+        case 1 ... 9:
+            register_code(KC_1 + (number - 1));
+            unregister_code(KC_1 + (number - 1));
+            break;
+        case 0xA ... 0xF:
+            register_code(KC_A + (number - 0xA));
+            unregister_code(KC_A + (number - 0xA));
+            break;
+    }
+}
+
+void api_send_unicode(uint32_t unicode) {
+#ifdef API_ENABLE
+    uint8_t chunk[4];
+    dword_to_bytes(unicode, chunk);
+    MT_SEND_DATA(DT_UNICODE, chunk, 5);
+#endif
+}
 
 __attribute__ ((weak))
 void led_set_user(uint8_t usb_led) {
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 0c60466495..e6adf974ab 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -59,6 +59,10 @@ extern uint32_t default_layer_state;
 
 #include "process_tap_dance.h"
 
+#ifdef PRINTING_ENABLE
+	#include "process_printer.h"
+#endif
+
 #define SEND_STRING(str) send_string(PSTR(str))
 void send_string(const char *str);
 
@@ -106,8 +110,15 @@ void breathing_speed_dec(uint8_t value);
 #endif
 
 #endif
+void send_dword(uint32_t number);
+void send_word(uint16_t number);
+void send_byte(uint8_t number);
+void send_nibble(uint8_t number);
+
 
 void led_set_user(uint8_t usb_led);
 void led_set_kb(uint8_t usb_led);
 
+void api_send_unicode(uint32_t unicode);
+
 #endif
diff --git a/quantum/rgblight.c b/quantum/rgblight.c
index d550c58660..625971e0fe 100644
--- a/quantum/rgblight.c
+++ b/quantum/rgblight.c
@@ -69,11 +69,12 @@ const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {100, 50, 20};
 
 rgblight_config_t rgblight_config;
 rgblight_config_t inmem_config;
-struct cRGB led[RGBLED_NUM];
-uint8_t rgblight_inited = 0;
 
+LED_TYPE led[RGBLED_NUM];
+uint8_t rgblight_inited = 0;
+bool rgblight_timer_enabled = false;
 
-void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1) {
+void sethsv(uint16_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) {
   uint8_t r = 0, g = 0, b = 0, base, color;
 
   if (sat == 0) { // Acromatic color (gray). Hue doesn't mind.
@@ -124,7 +125,7 @@ void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1) {
   setrgb(r, g, b, led1);
 }
 
-void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1) {
+void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1) {
   (*led1).r = r;
   (*led1).g = g;
   (*led1).b = b;
@@ -141,9 +142,9 @@ void eeconfig_update_rgblight_default(void) {
   dprintf("eeconfig_update_rgblight_default\n");
   rgblight_config.enable = 1;
   rgblight_config.mode = 1;
-  rgblight_config.hue = 200;
-  rgblight_config.sat = 204;
-  rgblight_config.val = 204;
+  rgblight_config.hue = 0;
+  rgblight_config.sat = 255;
+  rgblight_config.val = 255;
   eeconfig_update_rgblight(rgblight_config.raw);
 }
 void eeconfig_debug_rgblight(void) {
@@ -173,7 +174,7 @@ void rgblight_init(void) {
   }
   eeconfig_debug_rgblight(); // display current eeprom values
 
-  #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER)
+  #ifdef RGBLIGHT_ANIMATIONS
     rgblight_timer_init(); // setup the timer
   #endif
 
@@ -182,6 +183,19 @@ void rgblight_init(void) {
   }
 }
 
+void rgblight_update_dword(uint32_t dword) {
+  rgblight_config.raw = dword;
+  eeconfig_update_rgblight(rgblight_config.raw);
+  if (rgblight_config.enable)
+    rgblight_mode(rgblight_config.mode);
+  else {
+    #ifdef RGBLIGHT_ANIMATIONS
+      rgblight_timer_disable();
+    #endif
+      rgblight_set();
+  }
+}
+
 void rgblight_increase(void) {
   uint8_t mode = 0;
   if (rgblight_config.mode < RGBLIGHT_MODES) {
@@ -220,7 +234,7 @@ void rgblight_mode(uint8_t mode) {
   eeconfig_update_rgblight(rgblight_config.raw);
   xprintf("rgblight mode: %u\n", rgblight_config.mode);
   if (rgblight_config.mode == 1) {
-    #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER)
+    #ifdef RGBLIGHT_ANIMATIONS
       rgblight_timer_disable();
     #endif
   } else if (rgblight_config.mode >= 2 && rgblight_config.mode <= 23) {
@@ -230,7 +244,7 @@ void rgblight_mode(uint8_t mode) {
     // MODE 15-20, snake
     // MODE 21-23, knight
 
-    #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER)
+    #ifdef RGBLIGHT_ANIMATIONS
       rgblight_timer_enable();
     #endif
   }
@@ -244,7 +258,7 @@ void rgblight_toggle(void) {
   if (rgblight_config.enable) {
     rgblight_mode(rgblight_config.mode);
   } else {
-    #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER)
+    #ifdef RGBLIGHT_ANIMATIONS
       rgblight_timer_disable();
     #endif
     _delay_ms(50);
@@ -252,6 +266,13 @@ void rgblight_toggle(void) {
   }
 }
 
+void rgblight_enable(void) {
+  rgblight_config.enable = 1;
+  eeconfig_update_rgblight(rgblight_config.raw);
+  xprintf("rgblight enable: rgblight_config.enable = %u\n", rgblight_config.enable);
+  rgblight_mode(rgblight_config.mode);
+}
+
 
 void rgblight_increase_hue(void) {
   uint16_t hue;
@@ -307,7 +328,7 @@ void rgblight_decrease_val(void) {
 void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) {
   inmem_config.raw = rgblight_config.raw;
   if (rgblight_config.enable) {
-    struct cRGB tmp_led;
+    LED_TYPE tmp_led;
     sethsv(hue, sat, val, &tmp_led);
     inmem_config.hue = hue;
     inmem_config.sat = sat;
@@ -351,66 +372,84 @@ void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) {
 
 void rgblight_set(void) {
   if (rgblight_config.enable) {
-    ws2812_setleds(led, RGBLED_NUM);
+    #ifdef RGBW
+      ws2812_setleds_rgbw(led, RGBLED_NUM);
+    #else
+      ws2812_setleds(led, RGBLED_NUM);
+    #endif
   } else {
     for (uint8_t i = 0; i < RGBLED_NUM; i++) {
       led[i].r = 0;
       led[i].g = 0;
       led[i].b = 0;
     }
-    ws2812_setleds(led, RGBLED_NUM);
+    #ifdef RGBW
+      ws2812_setleds_rgbw(led, RGBLED_NUM);
+    #else
+      ws2812_setleds(led, RGBLED_NUM);
+    #endif
   }
 }
 
-#if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER)
+#ifdef RGBLIGHT_ANIMATIONS
 
 // Animation timer -- AVR Timer3
 void rgblight_timer_init(void) {
-  static uint8_t rgblight_timer_is_init = 0;
-  if (rgblight_timer_is_init) {
-    return;
-  }
-  rgblight_timer_is_init = 1;
-  /* Timer 3 setup */
-  TCCR3B = _BV(WGM32) //CTC mode OCR3A as TOP
-        | _BV(CS30); //Clock selelct: clk/1
-  /* Set TOP value */
-  uint8_t sreg = SREG;
-  cli();
-  OCR3AH = (RGBLED_TIMER_TOP >> 8) & 0xff;
-  OCR3AL = RGBLED_TIMER_TOP & 0xff;
-  SREG = sreg;
+  // static uint8_t rgblight_timer_is_init = 0;
+  // if (rgblight_timer_is_init) {
+  //   return;
+  // }
+  // rgblight_timer_is_init = 1;
+  // /* Timer 3 setup */
+  // TCCR3B = _BV(WGM32) // CTC mode OCR3A as TOP
+  //       | _BV(CS30); // Clock selelct: clk/1
+  // /* Set TOP value */
+  // uint8_t sreg = SREG;
+  // cli();
+  // OCR3AH = (RGBLED_TIMER_TOP >> 8) & 0xff;
+  // OCR3AL = RGBLED_TIMER_TOP & 0xff;
+  // SREG = sreg;
+
+  rgblight_timer_enabled = true;
 }
 void rgblight_timer_enable(void) {
-  TIMSK3 |= _BV(OCIE3A);
+  rgblight_timer_enabled = true;
   dprintf("TIMER3 enabled.\n");
 }
 void rgblight_timer_disable(void) {
-  TIMSK3 &= ~_BV(OCIE3A);
+  rgblight_timer_enabled = false;
   dprintf("TIMER3 disabled.\n");
 }
 void rgblight_timer_toggle(void) {
-  TIMSK3 ^= _BV(OCIE3A);
+  rgblight_timer_enabled ^= rgblight_timer_enabled;
   dprintf("TIMER3 toggled.\n");
 }
 
-ISR(TIMER3_COMPA_vect) {
-  // mode = 1, static light, do nothing here
-  if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) {
-    // mode = 2 to 5, breathing mode
-    rgblight_effect_breathing(rgblight_config.mode - 2);
-  } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 8) {
-    // mode = 6 to 8, rainbow mood mod
-    rgblight_effect_rainbow_mood(rgblight_config.mode - 6);
-  } else if (rgblight_config.mode >= 9 && rgblight_config.mode <= 14) {
-    // mode = 9 to 14, rainbow swirl mode
-    rgblight_effect_rainbow_swirl(rgblight_config.mode - 9);
-  } else if (rgblight_config.mode >= 15 && rgblight_config.mode <= 20) {
-    // mode = 15 to 20, snake mode
-    rgblight_effect_snake(rgblight_config.mode - 15);
-  } else if (rgblight_config.mode >= 21 && rgblight_config.mode <= 23) {
-    // mode = 21 to 23, knight mode
-    rgblight_effect_knight(rgblight_config.mode - 21);
+void rgblight_show_solid_color(uint8_t r, uint8_t g, uint8_t b) {
+  rgblight_enable();
+  rgblight_mode(1);
+  rgblight_setrgb(r, g, b);
+}
+
+void rgblight_task(void) {
+  if (rgblight_timer_enabled) {
+    // mode = 1, static light, do nothing here
+    if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) {
+      // mode = 2 to 5, breathing mode
+      rgblight_effect_breathing(rgblight_config.mode - 2);
+    } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 8) {
+      // mode = 6 to 8, rainbow mood mod
+      rgblight_effect_rainbow_mood(rgblight_config.mode - 6);
+    } else if (rgblight_config.mode >= 9 && rgblight_config.mode <= 14) {
+      // mode = 9 to 14, rainbow swirl mode
+      rgblight_effect_rainbow_swirl(rgblight_config.mode - 9);
+    } else if (rgblight_config.mode >= 15 && rgblight_config.mode <= 20) {
+      // mode = 15 to 20, snake mode
+      rgblight_effect_snake(rgblight_config.mode - 15);
+    } else if (rgblight_config.mode >= 21 && rgblight_config.mode <= 23) {
+      // mode = 21 to 23, knight mode
+      rgblight_effect_knight(rgblight_config.mode - 21);
+    }
   }
 }
 
@@ -449,7 +488,7 @@ void rgblight_effect_rainbow_swirl(uint8_t interval) {
   last_timer = timer_read();
   for (i = 0; i < RGBLED_NUM; i++) {
     hue = (360 / RGBLED_NUM * i + current_hue) % 360;
-    sethsv(hue, rgblight_config.sat, rgblight_config.val, &led[i]);
+    sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]);
   }
   rgblight_set();
 
@@ -486,7 +525,7 @@ void rgblight_effect_snake(uint8_t interval) {
         k = k + RGBLED_NUM;
       }
       if (i == k) {
-        sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val*(RGBLIGHT_EFFECT_SNAKE_LENGTH-j)/RGBLIGHT_EFFECT_SNAKE_LENGTH), &led[i]);
+        sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val*(RGBLIGHT_EFFECT_SNAKE_LENGTH-j)/RGBLIGHT_EFFECT_SNAKE_LENGTH), (LED_TYPE *)&led[i]);
       }
     }
   }
@@ -506,7 +545,7 @@ void rgblight_effect_knight(uint8_t interval) {
   static uint16_t last_timer = 0;
   uint8_t i, j, cur;
   int8_t k;
-  struct cRGB preled[RGBLED_NUM];
+  LED_TYPE preled[RGBLED_NUM];
   static int8_t increment = -1;
   if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_KNIGHT_INTERVALS[interval])) {
     return;
@@ -525,7 +564,7 @@ void rgblight_effect_knight(uint8_t interval) {
         k = RGBLED_NUM - 1;
       }
       if (i == k) {
-        sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, &preled[i]);
+        sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&preled[i]);
       }
     }
   }
diff --git a/quantum/rgblight.h b/quantum/rgblight.h
index 17f04ffcf2..aa1d026e0e 100644
--- a/quantum/rgblight.h
+++ b/quantum/rgblight.h
@@ -1,8 +1,7 @@
 #ifndef RGBLIGHT_H
 #define RGBLIGHT_H
 
-
-#if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER)
+#ifdef RGBLIGHT_ANIMATIONS
 	#define RGBLIGHT_MODES 23
 #else
 	#define RGBLIGHT_MODES 1
@@ -34,6 +33,7 @@
 #endif
 
 #define RGBLED_TIMER_TOP F_CPU/(256*64)
+// #define RGBLED_TIMER_TOP 0xFF10
 
 #include <stdint.h>
 #include <stdbool.h>
@@ -61,9 +61,11 @@ void rgblight_init(void);
 void rgblight_increase(void);
 void rgblight_decrease(void);
 void rgblight_toggle(void);
+void rgblight_enable(void);
 void rgblight_step(void);
 void rgblight_mode(uint8_t mode);
 void rgblight_set(void);
+void rgblight_update_dword(uint32_t dword);
 void rgblight_increase_hue(void);
 void rgblight_decrease_hue(void);
 void rgblight_increase_sat(void);
@@ -78,10 +80,15 @@ void eeconfig_update_rgblight(uint32_t val);
 void eeconfig_update_rgblight_default(void);
 void eeconfig_debug_rgblight(void);
 
-void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1);
-void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1);
+void sethsv(uint16_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1);
+void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1);
 void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val);
 
+#define EZ_RGB(val) rgblight_show_solid_color((val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF)
+void rgblight_show_solid_color(uint8_t r, uint8_t g, uint8_t b);
+
+void rgblight_task(void);
+
 void rgblight_timer_init(void);
 void rgblight_timer_enable(void);
 void rgblight_timer_disable(void);