qmk-keychron-q3-colemak-dh/keyboards/moonlander/moonlander.c
Drashna Jaelre f0b30e0027
Make Swap Hands use PROGMEM (#12284)
This converts the array that the Swap Hands feature uses to use PROGMEM,
and to read from that array, as such. Since this array never changes at
runtime, there is no reason to keep it in memory. Especially for AVR
boards, as memory is a precious resource.
2021-05-09 23:21:09 -07:00

492 lines
14 KiB
C

/* Copyright 2020 ZSA Technology Labs, Inc <@zsa>
* Copyright 2020 Jack Humbert <jack.humb@gmail.com>
* Copyright 2020 Christopher Courtney <drashna@live.com> (@drashna)
*
* 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 "moonlander.h"
#ifdef WEBUSB_ENABLE
# include "webusb.h"
#endif
keyboard_config_t keyboard_config;
bool mcp23018_leds[3] = {0, 0, 0};
bool is_launching = false;
#ifdef DYNAMIC_MACRO_ENABLE
static bool is_dynamic_recording = false;
void dynamic_macro_record_start_user(void) { is_dynamic_recording = true; }
void dynamic_macro_record_end_user(int8_t direction) {
is_dynamic_recording = false;
ML_LED_3(false);
}
#endif
void moonlander_led_task(void) {
if (is_launching) {
ML_LED_1(false);
ML_LED_2(false);
ML_LED_3(false);
ML_LED_4(false);
ML_LED_5(false);
ML_LED_6(false);
ML_LED_1(true);
wait_ms(250);
ML_LED_2(true);
wait_ms(250);
ML_LED_3(true);
wait_ms(250);
ML_LED_4(true);
wait_ms(250);
ML_LED_5(true);
wait_ms(250);
ML_LED_6(true);
wait_ms(250);
ML_LED_1(false);
wait_ms(250);
ML_LED_2(false);
wait_ms(250);
ML_LED_3(false);
wait_ms(250);
ML_LED_4(false);
wait_ms(250);
ML_LED_5(false);
wait_ms(250);
ML_LED_6(false);
wait_ms(250);
is_launching = false;
layer_state_set_kb(layer_state);
}
#ifdef DYNAMIC_MACRO_ENABLE
else if (is_dynamic_recording) {
ML_LED_3(true);
wait_ms(100);
ML_LED_3(false);
wait_ms(155);
}
#endif
#ifdef WEBUSB_ENABLE
else if (webusb_state.pairing == true) {
static uint8_t led_mask;
ML_LED_1(false);
ML_LED_2(false);
ML_LED_3(false);
ML_LED_4(false);
ML_LED_5(false);
ML_LED_6(false);
if (!led_mask) {
led_mask = 1;
} else {
led_mask++;
if (led_mask > 12) led_mask = 1;
}
switch (led_mask) {
case 1:
case 12:
ML_LED_1(true);
break;
case 2:
case 11:
ML_LED_2(true);
break;
case 3:
case 10:
ML_LED_3(true);
break;
case 4:
case 9:
ML_LED_4(true);
break;
case 5:
case 8:
ML_LED_5(true);
break;
case 6:
case 7:
ML_LED_6(true);
break;
}
wait_ms(150);
}
#endif
}
static THD_WORKING_AREA(waLEDThread, 128);
static THD_FUNCTION(LEDThread, arg) {
(void)arg;
chRegSetThreadName("LEDThread");
while (true) {
moonlander_led_task();
}
}
void keyboard_pre_init_kb(void) {
setPinOutput(B5);
setPinOutput(B4);
setPinOutput(B3);
writePinLow(B5);
writePinLow(B4);
writePinLow(B3);
chThdCreateStatic(waLEDThread, sizeof(waLEDThread), NORMALPRIO - 16, LEDThread, NULL);
/* the array is initialized to 0, no need to re-set it here */
// mcp23018_leds[0] = 0; // blue
// mcp23018_leds[1] = 0; // green
// mcp23018_leds[2] = 0; // red
keyboard_pre_init_user();
}
#if !defined(MOONLANDER_USER_LEDS)
layer_state_t layer_state_set_kb(layer_state_t state) {
state = layer_state_set_user(state);
if (is_launching || !keyboard_config.led_level) return state;
ML_LED_1(false);
ML_LED_2(false);
ML_LED_3(false);
ML_LED_4(false);
ML_LED_5(false);
ML_LED_6(false);
uint8_t layer = get_highest_layer(state);
switch (layer) {
case 1:
ML_LED_1(1);
ML_LED_4(1);
break;
case 2:
ML_LED_2(1);
ML_LED_5(1);
break;
case 3:
ML_LED_3(1);
break;
case 4:
ML_LED_4(1);
break;
case 5:
ML_LED_5(1);
break;
case 6:
ML_LED_6(1);
break;
default:
break;
}
return state;
}
#endif
#ifdef RGB_MATRIX_ENABLE
// clang-format off
const is31_led g_is31_leds[DRIVER_LED_TOTAL] = {
/* Refer to IS31 manual for these locations
* driver
* | R location
* | | G location
* | | | B location
* | | | | */
{0, C3_2, C1_1, C4_2}, // 1
{0, C2_2, C1_2, C4_3},
{0, C2_3, C1_3, C3_3},
{0, C2_4, C1_4, C3_4},
{0, C2_5, C1_5, C3_5},
{0, C2_6, C1_6, C3_6},
{0, C2_7, C1_7, C3_7},
{0, C2_8, C1_8, C3_8},
{0, C3_1, C2_1, C4_1},
{0, C7_8, C6_8, C8_8}, // 10
{0, C7_7, C6_7, C9_8},
{0, C8_7, C6_6, C9_7},
{0, C8_6, C7_6, C9_6},
{0, C8_5, C7_5, C9_5},
{0, C8_4, C7_4, C9_4},
{0, C8_3, C7_3, C9_3},
{0, C8_2, C7_2, C9_2},
{0, C8_1, C7_1, C9_1},
{0, C3_10, C1_9, C4_10}, // 19
{0, C2_10, C1_10, C4_11},
{0, C2_11, C1_11, C3_11},
{0, C2_12, C1_12, C3_12},
{0, C2_13, C1_13, C3_13},
{0, C2_14, C1_14, C3_14},
{0, C2_15, C1_15, C3_15},
{0, C2_16, C1_16, C3_16},
{0, C3_9, C2_9, C4_9},
{0, C7_16, C6_16, C8_16}, // 28
{0, C7_15, C6_15, C9_16},
{0, C8_15, C6_14, C9_15},
{0, C8_10, C7_10, C9_10},
{0, C8_9, C7_9, C9_9},
{0, C8_11, C7_11, C9_11},
{0, C8_12, C7_12, C9_12},
{0, C8_13, C7_13, C9_13},
{0, C8_14, C7_14, C9_14},
{1, C3_2, C1_1, C4_2}, // 1
{1, C2_2, C1_2, C4_3},
{1, C2_3, C1_3, C3_3},
{1, C2_4, C1_4, C3_4},
{1, C2_5, C1_5, C3_5},
{1, C2_6, C1_6, C3_6},
{1, C2_7, C1_7, C3_7},
{1, C2_8, C1_8, C3_8},
{1, C3_1, C2_1, C4_1},
{1, C7_8, C6_8, C8_8}, // 10
{1, C7_7, C6_7, C9_8},
{1, C8_7, C6_6, C9_7},
{1, C8_6, C7_6, C9_6},
{1, C8_5, C7_5, C9_5},
{1, C8_4, C7_4, C9_4},
{1, C8_3, C7_3, C9_3},
{1, C8_2, C7_2, C9_2},
{1, C8_1, C7_1, C9_1},
{1, C3_10, C1_9, C4_10}, // 19
{1, C2_10, C1_10, C4_11},
{1, C2_11, C1_11, C3_11},
{1, C2_12, C1_12, C3_12},
{1, C2_13, C1_13, C3_13},
{1, C2_14, C1_14, C3_14},
{1, C2_15, C1_15, C3_15},
{1, C2_16, C1_16, C3_16},
{1, C3_9, C2_9, C4_9},
{1, C7_16, C6_16, C8_16}, // 28
{1, C7_15, C6_15, C9_16},
{1, C8_15, C6_14, C9_15},
{1, C8_10, C7_10, C9_10},
{1, C8_9, C7_9, C9_9},
{1, C8_11, C7_11, C9_11},
{1, C8_12, C7_12, C9_12},
{1, C8_13, C7_13, C9_13},
{1, C8_14, C7_14, C9_14},
};
led_config_t g_led_config = { {
{ 0, 5, 10, 15, 20, 25, 29 },
{ 1, 6, 11, 16, 21, 26, 30 },
{ 2, 7, 12, 17, 22, 27, 31 },
{ 3, 8, 13, 18, 23, 28, NO_LED },
{ 4, 9, 14, 19, 24, NO_LED, NO_LED },
{ 32, 33, 34, 35, NO_LED, NO_LED, NO_LED },
{ 65, 61, 56, 51, 46, 41, 36 },
{ 66, 62, 57, 52, 47, 42, 37 },
{ 67, 63, 58, 53, 48, 43, 38 },
{ NO_LED, 64, 59, 54, 49, 44, 39 },
{ NO_LED, NO_LED, 60, 55, 50, 45, 40 },
{ NO_LED, NO_LED, NO_LED, 71, 70, 69, 68 },
}, {
{ 0, 0 }, { 0, 12 }, { 0, 25 }, { 0, 38 }, { 0, 51 },
{ 17, 0 }, { 17, 12 }, { 17, 25 }, { 17, 38 }, { 17, 51 },
{ 34, 0 }, { 34, 12 }, { 34, 25 }, { 34, 38 }, { 34, 51 },
{ 51, 0 }, { 51, 12 }, { 51, 25 }, { 51, 38 }, { 51, 51 },
{ 68, 0 }, { 68, 12 }, { 68, 25 }, { 68, 38 }, { 68, 51 },
{ 86, 0 }, { 86, 12 }, { 86, 25 }, { 86, 38 },
{ 105, 0 }, { 105, 12 }, { 105, 25 },
{ 90, 55 }, { 105, 68 }, { 116, 86 }, { 116, 59 },
{ 250, 0 }, { 250, 12 }, { 250, 25 }, { 250, 38 }, { 250, 51 },
{ 233, 0 }, { 233, 12 }, { 233, 25 }, { 233, 38 }, { 233, 51 },
{ 216, 0 }, { 216, 12 }, { 216, 25 }, { 216, 38 }, { 216, 51 },
{ 198, 0 }, { 198, 12 }, { 198, 25 }, { 198, 38 }, { 198, 51 },
{ 181, 0 }, { 181, 12 }, { 181, 25 }, { 181, 38 }, { 181, 51 },
{ 163, 0 }, { 163, 12 }, { 163, 25 }, { 163, 38 },
{ 146, 0 }, { 146, 12 }, { 146, 25 },
{ 161, 55 }, { 161, 68 }, { 146, 86 }, { 131, 59 }
}, {
1, 1, 1, 1, 1, 4,
4, 4, 4, 1, 4, 4,
4, 4, 1, 4, 4, 4,
4, 1, 4, 4, 4, 4,
1, 4, 4, 4, 4, 4,
4, 4, 1, 1, 1, 1,
1, 1, 1, 1, 1, 4,
4, 4, 4, 1, 4, 4,
4, 4, 1, 4, 4, 4,
4, 1, 4, 4, 4, 4,
1, 4, 4, 4, 4, 4,
4, 4, 1, 1, 1, 1
} };
// clang-format on
void suspend_power_down_kb(void) {
rgb_matrix_set_suspend_state(true);
suspend_power_down_user();
}
void suspend_wakeup_init_kb(void) {
rgb_matrix_set_suspend_state(false);
suspend_wakeup_init_user();
}
#endif
#ifdef AUDIO_ENABLE
bool music_mask_kb(uint16_t keycode) {
switch (keycode) {
case QK_LAYER_TAP ... QK_ONE_SHOT_LAYER_MAX:
case QK_LAYER_TAP_TOGGLE ... QK_LAYER_MOD_MAX:
case QK_MOD_TAP ... QK_MOD_TAP_MAX:
case AU_ON ... MUV_DE:
case RESET:
case EEP_RST:
return false;
default:
return music_mask_user(keycode);
}
}
#endif
#ifdef SWAP_HANDS_ENABLE
// swap-hands action needs a matrix to define the swap
// clang-format off
const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
/* Left hand, matrix positions */
{{6,6}, {5,6}, {4,6}, {3,6}, {2,6}, {1,6},{0,6}},
{{6,7}, {5,7}, {4,7}, {3,7}, {2,7}, {1,7},{0,7}},
{{6,8}, {5,8}, {4,8}, {3,8}, {2,8}, {1,8},{0,8}},
{{6,9}, {5,9}, {4,9}, {3,9}, {2,9}, {1,9},{0,9}},
{{6,10},{5,10},{4,10},{3,10},{2,10},{1,10},{0,10}},
{{6,11},{5,11},{4,11},{3,11},{2,11},{1,11},{0,11}},
/* Right hand, matrix positions */
{{6,0}, {5,0}, {4,0}, {3,0}, {2,0}, {1,0},{0,0}},
{{6,1}, {5,1}, {4,1}, {3,1}, {2,1}, {1,1},{0,1}},
{{6,2}, {5,2}, {4,2}, {3,2}, {2,2}, {1,2},{0,2}},
{{6,3}, {5,3}, {4,3}, {3,3}, {2,3}, {1,3},{0,3}},
{{6,4}, {5,4}, {4,4}, {3,4}, {2,4}, {1,4},{0,4}},
{{6,5}, {5,5}, {4,5}, {3,5}, {2,5}, {1,5},{0,5}},
};
// clang-format on
void keyboard_post_init_kb(void) {
rgb_matrix_enable_noeeprom();
keyboard_post_init_user();
}
#endif
#if defined(AUDIO_ENABLE) && defined(MUSIC_MAP)
// clang-format off
const uint8_t music_map[MATRIX_ROWS][MATRIX_COLS] = LAYOUT_moonlander(
58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
8, 9, 10, 11, 12, 3, 4, 13, 14, 15, 16, 17,
0, 1, 2, 5, 6, 7
);
// clang-format on
#endif
#ifdef ORYX_CONFIGURATOR
bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
#ifdef WEBUSB_ENABLE
case WEBUSB_PAIR:
if (!record->event.pressed && !webusb_state.pairing) layer_state_set_kb(layer_state);
break;
#endif
#if !defined(MOONLANDER_USER_LEDS)
case LED_LEVEL:
if (record->event.pressed) {
keyboard_config.led_level ^= 1;
eeconfig_update_kb(keyboard_config.raw);
if (keyboard_config.led_level) {
layer_state_set_kb(layer_state);
} else {
ML_LED_1(false);
ML_LED_2(false);
ML_LED_3(false);
ML_LED_4(false);
ML_LED_5(false);
ML_LED_6(false);
}
}
break;
#endif
#ifdef RGB_MATRIX_ENABLE
case TOGGLE_LAYER_COLOR:
if (record->event.pressed) {
keyboard_config.disable_layer_led ^= 1;
if (keyboard_config.disable_layer_led) rgb_matrix_set_color_all(0, 0, 0);
eeconfig_update_kb(keyboard_config.raw);
}
break;
case RGB_TOG:
if (record->event.pressed) {
switch (rgb_matrix_get_flags()) {
case LED_FLAG_ALL: {
rgb_matrix_set_flags(LED_FLAG_NONE);
keyboard_config.rgb_matrix_enable = false;
rgb_matrix_set_color_all(0, 0, 0);
} break;
default: {
rgb_matrix_set_flags(LED_FLAG_ALL);
keyboard_config.rgb_matrix_enable = true;
} break;
}
eeconfig_update_kb(keyboard_config.raw);
}
return false;
#endif
}
return process_record_user(keycode, record);
}
#endif
void matrix_init_kb(void) {
keyboard_config.raw = eeconfig_read_kb();
if (!keyboard_config.led_level && !keyboard_config.led_level_res) {
keyboard_config.led_level = true;
keyboard_config.led_level_res = 0b11;
eeconfig_update_kb(keyboard_config.raw);
}
#ifdef RGB_MATRIX_ENABLE
if (keyboard_config.rgb_matrix_enable) {
rgb_matrix_set_flags(LED_FLAG_ALL);
} else {
rgb_matrix_set_flags(LED_FLAG_NONE);
}
#endif
}
void eeconfig_init_kb(void) { // EEPROM is getting reset!
keyboard_config.raw = 0;
keyboard_config.rgb_matrix_enable = true;
keyboard_config.led_level = true;
keyboard_config.led_level_res = 0b11;
eeconfig_update_kb(keyboard_config.raw);
eeconfig_init_user();
}