2024-02-26 02:05:10 +00:00
/* Copyright 2023 Cipulot
*
* 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 3 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 "eeprom_tools.h"
# include "ec_switch_matrix.h"
# include "action.h"
# include "print.h"
# include "via.h"
2024-10-28 19:54:05 +00:00
# ifdef SPLIT_KEYBOARD
# include "transactions.h"
# endif
2024-02-26 02:05:10 +00:00
# ifdef VIA_ENABLE
void ec_rescale_values ( uint8_t item ) ;
void ec_save_threshold_data ( uint8_t option ) ;
void ec_save_bottoming_reading ( void ) ;
void ec_show_calibration_data ( void ) ;
void ec_clear_bottoming_calibration_data ( void ) ;
// Declaring enums for VIA config menu
enum via_enums {
// clang-format off
id_actuation_mode = 1 ,
id_mode_0_actuation_threshold = 2 ,
id_mode_0_release_threshold = 3 ,
id_save_threshold_data = 4 ,
id_mode_1_initial_deadzone_offset = 5 ,
id_mode_1_actuation_offset = 6 ,
id_mode_1_release_offset = 7 ,
id_bottoming_calibration = 8 ,
id_noise_floor_calibration = 9 ,
id_show_calibration_data = 10 ,
id_clear_bottoming_calibration_data = 11
// clang-format on
} ;
// Handle the data received by the keyboard from the VIA menus
void via_config_set_value ( uint8_t * data ) {
// data = [ value_id, value_data ]
uint8_t * value_id = & ( data [ 0 ] ) ;
uint8_t * value_data = & ( data [ 1 ] ) ;
2024-10-28 19:54:05 +00:00
# ifdef SPLIT_KEYBOARD
if ( is_keyboard_master ( ) ) {
transaction_rpc_send ( RPC_ID_VIA_CMD , 30 , data ) ;
}
# endif
2024-02-26 02:05:10 +00:00
switch ( * value_id ) {
case id_actuation_mode : {
eeprom_ec_config . actuation_mode = value_data [ 0 ] ;
ec_config . actuation_mode = eeprom_ec_config . actuation_mode ;
if ( ec_config . actuation_mode = = 0 ) {
uprintf ( " ######################### \n " ) ;
uprintf ( " # Actuation Mode: APC # \n " ) ;
uprintf ( " ######################### \n " ) ;
} else if ( ec_config . actuation_mode = = 1 ) {
uprintf ( " ################################# \n " ) ;
uprintf ( " # Actuation Mode: Rapid Trigger # \n " ) ;
uprintf ( " ################################# \n " ) ;
}
EEPROM_KB_PARTIAL_UPDATE ( eeprom_ec_config , actuation_mode ) ;
break ;
}
case id_mode_0_actuation_threshold : {
ec_config . mode_0_actuation_threshold = value_data [ 1 ] | ( value_data [ 0 ] < < 8 ) ;
uprintf ( " APC Mode Actuation Threshold: %d \n " , ec_config . mode_0_actuation_threshold ) ;
break ;
}
case id_mode_0_release_threshold : {
ec_config . mode_0_release_threshold = value_data [ 1 ] | ( value_data [ 0 ] < < 8 ) ;
uprintf ( " APC Mode Release Threshold: %d \n " , ec_config . mode_0_release_threshold ) ;
break ;
}
case id_mode_1_initial_deadzone_offset : {
ec_config . mode_1_initial_deadzone_offset = value_data [ 1 ] | ( value_data [ 0 ] < < 8 ) ;
uprintf ( " Rapid Trigger Mode Initial Deadzone Offset: %d \n " , ec_config . mode_1_initial_deadzone_offset ) ;
break ;
}
case id_mode_1_actuation_offset : {
ec_config . mode_1_actuation_offset = value_data [ 0 ] ;
uprintf ( " Rapid Trigger Mode Actuation Offset: %d \n " , ec_config . mode_1_actuation_offset ) ;
break ;
}
case id_mode_1_release_offset : {
ec_config . mode_1_release_offset = value_data [ 0 ] ;
uprintf ( " Rapid Trigger Mode Release Offset: %d \n " , ec_config . mode_1_release_offset ) ;
break ;
}
case id_bottoming_calibration : {
if ( value_data [ 0 ] = = 1 ) {
ec_config . bottoming_calibration = true ;
uprintf ( " ############################## \n " ) ;
uprintf ( " # Bottoming calibration mode # \n " ) ;
uprintf ( " ############################## \n " ) ;
} else {
ec_config . bottoming_calibration = false ;
ec_save_bottoming_reading ( ) ;
uprintf ( " ## Bottoming calibration done ## \n " ) ;
ec_show_calibration_data ( ) ;
}
break ;
}
case id_save_threshold_data : {
ec_save_threshold_data ( value_data [ 0 ] ) ;
break ;
}
case id_noise_floor_calibration : {
if ( value_data [ 0 ] = = 0 ) {
ec_noise_floor ( ) ;
ec_rescale_values ( 0 ) ;
ec_rescale_values ( 1 ) ;
ec_rescale_values ( 2 ) ;
2024-10-28 19:54:05 +00:00
ec_rescale_values ( 3 ) ;
ec_rescale_values ( 4 ) ;
2024-02-26 02:05:10 +00:00
uprintf ( " ############################# \n " ) ;
uprintf ( " # Noise floor data acquired # \n " ) ;
uprintf ( " ############################# \n " ) ;
break ;
}
}
case id_show_calibration_data : {
if ( value_data [ 0 ] = = 0 ) {
ec_show_calibration_data ( ) ;
}
2024-10-28 19:54:05 +00:00
break ;
2024-02-26 02:05:10 +00:00
}
case id_clear_bottoming_calibration_data : {
if ( value_data [ 0 ] = = 0 ) {
ec_clear_bottoming_calibration_data ( ) ;
}
2024-10-28 19:54:05 +00:00
break ;
2024-02-26 02:05:10 +00:00
}
default : {
// Unhandled value.
break ;
}
}
}
// Handle the data sent by the keyboard to the VIA menus
void via_config_get_value ( uint8_t * data ) {
// data = [ value_id, value_data ]
uint8_t * value_id = & ( data [ 0 ] ) ;
uint8_t * value_data = & ( data [ 1 ] ) ;
switch ( * value_id ) {
case id_actuation_mode : {
value_data [ 0 ] = eeprom_ec_config . actuation_mode ;
break ;
}
case id_mode_0_actuation_threshold : {
value_data [ 0 ] = eeprom_ec_config . mode_0_actuation_threshold > > 8 ;
value_data [ 1 ] = eeprom_ec_config . mode_0_actuation_threshold & 0xFF ;
break ;
}
case id_mode_0_release_threshold : {
value_data [ 0 ] = eeprom_ec_config . mode_0_release_threshold > > 8 ;
value_data [ 1 ] = eeprom_ec_config . mode_0_release_threshold & 0xFF ;
break ;
}
case id_mode_1_initial_deadzone_offset : {
value_data [ 0 ] = eeprom_ec_config . mode_1_initial_deadzone_offset > > 8 ;
value_data [ 1 ] = eeprom_ec_config . mode_1_initial_deadzone_offset & 0xFF ;
break ;
}
case id_mode_1_actuation_offset : {
value_data [ 0 ] = eeprom_ec_config . mode_1_actuation_offset ;
break ;
}
case id_mode_1_release_offset : {
value_data [ 0 ] = eeprom_ec_config . mode_1_release_offset ;
break ;
}
default : {
// Unhandled value.
break ;
}
}
}
// Handle the commands sent and received by the keyboard with VIA
void via_custom_value_command_kb ( uint8_t * data , uint8_t length ) {
// data = [ command_id, channel_id, value_id, value_data ]
uint8_t * command_id = & ( data [ 0 ] ) ;
uint8_t * channel_id = & ( data [ 1 ] ) ;
uint8_t * value_id_and_data = & ( data [ 2 ] ) ;
if ( * channel_id = = id_custom_channel ) {
switch ( * command_id ) {
case id_custom_set_value : {
via_config_set_value ( value_id_and_data ) ;
break ;
}
case id_custom_get_value : {
via_config_get_value ( value_id_and_data ) ;
break ;
}
case id_custom_save : {
// Bypass the save function in favor of pinpointed saves
break ;
}
default : {
// Unhandled message.
* command_id = id_unhandled ;
break ;
}
}
return ;
}
* command_id = id_unhandled ;
}
// Rescale the values received by VIA to fit the new range
void ec_rescale_values ( uint8_t item ) {
switch ( item ) {
// Rescale the APC mode actuation thresholds
case 0 :
for ( uint8_t row = 0 ; row < MATRIX_ROWS ; row + + ) {
for ( uint8_t col = 0 ; col < MATRIX_COLS ; col + + ) {
ec_config . rescaled_mode_0_actuation_threshold [ row ] [ col ] = rescale ( ec_config . mode_0_actuation_threshold , 0 , 1023 , ec_config . noise_floor [ row ] [ col ] , eeprom_ec_config . bottoming_reading [ row ] [ col ] ) ;
}
}
break ;
// Rescale the APC mode release thresholds
case 1 :
for ( uint8_t row = 0 ; row < MATRIX_ROWS ; row + + ) {
for ( uint8_t col = 0 ; col < MATRIX_COLS ; col + + ) {
ec_config . rescaled_mode_0_release_threshold [ row ] [ col ] = rescale ( ec_config . mode_0_release_threshold , 0 , 1023 , ec_config . noise_floor [ row ] [ col ] , eeprom_ec_config . bottoming_reading [ row ] [ col ] ) ;
}
}
break ;
// Rescale the Rapid Trigger mode initial deadzone offsets
case 2 :
for ( uint8_t row = 0 ; row < MATRIX_ROWS ; row + + ) {
for ( uint8_t col = 0 ; col < MATRIX_COLS ; col + + ) {
ec_config . rescaled_mode_1_initial_deadzone_offset [ row ] [ col ] = rescale ( ec_config . mode_1_initial_deadzone_offset , 0 , 1023 , ec_config . noise_floor [ row ] [ col ] , eeprom_ec_config . bottoming_reading [ row ] [ col ] ) ;
}
}
break ;
2024-10-28 19:54:05 +00:00
// Rescale the Rapid Trigger mode actuation offsets
case 3 :
for ( uint8_t row = 0 ; row < MATRIX_ROWS ; row + + ) {
for ( uint8_t col = 0 ; col < MATRIX_COLS ; col + + ) {
ec_config . rescaled_mode_1_actuation_offset [ row ] [ col ] = rescale ( ec_config . mode_1_actuation_offset , 0 , 1023 , ec_config . noise_floor [ row ] [ col ] , eeprom_ec_config . bottoming_reading [ row ] [ col ] ) ;
}
}
break ;
// Rescale the Rapid Trigger mode release offsets
case 4 :
for ( uint8_t row = 0 ; row < MATRIX_ROWS ; row + + ) {
for ( uint8_t col = 0 ; col < MATRIX_COLS ; col + + ) {
ec_config . rescaled_mode_1_release_offset [ row ] [ col ] = rescale ( ec_config . mode_1_release_offset , 0 , 1023 , ec_config . noise_floor [ row ] [ col ] , eeprom_ec_config . bottoming_reading [ row ] [ col ] ) ;
}
}
break ;
2024-02-26 02:05:10 +00:00
default :
// Unhandled item.
break ;
}
}
void ec_save_threshold_data ( uint8_t option ) {
// Save APC mode thresholds and rescale them for runtime usage
if ( option = = 0 ) {
eeprom_ec_config . mode_0_actuation_threshold = ec_config . mode_0_actuation_threshold ;
eeprom_ec_config . mode_0_release_threshold = ec_config . mode_0_release_threshold ;
ec_rescale_values ( 0 ) ;
ec_rescale_values ( 1 ) ;
}
// Save Rapid Trigger mode thresholds and rescale them for runtime usage
else if ( option = = 1 ) {
eeprom_ec_config . mode_1_initial_deadzone_offset = ec_config . mode_1_initial_deadzone_offset ;
2024-10-28 19:54:05 +00:00
eeprom_ec_config . mode_1_actuation_offset = ec_config . mode_1_actuation_offset ;
eeprom_ec_config . mode_1_release_offset = ec_config . mode_1_release_offset ;
2024-02-26 02:05:10 +00:00
ec_rescale_values ( 2 ) ;
2024-10-28 19:54:05 +00:00
ec_rescale_values ( 3 ) ;
ec_rescale_values ( 4 ) ;
2024-02-26 02:05:10 +00:00
}
eeconfig_update_kb_datablock ( & eeprom_ec_config ) ;
uprintf ( " #################################### \n " ) ;
uprintf ( " # New thresholds applied and saved # \n " ) ;
uprintf ( " #################################### \n " ) ;
}
// Save the bottoming reading
void ec_save_bottoming_reading ( void ) {
for ( uint8_t row = 0 ; row < MATRIX_ROWS ; row + + ) {
for ( uint8_t col = 0 ; col < MATRIX_COLS ; col + + ) {
2024-10-28 19:54:05 +00:00
// If the calibration starter flag is still set on the key, it indicates that the key was skipped during the scan because it is not physically present.
// If the flag is not set, it means a bottoming reading was taken. If this reading doesn't exceed the noise floor by the BOTTOMING_CALIBRATION_THRESHOLD, it likely indicates one of the following:
// 1. The key is part of an alternative layout and is not being pressed.
// 2. The key is in the current layout but is not being pressed.
// In both conditions we should set the bottoming reading to the maximum value to avoid false positives.
if ( ec_config . bottoming_calibration_starter [ row ] [ col ] | | ec_config . bottoming_reading [ row ] [ col ] < ( ec_config . noise_floor [ row ] [ col ] + BOTTOMING_CALIBRATION_THRESHOLD ) ) {
2024-02-26 02:05:10 +00:00
eeprom_ec_config . bottoming_reading [ row ] [ col ] = 1023 ;
} else {
eeprom_ec_config . bottoming_reading [ row ] [ col ] = ec_config . bottoming_reading [ row ] [ col ] ;
}
}
}
// Rescale the values to fit the new range for runtime usage
ec_rescale_values ( 0 ) ;
ec_rescale_values ( 1 ) ;
ec_rescale_values ( 2 ) ;
2024-10-28 19:54:05 +00:00
ec_rescale_values ( 3 ) ;
ec_rescale_values ( 4 ) ;
2024-02-26 02:05:10 +00:00
eeconfig_update_kb_datablock ( & eeprom_ec_config ) ;
}
// Show the calibration data
void ec_show_calibration_data ( void ) {
uprintf ( " \n ############### \n " ) ;
uprintf ( " # Noise Floor # \n " ) ;
uprintf ( " ############### \n " ) ;
for ( uint8_t row = 0 ; row < MATRIX_ROWS ; row + + ) {
for ( uint8_t col = 0 ; col < MATRIX_COLS - 1 ; col + + ) {
uprintf ( " %4d, " , ec_config . noise_floor [ row ] [ col ] ) ;
}
uprintf ( " %4d \n " , ec_config . noise_floor [ row ] [ MATRIX_COLS - 1 ] ) ;
}
uprintf ( " \n ###################### \n " ) ;
uprintf ( " # Bottoming Readings # \n " ) ;
uprintf ( " ###################### \n " ) ;
for ( uint8_t row = 0 ; row < MATRIX_ROWS ; row + + ) {
for ( uint8_t col = 0 ; col < MATRIX_COLS - 1 ; col + + ) {
uprintf ( " %4d, " , eeprom_ec_config . bottoming_reading [ row ] [ col ] ) ;
}
uprintf ( " %4d \n " , eeprom_ec_config . bottoming_reading [ row ] [ MATRIX_COLS - 1 ] ) ;
}
uprintf ( " \n ###################################### \n " ) ;
uprintf ( " # Rescaled APC Mode Actuation Points # \n " ) ;
uprintf ( " ###################################### \n " ) ;
uprintf ( " Original APC Mode Actuation Point: %4d \n " , ec_config . mode_0_actuation_threshold ) ;
for ( uint8_t row = 0 ; row < MATRIX_ROWS ; row + + ) {
for ( uint8_t col = 0 ; col < MATRIX_COLS - 1 ; col + + ) {
uprintf ( " %4d, " , ec_config . rescaled_mode_0_actuation_threshold [ row ] [ col ] ) ;
}
uprintf ( " %4d \n " , ec_config . rescaled_mode_0_actuation_threshold [ row ] [ MATRIX_COLS - 1 ] ) ;
}
uprintf ( " \n ###################################### \n " ) ;
uprintf ( " # Rescaled APC Mode Release Points # \n " ) ;
uprintf ( " ###################################### \n " ) ;
uprintf ( " Original APC Mode Release Point: %4d \n " , ec_config . mode_0_release_threshold ) ;
for ( uint8_t row = 0 ; row < MATRIX_ROWS ; row + + ) {
for ( uint8_t col = 0 ; col < MATRIX_COLS - 1 ; col + + ) {
uprintf ( " %4d, " , ec_config . rescaled_mode_0_release_threshold [ row ] [ col ] ) ;
}
uprintf ( " %4d \n " , ec_config . rescaled_mode_0_release_threshold [ row ] [ MATRIX_COLS - 1 ] ) ;
}
uprintf ( " \n ####################################################### \n " ) ;
uprintf ( " # Rescaled Rapid Trigger Mode Initial Deadzone Offset # \n " ) ;
uprintf ( " ####################################################### \n " ) ;
uprintf ( " Original Rapid Trigger Mode Initial Deadzone Offset: %4d \n " , ec_config . mode_1_initial_deadzone_offset ) ;
for ( uint8_t row = 0 ; row < MATRIX_ROWS ; row + + ) {
for ( uint8_t col = 0 ; col < MATRIX_COLS - 1 ; col + + ) {
uprintf ( " %4d, " , ec_config . rescaled_mode_1_initial_deadzone_offset [ row ] [ col ] ) ;
}
uprintf ( " %4d \n " , ec_config . rescaled_mode_1_initial_deadzone_offset [ row ] [ MATRIX_COLS - 1 ] ) ;
}
print ( " \n " ) ;
}
// Clear the calibration data
void ec_clear_bottoming_calibration_data ( void ) {
// Clear the EEPROM data
eeconfig_init_kb ( ) ;
// Reset the runtime values to the EEPROM values
keyboard_post_init_kb ( ) ;
uprintf ( " ###################################### \n " ) ;
uprintf ( " # Bottoming calibration data cleared # \n " ) ;
uprintf ( " ###################################### \n " ) ;
}
2024-10-28 19:54:05 +00:00
# ifdef SPLIT_KEYBOARD
void via_cmd_slave_handler ( uint8_t m2s_size , const void * m2s_buffer , uint8_t s2m_size , void * s2m_buffer ) {
if ( m2s_size = = ( RAW_EPSIZE - 2 ) ) {
via_config_set_value ( ( uint8_t * ) m2s_buffer ) ;
} else {
uprintf ( " Unexpected response in slave handler \n " ) ;
}
}
# endif
2024-02-26 02:05:10 +00:00
# endif // VIA_ENABLE