qmk_firmware/users/bbaserdem/bbaserdem.c

361 lines
12 KiB
C

/* Copyright 2021 Batuhan Başerdem
* <baserdem.batuhan@gmail.com> @bbaserdem
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "bbaserdem.h"
// Language imports
#include <sendstring_dvorak.h>
// Need memcpy and memcmp from string.h along with transfer stuff
#ifdef SPLIT_KEYBOARD
#include "transactions.h"
#include <string.h>
#endif // SPLIT_KEYBOARD
/*-------------------------*\
|*-----KEYBOARD CONFIG-----*|
\*-------------------------*/
userspace_config_t userspace_config;
userspace_runtime_t userspace_runtime;
/*---------------------------------*\
|*----SPLIT KEYBOARD TRANSPORT-----*|
\*---------------------------------*/
#ifdef SPLIT_KEYBOARD
userspace_config_t transport_userspace_config;
userspace_runtime_t transport_userspace_runtime;
// Translate the RPC data to the local variable
void userspace_config_sync(uint8_t in_buflen, const void* in_data, uint8_t out_buflen, void* out_data) {
// Copy incoming data to local variable
if (in_buflen == sizeof(transport_userspace_config)) {
memcpy(&transport_userspace_config, in_data, in_buflen);
}
// There is no data to send back; so no output handling
}
void userspace_runtime_sync(uint8_t in_buflen, const void* in_data, uint8_t out_buflen, void* out_data) {
// Copy incoming data to local variable
if (in_buflen == sizeof(transport_userspace_runtime)) {
memcpy(&transport_userspace_runtime, in_data, in_buflen);
}
// There is no data to send back; so no output handling
}
// Either send or receive the correct data
void userspace_transport_update(void) {
if (is_keyboard_master()) {
// If we are the main device; we want to send info.
transport_userspace_config.raw = userspace_config.raw;
transport_userspace_runtime.raw = userspace_runtime.raw;
} else {
// If we are the secondary device; we want to receive info, and save to eeprom.
userspace_config.raw = transport_userspace_config.raw;
userspace_runtime.raw = transport_userspace_runtime.raw;
}
}
// Initiate the protocol on sync
void userspace_transport_sync(bool force_sync) {
if (is_keyboard_master()) {
// Keep track of the last state
static userspace_config_t last_userspace_config;
static userspace_runtime_t last_userspace_runtime;
bool needs_sync = false;
// Check if the config values are different
if (memcmp(&transport_userspace_config, &last_userspace_config, sizeof(transport_userspace_config))) {
needs_sync = true;
memcpy(&last_userspace_config, &transport_userspace_config, sizeof(transport_userspace_config));
}
// Perform the sync if requested
if (needs_sync || force_sync) {
transaction_rpc_send(RPC_ID_CONFIG_SYNC, sizeof(transport_userspace_config), &transport_userspace_config);
needs_sync = false;
}
// Check if the runtime values are different
if (memcmp(&transport_userspace_runtime, &last_userspace_runtime, sizeof(transport_userspace_runtime))) {
needs_sync = true;
memcpy(&last_userspace_runtime, &transport_userspace_runtime, sizeof(transport_userspace_runtime));
}
// Perform the sync if requested
if (needs_sync || force_sync) {
transaction_rpc_send(RPC_ID_RUNTIME_SYNC, sizeof(transport_userspace_runtime), &transport_userspace_runtime);
needs_sync = false;
}
}
}
#endif // SPLIT_KEYBOARD
/*---------------------------*\
|*-----KEYBOARD PRE INIT-----*|
\*---------------------------*/
/* This code runs before anything is started.
* Good for early hardware setup
*/
__attribute__ ((weak)) void keyboard_pre_init_keymap(void) {}
__attribute__ ((weak)) void keyboard_pre_init_user(void) {
// Keymap specific stuff
keyboard_pre_init_keymap();
}
/*---------------------*\
|*-----MATRIX INIT-----*|
\*---------------------*/
/* This code runs once midway thru the firmware process.
* So far, sets the base layer and fixes unicode mode
*/
__attribute__ ((weak)) void matrix_init_keymap(void) {}
void matrix_init_user (void) {
// Keymap specific things
matrix_init_keymap();
}
/*----------------------------*\
|*-----KEYBOARD POST INIT-----*|
\*----------------------------*/
/* This code runs after anything is started.
* Good for late hardware setup, like setting up layer specifications
*/
__attribute__ ((weak)) void keyboard_post_init_keymap(void) {}
__attribute__ ((weak)) void keyboard_post_init_user(void) {
// Fix beginning base layer, in case some other firmware was flashed
// set_single_persistent_default_layer(_BASE);
// Unicode mode
# ifdef UNICODEMAP_ENABLE
set_unicode_input_mode(UC_LNX);
# endif // UNICODEMAP_ENABLE
// Split keyboard halves communication
# ifdef SPLIT_KEYBOARD
// Register the transactions
transaction_register_rpc( RPC_ID_CONFIG_SYNC, userspace_config_sync );
transaction_register_rpc(RPC_ID_RUNTIME_SYNC, userspace_runtime_sync);
// Load default config values
if (is_keyboard_master()) {
// If we are main; load from eeconfig
userspace_config.raw = eeconfig_read_user();
// And update the transport variable
userspace_transport_update();
// Do one forced transfer to sync halves
userspace_transport_sync(true);
} else {
// Just sync the data received
userspace_transport_update();
}
# else // SPLIT_KEYBOARD
// If we are not split; just load from eeprom
userspace_config.raw = eeconfig_read_user();
# endif // SPLIT_KEYBOARD
// Backlight LED
# ifdef BACKLIGHT_ENABLE
keyboard_post_init_backlight();
# endif // BACKLIGHT_ENABLE
// RGB underglow
# ifdef RGBLIGHT_ENABLE
keyboard_post_init_underglow();
# endif // RGBLIGHT_ENABLE
// Keymap specific stuff
keyboard_post_init_keymap();
}
/*---------------------------*\
|*-----HOUSEKEEPING TASK-----*|
\*---------------------------*/
/* I have no idea what this does
*/
__attribute__ ((weak)) void housekeeping_task_keymap(void) {}
void housekeeping_task_user(void) {
// Check eeprom every now and then
static userspace_config_t prev_userspace_config;
static fast_timer_t throttle_timer = 0;
static bool init_flag = true;
// Read this if we never read it before
if (init_flag) {
init_flag = false;
prev_userspace_config.raw = eeconfig_read_user();
}
// Throttled tasks here
if (timer_elapsed_fast(throttle_timer) >= HOUSEKEEPING_THROTTLE_INTERVAL_MS) {
// Refresh timer
throttle_timer = timer_read_fast();
// Check userspace config for eeprom updates
if (memcmp(&prev_userspace_config, &userspace_config, sizeof(userspace_config))) {
memcpy(&prev_userspace_config, &userspace_config, sizeof(userspace_config));
eeconfig_update_user(userspace_config.raw);
}
}
// Do transport stuff
# ifdef SPLIT_KEYBOARD
userspace_transport_update();
userspace_transport_sync(false);
# endif // SPLIT_KEYBOARD
// Hook to keymap code
housekeeping_task_keymap();
}
/*-----------------------*\
|*-----EECONFIG INIT-----*|
\*-----------------------*/
/* Default values to send to the eeprom
*/
void eeconfig_init_user(void) {
// Set everything to default
userspace_config.raw = 0;
// Set encoder states to sane defaults if enabled
# ifdef ENCODER_ENABLE
reset_encoder_state();
# endif // ENCODER_ENABLE
}
/*------------------------*\
|*-----PROCESS RECORD-----*|
\*------------------------*/
/* Process record: custom keycodes to process here
* Allow also the following codes to hook here as well;
* Macro definitions
* Audio hooks
*/
__attribute__ ((weak))
bool process_record_keymap(uint16_t keycode, keyrecord_t *record) {
return true;
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
// Return after running through all individual hooks
return
process_record_keymap(keycode, record) &&
# ifdef AUDIO_ENABLE
process_record_audio(keycode, record) &&
# endif // AUDIO_ENABLE
# ifdef ENCODER_ENABLE
process_record_encoder(keycode, record) &&
# endif // ENCODER_ENABLE
process_record_macro(keycode, record);
}
/*---------------------*\
|*-----MATRIX SCAN-----*|
\*---------------------*/
/* This code runs every frame
* I used to check for layer switching here, but layer state is better used.
* Try to not put anything here; as it runs hundreds time per second-ish
*/
__attribute__ ((weak)) void matrix_scan_keymap(void) { }
void matrix_scan_user (void) {
// Keymap specific scan function
matrix_scan_keymap();
}
/*---------------------*\
|*-----LAYER STATE-----*|
\*---------------------*/
/* This code runs after every layer change
* State represents the new layer state.
*/
__attribute__ ((weak))
layer_state_t layer_state_set_keymap (layer_state_t state) {
return state;
}
layer_state_t layer_state_set_user(layer_state_t state) {
// Keymap layer state setting
state = layer_state_set_keymap(state);
// For underglow stuff
# ifdef RGBLIGHT_ENABLE
state = layer_state_set_underglow(state);
# endif // RGBLIGHT_ENABLE
// Audio playback
# ifdef AUDIO_ENABLE
state = layer_state_set_audio(state);
# endif // AUDIO_ENABLE
return state;
}
/*-----------------------------*\
|*-----DEFAULT LAYER STATE-----*|
\*-----------------------------*/
/* This code runs after every time default base layer is changed
*/
__attribute__ ((weak))
layer_state_t default_layer_state_set_keymap (layer_state_t state) {
return state;
}
layer_state_t default_layer_state_set_user(layer_state_t state) {
// Keymap level code
state = default_layer_state_set_keymap(state);
return state;
}
/*------------------------*\
|*-----LED SET KEYMAP-----*|
\*------------------------*/
/* Code for LED indicators
* I'm not sure when exactly does this code run
*/
__attribute__ ((weak)) void led_set_keymap(uint8_t usb_led) {}
void led_set_user(uint8_t usb_led) {
led_set_keymap(usb_led);
}
/*-----------------*\
|*-----SUSPEND-----*|
\*-----------------*/
/* Suspend stuff here, mostly for the rgb lighting.
*/
__attribute__ ((weak)) void suspend_power_down_keymap (void) { }
void suspend_power_down_user(void) {
suspend_power_down_keymap();
// RGB matrix sleep hook
# ifdef RGB_MATRIX_ENABLE
suspend_power_down_rgb();
# endif // RGB_MATRIX_ENABLE
}
__attribute__ ((weak)) void suspend_wakeup_init_keymap (void) { }
void suspend_wakeup_init_user(void) {
suspend_wakeup_init_keymap();
// RGB matrix sleep hook
# ifdef RGB_MATRIX_ENABLE
suspend_wakeup_init_rgb();
# endif // RGB_MATRIX_ENABLE
}
/*------------------*\
|*-----SHUTDOWN-----*|
\*------------------*/
/* Shutdown stuff here; for when entering bootmode.
*/
__attribute__ ((weak)) void shutdown_keymap (void) { }
void shutdown_user(void) {
// Underglow LED hook on boot
# ifdef RGBLIGHT_ENABLE
shutdown_underglow();
# endif // RGBLIGHT_ENABLE
// Perkey led hook on boot
# ifdef RGB_MATRIX_ENABLE
shutdown_rgb();
# endif // RGB_MATRIX_ENABLE
// Keymap hooks
shutdown_keymap();
}