qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

via_ec.c (16676B)


      1 /* Copyright 2023 Cipulot
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     15  */
     16 #include "ec_switch_matrix.h"
     17 #include "action.h"
     18 #include "print.h"
     19 #include "via.h"
     20 
     21 #ifdef SPLIT_KEYBOARD
     22 #    include "transactions.h"
     23 #endif
     24 
     25 #ifdef VIA_ENABLE
     26 
     27 void ec_rescale_values(uint8_t item);
     28 void ec_save_threshold_data(uint8_t option);
     29 void ec_save_bottoming_reading(void);
     30 void ec_show_calibration_data(void);
     31 void ec_clear_bottoming_calibration_data(void);
     32 
     33 // Declaring enums for VIA config menu
     34 enum via_enums {
     35     // clang-format off
     36     id_actuation_mode = 1,
     37     id_mode_0_actuation_threshold = 2,
     38     id_mode_0_release_threshold = 3,
     39     id_save_threshold_data = 4,
     40     id_mode_1_initial_deadzone_offset = 5,
     41     id_mode_1_actuation_offset = 6,
     42     id_mode_1_release_offset = 7,
     43     id_bottoming_calibration = 8,
     44     id_noise_floor_calibration = 9,
     45     id_show_calibration_data = 10,
     46     id_clear_bottoming_calibration_data = 11
     47     // clang-format on
     48 };
     49 
     50 // Handle the data received by the keyboard from the VIA menus
     51 void via_config_set_value(uint8_t *data) {
     52     // data = [ value_id, value_data ]
     53     uint8_t *value_id   = &(data[0]);
     54     uint8_t *value_data = &(data[1]);
     55 
     56 #    ifdef SPLIT_KEYBOARD
     57     if (is_keyboard_master()) {
     58         transaction_rpc_send(RPC_ID_VIA_CMD, 30, data);
     59     }
     60 #    endif
     61 
     62     switch (*value_id) {
     63         case id_actuation_mode: {
     64             eeprom_ec_config.actuation_mode = value_data[0];
     65             ec_config.actuation_mode        = eeprom_ec_config.actuation_mode;
     66             if (ec_config.actuation_mode == 0) {
     67                 uprintf("#########################\n");
     68                 uprintf("#  Actuation Mode: APC  #\n");
     69                 uprintf("#########################\n");
     70             } else if (ec_config.actuation_mode == 1) {
     71                 uprintf("#################################\n");
     72                 uprintf("# Actuation Mode: Rapid Trigger #\n");
     73                 uprintf("#################################\n");
     74             }
     75             eeconfig_update_kb_datablock_field(eeprom_ec_config, actuation_mode);
     76             break;
     77         }
     78         case id_mode_0_actuation_threshold: {
     79             ec_config.mode_0_actuation_threshold = value_data[1] | (value_data[0] << 8);
     80             uprintf("APC Mode Actuation Threshold: %d\n", ec_config.mode_0_actuation_threshold);
     81             break;
     82         }
     83         case id_mode_0_release_threshold: {
     84             ec_config.mode_0_release_threshold = value_data[1] | (value_data[0] << 8);
     85             uprintf("APC Mode Release Threshold: %d\n", ec_config.mode_0_release_threshold);
     86             break;
     87         }
     88         case id_mode_1_initial_deadzone_offset: {
     89             ec_config.mode_1_initial_deadzone_offset = value_data[1] | (value_data[0] << 8);
     90             uprintf("Rapid Trigger Mode Initial Deadzone Offset: %d\n", ec_config.mode_1_initial_deadzone_offset);
     91             break;
     92         }
     93         case id_mode_1_actuation_offset: {
     94             ec_config.mode_1_actuation_offset = value_data[0];
     95             uprintf("Rapid Trigger Mode Actuation Offset: %d\n", ec_config.mode_1_actuation_offset);
     96             break;
     97         }
     98         case id_mode_1_release_offset: {
     99             ec_config.mode_1_release_offset = value_data[0];
    100             uprintf("Rapid Trigger Mode Release Offset: %d\n", ec_config.mode_1_release_offset);
    101             break;
    102         }
    103         case id_bottoming_calibration: {
    104             if (value_data[0] == 1) {
    105                 ec_config.bottoming_calibration = true;
    106                 uprintf("##############################\n");
    107                 uprintf("# Bottoming calibration mode #\n");
    108                 uprintf("##############################\n");
    109             } else {
    110                 ec_config.bottoming_calibration = false;
    111                 ec_save_bottoming_reading();
    112                 uprintf("## Bottoming calibration done ##\n");
    113                 ec_show_calibration_data();
    114             }
    115             break;
    116         }
    117         case id_save_threshold_data: {
    118             ec_save_threshold_data(value_data[0]);
    119             break;
    120         }
    121         case id_noise_floor_calibration: {
    122             if (value_data[0] == 0) {
    123                 ec_noise_floor();
    124                 ec_rescale_values(0);
    125                 ec_rescale_values(1);
    126                 ec_rescale_values(2);
    127                 ec_rescale_values(3);
    128                 ec_rescale_values(4);
    129                 uprintf("#############################\n");
    130                 uprintf("# Noise floor data acquired #\n");
    131                 uprintf("#############################\n");
    132                 break;
    133             }
    134         }
    135         case id_show_calibration_data: {
    136             if (value_data[0] == 0) {
    137                 ec_show_calibration_data();
    138             }
    139             break;
    140         }
    141         case id_clear_bottoming_calibration_data: {
    142             if (value_data[0] == 0) {
    143                 ec_clear_bottoming_calibration_data();
    144             }
    145             break;
    146         }
    147         default: {
    148             // Unhandled value.
    149             break;
    150         }
    151     }
    152 }
    153 
    154 // Handle the data sent by the keyboard to the VIA menus
    155 void via_config_get_value(uint8_t *data) {
    156     // data = [ value_id, value_data ]
    157     uint8_t *value_id   = &(data[0]);
    158     uint8_t *value_data = &(data[1]);
    159 
    160     switch (*value_id) {
    161         case id_actuation_mode: {
    162             value_data[0] = eeprom_ec_config.actuation_mode;
    163             break;
    164         }
    165         case id_mode_0_actuation_threshold: {
    166             value_data[0] = eeprom_ec_config.mode_0_actuation_threshold >> 8;
    167             value_data[1] = eeprom_ec_config.mode_0_actuation_threshold & 0xFF;
    168             break;
    169         }
    170         case id_mode_0_release_threshold: {
    171             value_data[0] = eeprom_ec_config.mode_0_release_threshold >> 8;
    172             value_data[1] = eeprom_ec_config.mode_0_release_threshold & 0xFF;
    173             break;
    174         }
    175         case id_mode_1_initial_deadzone_offset: {
    176             value_data[0] = eeprom_ec_config.mode_1_initial_deadzone_offset >> 8;
    177             value_data[1] = eeprom_ec_config.mode_1_initial_deadzone_offset & 0xFF;
    178             break;
    179         }
    180         case id_mode_1_actuation_offset: {
    181             value_data[0] = eeprom_ec_config.mode_1_actuation_offset;
    182             break;
    183         }
    184         case id_mode_1_release_offset: {
    185             value_data[0] = eeprom_ec_config.mode_1_release_offset;
    186             break;
    187         }
    188         default: {
    189             // Unhandled value.
    190             break;
    191         }
    192     }
    193 }
    194 
    195 // Handle the commands sent and received by the keyboard with VIA
    196 void via_custom_value_command_kb(uint8_t *data, uint8_t length) {
    197     // data = [ command_id, channel_id, value_id, value_data ]
    198     uint8_t *command_id        = &(data[0]);
    199     uint8_t *channel_id        = &(data[1]);
    200     uint8_t *value_id_and_data = &(data[2]);
    201 
    202     if (*channel_id == id_custom_channel) {
    203         switch (*command_id) {
    204             case id_custom_set_value: {
    205                 via_config_set_value(value_id_and_data);
    206                 break;
    207             }
    208             case id_custom_get_value: {
    209                 via_config_get_value(value_id_and_data);
    210                 break;
    211             }
    212             case id_custom_save: {
    213                 // Bypass the save function in favor of pinpointed saves
    214                 break;
    215             }
    216             default: {
    217                 // Unhandled message.
    218                 *command_id = id_unhandled;
    219                 break;
    220             }
    221         }
    222         return;
    223     }
    224 
    225     *command_id = id_unhandled;
    226 }
    227 
    228 // Rescale the values received by VIA to fit the new range
    229 void ec_rescale_values(uint8_t item) {
    230     switch (item) {
    231         // Rescale the APC mode actuation thresholds
    232         case 0:
    233             for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    234                 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
    235                     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]);
    236                 }
    237             }
    238             break;
    239         // Rescale the APC mode release thresholds
    240         case 1:
    241             for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    242                 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
    243                     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]);
    244                 }
    245             }
    246             break;
    247         // Rescale the Rapid Trigger mode initial deadzone offsets
    248         case 2:
    249             for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    250                 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
    251                     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]);
    252                 }
    253             }
    254             break;
    255         // Rescale the Rapid Trigger mode actuation offsets
    256         case 3:
    257             for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    258                 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
    259                     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]);
    260                 }
    261             }
    262             break;
    263         // Rescale the Rapid Trigger mode release offsets
    264         case 4:
    265             for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    266                 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
    267                     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]);
    268                 }
    269             }
    270             break;
    271 
    272         default:
    273             // Unhandled item.
    274             break;
    275     }
    276 }
    277 
    278 void ec_save_threshold_data(uint8_t option) {
    279     // Save APC mode thresholds and rescale them for runtime usage
    280     if (option == 0) {
    281         eeprom_ec_config.mode_0_actuation_threshold = ec_config.mode_0_actuation_threshold;
    282         eeprom_ec_config.mode_0_release_threshold   = ec_config.mode_0_release_threshold;
    283         ec_rescale_values(0);
    284         ec_rescale_values(1);
    285     }
    286     // Save Rapid Trigger mode thresholds and rescale them for runtime usage
    287     else if (option == 1) {
    288         eeprom_ec_config.mode_1_initial_deadzone_offset = ec_config.mode_1_initial_deadzone_offset;
    289         eeprom_ec_config.mode_1_actuation_offset        = ec_config.mode_1_actuation_offset;
    290         eeprom_ec_config.mode_1_release_offset          = ec_config.mode_1_release_offset;
    291         ec_rescale_values(2);
    292         ec_rescale_values(3);
    293         ec_rescale_values(4);
    294     }
    295     eeconfig_update_kb_datablock(&eeprom_ec_config, 0, EECONFIG_KB_DATA_SIZE);
    296     uprintf("####################################\n");
    297     uprintf("# New thresholds applied and saved #\n");
    298     uprintf("####################################\n");
    299 }
    300 
    301 // Save the bottoming reading
    302 void ec_save_bottoming_reading(void) {
    303     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    304         for (uint8_t col = 0; col < MATRIX_COLS; col++) {
    305             // 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.
    306             // 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:
    307             // 1. The key is part of an alternative layout and is not being pressed.
    308             // 2. The key is in the current layout but is not being pressed.
    309             // In both conditions we should set the bottoming reading to the maximum value to avoid false positives.
    310             if (ec_config.bottoming_calibration_starter[row][col] || ec_config.bottoming_reading[row][col] < (ec_config.noise_floor[row][col] + BOTTOMING_CALIBRATION_THRESHOLD)) {
    311                 eeprom_ec_config.bottoming_reading[row][col] = 1023;
    312             } else {
    313                 eeprom_ec_config.bottoming_reading[row][col] = ec_config.bottoming_reading[row][col];
    314             }
    315         }
    316     }
    317     // Rescale the values to fit the new range for runtime usage
    318     ec_rescale_values(0);
    319     ec_rescale_values(1);
    320     ec_rescale_values(2);
    321     ec_rescale_values(3);
    322     ec_rescale_values(4);
    323     eeconfig_update_kb_datablock(&eeprom_ec_config, 0, EECONFIG_KB_DATA_SIZE);
    324 }
    325 
    326 // Show the calibration data
    327 void ec_show_calibration_data(void) {
    328     uprintf("\n###############\n");
    329     uprintf("# Noise Floor #\n");
    330     uprintf("###############\n");
    331     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    332         for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) {
    333             uprintf("%4d,", ec_config.noise_floor[row][col]);
    334         }
    335         uprintf("%4d\n", ec_config.noise_floor[row][MATRIX_COLS - 1]);
    336     }
    337 
    338     uprintf("\n######################\n");
    339     uprintf("# Bottoming Readings #\n");
    340     uprintf("######################\n");
    341     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    342         for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) {
    343             uprintf("%4d,", eeprom_ec_config.bottoming_reading[row][col]);
    344         }
    345         uprintf("%4d\n", eeprom_ec_config.bottoming_reading[row][MATRIX_COLS - 1]);
    346     }
    347 
    348     uprintf("\n######################################\n");
    349     uprintf("# Rescaled APC Mode Actuation Points #\n");
    350     uprintf("######################################\n");
    351     uprintf("Original APC Mode Actuation Point: %4d\n", ec_config.mode_0_actuation_threshold);
    352     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    353         for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) {
    354             uprintf("%4d,", ec_config.rescaled_mode_0_actuation_threshold[row][col]);
    355         }
    356         uprintf("%4d\n", ec_config.rescaled_mode_0_actuation_threshold[row][MATRIX_COLS - 1]);
    357     }
    358 
    359     uprintf("\n######################################\n");
    360     uprintf("# Rescaled APC Mode Release Points   #\n");
    361     uprintf("######################################\n");
    362     uprintf("Original APC Mode Release Point: %4d\n", ec_config.mode_0_release_threshold);
    363     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    364         for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) {
    365             uprintf("%4d,", ec_config.rescaled_mode_0_release_threshold[row][col]);
    366         }
    367         uprintf("%4d\n", ec_config.rescaled_mode_0_release_threshold[row][MATRIX_COLS - 1]);
    368     }
    369 
    370     uprintf("\n#######################################################\n");
    371     uprintf("# Rescaled Rapid Trigger Mode Initial Deadzone Offset #\n");
    372     uprintf("#######################################################\n");
    373     uprintf("Original Rapid Trigger Mode Initial Deadzone Offset: %4d\n", ec_config.mode_1_initial_deadzone_offset);
    374     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    375         for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) {
    376             uprintf("%4d,", ec_config.rescaled_mode_1_initial_deadzone_offset[row][col]);
    377         }
    378         uprintf("%4d\n", ec_config.rescaled_mode_1_initial_deadzone_offset[row][MATRIX_COLS - 1]);
    379     }
    380     print("\n");
    381 }
    382 
    383 // Clear the calibration data
    384 void ec_clear_bottoming_calibration_data(void) {
    385     // Clear the EEPROM data
    386     eeconfig_init_kb();
    387 
    388     // Reset the runtime values to the EEPROM values
    389     keyboard_post_init_kb();
    390 
    391     uprintf("######################################\n");
    392     uprintf("# Bottoming calibration data cleared #\n");
    393     uprintf("######################################\n");
    394 }
    395 
    396 #    ifdef SPLIT_KEYBOARD
    397 void via_cmd_slave_handler(uint8_t m2s_size, const void *m2s_buffer, uint8_t s2m_size, void *s2m_buffer) {
    398     if (m2s_size == (RAW_EPSIZE-2)) {
    399         via_config_set_value((uint8_t *)m2s_buffer);
    400     } else {
    401         uprintf("Unexpected response in slave handler\n");
    402     }
    403 }
    404 #    endif
    405 
    406 #endif // VIA_ENABLE