From 35bff470f73e5041f4e969f5dae5f60d4c1ea3e0 Mon Sep 17 00:00:00 2001 From: Seth Date: Sat, 11 Sep 2021 00:32:29 -0700 Subject: [Keyboard] Update rocketboard_16 with *most* of its final features (#12537) --- keyboards/rocketboard_16/keymaps/default/keymap.c | 368 ++++++++++++++++++++-- 1 file changed, 333 insertions(+), 35 deletions(-) (limited to 'keyboards/rocketboard_16/keymaps/default') diff --git a/keyboards/rocketboard_16/keymaps/default/keymap.c b/keyboards/rocketboard_16/keymaps/default/keymap.c index 0c3ee96d41..050ab9f5b1 100644 --- a/keyboards/rocketboard_16/keymaps/default/keymap.c +++ b/keyboards/rocketboard_16/keymaps/default/keymap.c @@ -12,29 +12,41 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include QMK_KEYBOARD_H +#include "keycode_lookup.h" +#include +#ifdef CONSOLE_ENABLE +#include "print.h" +#endif // Each layer gets a name for readability, which is then used in the keymap matrix below. // The underscores don't mean anything - you can have a layer called STUFF or any other name. // Layer names don't all need to be of the same length, obviously, and you can also skip them // entirely and just use numbers. #define _BASE 0 +#define _SPEC 1 // Special layer // Use the following format to create custom key codes to make macros out of and such -/* enum custom_keycodes { - FOO = SAFE_RANGE, + KC_EXAM = SAFE_RANGE // "Examine" key code to show the keycode of a key pressed afterwards on the OLED }; -*/ + const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { - [_BASE] = LAYOUT_default( - RGB_MODE_FORWARD, KC_NUMLOCK, - KC_KP_7, KC_KP_8, KC_KP_9, KC_DELETE, - KC_KP_4, KC_KP_5, KC_KP_6, KC_END, - KC_KP_1, KC_KP_2, KC_KP_3, KC_AUDIO_VOL_UP, - KC_KP_0, RGB_TOG, KC_AUDIO_MUTE, KC_AUDIO_VOL_DOWN - ) + [_BASE] = LAYOUT_default( + RGB_MODE_FORWARD, KC_NUMLOCK, + KC_KP_7, KC_KP_8, KC_KP_9, KC_DELETE, + KC_KP_4, KC_KP_5, KC_KP_6, KC_END, + KC_KP_1, KC_KP_2, KC_KP_3, KC_F13, + KC_KP_0, MO(1), KC_KP_DOT, KC_KP_ENTER + ), + [_SPEC] = LAYOUT_default( + RGB_MODE_REVERSE, KC_AUDIO_MUTE, + KC_NO, KC_NO, KC_NO, KC_EXAM, + KC_NO, KC_NO, KC_NO, KC_NO, + RESET, RGB_TOG, RGB_SPI, RGB_SPD, + KC_NO, _______, KC_NO, KC_NO + ) }; bool encoder_update_user(uint8_t index, bool clockwise){ @@ -56,35 +68,321 @@ bool encoder_update_user(uint8_t index, bool clockwise){ #ifdef OLED_ENABLE -static void render_logo(void) { - static const char PROGMEM qmk_logo[] = { - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, - 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, - 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0x00 - }; +#define ANIM_FRAMES 3 +#define ANIM_FRAME_DURATION 110 // Number of milliseconds per frame (no faster than 110ms, last line struggles) +#define BACKGROUND_FRAMES 21 +#define ROCKET_CENTER_POS 3 +#define SPLASH_DUR 100 // Measured in frames, see above for frame length (note, 231 is used as a key value later on, CTRL+F for uses of this to make sure everything is good) + +uint32_t anim_timer = 0; +uint8_t current_frame = 0; +uint8_t rocket_y_position = 3; +uint8_t rocket_pos_change = 0; +uint8_t background_frame = 0; +uint8_t splash_dur_counter = 0; +bool examine_engaged = false; +uint16_t examined_keycode = KC_NO; +char lastKeycodeString[32] = { 0 }; + +const char star_background [8] [21] = +{ + {0x88, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x00, 0x93}, + {0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x00}, + {0x00, 0x8F, 0x00, 0x00, 0x8A, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x8B, 0x00, 0x00, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00}, + {0x8D, 0x00, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x8B, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x8A, 0x00, 0x00, 0x8E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x8F, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x8F, 0x00, 0x89, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x8F}, + {0x00, 0x8B, 0x00, 0x00, 0x91, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x00, 0x90, 0x00, 0x00, 0x8C, 0x00, 0x00}, +}; + +static void oled_write_ln_centered(const char * data, bool inverted) +{ + if(strlen(data) >= 21) // If more than 1 line of text is passed in, return without doing anything + { + return; + } + + // Character buffer to build up the string in + char line_buf[21]; + + // Amount to offset string from left side + uint8_t offset = (21 - strlen(data))/2; + + // Formatted string centering... look, it works, don't ask how... + snprintf(line_buf, 21, "%*s%s%*s\0", offset, "", data, offset, ""); // Centers data within 21 character buffer with null termination + + oled_write_ln(line_buf, inverted); +} - oled_write(qmk_logo, false); +// Prints the exhaust characters in an order determined by the phase for animation purposes +// startX - The x axis starting point in characters for the exhaust (3 behind the rocket) +// startY - The y axis starting point in characters for the exhaust (middle of the rocket) +// phase - The "phase" of the animation, no real rhyme or reason to the exact number, but each frame move +1 to make the animation work +static void render_exhaust(uint8_t startX, uint8_t startY, uint8_t phase) +{ + oled_set_cursor(startX, startY); + oled_write_char(0x85 + (phase % 3), false); + phase++; + oled_write_char(0x85 + (phase % 3), false); + phase++; + oled_write_char(0x85 + (phase % 3), false); +} + +// Renders the "stars" behind the rocket +// startY - The starting Y location (in characters) of the rocket so that stars aren't rendered on top of the rocket +static void render_stars(uint8_t startY, uint8_t phase) +{ + // Line 0 + oled_set_cursor(0, 0); + for(int i = 0; i < 21; i++) + { + oled_write_char(star_background[0][(i + phase) % 21], false); + } + // Line 1 + oled_set_cursor(0, 1); + for(int i = 0; i < 21; i++) + { + oled_write_char(star_background[1][(i + phase) % 21], false); + } + // Line 2 + oled_set_cursor(0, 2); + for(int i = 0; i < 21; i++) + { + oled_write_char(star_background[2][(i + phase) % 21], false); + } + // Line 3 + oled_set_cursor(0, 3); + for(int i = 0; i < 21; i++) + { + oled_write_char(star_background[3][(i + phase) % 21], false); + } + // Line 4 + oled_set_cursor(0, 4); + for(int i = 0; i < 21; i++) + { + oled_write_char(star_background[4][(i + phase) % 21], false); + } + // Line 5 + oled_set_cursor(0, 5); + for(int i = 0; i < 21; i++) + { + oled_write_char(star_background[5][(i + phase) % 21], false); + } + // Line 6 + oled_set_cursor(0, 6); + for(int i = 0; i < 21; i++) + { + oled_write_char(star_background[6][(i + phase) % 21], false); + } + // Line 7 + oled_set_cursor(0, 7); + for(int i = 0; i < 21; i++) + { + oled_write_char(star_background[7][(i + phase) % 21], false); + } + +} + +static void render_logo(uint8_t startX, uint8_t startY) +{ + oled_set_cursor(startX, startY); + oled_write_char(0x80, false); + oled_write_char(0x81, false); + oled_write_char(0x82, false); + oled_write_char(0x83, false); + oled_write_char(0x84, false); + oled_set_cursor(startX, startY + 1); + oled_write_char(0xA0, false); + oled_write_char(0xA1, false); + oled_write_char(0xA2, false); + oled_write_char(0xA3, false); + oled_write_char(0xA4, false); + oled_write_char(0xA5, false); + oled_set_cursor(startX, startY + 2); + oled_write_char(0xC0, false); + oled_write_char(0xC1, false); + oled_write_char(0xC2, false); + oled_write_char(0xC3, false); + oled_write_char(0xC4, false); } oled_rotation_t oled_init_user(oled_rotation_t rotation) { return OLED_ROTATION_180; } -void oled_task_user(void) { - uint8_t light_level = rgblight_get_val(); - light_level = (uint8_t)(100.0 * ((float)light_level/(float)RGBLIGHT_LIMIT_VAL)); // Convert to % - char c_light_level[3]; - itoa(light_level, c_light_level, 10); - - render_logo(); // Render the QMK logo - oled_write_ln(PSTR(""), false); // Add a newline - // Host Keyboard LED Status - led_t led_state = host_keyboard_led_state(); - oled_write(led_state.num_lock ? PSTR(" |NUM|") : PSTR(" | |"), false); - oled_write(led_state.caps_lock ? PSTR("|CAP|") : PSTR("| |"), false); - oled_write(led_state.scroll_lock ? PSTR("|SCR| ") : PSTR("| | "), false); - - oled_write_ln(PSTR(""), false); // Add a newline - oled_write(PSTR(" BKLT: "), false); - oled_write(c_light_level, false); - oled_write_ln(PSTR("% "), false); +void oled_task_user(void) +{ + // Playing the animation + if((timer_elapsed32(anim_timer) > ANIM_FRAME_DURATION) && (splash_dur_counter < SPLASH_DUR)) + { + anim_timer = timer_read32(); // read the current timer value + current_frame = (current_frame + 1) % ANIM_FRAMES; // Frame in the exhaust animation + background_frame = (background_frame + 1) % BACKGROUND_FRAMES; // Frame in the star animation + + // Move the rocket up and down + if((rocket_pos_change / 9) == 0) + { + rocket_y_position = ROCKET_CENTER_POS; + } + else if((rocket_pos_change / 9) == 1) + { + rocket_y_position = ROCKET_CENTER_POS + 1; + } + else if((rocket_pos_change / 9) == 2) + { + rocket_y_position = ROCKET_CENTER_POS; + } + if((rocket_pos_change / 9) == 3) + { + rocket_y_position = ROCKET_CENTER_POS - 1; + } + + // Renders the scene piece by piece + render_stars(8, background_frame); // Render star background + render_exhaust(6, rocket_y_position + 1, current_frame); // Render exhaust + render_logo(9, rocket_y_position); // Render the rocket + + // Timing for rocket position change + if(rocket_pos_change < 36) + { + rocket_pos_change++; + } + else + { + rocket_pos_change = 0; + } + + splash_dur_counter++; + } + else if((splash_dur_counter >= SPLASH_DUR) && (splash_dur_counter != 231)) // Should only run once at end of splash screen duration + { + splash_dur_counter = 231; // Nice known value + oled_clear(); // Clear the screen + } + + + // After the splash screen + if(splash_dur_counter == 231) + { + uint8_t light_level = rgblight_get_val(); + light_level = (uint8_t)(100.0 * ((float)light_level/(float)RGBLIGHT_LIMIT_VAL)); // Convert to % + char c_light_level[3]; + itoa(light_level, c_light_level, 10); + + // Display lock LED statuses + led_t led_state = host_keyboard_led_state(); + if(led_state.num_lock) + { + oled_write(PSTR(" |"), false); + oled_write(PSTR("NUM"), true); + oled_write(PSTR("|"), false); + } + else + { + oled_write(PSTR(" |NUM|"), false); + } + + if(led_state.caps_lock) + { + oled_write(PSTR("|"), false); + oled_write(PSTR("CAP"), true); + oled_write(PSTR("|"), false); + } + else + { + oled_write(PSTR("|CAP|"), false); + } + + if(led_state.scroll_lock) + { + oled_write(PSTR("|"), false); + oled_write(PSTR("SCR"), true); + oled_write(PSTR("| "), false); + } + else + { + oled_write(PSTR("|SCR| "), false); + } + + // Print the examine info + if(examine_engaged == true) + { + oled_set_cursor(0, 2); + oled_write_ln(PSTR(" Keycode: "), false); + oled_write_ln_centered(lastKeycodeString, false); + } + else + { + oled_set_cursor(0, 2); + oled_write_ln(PSTR(" "), false); + oled_write_ln(PSTR(" "), false); + } + + // Print the backlight % bottom right + oled_set_cursor(11, 7); + oled_write(PSTR("BKLT: "), false); + oled_write(c_light_level, false); + oled_write(PSTR("%"), false); + + // Print the layer number in bottom left + oled_set_cursor(0, 7); + oled_write(PSTR("L: "), false); + switch (get_highest_layer(layer_state)) + { + case 0: + oled_write(PSTR("0"), false); + break; + case 1: + oled_write(PSTR("1"), false); + break; + case 2: + oled_write(PSTR("2"), false); + break; + case 3: + oled_write(PSTR("3"), false); + break; + default: + oled_write(PSTR("Und"), false); + break; + } + + + } + +} + +// Process the extra/extended keycode functionality +bool process_record_user(uint16_t keycode, keyrecord_t *record) +{ + bool ret = true; // True will allow QMK to process the key as usual after the function runs, false skips QMK processing after this function runs + + switch (keycode) + { + case KC_EXAM: + if(record->event.pressed) // On pressed, flip bool examine_engaged + { + if(examine_engaged == false) + { + examine_engaged = true; + } + else + { + examine_engaged = false; + } + ret = false; + } + else // On release do nothing + { + ret = false; + } + break; + + default: // For any key other than EX, simply let QMK process after saving away what it was + memset(lastKeycodeString, 0, sizeof(lastKeycodeString)); + memcpy(lastKeycodeString, translate_keycode_to_string(keycode), sizeof(((lookup_table_t *)0)->key_string)); + ret = true; + break; + } + + return ret; } #endif -- cgit v1.2.3