summaryrefslogtreecommitdiff
path: root/keyboards
diff options
context:
space:
mode:
authorNick Brassel <nick@tzarc.org>2022-06-20 14:20:56 +1000
committerGitHub <noreply@github.com>2022-06-20 14:20:56 +1000
commitaa06893b58ac3ed88e796968d237f60f4c156875 (patch)
treead4b3a637b7bba88de772dd50150262d2992603e /keyboards
parentad2e85361128a2252798a7bb4c1cbc0bcd58e8ab (diff)
Add Djinn. (#17382)
* Add Djinn. * Review comments. * Further cleanup.
Diffstat (limited to 'keyboards')
-rw-r--r--keyboards/tzarc/djinn/config.h74
-rw-r--r--keyboards/tzarc/djinn/djinn.c199
-rw-r--r--keyboards/tzarc/djinn/djinn.h32
-rw-r--r--keyboards/tzarc/djinn/djinn_portscan_matrix.c117
-rw-r--r--keyboards/tzarc/djinn/djinn_split_sync.c58
-rw-r--r--keyboards/tzarc/djinn/djinn_usbpd.c28
-rw-r--r--keyboards/tzarc/djinn/graphics/djinn.qgf.c246
-rw-r--r--keyboards/tzarc/djinn/graphics/djinn.qgf.h11
-rw-r--r--keyboards/tzarc/djinn/graphics/lock-caps-OFF.qgf.c31
-rw-r--r--keyboards/tzarc/djinn/graphics/lock-caps-OFF.qgf.h11
-rw-r--r--keyboards/tzarc/djinn/graphics/lock-caps-ON.qgf.c32
-rw-r--r--keyboards/tzarc/djinn/graphics/lock-caps-ON.qgf.h11
-rw-r--r--keyboards/tzarc/djinn/graphics/lock-num-OFF.qgf.c31
-rw-r--r--keyboards/tzarc/djinn/graphics/lock-num-OFF.qgf.h11
-rw-r--r--keyboards/tzarc/djinn/graphics/lock-num-ON.qgf.c32
-rw-r--r--keyboards/tzarc/djinn/graphics/lock-num-ON.qgf.h11
-rw-r--r--keyboards/tzarc/djinn/graphics/lock-scrl-OFF.qgf.c32
-rw-r--r--keyboards/tzarc/djinn/graphics/lock-scrl-OFF.qgf.h11
-rw-r--r--keyboards/tzarc/djinn/graphics/lock-scrl-ON.qgf.c32
-rw-r--r--keyboards/tzarc/djinn/graphics/lock-scrl-ON.qgf.h11
-rw-r--r--keyboards/tzarc/djinn/graphics/theme_djinn_default.c307
-rw-r--r--keyboards/tzarc/djinn/graphics/theme_djinn_default.h19
-rw-r--r--keyboards/tzarc/djinn/graphics/thintel15.qff.c74
-rw-r--r--keyboards/tzarc/djinn/graphics/thintel15.qff.h11
-rw-r--r--keyboards/tzarc/djinn/halconf.h14
-rw-r--r--keyboards/tzarc/djinn/info.json140
-rw-r--r--keyboards/tzarc/djinn/keymaps/default/config.h60
-rw-r--r--keyboards/tzarc/djinn/keymaps/default/keymap.c107
-rw-r--r--keyboards/tzarc/djinn/keymaps/default/rules.mk15
-rw-r--r--keyboards/tzarc/djinn/mcuconf.h30
-rw-r--r--keyboards/tzarc/djinn/readme.md27
-rw-r--r--keyboards/tzarc/djinn/rev1/config.h35
-rw-r--r--keyboards/tzarc/djinn/rev1/info.json98
-rw-r--r--keyboards/tzarc/djinn/rev1/rev1.c3
-rw-r--r--keyboards/tzarc/djinn/rev1/rev1.h3
-rw-r--r--keyboards/tzarc/djinn/rev1/rules.mk1
-rw-r--r--keyboards/tzarc/djinn/rev2/config.h47
-rw-r--r--keyboards/tzarc/djinn/rev2/info.json100
-rw-r--r--keyboards/tzarc/djinn/rev2/rev2.c3
-rw-r--r--keyboards/tzarc/djinn/rev2/rev2.h3
-rw-r--r--keyboards/tzarc/djinn/rev2/rules.mk1
-rw-r--r--keyboards/tzarc/djinn/rules.mk23
42 files changed, 2142 insertions, 0 deletions
diff --git a/keyboards/tzarc/djinn/config.h b/keyboards/tzarc/djinn/config.h
new file mode 100644
index 0000000000..005784b98d
--- /dev/null
+++ b/keyboards/tzarc/djinn/config.h
@@ -0,0 +1,74 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+#include "config_common.h"
+
+// Encoders -- right-side is reversed
+#define ENCODERS_PAD_A \
+ { C14 }
+#define ENCODERS_PAD_B \
+ { C15 }
+#define ENCODERS_PAD_A_RIGHT \
+ { C15 }
+#define ENCODERS_PAD_B_RIGHT \
+ { C14 }
+
+#ifndef ENCODER_RESOLUTION
+# define ENCODER_RESOLUTION 2
+#endif // ENCODER_RESOLUTION
+
+// Bootloader
+#define STM32_BOOTLOADER_DUAL_BANK TRUE
+#define STM32_BOOTLOADER_DUAL_BANK_GPIO B7
+
+// Peripheral power control pins
+#define LCD_POWER_ENABLE_PIN A6
+
+// Split configuration
+#define SPLIT_TRANSACTION_IDS_KB RPC_ID_SYNC_STATE_KB
+#define SPLIT_TRANSPORT_MIRROR
+#define SPLIT_LAYER_STATE_ENABLE
+#define SPLIT_LED_STATE_ENABLE
+#define SPLIT_MODS_ENABLE
+#define SPLIT_WPM_ENABLE
+
+// SPI Configuration
+#define SPI_DRIVER SPID3
+#define SPI_SCK_PIN C10
+#define SPI_SCK_PAL_MODE 6
+#define SPI_MOSI_PIN C12
+#define SPI_MOSI_PAL_MODE 6
+#define SPI_MISO_PIN C11
+#define SPI_MISO_PAL_MODE 6
+
+// LCD Configuration
+#define LCD_RST_PIN B3
+#define LCD_CS_PIN D2
+#define LCD_DC_PIN A15
+#ifndef LCD_ACTIVITY_TIMEOUT
+# define LCD_ACTIVITY_TIMEOUT 30000
+#endif // LCD_ACTIVITY_TIMEOUT
+
+// Backlight driver (to control LCD backlight)
+#define BACKLIGHT_LEVELS 4
+#define BACKLIGHT_PWM_DRIVER PWMD17
+#define BACKLIGHT_PWM_CHANNEL 1
+#define BACKLIGHT_PAL_MODE 1
+
+// RGB configuration
+#define RGB_DI_PIN B2
+#define WS2812_EXTERNAL_PULLUP
+#define WS2812_PWM_DRIVER PWMD20
+#define WS2812_PWM_CHANNEL 1
+#define WS2812_PWM_PAL_MODE 3
+#define WS2812_DMA_STREAM STM32_DMA1_STREAM1
+#define WS2812_DMA_CHANNEL 1
+#define WS2812_DMAMUX_ID STM32_DMAMUX1_TIM20_UP
+
+// Audio configuration
+#define AUDIO_PIN A5
+#define AUDIO_PIN_ALT A4
+#define AUDIO_PIN_ALT_AS_NEGATIVE
+#ifndef STARTUP_SONG
+# define STARTUP_SONG SONG(STARTUP_SOUND)
+#endif // STARTUP_SONG
diff --git a/keyboards/tzarc/djinn/djinn.c b/keyboards/tzarc/djinn/djinn.c
new file mode 100644
index 0000000000..41155a6584
--- /dev/null
+++ b/keyboards/tzarc/djinn/djinn.c
@@ -0,0 +1,199 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <string.h>
+#include "quantum.h"
+#include <hal_pal.h>
+#include "djinn.h"
+#include "serial.h"
+#include "split_util.h"
+#include "qp.h"
+
+painter_device_t lcd;
+
+// clang-format off
+#ifdef SWAP_HANDS_ENABLE
+const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
+ { { 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 } },
+ { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 6, 10 }, { 5, 10 }, { 4, 10 }, { 3, 10 } },
+ { { 0, 0 }, { 6, 11 }, { 5, 11 }, { 4, 11 }, { 3, 11 }, { 2, 11 }, { 1, 11 } },
+
+ { { 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 } },
+ { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 6, 4 }, { 5, 4 }, { 4, 4 }, { 3, 4 } },
+ { { 0, 0 }, { 6, 5 }, { 5, 5 }, { 4, 5 }, { 3, 5 }, { 2, 5 }, { 1, 5 } },
+};
+# ifdef ENCODER_MAP_ENABLE
+const uint8_t PROGMEM encoder_hand_swap_config[NUM_ENCODERS] = { 1, 0 };
+# endif // ENCODER_MAP_ENABLE
+#endif // SWAP_HANDS_ENABLE
+// clang-format on
+
+void board_init(void) {
+ usbpd_init();
+}
+
+//----------------------------------------------------------
+// Initialisation
+
+void keyboard_post_init_kb(void) {
+ // Register keyboard state sync split transaction
+ transaction_register_rpc(RPC_ID_SYNC_STATE_KB, kb_state_sync_slave);
+
+ // Reset the initial shared data value between master and slave
+ memset(&kb_state, 0, sizeof(kb_state));
+
+ // Turn off increased current limits
+ setPinOutput(RGB_CURR_1500mA_OK_PIN);
+ writePinLow(RGB_CURR_1500mA_OK_PIN);
+ setPinOutput(RGB_CURR_3000mA_OK_PIN);
+ writePinLow(RGB_CURR_3000mA_OK_PIN);
+
+ // Turn on the RGB
+ setPinOutput(RGB_POWER_ENABLE_PIN);
+ writePinHigh(RGB_POWER_ENABLE_PIN);
+
+#ifdef EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN
+ setPinOutput(EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN);
+ writePinHigh(EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN);
+#endif // EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN
+
+ // Turn on the LCD
+ setPinOutput(LCD_POWER_ENABLE_PIN);
+ writePinHigh(LCD_POWER_ENABLE_PIN);
+
+ // Let the LCD get some power...
+ wait_ms(150);
+
+ // Initialise the LCD
+ lcd = qp_ili9341_make_spi_device(320, 240, LCD_CS_PIN, LCD_DC_PIN, LCD_RST_PIN, 4, 3);
+ qp_init(lcd, QP_ROTATION_0);
+
+ // Turn on the LCD and clear the display
+ kb_state.lcd_power = 1;
+ qp_power(lcd, true);
+ qp_rect(lcd, 0, 0, 239, 319, HSV_BLACK, true);
+
+ // Turn on the LCD backlight
+ backlight_enable();
+ backlight_level(BACKLIGHT_LEVELS);
+
+ // Allow for user post-init
+ keyboard_post_init_user();
+}
+
+//----------------------------------------------------------
+// RGB brightness scaling dependent on USBPD state
+
+#if defined(RGB_MATRIX_ENABLE)
+RGB rgb_matrix_hsv_to_rgb(HSV hsv) {
+ float scale;
+ switch (kb_state.current_setting) {
+ default:
+ case USBPD_500MA:
+ scale = 0.35f;
+ break;
+ case USBPD_1500MA:
+ scale = 0.75f;
+ break;
+ case USBPD_3000MA:
+ scale = 1.0f;
+ break;
+ }
+
+ hsv.v = (uint8_t)(hsv.v * scale);
+ return hsv_to_rgb(hsv);
+}
+#endif
+
+//----------------------------------------------------------
+// UI Placeholder, implemented in themes
+
+__attribute__((weak)) void draw_ui_user(void) {}
+
+//----------------------------------------------------------
+// Housekeeping
+
+void housekeeping_task_kb(void) {
+ // Update kb_state so we can send to slave
+ kb_state_update();
+
+ // Data sync from master to slave
+ kb_state_sync();
+
+ // Work out if we've changed our current limit, update the limiter circuit switches
+ static uint8_t current_setting = USBPD_500MA;
+ if (current_setting != kb_state.current_setting) {
+ current_setting = kb_state.current_setting;
+ switch (current_setting) {
+ default:
+ case USBPD_500MA:
+ writePinLow(RGB_CURR_1500mA_OK_PIN);
+ writePinLow(RGB_CURR_3000mA_OK_PIN);
+ break;
+ case USBPD_1500MA:
+ writePinHigh(RGB_CURR_1500mA_OK_PIN);
+ writePinLow(RGB_CURR_3000mA_OK_PIN);
+ break;
+ case USBPD_3000MA:
+ writePinHigh(RGB_CURR_1500mA_OK_PIN);
+ writePinHigh(RGB_CURR_3000mA_OK_PIN);
+ break;
+ }
+
+ // If we've changed the current limit, toggle rgb off and on if it was on, to force a brightness update on all LEDs
+ if (is_keyboard_master() && rgb_matrix_is_enabled()) {
+ rgb_matrix_disable_noeeprom();
+ rgb_matrix_enable_noeeprom();
+ }
+ }
+
+ // Turn on/off the LCD
+ static bool lcd_on = false;
+ if (lcd_on != (bool)kb_state.lcd_power) {
+ lcd_on = (bool)kb_state.lcd_power;
+ qp_power(lcd, lcd_on);
+ }
+
+ // Enable/disable RGB
+ if (lcd_on) {
+ // Turn on RGB
+ writePinHigh(RGB_POWER_ENABLE_PIN);
+ // Modify the RGB state if different to the LCD state
+ if (rgb_matrix_is_enabled() != lcd_on) {
+ // Wait for a small amount of time to allow the RGB capacitors to charge, before enabling RGB output
+ wait_ms(10);
+ // Enable RGB
+ rgb_matrix_enable_noeeprom();
+ }
+ } else {
+ // Turn off RGB
+ writePinLow(RGB_POWER_ENABLE_PIN);
+ // Disable the PWM output for the RGB
+ if (rgb_matrix_is_enabled() != lcd_on) {
+ rgb_matrix_disable_noeeprom();
+ }
+ }
+
+ // Match the backlight to the LCD state
+ if (is_keyboard_master() && is_backlight_enabled() != lcd_on) {
+ if (lcd_on)
+ backlight_enable();
+ else
+ backlight_disable();
+ }
+
+ // Draw the UI
+ if (kb_state.lcd_power) {
+ draw_ui_user();
+ }
+
+ // Go into low-scan interrupt-based mode if we haven't had any matrix activity in the last 250 milliseconds
+ if (last_input_activity_elapsed() > 250) {
+ matrix_wait_for_interrupt();
+ }
+} \ No newline at end of file
diff --git a/keyboards/tzarc/djinn/djinn.h b/keyboards/tzarc/djinn/djinn.h
new file mode 100644
index 0000000000..ff6b555e8e
--- /dev/null
+++ b/keyboards/tzarc/djinn/djinn.h
@@ -0,0 +1,32 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+#include "quantum.h"
+#include "qp.h"
+
+//----------------------------------------------------------
+// General stuff
+
+extern painter_device_t lcd;
+
+void matrix_wait_for_interrupt(void);
+
+void usbpd_update(void);
+const char* usbpd_str(usbpd_allowance_t allowance);
+
+//----------------------------------------------------------
+// Runtime data sync -- keyboard
+
+#pragma pack(push)
+#pragma pack(1)
+typedef struct kb_runtime_config {
+ unsigned lcd_power : 1;
+ usbpd_allowance_t current_setting : 2;
+} kb_runtime_config;
+#pragma pack(pop)
+
+extern kb_runtime_config kb_state;
+
+void kb_state_update(void);
+void kb_state_sync(void);
+void kb_state_sync_slave(uint8_t m2s_size, const void* m2s_buffer, uint8_t s2m_size, void* s2m_buffer);
diff --git a/keyboards/tzarc/djinn/djinn_portscan_matrix.c b/keyboards/tzarc/djinn/djinn_portscan_matrix.c
new file mode 100644
index 0000000000..f0ae9721f9
--- /dev/null
+++ b/keyboards/tzarc/djinn/djinn_portscan_matrix.c
@@ -0,0 +1,117 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include "quantum.h"
+#include <hal_pal.h>
+#include "djinn.h"
+
+#define GPIOB_BITMASK (1 << 13 | 1 << 14 | 1 << 15) // B13, B14, B15
+#define GPIOB_OFFSET 13
+#define GPIOB_COUNT 3
+#define GPIOC_BITMASK (1 << 6 | 1 << 7 | 1 << 8) // C6, C7, C8
+#define GPIOC_OFFSET 6
+
+// Pin definitions
+static const pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
+static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
+
+void matrix_wait_for_pin(pin_t pin, uint8_t target_state) {
+ rtcnt_t start = chSysGetRealtimeCounterX();
+ rtcnt_t end = start + 5000;
+ while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end)) {
+ if (readPin(pin) == target_state) {
+ break;
+ }
+ }
+}
+
+void matrix_wait_for_port(stm32_gpio_t *port, uint32_t target_bitmask) {
+ rtcnt_t start = chSysGetRealtimeCounterX();
+ rtcnt_t end = start + 5000;
+ while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end)) {
+ if ((palReadPort(port) & target_bitmask) == target_bitmask) {
+ break;
+ }
+ }
+}
+
+void matrix_init_custom(void) {
+ for (int i = 0; i < MATRIX_ROWS; ++i) {
+ setPinInputHigh(row_pins[i]);
+ }
+ for (int i = 0; i < MATRIX_COLS; ++i) {
+ setPinInputHigh(col_pins[i]);
+ }
+}
+
+bool matrix_scan_custom(matrix_row_t current_matrix[]) {
+ static matrix_row_t temp_matrix[MATRIX_ROWS] = {0};
+
+ for (int current_col = 0; current_col < MATRIX_COLS; ++current_col) {
+ // Keep track of the pin we're working with
+ pin_t curr_col_pin = col_pins[current_col];
+
+ // Setup the output column pin
+ setPinOutput(curr_col_pin);
+ writePinLow(curr_col_pin);
+ matrix_wait_for_pin(curr_col_pin, 0);
+
+ // Read the row ports
+ uint32_t gpio_b = palReadPort(GPIOB);
+ uint32_t gpio_c = palReadPort(GPIOC);
+
+ // Unselect the row pin
+ setPinInputHigh(curr_col_pin);
+
+ // Construct the packed bitmask for the pins
+ uint32_t readback = ~(((gpio_b & GPIOB_BITMASK) >> GPIOB_OFFSET) | (((gpio_c & GPIOC_BITMASK) >> GPIOC_OFFSET) << GPIOB_COUNT));
+
+ // Inject values into the matrix
+ for (int i = 0; i < MATRIX_ROWS; ++i) {
+ if (readback & (1 << i)) {
+ temp_matrix[i] |= (1ul << current_col);
+ } else {
+ temp_matrix[i] &= ~(1ul << current_col);
+ }
+ }
+
+ // Wait for readback of the unselected column to go high
+ matrix_wait_for_pin(curr_col_pin, 1);
+
+ // Wait for readback of each port to go high -- unselecting the row would have been completed
+ matrix_wait_for_port(GPIOB, GPIOB_BITMASK);
+ matrix_wait_for_port(GPIOC, GPIOC_BITMASK);
+ }
+
+ // Check if we've changed, return the last-read data
+ bool changed = memcmp(current_matrix, temp_matrix, sizeof(temp_matrix)) != 0;
+ if (changed) {
+ memcpy(current_matrix, temp_matrix, sizeof(temp_matrix));
+ }
+ return changed;
+}
+
+void matrix_wait_for_interrupt(void) {
+ // Set up row/col pins and attach callback
+ for (int i = 0; i < sizeof(col_pins) / sizeof(pin_t); ++i) {
+ setPinOutput(col_pins[i]);
+ writePinLow(col_pins[i]);
+ }
+ for (int i = 0; i < sizeof(row_pins) / sizeof(pin_t); ++i) {
+ setPinInputHigh(row_pins[i]);
+ palEnableLineEvent(row_pins[i], PAL_EVENT_MODE_BOTH_EDGES);
+ }
+
+ // Wait for an interrupt
+ __WFI();
+
+ // Now that the interrupt has woken us up, reset all the row/col pins back to defaults
+ for (int i = 0; i < sizeof(row_pins) / sizeof(pin_t); ++i) {
+ palDisableLineEvent(row_pins[i]);
+ writePinHigh(row_pins[i]);
+ setPinInputHigh(row_pins[i]);
+ }
+ for (int i = 0; i < sizeof(col_pins) / sizeof(pin_t); ++i) {
+ writePinHigh(col_pins[i]);
+ setPinInputHigh(col_pins[i]);
+ }
+} \ No newline at end of file
diff --git a/keyboards/tzarc/djinn/djinn_split_sync.c b/keyboards/tzarc/djinn/djinn_split_sync.c
new file mode 100644
index 0000000000..3c7a58d155
--- /dev/null
+++ b/keyboards/tzarc/djinn/djinn_split_sync.c
@@ -0,0 +1,58 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <string.h>
+#include "quantum.h"
+#include "transactions.h"
+#include "split_util.h"
+#include "djinn.h"
+
+kb_runtime_config kb_state;
+uint32_t last_slave_sync_time = 0;
+
+void kb_state_update(void) {
+ if (is_keyboard_master()) {
+ // Modify allowed current limits
+ usbpd_update();
+
+ // Turn off the LCD if there's been no matrix activity
+ kb_state.lcd_power = (last_input_activity_elapsed() < LCD_ACTIVITY_TIMEOUT) ? 1 : 0;
+ }
+}
+
+void kb_state_sync(void) {
+ if (!is_transport_connected()) return;
+
+ if (is_keyboard_master()) {
+ // Keep track of the last state, so that we can tell if we need to propagate to slave
+ static kb_runtime_config last_kb_state;
+ static uint32_t last_sync;
+ bool needs_sync = false;
+
+ // Check if the state values are different
+ if (memcmp(&kb_state, &last_kb_state, sizeof(kb_runtime_config))) {
+ needs_sync = true;
+ memcpy(&last_kb_state, &kb_state, sizeof(kb_runtime_config));
+ }
+
+ // Send to slave every 500ms regardless of state change
+ if (timer_elapsed32(last_sync) > 500) {
+ needs_sync = true;
+ }
+
+ // Perform the sync if requested
+ if (needs_sync) {
+ if (transaction_rpc_send(RPC_ID_SYNC_STATE_KB, sizeof(kb_runtime_config), &kb_state)) {
+ last_sync = timer_read32();
+ } else {
+ dprint("Failed to perform data transaction\n");
+ }
+ }
+ }
+}
+
+void kb_state_sync_slave(uint8_t m2s_size, const void* m2s_buffer, uint8_t s2m_size, void* s2m_buffer) {
+ if (m2s_size == sizeof(kb_runtime_config)) {
+ memcpy(&kb_state, m2s_buffer, sizeof(kb_runtime_config));
+ last_slave_sync_time = timer_read32();
+ }
+}
diff --git a/keyboards/tzarc/djinn/djinn_usbpd.c b/keyboards/tzarc/djinn/djinn_usbpd.c
new file mode 100644
index 0000000000..b0bf166b7c
--- /dev/null
+++ b/keyboards/tzarc/djinn/djinn_usbpd.c
@@ -0,0 +1,28 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <string.h>
+#include "quantum.h"
+#include "djinn.h"
+
+const char* usbpd_str(usbpd_allowance_t allowance) {
+ switch (allowance) {
+ default:
+ case USBPD_500MA:
+ return "500mA";
+ case USBPD_1500MA:
+ return "1500mA";
+ case USBPD_3000MA:
+ return "3000mA";
+ }
+}
+
+void usbpd_update(void) {
+ static uint32_t last_read = 0;
+ if (timer_elapsed32(last_read) > 250) {
+ usbpd_allowance_t allowance = usbpd_get_allowance();
+ if (kb_state.current_setting != allowance) {
+ dprintf("Transitioning UCPD1 %s -> %s\n", usbpd_str(kb_state.current_setting), usbpd_str(allowance));
+ kb_state.current_setting = allowance;
+ }
+ }
+} \ No newline at end of file
diff --git a/keyboards/tzarc/djinn/graphics/djinn.qgf.c b/keyboards/tzarc/djinn/graphics/djinn.qgf.c
new file mode 100644
index 0000000000..0acdf6ebb5
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/djinn.qgf.c
@@ -0,0 +1,246 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i djinn.png -f mono4`
+
+#include <qp.h>
+
+const uint32_t gfx_djinn_length = 3724;
+
+// clang-format off
+const uint8_t gfx_djinn[3724] = {
+ 0x00, 0xFF, 0x12, 0x00, 0x00, 0x51, 0x47, 0x46, 0x01, 0x8C, 0x0E, 0x00, 0x00, 0x73, 0xF1, 0xFF,
+ 0xFF, 0x66, 0x00, 0x20, 0x01, 0x01, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0xFD, 0x06, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xE8, 0x03, 0x05, 0xFA, 0x5C, 0x0E, 0x00,
+ 0x58, 0x00, 0x80, 0x90, 0x19, 0x00, 0x80, 0x2D, 0x18, 0x00, 0x81, 0xE0, 0x07, 0x18, 0x00, 0x81,
+ 0xFE, 0x01, 0x17, 0x00, 0x81, 0xF4, 0x2F, 0x17, 0x00, 0x82, 0x80, 0xFF, 0x07, 0x17, 0x00, 0x82,
+ 0xFD, 0xFF, 0x01, 0x16, 0x00, 0x82, 0xE0, 0xFF, 0x2F, 0x16, 0x00, 0x80, 0x80, 0x02, 0xFF, 0x80,
+ 0x03, 0x15, 0x00, 0x84, 0x40, 0xFE, 0xFF, 0x7F, 0x14, 0x15, 0x00, 0x80, 0xF9, 0x02, 0xFF, 0x81,
+ 0x4B, 0x1A, 0x14, 0x00, 0x80, 0xE4, 0x03, 0xFF, 0x81, 0xE0, 0x06, 0x13, 0x00, 0x80, 0xD0, 0x03,
+ 0xFF, 0x82, 0x0F, 0xBE, 0x01, 0x12, 0x00, 0x80, 0x80, 0x04, 0xFF, 0x81, 0xE0, 0x6F, 0x13, 0x00,
+ 0x80, 0xFE, 0x03, 0xFF, 0x82, 0x0F, 0xFE, 0x0B, 0x12, 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x82, 0xE0,
+ 0xFF, 0x02, 0x11, 0x00, 0x80, 0xE0, 0x04, 0xFF, 0x82, 0x0F, 0xFE, 0xBF, 0x11, 0x00, 0x80, 0x80,
+ 0x04, 0xFF, 0x83, 0xBF, 0xF4, 0xFF, 0x1F, 0x11, 0x00, 0x80, 0xFE, 0x04, 0xFF, 0x80, 0x47, 0x02,
+ 0xFF, 0x80, 0x07, 0x10, 0x00, 0x80, 0xF4, 0x04, 0xFF, 0x83, 0x2F, 0xF8, 0xFF, 0xBF, 0x10, 0x00,
+ 0x80, 0xD0, 0x05, 0xFF, 0x80, 0xD1, 0x02, 0xFF, 0x80, 0x1F, 0x0F, 0x00, 0x81, 0x40, 0xFE, 0x04,
+ 0xFF, 0x81, 0x0B, 0xFE, 0x02, 0xFF, 0x80, 0x06, 0x0F, 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x81, 0x2F,
+ 0xF4, 0x02, 0xFF, 0x80, 0xBF, 0x0F, 0x00, 0x80, 0xE0, 0x04, 0xFF, 0x81, 0xBF, 0xD0, 0x03, 0xFF,
+ 0x80, 0x1F, 0x0E, 0x00, 0x80, 0x40, 0x04, 0xFF, 0x81, 0xBF, 0x41, 0x04, 0xFF, 0x80, 0x06, 0x0E,
+ 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x81, 0x06, 0xFD, 0x03, 0xFF, 0x80, 0x7F, 0x0E, 0x00, 0x80, 0xE0,
+ 0x04, 0xFF, 0x81, 0x06, 0x90, 0x04, 0xFF, 0x80, 0x0B, 0x0D, 0x00, 0x80, 0x40, 0x04, 0xFF, 0x82,
+ 0x1B, 0x00, 0xE4, 0x04, 0xFF, 0x80, 0x01, 0x0D, 0x00, 0x80, 0xF8, 0x03, 0xFF, 0x80, 0x1B, 0x02,
+ 0x00, 0x80, 0xE4, 0x03, 0xFF, 0x80, 0x2F, 0x0D, 0x00, 0x80, 0xD0, 0x03, 0xFF, 0x80, 0x5B, 0x03,
+ 0x00, 0x80, 0xE4, 0x03, 0xFF, 0x80, 0x07, 0x0D, 0x00, 0x80, 0xFE, 0x02, 0xFF, 0x80, 0x6F, 0x04,
+ 0x00, 0x80, 0xF9, 0x02, 0xFF, 0x80, 0x7F, 0x0D, 0x00, 0x80, 0xE0, 0x02, 0xFF, 0x80, 0x7F, 0x05,
+ 0x00, 0x80, 0xFD, 0x02, 0xFF, 0x80, 0x0B, 0x0C, 0x00, 0x80, 0x40, 0x02, 0xFF, 0x81, 0xBF, 0x01,
+ 0x04, 0x00, 0x81, 0x40, 0xFE, 0x02, 0xFF, 0x0D, 0x00, 0x80, 0xF8, 0x02, 0xFF, 0x80, 0x02, 0x05,
+ 0x00, 0x80, 0x90, 0x02, 0xFF, 0x80, 0x0F, 0x0C, 0x00, 0x80, 0x80, 0x02, 0xFF, 0x80, 0x07, 0x06,
+ 0x00, 0x80, 0xF4, 0x02, 0xFF, 0x0D, 0x00, 0x82, 0xFD, 0xFF, 0x1F, 0x07, 0x00, 0x82, 0xFD, 0xFF,
+ 0x1F, 0x0C, 0x00, 0x82, 0xD0, 0xFF, 0x7F, 0x07, 0x00, 0x80, 0x80, 0x02, 0xFF, 0x80, 0x01, 0x0C,
+ 0x00, 0x82, 0xFD, 0xFF, 0x02, 0x07, 0x00, 0x82, 0xF4, 0xFF, 0x1F, 0x0C, 0x00, 0x82, 0xE0, 0xFF,
+ 0x0B, 0x08, 0x00, 0x82, 0xFE, 0xFF, 0x01, 0x0C, 0x00, 0x81, 0xFE, 0x7F, 0x08, 0x00, 0x82, 0xD0,
+ 0xFF, 0x1F, 0x0C, 0x00, 0x82, 0xE0, 0xFF, 0x02, 0x08, 0x00, 0x81, 0xF8, 0xFF, 0x0D, 0x00, 0x81,
+ 0xFE, 0x1F, 0x08, 0x00, 0x82, 0x40, 0xFF, 0x0F, 0x0C, 0x00, 0x82, 0xE0, 0xFF, 0x01, 0x08, 0x00,
+ 0x81, 0xF4, 0xFF, 0x0D, 0x00, 0x81, 0xFD, 0x0B, 0x09, 0x00, 0x81, 0xFE, 0x0B, 0x0C, 0x00, 0x81,
+ 0xD0, 0xBF, 0x09, 0x00, 0x81, 0xE0, 0xBF, 0x0D, 0x00, 0x81, 0xF9, 0x07, 0x09, 0x00, 0x81, 0xFD,
+ 0x07, 0x0C, 0x00, 0x81, 0x80, 0x7F, 0x09, 0x00, 0x81, 0xD0, 0x7F, 0x0D, 0x00, 0x81, 0xF8, 0x07,
+ 0x09, 0x00, 0x81, 0xF9, 0x03, 0x0C, 0x00, 0x81, 0x40, 0x7F, 0x09, 0x00, 0x81, 0x90, 0x2F, 0x0D,
+ 0x00, 0x81, 0xE0, 0x07, 0x09, 0x00, 0x81, 0xF8, 0x02, 0x0D, 0x00, 0x80, 0x7D, 0x09, 0x00, 0x81,
+ 0x80, 0x1F, 0x0D, 0x00, 0x81, 0x80, 0x07, 0x09, 0x00, 0x80, 0xB8, 0x0E, 0x00, 0x80, 0x74, 0x09,
+ 0x00, 0x81, 0x80, 0x0B, 0x0E, 0x00, 0x80, 0x0A, 0x03, 0x00, 0x80, 0x04, 0x05, 0x00, 0x80, 0x78,
+ 0x0E, 0x00, 0x80, 0x90, 0x03, 0x00, 0x83, 0xA4, 0x00, 0x80, 0x06, 0x02, 0x00, 0x81, 0x80, 0x02,
+ 0x0E, 0x00, 0x87, 0x04, 0x00, 0x40, 0xE9, 0x0B, 0x00, 0xF8, 0x5A, 0x02, 0x00, 0x80, 0x14, 0x10,
+ 0x00, 0x86, 0x40, 0xFA, 0xBF, 0x00, 0x40, 0xFF, 0x6B, 0x12, 0x00, 0x87, 0x90, 0xFE, 0xFF, 0x07,
+ 0x00, 0xE0, 0xFF, 0xAF, 0x11, 0x00, 0x80, 0x80, 0x02, 0xFF, 0x80, 0x1F, 0x02, 0x00, 0x82, 0xF9,
+ 0xFF, 0x2F, 0x11, 0x00, 0x82, 0xFE, 0xFF, 0x6F, 0x03, 0x00, 0x82, 0xFD, 0xFF, 0x0B, 0x10, 0x00,
+ 0x82, 0xF8, 0xFF, 0x7F, 0x03, 0x00, 0x82, 0x40, 0xFE, 0xFF, 0x10, 0x00, 0x83, 0xD0, 0xFF, 0xBF,
+ 0x01, 0x03, 0x00, 0x82, 0x80, 0xFF, 0x1F, 0x10, 0x00, 0x82, 0xFD, 0xFF, 0x02, 0x04, 0x00, 0x82,
+ 0xD0, 0xFF, 0x02, 0x0F, 0x00, 0x82, 0xE0, 0xFF, 0x0B, 0x05, 0x00, 0x81, 0xF8, 0x2F, 0x0F, 0x00,
+ 0x82, 0x40, 0xFF, 0x2F, 0x06, 0x00, 0x81, 0xFE, 0x02, 0x0F, 0x00, 0x89, 0xF4, 0xFF, 0x01, 0x00,
+ 0x50, 0x55, 0x05, 0x00, 0xD0, 0x7F, 0x0F, 0x00, 0x84, 0x40, 0xFF, 0x07, 0x00, 0xA4, 0x02, 0xAA,
+ 0x02, 0x00, 0x81, 0xF8, 0x07, 0x0F, 0x00, 0x81, 0xF4, 0x6F, 0x02, 0x00, 0x85, 0xFE, 0xFF, 0x07,
+ 0x00, 0x40, 0x7F, 0x0F, 0x00, 0x8A, 0x40, 0xFF, 0x81, 0x00, 0x80, 0xFF, 0x1F, 0x00, 0x40, 0xE0,
+ 0x0B, 0x0F, 0x00, 0x85, 0xF4, 0x1B, 0x1E, 0x00, 0xF0, 0xBF, 0x02, 0x00, 0x81, 0x19, 0xBD, 0x0F,
+ 0x00, 0x8B, 0x80, 0xBF, 0xF0, 0x02, 0x00, 0xFD, 0x07, 0x00, 0xE0, 0xC2, 0x0B, 0x05, 0x0E, 0x00,
+ 0x8A, 0xF8, 0x47, 0xBF, 0x00, 0x80, 0x2F, 0x00, 0x40, 0x7F, 0xB8, 0x61, 0x0E, 0x00, 0x8B, 0x40,
+ 0x6F, 0xF8, 0x1F, 0x00, 0xF4, 0x01, 0x00, 0xF9, 0x47, 0x1F, 0x1E, 0x0E, 0x00, 0x8B, 0xF4, 0x82,
+ 0xFF, 0x06, 0x00, 0x19, 0x00, 0xE4, 0xBF, 0xF0, 0xD1, 0x06, 0x0D, 0x00, 0x8C, 0x40, 0x1F, 0xFD,
+ 0xBF, 0x01, 0x40, 0x00, 0x90, 0xFF, 0x0B, 0x2E, 0xBD, 0x01, 0x0D, 0x00, 0x86, 0xF4, 0xE1, 0xFF,
+ 0xBF, 0x01, 0x00, 0x80, 0x02, 0xFF, 0x82, 0xE0, 0x92, 0x6F, 0x0D, 0x00, 0x8C, 0x45, 0x1B, 0xFE,
+ 0xFF, 0xBF, 0x05, 0x94, 0xFE, 0xFF, 0x1F, 0x2D, 0xF8, 0x1B, 0x0C, 0x00, 0x82, 0x74, 0xB4, 0xE0,
+ 0x07, 0xFF, 0x83, 0xD1, 0x86, 0xFF, 0x07, 0x0B, 0x00, 0x83, 0xD0, 0x47, 0x4B, 0xFE, 0x06, 0xFF,
+ 0x84, 0x2F, 0x7D, 0xF8, 0xFF, 0x06, 0x0A, 0x00, 0x83, 0x90, 0x7F, 0xB4, 0xF4, 0x07, 0xFF, 0x84,
+ 0xD2, 0x47, 0xFF, 0xBF, 0x01, 0x09, 0x00, 0x83, 0x90, 0xFF, 0x87, 0x47, 0x07, 0xFF, 0x85, 0x3F,
+ 0xB8, 0xF4, 0xFF, 0xBF, 0x05, 0x08, 0x00, 0x84, 0x95, 0xFF, 0x3F, 0x78, 0xF8, 0x07, 0xFF, 0x81,
+ 0x83, 0x4B, 0x03, 0xFF, 0x81, 0x56, 0x15, 0x04, 0x00, 0x82, 0x50, 0x55, 0xEA, 0x02, 0xFF, 0x81,
+ 0x82, 0x86, 0x07, 0xFF, 0x82, 0x7F, 0xB4, 0xE0, 0x03, 0xFF, 0x81, 0xAF, 0x6A, 0x03, 0x00, 0x81,
+ 0x90, 0xFA, 0x03, 0xFF, 0x82, 0x1F, 0x2D, 0xF8, 0x07, 0xFF, 0x82, 0x0B, 0x19, 0xFE, 0x04, 0xFF,
+ 0x80, 0x6F, 0x02, 0x00, 0x80, 0x40, 0x05, 0xFF, 0x02, 0xD1, 0x08, 0xFF, 0x81, 0x01, 0xE0, 0x05,
+ 0xFF, 0x80, 0x1B, 0x02, 0x00, 0x80, 0xFD, 0x04, 0xFF, 0x82, 0x0B, 0x0A, 0xFE, 0x07, 0xFF, 0x81,
+ 0xBF, 0x41, 0x06, 0xFF, 0x82, 0x02, 0x00, 0xE4, 0x04, 0xFF, 0x82, 0xBF, 0x10, 0xF4, 0x08, 0xFF,
+ 0x80, 0xBF, 0x06, 0xFF, 0x82, 0x7F, 0x00, 0x80, 0x05, 0xFF, 0x81, 0x1F, 0xD0, 0x08, 0xFF, 0x82,
+ 0xBF, 0x56, 0xF9, 0x05, 0xFF, 0x82, 0x1B, 0x00, 0xF9, 0x05, 0xFF, 0x80, 0x9B, 0x08, 0xFF, 0x80,
+ 0x5A, 0x02, 0x00, 0x80, 0xF4, 0x05, 0xFF, 0x81, 0x01, 0x90, 0x05, 0xFF, 0x81, 0xAB, 0x5A, 0x04,
+ 0x55, 0x80, 0xA9, 0x02, 0xAA, 0x84, 0x01, 0x40, 0x55, 0x05, 0xFD, 0x03, 0xFF, 0x84, 0xAA, 0x15,
+ 0x00, 0x94, 0xFA, 0x02, 0xFF, 0x81, 0xBF, 0x56, 0x09, 0x00, 0x87, 0x95, 0xFA, 0xFF, 0x81, 0xFF,
+ 0xAF, 0x6A, 0x15, 0x03, 0x00, 0x86, 0x40, 0xA5, 0xFA, 0xBF, 0x05, 0x50, 0x55, 0x03, 0xAA, 0x80,
+ 0x16, 0x02, 0x00, 0x92, 0x50, 0xE9, 0xFF, 0xBF, 0x2A, 0xA4, 0x56, 0x05, 0x00, 0x54, 0x65, 0x00,
+ 0x59, 0x01, 0x40, 0x55, 0x06, 0xA5, 0xFA, 0x02, 0xFF, 0x92, 0xBF, 0x5A, 0x01, 0x40, 0xA5, 0xFE,
+ 0xFF, 0x5A, 0x15, 0x00, 0x01, 0x00, 0x55, 0xAA, 0xFE, 0x07, 0xE0, 0xAF, 0x56, 0x02, 0x00, 0x80,
+ 0xE8, 0x03, 0xFF, 0x87, 0x6B, 0x05, 0x00, 0x95, 0xFA, 0xFF, 0xBF, 0x15, 0x03, 0x00, 0x81, 0x95,
+ 0xEA, 0x02, 0xFF, 0x86, 0xBF, 0x00, 0xFE, 0xFF, 0xAF, 0x1A, 0xE0, 0x02, 0xFF, 0x84, 0xAF, 0x05,
+ 0x00, 0x94, 0xFA, 0x02, 0xFF, 0x85, 0x6F, 0x01, 0x00, 0x54, 0xAA, 0xFE, 0x04, 0xFF, 0x81, 0x0B,
+ 0xE0, 0x03, 0xFF, 0x80, 0x82, 0x02, 0xFF, 0x83, 0x1B, 0x00, 0x50, 0xFA, 0x03, 0xFF, 0x83, 0x1B,
+ 0x00, 0x94, 0xFE, 0x06, 0xFF, 0x82, 0xBF, 0x00, 0xFE, 0x02, 0xFF, 0x85, 0x1F, 0xFD, 0xBF, 0x05,
+ 0x00, 0xE9, 0x04, 0xFF, 0x82, 0x06, 0x40, 0xFE, 0x08, 0xFF, 0x81, 0x0B, 0xE0, 0x03, 0xFF, 0x84,
+ 0xE1, 0xBF, 0x01, 0x94, 0xFE, 0x04, 0xFF, 0x81, 0x06, 0x90, 0x09, 0xFF, 0x82, 0xBF, 0x00, 0xFD,
+ 0x02, 0xFF, 0x83, 0x1F, 0xFE, 0x01, 0xE5, 0x04, 0xFF, 0x82, 0xBF, 0x06, 0xA4, 0x0A, 0xFF, 0x81,
+ 0x0B, 0xD0, 0x03, 0xFF, 0x82, 0xD1, 0x0B, 0xF9, 0x04, 0xFF, 0x82, 0xBF, 0x05, 0xE5, 0x0A, 0xFF,
+ 0x82, 0xBF, 0x00, 0xFD, 0x02, 0xFF, 0x82, 0x2F, 0x7C, 0xF4, 0x04, 0xFF, 0x82, 0xBF, 0x05, 0xE5,
+ 0x0B, 0xFF, 0x81, 0x07, 0x90, 0x03, 0xFF, 0x81, 0x42, 0x82, 0x04, 0xFF, 0x82, 0xBF, 0x05, 0xE9,
+ 0x0B, 0xFF, 0x82, 0x7F, 0x00, 0xF8, 0x02, 0xFF, 0x82, 0xBF, 0x10, 0xF9, 0x04, 0xFF, 0x81, 0x05,
+ 0xE9, 0x0C, 0xFF, 0x81, 0x06, 0x40, 0x03, 0xFF, 0x81, 0x1F, 0xD0, 0x04, 0xFF, 0x81, 0x06, 0xE0,
+ 0x0C, 0xFF, 0x82, 0x2F, 0x00, 0xF4, 0x03, 0xFF, 0x81, 0x47, 0xFE, 0x03, 0xFF, 0x82, 0x06, 0x00,
+ 0xE4, 0x0C, 0xFF, 0x82, 0x01, 0x00, 0xFE, 0x07, 0xFF, 0x83, 0x06, 0x90, 0x05, 0x90, 0x0B, 0xFF,
+ 0x82, 0x1B, 0x00, 0xD0, 0x07, 0xFF, 0x85, 0x0B, 0x90, 0xFF, 0x16, 0x40, 0xFA, 0x09, 0xFF, 0x80,
+ 0x7F, 0x02, 0x00, 0x80, 0xF9, 0x06, 0xFF, 0x81, 0x1B, 0x94, 0x02, 0xFF, 0x82, 0x5B, 0x00, 0xA5,
+ 0x09, 0xFF, 0x82, 0x02, 0x00, 0x40, 0x06, 0xFF, 0x81, 0x1B, 0xD4, 0x03, 0xFF, 0x83, 0x6F, 0x01,
+ 0x94, 0xFA, 0x07, 0xFF, 0x80, 0x1B, 0x02, 0x00, 0x80, 0xE0, 0x05, 0xFF, 0x81, 0x1B, 0x90, 0x04,
+ 0xFF, 0x84, 0xBF, 0x16, 0x40, 0xA5, 0xFE, 0x05, 0xFF, 0x80, 0x6F, 0x03, 0x00, 0x80, 0xF8, 0x04,
+ 0xFF, 0x81, 0x1B, 0x90, 0x06, 0xFF, 0x84, 0x6A, 0x01, 0x50, 0xA9, 0xFE, 0x03, 0xFF, 0x80, 0x6F,
+ 0x04, 0x00, 0x80, 0xFE, 0x03, 0xFF, 0x81, 0x1B, 0x90, 0x07, 0xFF, 0x84, 0xAF, 0x16, 0x00, 0x50,
+ 0x95, 0x02, 0xAA, 0x80, 0x56, 0x04, 0x00, 0x81, 0x40, 0xFE, 0x02, 0xFF, 0x81, 0x1B, 0x90, 0x09,
+ 0xFF, 0x81, 0xAB, 0x05, 0x09, 0x00, 0x84, 0x40, 0xFA, 0xBF, 0x05, 0x90, 0x0B, 0xFF, 0x81, 0xAF,
+ 0x55, 0x0B, 0x00, 0x80, 0x90, 0x0E, 0xFF, 0x80, 0xBF, 0x08, 0x00, 0x81, 0x40, 0xE5, 0x0F, 0xFF,
+ 0x80, 0x02, 0x07, 0x00, 0x81, 0x90, 0xFE, 0x0F, 0xFF, 0x80, 0x07, 0x08, 0x00, 0x80, 0xF9, 0x0F,
+ 0xFF, 0x80, 0x1F, 0x08, 0x00, 0x80, 0x40, 0x0F, 0xFF, 0x80, 0x7F, 0x09, 0x00, 0x80, 0xD0, 0x0F,
+ 0xFF, 0x80, 0x01, 0x09, 0x00, 0x80, 0xF8, 0x0E, 0xFF, 0x80, 0x0B, 0x0A, 0x00, 0x80, 0xFE, 0x0D,
+ 0xFF, 0x80, 0x2F, 0x0A, 0x00, 0x80, 0xD0, 0x0D, 0xFF, 0x81, 0xBF, 0x01, 0x0A, 0x00, 0x80, 0xF4,
+ 0x0D, 0xFF, 0x80, 0x06, 0x0B, 0x00, 0x80, 0xFD, 0x0C, 0xFF, 0x80, 0x1F, 0x0B, 0x00, 0x80, 0x80,
+ 0x0C, 0xFF, 0x80, 0xBF, 0x0C, 0x00, 0x80, 0xE4, 0x0C, 0xFF, 0x80, 0x02, 0x0C, 0x00, 0x80, 0xFD,
+ 0x0B, 0xFF, 0x80, 0x1F, 0x0C, 0x00, 0x80, 0x80, 0x0B, 0xFF, 0x80, 0xBF, 0x0D, 0x00, 0x80, 0xE0,
+ 0x0B, 0xFF, 0x80, 0x07, 0x0D, 0x00, 0x80, 0xFD, 0x0A, 0xFF, 0x80, 0x1F, 0x0D, 0x00, 0x80, 0x80,
+ 0x0A, 0xFF, 0x80, 0xBF, 0x0E, 0x00, 0x80, 0xE0, 0x0A, 0xFF, 0x80, 0x07, 0x0E, 0x00, 0x80, 0xFD,
+ 0x09, 0xFF, 0x80, 0x2F, 0x0E, 0x00, 0x80, 0x80, 0x0A, 0xFF, 0x80, 0x01, 0x0E, 0x00, 0x80, 0xE0,
+ 0x09, 0xFF, 0x80, 0x0B, 0x0F, 0x00, 0x80, 0xFD, 0x08, 0xFF, 0x80, 0x7F, 0x0F, 0x00, 0x80, 0x80,
+ 0x09, 0xFF, 0x80, 0x02, 0x0F, 0x00, 0x80, 0xF4, 0x08, 0xFF, 0x80, 0x1F, 0x10, 0x00, 0x80, 0xFE,
+ 0x07, 0xFF, 0x80, 0xBF, 0x10, 0x00, 0x80, 0x90, 0x08, 0xFF, 0x80, 0x07, 0x10, 0x00, 0x80, 0xF4,
+ 0x07, 0xFF, 0x80, 0x2F, 0x10, 0x00, 0x81, 0x40, 0xFE, 0x07, 0xFF, 0x80, 0x02, 0x10, 0x00, 0x80,
+ 0xD0, 0x07, 0xFF, 0x80, 0x1F, 0x11, 0x00, 0x80, 0xF8, 0x06, 0xFF, 0x80, 0xBF, 0x11, 0x00, 0x80,
+ 0x80, 0x07, 0xFF, 0x80, 0x07, 0x11, 0x00, 0x80, 0xF4, 0x06, 0xFF, 0x80, 0x3F, 0x12, 0x00, 0x80,
+ 0xFE, 0x06, 0xFF, 0x80, 0x02, 0x11, 0x00, 0x80, 0xD0, 0x06, 0xFF, 0x80, 0x1F, 0x12, 0x00, 0x80,
+ 0xFC, 0x05, 0xFF, 0x80, 0xBF, 0x12, 0x00, 0x80, 0x40, 0x06, 0xFF, 0x80, 0x07, 0x12, 0x00, 0x80,
+ 0xF4, 0x05, 0xFF, 0x80, 0x7F, 0x13, 0x00, 0x80, 0xFE, 0x05, 0xFF, 0x80, 0x02, 0x12, 0x00, 0x80,
+ 0xE0, 0x05, 0xFF, 0x80, 0x2F, 0x13, 0x00, 0x80, 0xFD, 0x05, 0xFF, 0x80, 0x01, 0x12, 0x00, 0x80,
+ 0xD0, 0x05, 0xFF, 0x80, 0x1B, 0x13, 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x80, 0xBF, 0x13, 0x00, 0x80,
+ 0x80, 0x05, 0xFF, 0x80, 0x07, 0x13, 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x80, 0x7F, 0x13, 0x00, 0x80,
+ 0x40, 0x05, 0xFF, 0x80, 0x02, 0x13, 0x00, 0x80, 0xF4, 0x04, 0xFF, 0x80, 0x2F, 0x13, 0x00, 0x80,
+ 0x40, 0x05, 0xFF, 0x80, 0x01, 0x13, 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x80, 0x1B, 0x13, 0x00, 0x80,
+ 0x80, 0x04, 0xFF, 0x80, 0xBF, 0x14, 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x80, 0x07, 0x13, 0x00, 0x80,
+ 0x80, 0x04, 0xFF, 0x80, 0x6F, 0x14, 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x80, 0x02, 0x13, 0x00, 0x80,
+ 0x80, 0x04, 0xFF, 0x80, 0x2F, 0x14, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x01, 0x13, 0x00, 0x80,
+ 0xD0, 0x04, 0xFF, 0x80, 0x0B, 0x14, 0x00, 0x80, 0xFD, 0x03, 0xFF, 0x80, 0x7F, 0x14, 0x00, 0x80,
+ 0xD0, 0x04, 0xFF, 0x80, 0x02, 0x14, 0x00, 0x80, 0xFD, 0x03, 0xFF, 0x80, 0x1F, 0x14, 0x00, 0x80,
+ 0xE0, 0x04, 0xFF, 0x15, 0x00, 0x80, 0xFE, 0x03, 0xFF, 0x80, 0x0B, 0x14, 0x00, 0x80, 0xF0, 0x03,
+ 0xFF, 0x80, 0x7F, 0x15, 0x00, 0x04, 0xFF, 0x80, 0x02, 0x14, 0x00, 0x80, 0xF4, 0x03, 0xFF, 0x80,
+ 0x1F, 0x14, 0x00, 0x80, 0x40, 0x03, 0xFF, 0x80, 0xBF, 0x15, 0x00, 0x80, 0xF8, 0x03, 0xFF, 0x80,
+ 0x07, 0x14, 0x00, 0x80, 0x80, 0x03, 0xFF, 0x80, 0x1F, 0x15, 0x00, 0x80, 0xFC, 0x02, 0xFF, 0x81,
+ 0xBF, 0x01, 0x14, 0x00, 0x80, 0xD0, 0x03, 0xFF, 0x80, 0x07, 0x15, 0x00, 0x80, 0xFD, 0x02, 0xFF,
+ 0x80, 0x2F, 0x15, 0x00, 0x80, 0xE0, 0x02, 0xFF, 0x81, 0xBF, 0x01, 0x15, 0x00, 0x03, 0xFF, 0x80,
+ 0x07, 0x15, 0x00, 0x80, 0xF4, 0x02, 0xFF, 0x80, 0x2F, 0x15, 0x00, 0x80, 0x40, 0x02, 0xFF, 0x80,
+ 0xBF, 0x16, 0x00, 0x80, 0xF8, 0x02, 0xFF, 0x80, 0x07, 0x15, 0x00, 0x80, 0xD0, 0x02, 0xFF, 0x80,
+ 0x1F, 0x16, 0x00, 0x82, 0xFD, 0xFF, 0xBF, 0x16, 0x00, 0x80, 0xE0, 0x02, 0xFF, 0x80, 0x02, 0x15,
+ 0x00, 0x83, 0x40, 0xFE, 0xFF, 0x0B, 0x16, 0x00, 0x82, 0xF4, 0xFF, 0x6F, 0x16, 0x00, 0x83, 0x80,
+ 0xFF, 0xBF, 0x01, 0x16, 0x00, 0x82, 0xFD, 0xFF, 0x06, 0x16, 0x00, 0x82, 0xE0, 0xFF, 0x0B, 0x16,
+ 0x00, 0x82, 0x40, 0xFE, 0x2F, 0x17, 0x00, 0x81, 0xF8, 0xBF, 0x17, 0x00, 0x82, 0x90, 0xBF, 0x01,
+ 0x17, 0x00, 0x81, 0xFE, 0x06, 0x17, 0x00, 0x81, 0xF4, 0x1B, 0x17, 0x00, 0x81, 0x80, 0x1B, 0x18,
+ 0x00, 0x80, 0x2E, 0x18, 0x00, 0x80, 0x24, 0x18, 0x00, 0x80, 0x40, 0x7F, 0x00, 0x61, 0x00, 0x82,
+ 0x40, 0x55, 0x01, 0x04, 0x00, 0x83, 0xA9, 0x01, 0x50, 0x1A, 0x0F, 0x00, 0x82, 0xFD, 0xBF, 0x16,
+ 0x03, 0x00, 0x84, 0xF9, 0xBF, 0x40, 0xFF, 0x1B, 0x0E, 0x00, 0x83, 0xD0, 0xAA, 0xFA, 0x1B, 0x02,
+ 0x00, 0x85, 0xE0, 0x56, 0x1E, 0xB9, 0xE5, 0x06, 0x0E, 0x00, 0x8A, 0x1D, 0x40, 0xE5, 0x0B, 0x00,
+ 0x40, 0x1B, 0xD0, 0xE6, 0x02, 0x78, 0x0E, 0x00, 0x8B, 0xD0, 0x01, 0x00, 0xE5, 0x06, 0x00, 0x74,
+ 0x00, 0x78, 0x1E, 0x40, 0x0B, 0x0E, 0x00, 0x80, 0x1D, 0x02, 0x00, 0x87, 0xB9, 0x00, 0x40, 0x07,
+ 0x80, 0xA7, 0x01, 0xB4, 0x0E, 0x00, 0x8B, 0xD0, 0x01, 0x00, 0x40, 0x2E, 0x00, 0xB4, 0x00, 0x6D,
+ 0x1E, 0x40, 0x0B, 0x0E, 0x00, 0x80, 0x1D, 0x02, 0x00, 0x87, 0x90, 0x07, 0x40, 0x2E, 0xE4, 0xD2,
+ 0x07, 0x7D, 0x0E, 0x00, 0x81, 0xD0, 0x01, 0x02, 0x00, 0x87, 0xB4, 0x00, 0x90, 0xFF, 0x0B, 0xF8,
+ 0xFF, 0x01, 0x0E, 0x00, 0x8A, 0x1D, 0x00, 0x01, 0x00, 0x1E, 0x00, 0xA4, 0x1A, 0x00, 0xA9, 0x06,
+ 0x0E, 0x00, 0x85, 0xD0, 0x01, 0xA0, 0x01, 0xD0, 0x03, 0x14, 0x00, 0x84, 0x1D, 0x00, 0x6E, 0x00,
+ 0x78, 0x14, 0x00, 0x85, 0xD0, 0x01, 0xE0, 0x0B, 0x40, 0x0B, 0x14, 0x00, 0x85, 0x1D, 0x00, 0xFE,
+ 0x01, 0xE0, 0x01, 0x02, 0x55, 0x86, 0x41, 0x55, 0x15, 0x40, 0x06, 0x90, 0x5A, 0x02, 0x00, 0x82,
+ 0x16, 0x50, 0x5A, 0x05, 0x00, 0x94, 0xD0, 0x01, 0xE0, 0x2E, 0x00, 0x2E, 0xE0, 0xFF, 0x2F, 0xF9,
+ 0xFF, 0x06, 0xF8, 0x86, 0xFF, 0x1B, 0x00, 0xF8, 0x46, 0xFE, 0x1B, 0x05, 0x00, 0x94, 0x1D, 0x00,
+ 0xDE, 0x07, 0xD0, 0x02, 0xAE, 0xEA, 0xD2, 0xAA, 0x7E, 0xE0, 0xBA, 0x7E, 0xE5, 0x07, 0xE0, 0xBB,
+ 0xBE, 0xE5, 0x07, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0x79, 0x00, 0x3C, 0xE0, 0x01, 0x2D, 0x1D,
+ 0x80, 0x87, 0x4F, 0xBE, 0x01, 0xB4, 0x41, 0x1F, 0xFE, 0x01, 0xF4, 0x01, 0x04, 0x00, 0x94, 0x1D,
+ 0x00, 0x5E, 0x0B, 0x80, 0x07, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x3E, 0x90, 0x06, 0x00, 0x1E, 0x7D,
+ 0x80, 0x07, 0x00, 0x2D, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xB5, 0x00, 0xB4, 0xE0, 0x01, 0x2D,
+ 0x1D, 0x80, 0xFB, 0x01, 0x14, 0x00, 0xD0, 0xF6, 0x01, 0x14, 0x00, 0x90, 0x03, 0x04, 0x00, 0x94,
+ 0x1D, 0x00, 0x1E, 0x0B, 0x40, 0x0B, 0x1E, 0xD0, 0xD2, 0x01, 0xB8, 0x0B, 0x00, 0x14, 0x00, 0xA9,
+ 0x1F, 0x00, 0x14, 0x00, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xB1, 0x01, 0xB0, 0xE0, 0x01,
+ 0x2D, 0x1D, 0x80, 0xE7, 0x01, 0x90, 0x06, 0x80, 0xE7, 0x02, 0x90, 0x0B, 0x80, 0x07, 0x04, 0x00,
+ 0x94, 0x1D, 0x00, 0x1E, 0x1A, 0x00, 0x1F, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xFB, 0x01,
+ 0x78, 0x2D, 0x40, 0xEE, 0x01, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xE1, 0x01, 0xE0, 0xE1,
+ 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04,
+ 0x00, 0x81, 0x1D, 0x00, 0x02, 0x1E, 0x80, 0x00, 0x02, 0x1E, 0x8D, 0xD0, 0xD2, 0x01, 0x78, 0x2D,
+ 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xE1,
+ 0x01, 0xE0, 0xE1, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D,
+ 0x80, 0x07, 0x04, 0x00, 0x81, 0x1D, 0x00, 0x02, 0x1E, 0x80, 0x00, 0x02, 0x1E, 0x8D, 0xD0, 0xD2,
+ 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0,
+ 0x01, 0xE0, 0xD1, 0x01, 0xD0, 0xE2, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7,
+ 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0x1E, 0x1D, 0x00, 0x2D, 0x1E, 0xD0,
+ 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95,
+ 0xD0, 0x01, 0xE0, 0xD1, 0x01, 0xD0, 0xE2, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80,
+ 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0x1E, 0x1D, 0x00, 0x2D, 0x1E,
+ 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00,
+ 0x95, 0xD0, 0x01, 0xE0, 0xD1, 0x01, 0xD0, 0xE2, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E,
+ 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0x1E, 0x1D, 0x00, 0x2D,
+ 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04,
+ 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xD1, 0x01, 0xD0, 0xE2, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74,
+ 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0x1E, 0x1D, 0x00,
+ 0x1D, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78,
+ 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xD1, 0x01, 0xE0, 0xE1, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02,
+ 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x81, 0x1D, 0x00, 0x02, 0x1E,
+ 0x80, 0x00, 0x02, 0x1E, 0x8D, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40,
+ 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xE1, 0x01, 0xE0, 0xE1, 0x01, 0x2D, 0x1D,
+ 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x81, 0x1D,
+ 0x00, 0x02, 0x1E, 0x80, 0x00, 0x02, 0x1E, 0x8D, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01,
+ 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xE1, 0x01, 0xF0, 0xE1,
+ 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04,
+ 0x00, 0x94, 0x1D, 0x00, 0x1E, 0x1A, 0x00, 0x0B, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7,
+ 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xA1, 0x01, 0xB4,
+ 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07,
+ 0x04, 0x00, 0x94, 0x1D, 0x00, 0x1E, 0x0B, 0x40, 0x0B, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40,
+ 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xB5, 0x00,
+ 0x78, 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80,
+ 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0x5E, 0x0B, 0x80, 0x07, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D,
+ 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0x79,
+ 0x00, 0x3C, 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D,
+ 0x80, 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0xDE, 0x02, 0xD0, 0x02, 0x1E, 0xD0, 0xD2, 0x01, 0x78,
+ 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0,
+ 0x2E, 0x00, 0x1E, 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4,
+ 0x2D, 0x80, 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0xFE, 0x01, 0xE0, 0x00, 0x1E, 0xD0, 0xD2, 0x01,
+ 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01,
+ 0xE0, 0x07, 0x40, 0x0B, 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03,
+ 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0x1E, 0x00, 0x78, 0x00, 0x1E, 0xD0, 0xD2,
+ 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0,
+ 0x01, 0x60, 0x00, 0xD0, 0x02, 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7,
+ 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x80, 0x1D, 0x03, 0x00, 0x90, 0x1E, 0x00, 0x1E, 0xD0,
+ 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x81,
+ 0xD0, 0x01, 0x02, 0x00, 0x91, 0xB4, 0x00, 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E,
+ 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x80, 0x1D, 0x02, 0x00, 0x91, 0xD0, 0x07,
+ 0x00, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78,
+ 0x04, 0x00, 0x95, 0xD0, 0x01, 0x00, 0x40, 0x1F, 0x00, 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02,
+ 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x80, 0x1D, 0x02, 0x00, 0x80,
+ 0x7D, 0x02, 0x00, 0x8E, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40,
+ 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0x40, 0xF9, 0x01, 0x00, 0xE0, 0x01, 0x2D, 0x1D,
+ 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x94, 0x6D,
+ 0x95, 0xFA, 0x06, 0x00, 0x40, 0x1A, 0xD0, 0xD2, 0x56, 0x79, 0x6D, 0x95, 0xE7, 0x56, 0x79, 0x7C,
+ 0x95, 0xDB, 0x56, 0x79, 0x04, 0x00, 0x83, 0xD0, 0xFF, 0xBF, 0x06, 0x02, 0x00, 0x8F, 0xB8, 0x00,
+ 0x2D, 0xFD, 0xFF, 0xD7, 0xFF, 0x7F, 0xFE, 0xFF, 0xC7, 0xFF, 0xBF, 0xFD, 0xFF, 0x07, 0x04, 0x00,
+ 0x02, 0x55, 0x80, 0x05, 0x02, 0x00, 0x8F, 0xE4, 0x07, 0xD0, 0x52, 0x55, 0x15, 0x54, 0x55, 0x51,
+ 0x55, 0x15, 0x54, 0x55, 0x45, 0x55, 0x15, 0x09, 0x00, 0x83, 0x40, 0x1B, 0x00, 0x2D, 0x16, 0x00,
+ 0x83, 0xB4, 0x00, 0xE0, 0x01, 0x15, 0x00, 0x83, 0x40, 0x0B, 0x40, 0x0B, 0x16, 0x00, 0x82, 0xB4,
+ 0x00, 0x7D, 0x16, 0x00, 0x83, 0x40, 0x0B, 0xF5, 0x01, 0x16, 0x00, 0x82, 0xB4, 0xE5, 0x07, 0x16,
+ 0x00, 0x82, 0x40, 0xFF, 0x1B, 0x17, 0x00, 0x81, 0xA4, 0x16, 0x5D, 0x00,
+};
+// clang-format on
diff --git a/keyboards/tzarc/djinn/graphics/djinn.qgf.h b/keyboards/tzarc/djinn/graphics/djinn.qgf.h
new file mode 100644
index 0000000000..59711daffd
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/djinn.qgf.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i djinn.png -f mono4`
+
+#pragma once
+
+#include <qp.h>
+
+extern const uint32_t gfx_djinn_length;
+extern const uint8_t gfx_djinn[3724];
diff --git a/keyboards/tzarc/djinn/graphics/lock-caps-OFF.qgf.c b/keyboards/tzarc/djinn/graphics/lock-caps-OFF.qgf.c
new file mode 100644
index 0000000000..5aef043e3a
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/lock-caps-OFF.qgf.c
@@ -0,0 +1,31 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-caps-OFF.png -f mono4`
+
+#include <qp.h>
+
+const uint32_t gfx_lock_caps_OFF_length = 288;
+
+// clang-format off
+const uint8_t gfx_lock_caps_OFF[288] = {
+ 0x00, 0xFF, 0x12, 0x00, 0x00, 0x51, 0x47, 0x46, 0x01, 0x20, 0x01, 0x00, 0x00, 0xDF, 0xFE, 0xFF,
+ 0xFF, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0xFD, 0x06, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xE8, 0x03, 0x05, 0xFA, 0xF0, 0x00, 0x00,
+ 0x08, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x0F, 0x02, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x3F,
+ 0x02, 0x00, 0x80, 0x3C, 0x04, 0x00, 0x80, 0xFC, 0x02, 0x00, 0x80, 0x3C, 0x04, 0x00, 0x83, 0xF0,
+ 0x03, 0x00, 0x3C, 0x04, 0x00, 0x83, 0xC0, 0x0F, 0x00, 0x3C, 0x05, 0x00, 0x82, 0x3F, 0x00, 0x3C,
+ 0x02, 0x00, 0x85, 0xF0, 0x0F, 0x00, 0xFC, 0x00, 0x3C, 0x02, 0x00, 0x85, 0xF0, 0x0F, 0x00, 0xF0,
+ 0x03, 0x3C, 0x02, 0x00, 0x85, 0xFC, 0x0F, 0x00, 0xC0, 0x0F, 0x3C, 0x02, 0x00, 0x81, 0xFC, 0x3F,
+ 0x02, 0x00, 0x81, 0x3F, 0x3C, 0x02, 0x00, 0x81, 0xFC, 0x3F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00,
+ 0x81, 0xFC, 0x3F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xFC, 0x3F, 0x02, 0x00, 0x02, 0x3C,
+ 0x02, 0x00, 0x02, 0x3F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0x3F, 0xFC, 0x02, 0x00, 0x02,
+ 0x3C, 0x02, 0x00, 0x81, 0x3F, 0xFC, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0x3F, 0xFC, 0x02,
+ 0x00, 0x02, 0x3C, 0x81, 0x00, 0xC0, 0x02, 0xFF, 0x02, 0x00, 0x02, 0x3C, 0x81, 0x00, 0xC0, 0x02,
+ 0xFF, 0x81, 0x03, 0x00, 0x02, 0x3C, 0x81, 0x00, 0xC0, 0x02, 0xFF, 0x81, 0x03, 0x00, 0x02, 0x3C,
+ 0x85, 0x00, 0xC0, 0x0F, 0xF0, 0x03, 0x00, 0x02, 0x3C, 0x85, 0x00, 0xF0, 0x0F, 0xF0, 0x03, 0x00,
+ 0x02, 0x3C, 0x85, 0x00, 0xF0, 0x0F, 0xF0, 0x0F, 0x00, 0x02, 0x3C, 0x85, 0x00, 0xF0, 0x03, 0xF0,
+ 0x0F, 0x00, 0x02, 0x3C, 0x06, 0x00, 0x02, 0x3C, 0x06, 0x00, 0x02, 0x3C, 0x06, 0x00, 0x02, 0x3C,
+ 0x06, 0x00, 0x81, 0x3C, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x80, 0x3F, 0x08, 0x00,
+};
+// clang-format on
diff --git a/keyboards/tzarc/djinn/graphics/lock-caps-OFF.qgf.h b/keyboards/tzarc/djinn/graphics/lock-caps-OFF.qgf.h
new file mode 100644
index 0000000000..9d79762833
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/lock-caps-OFF.qgf.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-caps-OFF.png -f mono4`
+
+#pragma once
+
+#include <qp.h>
+
+extern const uint32_t gfx_lock_caps_OFF_length;
+extern const uint8_t gfx_lock_caps_OFF[288];
diff --git a/keyboards/tzarc/djinn/graphics/lock-caps-ON.qgf.c b/keyboards/tzarc/djinn/graphics/lock-caps-ON.qgf.c
new file mode 100644
index 0000000000..9da36cb446
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/lock-caps-ON.qgf.c
@@ -0,0 +1,32 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-caps-ON.png -f mono4`
+
+#include <qp.h>
+
+const uint32_t gfx_lock_caps_ON_length = 291;
+
+// clang-format off
+const uint8_t gfx_lock_caps_ON[291] = {
+ 0x00, 0xFF, 0x12, 0x00, 0x00, 0x51, 0x47, 0x46, 0x01, 0x23, 0x01, 0x00, 0x00, 0xDC, 0xFE, 0xFF,
+ 0xFF, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0xFD, 0x06, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xE8, 0x03, 0x05, 0xFA, 0xF3, 0x00, 0x00,
+ 0x08, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x0F, 0x02, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x3F,
+ 0x02, 0x00, 0x80, 0xFC, 0x05, 0xFF, 0x02, 0x00, 0x80, 0xFC, 0x05, 0xFF, 0x82, 0x03, 0x00, 0xFC,
+ 0x05, 0xFF, 0x82, 0x0F, 0x00, 0xFC, 0x05, 0xFF, 0x82, 0x3F, 0x00, 0xFC, 0x02, 0xFF, 0x81, 0x0F,
+ 0xF0, 0x02, 0xFF, 0x81, 0x00, 0xFC, 0x02, 0xFF, 0x81, 0x0F, 0xF0, 0x02, 0xFF, 0x81, 0x03, 0xFC,
+ 0x02, 0xFF, 0x81, 0x03, 0xF0, 0x02, 0xFF, 0x81, 0x0F, 0xFC, 0x02, 0xFF, 0x81, 0x03, 0xC0, 0x02,
+ 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x03, 0xC0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF,
+ 0x81, 0x03, 0xC0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x03, 0xC0, 0x02, 0xFF, 0x81,
+ 0x3F, 0xFC, 0x02, 0xFF, 0x02, 0xC0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0xC0, 0x03,
+ 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0xC0, 0x03, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02,
+ 0xFF, 0x81, 0xC0, 0x03, 0x02, 0xFF, 0x83, 0x3F, 0xFC, 0xFF, 0x3F, 0x02, 0x00, 0x02, 0xFF, 0x83,
+ 0x3F, 0xFC, 0xFF, 0x3F, 0x02, 0x00, 0x85, 0xFC, 0xFF, 0x3F, 0xFC, 0xFF, 0x3F, 0x02, 0x00, 0xA3,
+ 0xFC, 0xFF, 0x3F, 0xFC, 0xFF, 0x3F, 0xF0, 0x0F, 0xFC, 0xFF, 0x3F, 0xFC, 0xFF, 0x0F, 0xF0, 0x0F,
+ 0xFC, 0xFF, 0x3F, 0xFC, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x3F, 0xFC, 0xFF, 0x0F, 0xFC, 0x0F,
+ 0xF0, 0xFF, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF,
+ 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x80,
+ 0x3F, 0x08, 0x00,
+};
+// clang-format on
diff --git a/keyboards/tzarc/djinn/graphics/lock-caps-ON.qgf.h b/keyboards/tzarc/djinn/graphics/lock-caps-ON.qgf.h
new file mode 100644
index 0000000000..a7d60a6195
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/lock-caps-ON.qgf.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-caps-ON.png -f mono4`
+
+#pragma once
+
+#include <qp.h>
+
+extern const uint32_t gfx_lock_caps_ON_length;
+extern const uint8_t gfx_lock_caps_ON[291];
diff --git a/keyboards/tzarc/djinn/graphics/lock-num-OFF.qgf.c b/keyboards/tzarc/djinn/graphics/lock-num-OFF.qgf.c
new file mode 100644
index 0000000000..2dd7dbef73
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/lock-num-OFF.qgf.c
@@ -0,0 +1,31 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-num-OFF.png -f mono4`
+
+#include <qp.h>
+
+const uint32_t gfx_lock_num_OFF_length = 286;
+
+// clang-format off
+const uint8_t gfx_lock_num_OFF[286] = {
+ 0x00, 0xFF, 0x12, 0x00, 0x00, 0x51, 0x47, 0x46, 0x01, 0x1E, 0x01, 0x00, 0x00, 0xE1, 0xFE, 0xFF,
+ 0xFF, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0xFD, 0x06, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xE8, 0x03, 0x05, 0xFA, 0xEE, 0x00, 0x00,
+ 0x08, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x0F, 0x02, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x3F,
+ 0x02, 0x00, 0x80, 0x3C, 0x04, 0x00, 0x80, 0xFC, 0x02, 0x00, 0x80, 0x3C, 0x04, 0x00, 0x83, 0xF0,
+ 0x03, 0x00, 0x3C, 0x04, 0x00, 0x83, 0xC0, 0x0F, 0x00, 0x3C, 0x05, 0x00, 0x82, 0x3F, 0x00, 0x3C,
+ 0x02, 0x00, 0x85, 0xF0, 0x0F, 0x00, 0xFC, 0x00, 0x3C, 0x02, 0x00, 0x85, 0xFC, 0x0F, 0x00, 0xF0,
+ 0x03, 0x3C, 0x02, 0x00, 0x89, 0xFF, 0x0F, 0x00, 0xC0, 0x0F, 0x3C, 0x00, 0xC0, 0xFF, 0x0F, 0x02,
+ 0x00, 0x81, 0x3F, 0x3C, 0x02, 0x00, 0x81, 0xCF, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81,
+ 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02,
+ 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02,
+ 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02,
+ 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0,
+ 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00,
+ 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C,
+ 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00,
+ 0x02, 0x3C, 0x06, 0x00, 0x02, 0x3C, 0x06, 0x00, 0x02, 0x3C, 0x06, 0x00, 0x02, 0x3C, 0x06, 0x00,
+ 0x81, 0x3C, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x80, 0x3F, 0x08, 0x00,
+};
+// clang-format on
diff --git a/keyboards/tzarc/djinn/graphics/lock-num-OFF.qgf.h b/keyboards/tzarc/djinn/graphics/lock-num-OFF.qgf.h
new file mode 100644
index 0000000000..c0b24bffbd
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/lock-num-OFF.qgf.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-num-OFF.png -f mono4`
+
+#pragma once
+
+#include <qp.h>
+
+extern const uint32_t gfx_lock_num_OFF_length;
+extern const uint8_t gfx_lock_num_OFF[286];
diff --git a/keyboards/tzarc/djinn/graphics/lock-num-ON.qgf.c b/keyboards/tzarc/djinn/graphics/lock-num-ON.qgf.c
new file mode 100644
index 0000000000..803dc6b19a
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/lock-num-ON.qgf.c
@@ -0,0 +1,32 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-num-ON.png -f mono4`
+
+#include <qp.h>
+
+const uint32_t gfx_lock_num_ON_length = 302;
+
+// clang-format off
+const uint8_t gfx_lock_num_ON[302] = {
+ 0x00, 0xFF, 0x12, 0x00, 0x00, 0x51, 0x47, 0x46, 0x01, 0x2E, 0x01, 0x00, 0x00, 0xD1, 0xFE, 0xFF,
+ 0xFF, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0xFD, 0x06, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xE8, 0x03, 0x05, 0xFA, 0xFE, 0x00, 0x00,
+ 0x08, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x0F, 0x02, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x3F,
+ 0x02, 0x00, 0x80, 0xFC, 0x05, 0xFF, 0x02, 0x00, 0x80, 0xFC, 0x05, 0xFF, 0x82, 0x03, 0x00, 0xFC,
+ 0x05, 0xFF, 0x82, 0x0F, 0x00, 0xFC, 0x05, 0xFF, 0x82, 0x3F, 0x00, 0xFC, 0x02, 0xFF, 0x81, 0x0F,
+ 0xF0, 0x02, 0xFF, 0x81, 0x00, 0xFC, 0x02, 0xFF, 0x81, 0x03, 0xF0, 0x02, 0xFF, 0x81, 0x03, 0xFC,
+ 0x02, 0xFF, 0x81, 0x00, 0xF0, 0x02, 0xFF, 0x85, 0x0F, 0xFC, 0xFF, 0x3F, 0x00, 0xF0, 0x02, 0xFF,
+ 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x30, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81,
+ 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F,
+ 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0,
+ 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02,
+ 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF,
+ 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81,
+ 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F,
+ 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0,
+ 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x06,
+ 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF,
+ 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x80, 0x3F, 0x08, 0x00,
+};
+// clang-format on
diff --git a/keyboards/tzarc/djinn/graphics/lock-num-ON.qgf.h b/keyboards/tzarc/djinn/graphics/lock-num-ON.qgf.h
new file mode 100644
index 0000000000..d714e88828
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/lock-num-ON.qgf.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-num-ON.png -f mono4`
+
+#pragma once
+
+#include <qp.h>
+
+extern const uint32_t gfx_lock_num_ON_length;
+extern const uint8_t gfx_lock_num_ON[302];
diff --git a/keyboards/tzarc/djinn/graphics/lock-scrl-OFF.qgf.c b/keyboards/tzarc/djinn/graphics/lock-scrl-OFF.qgf.c
new file mode 100644
index 0000000000..c31e4619ef
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/lock-scrl-OFF.qgf.c
@@ -0,0 +1,32 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-scrl-OFF.png -f mono4`
+
+#include <qp.h>
+
+const uint32_t gfx_lock_scrl_OFF_length = 292;
+
+// clang-format off
+const uint8_t gfx_lock_scrl_OFF[292] = {
+ 0x00, 0xFF, 0x12, 0x00, 0x00, 0x51, 0x47, 0x46, 0x01, 0x24, 0x01, 0x00, 0x00, 0xDB, 0xFE, 0xFF,
+ 0xFF, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0xFD, 0x06, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xE8, 0x03, 0x05, 0xFA, 0xF4, 0x00, 0x00,
+ 0x08, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x0F, 0x02, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x3F,
+ 0x02, 0x00, 0x80, 0x3C, 0x04, 0x00, 0x80, 0xFC, 0x02, 0x00, 0x80, 0x3C, 0x04, 0x00, 0x83, 0xF0,
+ 0x03, 0x00, 0x3C, 0x04, 0x00, 0x83, 0xC0, 0x0F, 0x00, 0x3C, 0x05, 0x00, 0x82, 0x3F, 0x00, 0x3C,
+ 0x05, 0x00, 0x82, 0xFC, 0x00, 0x3C, 0x02, 0x00, 0x85, 0xC0, 0x03, 0x00, 0xF0, 0x03, 0x3C, 0x02,
+ 0x00, 0x85, 0xC0, 0x03, 0x00, 0xC0, 0x0F, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x03, 0x02, 0x00, 0x81,
+ 0x3F, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x03, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x03,
+ 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x03, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81,
+ 0xC0, 0x03, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x03, 0x02, 0x00, 0x02, 0x3C, 0x02,
+ 0x00, 0x81, 0xC0, 0x03, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x03, 0x02, 0x00, 0x02,
+ 0x3C, 0x80, 0x00, 0x02, 0xC0, 0x02, 0x03, 0x80, 0x00, 0x02, 0x3C, 0x81, 0x00, 0xF0, 0x02, 0xC3,
+ 0x81, 0x0F, 0x00, 0x02, 0x3C, 0x85, 0x00, 0xC0, 0xCF, 0xF3, 0x03, 0x00, 0x02, 0x3C, 0x02, 0x00,
+ 0x02, 0xFF, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xFC, 0x3F, 0x02, 0x00, 0x02, 0x3C, 0x02,
+ 0x00, 0x81, 0xF0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x81, 0x00, 0xF0, 0x02, 0xFF, 0x81, 0x0F, 0x00,
+ 0x02, 0x3C, 0x81, 0x00, 0xF0, 0x02, 0xFF, 0x81, 0x0F, 0x00, 0x02, 0x3C, 0x06, 0x00, 0x02, 0x3C,
+ 0x06, 0x00, 0x02, 0x3C, 0x06, 0x00, 0x81, 0x3C, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF,
+ 0x80, 0x3F, 0x08, 0x00,
+};
+// clang-format on
diff --git a/keyboards/tzarc/djinn/graphics/lock-scrl-OFF.qgf.h b/keyboards/tzarc/djinn/graphics/lock-scrl-OFF.qgf.h
new file mode 100644
index 0000000000..95e5f633cb
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/lock-scrl-OFF.qgf.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-scrl-OFF.png -f mono4`
+
+#pragma once
+
+#include <qp.h>
+
+extern const uint32_t gfx_lock_scrl_OFF_length;
+extern const uint8_t gfx_lock_scrl_OFF[292];
diff --git a/keyboards/tzarc/djinn/graphics/lock-scrl-ON.qgf.c b/keyboards/tzarc/djinn/graphics/lock-scrl-ON.qgf.c
new file mode 100644
index 0000000000..f1cc86493a
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/lock-scrl-ON.qgf.c
@@ -0,0 +1,32 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-scrl-ON.png -f mono4`
+
+#include <qp.h>
+
+const uint32_t gfx_lock_scrl_ON_length = 296;
+
+// clang-format off
+const uint8_t gfx_lock_scrl_ON[296] = {
+ 0x00, 0xFF, 0x12, 0x00, 0x00, 0x51, 0x47, 0x46, 0x01, 0x28, 0x01, 0x00, 0x00, 0xD7, 0xFE, 0xFF,
+ 0xFF, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0xFD, 0x06, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xE8, 0x03, 0x05, 0xFA, 0xF8, 0x00, 0x00,
+ 0x08, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x0F, 0x02, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x3F,
+ 0x02, 0x00, 0x80, 0xFC, 0x05, 0xFF, 0x02, 0x00, 0x80, 0xFC, 0x05, 0xFF, 0x82, 0x03, 0x00, 0xFC,
+ 0x05, 0xFF, 0x82, 0x0F, 0x00, 0xFC, 0x05, 0xFF, 0x82, 0x3F, 0x00, 0xFC, 0x06, 0xFF, 0x81, 0x00,
+ 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x03, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC,
+ 0x02, 0xFF, 0x81, 0x0F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02,
+ 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF,
+ 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81,
+ 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F,
+ 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC,
+ 0x02, 0xFF, 0x82, 0x3F, 0xFC, 0xFF, 0x02, 0x3F, 0x02, 0xFC, 0x84, 0xFF, 0x3F, 0xFC, 0xFF, 0x0F,
+ 0x02, 0x3C, 0x8B, 0xF0, 0xFF, 0x3F, 0xFC, 0xFF, 0x3F, 0x30, 0x0C, 0xFC, 0xFF, 0x3F, 0xFC, 0x02,
+ 0xFF, 0x02, 0x00, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x03, 0xC0, 0x02, 0xFF, 0x81,
+ 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x0F, 0xF0, 0x02, 0xFF, 0x83, 0x3F, 0xFC, 0xFF, 0x0F, 0x02, 0x00,
+ 0x85, 0xF0, 0xFF, 0x3F, 0xFC, 0xFF, 0x0F, 0x02, 0x00, 0x83, 0xF0, 0xFF, 0x3F, 0xFC, 0x06, 0xFF,
+ 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81,
+ 0x3F, 0xFC, 0x06, 0xFF, 0x80, 0x3F, 0x08, 0x00,
+};
+// clang-format on
diff --git a/keyboards/tzarc/djinn/graphics/lock-scrl-ON.qgf.h b/keyboards/tzarc/djinn/graphics/lock-scrl-ON.qgf.h
new file mode 100644
index 0000000000..f8ee67c002
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/lock-scrl-ON.qgf.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-scrl-ON.png -f mono4`
+
+#pragma once
+
+#include <qp.h>
+
+extern const uint32_t gfx_lock_scrl_ON_length;
+extern const uint8_t gfx_lock_scrl_ON[296];
diff --git a/keyboards/tzarc/djinn/graphics/theme_djinn_default.c b/keyboards/tzarc/djinn/graphics/theme_djinn_default.c
new file mode 100644
index 0000000000..616a3c2430
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/theme_djinn_default.c
@@ -0,0 +1,307 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include QMK_KEYBOARD_H
+#include <hal.h>
+#include <string.h>
+#include <ctype.h>
+#include <printf.h>
+#include "qp.h"
+#include "backlight.h"
+#include "transactions.h"
+#include "split_util.h"
+
+#include "djinn.h"
+#include "theme_djinn_default.h"
+
+#include "djinn.qgf.h"
+#include "lock-caps-ON.qgf.h"
+#include "lock-scrl-ON.qgf.h"
+#include "lock-num-ON.qgf.h"
+#include "lock-caps-OFF.qgf.h"
+#include "lock-scrl-OFF.qgf.h"
+#include "lock-num-OFF.qgf.h"
+#include "thintel15.qff.h"
+
+static painter_image_handle_t djinn_logo;
+static painter_image_handle_t lock_caps_on;
+static painter_image_handle_t lock_caps_off;
+static painter_image_handle_t lock_num_on;
+static painter_image_handle_t lock_num_off;
+static painter_image_handle_t lock_scrl_on;
+static painter_image_handle_t lock_scrl_off;
+static painter_font_handle_t thintel;
+
+//----------------------------------------------------------
+// RGB Matrix naming
+#if defined(RGB_MATRIX_ENABLE)
+# include <rgb_matrix.h>
+
+# if defined(RGB_MATRIX_EFFECT)
+# undef RGB_MATRIX_EFFECT
+# endif // defined(RGB_MATRIX_EFFECT)
+
+# define RGB_MATRIX_EFFECT(x) RGB_MATRIX_EFFECT_##x,
+enum {
+ RGB_MATRIX_EFFECT_NONE,
+# include "rgb_matrix_effects.inc"
+# undef RGB_MATRIX_EFFECT
+# ifdef RGB_MATRIX_CUSTOM_KB
+# include "rgb_matrix_kb.inc"
+# endif
+# ifdef RGB_MATRIX_CUSTOM_USER
+# include "rgb_matrix_user.inc"
+# endif
+};
+
+# define RGB_MATRIX_EFFECT(x) \
+ case RGB_MATRIX_EFFECT_##x: \
+ return #x;
+const char *rgb_matrix_name(uint8_t effect) {
+ switch (effect) {
+ case RGB_MATRIX_EFFECT_NONE:
+ return "NONE";
+# include "rgb_matrix_effects.inc"
+# undef RGB_MATRIX_EFFECT
+# ifdef RGB_MATRIX_CUSTOM_KB
+# include "rgb_matrix_kb.inc"
+# endif
+# ifdef RGB_MATRIX_CUSTOM_USER
+# include "rgb_matrix_user.inc"
+# endif
+ default:
+ return "UNKNOWN";
+ }
+}
+#endif // defined(RGB_MATRIX_ENABLE)
+
+//----------------------------------------------------------
+// UI Initialisation
+void keyboard_post_init_display(void) {
+ djinn_logo = qp_load_image_mem(gfx_djinn);
+ lock_caps_on = qp_load_image_mem(gfx_lock_caps_ON);
+ lock_caps_off = qp_load_image_mem(gfx_lock_caps_OFF);
+ lock_num_on = qp_load_image_mem(gfx_lock_num_ON);
+ lock_num_off = qp_load_image_mem(gfx_lock_num_OFF);
+ lock_scrl_on = qp_load_image_mem(gfx_lock_scrl_ON);
+ lock_scrl_off = qp_load_image_mem(gfx_lock_scrl_OFF);
+ thintel = qp_load_font_mem(font_thintel15);
+}
+
+//----------------------------------------------------------
+// UI Drawing
+void draw_ui_user(void) {
+ bool hue_redraw = false;
+ static uint16_t last_hue = 0xFFFF;
+#if defined(RGB_MATRIX_ENABLE)
+ uint16_t curr_hue = rgb_matrix_get_hue();
+#else // defined(RGB_MATRIX_ENABLE)
+ uint16_t curr_hue = 0;
+#endif // defined(RGB_MATRIX_ENABLE)
+ if (last_hue != curr_hue) {
+ last_hue = curr_hue;
+ hue_redraw = true;
+ }
+
+ bool layer_state_redraw = false;
+ static uint32_t last_layer_state = 0;
+ if (last_layer_state != layer_state) {
+ last_layer_state = layer_state;
+ layer_state_redraw = true;
+ }
+
+ bool power_state_redraw = false;
+ static usbpd_allowance_t last_current_state = (usbpd_allowance_t)(~0);
+ if (last_current_state != kb_state.current_setting) {
+ last_current_state = kb_state.current_setting;
+ power_state_redraw = true;
+ }
+
+ bool scan_redraw = false;
+ static uint32_t last_scan_update = 0;
+ if (timer_elapsed32(last_scan_update) > 125) {
+ last_scan_update = timer_read32();
+ scan_redraw = true;
+ }
+
+ bool wpm_redraw = false;
+ static uint32_t last_wpm_update = 0;
+ if (timer_elapsed32(last_wpm_update) > 125) {
+ last_wpm_update = timer_read32();
+ wpm_redraw = true;
+ }
+
+#if defined(RGB_MATRIX_ENABLE)
+ bool rgb_effect_redraw = false;
+ static uint16_t last_effect = 0xFFFF;
+ uint8_t curr_effect = rgb_matrix_config.mode;
+ if (last_effect != curr_effect) {
+ last_effect = curr_effect;
+ rgb_effect_redraw = true;
+ }
+#endif // defined(RGB_MATRIX_ENABLE)
+
+ // Show the Djinn logo and two vertical bars on both sides
+ if (hue_redraw) {
+ qp_drawimage_recolor(lcd, 120 - djinn_logo->width / 2, 32, djinn_logo, curr_hue, 255, 255, curr_hue, 255, 0);
+ qp_rect(lcd, 0, 0, 8, 319, curr_hue, 255, 255, true);
+ qp_rect(lcd, 231, 0, 239, 319, curr_hue, 255, 255, true);
+ }
+
+ int ypos = 4;
+
+ // Show layer info on the left side
+ if (is_keyboard_left()) {
+ char buf[64] = {0};
+ int xpos = 16;
+
+#if defined(RGB_MATRIX_ENABLE)
+ if (hue_redraw || rgb_effect_redraw) {
+ static int max_rgb_xpos = 0;
+ xpos = 16;
+ snprintf_(buf, sizeof(buf), "rgb: %s", rgb_matrix_name(curr_effect));
+
+ for (int i = 5; i < sizeof(buf); ++i) {
+ if (buf[i] == 0)
+ break;
+ else if (buf[i] == '_')
+ buf[i] = ' ';
+ else if (buf[i - 1] == ' ')
+ buf[i] = toupper(buf[i]);
+ else if (buf[i - 1] != ' ')
+ buf[i] = tolower(buf[i]);
+ }
+
+ xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
+ if (max_rgb_xpos < xpos) {
+ max_rgb_xpos = xpos;
+ }
+ qp_rect(lcd, xpos, ypos, max_rgb_xpos, ypos + thintel->line_height, 0, 0, 0, true);
+ }
+
+ ypos += thintel->line_height + 4;
+#endif // defined(RGB_MATRIX_ENABLE)
+
+ if (hue_redraw || layer_state_redraw) {
+ extern const char *current_layer_name(void);
+ const char *layer_name = current_layer_name();
+
+ static int max_layer_xpos = 0;
+ xpos = 16;
+ snprintf_(buf, sizeof(buf), "layer: %s", layer_name);
+ xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
+ if (max_layer_xpos < xpos) {
+ max_layer_xpos = xpos;
+ }
+ qp_rect(lcd, xpos, ypos, max_layer_xpos, ypos + thintel->line_height, 0, 0, 0, true);
+ }
+
+ ypos += thintel->line_height + 4;
+
+ if (hue_redraw || power_state_redraw) {
+ static int max_power_xpos = 0;
+ xpos = 16;
+ snprintf_(buf, sizeof(buf), "power: %s", usbpd_str(kb_state.current_setting));
+ xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
+ if (max_power_xpos < xpos) {
+ max_power_xpos = xpos;
+ }
+ qp_rect(lcd, xpos, ypos, max_power_xpos, ypos + thintel->line_height, 0, 0, 0, true);
+ }
+
+ ypos += thintel->line_height + 4;
+
+ if (hue_redraw || scan_redraw) {
+ static int max_scans_xpos = 0;
+ xpos = 16;
+ snprintf_(buf, sizeof(buf), "scans: %d", (int)theme_state.scan_rate);
+ xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
+ if (max_scans_xpos < xpos) {
+ max_scans_xpos = xpos;
+ }
+ qp_rect(lcd, xpos, ypos, max_scans_xpos, ypos + thintel->line_height, 0, 0, 0, true);
+ }
+
+ ypos += thintel->line_height + 4;
+
+ if (hue_redraw || wpm_redraw) {
+ static int max_wpm_xpos = 0;
+ xpos = 16;
+ snprintf_(buf, sizeof(buf), "wpm: %d", (int)get_current_wpm());
+ xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
+ if (max_wpm_xpos < xpos) {
+ max_wpm_xpos = xpos;
+ }
+ qp_rect(lcd, xpos, ypos, max_wpm_xpos, ypos + thintel->line_height, 0, 0, 0, true);
+ }
+
+ ypos += thintel->line_height + 4;
+ }
+
+ // Show LED lock indicators on the right side
+ if (!is_keyboard_left()) {
+ static led_t last_led_state = {0};
+ if (hue_redraw || last_led_state.raw != host_keyboard_led_state().raw) {
+ last_led_state.raw = host_keyboard_led_state().raw;
+ qp_drawimage_recolor(lcd, 239 - 12 - (32 * 3), 0, last_led_state.caps_lock ? lock_caps_on : lock_caps_off, curr_hue, 255, last_led_state.caps_lock ? 255 : 32, curr_hue, 255, 0);
+ qp_drawimage_recolor(lcd, 239 - 12 - (32 * 2), 0, last_led_state.num_lock ? lock_num_on : lock_num_off, curr_hue, 255, last_led_state.num_lock ? 255 : 32, curr_hue, 255, 0);
+ qp_drawimage_recolor(lcd, 239 - 12 - (32 * 1), 0, last_led_state.scroll_lock ? lock_scrl_on : lock_scrl_off, curr_hue, 255, last_led_state.scroll_lock ? 255 : 32, curr_hue, 255, 0);
+ }
+ }
+}
+
+//----------------------------------------------------------
+// Sync
+
+theme_runtime_config theme_state;
+
+void rpc_theme_sync_callback(uint8_t m2s_size, const void *m2s_buffer, uint8_t s2m_size, void *s2m_buffer) {
+ if (m2s_size == sizeof(theme_state)) {
+ memcpy(&theme_state, m2s_buffer, m2s_size);
+ }
+}
+
+void theme_init(void) {
+ // Register keyboard state sync split transaction
+ transaction_register_rpc(THEME_DATA_SYNC, rpc_theme_sync_callback);
+
+ // Reset the initial shared data value between master and slave
+ memset(&theme_state, 0, sizeof(theme_state));
+}
+
+void theme_state_update(void) {
+ if (is_keyboard_master()) {
+ // Keep the scan rate in sync
+ theme_state.scan_rate = get_matrix_scan_rate();
+ }
+}
+
+void theme_state_sync(void) {
+ if (!is_transport_connected()) return;
+
+ if (is_keyboard_master()) {
+ // Keep track of the last state, so that we can tell if we need to propagate to slave
+ static theme_runtime_config last_theme_state;
+ static uint32_t last_sync;
+ bool needs_sync = false;
+
+ // Check if the state values are different
+ if (memcmp(&theme_state, &last_theme_state, sizeof(theme_runtime_config))) {
+ needs_sync = true;
+ memcpy(&last_theme_state, &theme_state, sizeof(theme_runtime_config));
+ }
+
+ // Send to slave every 125ms regardless of state change
+ if (timer_elapsed32(last_sync) > 125) {
+ needs_sync = true;
+ }
+
+ // Perform the sync if requested
+ if (needs_sync) {
+ if (transaction_rpc_send(THEME_DATA_SYNC, sizeof(theme_runtime_config), &theme_state)) {
+ last_sync = timer_read32();
+ } else {
+ dprint("Failed to perform rpc call\n");
+ }
+ }
+ }
+}
diff --git a/keyboards/tzarc/djinn/graphics/theme_djinn_default.h b/keyboards/tzarc/djinn/graphics/theme_djinn_default.h
new file mode 100644
index 0000000000..4f3927e469
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/theme_djinn_default.h
@@ -0,0 +1,19 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+//----------------------------------------------------------
+// Sync
+
+#pragma pack(push)
+#pragma pack(1)
+typedef struct theme_runtime_config {
+ uint32_t scan_rate;
+} theme_runtime_config;
+#pragma pack(pop)
+
+extern theme_runtime_config theme_state;
+
+void theme_init(void);
+void theme_state_update(void);
+void theme_state_sync(void);
diff --git a/keyboards/tzarc/djinn/graphics/thintel15.qff.c b/keyboards/tzarc/djinn/graphics/thintel15.qff.c
new file mode 100644
index 0000000000..237f2e9e5f
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/thintel15.qff.c
@@ -0,0 +1,74 @@
+// Copyright 2022 QMK -- generated source code only, font retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-font-image -i thintel15.png -f mono2`
+
+#include <qp.h>
+
+const uint32_t font_thintel15_length = 966;
+
+// clang-format off
+const uint8_t font_thintel15[966] = {
+ 0x00, 0xFF, 0x14, 0x00, 0x00, 0x51, 0x46, 0x46, 0x01, 0xC6, 0x03, 0x00, 0x00, 0x39, 0xFC, 0xFF,
+ 0xFF, 0x0B, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x01, 0xFE, 0x1D, 0x01, 0x00, 0x02, 0x00,
+ 0x00, 0xC2, 0x00, 0x00, 0x84, 0x01, 0x00, 0x06, 0x03, 0x00, 0x46, 0x05, 0x00, 0x88, 0x07, 0x00,
+ 0x46, 0x0A, 0x00, 0x82, 0x0C, 0x00, 0x43, 0x0D, 0x00, 0x83, 0x0E, 0x00, 0xC4, 0x0F, 0x00, 0x46,
+ 0x11, 0x00, 0x83, 0x13, 0x00, 0xC5, 0x14, 0x00, 0x82, 0x16, 0x00, 0x44, 0x17, 0x00, 0xC5, 0x18,
+ 0x00, 0x84, 0x1A, 0x00, 0x05, 0x1C, 0x00, 0xC5, 0x1D, 0x00, 0x85, 0x1F, 0x00, 0x45, 0x21, 0x00,
+ 0x05, 0x23, 0x00, 0xC5, 0x24, 0x00, 0x85, 0x26, 0x00, 0x45, 0x28, 0x00, 0x02, 0x2A, 0x00, 0xC3,
+ 0x2A, 0x00, 0x05, 0x2C, 0x00, 0xC5, 0x2D, 0x00, 0x85, 0x2F, 0x00, 0x45, 0x31, 0x00, 0x08, 0x33,
+ 0x00, 0xC5, 0x35, 0x00, 0x85, 0x37, 0x00, 0x45, 0x39, 0x00, 0x05, 0x3B, 0x00, 0xC4, 0x3C, 0x00,
+ 0x44, 0x3E, 0x00, 0xC5, 0x3F, 0x00, 0x85, 0x41, 0x00, 0x44, 0x43, 0x00, 0xC5, 0x44, 0x00, 0x85,
+ 0x46, 0x00, 0x44, 0x48, 0x00, 0xC6, 0x49, 0x00, 0x06, 0x4C, 0x00, 0x45, 0x4E, 0x00, 0x05, 0x50,
+ 0x00, 0xC5, 0x51, 0x00, 0x85, 0x53, 0x00, 0x45, 0x55, 0x00, 0x06, 0x57, 0x00, 0x45, 0x59, 0x00,
+ 0x06, 0x5B, 0x00, 0x46, 0x5D, 0x00, 0x86, 0x5F, 0x00, 0xC6, 0x61, 0x00, 0x06, 0x64, 0x00, 0x44,
+ 0x66, 0x00, 0xC4, 0x67, 0x00, 0x44, 0x69, 0x00, 0xC6, 0x6A, 0x00, 0x05, 0x6D, 0x00, 0xC3, 0x6E,
+ 0x00, 0x05, 0x70, 0x00, 0xC5, 0x71, 0x00, 0x84, 0x73, 0x00, 0x05, 0x75, 0x00, 0xC5, 0x76, 0x00,
+ 0x84, 0x78, 0x00, 0x05, 0x7A, 0x00, 0xC5, 0x7B, 0x00, 0x82, 0x7D, 0x00, 0x43, 0x7E, 0x00, 0x85,
+ 0x7F, 0x00, 0x42, 0x81, 0x00, 0x06, 0x82, 0x00, 0x45, 0x84, 0x00, 0x05, 0x86, 0x00, 0xC5, 0x87,
+ 0x00, 0x85, 0x89, 0x00, 0x44, 0x8B, 0x00, 0xC5, 0x8C, 0x00, 0x83, 0x8E, 0x00, 0xC5, 0x8F, 0x00,
+ 0x86, 0x91, 0x00, 0xC6, 0x93, 0x00, 0x06, 0x96, 0x00, 0x45, 0x98, 0x00, 0x04, 0x9A, 0x00, 0x85,
+ 0x9B, 0x00, 0x42, 0x9D, 0x00, 0x05, 0x9E, 0x00, 0xC5, 0x9F, 0x00, 0x04, 0xFB, 0x86, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x54, 0x45, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xFD, 0xD2,
+ 0xAF, 0x28, 0x00, 0x00, 0x00, 0x84, 0x53, 0x15, 0x0E, 0x55, 0x39, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x12, 0x15, 0x0A, 0x28, 0x54, 0x24, 0x00, 0x00, 0x00, 0x80, 0x50, 0x14, 0x52, 0x95, 0x58, 0x00,
+ 0x00, 0x00, 0x14, 0x00, 0x00, 0x4A, 0x92, 0x24, 0x02, 0x00, 0x91, 0x24, 0x49, 0x01, 0x00, 0x20,
+ 0x27, 0x05, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x1F, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x60, 0x0A, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x24, 0x22,
+ 0x11, 0x00, 0x00, 0xC0, 0xA4, 0x94, 0x52, 0x32, 0x00, 0x00, 0x20, 0x23, 0x22, 0x72, 0x00, 0x00,
+ 0xC0, 0x24, 0x44, 0x44, 0x78, 0x00, 0x00, 0xC0, 0x24, 0x44, 0x50, 0x32, 0x00, 0x00, 0x80, 0x29,
+ 0x95, 0x1E, 0x42, 0x00, 0x00, 0xE0, 0x85, 0x83, 0x50, 0x32, 0x00, 0x00, 0xC0, 0xA4, 0x70, 0x52,
+ 0x32, 0x00, 0x00, 0xE0, 0x21, 0x42, 0x84, 0x10, 0x00, 0x00, 0xC0, 0xA4, 0x64, 0x52, 0x32, 0x00,
+ 0x00, 0xC0, 0xA4, 0xE4, 0x50, 0x32, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x30, 0x60, 0x0A, 0x00,
+ 0x00, 0x11, 0x11, 0x04, 0x41, 0x00, 0x00, 0x00, 0x80, 0x07, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x08,
+ 0x82, 0x88, 0x08, 0x00, 0x00, 0xC0, 0x24, 0x64, 0x04, 0x10, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x59,
+ 0x55, 0x2D, 0x02, 0x1C, 0x00, 0x00, 0x00, 0xC0, 0xA4, 0xF4, 0x52, 0x4A, 0x00, 0x00, 0xE0, 0xA4,
+ 0x74, 0x52, 0x3A, 0x00, 0x00, 0xC0, 0xA4, 0x10, 0x42, 0x32, 0x00, 0x00, 0xE0, 0xA4, 0x94, 0x52,
+ 0x3A, 0x00, 0x00, 0x70, 0x11, 0x17, 0x71, 0x00, 0x00, 0x70, 0x11, 0x17, 0x11, 0x00, 0x00, 0xC0,
+ 0xA4, 0xD0, 0x52, 0x32, 0x00, 0x00, 0x20, 0xA5, 0xF4, 0x52, 0x4A, 0x00, 0x00, 0x70, 0x22, 0x22,
+ 0x72, 0x00, 0x00, 0xC0, 0x21, 0x84, 0x50, 0x32, 0x00, 0x00, 0x20, 0xA5, 0x32, 0x4A, 0x4A, 0x00,
+ 0x00, 0x10, 0x11, 0x11, 0x71, 0x00, 0x00, 0x40, 0xB4, 0x55, 0x51, 0x14, 0x45, 0x00, 0x00, 0x00,
+ 0x40, 0x34, 0x55, 0x59, 0x14, 0x45, 0x00, 0x00, 0x00, 0xC0, 0xA4, 0x94, 0x52, 0x32, 0x00, 0x00,
+ 0xE0, 0xA4, 0x74, 0x42, 0x08, 0x00, 0x00, 0xC0, 0xA4, 0x94, 0x52, 0x51, 0x00, 0x00, 0xE0, 0xA4,
+ 0x74, 0x52, 0x4A, 0x00, 0x00, 0xC0, 0xA4, 0x60, 0x50, 0x32, 0x00, 0x00, 0xC0, 0x47, 0x10, 0x04,
+ 0x41, 0x10, 0x00, 0x00, 0x00, 0x20, 0xA5, 0x94, 0x52, 0x32, 0x00, 0x00, 0x40, 0x14, 0x45, 0x51,
+ 0xA4, 0x10, 0x00, 0x00, 0x00, 0x40, 0x14, 0x45, 0x51, 0xB5, 0x45, 0x00, 0x00, 0x00, 0x40, 0x14,
+ 0x29, 0x84, 0x12, 0x45, 0x00, 0x00, 0x00, 0x40, 0x14, 0x45, 0x0E, 0x41, 0x10, 0x00, 0x00, 0x00,
+ 0xC0, 0x07, 0x21, 0x84, 0x10, 0x7C, 0x00, 0x00, 0x00, 0x17, 0x11, 0x11, 0x11, 0x07, 0x00, 0x10,
+ 0x21, 0x22, 0x44, 0x00, 0x00, 0x47, 0x44, 0x44, 0x44, 0x07, 0x00, 0x84, 0x12, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x93, 0x5C, 0x72, 0x00, 0x00, 0x20, 0x84, 0x93, 0x52, 0x3A, 0x00, 0x00, 0x00, 0x60,
+ 0x11, 0x61, 0x00, 0x00, 0x00, 0x21, 0x97, 0x52, 0x72, 0x00, 0x00, 0x00, 0x00, 0x93, 0x5E, 0x70,
+ 0x00, 0x00, 0x60, 0x11, 0x13, 0x11, 0x00, 0x00, 0x00, 0x00, 0x97, 0x52, 0x72, 0x28, 0x19, 0x20,
+ 0x84, 0x93, 0x52, 0x4A, 0x00, 0x00, 0x10, 0x55, 0x00, 0x80, 0x20, 0x49, 0x0A, 0x00, 0x20, 0x84,
+ 0x94, 0x4E, 0x4A, 0x00, 0x00, 0x54, 0x55, 0x00, 0x00, 0x00, 0x2C, 0x55, 0x55, 0x55, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x93, 0x52, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x93, 0x52, 0x32, 0x00, 0x00, 0x00,
+ 0x80, 0x93, 0x52, 0x3A, 0x21, 0x00, 0x00, 0x00, 0x97, 0x52, 0x72, 0x08, 0x01, 0x00, 0x50, 0x13,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x17, 0x0C, 0x3A, 0x00, 0x00, 0x48, 0x96, 0x44, 0x00, 0x00, 0x00,
+ 0x80, 0x94, 0x52, 0x72, 0x00, 0x00, 0x00, 0x00, 0x44, 0x51, 0xA4, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x44, 0x51, 0x54, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x0A, 0xA1, 0x44, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x94, 0x52, 0x72, 0x28, 0x19, 0x00, 0x70, 0x24, 0x71, 0x00, 0x00, 0x4C, 0x08,
+ 0x11, 0x84, 0x10, 0x0C, 0x00, 0x55, 0x55, 0x01, 0x83, 0x10, 0x82, 0x08, 0x21, 0x03, 0x00, 0x00,
+ 0x00, 0xB0, 0x1A, 0x00, 0x00, 0x00,
+};
+// clang-format on
diff --git a/keyboards/tzarc/djinn/graphics/thintel15.qff.h b/keyboards/tzarc/djinn/graphics/thintel15.qff.h
new file mode 100644
index 0000000000..8e64bb45f3
--- /dev/null
+++ b/keyboards/tzarc/djinn/graphics/thintel15.qff.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, font retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-font-image -i thintel15.png -f mono2`
+
+#pragma once
+
+#include <qp.h>
+
+extern const uint32_t font_thintel15_length;
+extern const uint8_t font_thintel15[966];
diff --git a/keyboards/tzarc/djinn/halconf.h b/keyboards/tzarc/djinn/halconf.h
new file mode 100644
index 0000000000..ae3576cec0
--- /dev/null
+++ b/keyboards/tzarc/djinn/halconf.h
@@ -0,0 +1,14 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+#define HAL_USE_GPT TRUE
+#define HAL_USE_PWM TRUE
+#define HAL_USE_SPI TRUE
+#define HAL_USE_SERIAL TRUE
+#define SERIAL_BUFFERS_SIZE 256
+
+// This enables interrupt-driven mode
+#define PAL_USE_WAIT TRUE
+
+#include_next <halconf.h>
diff --git a/keyboards/tzarc/djinn/info.json b/keyboards/tzarc/djinn/info.json
new file mode 100644
index 0000000000..959663a6d6
--- /dev/null
+++ b/keyboards/tzarc/djinn/info.json
@@ -0,0 +1,140 @@
+{
+ "keyboard_name": "Djinn",
+ "manufacturer": "Tzarc",
+ "maintainer": "tzarc",
+ "url": "https://github.com/tzarc/djinn",
+ "processor": "STM32G474",
+ "bootloader": "stm32-dfu",
+ "bootloader_instructions": "Press the physical RESET button on the top of the board, or hold the top-left key when plugging in the board.",
+ "build": {
+ "lto": true
+ },
+ "debounce": 5,
+ "features": {
+ "audio": true,
+ "backlight": true,
+ "bootmagic": true,
+ "console": true,
+ "encoder": true,
+ "mousekey": true,
+ "extrakey": true,
+ "nkro": true,
+ "quantum_painter": true,
+ "rgb_matrix": true,
+ "unicode": false,
+ "usbpd": true,
+ "wpm": true
+ },
+ "matrix_pins": {
+ "custom_lite": true,
+ "rows": ["B13", "B14", "B15", "C6", "C7", "C8"],
+ "cols": ["C0", "C1", "C2", "C3", "A0", "A1", "A2"]
+ },
+ "backlight": {
+ "pin": "A7"
+ },
+ "split": {
+ "enabled": true,
+ "main": "pin"
+ },
+ "layouts": {
+ "LAYOUT_all": {
+ "layout": [
+ { "matrix": [0, 0], "label": "Esc", "x": 0, "y": 0.88 },
+ { "matrix": [0, 1], "label": "1", "x": 1, "y": 0.63 },
+ { "matrix": [0, 2], "label": "2", "x": 2, "y": 0.38 },
+ { "matrix": [0, 3], "label": "3", "x": 3, "y": 0 },
+ { "matrix": [0, 4], "label": "4", "x": 4, "y": 0.13 },
+ { "matrix": [0, 5], "label": "5", "x": 5, "y": 0.5 },
+ { "matrix": [0, 6], "label": "~", "x": 6, "y": 1 },
+
+ { "matrix": [6, 6], "label": "Del", "x": 12, "y": 1 },
+ { "matrix": [6, 5], "label": "6", "x": 13, "y": 0.5 },
+ { "matrix": [6, 4], "label": "7", "x": 14, "y": 0.13 },
+ { "matrix": [6, 3], "label": "8", "x": 15, "y": 0 },
+ { "matrix": [6, 2], "label": "9", "x": 16, "y": 0.38 },
+ { "matrix": [6, 1], "label": "0", "x": 17, "y": 0.63 },
+ { "matrix": [6, 0], "label": "Bksp", "x": 18, "y": 0.88 },
+
+ { "matrix": [1, 0], "label": "Tab", "x": 0, "y": 1.88 },
+ { "matrix": [1, 1], "label": "Q", "x": 1, "y": 1.63 },
+ { "matrix": [1, 2], "label": "W", "x": 2, "y": 1.38 },
+ { "matrix": [1, 3], "label": "E", "x": 3, "y": 1 },
+ { "matrix": [1, 4], "label": "R", "x": 4, "y": 1.13 },
+ { "matrix": [1, 5], "label": "T", "x": 5, "y": 1.5 },
+ { "matrix": [1, 6], "label": "[", "x": 6, "y": 2 },
+
+ { "matrix": [7, 6], "label": "]", "x": 12, "y": 2 },
+ { "matrix": [7, 5], "label": "Y", "x": 13, "y": 1.5 },
+ { "matrix": [7, 4], "label": "U", "x": 14, "y": 1.13 },
+ { "matrix": [7, 3], "label": "I", "x": 15, "y": 1 },
+ { "matrix": [7, 2], "label": "O", "x": 16, "y": 1.38 },
+ { "matrix": [7, 1], "label": "P", "x": 17, "y": 1.63 },
+ { "matrix": [7, 0], "label": "\\", "x": 18, "y": 1.88 },
+
+ { "matrix": [2, 0], "label": "Ctrl", "x": 0, "y": 2.88 },
+ { "matrix": [2, 1], "label": "A", "x": 1, "y": 2.63 },
+ { "matrix": [2, 2], "label": "S", "x": 2, "y": 2.38 },
+ { "matrix": [2, 3], "label": "D", "x": 3, "y": 2 },
+ { "matrix": [2, 4], "label": "F", "x": 4, "y": 2.13 },
+ { "matrix": [2, 5], "label": "G", "x": 5, "y": 2.5 },
+ { "matrix": [2, 6], "label": "Home", "x": 6, "y": 3 },
+
+ { "matrix": [8, 6], "label": "PgUp", "x": 12, "y": 3 },
+ { "matrix": [8, 5], "label": "H", "x": 13, "y": 2.5 },
+ { "matrix": [8, 4], "label": "J", "x": 14, "y": 2.13 },
+ { "matrix": [8, 3], "label": "K", "x": 15, "y": 2 },
+ { "matrix": [8, 2], "label": "L", "x": 16, "y": 2.38 },
+ { "matrix": [8, 1], "label": ";", "x": 17, "y": 2.63 },
+ { "matrix": [8, 0], "label": "\"", "x": 18, "y": 2.88 },
+
+ { "matrix": [3, 0], "label": "Shift", "x": 0, "y": 3.88 },
+ { "matrix": [3, 1], "label": "Z", "x": 1, "y": 3.63 },
+ { "matrix": [3, 2], "label": "X", "x": 2, "y": 3.38 },
+ { "matrix": [3, 3], "label": "C", "x": 3, "y": 3 },
+ { "matrix": [3, 4], "label": "V", "x": 4, "y": 3.13 },
+ { "matrix": [3, 5], "label": "B", "x": 5, "y": 3.5 },
+ { "matrix": [3, 6], "label": "End", "x": 6, "y": 4 },
+
+ { "matrix": [9, 6], "label": "PgDn", "x": 12, "y": 4 },
+ { "matrix": [9, 5], "label": "N", "x": 13, "y": 3.5 },
+ { "matrix": [9, 4], "label": "M", "x": 14, "y": 3.13 },
+ { "matrix": [9, 3], "label": ",", "x": 15, "y": 3 },
+ { "matrix": [9, 2], "label": ".", "x": 16, "y": 3.38 },
+ { "matrix": [9, 1], "label": "/", "x": 17, "y": 3.63 },
+ { "matrix": [9, 0], "label": "Shift", "x": 18, "y": 3.88 },
+
+ { "matrix": [4, 3], "label": "GUI", "x": 2.5, "y": 4.9 },
+ { "matrix": [4, 4], "label": "Lower", "x": 3.5, "y": 4.9 },
+ { "matrix": [4, 5], "label": "Space", "x": 4.5, "y": 5.06 },
+ { "matrix": [4, 6], "label": " ", "x": 5.5, "y": 5.4 },
+
+ { "matrix": [10, 6], "label": " ", "x": 12.5, "y": 5.4 },
+ { "matrix": [10, 5], "label": "Space", "x": 13.5, "y": 5.06 },
+ { "matrix": [10, 4], "label": "Raise", "x": 14.5, "y": 4.88 },
+ { "matrix": [10, 3], "label": "Alt", "x": 15.5, "y": 4.9 },
+
+ { "matrix": [5, 6], "label": "RGB", "x": 7.25, "y": 4.9 },
+ { "matrix": [11, 6], "label": "RGB", "x": 10.75, "y": 4.9 },
+
+ { "matrix": [5, 1], "label": "Up", "x": 4.5, "y": 7 },
+ { "matrix": [11, 1], "label": "Up", "x": 13.5, "y": 7 },
+
+ { "matrix": [5, 2], "label": "Left", "x": 3.5, "y": 8 },
+ { "matrix": [5, 5], "label": "Press", "x": 4.5, "y": 8 },
+ { "matrix": [5, 4], "label": "Right", "x": 5.5, "y": 8 },
+
+ { "matrix": [11, 2], "label": "Left", "x": 12.5, "y": 8 },
+ { "matrix": [11, 5], "label": "Press", "x": 13.5, "y": 8 },
+ { "matrix": [11, 4], "label": "Right", "x": 14.5, "y": 8 },
+
+ { "matrix": [5, 3], "label": "Down", "x": 4.5, "y": 9 },
+ { "matrix": [11, 3], "label": "Down", "x": 13.5, "y": 9 }
+ ]
+ }
+ },
+ "usb": {
+ "vid": "0x1209",
+ "pid": "0x4919"
+ }
+}
diff --git a/keyboards/tzarc/djinn/keymaps/default/config.h b/keyboards/tzarc/djinn/keymaps/default/config.h
new file mode 100644
index 0000000000..87e3e11665
--- /dev/null
+++ b/keyboards/tzarc/djinn/keymaps/default/config.h
@@ -0,0 +1,60 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+// Encoder settings
+#define ENCODER_RESOLUTION 2
+
+// LCD blanking period
+#define LCD_ACTIVITY_TIMEOUT 30000
+
+// RGB settings
+#define RGB_MATRIX_KEYPRESSES
+#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
+
+// Allow for an extra sync command over the split
+#define SPLIT_TRANSACTION_IDS_USER THEME_DATA_SYNC
+
+// RGB 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_FRACTAL
+#define ENABLE_RGB_MATRIX_PIXEL_RAIN
+#define ENABLE_RGB_MATRIX_TYPING_HEATMAP
+#define ENABLE_RGB_MATRIX_DIGITAL_RAIN
+#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 \ No newline at end of file
diff --git a/keyboards/tzarc/djinn/keymaps/default/keymap.c b/keyboards/tzarc/djinn/keymaps/default/keymap.c
new file mode 100644
index 0000000000..32a53e27b8
--- /dev/null
+++ b/keyboards/tzarc/djinn/keymaps/default/keymap.c
@@ -0,0 +1,107 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include QMK_KEYBOARD_H
+#include "theme_djinn_default.h"
+
+// Layer definitions
+enum { _QWERTY, _LOWER, _RAISE, _ADJUST };
+
+//----------------------------------------------------------
+// Key map
+
+// clang-format off
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [_QWERTY] = LAYOUT_all(
+ KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_GRV, KC_DEL, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC,
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_LBRC, KC_RBRC, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSLS,
+ KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G, KC_HOME, KC_PGUP, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT,
+ KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_END, KC_PGDN, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT,
+ KC_LGUI, MO(_LOWER),KC_SPC, KC_NO, KC_NO, KC_SPC, MO(_RAISE),KC_LALT,
+ RGB_RMOD, RGB_MOD,
+ KC_UP, KC_UP,
+ KC_LEFT, _______, KC_RIGHT, KC_LEFT, _______, KC_RIGHT,
+ KC_DOWN, KC_DOWN
+ ),
+ [_LOWER] = LAYOUT_all(
+ KC_F12, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, _______, _______, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11,
+ _______, _______, KC_UP, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, KC_LEFT, KC_DOWN, KC_RIGHT,_______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______,
+ BL_DEC, BL_INC,
+ _______, _______,
+ _______, _______, _______, _______, _______, _______,
+ _______, _______
+ ),
+ [_RAISE] = LAYOUT_all(
+ KC_F12, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, _______, _______, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11,
+ _______,_______, KC_UP, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______,KC_LEFT, KC_DOWN, KC_RIGHT,_______, KC_UNDS, KC_NO, KC_NO, KC_EQL, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, KC_MINS, KC_NO, KC_NO, KC_PLUS, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______,
+ _______, _______,
+ _______, _______, _______, _______, _______, _______,
+ _______, _______
+ ),
+ [_ADJUST] = LAYOUT_all(
+ _______, KC_CLCK, KC_NLCK, KC_SLCK, _______, _______, _______, _______, _______, _______, _______, DEBUG, EEP_RST, QK_BOOT,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______,
+ _______, _______,
+ _______, _______, _______, _______, _______, _______,
+ _______, _______
+ )
+};
+// clang-format on
+
+//----------------------------------------------------------
+// Encoder map
+
+// clang-format off
+const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
+ [_QWERTY] = { ENCODER_CCW_CW(KC_MS_WH_UP, KC_MS_WH_DOWN), ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
+ [_LOWER] = { ENCODER_CCW_CW(RGB_HUD, RGB_HUI), ENCODER_CCW_CW(RGB_SAD, RGB_SAI) },
+ [_RAISE] = { ENCODER_CCW_CW(RGB_VAD, RGB_VAI), ENCODER_CCW_CW(RGB_SPD, RGB_SPI) },
+ [_ADJUST] = { ENCODER_CCW_CW(RGB_RMOD, RGB_MOD), ENCODER_CCW_CW(KC_LEFT, KC_RIGHT) },
+};
+// clang-format on
+
+//----------------------------------------------------------
+// Layer naming
+
+const char *current_layer_name(void) {
+ switch (get_highest_layer(layer_state)) {
+ case _QWERTY:
+ return "qwerty";
+ case _LOWER:
+ return "lower";
+ case _RAISE:
+ return "raise";
+ case _ADJUST:
+ return "adjust";
+ }
+ return "unknown";
+}
+
+//----------------------------------------------------------
+// Overrides
+
+void keyboard_post_init_user(void) {
+ // Initialise the theme
+ theme_init();
+
+ void keyboard_post_init_display(void);
+ keyboard_post_init_display();
+}
+
+void housekeeping_task_user(void) {
+ // Update kb_state so we can send to slave
+ theme_state_update();
+
+ // Data sync from master to slave
+ theme_state_sync();
+}
diff --git a/keyboards/tzarc/djinn/keymaps/default/rules.mk b/keyboards/tzarc/djinn/keymaps/default/rules.mk
new file mode 100644
index 0000000000..dbeb87a16c
--- /dev/null
+++ b/keyboards/tzarc/djinn/keymaps/default/rules.mk
@@ -0,0 +1,15 @@
+DEBUG_MATRIX_SCAN_RATE_ENABLE ?= api
+ENCODER_MAP_ENABLE = yes
+SWAP_HANDS_ENABLE = no
+
+VPATH += keyboards/tzarc/djinn/graphics
+SRC += \
+ theme_djinn_default.c \
+ djinn.qgf.c \
+ lock-caps-ON.qgf.c \
+ lock-scrl-ON.qgf.c \
+ lock-num-ON.qgf.c \
+ lock-caps-OFF.qgf.c \
+ lock-scrl-OFF.qgf.c \
+ lock-num-OFF.qgf.c \
+ thintel15.qff.c
diff --git a/keyboards/tzarc/djinn/mcuconf.h b/keyboards/tzarc/djinn/mcuconf.h
new file mode 100644
index 0000000000..f3a7fbfb16
--- /dev/null
+++ b/keyboards/tzarc/djinn/mcuconf.h
@@ -0,0 +1,30 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+#include_next <mcuconf.h>
+
+// Used for audio
+#undef STM32_PWM_USE_TIM1
+#undef STM32_GPT_USE_TIM6
+#undef STM32_GPT_USE_TIM7
+#undef STM32_GPT_USE_TIM8
+#define STM32_PWM_USE_TIM1 TRUE
+#define STM32_GPT_USE_TIM6 TRUE
+#define STM32_GPT_USE_TIM7 TRUE
+#define STM32_GPT_USE_TIM8 TRUE
+
+// Used for backlight
+#undef STM32_PWM_USE_TIM17
+#define STM32_PWM_USE_TIM17 TRUE
+
+// Used for SK6812 chain
+#undef STM32_PWM_USE_TIM20
+#define STM32_PWM_USE_TIM20 TRUE
+
+// Used for split comms
+#undef STM32_SERIAL_USE_USART3
+#define STM32_SERIAL_USE_USART3 TRUE
+
+// Used for EEPROM/LCD
+#undef STM32_SPI_USE_SPI3
+#define STM32_SPI_USE_SPI3 TRUE
diff --git a/keyboards/tzarc/djinn/readme.md b/keyboards/tzarc/djinn/readme.md
new file mode 100644
index 0000000000..5cb9e9339c
--- /dev/null
+++ b/keyboards/tzarc/djinn/readme.md
@@ -0,0 +1,27 @@
+# Djinn
+
+![Djinn](https://i.imgur.com/ArSjkv8.jpg)
+
+The Djinn is a 64-key split keyboard -- dual 4x7 with a 4-key thumb cluster and encoders. It also has a 5-way tactile switch under the thumb. Oh, and two displays.
+
+Keyboard Maintainer: [tzarc](https://github.com/tzarc)
+Hardware Supported: Djinn: rev1, rev2
+Hardware Availability: [Open-source](https://github.com/tzarc/djinn)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make tzarc/djinn/rev2:default
+
+Flashing example for this keyboard:
+
+ make tzarc/djinn/rev2: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).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+* **Bootmagic reset**: Hold down the top-left key and plug in the keyboard.
+* **Physical reset button**: Briefly press the button on the back of the PCB.
+* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available.
diff --git a/keyboards/tzarc/djinn/rev1/config.h b/keyboards/tzarc/djinn/rev1/config.h
new file mode 100644
index 0000000000..14cdaf2fdb
--- /dev/null
+++ b/keyboards/tzarc/djinn/rev1/config.h
@@ -0,0 +1,35 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+// Limit the backlight brightness
+#ifndef BACKLIGHT_LIMIT_VAL
+# define BACKLIGHT_LIMIT_VAL 144
+#endif // BACKLIGHT_LIMIT_VAL
+
+// Split configuration
+#define SPLIT_HAND_PIN B11
+#ifdef USE_PLUG_DETECT_PIN
+# define USB_VBUS_PIN B12
+#endif
+#define SERIAL_USART_DRIVER SD3
+#define SERIAL_USART_TX_PAL_MODE 7
+#define SOFT_SERIAL_PIN B9
+#ifndef SERIAL_USART_SPEED
+# define SERIAL_USART_SPEED 640000
+#endif // SERIAL_USART_SPEED
+
+// RGB configuration
+#define RGBLED_NUM 84
+#define DRIVER_LED_TOTAL 84
+#define RGB_MATRIX_SPLIT \
+ { 42, 42 }
+#define RGB_POWER_ENABLE_PIN B1
+#define RGB_CURR_1500mA_OK_PIN B0
+#define RGB_CURR_3000mA_OK_PIN C5
+
+// EEPROM configuration
+#define EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN B5
+#define EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR 8 // (160MHz/8) => 20MHz
+#define EXTERNAL_EEPROM_BYTE_COUNT 8192
+#define EXTERNAL_EEPROM_PAGE_SIZE 64 // it's FRAM, so it doesn't actually matter, this just sets the RAM buffer size
diff --git a/keyboards/tzarc/djinn/rev1/info.json b/keyboards/tzarc/djinn/rev1/info.json
new file mode 100644
index 0000000000..73ddbe9e41
--- /dev/null
+++ b/keyboards/tzarc/djinn/rev1/info.json
@@ -0,0 +1,98 @@
+{
+ "usb": {
+ "device_version": "1.0.0"
+ },
+ "split": {
+ "usb_detect": {
+ "enabled": true
+ }
+ },
+ "rgb_matrix": {
+ "layout": [
+ { "flags": 2, "x": 110, "y": 30 },
+ { "flags": 2, "x": 110, "y": 80 },
+ { "flags": 2, "x": 110, "y": 130 },
+ { "flags": 2, "x": 95, "y": 180 },
+ { "flags": 2, "x": 75, "y": 195 },
+ { "flags": 2, "x": 60, "y": 210 },
+ { "flags": 2, "x": 45, "y": 190 },
+ { "flags": 2, "x": 35, "y": 175 },
+ { "flags": 2, "x": 20, "y": 160 },
+ { "flags": 2, "x": 5, "y": 160 },
+ { "flags": 4, "matrix": [4, 3], "x": 78, "y": 150 },
+ { "flags": 4, "matrix": [4, 4], "x": 104, "y": 150 },
+ { "flags": 4, "matrix": [4, 5], "x": 130, "y": 150 },
+ { "flags": 4, "matrix": [4, 6], "x": 156, "y": 150 },
+ { "flags": 4, "matrix": [3, 6], "x": 156, "y": 120 },
+ { "flags": 4, "matrix": [3, 5], "x": 130, "y": 120 },
+ { "flags": 4, "matrix": [3, 4], "x": 104, "y": 120 },
+ { "flags": 4, "matrix": [3, 3], "x": 78, "y": 120 },
+ { "flags": 4, "matrix": [3, 2], "x": 52, "y": 120 },
+ { "flags": 4, "matrix": [3, 1], "x": 26, "y": 120 },
+ { "flags": 4, "matrix": [3, 0], "x": 0, "y": 120 },
+ { "flags": 4, "matrix": [2, 0], "x": 0, "y": 90 },
+ { "flags": 4, "matrix": [2, 1], "x": 26, "y": 90 },
+ { "flags": 4, "matrix": [2, 2], "x": 52, "y": 90 },
+ { "flags": 4, "matrix": [2, 3], "x": 78, "y": 90 },
+ { "flags": 4, "matrix": [2, 4], "x": 104, "y": 90 },
+ { "flags": 4, "matrix": [2, 5], "x": 130, "y": 90 },
+ { "flags": 4, "matrix": [2, 6], "x": 156, "y": 90 },
+ { "flags": 4, "matrix": [1, 6], "x": 156, "y": 60 },
+ { "flags": 4, "matrix": [1, 5], "x": 130, "y": 60 },
+ { "flags": 4, "matrix": [1, 4], "x": 104, "y": 60 },
+ { "flags": 4, "matrix": [1, 3], "x": 78, "y": 60 },
+ { "flags": 4, "matrix": [1, 2], "x": 52, "y": 60 },
+ { "flags": 4, "matrix": [1, 1], "x": 26, "y": 60 },
+ { "flags": 4, "matrix": [1, 0], "x": 0, "y": 60 },
+ { "flags": 4, "matrix": [0, 0], "x": 0, "y": 30 },
+ { "flags": 4, "matrix": [0, 1], "x": 26, "y": 30 },
+ { "flags": 4, "matrix": [0, 2], "x": 52, "y": 30 },
+ { "flags": 4, "matrix": [0, 3], "x": 78, "y": 30 },
+ { "flags": 4, "matrix": [0, 4], "x": 104, "y": 30 },
+ { "flags": 4, "matrix": [0, 5], "x": 130, "y": 30 },
+ { "flags": 4, "matrix": [0, 6], "x": 156, "y": 30 },
+ { "flags": 2, "x": 114, "y": 30 },
+ { "flags": 2, "x": 114, "y": 80 },
+ { "flags": 2, "x": 114, "y": 130 },
+ { "flags": 2, "x": 129, "y": 180 },
+ { "flags": 2, "x": 149, "y": 195 },
+ { "flags": 2, "x": 164, "y": 210 },
+ { "flags": 2, "x": 179, "y": 190 },
+ { "flags": 2, "x": 189, "y": 175 },
+ { "flags": 2, "x": 204, "y": 160 },
+ { "flags": 2, "x": 219, "y": 160 },
+ { "flags": 4, "matrix": [10, 3], "x": 146, "y": 150 },
+ { "flags": 4, "matrix": [10, 4], "x": 120, "y": 150 },
+ { "flags": 4, "matrix": [10, 5], "x": 94, "y": 150 },
+ { "flags": 4, "matrix": [10, 6], "x": 68, "y": 150 },
+ { "flags": 4, "matrix": [9, 6], "x": 68, "y": 120 },
+ { "flags": 4, "matrix": [9, 5], "x": 94, "y": 120 },
+ { "flags": 4, "matrix": [9, 4], "x": 120, "y": 120 },
+ { "flags": 4, "matrix": [9, 3], "x": 146, "y": 120 },
+ { "flags": 4, "matrix": [9, 2], "x": 172, "y": 120 },
+ { "flags": 4, "matrix": [9, 1], "x": 198, "y": 120 },
+ { "flags": 4, "matrix": [9, 0], "x": 224, "y": 120 },
+ { "flags": 4, "matrix": [8, 0], "x": 224, "y": 90 },
+ { "flags": 4, "matrix": [8, 1], "x": 198, "y": 90 },
+ { "flags": 4, "matrix": [8, 2], "x": 172, "y": 90 },
+ { "flags": 4, "matrix": [8, 3], "x": 146, "y": 90 },
+ { "flags": 4, "matrix": [8, 4], "x": 120, "y": 90 },
+ { "flags": 4, "matrix": [8, 5], "x": 94, "y": 90 },
+ { "flags": 4, "matrix": [8, 6], "x": 68, "y": 90 },
+ { "flags": 4, "matrix": [7, 6], "x": 68, "y": 60 },
+ { "flags": 4, "matrix": [7, 5], "x": 94, "y": 60 },
+ { "flags": 4, "matrix": [7, 4], "x": 120, "y": 60 },
+ { "flags": 4, "matrix": [7, 3], "x": 146, "y": 60 },
+ { "flags": 4, "matrix": [7, 2], "x": 172, "y": 60 },
+ { "flags": 4, "matrix": [7, 1], "x": 198, "y": 60 },
+ { "flags": 4, "matrix": [7, 0], "x": 224, "y": 60 },
+ { "flags": 4, "matrix": [6, 0], "x": 224, "y": 30 },
+ { "flags": 4, "matrix": [6, 1], "x": 198, "y": 30 },
+ { "flags": 4, "matrix": [6, 2], "x": 172, "y": 30 },
+ { "flags": 4, "matrix": [6, 3], "x": 146, "y": 30 },
+ { "flags": 4, "matrix": [6, 4], "x": 120, "y": 30 },
+ { "flags": 4, "matrix": [6, 5], "x": 94, "y": 30 },
+ { "flags": 4, "matrix": [6, 6], "x": 68, "y": 30 }
+ ]
+ }
+}
diff --git a/keyboards/tzarc/djinn/rev1/rev1.c b/keyboards/tzarc/djinn/rev1/rev1.c
new file mode 100644
index 0000000000..95f0e20020
--- /dev/null
+++ b/keyboards/tzarc/djinn/rev1/rev1.c
@@ -0,0 +1,3 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include "rev1.h"
diff --git a/keyboards/tzarc/djinn/rev1/rev1.h b/keyboards/tzarc/djinn/rev1/rev1.h
new file mode 100644
index 0000000000..1845cb8fdd
--- /dev/null
+++ b/keyboards/tzarc/djinn/rev1/rev1.h
@@ -0,0 +1,3 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
diff --git a/keyboards/tzarc/djinn/rev1/rules.mk b/keyboards/tzarc/djinn/rev1/rules.mk
new file mode 100644
index 0000000000..f468872849
--- /dev/null
+++ b/keyboards/tzarc/djinn/rev1/rules.mk
@@ -0,0 +1 @@
+# Placeholder to make the build system work.
diff --git a/keyboards/tzarc/djinn/rev2/config.h b/keyboards/tzarc/djinn/rev2/config.h
new file mode 100644
index 0000000000..52c909d442
--- /dev/null
+++ b/keyboards/tzarc/djinn/rev2/config.h
@@ -0,0 +1,47 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+// Limit the backlight brightness
+#ifndef BACKLIGHT_LIMIT_VAL
+# define BACKLIGHT_LIMIT_VAL 144
+#endif // BACKLIGHT_LIMIT_VAL
+
+// Split configuration
+#define SPLIT_HAND_PIN B9
+#define USB_VBUS_PIN B12
+#define SERIAL_USART_DRIVER SD3
+#define SERIAL_USART_PIN_SWAP
+#define SERIAL_USART_TX_PIN B10
+#define SERIAL_USART_TX_PAL_MODE 7
+#define SERIAL_USART_RX_PIN B11
+#define SERIAL_USART_RX_PAL_MODE 7
+#ifndef SERIAL_USART_SPEED
+# define SERIAL_USART_SPEED 1200000
+#endif // SERIAL_USART_SPEED
+#define SERIAL_USART_FULL_DUPLEX
+
+// RGB configuration
+#define RGBLED_NUM 86
+#define DRIVER_LED_TOTAL 86
+#define RGB_MATRIX_SPLIT \
+ { 43, 43 }
+#define RGB_POWER_ENABLE_PIN B0
+#define RGB_CURR_1500mA_OK_PIN C5
+#define RGB_CURR_3000mA_OK_PIN C4
+
+// EEPROM configuration
+#define EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN B5
+#define EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR 8 // (160MHz/8) => 20MHz
+#define EXTERNAL_EEPROM_BYTE_COUNT 8192
+#define EXTERNAL_EEPROM_PAGE_SIZE 64 // it's FRAM, so it doesn't actually matter, this just sets the RAM buffer size
+
+// External flash config
+#define EXTERNAL_FLASH_SPI_MODE 3
+#define EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN A8
+#define EXTERNAL_FLASH_SPI_CLOCK_DIVISOR 4 // (160MHz/4) => 40MHz
+#define EXTERNAL_FLASH_SIZE (4 * 1024 * 1024) // 32Mb/4MB capacity
+
+// Fault indicators
+#define BOARD_POWER_FAULT_PIN C9
+#define RGB_POWER_FAULT_PIN C4
diff --git a/keyboards/tzarc/djinn/rev2/info.json b/keyboards/tzarc/djinn/rev2/info.json
new file mode 100644
index 0000000000..e9b151cb93
--- /dev/null
+++ b/keyboards/tzarc/djinn/rev2/info.json
@@ -0,0 +1,100 @@
+{
+ "usb": {
+ "device_version": "2.0.0"
+ },
+ "split": {
+ "usb_detect": {
+ "enabled": false
+ }
+ },
+ "rgb_matrix": {
+ "layout": [
+ { "flags": 2, "x": 110, "y": 30 },
+ { "flags": 2, "x": 110, "y": 80 },
+ { "flags": 2, "x": 110, "y": 130 },
+ { "flags": 2, "x": 95, "y": 180 },
+ { "flags": 2, "x": 75, "y": 195 },
+ { "flags": 2, "x": 60, "y": 210 },
+ { "flags": 2, "x": 45, "y": 190 },
+ { "flags": 2, "x": 35, "y": 175 },
+ { "flags": 2, "x": 20, "y": 160 },
+ { "flags": 2, "x": 5, "y": 160 },
+ { "flags": 2, "x": 5, "y": 160 },
+ { "flags": 4, "matrix": [4, 3], "x": 78, "y": 150 },
+ { "flags": 4, "matrix": [4, 4], "x": 104, "y": 150 },
+ { "flags": 4, "matrix": [4, 5], "x": 130, "y": 150 },
+ { "flags": 4, "matrix": [4, 6], "x": 156, "y": 150 },
+ { "flags": 4, "matrix": [3, 6], "x": 156, "y": 120 },
+ { "flags": 4, "matrix": [3, 5], "x": 130, "y": 120 },
+ { "flags": 4, "matrix": [3, 4], "x": 104, "y": 120 },
+ { "flags": 4, "matrix": [3, 3], "x": 78, "y": 120 },
+ { "flags": 4, "matrix": [3, 2], "x": 52, "y": 120 },
+ { "flags": 4, "matrix": [3, 1], "x": 26, "y": 120 },
+ { "flags": 4, "matrix": [3, 0], "x": 0, "y": 120 },
+ { "flags": 4, "matrix": [2, 0], "x": 0, "y": 90 },
+ { "flags": 4, "matrix": [2, 1], "x": 26, "y": 90 },
+ { "flags": 4, "matrix": [2, 2], "x": 52, "y": 90 },
+ { "flags": 4, "matrix": [2, 3], "x": 78, "y": 90 },
+ { "flags": 4, "matrix": [2, 4], "x": 104, "y": 90 },
+ { "flags": 4, "matrix": [2, 5], "x": 130, "y": 90 },
+ { "flags": 4, "matrix": [2, 6], "x": 156, "y": 90 },
+ { "flags": 4, "matrix": [1, 6], "x": 156, "y": 60 },
+ { "flags": 4, "matrix": [1, 5], "x": 130, "y": 60 },
+ { "flags": 4, "matrix": [1, 4], "x": 104, "y": 60 },
+ { "flags": 4, "matrix": [1, 3], "x": 78, "y": 60 },
+ { "flags": 4, "matrix": [1, 2], "x": 52, "y": 60 },
+ { "flags": 4, "matrix": [1, 1], "x": 26, "y": 60 },
+ { "flags": 4, "matrix": [1, 0], "x": 0, "y": 60 },
+ { "flags": 4, "matrix": [0, 0], "x": 0, "y": 30 },
+ { "flags": 4, "matrix": [0, 1], "x": 26, "y": 30 },
+ { "flags": 4, "matrix": [0, 2], "x": 52, "y": 30 },
+ { "flags": 4, "matrix": [0, 3], "x": 78, "y": 30 },
+ { "flags": 4, "matrix": [0, 4], "x": 104, "y": 30 },
+ { "flags": 4, "matrix": [0, 5], "x": 130, "y": 30 },
+ { "flags": 4, "matrix": [0, 6], "x": 156, "y": 30 },
+ { "flags": 2, "x": 114, "y": 30 },
+ { "flags": 2, "x": 114, "y": 80 },
+ { "flags": 2, "x": 114, "y": 130 },
+ { "flags": 2, "x": 129, "y": 180 },
+ { "flags": 2, "x": 149, "y": 195 },
+ { "flags": 2, "x": 164, "y": 210 },
+ { "flags": 2, "x": 179, "y": 190 },
+ { "flags": 2, "x": 189, "y": 175 },
+ { "flags": 2, "x": 24, "y": 160 },
+ { "flags": 2, "x": 219, "y": 160 },
+ { "flags": 2, "x": 219, "y": 160 },
+ { "flags": 4, "matrix": [10, 3], "x": 146, "y": 150 },
+ { "flags": 4, "matrix": [10, 4], "x": 120, "y": 150 },
+ { "flags": 4, "matrix": [10, 5], "x": 94, "y": 150 },
+ { "flags": 4, "matrix": [10, 6], "x": 68, "y": 150 },
+ { "flags": 4, "matrix": [9, 6], "x": 68, "y": 120 },
+ { "flags": 4, "matrix": [9, 5], "x": 94, "y": 120 },
+ { "flags": 4, "matrix": [9, 4], "x": 120, "y": 120 },
+ { "flags": 4, "matrix": [9, 3], "x": 146, "y": 120 },
+ { "flags": 4, "matrix": [9, 2], "x": 172, "y": 120 },
+ { "flags": 4, "matrix": [9, 1], "x": 198, "y": 120 },
+ { "flags": 4, "matrix": [9, 0], "x": 224, "y": 120 },
+ { "flags": 4, "matrix": [8, 0], "x": 224, "y": 90 },
+ { "flags": 4, "matrix": [8, 1], "x": 198, "y": 90 },
+ { "flags": 4, "matrix": [8, 2], "x": 172, "y": 90 },
+ { "flags": 4, "matrix": [8, 3], "x": 146, "y": 90 },
+ { "flags": 4, "matrix": [8, 4], "x": 120, "y": 90 },
+ { "flags": 4, "matrix": [8, 5], "x": 94, "y": 90 },
+ { "flags": 4, "matrix": [8, 6], "x": 68, "y": 90 },
+ { "flags": 4, "matrix": [7, 6], "x": 68, "y": 60 },
+ { "flags": 4, "matrix": [7, 5], "x": 94, "y": 60 },
+ { "flags": 4, "matrix": [7, 4], "x": 120, "y": 60 },
+ { "flags": 4, "matrix": [7, 3], "x": 146, "y": 60 },
+ { "flags": 4, "matrix": [7, 2], "x": 172, "y": 60 },
+ { "flags": 4, "matrix": [7, 1], "x": 198, "y": 60 },
+ { "flags": 4, "matrix": [7, 0], "x": 224, "y": 60 },
+ { "flags": 4, "matrix": [6, 0], "x": 224, "y": 30 },
+ { "flags": 4, "matrix": [6, 1], "x": 198, "y": 30 },
+ { "flags": 4, "matrix": [6, 2], "x": 172, "y": 30 },
+ { "flags": 4, "matrix": [6, 3], "x": 146, "y": 30 },
+ { "flags": 4, "matrix": [6, 4], "x": 120, "y": 30 },
+ { "flags": 4, "matrix": [6, 5], "x": 94, "y": 30 },
+ { "flags": 4, "matrix": [6, 6], "x": 68, "y": 30 }
+ ]
+ }
+}
diff --git a/keyboards/tzarc/djinn/rev2/rev2.c b/keyboards/tzarc/djinn/rev2/rev2.c
new file mode 100644
index 0000000000..f55e0c224a
--- /dev/null
+++ b/keyboards/tzarc/djinn/rev2/rev2.c
@@ -0,0 +1,3 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include "rev2.h"
diff --git a/keyboards/tzarc/djinn/rev2/rev2.h b/keyboards/tzarc/djinn/rev2/rev2.h
new file mode 100644
index 0000000000..1845cb8fdd
--- /dev/null
+++ b/keyboards/tzarc/djinn/rev2/rev2.h
@@ -0,0 +1,3 @@
+// Copyright 2018-2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
diff --git a/keyboards/tzarc/djinn/rev2/rules.mk b/keyboards/tzarc/djinn/rev2/rules.mk
new file mode 100644
index 0000000000..f468872849
--- /dev/null
+++ b/keyboards/tzarc/djinn/rev2/rules.mk
@@ -0,0 +1 @@
+# Placeholder to make the build system work.
diff --git a/keyboards/tzarc/djinn/rules.mk b/keyboards/tzarc/djinn/rules.mk
new file mode 100644
index 0000000000..2f343a5a9d
--- /dev/null
+++ b/keyboards/tzarc/djinn/rules.mk
@@ -0,0 +1,23 @@
+CUSTOM_MATRIX = lite
+
+SERIAL_DRIVER = usart
+
+BACKLIGHT_DRIVER = pwm
+
+WS2812_DRIVER = pwm
+CIE1931_CURVE = yes
+
+RGB_MATRIX_DRIVER = WS2812
+
+EEPROM_DRIVER = spi
+
+AUDIO_DRIVER = pwm_software
+
+QUANTUM_PAINTER_DRIVERS = ili9341_spi
+
+SRC += \
+ djinn_portscan_matrix.c \
+ djinn_split_sync.c \
+ djinn_usbpd.c
+
+DEFAULT_FOLDER = tzarc/djinn/rev2