mschwingen.c (6532B)
1 /* 2 * Copyright 2020 Michael Schwingen 3 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 #include <util/delay.h> 18 #include "mschwingen.h" 19 #include "uart.h" 20 #include "print.h" 21 #include "sendchar.h" 22 #include "sleep_led.h" 23 24 #ifdef KEYBOARD_ibm_model_m_mschwingen_led_ws2812 25 #include "ws2812.h" 26 #endif 27 28 #ifdef UART_DEBUG 29 # undef sendchar 30 static int8_t capture_sendchar(uint8_t c) { 31 // sendchar(c); 32 uart_write(c); 33 return 0; 34 } 35 #endif 36 37 static uint16_t blink_cycle_timer; 38 static bool blink_state = false; 39 static uint8_t isRecording = 0; 40 41 #ifdef KEYBOARD_ibm_model_m_mschwingen_led_ws2812 42 # if RGBLIGHT_LED_COUNT < 3 43 # error we need at least 3 RGB LEDs! 44 # endif 45 46 # define BRIGHT 32 47 # define DIM 6 48 49 static led_t led_state; 50 static uint8_t layer; 51 static uint8_t default_layer; 52 #endif 53 54 // we need our own sleep_led_* implementation to get callbacks on USB 55 // suspend/resume in order to completely turn off WS2812 LEDs 56 static bool suspend_active = false; 57 void sleep_led_init(void) {} 58 59 void sleep_led_toggle(void) {} 60 61 void sleep_led_disable(void) { 62 suspend_active = false; 63 gpio_write_pin_high(MODELM_STATUS_LED); 64 } 65 66 void sleep_led_enable(void) { 67 suspend_active = true; 68 gpio_write_pin_low(MODELM_STATUS_LED); 69 #ifdef KEYBOARD_ibm_model_m_mschwingen_led_ws2812 70 ws2812_set_color_all(0, 0, 0); 71 ws2812_flush(); 72 #endif 73 } 74 75 void keyboard_pre_init_kb(void) { 76 #ifdef KEYBOARD_ibm_model_m_mschwingen_led_ws2812 77 ws2812_init(); 78 ws2812_flush(); 79 #else 80 /* Set status LEDs pins to output and Low (on) */ 81 gpio_set_pin_output(MODELM_LED_CAPSLOCK); 82 gpio_set_pin_output(MODELM_LED_SCROLLOCK); 83 gpio_set_pin_output(MODELM_LED_NUMLOCK); 84 gpio_write_pin_low(MODELM_LED_CAPSLOCK); 85 gpio_write_pin_low(MODELM_LED_SCROLLOCK); 86 gpio_write_pin_low(MODELM_LED_NUMLOCK); 87 #endif 88 gpio_set_pin_output(MODELM_STATUS_LED); 89 gpio_write_pin_high(MODELM_STATUS_LED); 90 _delay_ms(50); 91 #ifdef UART_DEBUG 92 uart_init(115200); 93 print_set_sendchar(capture_sendchar); 94 uprintf("\r\nHello world!\r\n"); 95 #endif 96 97 gpio_set_pin_output(SR_LOAD_PIN); 98 gpio_set_pin_output(SR_CLK_PIN); 99 gpio_set_pin_output(SR_DOUT_PIN); // MOSI - unused 100 gpio_write_pin_low(SR_CLK_PIN); 101 102 keyboard_pre_init_user(); 103 } 104 105 #ifdef KEYBOARD_ibm_model_m_mschwingen_led_ws2812 106 static void led_update_rgb(void) { 107 if (isRecording && blink_state) { 108 ws2812_set_color(0, BRIGHT, BRIGHT, BRIGHT); 109 } else { 110 switch (default_layer) { 111 case 0: 112 if (led_state.num_lock) { 113 ws2812_set_color(0, 0, 0, BRIGHT); 114 } else { 115 ws2812_set_color(0, 0, 0, DIM); 116 } 117 break; 118 case 1: 119 if (led_state.num_lock) { 120 ws2812_set_color(0, 0, BRIGHT, 0); 121 } else { 122 ws2812_set_color(0, 0, 0, 0); 123 } 124 break; 125 } 126 } 127 128 if (led_state.caps_lock) { 129 ws2812_set_color(1, 0, BRIGHT, 0); 130 } else { 131 ws2812_set_color(1, 0, 0, 0); 132 } 133 134 switch (layer) { 135 case 0: 136 case 1: 137 default: 138 if (led_state.scroll_lock) { 139 ws2812_set_color(2, 0, BRIGHT, 0); 140 } else { 141 ws2812_set_color(2, 0, 0, 0); 142 } 143 break; 144 case 2: 145 if (led_state.scroll_lock) { 146 ws2812_set_color(2, BRIGHT, 0, 0); 147 } else { 148 ws2812_set_color(2, DIM, 0, 0); 149 } 150 break; 151 case 3: 152 if (led_state.scroll_lock) { 153 ws2812_set_color(2, 0, BRIGHT, BRIGHT); 154 } else { 155 ws2812_set_color(2, 0, DIM, DIM); 156 } 157 break; 158 } 159 if (!suspend_active) { 160 ws2812_flush(); 161 } 162 } 163 164 bool led_update_kb(led_t state) { 165 dprintf("LED Update: %d %d %d", led_state.num_lock, led_state.caps_lock, led_state.scroll_lock); 166 led_state = state; 167 led_update_rgb(); 168 169 return true; 170 } 171 172 void update_layer_leds(void) { 173 static uint8_t old_layer = 255; 174 static uint8_t old_default_layer = 255; 175 176 layer = get_highest_layer(layer_state); 177 default_layer = get_highest_layer(default_layer_state); 178 179 if (isRecording && timer_elapsed(blink_cycle_timer) > 150) { 180 blink_state = !blink_state; 181 blink_cycle_timer = timer_read(); 182 old_layer = 255; // fallthrough next check 183 } 184 185 if (layer == old_layer && default_layer == old_default_layer) { 186 return; 187 } 188 old_layer = layer; 189 old_default_layer = default_layer; 190 dprintf("Layer change: %d %d", default_layer, layer); 191 led_update_rgb(); 192 } 193 194 /*****************************************************************************/ 195 #else // classic LEDs on GPIO 196 bool led_update_kb(led_t led_state) { 197 dprintf("LED Update: %d %d %d", led_state.num_lock, led_state.caps_lock, led_state.scroll_lock); 198 199 if (led_update_user(led_state)) { 200 if (!isRecording) gpio_write_pin(MODELM_LED_NUMLOCK, !led_state.num_lock); 201 gpio_write_pin(MODELM_LED_CAPSLOCK, !led_state.caps_lock); 202 gpio_write_pin(MODELM_LED_SCROLLOCK, !led_state.scroll_lock); 203 } 204 return true; 205 } 206 207 void update_layer_leds(void) { 208 if (isRecording && timer_elapsed(blink_cycle_timer) > 150) { 209 blink_state = !blink_state; 210 blink_cycle_timer = timer_read(); 211 gpio_write_pin(MODELM_LED_NUMLOCK, blink_state); 212 } 213 } 214 215 #endif 216 217 bool dynamic_macro_record_start_kb(int8_t direction) { 218 if (!dynamic_macro_record_start_user(direction)) { 219 return false; 220 } 221 isRecording++; 222 blink_cycle_timer = timer_read(); 223 return true; 224 } 225 226 bool dynamic_macro_record_end_kb(int8_t direction) { 227 if (!dynamic_macro_record_end_user(direction)) { 228 return false; 229 } 230 if (isRecording) isRecording--; 231 return true; 232 }