361 lines
12 KiB
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();
|
|
}
|