summaryrefslogtreecommitdiff
path: root/keyboards
diff options
context:
space:
mode:
authorFlorian Didron <fdidron@users.noreply.github.com>2023-09-06 20:45:35 +0700
committerGitHub <noreply@github.com>2023-09-06 20:45:35 +0700
commit551d63b98ff95d5920c1477f1cc84475715bc5e6 (patch)
tree719a504b9ca99cbc34421f44bafb20e99a7a4daf /keyboards
parentcf87d88fb228d9118480a98c909508adacb64f26 (diff)
feat/voyager (#374)
* feat: tentative fix for keyboard crash during esd testing * feat: adds support for the GD32 voyager * feat: adds voyager's dfu suffix * fix: instability issues over i2c * fix: more robust right side scan * fix: tentative delay after init * Revert "fix: tentative delay after init" This reverts commit b0a6461cf1cef60574eac1647fd14e1fe63a020c. * fix: scan left side in between right scan process * fix: resets matrix + layer state when reconnecting the right side * chore: comments and code cleanup * fix: restore previous control flow * fix: decouple led driver reinit from io expander reinit * feat: reinit led drivers independtly * fix: prevents slamming the led driver over i2c * Revert "fix: prevents slamming the led driver over i2c" This reverts commit 48b8c809ea7a99ad2c3e941b83313787985c95e0. * Revert "feat: reinit led drivers independtly" This reverts commit 6405e6b3673478af1d98244c4df6ab73b95b18e1. * fix: reboot on io expander * fix: wait time after reading the io expander * chore: code cleanup and some refactors. * feat: adds led brightness and status led control over hid * fix: remove stray printf * fix: compilation error on ergodox * fix: gd32 eeprom fix * fix: caps lock crash * fix: soft reset to bootloader key. * chore: move the app address define where it should be * fix: cleanup + debounce default * feat: tentatively set gd32 clock to 98Mhz * feat: realign to latest chibios contrib * chore: points to ZSA's chibios contrib fork --------- Co-authored-by: Florian Didron <0x6664@hey.com>
Diffstat (limited to 'keyboards')
-rw-r--r--keyboards/voyager/.DS_Storebin0 -> 8196 bytes
-rw-r--r--keyboards/voyager/chconf.h14
-rw-r--r--keyboards/voyager/config.h140
-rw-r--r--keyboards/voyager/gd32/config.h4
-rw-r--r--keyboards/voyager/gd32/info.json227
-rw-r--r--keyboards/voyager/gd32/rules.mk32
-rw-r--r--keyboards/voyager/halconf.h22
-rw-r--r--keyboards/voyager/info.json227
-rw-r--r--keyboards/voyager/keymaps/.DS_Storebin0 -> 8196 bytes
-rw-r--r--keyboards/voyager/keymaps/default/config.h15
-rw-r--r--keyboards/voyager/keymaps/default/keymap.c196
-rw-r--r--keyboards/voyager/keymaps/default/rules.mk12
-rw-r--r--keyboards/voyager/ld/IGNITION.ld85
-rw-r--r--keyboards/voyager/matrix.c241
-rw-r--r--keyboards/voyager/mcuconf.h39
-rw-r--r--keyboards/voyager/readme.md58
-rw-r--r--keyboards/voyager/rgb_matrix_kb.inc32
-rw-r--r--keyboards/voyager/rules.mk33
-rw-r--r--keyboards/voyager/voyager.c386
-rw-r--r--keyboards/voyager/voyager.h74
20 files changed, 1837 insertions, 0 deletions
diff --git a/keyboards/voyager/.DS_Store b/keyboards/voyager/.DS_Store
new file mode 100644
index 0000000000..46b234f95f
--- /dev/null
+++ b/keyboards/voyager/.DS_Store
Binary files differ
diff --git a/keyboards/voyager/chconf.h b/keyboards/voyager/chconf.h
new file mode 100644
index 0000000000..5abb622086
--- /dev/null
+++ b/keyboards/voyager/chconf.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#define CH_CFG_ST_RESOLUTION 16
+
+#define CH_CFG_ST_FREQUENCY 2000
+
+#define CH_CFG_INTERVALS_SIZE 32
+
+#define CH_CFG_TIME_TYPES_SIZE 32
+
+#define CH_CFG_USE_CONDVARS_TIMEOUT FALSE
+
+#include_next <chconf.h>
+
diff --git a/keyboards/voyager/config.h b/keyboards/voyager/config.h
new file mode 100644
index 0000000000..311310fff4
--- /dev/null
+++ b/keyboards/voyager/config.h
@@ -0,0 +1,140 @@
+/* Copyright 2020 ZSA Technology Labs, Inc <@zsa>
+ * Copyright 2020 Jack Humbert <jack.humb@gmail.com>
+ * 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/>.
+ */
+
+#pragma once
+
+#include "config_common.h"
+
+/* key matrix size */
+#define MATRIX_ROWS 12
+#define MATRIX_COLS 7
+
+/* PCB default pin-out */
+// #define MATRIX_ROW_PINS { B10, B11, B12, B13, B14, B15 }
+// #define MATRIX_COL_PINS { A0, A1, A2, A3, A6, A7, B0 }
+
+// #define MCP23_ROW_PINS { GPB5, GBP4, GBP3, GBP2, GBP1, GBP0 }
+// #define MCP23_COL_PINS { GPA0, GBA1, GBA2, GBA3, GBA4, GBA5, GBA6 }
+
+// #define MCP23_LED_R GPB7
+// #define MCP23_LED_G GPB6
+// #define MCP23_LED_B GPA7
+
+// Not needed, is default address:
+// #define EXTERNAL_EEPROM_I2C_BASE_ADDRESS 0b10100000
+
+/* COL2ROW or ROW2COL */
+#define DIODE_DIRECTION ROW2COL
+
+/* Set 0 if debouncing isn't needed */
+#ifndef DEBOUNCE
+# define DEBOUNCE 5
+#endif
+
+/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
+#define LOCKING_SUPPORT_ENABLE
+/* Locking resynchronize hack */
+#define LOCKING_RESYNC_ENABLE
+
+/*
+ * Feature disable options
+ * These options are also useful to firmware size reduction.
+ */
+
+/* disable debug print */
+// #define NO_DEBUG
+
+#define DRIVER_ADDR_1 0b1110100
+#define DRIVER_ADDR_2 0b1110111
+
+#define DRIVER_COUNT 2
+#define DRIVER_1_LED_TOTAL 36
+#define DRIVER_2_LED_TOTAL 36
+#define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
+#define RGB_MATRIX_CENTER \
+ { 125, 26 }
+#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 175
+#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
+#define RGB_MATRIX_KEYPRESSES
+#define RGB_DISABLE_WHEN_USB_SUSPENDED
+// RGB Matrix Animation modes. Explicitly enabled
+// For full list of effects, see:
+// https://docs.qmk.fm/#/feature_rgb_matrix?id=rgb-matrix-effects
+#define ENABLE_RGB_MATRIX_ALPHAS_MODS
+#define ENABLE_RGB_MATRIX_GRADIENT_UP_DOWN
+#define ENABLE_RGB_MATRIX_GRADIENT_LEFT_RIGHT
+#define ENABLE_RGB_MATRIX_BREATHING
+#define ENABLE_RGB_MATRIX_BAND_SAT
+#define ENABLE_RGB_MATRIX_BAND_VAL
+#define ENABLE_RGB_MATRIX_BAND_PINWHEEL_SAT
+#define ENABLE_RGB_MATRIX_BAND_PINWHEEL_VAL
+#define ENABLE_RGB_MATRIX_BAND_SPIRAL_SAT
+#define ENABLE_RGB_MATRIX_BAND_SPIRAL_VAL
+#define ENABLE_RGB_MATRIX_CYCLE_ALL
+#define ENABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT
+#define ENABLE_RGB_MATRIX_CYCLE_UP_DOWN
+#define ENABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON
+#define ENABLE_RGB_MATRIX_CYCLE_OUT_IN
+#define ENABLE_RGB_MATRIX_CYCLE_OUT_IN_DUAL
+#define ENABLE_RGB_MATRIX_CYCLE_PINWHEEL
+#define ENABLE_RGB_MATRIX_CYCLE_SPIRAL
+#define ENABLE_RGB_MATRIX_DUAL_BEACON
+#define ENABLE_RGB_MATRIX_RAINBOW_BEACON
+#define ENABLE_RGB_MATRIX_RAINBOW_PINWHEELS
+#define ENABLE_RGB_MATRIX_RAINDROPS
+#define ENABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS
+#define ENABLE_RGB_MATRIX_HUE_BREATHING
+#define ENABLE_RGB_MATRIX_HUE_PENDULUM
+#define ENABLE_RGB_MATRIX_HUE_WAVE
+#define ENABLE_RGB_MATRIX_PIXEL_RAIN
+#define ENABLE_RGB_MATRIX_PIXEL_FLOW
+#define ENABLE_RGB_MATRIX_PIXEL_FRACTAL
+// enabled only if RGB_MATRIX_FRAMEBUFFER_EFFECTS is defined
+#define ENABLE_RGB_MATRIX_TYPING_HEATMAP
+#define ENABLE_RGB_MATRIX_DIGITAL_RAIN
+// enabled only of RGB_MATRIX_KEYPRESSES or RGB_MATRIX_KEYRELEASES is defined
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE_SIMPLE
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS
+#define ENABLE_RGB_MATRIX_SPLASH
+#define ENABLE_RGB_MATRIX_MULTISPLASH
+#define ENABLE_RGB_MATRIX_SOLID_SPLASH
+#define ENABLE_RGB_MATRIX_SOLID_MULTISPLASH
+
+#ifndef ISSI_TIMEOUT
+# define ISSI_TIMEOUT 5
+#endif
+
+#define MOUSEKEY_INTERVAL 20
+#define MOUSEKEY_DELAY 0
+#define MOUSEKEY_TIME_TO_MAX 60
+#define MOUSEKEY_MAX_SPEED 7
+#define MOUSEKEY_WHEEL_DELAY 400
+#define MOUSEKEY_WHEEL_INTERVAL MOUSEKEY_INTERVAL
+#define MOUSEKEY_WHEEL_MAX_SPEED MOUSEKEY_MAX_SPEED
+#define MOUSEKEY_WHEEL_TIME_TO_MAX MOUSEKEY_TIME_TO_MAX
+
+#define TAPPING_TOGGLE 1
+
+// Delay between each i2c io expander ops (in MCU cycles)
+#define IO_EXPANDER_OP_DELAY 500 \ No newline at end of file
diff --git a/keyboards/voyager/gd32/config.h b/keyboards/voyager/gd32/config.h
new file mode 100644
index 0000000000..86c3985db2
--- /dev/null
+++ b/keyboards/voyager/gd32/config.h
@@ -0,0 +1,4 @@
+#define GD32
+#define FEE_PAGE_SIZE 0x400
+#define FEE_PAGE_COUNT 2
+#define FEE_MCU_FLASH_SIZE 256 \ No newline at end of file
diff --git a/keyboards/voyager/gd32/info.json b/keyboards/voyager/gd32/info.json
new file mode 100644
index 0000000000..4ac2636296
--- /dev/null
+++ b/keyboards/voyager/gd32/info.json
@@ -0,0 +1,227 @@
+{
+ "keyboard_name": "Voyager",
+ "manufacturer": "ZSA Technology Labs",
+ "url": "zsa.io/voyager",
+ "maintainer": "ZSA Technology Labs",
+ "usb": {
+ "vid": "0x3297",
+ "pid": "0x1978",
+ "device_version": "0.0.1"
+ },
+ "layouts": {
+ "LAYOUT_voyager": {
+ "layout": [
+ {
+ "x": 3,
+ "y": 0
+ },
+ {
+ "x": 12,
+ "y": 0
+ },
+ {
+ "x": 2,
+ "y": 0.25
+ },
+ {
+ "x": 4,
+ "y": 0.25
+ },
+ {
+ "x": 11,
+ "y": 0.25
+ },
+ {
+ "x": 13,
+ "y": 0.25
+ },
+ {
+ "x": 0,
+ "y": 0.5
+ },
+ {
+ "x": 1,
+ "y": 0.5
+ },
+ {
+ "x": 5,
+ "y": 0.5
+ },
+ {
+ "x": 10,
+ "y": 0.5
+ },
+ {
+ "x": 14,
+ "y": 0.5
+ },
+ {
+ "x": 15,
+ "y": 0.5
+ },
+ {
+ "x": 3,
+ "y": 1
+ },
+ {
+ "x": 12,
+ "y": 1
+ },
+ {
+ "x": 2,
+ "y": 1.25
+ },
+ {
+ "x": 4,
+ "y": 1.25
+ },
+ {
+ "x": 11,
+ "y": 1.25
+ },
+ {
+ "x": 13,
+ "y": 1.25
+ },
+ {
+ "x": 0,
+ "y": 1.5
+ },
+ {
+ "x": 1,
+ "y": 1.5
+ },
+ {
+ "x": 5,
+ "y": 1.5
+ },
+ {
+ "x": 10,
+ "y": 1.5
+ },
+ {
+ "x": 14,
+ "y": 1.5
+ },
+ {
+ "x": 15,
+ "y": 1.5
+ },
+ {
+ "x": 3,
+ "y": 2
+ },
+ {
+ "x": 12,
+ "y": 2
+ },
+ {
+ "x": 2,
+ "y": 2.25
+ },
+ {
+ "x": 4,
+ "y": 2.25
+ },
+ {
+ "x": 11,
+ "y": 2.25
+ },
+ {
+ "x": 13,
+ "y": 2.25
+ },
+ {
+ "x": 0,
+ "y": 2.5
+ },
+ {
+ "x": 1,
+ "y": 2.5
+ },
+ {
+ "x": 5,
+ "y": 2.5
+ },
+ {
+ "x": 10,
+ "y": 2.5
+ },
+ {
+ "x": 14,
+ "y": 2.5
+ },
+ {
+ "x": 15,
+ "y": 2.5
+ },
+ {
+ "x": 3,
+ "y": 3
+ },
+ {
+ "x": 12,
+ "y": 3
+ },
+ {
+ "x": 2,
+ "y": 3.25
+ },
+ {
+ "x": 4,
+ "y": 3.25
+ },
+ {
+ "x": 11,
+ "y": 3.25
+ },
+ {
+ "x": 13,
+ "y": 3.25
+ },
+ {
+ "x": 0,
+ "y": 3.5
+ },
+ {
+ "x": 1,
+ "y": 3.5
+ },
+ {
+ "x": 5,
+ "y": 3.5
+ },
+ {
+ "x": 10,
+ "y": 3.5
+ },
+ {
+ "x": 14,
+ "y": 3.5
+ },
+ {
+ "x": 15,
+ "y": 3.5
+ },
+ {
+ "x": 0,
+ "y": 4.5
+ },
+ {
+ "x": 1,
+ "y": 4.5,
+ "h": 1.75
+ },
+ {
+ "x": -0.75,
+ "y": 4.75,
+ "h": 1.75
+ },
+ {
+ "x": 0.25,
+ "y": 4.75
+ }
+ ]
+ }
+ }
+}
diff --git a/keyboards/voyager/gd32/rules.mk b/keyboards/voyager/gd32/rules.mk
new file mode 100644
index 0000000000..7b4ff0f14d
--- /dev/null
+++ b/keyboards/voyager/gd32/rules.mk
@@ -0,0 +1,32 @@
+# MCU name
+MCU = GD32F303
+
+# Bootloader selection
+BOOTLOADER = ignition
+
+# Build Options
+# change yes to no to disable
+#
+BOOTMAGIC_ENABLE = yes # Enable Bootmagic Lite
+MOUSEKEY_ENABLE = yes # Mouse keys
+EXTRAKEY_ENABLE = yes # Audio control and System control
+CONSOLE_ENABLE = no # Console for debug
+COMMAND_ENABLE = no # Commands for debug and configuration
+NKRO_ENABLE = yes # Enable N-Key Rollover
+BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
+RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
+AUDIO_ENABLE = no # Audio output
+CUSTOM_MATRIX = lite
+SWAP_HANDS_ENABLE = yes
+RGB_MATRIX_ENABLE = yes
+RGB_MATRIX_DRIVER = IS31FL3731
+EEPROM_DRIVER = vendor
+MOUSE_SHARED_EP = no
+LTO_ENABLE = no
+DFU_SUFFIX_ARGS = -v 3297 -p 1791
+
+#project specific files
+SRC += matrix.c
+QUANTUM_LIB_SRC += i2c_master.c
+
+MOUSE_SHARED_EP = no \ No newline at end of file
diff --git a/keyboards/voyager/halconf.h b/keyboards/voyager/halconf.h
new file mode 100644
index 0000000000..46b53b1a7f
--- /dev/null
+++ b/keyboards/voyager/halconf.h
@@ -0,0 +1,22 @@
+/* Copyright 2021 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
+
+#define HAL_USE_I2C TRUE
+#define HAL_USE_GPT TRUE
+#define HAL_USE_DAC TRUE
+
+#include_next <halconf.h>
diff --git a/keyboards/voyager/info.json b/keyboards/voyager/info.json
new file mode 100644
index 0000000000..340a527e9d
--- /dev/null
+++ b/keyboards/voyager/info.json
@@ -0,0 +1,227 @@
+{
+ "keyboard_name": "Voyager",
+ "manufacturer": "ZSA Technology Labs",
+ "url": "zsa.io/voyager",
+ "maintainer": "ZSA Technology Labs",
+ "usb": {
+ "vid": "0x3297",
+ "pid": "0x1977",
+ "device_version": "0.0.1"
+ },
+ "layouts": {
+ "LAYOUT_voyager": {
+ "layout": [
+ {
+ "x": 3,
+ "y": 0
+ },
+ {
+ "x": 12,
+ "y": 0
+ },
+ {
+ "x": 2,
+ "y": 0.25
+ },
+ {
+ "x": 4,
+ "y": 0.25
+ },
+ {
+ "x": 11,
+ "y": 0.25
+ },
+ {
+ "x": 13,
+ "y": 0.25
+ },
+ {
+ "x": 0,
+ "y": 0.5
+ },
+ {
+ "x": 1,
+ "y": 0.5
+ },
+ {
+ "x": 5,
+ "y": 0.5
+ },
+ {
+ "x": 10,
+ "y": 0.5
+ },
+ {
+ "x": 14,
+ "y": 0.5
+ },
+ {
+ "x": 15,
+ "y": 0.5
+ },
+ {
+ "x": 3,
+ "y": 1
+ },
+ {
+ "x": 12,
+ "y": 1
+ },
+ {
+ "x": 2,
+ "y": 1.25
+ },
+ {
+ "x": 4,
+ "y": 1.25
+ },
+ {
+ "x": 11,
+ "y": 1.25
+ },
+ {
+ "x": 13,
+ "y": 1.25
+ },
+ {
+ "x": 0,
+ "y": 1.5
+ },
+ {
+ "x": 1,
+ "y": 1.5
+ },
+ {
+ "x": 5,
+ "y": 1.5
+ },
+ {
+ "x": 10,
+ "y": 1.5
+ },
+ {
+ "x": 14,
+ "y": 1.5
+ },
+ {
+ "x": 15,
+ "y": 1.5
+ },
+ {
+ "x": 3,
+ "y": 2
+ },
+ {
+ "x": 12,
+ "y": 2
+ },
+ {
+ "x": 2,
+ "y": 2.25
+ },
+ {
+ "x": 4,
+ "y": 2.25
+ },
+ {
+ "x": 11,
+ "y": 2.25
+ },
+ {
+ "x": 13,
+ "y": 2.25
+ },
+ {
+ "x": 0,
+ "y": 2.5
+ },
+ {
+ "x": 1,
+ "y": 2.5
+ },
+ {
+ "x": 5,
+ "y": 2.5
+ },
+ {
+ "x": 10,
+ "y": 2.5
+ },
+ {
+ "x": 14,
+ "y": 2.5
+ },
+ {
+ "x": 15,
+ "y": 2.5
+ },
+ {
+ "x": 3,
+ "y": 3
+ },
+ {
+ "x": 12,
+ "y": 3
+ },
+ {
+ "x": 2,
+ "y": 3.25
+ },
+ {
+ "x": 4,
+ "y": 3.25
+ },
+ {
+ "x": 11,
+ "y": 3.25
+ },
+ {
+ "x": 13,
+ "y": 3.25
+ },
+ {
+ "x": 0,
+ "y": 3.5
+ },
+ {
+ "x": 1,
+ "y": 3.5
+ },
+ {
+ "x": 5,
+ "y": 3.5
+ },
+ {
+ "x": 10,
+ "y": 3.5
+ },
+ {
+ "x": 14,
+ "y": 3.5
+ },
+ {
+ "x": 15,
+ "y": 3.5
+ },
+ {
+ "x": 0,
+ "y": 4.5
+ },
+ {
+ "x": 1,
+ "y": 4.5,
+ "h": 1.75
+ },
+ {
+ "x": -0.75,
+ "y": 4.75,
+ "h": 1.75
+ },
+ {
+ "x": 0.25,
+ "y": 4.75
+ }
+ ]
+ }
+ }
+}
diff --git a/keyboards/voyager/keymaps/.DS_Store b/keyboards/voyager/keymaps/.DS_Store
new file mode 100644
index 0000000000..50a04ea7b9
--- /dev/null
+++ b/keyboards/voyager/keymaps/.DS_Store
Binary files differ
diff --git a/keyboards/voyager/keymaps/default/config.h b/keyboards/voyager/keymaps/default/config.h
new file mode 100644
index 0000000000..235b8a10a1
--- /dev/null
+++ b/keyboards/voyager/keymaps/default/config.h
@@ -0,0 +1,15 @@
+/*
+ Set any config.h overrides for your specific keymap here.
+ See config.h options at https://docs.qmk.fm/#/config_options?id=the-configh-file
+*/
+#define ORYX_CONFIGURATOR
+#define USB_SUSPEND_WAKEUP_DELAY 0
+#define IGNORE_MOD_TAP_INTERRUPT
+#define FIRMWARE_VERSION u8"dAA/M7l"
+#define RAW_USAGE_PAGE 0xFF60
+#define RAW_USAGE_ID 0x61
+#define LAYER_STATE_8BIT
+#define COMBO_COUNT 1
+
+#define RGB_MATRIX_STARTUP_SPD 60
+
diff --git a/keyboards/voyager/keymaps/default/keymap.c b/keyboards/voyager/keymaps/default/keymap.c
new file mode 100644
index 0000000000..b96185d304
--- /dev/null
+++ b/keyboards/voyager/keymaps/default/keymap.c
@@ -0,0 +1,196 @@
+#include QMK_KEYBOARD_H
+#include "version.h"
+#include "keymap_german.h"
+#include "keymap_nordic.h"
+#include "keymap_french.h"
+#include "keymap_spanish.h"
+#include "keymap_hungarian.h"
+#include "keymap_swedish.h"
+#include "keymap_br_abnt2.h"
+#include "keymap_canadian_multilingual.h"
+#include "keymap_german_ch.h"
+#include "keymap_jp.h"
+#include "keymap_korean.h"
+#include "keymap_bepo.h"
+#include "keymap_italian.h"
+#include "keymap_slovenian.h"
+#include "keymap_lithuanian_azerty.h"
+#include "keymap_danish.h"
+#include "keymap_norwegian.h"
+#include "keymap_portuguese.h"
+#include "keymap_contributions.h"
+#include "keymap_czech.h"
+#include "keymap_romanian.h"
+#include "keymap_russian.h"
+#include "keymap_uk.h"
+#include "keymap_estonian.h"
+#include "keymap_belgian.h"
+#include "keymap_us_international.h"
+#include "keymap_croatian.h"
+#include "keymap_turkish_q.h"
+#include "keymap_slovak.h"
+
+#define KC_MAC_UNDO LGUI(KC_Z)
+#define KC_MAC_CUT LGUI(KC_X)
+#define KC_MAC_COPY LGUI(KC_C)
+#define KC_MAC_PASTE LGUI(KC_V)
+#define KC_PC_UNDO LCTL(KC_Z)
+#define KC_PC_CUT LCTL(KC_X)
+#define KC_PC_COPY LCTL(KC_C)
+#define KC_PC_PASTE LCTL(KC_V)
+#define ES_LESS_MAC KC_GRAVE
+#define ES_GRTR_MAC LSFT(KC_GRAVE)
+#define ES_BSLS_MAC ALGR(KC_6)
+#define NO_PIPE_ALT KC_GRAVE
+#define NO_BSLS_ALT KC_EQUAL
+#define LSA_T(kc) MT(MOD_LSFT | MOD_LALT, kc)
+#define BP_NDSH_MAC ALGR(KC_8)
+#define SE_SECT_MAC ALGR(KC_6)
+#define MOON_LED_LEVEL LED_LEVEL
+
+enum custom_keycodes {
+ RGB_SLD = ML_SAFE_RANGE,
+ HSV_0_255_255,
+ HSV_74_255_255,
+ HSV_169_255_255,
+};
+
+
+
+enum tap_dance_codes {
+ DANCE_0,
+};
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [0] = LAYOUT_voyager(
+ TD(DANCE_0), KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINUS,
+ CAPS_WORD, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSLASH,
+ MT(MOD_LSFT, KC_BSPACE),KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCOLON, MT(MOD_RSFT, KC_QUOTE),
+ KC_LGUI, MT(MOD_LALT, KC_Z),KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMMA, KC_DOT, MT(MOD_RALT, KC_SLASH),KC_RCTRL,
+ LT(1,KC_ENTER), MT(MOD_LCTL, KC_TAB), MT(MOD_LSFT, KC_BSPACE),LT(2,KC_SPACE)
+ ),
+ [1] = LAYOUT_voyager(
+ KC_ESCAPE, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11,
+ KC_GRAVE, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_7, KC_8, KC_9, KC_MINUS, KC_SLASH, KC_F12,
+ KC_TRANSPARENT, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_4, KC_5, KC_6, KC_PLUS, KC_ASTR, KC_BSPACE,
+ KC_TRANSPARENT, KC_TRANSPARENT, KC_LBRACKET, KC_RBRACKET, KC_LCBR, KC_RCBR, KC_1, KC_2, KC_3, KC_DOT, KC_EQUAL, KC_ENTER,
+ KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_0
+ ),
+ [2] = LAYOUT_voyager(
+ RGB_TOG, TOGGLE_LAYER_COLOR,RGB_MOD, RGB_SLD, RGB_VAD, RGB_VAI, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
+ KC_TRANSPARENT, KC_TRANSPARENT, KC_AUDIO_VOL_DOWN,KC_AUDIO_VOL_UP,KC_AUDIO_MUTE, KC_TRANSPARENT, KC_PGUP, KC_HOME, KC_UP, KC_END, KC_TRANSPARENT, KC_TRANSPARENT,
+ KC_TRANSPARENT, KC_MEDIA_PREV_TRACK,KC_MEDIA_NEXT_TRACK,KC_MEDIA_STOP, KC_MEDIA_PLAY_PAUSE,KC_TRANSPARENT, KC_PGDOWN, KC_LEFT, KC_DOWN, KC_RIGHT, KC_TRANSPARENT, KC_TRANSPARENT,
+ KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, HSV_0_255_255, HSV_74_255_255, HSV_169_255_255, KC_TRANSPARENT, LCTL(LSFT(KC_TAB)),LCTL(KC_TAB), KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
+ KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT
+ ),
+};
+
+const uint16_t PROGMEM combo0[] = { MT(MOD_RSFT, KC_QUOTE), MT(MOD_LSFT, KC_BSPACE), COMBO_END};
+
+combo_t key_combos[COMBO_COUNT] = {
+ COMBO(combo0, KC_CAPSLOCK),
+};
+
+
+
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+ switch (keycode) {
+
+ case RGB_SLD:
+ if (record->event.pressed) {
+ rgblight_mode(1);
+ }
+ return false;
+ case HSV_0_255_255:
+ if (record->event.pressed) {
+ rgblight_mode(1);
+ rgblight_sethsv(0,255,255);
+ }
+ return false;
+ case HSV_74_255_255:
+ if (record->event.pressed) {
+ rgblight_mode(1);
+ rgblight_sethsv(74,255,255);
+ }
+ return false;
+ case HSV_169_255_255:
+ if (record->event.pressed) {
+ rgblight_mode(1);
+ rgblight_sethsv(169,255,255);
+ }
+ return false;
+ }
+ return true;
+}
+
+
+typedef struct {
+ bool is_press_action;
+ uint8_t step;
+} tap;
+
+enum {
+ SINGLE_TAP = 1,
+ SINGLE_HOLD,
+ DOUBLE_TAP,
+ DOUBLE_HOLD,
+ DOUBLE_SINGLE_TAP,
+ MORE_TAPS
+};
+
+static tap dance_state[1];
+
+uint8_t dance_step(qk_tap_dance_state_t *state);
+
+uint8_t dance_step(qk_tap_dance_state_t *state) {
+ if (state->count == 1) {
+ if (state->interrupted || !state->pressed) return SINGLE_TAP;
+ else return SINGLE_HOLD;
+ } else if (state->count == 2) {
+ if (state->interrupted) return DOUBLE_SINGLE_TAP;
+ else if (state->pressed) return DOUBLE_HOLD;
+ else return DOUBLE_TAP;
+ }
+ return MORE_TAPS;
+}
+
+
+void on_dance_0(qk_tap_dance_state_t *state, void *user_data);
+void dance_0_finished(qk_tap_dance_state_t *state, void *user_data);
+void dance_0_reset(qk_tap_dance_state_t *state, void *user_data);
+
+void on_dance_0(qk_tap_dance_state_t *state, void *user_data) {
+ if(state->count == 3) {
+ tap_code16(KC_EQUAL);
+ tap_code16(KC_EQUAL);
+ tap_code16(KC_EQUAL);
+ }
+ if(state->count > 3) {
+ tap_code16(KC_EQUAL);
+ }
+}
+
+void dance_0_finished(qk_tap_dance_state_t *state, void *user_data) {
+ dance_state[0].step = dance_step(state);
+ switch (dance_state[0].step) {
+ case SINGLE_TAP: register_code16(KC_EQUAL); break;
+ case SINGLE_HOLD: register_code16(KC_ESCAPE); break;
+ case DOUBLE_TAP: register_code16(KC_EQUAL); register_code16(KC_EQUAL); break;
+ case DOUBLE_SINGLE_TAP: tap_code16(KC_EQUAL); register_code16(KC_EQUAL);
+ }
+}
+
+void dance_0_reset(qk_tap_dance_state_t *state, void *user_data) {
+ wait_ms(10);
+ switch (dance_state[0].step) {
+ case SINGLE_TAP: unregister_code16(KC_EQUAL); break;
+ case SINGLE_HOLD: unregister_code16(KC_ESCAPE); break;
+ case DOUBLE_TAP: unregister_code16(KC_EQUAL); break;
+ case DOUBLE_SINGLE_TAP: unregister_code16(KC_EQUAL); break;
+ }
+ dance_state[0].step = 0;
+}
+
+qk_tap_dance_action_t tap_dance_actions[] = {
+ [DANCE_0] = ACTION_TAP_DANCE_FN_ADVANCED(on_dance_0, dance_0_finished, dance_0_reset),
+};
diff --git a/keyboards/voyager/keymaps/default/rules.mk b/keyboards/voyager/keymaps/default/rules.mk
new file mode 100644
index 0000000000..df7ed84338
--- /dev/null
+++ b/keyboards/voyager/keymaps/default/rules.mk
@@ -0,0 +1,12 @@
+# Set any rules.mk overrides for your specific keymap here.
+# See rules at https://docs.qmk.fm/#/config_options?id=the-rulesmk-file
+CONSOLE_ENABLE = yes
+COMMAND_ENABLE = no
+MOUSEKEY_ENABLE = no
+ORYX_ENABLE = yes
+RGB_MATRIX_CUSTOM_KB = yes
+TAP_DANCE_ENABLE = yes
+SPACE_CADET_ENABLE = no
+CAPS_WORD_ENABLE = yes
+COMBO_ENABLE = yes
+SRC = matrix.c
diff --git a/keyboards/voyager/ld/IGNITION.ld b/keyboards/voyager/ld/IGNITION.ld
new file mode 100644
index 0000000000..0619983beb
--- /dev/null
+++ b/keyboards/voyager/ld/IGNITION.ld
@@ -0,0 +1,85 @@
+/*
+ ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/*
+ * STM32F303xC memory setup.
+ */
+MEMORY
+{
+ flash0 (rx) : org = 0x08002000, len = 256k - 0x2000
+ flash1 (rx) : org = 0x00000000, len = 0
+ flash2 (rx) : org = 0x00000000, len = 0
+ flash3 (rx) : org = 0x00000000, len = 0
+ flash4 (rx) : org = 0x00000000, len = 0
+ flash5 (rx) : org = 0x00000000, len = 0
+ flash6 (rx) : org = 0x00000000, len = 0
+ flash7 (rx) : org = 0x00000000, len = 0
+ ram0 (wx) : org = 0x20000000, len = 40k
+ ram1 (wx) : org = 0x00000000, len = 0
+ ram2 (wx) : org = 0x00000000, len = 0
+ ram3 (wx) : org = 0x00000000, len = 0
+ ram4 (wx) : org = 0x10000000, len = 8k
+ ram5 (wx) : org = 0x00000000, len = 0
+ ram6 (wx) : org = 0x00000000, len = 0
+ ram7 (wx) : org = 0x00000000, len = 0
+}
+
+/* For each data/text section two region are defined, a virtual region
+ and a load region (_LMA suffix).*/
+
+/* Flash region to be used for exception vectors.*/
+REGION_ALIAS("VECTORS_FLASH", flash0);
+REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
+
+/* Flash region to be used for constructors and destructors.*/
+REGION_ALIAS("XTORS_FLASH", flash0);
+REGION_ALIAS("XTORS_FLASH_LMA", flash0);
+
+/* Flash region to be used for code text.*/
+REGION_ALIAS("TEXT_FLASH", flash0);
+REGION_ALIAS("TEXT_FLASH_LMA", flash0);
+
+/* Flash region to be used for read only data.*/
+REGION_ALIAS("RODATA_FLASH", flash0);
+REGION_ALIAS("RODATA_FLASH_LMA", flash0);
+
+/* Flash region to be used for various.*/
+REGION_ALIAS("VARIOUS_FLASH", flash0);
+REGION_ALIAS("VARIOUS_FLASH_LMA", flash0);
+
+/* Flash region to be used for RAM(n) initialization data.*/
+REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0);
+
+/* RAM region to be used for Main stack. This stack accommodates the processing
+ of all exceptions and interrupts.*/
+REGION_ALIAS("MAIN_STACK_RAM", ram0);
+
+/* RAM region to be used for the process stack. This is the stack used by
+ the main() function.*/
+REGION_ALIAS("PROCESS_STACK_RAM", ram0);
+
+/* RAM region to be used for data segment.*/
+REGION_ALIAS("DATA_RAM", ram0);
+REGION_ALIAS("DATA_RAM_LMA", flash0);
+
+/* RAM region to be used for BSS segment.*/
+REGION_ALIAS("BSS_RAM", ram0);
+
+/* RAM region to be used for the default heap.*/
+REGION_ALIAS("HEAP_RAM", ram0);
+
+/* Generic rules inclusion.*/
+INCLUDE rules.ld \ No newline at end of file
diff --git a/keyboards/voyager/matrix.c b/keyboards/voyager/matrix.c
new file mode 100644
index 0000000000..4de3ed860d
--- /dev/null
+++ b/keyboards/voyager/matrix.c
@@ -0,0 +1,241 @@
+/* Copyright 2020 ZSA Technology Labs, Inc <@zsa>
+ * Copyright 2020 Jack Humbert <jack.humb@gmail.com>
+ * 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 "voyager.h"
+#include "is31fl3731.h"
+#include "i2c_master.h"
+
+extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values
+extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
+static matrix_row_t raw_matrix_right[MATRIX_COLS];
+
+#define ROWS_PER_HAND (MATRIX_ROWS / 2)
+#ifndef VOYAGER_I2C_TIMEOUT
+# define VOYAGER_I2C_TIMEOUT 100
+#endif
+
+extern bool mcp23018_leds[3];
+extern bool is_launching;
+
+bool mcp23018_initd = false;
+// extern bool IS31FL3731_initd;
+static uint8_t mcp23018_reset_loop;
+// static uint8_t is31fl3731_reset_loop;
+
+uint8_t mcp23018_tx[3];
+uint8_t mcp23018_rx[1];
+
+void mcp23018_init(void) {
+ i2c_init();
+
+ mcp23018_tx[0] = 0x00; // IODIRA
+ mcp23018_tx[1] = 0b00000000; // A is output
+ mcp23018_tx[2] = 0b00111111; // B is inputs
+
+ if (MSG_OK == i2c_transmit(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx, 3, VOYAGER_I2C_TIMEOUT)) {
+ mcp23018_tx[0] = 0x0C; // GPPUA
+ mcp23018_tx[1] = 0b10000000; // A is not pulled-up
+ mcp23018_tx[2] = 0b11111111; // B is pulled-up
+ wait_ms(5);
+
+ if (MSG_OK == i2c_transmit(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx, 3, VOYAGER_I2C_TIMEOUT)) {
+ wait_ms(5);
+ mcp23018_initd = is_launching = true;
+ }
+ }
+}
+
+bool io_expander_ready(void) {
+ uint8_t tx[1] = {0x13};
+ if (MSG_OK == i2c_readReg(MCP23018_DEFAULT_ADDRESS << 1, tx[0], &tx[0], 1, VOYAGER_I2C_TIMEOUT)) {
+ return true;
+ }
+ return false;
+}
+
+void matrix_init_custom(void) {
+ // outputs
+ setPinOutput(B10);
+ setPinOutput(B11);
+ setPinOutput(B12);
+ setPinOutput(B13);
+ setPinOutput(B14);
+ setPinOutput(B15);
+
+ // inputs
+ setPinInputLow(A0);
+ setPinInputLow(A1);
+ setPinInputLow(A2);
+ setPinInputLow(A3);
+ setPinInputLow(A6);
+ setPinInputLow(A7);
+ setPinInputLow(B0);
+
+ mcp23018_init();
+}
+
+bool matrix_scan_custom(matrix_row_t current_matrix[]) {
+ bool changed = false;
+ // Attempt to reset the mcp23018 if it's not initialized
+ if (!mcp23018_initd) {
+ if (++mcp23018_reset_loop == 0) {
+ // Since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans. This will be approx bit more frequent than once per second.
+ if (io_expander_ready()) {
+ // If we managed to initialize the mcp23018 - we need to reinitialize the matrix / layer state. During an electric discharge the i2c peripherals might be in a weird state. Giving a delay and resetting the MCU allows to recover from this.
+ wait_ms(200);
+ mcu_reset();
+ }
+ }
+ }
+
+ // Scanning left and right side of the keyboard for key presses.
+ // Left side is scanned by reading the gpio pins directly, right side is scanned by reading the mcp23018 registers.
+
+ matrix_row_t data = 0;
+ for (uint8_t row = 0; row <= ROWS_PER_HAND; row++) {
+ // strobe row
+ switch (row) {
+ case 0:
+ writePinHigh(B10);
+ break;
+ case 1:
+ writePinHigh(B11);
+ break;
+ case 2:
+ writePinHigh(B12);
+ break;
+ case 3:
+ writePinHigh(B13);
+ break;
+ case 4:
+ writePinHigh(B14);
+ break;
+ case 5:
+ writePinHigh(B15);
+ break;
+ case 6:
+ break; // Left hand has 6 rows
+ }
+
+ // Selecting the row on the right side of the keyboard.
+ if (mcp23018_initd) {
+ // select row
+ mcp23018_tx[0] = 0x12; // GPIOA
+ mcp23018_tx[1] = (0b01111111 & ~(1 << (row))) | ((uint8_t)!mcp23018_leds[2] << 7); // activate row
+ mcp23018_tx[2] = ((uint8_t)!mcp23018_leds[1] << 6) | ((uint8_t)!mcp23018_leds[0] << 7); // activate row
+
+ if (MSG_OK != i2c_transmit(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx, 3, VOYAGER_I2C_TIMEOUT)) {
+ mcp23018_initd = false;
+ }
+ }
+ // Reading the left side of the keyboard.
+ if (row < ROWS_PER_HAND) {
+ // i2c comm incur enough wait time
+ if (!mcp23018_initd) {
+ // need wait to settle pin state
+ matrix_io_delay();
+ }
+ // read col data
+ data = ((readPin(A0) << 0) | (readPin(A1) << 1) | (readPin(A2) << 2) | (readPin(A3) << 3) | (readPin(A6) << 4) | (readPin(A7) << 5) | (readPin(B0) << 6));
+ // unstrobe row
+ switch (row) {
+ case 0:
+ writePinLow(B10);
+ break;
+ case 1:
+ writePinLow(B11);
+ break;
+ case 2:
+ writePinLow(B12);
+ break;
+ case 3:
+ writePinLow(B13);
+ break;
+ case 4:
+ writePinLow(B14);
+ break;
+ case 5:
+ writePinLow(B15);
+ break;
+ case 6:
+ break;
+ }
+
+ if (current_matrix[row] != data) {
+ current_matrix[row] = data;
+ changed = true;
+ }
+ }
+
+ // Reading the right side of the keyboard.
+ if (mcp23018_initd) {
+ for (uint16_t i = 0; i < IO_EXPANDER_OP_DELAY; i++) {
+ __asm__("nop");
+ }
+
+ mcp23018_tx[0] = 0x13; // GPIOB
+ if (MSG_OK != i2c_readReg(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx[0], &mcp23018_rx[0], 1, VOYAGER_I2C_TIMEOUT)) {
+ mcp23018_initd = false;
+ }
+ data = ~(mcp23018_rx[0] & 0b00111111);
+ for (uint16_t i = 0; i < IO_EXPANDER_OP_DELAY; i++) {
+ __asm__("nop");
+ }
+ } else {
+ data = 0;
+ }
+
+ if (raw_matrix_right[row] != data) {
+ raw_matrix_right[row] = data;
+ changed = true;
+ }
+ }
+
+ for (uint8_t row = 0; row < ROWS_PER_HAND; row++) {
+ current_matrix[11 - row] = 0;
+ for (uint8_t col = 0; col < MATRIX_COLS; col++) {
+ current_matrix[11 - row] |= ((raw_matrix_right[6 - col] & (1 << row) ? 1 : 0) << col);
+ }
+ }
+ return changed;
+}
+
+// DO NOT REMOVE
+// Needed for proper wake/sleep
+void matrix_power_up(void) {
+ bool temp_launching = is_launching;
+
+ matrix_init_custom();
+
+ is_launching = temp_launching;
+ if (!temp_launching) {
+ STATUS_LED_1(false);
+ STATUS_LED_2(false);
+ STATUS_LED_3(false);
+ STATUS_LED_4(false);
+ }
+
+ // initialize matrix state: all keys off
+ for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
+ matrix[i] = 0;
+ }
+}
+
+bool is_transport_connected(void) {
+ return mcp23018_initd;
+} \ No newline at end of file
diff --git a/keyboards/voyager/mcuconf.h b/keyboards/voyager/mcuconf.h
new file mode 100644
index 0000000000..69f458a937
--- /dev/null
+++ b/keyboards/voyager/mcuconf.h
@@ -0,0 +1,39 @@
+/* Copyright 2021 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
+
+#include_next "mcuconf.h"
+
+// for i2c expander, and ISSI
+#undef STM32_I2C_USE_I2C1
+#define STM32_I2C_USE_I2C1 TRUE
+
+// for future hardwar
+#undef STM32_I2C_USE_I2C2
+#define STM32_I2C_USE_I2C2 TRUE
+
+// for audio
+#undef STM32_DAC_USE_DAC1_CH1
+#define STM32_DAC_USE_DAC1_CH1 TRUE
+#undef STM32_DAC_USE_DAC1_CH2
+#define STM32_DAC_USE_DAC1_CH2 TRUE
+#undef STM32_GPT_USE_TIM6
+#define STM32_GPT_USE_TIM6 TRUE
+#undef STM32_GPT_USE_TIM7
+#define STM32_GPT_USE_TIM7 TRUE
+#undef STM32_GPT_USE_TIM8
+#define STM32_GPT_USE_TIM8 TRUE
diff --git a/keyboards/voyager/readme.md b/keyboards/voyager/readme.md
new file mode 100644
index 0000000000..2758f6d60a
--- /dev/null
+++ b/keyboards/voyager/readme.md
@@ -0,0 +1,58 @@
+# Voyager
+
+![Voyager](https://zsa.io/static/gallery-white-case-7a2ef555f8f7f4ce1b9030477b16e517.png)
+
+A next-gen split, ergonomic keyboard with an active left side, USB type C, integrated wrist rest, and a thumb cluster that can move.
+
+
+* Keyboard Maintainer: [drashna](https://github.com/drashna), [ZSA](https://github.com/zsa/)
+* Hardware Supported: Voyager (STM32F303xC)
+* Hardware Availability: [ZSA Store](https://zsa.io/voyager/)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make voyager:default
+
+Flashing example for this keyboard:
+
+ make voyager:default:flash
+
+See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
+
+
+## Voyager Customization
+
+### Indicator LEDs
+
+There are 6 functions for enabling and disabling the LEDs on the top of the boards. The functions are `ML_LED_1(bool)` through `ML_LED_6(bool)`, with the first LED being the left most LED on the left hand, and the sixth LED being the right most LED on the right side.
+
+By default, the Indicator LEDs are used to indicate the layer state for the keyboard. If you wish to change this (and indicate caps/num/scroll lock status instead), then define `VOYAGER_USER_LEDS` in your `config.h` file.
+
+
+### Oryx Configuration
+
+To enable the features from Oryx (ZSA's Configurator), either compile the `default` keymap, or add `#define ORYX_CONFIGURATOR` to your `config.h` file.
+
+This enables the front Indicator LEDs, and the `TOGGLE_LAYER_COLOR` keycode. The `TOGGLE_LAYER_COLOR` keycode toggles the customized LED map configured on Oryx.
+
+### RGB Matrix Features
+
+If you're using the Smart LED (layer indication) feature from the Oryx Configurator, you want to make sure that you enable these options by adding `#define ORYX_CONFIGURATOR` to your keymap's `config.h`.
+
+This changes the `RGB_TOG` keycode so that it will toggle the lights on and off, in a way that will allow the Smart LEDs to continue to work, even with the rest of the LEDs turned off.
+
+Additionally, a new keycode has been added to toggle the Smart LEDs. Use `TOGGLE_LAYER_COLOR`, if you aren't already.
+
+### Detecting split / Gaming mode
+
+To make it extra gaming friendly, you can configure what happens when you disconnect the right half. This is especially useful when using gaming unfriendly layers or layouts (e.g. home row mods, dvorak, colemak).
+
+Example for enabling a specific layer while right side is disconnected:
+
+```
+void housekeeping_task_user(void) {
+ if (!is_transport_connected()) {
+ // set layer
+ }
+}
+```
diff --git a/keyboards/voyager/rgb_matrix_kb.inc b/keyboards/voyager/rgb_matrix_kb.inc
new file mode 100644
index 0000000000..18cf39dfac
--- /dev/null
+++ b/keyboards/voyager/rgb_matrix_kb.inc
@@ -0,0 +1,32 @@
+#ifdef RGB_MATRIX_ENABLE
+RGB_MATRIX_EFFECT(oryx_webhid_effect)
+# ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
+
+static void oryx_webhid_effect_init(void) {
+ // Paint it black
+ for (uint8_t i = 0; i < DRIVER_LED_TOTAL; ++i) {
+ webhid_leds[i] = (RGB){0, 0, 0};
+ }
+}
+
+static bool oryx_webhid_effect_run(effect_params_t* params) {
+ RGB_MATRIX_USE_LIMITS(led_min, led_max);
+ uint8_t val = rgb_matrix_get_val() * 100 / 175;
+ if(val == 0) {
+ rgb_matrix_set_color_all(0, 0, 0);
+ }
+ else {
+ for (uint8_t i = led_min; i < led_max; ++i) {
+ rgb_matrix_set_color(i, webhid_leds[i].r * val / 100, webhid_leds[i].g * val / 100, webhid_leds[i].b * val / 100);
+ }
+ }
+ return rgb_matrix_check_finished_leds(led_max);
+}
+
+static bool oryx_webhid_effect(effect_params_t* params) {
+ if (params->init) oryx_webhid_effect_init();
+ return oryx_webhid_effect_run(params);
+}
+
+# endif
+#endif
diff --git a/keyboards/voyager/rules.mk b/keyboards/voyager/rules.mk
new file mode 100644
index 0000000000..27c275a9e9
--- /dev/null
+++ b/keyboards/voyager/rules.mk
@@ -0,0 +1,33 @@
+# MCU name
+MCU = STM32F303
+
+# Bootloader selection
+BOOTLOADER = ignition
+
+# Build Options
+# change yes to no to disable
+#
+BOOTMAGIC_ENABLE = yes # Enable Bootmagic Lite
+MOUSEKEY_ENABLE = yes # Mouse keys
+EXTRAKEY_ENABLE = yes # Audio control and System control
+CONSOLE_ENABLE = no # Console for debug
+COMMAND_ENABLE = no # Commands for debug and configuration
+NKRO_ENABLE = yes # Enable N-Key Rollover
+BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
+RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
+AUDIO_ENABLE = no # Audio output
+CUSTOM_MATRIX = lite
+SWAP_HANDS_ENABLE = yes
+RGB_MATRIX_ENABLE = yes
+RGB_MATRIX_DRIVER = IS31FL3731
+EEPROM_DRIVER = vendor
+MOUSE_SHARED_EP = no
+LTO_ENABLE = no
+DFU_SUFFIX_ARGS = -v 3297 -p 0791
+DEBUG_ENABLE = yes
+
+#project specific files
+SRC += matrix.c
+QUANTUM_LIB_SRC += i2c_master.c
+
+MOUSE_SHARED_EP = no \ No newline at end of file
diff --git a/keyboards/voyager/voyager.c b/keyboards/voyager/voyager.c
new file mode 100644
index 0000000000..f31dce2924
--- /dev/null
+++ b/keyboards/voyager/voyager.c
@@ -0,0 +1,386 @@
+/* Copyright 2020 ZSA Technology Labs, Inc <@zsa>
+ * Copyright 2020 Jack Humbert <jack.humb@gmail.com>
+ * 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 "voyager.h"
+#include "raw_hid.h"
+
+keyboard_config_t keyboard_config;
+
+bool mcp23018_leds[2] = {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;
+ STATUS_LED_3(false);
+}
+#endif
+
+void voyager_led_task(void) {
+ if (rawhid_state.rgb_control) return;
+ if (is_launching) {
+ STATUS_LED_1(false);
+ STATUS_LED_2(false);
+ STATUS_LED_3(false);
+ STATUS_LED_4(false);
+
+ STATUS_LED_1(true);
+ wait_ms(250);
+ STATUS_LED_2(true);
+ wait_ms(250);
+ STATUS_LED_3(true);
+ wait_ms(250);
+ STATUS_LED_4(true);
+ wait_ms(250);
+ STATUS_LED_1(false);
+ wait_ms(250);
+ STATUS_LED_2(false);
+ wait_ms(250);
+ STATUS_LED_3(false);
+ wait_ms(250);
+ STATUS_LED_4(false);
+ wait_ms(250);
+ is_launching = false;
+ layer_state_set_kb(layer_state);
+ }
+#ifdef DYNAMIC_MACRO_ENABLE
+ else if (is_dynamic_recording) {
+ STATUS_LED_3(true);
+ wait_ms(100);
+ STATUS_LED_3(false);
+ wait_ms(155);
+ }
+#endif
+#if !defined(VOYAGER_USER_LEDS)
+ else {
+ layer_state_set_kb(layer_state);
+ }
+#endif
+}
+
+static THD_WORKING_AREA(waLEDThread, 128);
+static THD_FUNCTION(LEDThread, arg) {
+ (void)arg;
+ chRegSetThreadName("LEDThread");
+ while (true) {
+ voyager_led_task();
+ }
+}
+
+void keyboard_pre_init_kb(void) {
+ // Initialize Reset pins
+ setPinInput(A8);
+ setPinOutput(A9);
+ writePinLow(A9);
+
+ setPinOutput(B5);
+ setPinOutput(B4);
+ setPinOutput(B3);
+
+ writePinLow(B5);
+ writePinLow(B4);
+ writePinLow(B3);
+
+ chThdCreateStatic(waLEDThread, sizeof(waLEDThread), NORMALPRIO - 16, LEDThread, NULL);
+ keyboard_pre_init_user();
+}
+
+#if !defined(VOYAGER_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 || rawhid_state.rgb_control) return state;
+ bool LED_1 = false;
+ bool LED_2 = false;
+ bool LED_3 = false;
+# if !defined(CAPS_LOCK_STATUS)
+ bool LED_4 = false;
+# endif
+
+ uint8_t layer = get_highest_layer(state);
+ switch (layer) {
+ case 1:
+ LED_1 = true;
+ break;
+ case 2:
+ LED_2 = true;
+ break;
+ case 3:
+ LED_3 = true;
+ break;
+ case 4:
+# if !defined(CAPS_LOCK_STATUS)
+ LED_4 = true;
+# endif
+ break;
+ case 5:
+ LED_1 = true;
+ LED_2 = true;
+ break;
+ case 6:
+ LED_1 = true;
+ LED_2 = true;
+ LED_3 = true;
+ break;
+ case 7:
+ LED_1 = true;
+ LED_2 = true;
+ LED_3 = true;
+# if !defined(CAPS_LOCK_STATUS)
+ LED_4 = true;
+# endif
+ break;
+ default:
+ break;
+ }
+
+ STATUS_LED_1(LED_1);
+ STATUS_LED_2(LED_2);
+ STATUS_LED_3(LED_3);
+# if !defined(CAPS_LOCK_STATUS)
+ STATUS_LED_4(LED_4);
+# endif
+ return state;
+}
+#endif
+
+#ifdef RGB_MATRIX_ENABLE
+// clang-format off
+const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL] = {
+/* Refer to IS31 manual for these locations
+ * driver
+ * | R location
+ * | | G location
+ * | | | B location
+ * | | | | */
+ {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, C8_1, C7_1, C9_1},
+ {0, C8_2, C7_2, C9_2},
+ {0, C8_3, C7_3, C9_3},
+ {0, C8_4, C7_4, C9_4},
+ {0, C8_5, C7_5, C9_5},
+ {0, C8_6, C7_6, C9_6},
+ {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, C8_9, C7_9, C9_9},
+ {0, C8_10, C7_10, C9_10},
+ {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, C2_7, C1_7, C3_7},
+ {1, C2_6, C1_6, C3_6},
+ {1, C2_5, C1_5, C3_5},
+ {1, C2_4, C1_4, C3_4},
+ {1, C2_3, C1_3, C3_3},
+ {1, C2_2, C1_2, C4_3},
+
+ {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, C2_8, C1_8, C3_8},
+
+ {1, C2_14, C1_14, C3_14},
+ {1, C2_13, C1_13, C3_13},
+ {1, C2_12, C1_12, C3_12},
+ {1, C2_11, C1_11, C3_11},
+ {1, C2_10, C1_10, C4_11},
+ {1, C8_6, C7_6, C9_6},
+
+ {1, C8_12, C7_12, C9_12},
+ {1, C8_11, C7_11, C9_11},
+ {1, C8_10, C7_10, C9_10},
+ {1, C8_9, C7_9, C9_9},
+ {1, C2_16, C1_16, C3_16},
+ {1, C2_15, C1_15, C3_15},
+
+ {1, C8_14, C7_14, C9_14},
+ {1, C8_13, C7_13, C9_13},
+};
+
+led_config_t g_led_config = { {
+ { NO_LED, 0, 5, 10, 15, 20, 25 },
+ { NO_LED, 1, 6, 11, 16, 21, 26 },
+ { NO_LED, 2, 7, 12, 17, 22, 27 },
+ { NO_LED, 3, 8, 13, 18, 23, NO_LED },
+ { NO_LED, NO_LED, NO_LED, NO_LED, 24, NO_LED, NO_LED },
+ { 32, 33, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED },
+ { 41, 46, 51, 56, 61, 65, NO_LED },
+
+ { 66, 62, 57, 52, 47, 42, NO_LED },
+ { 67, 63, 58, 53, 48, 43, NO_LED },
+ { NO_LED, 64, 59, 54, 49, 44, NO_LED },
+ { NO_LED, NO_LED, 60, NO_LED, NO_LED, NO_LED, NO_LED },
+ { NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, 69, 68 },
+}, {
+ { 0, 4}, { 0, 20}, { 0, 36}, { 0, 52}, { 0, 68},
+ { 16, 3}, { 16, 19}, { 16, 35}, { 16, 51}, { 16, 67},
+ { 32, 1}, { 32, 17}, { 32, 33}, { 32, 49}, { 32, 65},
+ { 48, 0}, { 48, 16}, { 48, 32}, { 48, 48}, { 48, 64},
+ { 64, 1}, { 64, 17}, { 64, 33}, { 64, 49}, { 64, 65},
+ { 80, 3}, { 80, 19}, { 80, 35}, { 80, 51}, { 96, 4},
+ { 96, 20}, { 96, 36}, { 88, 69}, {100, 80}, {112, 91},
+ {108, 69},
+
+ {240, 4}, {240, 20}, {240, 36}, {240, 52}, {240, 68},
+ {224, 3}, {224, 19}, {224, 35}, {224, 51}, {224, 67},
+ {208, 1}, {208, 17}, {208, 33}, {208, 49}, {208, 65},
+ {192, 0}, {192, 16}, {192, 32}, {192, 48}, {192, 64},
+ {176, 1}, {176, 17}, {176, 33}, {176, 49}, {176, 65},
+ {160, 3}, {160, 19}, {160, 35}, {160, 51}, {144, 4},
+ {144, 20}, {144, 36}, {152, 69}, {140, 80}, {128, 91},
+ {132, 69}
+
+}, {
+ 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
+
+#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
+
+#ifdef CAPS_LOCK_STATUS
+bool led_update_kb(led_t led_state) {
+ bool res = led_update_user(led_state);
+ if (res) {
+ STATUS_LED_4(led_state.caps_lock);
+ }
+ return res;
+}
+#endif
+
+bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
+ if (!process_record_user(keycode, record)) {
+ return false;
+ }
+ switch (keycode) {
+#if !defined(VOYAGER_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 {
+ STATUS_LED_1(false);
+ STATUS_LED_2(false);
+ STATUS_LED_3(false);
+ STATUS_LED_4(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);
+ }
+ break;
+ case RGB_TOG:
+ if (record->event.pressed) {
+ switch (rgb_matrix_get_flags()) {
+ case LED_FLAG_ALL: {
+ rgb_matrix_set_flags(LED_FLAG_NONE);
+ rgb_matrix_set_color_all(0, 0, 0);
+ } break;
+ default: {
+ rgb_matrix_set_flags(LED_FLAG_ALL);
+ } break;
+ }
+ }
+ return false;
+#endif
+ }
+ return true;
+}
+
+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);
+ }
+ matrix_init_user();
+}
+
+void eeconfig_init_kb(void) { // EEPROM is getting reset!
+ keyboard_config.raw = 0;
+ keyboard_config.led_level = true;
+ keyboard_config.led_level_res = 0b11;
+ eeconfig_update_kb(keyboard_config.raw);
+ eeconfig_init_user();
+}
diff --git a/keyboards/voyager/voyager.h b/keyboards/voyager/voyager.h
new file mode 100644
index 0000000000..a9fa3169aa
--- /dev/null
+++ b/keyboards/voyager/voyager.h
@@ -0,0 +1,74 @@
+/* Copyright 2020 ZSA Technology Labs, Inc <@zsa>
+ * Copyright 2020 Jack Humbert <jack.humb@gmail.com>
+ * 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/>.
+ */
+
+#pragma once
+
+#include "quantum.h"
+
+extern bool mcp23018_leds[];
+
+#define MCP23018_DEFAULT_ADDRESS 0b0100000
+
+#define STATUS_LED_1(status) writePin(B5, (bool)status)
+#define STATUS_LED_2(status) writePin(B4, (bool)status)
+#define STATUS_LED_3(status) mcp23018_leds[0] = (bool)status
+#define STATUS_LED_4(status) mcp23018_leds[1] = (bool)status
+
+// clang-format off
+#define LAYOUT_voyager( \
+ k00, k01, k02, k03, k04, k05, k26, k27, k28, k29, k30, k31, \
+ k06, k07, k08, k09, k10, k11, k32, k33, k34, k35, k36, k37, \
+ k12, k13, k14, k15, k16, k17, k38, k39, k40, k41, k42, k43, \
+ k18, k19, k20, k21, k22, k23, k44, k45, k46, k47, k48, k49, \
+ k24, k25, k50, k51 \
+)\
+{ \
+ { KC_NO, k00, k01, k02, k03, k04, k05 }, \
+ { KC_NO, k06, k07, k08, k09, k10, k11 }, \
+ { KC_NO, k12, k13, k14, k15, k16, k17 }, \
+ { KC_NO, k18, k19, k20, k21, k22, KC_NO }, \
+ { KC_NO, KC_NO, KC_NO, KC_NO, k23, KC_NO, KC_NO }, \
+ { k24, k25, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
+\
+ { k26, k27, k28, k29, k30, k31, KC_NO }, \
+ { k32, k33, k34, k35, k36, k37, KC_NO }, \
+ { k38, k39, k40, k41, k42, k43, KC_NO }, \
+ { KC_NO, k45, k46, k47, k48, k49, KC_NO }, \
+ { KC_NO, KC_NO, k44, KC_NO, KC_NO, KC_NO, KC_NO }, \
+ { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, k50, k51 }, \
+}
+// clang-format on
+enum voyager_keycodes {
+ TOGGLE_LAYER_COLOR = SAFE_RANGE,
+ LED_LEVEL,
+ ML_SAFE_RANGE,
+};
+
+typedef union {
+ uint32_t raw;
+ struct {
+ bool disable_layer_led : 1;
+ bool placeholder : 1;
+ bool led_level : 1;
+ uint8_t led_level_res : 2; // DO NOT REMOVE
+ };
+} keyboard_config_t;
+
+extern keyboard_config_t keyboard_config;
+
+bool is_transport_connected(void);