Skip to content

Commit

Permalink
Add Djinn. (qmk#17382)
Browse files Browse the repository at this point in the history
* Add Djinn.

* Review comments.

* Further cleanup.
  • Loading branch information
tzarc committed Jun 20, 2022
1 parent ad2e853 commit aa06893
Show file tree
Hide file tree
Showing 43 changed files with 2,145 additions and 1 deletion.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,12 @@ CMakeLists.txt
.vscode/temp.sql
tags

# Ignore image files
# Ignore image/font files
*.gif
*.jpg
*.png
*.ttf
*.otf

# Things Travis sees
/.vs
Expand Down
74 changes: 74 additions & 0 deletions keyboards/tzarc/djinn/config.h
Original file line number Diff line number Diff line change
@@ -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
199 changes: 199 additions & 0 deletions keyboards/tzarc/djinn/djinn.c
Original file line number Diff line number Diff line change
@@ -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();
}
}
32 changes: 32 additions & 0 deletions keyboards/tzarc/djinn/djinn.h
Original file line number Diff line number Diff line change
@@ -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);
Loading

0 comments on commit aa06893

Please sign in to comment.