Skip to content

Commit

Permalink
Update my keymap for new ST7565 driver.
Browse files Browse the repository at this point in the history
More or less copied my visualizer.
  • Loading branch information
firetech committed Jun 5, 2021
1 parent 2530823 commit 9004ac3
Show file tree
Hide file tree
Showing 8 changed files with 341 additions and 25 deletions.
4 changes: 3 additions & 1 deletion layouts/community/ergodox/firetech/bongocat.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@

#define BONGOCAT_LINEWIDTH 56 // ceil(BONGOCAT_WIDTH / 8.0) * 8

const uint8_t bongocat[][BONGOCAT_LINEWIDTH*BONGOCAT_HEIGHT/8] = {
#define BONGOCAT_LENGTH BONGOCAT_LINEWIDTH*BONGOCAT_HEIGHT/8

const uint8_t PROGMEM bongocat[][BONGOCAT_LENGTH] = {
// .o.
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff,
Expand Down
24 changes: 16 additions & 8 deletions layouts/community/ergodox/firetech/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,28 @@

#define PERMISSIVE_HOLD

#ifdef KEYBOARD_ergodox_infinity
# undef BACKLIGHT_LEVELS
# define BACKLIGHT_LEVELS 5
# undef LED_MATRIX_VAL_STEP
# define LED_MATRIX_VAL_STEP 51

# define EE_HANDS
#undef BACKLIGHT_LEVELS
#define BACKLIGHT_LEVELS 5
#undef LED_MATRIX_VAL_STEP
#define LED_MATRIX_VAL_STEP 51

#ifdef SPLIT_KEYBOARD
# define SPLIT_WPM_ENABLE
# define SPLIT_TRANSACTION_IDS_USER MAX_WPM
# define SPLIT_TRANSACTION_IDS_USER FT_MAX_WPM, FT_DISPLAY_STATE
# define SPLIT_TRANSPORT_MIRROR
# define LED_MATRIX_KEYREACTIVE_ENABLED
#endif

#ifdef ST7565_ENABLE
# define ST7565_TIMEOUT 0
#endif

#ifdef KEYBOARD_ergodox_infinity
# define EE_HANDS
#endif

#ifdef KEYBOARD_ergodox_ez
# define QMK_KEYS_PER_SCAN 4
#endif

#define DEBUG_MATRIX_SCAN_RATE
36 changes: 32 additions & 4 deletions layouts/community/ergodox/firetech/keymap_extra.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@
*/

#include QMK_KEYBOARD_H
#include <string.h>
#include <stdio.h>

#include "wpm.h"
#include "keymap_extra.h"
#include <stdio.h>
#ifdef ST7565_ENABLE
# include "keymap_st7565.h"
#endif

#define WPM_BUF_SIZE 4

Expand All @@ -29,35 +34,58 @@ enum custom_keycodes {

static uint8_t max_wpm = 0;

#if defined(SPLIT_KEYBOARD) && defined(WPM_ENABLE)
#if defined(SPLIT_KEYBOARD) && (defined(WPM_ENABLE) || defined(ST7565_ENABLE))
# include "transactions.h"

# ifndef FORCED_SYNC_THROTTLE_MS
# define FORCED_SYNC_THROTTLE_MS 100
# endif

# ifdef WPM_ENABLE
void max_wpm_slave_handler(uint8_t in_buflen, const void* in_data, uint8_t out_buflen, void* out_data) {
set_max_wpm(*((uint8_t *)in_data));
}

static bool max_wpm_changed = false;
# endif

# ifdef ST7565_ENABLE
void display_state_slave_handler(uint8_t in_buflen, const void* in_data, uint8_t out_buflen, void* out_data) {
set_ft_display_state((ft_display_state_t *)in_data);
}
# endif

void housekeeping_task_user(void) {
if (is_keyboard_master()) {
# ifdef WPM_ENABLE
static uint16_t last_max_wpm_update = 0;
if (max_wpm_changed || timer_elapsed(last_max_wpm_update) > FORCED_SYNC_THROTTLE_MS) {
if (transaction_rpc_send(MAX_WPM, sizeof(max_wpm), &max_wpm)) {
if (transaction_rpc_send(FT_MAX_WPM, sizeof(max_wpm), &max_wpm)) {
max_wpm_changed = false;
last_max_wpm_update = timer_read();
}
}
# endif
# ifdef ST7565_ENABLE
static uint16_t last_display_state_update = 0;
static ft_display_state_t last_display_state;
if (!same_ft_display_state(&last_display_state, &ft_display_state) || timer_elapsed(last_display_state_update) > FORCED_SYNC_THROTTLE_MS) {
if (transaction_rpc_send(FT_DISPLAY_STATE, sizeof(ft_display_state), &ft_display_state)) {
memcpy(&last_display_state, &ft_display_state, sizeof(last_display_state));
last_display_state_update = timer_read();
}
}
# endif
}
}
#endif

void keyboard_post_init_user(void) {
#ifdef SPLIT_KEYBOARD
transaction_register_rpc(MAX_WPM, max_wpm_slave_handler);
transaction_register_rpc(FT_MAX_WPM, max_wpm_slave_handler);
# ifdef ST7565_ENABLE
transaction_register_rpc(FT_DISPLAY_STATE, display_state_slave_handler);
# endif
#endif
}

Expand Down
3 changes: 3 additions & 0 deletions layouts/community/ergodox/firetech/keymap_extra.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@

#pragma once

#define SWAP_LAYER 1
#define FN_LAYER 2

uint8_t get_max_wpm(void);
void set_max_wpm(uint8_t);
257 changes: 257 additions & 0 deletions layouts/community/ergodox/firetech/keymap_st7565.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
#include QMK_KEYBOARD_H
#include <math.h>
#include <string.h>

#include "keymap_st7565.h"
#include "keymap_extra.h"
#include "bongocat.h"

#define STAT_BUF_SIZE 10

#define WPM_ANIM_START 20 // Animation idle below this WPM value
#define WPM_TO_FRAME_TIME(wpm) (2565 - 537 * log(wpm)) // Formula to convert WPM to frame time

ft_display_state_t ft_display_state = {
.is_on = true,
.leds = 0xFF,
.layer = 0xFFFFFFFF,
.swap_displays = false,
};
static bool clear_display = true;

void set_ft_display_state(ft_display_state_t* new_state) {
if (!same_ft_display_state(&ft_display_state, new_state)) {
memcpy(&ft_display_state, new_state, sizeof(ft_display_state));
if (ft_display_state.is_on != st7565_is_on()) {
if (ft_display_state.is_on) {
st7565_on();
} else {
st7565_off();
}
}
clear_display = true;
}
}

bool same_ft_display_state(ft_display_state_t *a, ft_display_state_t *b) {
if (a->is_on == b->is_on &&
a->leds == b->leds &&
a->layer == b->layer &&
a->layer == b->layer &&
a->swap_displays == b->swap_displays) {
return true;
}
return false;
}

/* LCD backlight code copied from quantum/visualizer/lcd_backlight.c */
static uint8_t current_hue = 0;
static uint8_t current_saturation = 0;
static uint8_t current_intensity = 0;
static uint8_t current_brightness = 255;

// This code is based on Brian Neltner's blogpost and example code
// "Why every LED light should be using HSI colorspace".
// http://blog.saikoled.com/post/43693602826/why-every-led-light-should-be-using-hsi
static void hsi_to_rgb(float h, float s, float i, uint16_t* r_out, uint16_t* g_out, uint16_t* b_out) {
unsigned int r, g, b;
h = fmodf(h, 360.0f); // cycle h around to 0-360 degrees
h = 3.14159f * h / 180.0f; // Convert to radians.
s = s > 0.0f ? (s < 1.0f ? s : 1.0f) : 0.0f; // clamp s and i to interval [0,1]
i = i > 0.0f ? (i < 1.0f ? i : 1.0f) : 0.0f;

// Math! Thanks in part to Kyle Miller.
if (h < 2.09439f) {
r = 65535.0f * i / 3.0f * (1.0f + s * cos(h) / cosf(1.047196667f - h));
g = 65535.0f * i / 3.0f * (1.0f + s * (1.0f - cosf(h) / cos(1.047196667f - h)));
b = 65535.0f * i / 3.0f * (1.0f - s);
} else if (h < 4.188787) {
h = h - 2.09439;
g = 65535.0f * i / 3.0f * (1.0f + s * cosf(h) / cosf(1.047196667f - h));
b = 65535.0f * i / 3.0f * (1.0f + s * (1.0f - cosf(h) / cosf(1.047196667f - h)));
r = 65535.0f * i / 3.0f * (1.0f - s);
} else {
h = h - 4.188787;
b = 65535.0f * i / 3.0f * (1.0f + s * cosf(h) / cosf(1.047196667f - h));
r = 65535.0f * i / 3.0f * (1.0f + s * (1.0f - cosf(h) / cosf(1.047196667f - h)));
g = 65535.0f * i / 3.0f * (1.0f - s);
}
*r_out = r > 65535 ? 65535 : r;
*g_out = g > 65535 ? 65535 : g;
*b_out = b > 65535 ? 65535 : b;
}

static void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity) {
uint16_t r, g, b;
float hue_f = 360.0f * (float)hue / 255.0f;
float saturation_f = (float)saturation / 255.0f;
float intensity_f = (float)intensity / 255.0f;
intensity_f *= (float)current_brightness / 255.0f;
hsi_to_rgb(hue_f, saturation_f, intensity_f, &r, &g, &b);
current_hue = hue;
current_saturation = saturation;
current_intensity = intensity;
ergodox_infinity_lcd_color(r, g, b);
}

static void lcd_backlight_brightness(uint8_t b) {
current_brightness = b;
lcd_backlight_color(current_hue, current_saturation, current_intensity);
}
/* End of copied LCD backlight code */

static uint8_t prev_brightness = 0;

void st7565_on_user(void) {
ft_display_state.is_on = true;
lcd_backlight_brightness(prev_brightness);
}

void st7565_off_user(void) {
ft_display_state.is_on = false;
prev_brightness = current_brightness;
lcd_backlight_brightness(0);
}

void set_hand_swap(bool do_swap) {
ft_display_state.swap_displays = do_swap;
clear_display = true;
}

static inline void write_led_state(uint8_t *row, uint8_t *col, uint8_t led, const char *text_P) {
if (ft_display_state.leds & (1u << led)) {
const size_t length = strlen_P(text_P);
if (*col + length > st7565_max_chars()) {
st7565_advance_page(true);
st7565_write_P(PSTR(" "), false);
*col = 2;
*row += 1;
}
st7565_write_P(text_P, false);
st7565_write_char(' ', false);
*col += length + 1;
}
}

void draw_right(const char *layer_text_P) {
st7565_write_ln_P(layer_text_P, false);
if (strlen_P(layer_text_P) < st7565_max_chars()) {
st7565_advance_page(true);
}

st7565_write_char(0x2A, false);
st7565_write_char(' ', false);
uint8_t row = 2;
uint8_t col = 2;
write_led_state(&row, &col, USB_LED_NUM_LOCK, PSTR("Num"));
write_led_state(&row, &col, USB_LED_CAPS_LOCK, PSTR("Caps"));
write_led_state(&row, &col, USB_LED_SCROLL_LOCK, PSTR("Scroll"));
write_led_state(&row, &col, USB_LED_COMPOSE, PSTR("Compose"));
write_led_state(&row, &col, USB_LED_KANA, PSTR("Kana"));
while (row++ <= 3) {
st7565_advance_page(true);
}
}

void draw_left(void) {
char stat_buf[STAT_BUF_SIZE];

const uint8_t* wpm_frame = bongocat[0];
#ifdef WPM_ENABLE
uint8_t wpm = get_current_wpm();

st7565_advance_page(true);
st7565_advance_page(true);
st7565_write_P(PSTR("WPM: "), false);
snprintf(stat_buf, STAT_BUF_SIZE, "%3u", wpm);
st7565_write_ln(stat_buf, false);

st7565_write_P(PSTR("Max: "), false);
snprintf(stat_buf, STAT_BUF_SIZE, "%3u", get_max_wpm());
st7565_write_ln(stat_buf, false);

static uint16_t wpm_anim_timer = 0;
static uint8_t wpm_anim_at_frame = 1;
if (wpm >= WPM_ANIM_START) {
wpm_frame = bongocat[wpm_anim_at_frame];

if (timer_elapsed(wpm_anim_timer) >= WPM_TO_FRAME_TIME(wpm)) {
wpm_anim_at_frame = 3 - wpm_anim_at_frame;
wpm_anim_timer = timer_read();
}
}
#endif

debug_enable = true;
uint8_t x = ST7565_DISPLAY_WIDTH - BONGOCAT_WIDTH;
uint8_t y = 0;
for (uint8_t byte = 0; byte < BONGOCAT_LENGTH; byte++) {
uint8_t pixels = pgm_read_byte(wpm_frame + byte);
for (uint8_t mask = (1u << 7); mask > 0; mask >>= 1) {
st7565_write_pixel(x, y, (pixels & mask) == 0);
if (++x > ST7565_DISPLAY_WIDTH) {
x = ST7565_DISPLAY_WIDTH - BONGOCAT_WIDTH;
y++;
break;
}
}
}

#ifdef LED_MATRIX_ENABLE
if (ft_display_state.layer & (1 << FN_LAYER)) {
st7565_set_cursor(0, 0);
uint8_t brightness = led_matrix_get_val();
uint8_t backlight_level = 0;
if (led_matrix_is_enabled()) {
backlight_level = brightness * 100.0 / UINT8_MAX;
}
st7565_write_P(PSTR("Backlight: "), false);
snprintf(stat_buf, STAT_BUF_SIZE, "%3u%%", backlight_level);
st7565_write(stat_buf, false);
}
#endif
}

void st7565_task_user(void) {
if (is_keyboard_master()) {
ft_display_state.is_on = st7565_is_on();
ft_display_state.leds = host_keyboard_leds();
ft_display_state.layer = layer_state;
}

if (ft_display_state.is_on) {
#ifdef LED_MATRIX_ENABLE
lcd_backlight_brightness(led_matrix_get_val());
#endif

const char *layer_text_P;
if (ft_display_state.layer & (1 << FN_LAYER)) {
lcd_backlight_color(170, 255, 255);
if (ft_display_state.layer & (1 << SWAP_LAYER)) {
layer_text_P = PSTR("Fn Swap On Space");
} else {
layer_text_P = PSTR("Fn");
}
} else if (ft_display_state.layer & (1 << SWAP_LAYER)) {
lcd_backlight_color(128, 255, 255);
layer_text_P = PSTR("Swap On Space");
} else {
lcd_backlight_color(0, 0, 255);
layer_text_P = PSTR("Default");
}

bool is_left = is_keyboard_left();
if (ft_display_state.swap_displays) { is_left = !is_left; }

if (clear_display) {
st7565_clear();
clear_display = false;
}

if (is_left) {
draw_left();
} else {
draw_right(layer_text_P);
}
}
}
Loading

0 comments on commit 9004ac3

Please sign in to comment.