helix.c (12917B)
1 /* Copyright 2023 splitkb.com <support@splitkb.com> 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 2 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16 17 #include "quantum.h" 18 19 // The first four layers gets a name for readability, which is then used in the OLED below. 20 enum layers { 21 _DEFAULT, 22 _LOWER, 23 _RAISE, 24 _ADJUST 25 }; 26 27 #ifdef OLED_ENABLE 28 // NOTE: Most of the OLED code was originally written by Soundmonster for the Corne, 29 // and has been copied directly from `crkbd/soundmonster/keymap.c` 30 31 oled_rotation_t oled_init_kb(oled_rotation_t rotation) { 32 return OLED_ROTATION_270; 33 } 34 35 void render_mod_status_gui_alt(uint8_t modifiers) { 36 static const char PROGMEM gui_off_1[] = {0x85, 0x86, 0}; 37 static const char PROGMEM gui_off_2[] = {0xa5, 0xa6, 0}; 38 static const char PROGMEM gui_on_1[] = {0x8d, 0x8e, 0}; 39 static const char PROGMEM gui_on_2[] = {0xad, 0xae, 0}; 40 41 static const char PROGMEM alt_off_1[] = {0x87, 0x88, 0}; 42 static const char PROGMEM alt_off_2[] = {0xa7, 0xa8, 0}; 43 static const char PROGMEM alt_on_1[] = {0x8f, 0x90, 0}; 44 static const char PROGMEM alt_on_2[] = {0xaf, 0xb0, 0}; 45 46 // fillers between the modifier icons bleed into the icon frames 47 static const char PROGMEM off_off_1[] = {0xc5, 0}; 48 static const char PROGMEM off_off_2[] = {0xc6, 0}; 49 static const char PROGMEM on_off_1[] = {0xc7, 0}; 50 static const char PROGMEM on_off_2[] = {0xc8, 0}; 51 static const char PROGMEM off_on_1[] = {0xc9, 0}; 52 static const char PROGMEM off_on_2[] = {0xca, 0}; 53 static const char PROGMEM on_on_1[] = {0xcb, 0}; 54 static const char PROGMEM on_on_2[] = {0xcc, 0}; 55 56 if(modifiers & MOD_MASK_GUI) { 57 oled_write_P(gui_on_1, false); 58 } else { 59 oled_write_P(gui_off_1, false); 60 } 61 62 if ((modifiers & MOD_MASK_GUI) && (modifiers & MOD_MASK_ALT)) { 63 oled_write_P(on_on_1, false); 64 } else if(modifiers & MOD_MASK_GUI) { 65 oled_write_P(on_off_1, false); 66 } else if(modifiers & MOD_MASK_ALT) { 67 oled_write_P(off_on_1, false); 68 } else { 69 oled_write_P(off_off_1, false); 70 } 71 72 if(modifiers & MOD_MASK_ALT) { 73 oled_write_P(alt_on_1, false); 74 } else { 75 oled_write_P(alt_off_1, false); 76 } 77 78 if(modifiers & MOD_MASK_GUI) { 79 oled_write_P(gui_on_2, false); 80 } else { 81 oled_write_P(gui_off_2, false); 82 } 83 84 if ((modifiers & MOD_MASK_GUI) && (modifiers & MOD_MASK_ALT)) { 85 oled_write_P(on_on_2, false); 86 } else if(modifiers & MOD_MASK_GUI) { 87 oled_write_P(on_off_2, false); 88 } else if(modifiers & MOD_MASK_ALT) { 89 oled_write_P(off_on_2, false); 90 } else { 91 oled_write_P(off_off_2, false); 92 } 93 94 if(modifiers & MOD_MASK_ALT) { 95 oled_write_P(alt_on_2, false); 96 } else { 97 oled_write_P(alt_off_2, false); 98 } 99 } 100 101 void render_mod_status_ctrl_shift(uint8_t modifiers) { 102 static const char PROGMEM ctrl_off_1[] = {0x89, 0x8a, 0}; 103 static const char PROGMEM ctrl_off_2[] = {0xa9, 0xaa, 0}; 104 static const char PROGMEM ctrl_on_1[] = {0x91, 0x92, 0}; 105 static const char PROGMEM ctrl_on_2[] = {0xb1, 0xb2, 0}; 106 107 static const char PROGMEM shift_off_1[] = {0x8b, 0x8c, 0}; 108 static const char PROGMEM shift_off_2[] = {0xab, 0xac, 0}; 109 static const char PROGMEM shift_on_1[] = {0xcd, 0xce, 0}; 110 static const char PROGMEM shift_on_2[] = {0xcf, 0xd0, 0}; 111 112 // fillers between the modifier icons bleed into the icon frames 113 static const char PROGMEM off_off_1[] = {0xc5, 0}; 114 static const char PROGMEM off_off_2[] = {0xc6, 0}; 115 static const char PROGMEM on_off_1[] = {0xc7, 0}; 116 static const char PROGMEM on_off_2[] = {0xc8, 0}; 117 static const char PROGMEM off_on_1[] = {0xc9, 0}; 118 static const char PROGMEM off_on_2[] = {0xca, 0}; 119 static const char PROGMEM on_on_1[] = {0xcb, 0}; 120 static const char PROGMEM on_on_2[] = {0xcc, 0}; 121 122 if(modifiers & MOD_MASK_CTRL) { 123 oled_write_P(ctrl_on_1, false); 124 } else { 125 oled_write_P(ctrl_off_1, false); 126 } 127 128 if ((modifiers & MOD_MASK_CTRL) && (modifiers & MOD_MASK_SHIFT)) { 129 oled_write_P(on_on_1, false); 130 } else if(modifiers & MOD_MASK_CTRL) { 131 oled_write_P(on_off_1, false); 132 } else if(modifiers & MOD_MASK_SHIFT) { 133 oled_write_P(off_on_1, false); 134 } else { 135 oled_write_P(off_off_1, false); 136 } 137 138 if(modifiers & MOD_MASK_SHIFT) { 139 oled_write_P(shift_on_1, false); 140 } else { 141 oled_write_P(shift_off_1, false); 142 } 143 144 if(modifiers & MOD_MASK_CTRL) { 145 oled_write_P(ctrl_on_2, false); 146 } else { 147 oled_write_P(ctrl_off_2, false); 148 } 149 150 if ((modifiers & MOD_MASK_CTRL) && (modifiers & MOD_MASK_SHIFT)) { 151 oled_write_P(on_on_2, false); 152 } else if(modifiers & MOD_MASK_CTRL) { 153 oled_write_P(on_off_2, false); 154 } else if(modifiers & MOD_MASK_SHIFT) { 155 oled_write_P(off_on_2, false); 156 } else { 157 oled_write_P(off_off_2, false); 158 } 159 160 if(modifiers & MOD_MASK_SHIFT) { 161 oled_write_P(shift_on_2, false); 162 } else { 163 oled_write_P(shift_off_2, false); 164 } 165 } 166 167 void render_logo(void) { 168 static const char PROGMEM aurora_logo[] = { 169 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf8, 0xc0, 0xf8, 0xe0, 0xc0, 0xfc, 0x00, 0x7e, 0x18, 0x00, 0x80, 170 0x00, 0x02, 0x80, 0xf0, 0x00, 0xc0, 0x80, 0xf8, 0xc0, 0xe0, 0x70, 0x60, 0x3c, 0x38, 0x3c, 0x1c, 171 0x00, 0x3f, 0x0c, 0x0f, 0x1f, 0x03, 0x07, 0x01, 0xc3, 0x00, 0xe0, 0x80, 0x00, 0xe0, 0x80, 0xf8, 172 0x80, 0xc0, 0xf7, 0xc7, 0x6f, 0x7b, 0x39, 0x30, 0x00, 0x80, 0x00, 0xc0, 0x00, 0xc0, 0xc2, 0xe0, 173 0x00, 0x40, 0x38, 0x30, 0x38, 0x1e, 0x18, 0x1e, 0x0f, 0x0c, 0x07, 0x07, 0x07, 0x03, 0x03, 0x21, 174 0x21, 0x31, 0x30, 0x18, 0x18, 0x1c, 0x08, 0x0c, 0x0e, 0x07, 0x06, 0x07, 0x03, 0xc3, 0x03, 0x01, 175 0x4c, 0xcc, 0xc2, 0xc2, 0x41, 0x49, 0x09, 0x2b, 0x2a, 0x6a, 0x6e, 0x24, 0x24, 0x04, 0x92, 0x92, 176 0xb1, 0xf1, 0xf1, 0xf2, 0xe6, 0xa4, 0xa4, 0x04, 0x04, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28 177 }; 178 oled_write_raw_P(aurora_logo, sizeof(aurora_logo)); 179 oled_set_cursor(0, 4); 180 } 181 182 void render_logo_text(void) { 183 oled_write_P(PSTR("helix"), false); 184 } 185 186 void render_kb_LED_state(void) { 187 // Host Keyboard LED Status 188 led_t led_state = host_keyboard_led_state(); 189 oled_write_P(led_state.num_lock ? PSTR("N ") : PSTR(" "), false); 190 oled_write_P(led_state.caps_lock ? PSTR("C ") : PSTR(" "), false); 191 oled_write_P(led_state.scroll_lock ? PSTR("S ") : PSTR(" "), false); 192 } 193 194 void render_layer_state(void) { 195 static const char PROGMEM default_layer[] = { 196 0x20, 0x94, 0x95, 0x96, 0x20, 197 0x20, 0xb4, 0xb5, 0xb6, 0x20, 198 0x20, 0xd4, 0xd5, 0xd6, 0x20, 0}; 199 static const char PROGMEM raise_layer[] = { 200 0x20, 0x97, 0x98, 0x99, 0x20, 201 0x20, 0xb7, 0xb8, 0xb9, 0x20, 202 0x20, 0xd7, 0xd8, 0xd9, 0x20, 0}; 203 static const char PROGMEM lower_layer[] = { 204 0x20, 0x9a, 0x9b, 0x9c, 0x20, 205 0x20, 0xba, 0xbb, 0xbc, 0x20, 206 0x20, 0xda, 0xdb, 0xdc, 0x20, 0}; 207 static const char PROGMEM adjust_layer[] = { 208 0x20, 0x9d, 0x9e, 0x9f, 0x20, 209 0x20, 0xbd, 0xbe, 0xbf, 0x20, 210 0x20, 0xdd, 0xde, 0xdf, 0x20, 0}; 211 212 switch (get_highest_layer(layer_state | default_layer_state)) { 213 case _LOWER: 214 oled_write_P(lower_layer, false); 215 break; 216 case _RAISE: 217 oled_write_P(raise_layer, false); 218 break; 219 case _ADJUST: 220 oled_write_P(adjust_layer, false); 221 break; 222 default: 223 oled_write_P(default_layer, false); 224 } 225 } 226 227 228 bool oled_task_kb(void) { 229 if (!oled_task_user()) { 230 return false; 231 } 232 if (is_keyboard_master()) { 233 // Renders the current keyboard state (layers and mods) 234 render_logo(); 235 render_logo_text(); 236 oled_advance_page(false); 237 render_layer_state(); 238 oled_advance_page(false); 239 render_mod_status_gui_alt(get_mods()|get_oneshot_mods()); 240 render_mod_status_ctrl_shift(get_mods()|get_oneshot_mods()); 241 render_kb_LED_state(); 242 } else { 243 // clang-format off 244 static const char PROGMEM aurora_art[] = { 245 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x08, 0x00, 0x00, 246 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 247 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 248 0xe0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x80, 249 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x80, 0x00, 0xf0, 0x00, 0x00, 0xc0, 250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 251 0x81, 0x00, 0xc0, 0x00, 0xfe, 0x00, 0xfc, 0x00, 0xff, 0x20, 0xff, 0xf0, 0x0f, 0xf0, 0x00, 0xff, 252 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0xf8, 0x00, 0x00, 0xf8, 253 0xff, 0x10, 0xff, 0x84, 0xff, 0x60, 0xff, 0x36, 0xff, 0x0f, 0xff, 0x3f, 0x00, 0x5f, 0x00, 0x05, 254 0x80, 0x00, 0x80, 0x00, 0xc0, 0x38, 0x00, 0xec, 0xf0, 0x00, 0xfb, 0x80, 0xff, 0xf0, 0xff, 0xef, 255 0xff, 0xe8, 0xff, 0x03, 0xff, 0x0c, 0xff, 0x00, 0xff, 0x00, 0x03, 0x00, 0x00, 0xf8, 0x00, 0x80, 256 0xff, 0x20, 0xff, 0xd0, 0xff, 0xe0, 0xfe, 0xf8, 0xff, 0xfc, 0xff, 0xff, 0x0f, 0xff, 0x01, 0x3f, 257 0xff, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x03, 0x00, 0xfe, 0x80, 0xfe, 0x00, 0xc0, 0xff, 0xc4, 0xfb, 258 0xff, 0xfe, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0x07, 0xff, 0x03, 0x3f, 0x00, 0x0f, 0xc0, 0x00, 259 0x00, 0x00, 0xb8, 0x00, 0xff, 0x40, 0xbe, 0xf0, 0xff, 0xf1, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 260 0x1f, 0xff, 0x67, 0x00, 0xef, 0x00, 0x1f, 0x00, 0x00, 0x07, 0x00, 0x00, 0xe0, 0x00, 0xff, 0xf0, 261 0xff, 0x88, 0xff, 0xc4, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0x7f, 0x0f, 0xff, 262 0x00, 0x07, 0xfe, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0xc0, 0x3f, 0xf8, 0xe7, 0xff, 263 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0x1f, 0x3f, 0x01, 0xff, 0x0b, 0x00, 0xff, 0x00, 0x00, 0x05, 264 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x60, 0x80, 0xfe, 0xe3, 0xfc, 0xff, 0x1e, 0xff, 0xff, 0x23, 265 0xff, 0x09, 0xff, 0x20, 0x00, 0x3f, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x40, 0x00, 0xc0, 0x00, 0xfc, 266 0xe0, 0xfc, 0xf0, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0x0f, 0xff, 0x07, 0x1f, 0x00, 0x01, 0x0f, 0x00, 267 0x0f, 0x00, 0x81, 0x70, 0x0c, 0xf0, 0x80, 0x00, 0x00, 0xe4, 0xf8, 0xe6, 0x70, 0x3f, 0xcf, 0xff, 268 0x1f, 0xff, 0x48, 0xff, 0x0f, 0x00, 0x07, 0x00, 0x00, 0x43, 0x60, 0xf8, 0xf0, 0xfe, 0x38, 0xfe, 269 0x00, 0xfc, 0x03, 0x00, 0xc8, 0x72, 0xcf, 0xfc, 0x00, 0x03, 0x0f, 0x01, 0xe0, 0x1c, 0xe0, 0x03, 270 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x06, 0xf9, 0x00, 0x03, 0x00, 0x07, 271 0xff, 0x00, 0x10, 0x12, 0xc9, 0xf0, 0xcf, 0xb4, 0x7f, 0x80, 0xe0, 0x1e, 0x01, 0x40, 0x65, 0x5e, 272 0xe0, 0x00, 0x00, 0xf0, 0x0c, 0xf0, 0x00, 0x80, 0x7e, 0x01, 0x80, 0x93, 0xfc, 0xc0, 0x00, 0x00, 273 0x00, 0x00, 0x00, 0x00, 0x89, 0x18, 0x2c, 0x46, 0x00, 0x07, 0x21, 0x10, 0x10, 0x80, 0x09, 0x13, 274 0x31, 0xbf, 0xff, 0x00, 0x08, 0x1a, 0xf7, 0x0f, 0x00, 0x00, 0x44, 0x45, 0x34, 0xbf, 0xb8, 0x00, 275 0x10, 0xf0, 0x08, 0xf4, 0x18, 0x11, 0xfc, 0x18, 0xfb, 0x0e, 0x10, 0xf8, 0x04, 0xf8, 0x10, 0x20, 276 0x18, 0x09, 0xff, 0x0c, 0xea, 0x1f, 0x28, 0x60, 0x30, 0xf8, 0x20, 0xc0, 0x42, 0x33, 0x21, 0x00 277 }; 278 // clang-format on 279 oled_write_raw_P(aurora_art, sizeof(aurora_art)); 280 } 281 return false; 282 } 283 #endif 284 285 #ifdef ENCODER_ENABLE 286 bool encoder_update_kb(uint8_t index, bool clockwise) { 287 if (!encoder_update_user(index, clockwise)) { 288 return false; 289 } 290 // 0 is left-half encoder, 291 // 1 is right-half encoder 292 if (index == 0) { 293 // Volume control 294 if (clockwise) { 295 tap_code(KC_VOLU); 296 } else { 297 tap_code(KC_VOLD); 298 } 299 } else if (index == 1) { 300 // Page up/Page down 301 if (clockwise) { 302 tap_code(KC_PGDN); 303 } else { 304 tap_code(KC_PGUP); 305 } 306 } 307 return true; 308 } 309 #endif