@ -0,0 +1,7 @@ | |||||
// Copyright 2023 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#pragma once | |||||
#define PICO_XOSC_STARTUP_DELAY_MULTIPLIER 64 | |||||
#define TAPPING_TERM 499 |
@ -0,0 +1,100 @@ | |||||
// Copyright 2023 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#include "drashna.h" | |||||
// clang-format off | |||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||||
[0] = LAYOUT( | |||||
LT(1,KC_MUTE), | |||||
KC_ENT, KC_0, KC_BSPC, | |||||
KC_7, KC_8, KC_9, | |||||
KC_4, KC_5, KC_6, | |||||
KC_1, KC_2, KC_3 | |||||
), | |||||
[1] = LAYOUT( | |||||
_______, | |||||
CK_TOGG, AU_TOGG, _______, | |||||
_______, _______, _______, | |||||
_______, _______, _______, | |||||
_______, _______, _______ | |||||
), | |||||
}; | |||||
// clang-format on | |||||
#ifdef ENCODER_MAP_ENABLE | |||||
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = { | |||||
[0] = {ENCODER_CCW_CW(KC_VOLD, KC_VOLU)}, | |||||
[1] = {ENCODER_CCW_CW(RGB_RMOD, RGB_MOD)}, | |||||
}; | |||||
#endif | |||||
void render_oled_title(bool side) { | |||||
oled_write_P(PSTR(" Macropad "), true); | |||||
} | |||||
void render_rgb_mode(uint8_t col, uint8_t line); | |||||
void l_render_keylock_status(led_t led_usb_state, uint8_t col, uint8_t line) { | |||||
oled_set_cursor(col, line); | |||||
#ifdef CAPS_WORD_ENABLE | |||||
led_usb_state.caps_lock |= is_caps_word_on(); | |||||
#endif | |||||
oled_write_P(PSTR(OLED_RENDER_LOCK_NUML), led_usb_state.num_lock); | |||||
oled_write_P(PSTR(" "), false); | |||||
oled_write_P(PSTR(OLED_RENDER_LOCK_CAPS), led_usb_state.caps_lock); | |||||
oled_write_P(PSTR(" "), false); | |||||
oled_write_P(PSTR(OLED_RENDER_LOCK_SCLK), led_usb_state.scroll_lock); | |||||
} | |||||
bool oled_task_keymap(void) { | |||||
oled_write_raw_P(header_image, sizeof(header_image)); | |||||
oled_set_cursor(0, 1); | |||||
oled_write_raw_P(row_2_image, sizeof(row_2_image)); | |||||
oled_set_cursor(4, 0); | |||||
render_oled_title(false); | |||||
render_kitty(0, 2); | |||||
render_matrix_scan_rate(1, 7, 2); | |||||
#ifdef AUDIO_ENABLE | |||||
oled_set_cursor(7, 4); | |||||
bool l_is_audio_on = is_audio_on(); | |||||
static const char PROGMEM audio_status[2][3] = {{0xE0, 0xE1, 0}, {0xE2, 0xE3, 0}}; | |||||
oled_write_P(audio_status[l_is_audio_on], false); | |||||
# ifdef AUDIO_CLICKY | |||||
bool l_is_clicky_on = is_clicky_on(); | |||||
static const char PROGMEM audio_clicky_status[2][3] = {{0xF4, 0xF5, 0}, {0xF6, 0xF7, 0}}; | |||||
oled_write_P(audio_clicky_status[l_is_clicky_on && l_is_audio_on], false); | |||||
# endif | |||||
#endif | |||||
static const char PROGMEM cat_mode[3] = {0xF8, 0xF9, 0}; | |||||
oled_write_P(cat_mode, get_keyboard_lock()); | |||||
#ifdef RGB_MATIRX_ENABLE | |||||
static const char PROGMEM rgb_layer_status[2][3] = {{0xEE, 0xEF, 0}, {0xF0, 0xF1, 0}}; | |||||
oled_write_P(rgb_layer_status[rgb_matrix_is_enabled()], false); | |||||
#endif | |||||
#ifdef HAPTIC_ENABLE | |||||
static const char PROGMEM nukem_good[2] = {0xFA, 0}; | |||||
oled_write_P(haptic_get_enable() ? nukem_good : PSTR(" "), false); | |||||
#endif | |||||
l_render_keylock_status(host_keyboard_led_state(), 7, 5); | |||||
render_rgb_mode(1, 6); | |||||
for (uint8_t i = 1; i < 7; i++) { | |||||
oled_set_cursor(0, i); | |||||
oled_write_raw_P(display_border, sizeof(display_border)); | |||||
oled_set_cursor(21, i); | |||||
oled_write_raw_P(display_border, sizeof(display_border)); | |||||
} | |||||
oled_set_cursor(0, 7); | |||||
oled_write_raw_P(footer_image, sizeof(footer_image)); | |||||
return false; | |||||
} |
@ -0,0 +1,3 @@ | |||||
ENCODER_MAP_ENABLE = yes | |||||
DEBUG_MATRIX_SCAN_RATE_ENABLE = api | |||||
WPM_ENABLE = yes |
@ -1,20 +0,0 @@ | |||||
// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#pragma once | |||||
#ifndef RGBLIGHT_LIMIT_VAL | |||||
# if defined(OLED_ENABLE) | |||||
# define RGBLIGHT_LIMIT_VAL 100 | |||||
# else | |||||
# define RGBLIGHT_LIMIT_VAL 150 | |||||
# endif | |||||
#endif | |||||
#ifndef OLED_BRIGHTNESS | |||||
# ifdef RGBLIGHT_ENABLE | |||||
# define OLED_BRIGHTNESS 80 | |||||
# else | |||||
# define OLED_BRIGHTNESS 150 | |||||
# endif | |||||
#endif |
@ -1,83 +0,0 @@ | |||||
/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 2 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "drashna.h" | |||||
/* | |||||
* The `LAYOUT_base` macro is a template to allow the use of identical | |||||
* modifiers for the default layouts (eg QWERTY, Colemak, Dvorak, etc), so | |||||
* that there is no need to set them up for each layout, and modify all of | |||||
* them if I want to change them. This helps to keep consistency and ease | |||||
* of use. K## is a placeholder to pass through the individual keycodes | |||||
*/ | |||||
// clang-format off | |||||
#define LAYOUT_wrapper(...) LAYOUT(__VA_ARGS__) | |||||
#define LAYOUT_base( \ | |||||
K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, \ | |||||
K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, \ | |||||
K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A \ | |||||
) \ | |||||
LAYOUT_wrapper( \ | |||||
KC_ESC, K01, K02, K03, K04, K05, KC_NO, K06, K07, K08, K09, K0A, KC_DEL, \ | |||||
ALT_T(KC_TAB), K11, K12, K13, K14, K15, KC_BSPC, K16, K17, K18, K19, K1A, RALT_T(K1B), \ | |||||
KC_MLSF, CTL_T(K21), K22, K23, K24, LT(_LOWER,K25), KC_SPC, LT(_RAISE,K26), K27, K28, K29, RCTL_T(K2A), KC_ENT \ | |||||
) | |||||
#define LAYOUT_base_wrapper(...) LAYOUT_base(__VA_ARGS__) | |||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||||
[_DEFAULT_LAYER_1] = LAYOUT_base_wrapper( | |||||
_________________QWERTY_L1_________________, _________________QWERTY_R1_________________, | |||||
_________________QWERTY_L2_________________, _________________QWERTY_R2_________________, | |||||
_________________QWERTY_L3_________________, _________________QWERTY_R3_________________ | |||||
), | |||||
[_DEFAULT_LAYER_2] = LAYOUT_base_wrapper( | |||||
______________COLEMAK_MOD_DH_L1____________, ______________COLEMAK_MOD_DH_R1____________, | |||||
______________COLEMAK_MOD_DH_L2____________, ______________COLEMAK_MOD_DH_R2____________, | |||||
______________COLEMAK_MOD_DH_L3____________, ______________COLEMAK_MOD_DH_R3____________ | |||||
), | |||||
[_DEFAULT_LAYER_3] = LAYOUT_base_wrapper( | |||||
_________________COLEMAK_L1________________, _________________COLEMAK_R1________________, | |||||
_________________COLEMAK_L2________________, _________________COLEMAK_R2________________, | |||||
_________________COLEMAK_L3________________, _________________COLEMAK_R3________________ | |||||
), | |||||
[_DEFAULT_LAYER_4] = LAYOUT_base_wrapper( | |||||
_________________DVORAK_L1_________________, _________________DVORAK_R1_________________, | |||||
_________________DVORAK_L2_________________, _________________DVORAK_R2_________________, | |||||
_________________DVORAK_L3_________________, _________________DVORAK_R3_________________ | |||||
), | |||||
[_LOWER] = LAYOUT_wrapper( | |||||
KC_TILD, _________________LOWER_L1__________________, _______, _________________LOWER_R1__________________, KC_BSPC, | |||||
KC_DEL, _________________LOWER_L2__________________, _______, _________________LOWER_R2__________________, KC_PIPE, | |||||
_______, _________________LOWER_L3__________________, _______, _________________LOWER_R3__________________, _______ | |||||
), | |||||
[_RAISE] = LAYOUT_wrapper( | |||||
KC_GRV, _________________RAISE_L1__________________, _______, _________________RAISE_R1__________________, KC_BSPC, | |||||
KC_DEL, _________________RAISE_L2__________________, _______, _________________RAISE_R2__________________, KC_BSLS, | |||||
_______, _________________RAISE_L3__________________, _______, _________________RAISE_R3__________________, _______ | |||||
), | |||||
[_ADJUST] = LAYOUT_wrapper( | |||||
QK_MAKE, _________________ADJUST_L1_________________, KC_NUKE, _________________ADJUST_R1_________________, QK_BOOT, | |||||
VRSN, _________________ADJUST_L2_________________, MG_NKRO, _________________ADJUST_R2_________________, EE_CLR, | |||||
TG_MODS, _________________ADJUST_L3_________________, KC_RGB_T,_________________ADJUST_R3_________________, RGB_IDL | |||||
) | |||||
}; | |||||
// clang-format on |
@ -1,3 +0,0 @@ | |||||
# @drashna's keymap for the C39 | |||||
HERE BE DRAGONS |
@ -1,19 +0,0 @@ | |||||
# MCU name | |||||
MCU = STM32F303 | |||||
BOARD = QMK_PROTON_C | |||||
# Bootloader selection | |||||
BOOTLOADER = stm32-dfu | |||||
BOOTMAGIC_ENABLE = yes # Enable Bootmagic Lite | |||||
MOUSEKEY_ENABLE = yes | |||||
EXTRAKEY_ENABLE = yes | |||||
CONSOLE_ENABLE = yes | |||||
COMMAND_ENABLE = yes | |||||
NKRO_ENABLE = yes | |||||
AUDIO_ENABLE = yes | |||||
UNICODE_ENABLE = yes | |||||
HAPTIC_ENABLE = yes | |||||
HAPTIC_DRIVER = SOLENOID | |||||
RGBLIGHT_STARTUP_ANIMATION = yes |
@ -0,0 +1,24 @@ | |||||
/* Copyright 2020 QMK | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. | |||||
*/ | |||||
#pragma once | |||||
#if defined(KEYBOARD_splitkb_kyria_rev3) | |||||
# define HAL_USE_I2C TRUE | |||||
# define HAL_USE_PWM TRUE | |||||
# define HAL_USE_SERIAL TRUE | |||||
#endif | |||||
#include_next <halconf.h> |
@ -0,0 +1,35 @@ | |||||
/* Copyright 2020 Nick Brassel (tzarc) | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. | |||||
*/ | |||||
#pragma once | |||||
#include_next <mcuconf.h> | |||||
#if defined(KEYBOARD_splitkb_kyria_rev3) | |||||
# undef STM32_PWM_USE_ADVANCED | |||||
# define STM32_PWM_USE_ADVANCED TRUE | |||||
# undef STM32_PWM_USE_TIM2 | |||||
# define STM32_PWM_USE_TIM2 TRUE | |||||
# undef STM32_PWM_USE_TIM3 | |||||
# define STM32_PWM_USE_TIM3 FALSE | |||||
# undef STM32_SERIAL_USE_USART1 | |||||
# define STM32_SERIAL_USE_USART1 TRUE | |||||
# undef STM32_ST_USE_TIMER | |||||
# define STM32_ST_USE_TIMER 3 | |||||
#endif |
@ -1,7 +0,0 @@ | |||||
# The default keymap for zima | |||||
This includes support for the OLED and Encoder. However, the actual code is found in the `zima.c` file. This can be replaced by adding your own `oled_task_user(void)` and `encoder_update_user` functinons. These will replace what is in the keyboard, and allow you to customize these features. | |||||
The reason that this is done this way, is so that this functionality will work on the [QMK Configurator](https://config.qmk.fm/#/splitkb/zima/LAYOUT_ortho_4x3) | |||||
For reference, the code used for the oled and encoder defaults is in [zima.c](https://github.com/qmk/qmk_firmware/tree/master/keyboards/splitkb/zima/zima.c). |
@ -1,10 +1,10 @@ | |||||
BOOTMAGIC_ENABLE = yes # Enable Bootmagic Lite | |||||
BOOTMAGIC_ENABLE = yes | |||||
EXTRAKEY_ENABLE = yes | EXTRAKEY_ENABLE = yes | ||||
MOUSEKEY_ENABLE = yes | MOUSEKEY_ENABLE = yes | ||||
TAP_DANCE_ENABLE = no | TAP_DANCE_ENABLE = no | ||||
NKRO_ENABLE = yes | NKRO_ENABLE = yes | ||||
RGBLIGHT_STARTUP_ANIMATION = yes | |||||
RGBLIGHT_STARTUP_ANIMATION = no | |||||
ENCODER_MAP_ENABLE = yes | ENCODER_MAP_ENABLE = yes | ||||
AUTOCORRECT_ENABLE = no | |||||
CUSTOM_UNICODE_ENABLE = no | |||||
AUTOCORRECT_ENABLE = no | |||||
CUSTOM_UNICODE_ENABLE = no |
@ -0,0 +1,53 @@ | |||||
// Copyright 2023 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#include "eeconfig_users.h" | |||||
#include "eeprom.h" | |||||
#include "eeconfig.h" | |||||
#include <string.h> | |||||
#if (TOTAL_EEPROM_BYTE_COUNT - 1) < EECONFIG_SIZE && !defined(KEYBOARD_input_club_ergodox_infinity) | |||||
# error "More eeprom configured than is available." | |||||
#endif | |||||
#if (EECONFIG_USER_DATA_SIZE) != 0 && (EECONFIG_USER_DATA_SIZE) < 4 | |||||
# error "Not enough EEPROM configured for user config." | |||||
#endif | |||||
#if (EECONFIG_USER_DATA_SIZE) == 0 | |||||
# define EECONFIG_USER_TEMP EECONFIG_USER | |||||
#else | |||||
# define EECONFIG_USER_TEMP (uint32_t *)(EECONFIG_USER_DATABLOCK) | |||||
#endif | |||||
void eeconfig_read_user_config(uint32_t *data) { | |||||
#if (EECONFIG_USER_DATA_SIZE) > 0 | |||||
if (!eeconfig_is_user_datablock_valid()) { | |||||
memset(data, 0, 4); | |||||
} else | |||||
#endif | |||||
eeprom_read_block(data, EECONFIG_USER_TEMP, 4); | |||||
} | |||||
void eeconfig_update_user_config(const uint32_t *data) { | |||||
eeprom_update_block(data, EECONFIG_USER_TEMP, 4); | |||||
#if (EECONFIG_USER_DATA_SIZE) > 0 | |||||
eeprom_update_dword(EECONFIG_USER, (EECONFIG_USER_DATA_VERSION)); | |||||
#endif | |||||
} | |||||
void eeconfig_read_user_data(void *data) { | |||||
#if (EECONFIG_USER_DATA_SIZE) > 4 | |||||
if (eeconfig_is_user_datablock_valid()) { | |||||
eeprom_read_block(data, EECONFIG_USER_DATABLOCK + 4, (EECONFIG_USER_DATA_SIZE)-4); | |||||
} else { | |||||
memset(data, 0, (EECONFIG_USER_DATA_SIZE)); | |||||
} | |||||
#endif | |||||
} | |||||
void eeconfig_update_user_data(const void *data) { | |||||
#if (EECONFIG_USER_DATA_SIZE) > 4 | |||||
eeprom_update_dword(EECONFIG_USER, (EECONFIG_USER_DATA_VERSION)); | |||||
eeprom_update_block(data, EECONFIG_USER_DATABLOCK + 4, (EECONFIG_USER_DATA_SIZE)-4); | |||||
#endif | |||||
} |
@ -0,0 +1,12 @@ | |||||
// Copyright 2023 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#pragma once | |||||
#include <stdint.h> | |||||
void eeconfig_read_user_config(uint32_t *data); | |||||
void eeconfig_update_user_config(const uint32_t *data); | |||||
void eeconfig_read_user_data(void *data); | |||||
void eeconfig_update_user_data(const void *data); |
@ -0,0 +1,283 @@ | |||||
// Copyright 2016 Jack Humbert | |||||
// Copyright 2019 Wojciech Siewierski < wojciech dot siewierski at onet dot pl > | |||||
// Copyright 2023 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#include "keyrecords/dynamic_macros.h" | |||||
#include "keyrecords/process_records.h" | |||||
#include "wait.h" | |||||
#include "debug.h" | |||||
#include "eeprom.h" | |||||
#include "eeconfig.h" | |||||
#include <string.h> | |||||
static uint8_t macro_id = 255; | |||||
static uint8_t recording_state = STATE_NOT_RECORDING; | |||||
#if EECONFIG_USER_DATA_SIZE < 4 | |||||
# error "EECONFIG_USER_DATA_SIZE not set. Don't step on others eeprom." | |||||
#endif | |||||
#ifndef DYNAMIC_MACRO_EEPROM_BLOCK0_ADDR | |||||
# define DYNAMIC_MACRO_EEPROM_BLOCK0_ADDR (uint8_t*)(EECONFIG_USER_DATABLOCK + 4) | |||||
#endif | |||||
dynamic_macro_t dynamic_macros[DYNAMIC_MACRO_COUNT]; | |||||
_Static_assert((sizeof(dynamic_macros)) <= (EECONFIG_USER_DATA_SIZE - 4), "User Data Size must be large enough to host all macros"); | |||||
__attribute__((weak)) void dynamic_macro_record_start_user(void) {} | |||||
__attribute__((weak)) void dynamic_macro_play_user(uint8_t macro_id) {} | |||||
__attribute__((weak)) void dynamic_macro_record_key_user(uint8_t macro_id, keyrecord_t* record) {} | |||||
__attribute__((weak)) void dynamic_macro_record_end_user(uint8_t macro_id) {} | |||||
/** | |||||
* @brief Gets the current macro ID | |||||
* | |||||
* @return uint8_t | |||||
*/ | |||||
uint8_t dynamic_macro_get_current_id(void) { | |||||
return macro_id; | |||||
} | |||||
/** | |||||
* @brief Gets the current recording state | |||||
* | |||||
* @return uint8_t | |||||
*/ | |||||
uint8_t dynamic_macro_get_recording_state(void) { | |||||
return recording_state; | |||||
} | |||||
/** | |||||
* Start recording of the dynamic macro. | |||||
* | |||||
* @param macro_id[in] The id of macro to be recorded | |||||
*/ | |||||
bool dynamic_macro_record_start(uint8_t macro_id) { | |||||
if (macro_id >= (uint8_t)(DYNAMIC_MACRO_COUNT)) { | |||||
return false; | |||||
} | |||||
dprintf("dynamic macro recording: started for slot %d\n", macro_id); | |||||
dynamic_macro_record_start_user(); | |||||
clear_keyboard(); | |||||
layer_clear(); | |||||
dynamic_macros[macro_id].length = 0; | |||||
return true; | |||||
} | |||||
/** | |||||
* Play the dynamic macro. | |||||
* | |||||
* @param macro_id[in] The id of macro to be played | |||||
*/ | |||||
void dynamic_macro_play(uint8_t macro_id) { | |||||
if (macro_id >= (uint8_t)(DYNAMIC_MACRO_COUNT)) { | |||||
return; | |||||
} | |||||
dprintf("dynamic macro: slot %d playback, length %d\n", macro_id, dynamic_macros[macro_id].length); | |||||
layer_state_t saved_layer_state = layer_state; | |||||
clear_keyboard(); | |||||
layer_clear(); | |||||
for (uint8_t i = 0; i < dynamic_macros[macro_id].length; ++i) { | |||||
process_record(&dynamic_macros[macro_id].events[i]); | |||||
} | |||||
clear_keyboard(); | |||||
layer_state_set(saved_layer_state); | |||||
dynamic_macro_play_user(macro_id); | |||||
} | |||||
/** | |||||
* Record a single key in a dynamic macro. | |||||
* | |||||
* @param macro_id[in] The start of the used macro buffer. | |||||
* @param record[in] The current keypress. | |||||
*/ | |||||
void dynamic_macro_record_key(uint8_t macro_id, keyrecord_t* record) { | |||||
dynamic_macro_t* macro = &dynamic_macros[macro_id]; | |||||
uint8_t length = macro->length; | |||||
/* If we've just started recording, ignore all the key releases. */ | |||||
if (!record->event.pressed && length == 0) { | |||||
dprintln("dynamic macro: ignoring a leading key-up event"); | |||||
return; | |||||
} | |||||
if (length < DYNAMIC_MACRO_SIZE) { | |||||
macro->events[length] = *record; | |||||
macro->length = ++length; | |||||
} else { | |||||
dynamic_macro_record_key_user(macro_id, record); | |||||
} | |||||
dprintf("dynamic macro: slot %d length: %d/%d\n", macro_id, length, DYNAMIC_MACRO_SIZE); | |||||
} | |||||
/** | |||||
* End recording of the dynamic macro. Essentially just update the | |||||
* pointer to the end of the macro. | |||||
*/ | |||||
void dynamic_macro_record_end(uint8_t macro_id) { | |||||
if (macro_id >= (uint8_t)(DYNAMIC_MACRO_COUNT)) { | |||||
return; | |||||
} | |||||
dynamic_macro_record_end_user(macro_id); | |||||
dynamic_macro_t* macro = &dynamic_macros[macro_id]; | |||||
uint8_t length = macro->length; | |||||
keyrecord_t* events_begin = &(macro->events[0]); | |||||
keyrecord_t* events_pointer = &(macro->events[length - 1]); | |||||
dprintf("dynamic_macro: macro length before trimming: %d\n", macro->length); | |||||
while (events_pointer != events_begin && (events_pointer)->event.pressed) { | |||||
dprintln("dynamic macro: trimming a trailing key-down event"); | |||||
--(macro->length); | |||||
--events_pointer; | |||||
} | |||||
macro->checksum = dynamic_macro_calc_crc(macro); | |||||
dynamic_macro_save_eeprom(macro_id); | |||||
dprintf("dynamic macro: slot %d saved, length: %d\n", macro_id, length); | |||||
} | |||||
bool process_record_dynamic_macro(uint16_t keycode, keyrecord_t* record) { | |||||
if (STATE_NOT_RECORDING == recording_state) { | |||||
/* Program key pressed to request programming mode */ | |||||
if (keycode == DYN_MACRO_PROG && record->event.pressed) { | |||||
// dynamic_macro_led_blink(); | |||||
recording_state = STATE_RECORD_KEY_PRESSED; | |||||
dprintf("dynamic macro: programming key pressed, waiting for macro slot selection. %d\n", recording_state); | |||||
return false; | |||||
} | |||||
/* Macro key pressed to request macro playback */ | |||||
if (IS_DYN_KEYCODE(keycode) && record->event.pressed) { | |||||
dynamic_macro_play(keycode - DYN_MACRO_KEY00); | |||||
return false; | |||||
} | |||||
/* Non-dynamic macro key, process it elsewhere. */ | |||||
return true; | |||||
} else if (STATE_RECORD_KEY_PRESSED == recording_state) { | |||||
/* Program key pressed again before a macro selector key, cancel macro recording. | |||||
Blink leds to indicate cancelation. */ | |||||
if (keycode == DYN_MACRO_PROG && record->event.pressed) { | |||||
// dynamic_macro_led_blink(); | |||||
recording_state = STATE_NOT_RECORDING; | |||||
dprintf("dynamic macro: programming key pressed, programming mode canceled. %d\n", recording_state); | |||||
return false; | |||||
} else if (IS_DYN_KEYCODE(keycode) && record->event.pressed) { | |||||
macro_id = keycode - DYN_MACRO_KEY00; | |||||
if (dynamic_macro_record_start(macro_id)) { | |||||
/* Macro slot selected, enter recording state. */ | |||||
recording_state = STATE_CURRENTLY_RECORDING; | |||||
} else { | |||||
recording_state = STATE_NOT_RECORDING; | |||||
} | |||||
return false; | |||||
} | |||||
/* Ignore any non-macro key press while in RECORD_KEY_PRESSED state. */ | |||||
return false; | |||||
} else if (STATE_CURRENTLY_RECORDING == recording_state) { | |||||
/* Program key pressed to request end of macro recording. */ | |||||
if (keycode == DYN_MACRO_PROG && record->event.pressed) { | |||||
dynamic_macro_record_end(macro_id); | |||||
recording_state = STATE_NOT_RECORDING; | |||||
return false; | |||||
} | |||||
/* Don't record other macro key presses. */ | |||||
else if (IS_DYN_KEYCODE(keycode) && record->event.pressed) { | |||||
dprintln("dynamic macro: playback key ignored in programming mode."); | |||||
return false; | |||||
} | |||||
/* Non-macro keypress that should be recorded */ | |||||
else { | |||||
dynamic_macro_record_key(macro_id, record); | |||||
/* Don't output recorded keypress. */ | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
static inline uint16_t crc16_update(uint16_t crc, uint8_t a) { | |||||
crc ^= a; | |||||
for (uint8_t i = 0; i < 8; ++i) { | |||||
if (crc & 1) | |||||
crc = (crc >> 1) ^ 0xA001; | |||||
else | |||||
crc = (crc >> 1); | |||||
} | |||||
return crc; | |||||
} | |||||
uint16_t dynamic_macro_calc_crc(dynamic_macro_t* macro) { | |||||
uint16_t crc = 0; | |||||
uint8_t* data = (uint8_t*)macro; | |||||
for (uint16_t i = 0; i < DYNAMIC_MACRO_CRC_LENGTH; ++i) { | |||||
crc = crc16_update(crc, *(data++)); | |||||
} | |||||
return crc; | |||||
} | |||||
inline void* dynamic_macro_eeprom_macro_addr(uint8_t macro_id) { | |||||
return DYNAMIC_MACRO_EEPROM_BLOCK0_ADDR + sizeof(dynamic_macro_t) * macro_id; | |||||
} | |||||
void dynamic_macro_load_eeprom_all(void) { | |||||
for (uint8_t i = 0; i < DYNAMIC_MACRO_COUNT; ++i) { | |||||
dynamic_macro_load_eeprom(i); | |||||
} | |||||
} | |||||
void dynamic_macro_load_eeprom(uint8_t macro_id) { | |||||
dynamic_macro_t* dst = &dynamic_macros[macro_id]; | |||||
eeprom_read_block(dst, dynamic_macro_eeprom_macro_addr(macro_id), sizeof(dynamic_macro_t)); | |||||
/* Validate checksum, ifchecksum is NOT valid for macro, set its length to 0 to prevent its use. */ | |||||
if (dynamic_macro_calc_crc(dst) != dst->checksum) { | |||||
dprintf("dynamic macro: slot %d not loaded, checksum mismatch\n", macro_id); | |||||
dst->length = 0; | |||||
return; | |||||
} | |||||
dprintf("dynamic macro: slot %d loaded from eeprom, checksum okay\n", macro_id); | |||||
} | |||||
void dynamic_macro_save_eeprom(uint8_t macro_id) { | |||||
dynamic_macro_t* src = &dynamic_macros[macro_id]; | |||||
eeprom_update_block(src, dynamic_macro_eeprom_macro_addr(macro_id), sizeof(dynamic_macro_t)); | |||||
dprintf("dynamic macro: slot %d saved to eeprom\n", macro_id); | |||||
} | |||||
void dynamic_macro_init(void) { | |||||
/* zero out macro blocks */ | |||||
memset(&dynamic_macros, 0, DYNAMIC_MACRO_COUNT * sizeof(dynamic_macro_t)); | |||||
dynamic_macro_load_eeprom_all(); | |||||
} |
@ -0,0 +1,50 @@ | |||||
// Copyright 2016 Jack Humbert | |||||
// Copyright 2019 Wojciech Siewierski < wojciech dot siewierski at onet dot pl > | |||||
// Copyright 2023 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#pragma once | |||||
#include "action.h" | |||||
#include "action_layer.h" | |||||
#ifndef DYNAMIC_MACRO_COUNT | |||||
# define DYNAMIC_MACRO_COUNT 8 | |||||
#endif | |||||
#ifndef DYNAMIC_MACRO_SIZE | |||||
# define DYNAMIC_MACRO_SIZE 64 | |||||
#endif | |||||
enum dynamic_macro_recording_state { | |||||
STATE_NOT_RECORDING, | |||||
STATE_RECORD_KEY_PRESSED, | |||||
STATE_CURRENTLY_RECORDING, | |||||
}; | |||||
typedef struct { | |||||
keyrecord_t events[DYNAMIC_MACRO_SIZE]; | |||||
uint8_t length; | |||||
uint16_t checksum; | |||||
} dynamic_macro_t; | |||||
void dynamic_macro_init(void); | |||||
bool dynamic_macro_record_start(uint8_t macro_id); | |||||
void dynamic_macro_play(uint8_t macro_id); | |||||
void dynamic_macro_record_key(uint8_t macro_id, keyrecord_t* record); | |||||
void dynamic_macro_record_end(uint8_t macro_id); | |||||
bool process_record_dynamic_macro(uint16_t keycode, keyrecord_t* record); | |||||
void dynamic_macro_record_start_user(void); | |||||
void dynamic_macro_play_user(uint8_t macro_id); | |||||
void dynamic_macro_record_key_user(uint8_t macro_id, keyrecord_t* record); | |||||
void dynamic_macro_record_end_user(uint8_t macro_id); | |||||
#define DYNAMIC_MACRO_CRC_LENGTH (sizeof(dynamic_macro_t) - sizeof(uint16_t)) | |||||
#define IS_DYN_KEYCODE(keycode) (keycode >= DYN_MACRO_KEY00 && keycode <= DYN_MACRO_KEY15) | |||||
uint16_t dynamic_macro_calc_crc(dynamic_macro_t* macro); | |||||
void dynamic_macro_load_eeprom_all(void); | |||||
void dynamic_macro_load_eeprom(uint8_t macro_id); | |||||
void dynamic_macro_save_eeprom(uint8_t macro_id); | |||||
bool dynamic_macro_header_correct(void); |
@ -0,0 +1,207 @@ | |||||
// Copyright 2023 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | |||||
// SPDX-License-Identifier: GPL-2.0-or-later | |||||
#pragma once | |||||
// clang-format off | |||||
static const char PROGMEM code_to_name[256] = { | |||||
// 0 1 2 3 4 5 6 7 8 9 A B c D E F | |||||
' ', ' ', ' ', ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', // 0x | |||||
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', // 1x | |||||
'3', '4', '5', '6', '7', '8', '9', '0', 20, 19, 27, 26, 22, '-', '=', '[', // 2x | |||||
']','\\', '#', ';','\'', '`', ',', '.', '/', 128,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA, // 3x | |||||
0xDB,0xDC,0xDD,0xDE,0XDF,0xFB, 'P', 'S', 19, ' ', 17, 30, 16, 16, 31, 26, // 4x | |||||
27, 25, 24, 'N', '/', '*', '-', '+', 23, '1', '2', '3', '4', '5', '6', '7', // 5x | |||||
'8', '9', '0', '.','\\', 'A', 0, '=', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 6x | |||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 7x | |||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 8x | |||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 9x | |||||
' ', ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // Ax | |||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // Bx | |||||
' ',0x9E,0x9E, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',0x9D,0x9D,0x9D,0x9D, // Cx | |||||
0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D, // Dx | |||||
'C', 'S', 'A', 'G', 'C', 'S', 'A', 'G', ' ', ' ', ' ', ' ', ' ', 24, 26, 24, // Ex | |||||
25, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 24, 25, 27, 26, ' ', ' ', ' ' // Fx | |||||
}; | |||||
static const char PROGMEM gmk_bad_logo[384] = { | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF0, 0x70, 0x38, 0x38, 0x38, 0x78, 0x70, 0xF0, 0xE0, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF0, 0xF8, 0xF8, 0xF8, 0xF8, 0x00, 0x00, 0x00, 0x80, 0xE0, 0xF8, 0xF8, 0xF8, 0xF8, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF8, 0xF8, 0xF8, 0x38, 0x00, 0x80, 0xE0, 0xF0, 0xF8, 0x78, 0x38, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF8, 0xF8, 0xF8, 0x38, 0x38, 0x38, 0xF8, 0xF0, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFC, 0xFC, 0xFC, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xFF, 0xFF, 0xFF, 0xC1, 0x80, 0x00, 0x00, 0x38, 0x38, 0xB8, 0xB8, 0xF9, 0xF9, 0xF8, 0x38, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF8, 0xFF, 0xFF, 0x1F, 0x01, 0x3F, 0xFF, 0xFF, 0xF0, 0xFE, 0x7F, 0x0F, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0x3F, 0x1E, 0x7F, 0xFF, 0xFF, 0xF3, 0xC1, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0x3F, 0x1C, 0x1C, 0x9C, 0xFF, 0xFF, 0xF3, 0xE1, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFC, 0xFE, 0xFF, 0x0F, 0x07, 0x07, 0x8E, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFC, 0xFE, 0xFF, 0x8F, 0x07, 0x07, 0x8E, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x07, 0x07, 0x07, 0x07, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x07, 0x07, 0x07, 0x01, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x01, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x07, 0x07, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x07, 0x07, 0x07, 0x03, 0x07, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x07, 0x07, 0x07, 0x03, 0x07, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x07, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 | |||||
}; | |||||
static const char PROGMEM hue_manitee_logo[384] = { | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0x90, 0x70, 0xE8, 0xA8, 0xE4, 0xC4, 0xC4, 0xA0, 0xE4, 0xB0, 0xDC, 0xE4, 0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0xFC, 0xF8, 0xF0, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFC, 0xF6, 0xF7, 0xEF, 0xFF, 0x87, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x1F, 0x1F, 0x19, 0x15, 0xF7, 0x16, 0x1A, 0x1B, 0x16, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xC0, 0xC0, 0x00, 0x00, 0x03, 0x03, 0xFF, 0xFF, 0x03, 0x03, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x30, 0x30, 0xCC, 0xCC, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x07, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x07, 0x03, 0x00, 0x00, 0x02, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |||||
}; | |||||
static const char PROGMEM corne_logo[384] = { | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xF8, 0x18, 0x00, 0xC0, 0xF0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0xC0, 0xC0, 0xE0, 0xE0, 0xE0, 0xE0, 0x00, 0x00, 0xE0, 0xE0, 0xC0, 0xC0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFC, 0xFE, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xC3, 0xC3, 0xC3, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x9D, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x9D, 0xDF, 0xDF, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x1F, 0x3F, 0x3F, 0x7F, 0x7F, 0x7F, 0x3F, 0x3F, 0x1F, 0x3F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7C, 0x78, 0x78, 0x38, 0x1C, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |||||
}; | |||||
static const char PROGMEM loose_logo[384] = { | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x00, 0xFC, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x02, 0xF9, 0x01, 0x01, 0x05, 0x09, 0x11, 0x22, 0x06, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x46, 0x46, 0x44, 0x44, 0x45, 0x44, 0x29, 0x28, 0x2A, 0x28, 0x11, 0x13, 0x05, 0x07, 0x05, 0x07, 0x05, 0x07, 0x05, 0x07, 0xE5, 0xE7, 0xE5, 0x07, 0x05, 0x07, 0x05, 0x07, 0x05, 0x07, 0x05, 0x07, 0x85, 0xC7, 0xE5, 0xE7, 0xE5, 0xE7, 0xE5, 0xE7, 0xE5, 0xC7, 0x85, 0x07, 0x85, 0xC7, 0xE5, 0xE7, 0xE5, 0xE7, 0xE5, 0xE7, 0xE5, 0xC7, 0x85, 0x07, 0x85, 0xC7, 0xE5, 0xE7, 0xE5, 0xE7, 0xE5, 0xE7, 0xE5, 0xE7, 0xE5, 0x07, 0xE5, 0xE7, 0xE5, 0xE7, 0xE5, 0xE7, 0xE5, 0xE7, 0xE5, 0xE7, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC1, 0xC1, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x80, 0x00, 0x1C, 0x3E, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x14, 0x14, 0x14, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xBE, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x81, 0xBD, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x8F, 0x9F, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0xFC, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x20, 0x47, 0x48, 0x50, 0x40, 0x41, 0x42, 0x24, 0x30, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x31, 0x31, 0x11, 0x51, 0x11, 0x11, 0x4A, 0x0A, 0x2A, 0x0A, 0x44, 0x64, 0x50, 0x70, 0x50, 0x70, 0x50, 0x70, 0x50, 0x70, 0x53, 0x73, 0x53, 0x73, 0x53, 0x73, 0x53, 0x73, 0x53, 0x73, 0x53, 0x70, 0x50, 0x71, 0x53, 0x73, 0x53, 0x73, 0x53, 0x73, 0x53, 0x71, 0x50, 0x70, 0x50, 0x71, 0x53, 0x73, 0x53, 0x73, 0x53, 0x73, 0x53, 0x71, 0x50, 0x70, 0x53, 0x73, 0x53, 0x73, 0x53, 0x73, 0x53, 0x73, 0x53, 0x73, 0x51, 0x70, 0x53, 0x73, 0x53, 0x73, 0x53, 0x73, 0x53, 0x73, 0x53, 0x73, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |||||
}; | |||||
static const char PROGMEM skeeb_logo[384] = { | |||||
0xC0, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x01, 0xFF, 0xFF, 0x01, 0x01, 0xFF, 0xFF, 0x01, 0x01, 0xFF, 0xFF, 0x19, 0x19, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x01, 0x01, 0xFF, 0xFF, 0x81, 0x81, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x19, 0x19, 0xFF, 0xFF, 0xF9, 0xF9, 0xF9, 0xF9, 0x01, 0x01, 0xF9, 0xF9, 0xF9, 0xF9, 0xFF, 0xFF, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xF9, 0xF9, 0xFF, 0xFF, 0x19, 0x19, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x67, 0x67, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0xC0, 0x00, | |||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0x08, 0x08, 0x0F, 0x0F, 0x0E, 0x0E, 0x0F, 0x0F, 0x08, 0x08, 0x0F, 0x0F, 0x08, 0x08, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x08, 0x08, 0x0F, 0x0F, 0x09, 0x09, 0x09, 0x09, 0xF9, 0xF9, 0x09, 0x09, 0x08, 0x08, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x08, 0x08, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0F, 0x0F, 0x08, 0x08, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x08, 0x08, 0x0F, 0x0F, 0x0F, 0x0F, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, | |||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xFF, 0x08, 0x08, 0x0F, 0x0F, 0x08, 0x08, 0x03, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x03, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x01, 0x02, 0xFC, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00 | |||||
}; | |||||
static const char PROGMEM qmk_logo[384] = { | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0xF0, 0xF8, 0xF8, 0xFF, 0x38, 0xFF, 0xF8, 0xF8, 0x3F, 0xF8, 0xF8, 0xFF, 0x38, 0xFF, 0xF8, 0xF8, 0xF0, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0xC0, 0x80, 0x00, 0x00, 0xC0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x49, 0x49, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xDF, 0xBF, 0xBF, 0x00, 0xBF, 0xBF, 0xDF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x49, 0x49, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x3F, 0x60, 0x60, 0xE0, 0xBF, 0x1F, 0x00, 0x7F, 0x7F, 0x07, 0x1E, 0x38, 0x1E, 0x07, 0x7F, 0x7F, 0x00, 0x7F, 0x7F, 0x0E, 0x1F, 0x3B, 0x71, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x0C, 0x0C, 0x0C, 0x00, 0x7E, 0x7E, 0x00, 0x7F, 0x7E, 0x03, 0x03, 0x00, 0x7F, 0x7E, 0x03, 0x03, 0x7E, 0x7E, 0x03, 0x03, 0x7F, 0x7E, 0x00, 0x0F, 0x3E, 0x70, 0x3C, 0x06, 0x3C, 0x70, 0x3E, 0x0F, 0x00, 0x32, 0x7B, 0x49, 0x49, 0x3F, 0x7E, 0x00, 0x7F, 0x7E, 0x03, 0x03, 0x00, 0x1E, 0x3F, 0x69, 0x69, 0x6F, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x07, 0x0F, 0x0F, 0x7F, 0x0F, 0x7F, 0x0F, 0x0F, 0x7E, 0x0F, 0x0F, 0x7F, 0x0F, 0x7F, 0x0F, 0x0F, 0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |||||
}; | |||||
static const char PROGMEM qmk_large_logo[1024] = { | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x3f, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x83, 0x83, 0x83, 0x83, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x83, 0x83, 0x83, 0x83, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x83, 0x83, 0x83, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x1f, 0x3f, 0x7f, 0x7e, 0xf8, 0xf0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf8, 0x7e, 0x7f, 0x3f, 0x1f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xfc, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |||||
}; | |||||
static const char PROGMEM header_image[128] = { 0x00, 0xC0, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0xC0 }; | |||||
static const char PROGMEM row_2_image[128] = { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }; | |||||
static const char PROGMEM display_border[3] = {0x0, 0xFF, 0x0}; | |||||
static const char PROGMEM footer_image[128] = { 0x00, 0x03, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x03 }; | |||||
static const char PROGMEM mouse_logo[3][2][16] = { | |||||
{ // mouse icon | |||||
{ 0x00, 0x00, 0x00, 0xFC, 0x02, 0x02, 0x02, 0x3A, 0x02, 0x02, 0x02, 0xFC, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x3F, 0x60, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x60, 0x3F, 0x00, 0x00, 0x00 } | |||||
}, | |||||
{ // crosshair icon | |||||
{0x80, 0xF0, 0x88, 0xE4, 0x92, 0x8A, 0xCA, 0x7F, 0xCA, 0x8A, 0x92, 0xE4, 0x88, 0xF0, 0x80, 0x00 }, | |||||
{0x00, 0x07, 0x08, 0x13, 0x24, 0x28, 0x29, 0x7F, 0x29, 0x28, 0x24, 0x13, 0x08, 0x07, 0x00, 0x00 } | |||||
}, | |||||
{ // dragscroll icon | |||||
{0x00, 0x00, 0x70, 0x88, 0x9C, 0x02, 0x0F, 0x01, 0x0F, 0x02, 0x8C, 0x44, 0x38, 0x00, 0x00, 0x00}, | |||||
{0x00, 0x00, 0x02, 0x06, 0x0F, 0x1C, 0x3C, 0x7C, 0x3C, 0x1C, 0x0F, 0x06, 0x02, 0x00, 0x00, 0x00} | |||||
} | |||||
}; | |||||
// Images credit j-inc(/James Incandenza) and pixelbenny. | |||||
// Credit to obosob for initial animation approach. | |||||
// heavily modified by drashna because he's a glutton for punishment | |||||
#define OLED_ANIM_SIZE 36 | |||||
#define OLED_ANIM_ROWS 4 | |||||
#define OLED_ANIM_MAX_FRAMES 3 | |||||
static const char PROGMEM animation[4][OLED_ANIM_MAX_FRAMES][OLED_ANIM_ROWS][OLED_ANIM_SIZE] = { | |||||
{ // sleep frames | |||||
{ | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0xa8, 0x48, 0xa8, 0x18, 0x08, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x80, 0x44, 0x84, 0x06, 0x05, 0x04, 0x80, 0x40, 0x20, 0x10, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x18, 0x04, 0x04, 0x02, 0x7a, 0x86, 0x01, 0x80, 0x80, 0x01, 0x03, 0x05, 0x07, 0x01, 0x00, 0x00, 0x80, 0x83, 0x45, 0xfa, 0x3c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x33, 0x24, 0x28, 0x28, 0x29, 0x29, 0x29, 0x3a, 0x18, 0x1c, 0x39, 0x24, 0x24, 0x3a, 0x2d, 0x26, 0x31, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00 } | |||||
}, | |||||
{ | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x3a, 0x2a, 0x26, 0x22, 0x80, 0xc0, 0x80, 0x00, 0x24, 0x34, 0x2c, 0xe4, 0x60, 0x10, 0x70, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x38, 0x04, 0x02, 0x02, 0x01, 0x79, 0x87, 0x01, 0x80, 0x81, 0x83, 0x05, 0x05, 0x03, 0x01, 0x00, 0x00, 0x80, 0x43, 0x05, 0xfa, 0x3c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x33, 0x24, 0x28, 0x28, 0x28, 0x29, 0x29, 0x3a, 0x18, 0x1c, 0x39, 0x24, 0x24, 0x3a, 0x2d, 0x26, 0x31, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00 } | |||||
} | |||||
}, | |||||
{ // wake frames | |||||
{ | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x30, 0x08, 0x10, 0x60, 0x80, 0x00, 0x80, 0x60, 0x10, 0x08, 0x30, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x80, 0x40, 0x40, 0x5c, 0x00, 0x01, 0x41, 0x01, 0x00, 0x5c, 0x40, 0x40, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x80, 0xe1, 0x12, 0x0a, 0x06, 0x00, 0x80, 0x00, 0x06, 0x0a, 0x12, 0xe1, 0x80, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x10, 0x10, 0x1f, 0x11, 0x10, 0x10, 0x14, 0x14, 0x1f, 0x1c, 0x14, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00 } | |||||
}, | |||||
{ | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x30, 0x08, 0x10, 0x60, 0x80, 0x00, 0x80, 0x60, 0x10, 0x08, 0x30, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x90, 0x12, 0x0a, 0x02, 0xf4, 0x09, 0x0d, 0xf1, 0x04, 0x02, 0x0a, 0x12, 0x90, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x80, 0xe1, 0x12, 0x0a, 0x06, 0x01, 0x81, 0x00, 0x06, 0x0a, 0x12, 0xe1, 0x80, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x10, 0x10, 0x1f, 0x11, 0x10, 0x10, 0x14, 0x14, 0x1f, 0x1c, 0x14, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00 } | |||||
} | |||||
}, | |||||
{ // kaki frames | |||||
{ | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x40, 0x80, 0x80, 0x80, 0x00, 0xfc, 0x84, 0x08, 0x08, 0x10, 0x20, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1e, 0x60, 0x80, 0x00, 0x00, 0x91, 0xa1, 0x80, 0x00, 0x00, 0x22, 0x84, 0x40, 0x50, 0x48, 0xc1, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x41, 0x82, 0xe2, 0x12, 0x0a, 0x06, 0x00, 0x80, 0x88, 0x4f, 0x02, 0x22, 0xe2, 0x9f, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x14, 0x10, 0x10, 0x10, 0x10, 0x10, 0x14, 0x14, 0x1f, 0x1a, 0x0a, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 } | |||||
}, | |||||
{ | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x06, 0x1a, 0x22, 0xc2, 0x04, 0x04, 0x04, 0x07, 0x00, 0xc0, 0x20, 0x10, 0x80, 0x80, 0x01, 0x01, 0x02, 0xfc, 0xfe, 0x02, 0x3c, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0d, 0x8d, 0x55, 0x50, 0x94, 0xf0, 0x10, 0x09, 0x08, 0x00, 0x80, 0x00, 0x06, 0x09, 0x1b, 0xee, 0x00, 0x00, 0x00, 0x00, 0x81, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x10, 0x10, 0x1f, 0x19, 0x18, 0x1c, 0x14, 0x16, 0x15, 0x14, 0x14, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00 } | |||||
}, | |||||
{ | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x01, 0x02, 0x04, 0x04, 0x03, 0x80, 0x40, 0x40, 0x20, 0x00, 0x01, 0x02, 0x8c, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0d, 0x8d, 0x55, 0x50, 0x94, 0xf0, 0x10, 0x0a, 0x0e, 0x1d, 0x95, 0x24, 0x24, 0x27, 0x13, 0xe1, 0x01, 0x01, 0x01, 0x01, 0x02, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x10, 0x10, 0x1f, 0x19, 0x18, 0x1c, 0x14, 0x14, 0x17, 0x14, 0x14, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00 } | |||||
} | |||||
}, | |||||
{ // rtogi frames | |||||
{ | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x10, 0x10, 0x08, 0x04, 0x02, 0x01, 0x0f, 0x90, 0x10, 0x20, 0xf0, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x48, 0x47, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x88, 0xc7, 0xc4, 0x62, 0x23, 0x11, 0x3f, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x80, 0x40, 0x20, 0x10, 0x88, 0xcc, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x80, 0x80, 0xc0, 0xe1, 0xfe, 0xb8, 0x88, 0x0c, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x06, 0x04, 0x04, 0x04, 0x04, 0x05, 0x04, 0x04, 0x04, 0x07, 0x07, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } | |||||
}, | |||||
{ | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x10, 0x10, 0x08, 0x04, 0x02, 0x01, 0x1f, 0xa0, 0x20, 0x40, 0x80, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x48, 0x47, 0x88, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x28, 0x6b, 0x40, 0xa0, 0x99, 0x86, 0xff, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x0f, 0x11, 0x22, 0x44, 0x48, 0x4c, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x80, 0x80, 0xc0, 0xe1, 0xfe, 0xb8, 0x88, 0x0c, 0x04, 0x06, 0x06, 0x06, 0x0e, 0x0e, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x06, 0x04, 0x04, 0x04, 0x04, 0x05, 0x04, 0x04, 0x04, 0x07, 0x07, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } | |||||
} | |||||
} | |||||
}; | |||||
static const char PROGMEM tri_layer_image[][3][24] = { | |||||
{ // base | |||||
{ 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x88, 0x88, 0x5D, 0x5D, 0x3E, 0x3E, 0x7C, 0x7C, 0xF8, 0xF8, 0x7C, 0x7C, 0x3E, 0x3E, 0x5D, 0x5D, 0x88, 0x88, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 } | |||||
}, | |||||
{ // raise | |||||
{ 0x00, 0x00, 0x00, 0x80, 0x80, 0xC0, 0xC0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0xC0, 0x80, 0x80, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x88, 0x88, 0x55, 0x55, 0x23, 0x23, 0x47, 0x47, 0x8F, 0x8F, 0x47, 0x47, 0x23, 0x23, 0x55, 0x55, 0x88, 0x88, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 } | |||||
}, | |||||
{ // lower | |||||
{ 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x88, 0x88, 0xD5, 0xD5, 0xE2, 0xE2, 0xC4, 0xC4, 0x88, 0x88, 0xC4, 0xC4, 0xE2, 0xE2, 0xD5, 0xD5, 0x88, 0x88, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x07, 0x07, 0x0F, 0x0F, 0x07, 0x07, 0x03, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 } | |||||
}, | |||||
{ // adjust | |||||
{ 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0xC0, 0x60, 0xA0, 0x50, 0xB0, 0x58, 0xA8, 0x50, 0xB0, 0x60, 0xA0, 0x40, 0xC0, 0x80, 0x80, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x88, 0x88, 0x5D, 0xD5, 0x6B, 0xB6, 0x6D, 0xD6, 0xAD, 0xDA, 0x6D, 0xD6, 0x6B, 0xB6, 0x5D, 0xD5, 0x88, 0x88, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x02, 0x05, 0x06, 0x0D, 0x0A, 0x05, 0x06, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 } | |||||
}, | |||||
{ // blank | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
}, | |||||
{ // better gamepad | |||||
{ 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xE0, 0x70, 0xF0, 0xF0, 0xF0, 0xF0, 0x90, 0x90, 0xF0, 0xF0, 0xF0, 0xF0, 0x70, 0xE0, 0xE0, 0xC0, 0x00, 0x00, 0x00 }, | |||||
{ 0x80, 0xF8, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xE6, 0xC3, 0xC3, 0xE6, 0xFF, 0xFF, 0xFE, 0xF7, 0xE3, 0xF6, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xF8, 0x80 }, | |||||
{ 0x07, 0x0F, 0x0F, 0x0F, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0F, 0x0F, 0x0F, 0x07 } | |||||
}, | |||||
{ // mouse | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x20, 0x20, 0x20, 0xA0, 0x20, 0x20, 0x20, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | |||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } | |||||
} | |||||
}; |
@ -0,0 +1,12 @@ | |||||
CUSTOM_OLED_DRIVER ?= yes | |||||
ifeq ($(strip $(OLED_ENABLE)), yes) | |||||
ifeq ($(strip $(CUSTOM_OLED_DRIVER)), yes) | |||||
OPT_DEFS += -DCUSTOM_OLED_DRIVER | |||||
SRC += $(USER_PATH)/oled/oled_stuff.c | |||||
endif | |||||
ifeq ($(strip $(OLED_DISPLAY_TEST)), yes) | |||||
OPT_DEFS += -DOLED_DISPLAY_TEST | |||||
endif | |||||
endif | |||||
DEFERRED_EXEC_ENABLE = yes |
@ -1,860 +0,0 @@ | |||||
/* | |||||
Copyright 2019 Ryan Caltabiano <https://github.com/XScorpion2> | |||||
This program is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "i2c_master.h" | |||||
#include "oled_driver.h" | |||||
#include OLED_FONT_H | |||||
#include "timer.h" | |||||
#include "print.h" | |||||
#include <string.h> | |||||
#include "progmem.h" | |||||
#include "keyboard.h" | |||||
// for SH1107: https://www.displayfuture.com/Display/datasheet/controller/SH1107.pdf | |||||
// Fundamental Commands | |||||
#define CONTRAST 0x81 | |||||
#define DISPLAY_ALL_ON 0xA5 | |||||
#define DISPLAY_ALL_ON_RESUME 0xA4 | |||||
#define NORMAL_DISPLAY 0xA6 | |||||
#define INVERT_DISPLAY 0xA7 | |||||
#define DISPLAY_ON 0xAF | |||||
#define DISPLAY_OFF 0xAE | |||||
#define NOP 0xE3 | |||||
// Scrolling Commands | |||||
#define ACTIVATE_SCROLL 0x2F | |||||
#define DEACTIVATE_SCROLL 0x2E | |||||
#define SCROLL_RIGHT 0x26 | |||||
#define SCROLL_LEFT 0x27 | |||||
#define SCROLL_RIGHT_UP 0x29 | |||||
#define SCROLL_LEFT_UP 0x2A | |||||
// Addressing Setting Commands | |||||
#define MEMORY_MODE 0x20 | |||||
#define COLUMN_ADDR 0x21 | |||||
#define PAGE_ADDR 0x22 | |||||
#define PAM_SETCOLUMN_LSB 0x00 | |||||
#define PAM_SETCOLUMN_MSB 0x10 | |||||
#define PAM_PAGE_ADDR 0xB0 // 0xb0 -- 0xb7 | |||||
// Hardware Configuration Commands | |||||
#define DISPLAY_START_LINE 0x40 | |||||
#define SEGMENT_REMAP 0xA0 | |||||
#define SEGMENT_REMAP_INV 0xA1 | |||||
#define MULTIPLEX_RATIO 0xA8 | |||||
#define COM_SCAN_INC 0xC0 | |||||
#define COM_SCAN_DEC 0xC8 | |||||
#define DISPLAY_OFFSET 0xD3 | |||||
#define COM_PINS 0xDA | |||||
#define COM_PINS_SEQ 0x02 | |||||
#define COM_PINS_ALT 0x12 | |||||
#define COM_PINS_SEQ_LR 0x22 | |||||
#define COM_PINS_ALT_LR 0x32 | |||||
// Timing & Driving Commands | |||||
#define DISPLAY_CLOCK 0xD5 | |||||
#define PRE_CHARGE_PERIOD 0xD9 | |||||
#define VCOM_DETECT 0xDB | |||||
// Advance Graphic Commands | |||||
#define FADE_BLINK 0x23 | |||||
#define ENABLE_FADE 0x20 | |||||
#define ENABLE_BLINK 0x30 | |||||
// Charge Pump Commands | |||||
#define CHARGE_PUMP 0x8D | |||||
// Commands specific to the SH1107 chip | |||||
#define SH1107_DISPLAY_START_LINE 0xDC | |||||
#define SH1107_MEMORY_MODE_PAGE 0x20 | |||||
#define SH1107_MEMORY_MODE_VERTICAL 0x21 | |||||
// Misc defines | |||||
#ifndef OLED_BLOCK_COUNT | |||||
# define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) | |||||
#endif | |||||
#ifndef OLED_BLOCK_SIZE | |||||
# define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) | |||||
#endif | |||||
#define OLED_ALL_BLOCKS_MASK (((((OLED_BLOCK_TYPE)1 << (OLED_BLOCK_COUNT - 1)) - 1) << 1) | 1) | |||||
#ifndef OLED_COM_PIN_COUNT | |||||
# define OLED_COM_PIN_COUNT 128 | |||||
#endif | |||||
#ifndef OLED_COM_PIN_OFFSET | |||||
# define OLED_COM_PIN_OFFSET 0 | |||||
#endif | |||||
// i2c defines | |||||
#define I2C_CMD 0x00 | |||||
#define I2C_DATA 0x40 | |||||
#if defined(__AVR__) | |||||
# define I2C_TRANSMIT_P(data) i2c_transmit_P((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), OLED_I2C_TIMEOUT) | |||||
#else // defined(__AVR__) | |||||
# define I2C_TRANSMIT_P(data) i2c_transmit((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), OLED_I2C_TIMEOUT) | |||||
#endif // defined(__AVR__) | |||||
#define I2C_TRANSMIT(data) i2c_transmit((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), OLED_I2C_TIMEOUT) | |||||
#define I2C_WRITE_REG(mode, data, size) i2c_writeReg((OLED_DISPLAY_ADDRESS << 1), mode, data, size, OLED_I2C_TIMEOUT) | |||||
#define HAS_FLAGS(bits, flags) ((bits & flags) == flags) | |||||
// Display buffer's is the same as the OLED memory layout | |||||
// this is so we don't end up with rounding errors with | |||||
// parts of the display unusable or don't get cleared correctly | |||||
// and also allows for drawing & inverting | |||||
uint8_t oled_buffer[OLED_MATRIX_SIZE]; | |||||
uint8_t *oled_cursor; | |||||
OLED_BLOCK_TYPE oled_dirty = 0; | |||||
bool oled_initialized = false; | |||||
bool oled_active = false; | |||||
bool oled_scrolling = false; | |||||
bool oled_inverted = false; | |||||
uint8_t oled_brightness = OLED_BRIGHTNESS; | |||||
oled_rotation_t oled_rotation = 0; | |||||
uint8_t oled_rotation_width = 0; | |||||
uint8_t oled_scroll_speed = 0; // this holds the speed after being remapped to ssd1306 internal values | |||||
uint8_t oled_scroll_start = 0; | |||||
uint8_t oled_scroll_end = 7; | |||||
#if OLED_TIMEOUT > 0 | |||||
uint32_t oled_timeout; | |||||
#endif | |||||
#if OLED_SCROLL_TIMEOUT > 0 | |||||
uint32_t oled_scroll_timeout; | |||||
#endif | |||||
#if OLED_UPDATE_INTERVAL > 0 | |||||
uint16_t oled_update_timeout; | |||||
#endif | |||||
// Internal variables to reduce math instructions | |||||
#if defined(__AVR__) | |||||
// identical to i2c_transmit, but for PROGMEM since all initialization is in PROGMEM arrays currently | |||||
// probably should move this into i2c_master... | |||||
static i2c_status_t i2c_transmit_P(uint8_t address, const uint8_t *data, uint16_t length, uint16_t timeout) { | |||||
i2c_status_t status = i2c_start(address | I2C_WRITE, timeout); | |||||
for (uint16_t i = 0; i < length && status >= 0; i++) { | |||||
status = i2c_write(pgm_read_byte((const char *)data++), timeout); | |||||
if (status) break; | |||||
} | |||||
i2c_stop(); | |||||
return status; | |||||
} | |||||
#endif | |||||
// Flips the rendering bits for a character at the current cursor position | |||||
static void InvertCharacter(uint8_t *cursor) { | |||||
const uint8_t *end = cursor + OLED_FONT_WIDTH; | |||||
while (cursor < end) { | |||||
*cursor = ~(*cursor); | |||||
cursor++; | |||||
} | |||||
} | |||||
bool oled_init(oled_rotation_t rotation) { | |||||
#if defined(USE_I2C) && defined(SPLIT_KEYBOARD) | |||||
if (!is_keyboard_master()) { | |||||
return true; | |||||
} | |||||
#endif | |||||
oled_rotation = oled_init_user(oled_init_kb(rotation)); | |||||
if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) { | |||||
oled_rotation_width = OLED_DISPLAY_WIDTH; | |||||
} else { | |||||
oled_rotation_width = OLED_DISPLAY_HEIGHT; | |||||
} | |||||
i2c_init(); | |||||
static const uint8_t PROGMEM display_setup1[] = { | |||||
I2C_CMD, | |||||
DISPLAY_OFF, | |||||
DISPLAY_CLOCK, | |||||
0x80, | |||||
MULTIPLEX_RATIO, | |||||
OLED_DISPLAY_WIDTH - 1, | |||||
SH1107_DISPLAY_START_LINE, | |||||
0x00, | |||||
CHARGE_PUMP, | |||||
0x14, | |||||
SH1107_MEMORY_MODE_PAGE, | |||||
}; | |||||
if (I2C_TRANSMIT_P(display_setup1) != I2C_STATUS_SUCCESS) { | |||||
print("oled_init cmd set 1 failed\n"); | |||||
return false; | |||||
} | |||||
if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_180)) { | |||||
static const uint8_t PROGMEM display_normal[] = { | |||||
I2C_CMD, | |||||
SEGMENT_REMAP_INV, | |||||
COM_SCAN_DEC, | |||||
DISPLAY_OFFSET, | |||||
OLED_COM_PIN_OFFSET, | |||||
}; | |||||
if (I2C_TRANSMIT_P(display_normal) != I2C_STATUS_SUCCESS) { | |||||
print("oled_init cmd normal rotation failed\n"); | |||||
return false; | |||||
} | |||||
} else { | |||||
static const uint8_t PROGMEM display_flipped[] = { | |||||
I2C_CMD, | |||||
SEGMENT_REMAP, | |||||
COM_SCAN_INC, | |||||
DISPLAY_OFFSET, | |||||
(OLED_COM_PIN_COUNT - OLED_COM_PIN_OFFSET) % OLED_COM_PIN_COUNT, | |||||
}; | |||||
if (I2C_TRANSMIT_P(display_flipped) != I2C_STATUS_SUCCESS) { | |||||
print("display_flipped failed\n"); | |||||
return false; | |||||
} | |||||
} | |||||
static const uint8_t PROGMEM display_setup2[] = { | |||||
I2C_CMD, COM_PINS, | |||||
OLED_COM_PINS, | |||||
CONTRAST, OLED_BRIGHTNESS, | |||||
PRE_CHARGE_PERIOD, 0x22, | |||||
VCOM_DETECT, 0x35, | |||||
DISPLAY_ALL_ON_RESUME, | |||||
NORMAL_DISPLAY, | |||||
DEACTIVATE_SCROLL, | |||||
DISPLAY_ON | |||||
}; | |||||
if (I2C_TRANSMIT_P(display_setup2) != I2C_STATUS_SUCCESS) { | |||||
print("display_setup2 failed\n"); | |||||
return false; | |||||
} | |||||
#if OLED_TIMEOUT > 0 | |||||
oled_timeout = timer_read32() + OLED_TIMEOUT; | |||||
#endif | |||||
#if OLED_SCROLL_TIMEOUT > 0 | |||||
oled_scroll_timeout = timer_read32() + OLED_SCROLL_TIMEOUT; | |||||
#endif | |||||
oled_clear(); | |||||
oled_initialized = true; | |||||
oled_active = true; | |||||
oled_scrolling = false; | |||||
return true; | |||||
} | |||||
__attribute__((weak)) oled_rotation_t oled_init_kb(oled_rotation_t rotation) { | |||||
return rotation; | |||||
} | |||||
__attribute__((weak)) oled_rotation_t oled_init_user(oled_rotation_t rotation) { | |||||
return rotation; | |||||
} | |||||
void oled_clear(void) { | |||||
memset(oled_buffer, 0, sizeof(oled_buffer)); | |||||
oled_cursor = &oled_buffer[0]; | |||||
oled_dirty = OLED_ALL_BLOCKS_MASK; | |||||
} | |||||
static void calc_bounds(uint8_t update_start, uint8_t *cmd_array) { | |||||
// Calculate commands to set memory addressing bounds. | |||||
uint8_t start_page = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_WIDTH; | |||||
uint8_t start_column = OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_WIDTH; | |||||
// Commands for Page Addressing Mode. Sets starting page and column; has no end bound. | |||||
// Column value must be split into high and low nybble and sent as two commands. | |||||
cmd_array[0] = PAM_PAGE_ADDR | start_page; | |||||
cmd_array[1] = PAM_SETCOLUMN_LSB | ((OLED_COLUMN_OFFSET + start_column) & 0x0f); | |||||
cmd_array[2] = PAM_SETCOLUMN_MSB | ((OLED_COLUMN_OFFSET + start_column) >> 4 & 0x0f); | |||||
} | |||||
static void calc_bounds_90(uint8_t update_start, uint8_t *cmd_array) { | |||||
// Block numbering starts from the bottom left corner, going up and then to | |||||
// the right. The controller needs the page and column numbers for the top | |||||
// left and bottom right corners of that block. | |||||
// Total number of pages across the screen height. | |||||
const uint8_t height_in_pages = OLED_DISPLAY_HEIGHT / 8; | |||||
// Difference of starting page numbers for adjacent blocks; may be 0 if | |||||
// blocks are large enough to occupy one or more whole 8px columns. | |||||
const uint8_t page_inc_per_block = OLED_BLOCK_SIZE % OLED_DISPLAY_HEIGHT / 8; | |||||
// Top page number for a block which is at the bottom edge of the screen. | |||||
const uint8_t bottom_block_top_page = (height_in_pages - page_inc_per_block) % height_in_pages; | |||||
// Only the Page Addressing Mode is supported | |||||
uint8_t start_page = bottom_block_top_page - (OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_HEIGHT / 8); | |||||
uint8_t start_column = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_HEIGHT * 8; | |||||
cmd_array[0] = PAM_PAGE_ADDR | start_page; | |||||
cmd_array[1] = PAM_SETCOLUMN_LSB | ((OLED_COLUMN_OFFSET + start_column) & 0x0f); | |||||
cmd_array[2] = PAM_SETCOLUMN_MSB | ((OLED_COLUMN_OFFSET + start_column) >> 4 & 0x0f); | |||||
} | |||||
uint8_t crot(uint8_t a, int8_t n) { | |||||
const uint8_t mask = 0x7; | |||||
n &= mask; | |||||
return a << n | a >> (-n & mask); | |||||
} | |||||
static void rotate_90(const uint8_t *src, uint8_t *dest) { | |||||
for (uint8_t i = 0, shift = 7; i < 8; ++i, --shift) { | |||||
uint8_t selector = (1 << i); | |||||
for (uint8_t j = 0; j < 8; ++j) { | |||||
dest[i] |= crot(src[j] & selector, shift - (int8_t)j); | |||||
} | |||||
} | |||||
} | |||||
void oled_render(void) { | |||||
// Do we have work to do? | |||||
oled_dirty &= OLED_ALL_BLOCKS_MASK; | |||||
if (!oled_dirty || !oled_initialized || oled_scrolling) { | |||||
return; | |||||
} | |||||
// Turn on display if it is off | |||||
oled_on(); | |||||
uint8_t update_start = 0; | |||||
uint8_t num_processed = 0; | |||||
while (oled_dirty && num_processed++ < OLED_UPDATE_PROCESS_LIMIT) { // render all dirty blocks (up to the configured limit) | |||||
// Find next dirty block | |||||
while (!(oled_dirty & ((OLED_BLOCK_TYPE)1 << update_start))) { | |||||
++update_start; | |||||
} | |||||
// Set column & page position | |||||
static uint8_t display_start[] = {I2C_CMD, PAM_PAGE_ADDR, PAM_SETCOLUMN_LSB, PAM_SETCOLUMN_MSB}; | |||||
if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) { | |||||
calc_bounds(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start | |||||
} else { | |||||
calc_bounds_90(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start | |||||
} | |||||
// Send column & page position | |||||
if (I2C_TRANSMIT(display_start) != I2C_STATUS_SUCCESS) { | |||||
print("oled_render offset command failed\n"); | |||||
return; | |||||
} | |||||
if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) { | |||||
// Send render data chunk as is | |||||
if (I2C_WRITE_REG(I2C_DATA, &oled_buffer[OLED_BLOCK_SIZE * update_start], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) { | |||||
print("oled_render data failed\n"); | |||||
return; | |||||
} | |||||
} else { | |||||
// Rotate the render chunks | |||||
const static uint8_t source_map[] = OLED_SOURCE_MAP; | |||||
const static uint8_t target_map[] = OLED_TARGET_MAP; | |||||
static uint8_t temp_buffer[OLED_BLOCK_SIZE]; | |||||
memset(temp_buffer, 0, sizeof(temp_buffer)); | |||||
for (uint8_t i = 0; i < sizeof(source_map); ++i) { | |||||
rotate_90(&oled_buffer[OLED_BLOCK_SIZE * update_start + source_map[i]], &temp_buffer[target_map[i]]); | |||||
} | |||||
// For SH1106 or SH1107 the data chunk must be split into separate pieces for each page | |||||
const uint8_t columns_in_block = (OLED_BLOCK_SIZE + OLED_DISPLAY_HEIGHT - 1) / OLED_DISPLAY_HEIGHT * 8; | |||||
const uint8_t num_pages = OLED_BLOCK_SIZE / columns_in_block; | |||||
for (uint8_t i = 0; i < num_pages; ++i) { | |||||
// Send column & page position for all pages except the first one | |||||
if (i > 0) { | |||||
display_start[1]++; | |||||
if (I2C_TRANSMIT(display_start) != I2C_STATUS_SUCCESS) { | |||||
print("oled_render offset command failed\n"); | |||||
return; | |||||
} | |||||
} | |||||
// Send data for the page | |||||
if (I2C_WRITE_REG(I2C_DATA, &temp_buffer[columns_in_block * i], columns_in_block) != I2C_STATUS_SUCCESS) { | |||||
print("oled_render90 data failed\n"); | |||||
return; | |||||
} | |||||
} | |||||
} | |||||
// Clear dirty flag | |||||
oled_dirty &= ~((OLED_BLOCK_TYPE)1 << update_start); | |||||
} | |||||
} | |||||
void oled_set_cursor(uint8_t col, uint8_t line) { | |||||
uint16_t index = line * oled_rotation_width + col * OLED_FONT_WIDTH; | |||||
// Out of bounds? | |||||
if (index >= OLED_MATRIX_SIZE) { | |||||
index = 0; | |||||
} | |||||
oled_cursor = &oled_buffer[index]; | |||||
} | |||||
void oled_advance_page(bool clearPageRemainder) { | |||||
uint16_t index = oled_cursor - &oled_buffer[0]; | |||||
uint8_t remaining = oled_rotation_width - (index % oled_rotation_width); | |||||
if (clearPageRemainder) { | |||||
// Remaining Char count | |||||
remaining = remaining / OLED_FONT_WIDTH; | |||||
// Write empty character until next line | |||||
while (remaining--) | |||||
oled_write_char(' ', false); | |||||
} else { | |||||
// Next page index out of bounds? | |||||
if (index + remaining >= OLED_MATRIX_SIZE) { | |||||
index = 0; | |||||
remaining = 0; | |||||
} | |||||
oled_cursor = &oled_buffer[index + remaining]; | |||||
} | |||||
} | |||||
void oled_advance_char(void) { | |||||
uint16_t nextIndex = oled_cursor - &oled_buffer[0] + OLED_FONT_WIDTH; | |||||
uint8_t remainingSpace = oled_rotation_width - (nextIndex % oled_rotation_width); | |||||
// Do we have enough space on the current line for the next character | |||||
if (remainingSpace < OLED_FONT_WIDTH) { | |||||
nextIndex += remainingSpace; | |||||
} | |||||
// Did we go out of bounds | |||||
if (nextIndex >= OLED_MATRIX_SIZE) { | |||||
nextIndex = 0; | |||||
} | |||||
// Update cursor position | |||||
oled_cursor = &oled_buffer[nextIndex]; | |||||
} | |||||
// Main handler that writes character data to the display buffer | |||||
void oled_write_char(const char data, bool invert) { | |||||
// Advance to the next line if newline | |||||
if (data == '\n') { | |||||
// Old source wrote ' ' until end of line... | |||||
oled_advance_page(true); | |||||
return; | |||||
} | |||||
if (data == '\r') { | |||||
oled_advance_page(false); | |||||
return; | |||||
} | |||||
// copy the current render buffer to check for dirty after | |||||
static uint8_t oled_temp_buffer[OLED_FONT_WIDTH]; | |||||
memcpy(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH); | |||||
_Static_assert(sizeof(font) >= ((OLED_FONT_END + 1 - OLED_FONT_START) * OLED_FONT_WIDTH), "OLED_FONT_END references outside array"); | |||||
// set the reder buffer data | |||||
uint8_t cast_data = (uint8_t)data; // font based on unsigned type for index | |||||
if (cast_data < OLED_FONT_START || cast_data > OLED_FONT_END) { | |||||
memset(oled_cursor, 0x00, OLED_FONT_WIDTH); | |||||
} else { | |||||
const uint8_t *glyph = &font[(cast_data - OLED_FONT_START) * OLED_FONT_WIDTH]; | |||||
memcpy_P(oled_cursor, glyph, OLED_FONT_WIDTH); | |||||
} | |||||
// Invert if needed | |||||
if (invert) { | |||||
InvertCharacter(oled_cursor); | |||||
} | |||||
// Dirty check | |||||
if (memcmp(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH)) { | |||||
uint16_t index = oled_cursor - &oled_buffer[0]; | |||||
oled_dirty |= ((OLED_BLOCK_TYPE)1 << (index / OLED_BLOCK_SIZE)); | |||||
// Edgecase check if the written data spans the 2 chunks | |||||
oled_dirty |= ((OLED_BLOCK_TYPE)1 << ((index + OLED_FONT_WIDTH - 1) / OLED_BLOCK_SIZE)); | |||||
} | |||||
// Finally move to the next char | |||||
oled_advance_char(); | |||||
} | |||||
void oled_write(const char *data, bool invert) { | |||||
const char *end = data + strlen(data); | |||||
while (data < end) { | |||||
oled_write_char(*data, invert); | |||||
data++; | |||||
} | |||||
} | |||||
void oled_write_ln(const char *data, bool invert) { | |||||
oled_write(data, invert); | |||||
oled_advance_page(true); | |||||
} | |||||
void oled_pan(bool left) { | |||||
uint16_t i = 0; | |||||
for (uint16_t y = 0; y < OLED_DISPLAY_HEIGHT / 8; y++) { | |||||
if (left) { | |||||
for (uint16_t x = 0; x < OLED_DISPLAY_WIDTH - 1; x++) { | |||||
i = y * OLED_DISPLAY_WIDTH + x; | |||||
oled_buffer[i] = oled_buffer[i + 1]; | |||||
} | |||||
} else { | |||||
for (uint16_t x = OLED_DISPLAY_WIDTH - 1; x > 0; x--) { | |||||
i = y * OLED_DISPLAY_WIDTH + x; | |||||
oled_buffer[i] = oled_buffer[i - 1]; | |||||
} | |||||
} | |||||
} | |||||
oled_dirty = OLED_ALL_BLOCKS_MASK; | |||||
} | |||||
void oled_pan_section(bool left, uint16_t y_start, uint16_t y_end, uint16_t x_start, uint16_t x_end) { | |||||
uint16_t i = 0; | |||||
for (uint16_t y = y_start; y < y_end; y++) { | |||||
if (left) { | |||||
for (uint16_t x = x_start; x < x_end - 1; x++) { | |||||
i = y * OLED_DISPLAY_WIDTH + x; | |||||
oled_buffer[i] = oled_buffer[i + 1]; | |||||
oled_dirty |= ((OLED_BLOCK_TYPE)1 << (i / OLED_BLOCK_SIZE)); | |||||
} | |||||
} else { | |||||
for (uint16_t x = x_end - 1; x > 0; x--) { | |||||
i = y * OLED_DISPLAY_WIDTH + x; | |||||
oled_buffer[i] = oled_buffer[i - 1]; | |||||
oled_dirty |= ((OLED_BLOCK_TYPE)1 << (i / OLED_BLOCK_SIZE)); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
oled_buffer_reader_t oled_read_raw(uint16_t start_index) { | |||||
if (start_index > OLED_MATRIX_SIZE) start_index = OLED_MATRIX_SIZE; | |||||
oled_buffer_reader_t ret_reader; | |||||
ret_reader.current_element = &oled_buffer[start_index]; | |||||
ret_reader.remaining_element_count = OLED_MATRIX_SIZE - start_index; | |||||
return ret_reader; | |||||
} | |||||
void oled_write_raw_byte(const char data, uint16_t index) { | |||||
if (index > OLED_MATRIX_SIZE) index = OLED_MATRIX_SIZE; | |||||
if (oled_buffer[index] == data) return; | |||||
oled_buffer[index] = data; | |||||
oled_dirty |= ((OLED_BLOCK_TYPE)1 << (index / OLED_BLOCK_SIZE)); | |||||
} | |||||
void oled_write_raw(const char *data, uint16_t size) { | |||||
uint16_t cursor_start_index = oled_cursor - &oled_buffer[0]; | |||||
if ((size + cursor_start_index) > OLED_MATRIX_SIZE) size = OLED_MATRIX_SIZE - cursor_start_index; | |||||
for (uint16_t i = cursor_start_index; i < cursor_start_index + size; i++) { | |||||
uint8_t c = *data++; | |||||
if (oled_buffer[i] == c) continue; | |||||
oled_buffer[i] = c; | |||||
oled_dirty |= ((OLED_BLOCK_TYPE)1 << (i / OLED_BLOCK_SIZE)); | |||||
} | |||||
} | |||||
void oled_write_pixel(uint8_t x, uint8_t y, bool on) { | |||||
if (x >= oled_rotation_width) { | |||||
return; | |||||
} | |||||
uint16_t index = x + (y / 8) * oled_rotation_width; | |||||
if (index >= OLED_MATRIX_SIZE) { | |||||
return; | |||||
} | |||||
uint8_t data = oled_buffer[index]; | |||||
if (on) { | |||||
data |= (1 << (y % 8)); | |||||
} else { | |||||
data &= ~(1 << (y % 8)); | |||||
} | |||||
if (oled_buffer[index] != data) { | |||||
oled_buffer[index] = data; | |||||
oled_dirty |= ((OLED_BLOCK_TYPE)1 << (index / OLED_BLOCK_SIZE)); | |||||
} | |||||
} | |||||
#if defined(__AVR__) | |||||
void oled_write_P(const char *data, bool invert) { | |||||
uint8_t c = pgm_read_byte(data); | |||||
while (c != 0) { | |||||
oled_write_char(c, invert); | |||||
c = pgm_read_byte(++data); | |||||
} | |||||
} | |||||
void oled_write_ln_P(const char *data, bool invert) { | |||||
oled_write_P(data, invert); | |||||
oled_advance_page(true); | |||||
} | |||||
void oled_write_raw_P(const char *data, uint16_t size) { | |||||
uint16_t cursor_start_index = oled_cursor - &oled_buffer[0]; | |||||
if ((size + cursor_start_index) > OLED_MATRIX_SIZE) size = OLED_MATRIX_SIZE - cursor_start_index; | |||||
for (uint16_t i = cursor_start_index; i < cursor_start_index + size; i++) { | |||||
uint8_t c = pgm_read_byte(data++); | |||||
if (oled_buffer[i] == c) continue; | |||||
oled_buffer[i] = c; | |||||
oled_dirty |= ((OLED_BLOCK_TYPE)1 << (i / OLED_BLOCK_SIZE)); | |||||
} | |||||
} | |||||
#endif // defined(__AVR__) | |||||
bool oled_on(void) { | |||||
if (!oled_initialized) { | |||||
return oled_active; | |||||
} | |||||
#if OLED_TIMEOUT > 0 | |||||
oled_timeout = timer_read32() + OLED_TIMEOUT; | |||||
#endif | |||||
static const uint8_t PROGMEM display_on[] = | |||||
#ifdef OLED_FADE_OUT | |||||
{I2C_CMD, FADE_BLINK, 0x00}; | |||||
#else | |||||
{I2C_CMD, DISPLAY_ON}; | |||||
#endif | |||||
if (!oled_active) { | |||||
if (I2C_TRANSMIT_P(display_on) != I2C_STATUS_SUCCESS) { | |||||
print("oled_on cmd failed\n"); | |||||
return oled_active; | |||||
} | |||||
oled_active = true; | |||||
} | |||||
return oled_active; | |||||
} | |||||
bool oled_off(void) { | |||||
if (!oled_initialized) { | |||||
return !oled_active; | |||||
} | |||||
static const uint8_t PROGMEM display_off[] = | |||||
#ifdef OLED_FADE_OUT | |||||
{I2C_CMD, FADE_BLINK, ENABLE_FADE | OLED_FADE_OUT_INTERVAL}; | |||||
#else | |||||
{I2C_CMD, DISPLAY_OFF}; | |||||
#endif | |||||
if (oled_active) { | |||||
if (I2C_TRANSMIT_P(display_off) != I2C_STATUS_SUCCESS) { | |||||
print("oled_off cmd failed\n"); | |||||
return oled_active; | |||||
} | |||||
oled_active = false; | |||||
} | |||||
return !oled_active; | |||||
} | |||||
bool is_oled_on(void) { | |||||
return oled_active; | |||||
} | |||||
uint8_t oled_set_brightness(uint8_t level) { | |||||
if (!oled_initialized) { | |||||
return oled_brightness; | |||||
} | |||||
uint8_t set_contrast[] = {I2C_CMD, CONTRAST, level}; | |||||
if (oled_brightness != level) { | |||||
if (I2C_TRANSMIT(set_contrast) != I2C_STATUS_SUCCESS) { | |||||
print("set_brightness cmd failed\n"); | |||||
return oled_brightness; | |||||
} | |||||
oled_brightness = level; | |||||
} | |||||
return oled_brightness; | |||||
} | |||||
uint8_t oled_get_brightness(void) { | |||||
return oled_brightness; | |||||
} | |||||
// Set the specific 8 lines rows of the screen to scroll. | |||||
// 0 is the default for start, and 7 for end, which is the entire | |||||
// height of the screen. For 128x32 screens, rows 4-7 are not used. | |||||
void oled_scroll_set_area(uint8_t start_line, uint8_t end_line) { | |||||
oled_scroll_start = start_line; | |||||
oled_scroll_end = end_line; | |||||
} | |||||
void oled_scroll_set_speed(uint8_t speed) { | |||||
// Sets the speed for scrolling... does not take effect | |||||
// until scrolling is either started or restarted | |||||
// the ssd1306 supports 8 speeds | |||||
// FrameRate2 speed = 7 | |||||
// FrameRate3 speed = 4 | |||||
// FrameRate4 speed = 5 | |||||
// FrameRate5 speed = 0 | |||||
// FrameRate25 speed = 6 | |||||
// FrameRate64 speed = 1 | |||||
// FrameRate128 speed = 2 | |||||
// FrameRate256 speed = 3 | |||||
// for ease of use these are remaped here to be in order | |||||
static const uint8_t scroll_remap[8] = {7, 4, 5, 0, 6, 1, 2, 3}; | |||||
oled_scroll_speed = scroll_remap[speed]; | |||||
} | |||||
bool oled_scroll_right(void) { | |||||
if (!oled_initialized) { | |||||
return oled_scrolling; | |||||
} | |||||
// Dont enable scrolling if we need to update the display | |||||
// This prevents scrolling of bad data from starting the scroll too early after init | |||||
if (!oled_dirty && !oled_scrolling) { | |||||
uint8_t display_scroll_right[] = {I2C_CMD, SCROLL_RIGHT, 0x00, oled_scroll_start, oled_scroll_speed, oled_scroll_end, 0x00, 0xFF, ACTIVATE_SCROLL}; | |||||
if (I2C_TRANSMIT(display_scroll_right) != I2C_STATUS_SUCCESS) { | |||||
print("oled_scroll_right cmd failed\n"); | |||||
return oled_scrolling; | |||||
} | |||||
oled_scrolling = true; | |||||
} | |||||
return oled_scrolling; | |||||
} | |||||
bool oled_scroll_left(void) { | |||||
if (!oled_initialized) { | |||||
return oled_scrolling; | |||||
} | |||||
// Dont enable scrolling if we need to update the display | |||||
// This prevents scrolling of bad data from starting the scroll too early after init | |||||
if (!oled_dirty && !oled_scrolling) { | |||||
uint8_t display_scroll_left[] = {I2C_CMD, SCROLL_LEFT, 0x00, oled_scroll_start, oled_scroll_speed, oled_scroll_end, 0x00, 0xFF, ACTIVATE_SCROLL}; | |||||
if (I2C_TRANSMIT(display_scroll_left) != I2C_STATUS_SUCCESS) { | |||||
print("oled_scroll_left cmd failed\n"); | |||||
return oled_scrolling; | |||||
} | |||||
oled_scrolling = true; | |||||
} | |||||
return oled_scrolling; | |||||
} | |||||
bool oled_scroll_off(void) { | |||||
if (!oled_initialized) { | |||||
return !oled_scrolling; | |||||
} | |||||
if (oled_scrolling) { | |||||
static const uint8_t PROGMEM display_scroll_off[] = {I2C_CMD, DEACTIVATE_SCROLL}; | |||||
if (I2C_TRANSMIT_P(display_scroll_off) != I2C_STATUS_SUCCESS) { | |||||
print("oled_scroll_off cmd failed\n"); | |||||
return oled_scrolling; | |||||
} | |||||
oled_scrolling = false; | |||||
oled_dirty = OLED_ALL_BLOCKS_MASK; | |||||
} | |||||
return !oled_scrolling; | |||||
} | |||||
bool is_oled_scrolling(void) { | |||||
return oled_scrolling; | |||||
} | |||||
bool oled_invert(bool invert) { | |||||
if (!oled_initialized) { | |||||
return oled_inverted; | |||||
} | |||||
if (invert && !oled_inverted) { | |||||
static const uint8_t PROGMEM display_inverted[] = {I2C_CMD, INVERT_DISPLAY}; | |||||
if (I2C_TRANSMIT_P(display_inverted) != I2C_STATUS_SUCCESS) { | |||||
print("oled_invert cmd failed\n"); | |||||
return oled_inverted; | |||||
} | |||||
oled_inverted = true; | |||||
} else if (!invert && oled_inverted) { | |||||
static const uint8_t PROGMEM display_normal[] = {I2C_CMD, NORMAL_DISPLAY}; | |||||
if (I2C_TRANSMIT_P(display_normal) != I2C_STATUS_SUCCESS) { | |||||
print("oled_invert cmd failed\n"); | |||||
return oled_inverted; | |||||
} | |||||
oled_inverted = false; | |||||
} | |||||
return oled_inverted; | |||||
} | |||||
uint8_t oled_max_chars(void) { | |||||
if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) { | |||||
return OLED_DISPLAY_WIDTH / OLED_FONT_WIDTH; | |||||
} | |||||
return OLED_DISPLAY_HEIGHT / OLED_FONT_WIDTH; | |||||
} | |||||
uint8_t oled_max_lines(void) { | |||||
if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) { | |||||
return OLED_DISPLAY_HEIGHT / OLED_FONT_HEIGHT; | |||||
} | |||||
return OLED_DISPLAY_WIDTH / OLED_FONT_HEIGHT; | |||||
} | |||||
void oled_task(void) { | |||||
if (!oled_initialized) { | |||||
return; | |||||
} | |||||
#if OLED_UPDATE_INTERVAL > 0 | |||||
if (timer_elapsed(oled_update_timeout) >= OLED_UPDATE_INTERVAL) { | |||||
oled_update_timeout = timer_read(); | |||||
oled_set_cursor(0, 0); | |||||
oled_task_kb(); | |||||
} | |||||
#else | |||||
oled_set_cursor(0, 0); | |||||
oled_task_kbr(); | |||||
#endif | |||||
#if OLED_SCROLL_TIMEOUT > 0 | |||||
if (oled_dirty && oled_scrolling) { | |||||
oled_scroll_timeout = timer_read32() + OLED_SCROLL_TIMEOUT; | |||||
oled_scroll_off(); | |||||
} | |||||
#endif | |||||
// Smart render system, no need to check for dirty | |||||
oled_render(); | |||||
// Display timeout check | |||||
#if OLED_TIMEOUT > 0 | |||||
if (oled_active && timer_expired32(timer_read32(), oled_timeout)) { | |||||
oled_off(); | |||||
} | |||||
#endif | |||||
#if OLED_SCROLL_TIMEOUT > 0 | |||||
if (!oled_scrolling && timer_expired32(timer_read32(), oled_scroll_timeout)) { | |||||
# ifdef OLED_SCROLL_TIMEOUT_RIGHT | |||||
oled_scroll_right(); | |||||
# else | |||||
oled_scroll_left(); | |||||
# endif | |||||
} | |||||
#endif | |||||
} | |||||
__attribute__((weak)) bool oled_task_kb(void) { | |||||
return oled_task_user(); | |||||
} | |||||
__attribute__((weak)) bool oled_task_user(void) { | |||||
return true; | |||||
} |