2021-06-17 23:10:06 +00:00
|
|
|
/* Copyright 2021 QMK
|
|
|
|
*
|
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
2024-03-10 11:24:17 +00:00
|
|
|
#include <stdint.h>
|
2021-06-17 23:10:06 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
|
2021-07-02 21:28:32 +00:00
|
|
|
#include "crc.h"
|
2021-06-17 23:10:06 +00:00
|
|
|
#include "debug.h"
|
|
|
|
#include "matrix.h"
|
2023-07-16 13:42:56 +00:00
|
|
|
#include "host.h"
|
|
|
|
#include "action_util.h"
|
|
|
|
#include "sync_timer.h"
|
|
|
|
#include "wait.h"
|
2021-06-17 23:10:06 +00:00
|
|
|
#include "transactions.h"
|
|
|
|
#include "transport.h"
|
|
|
|
#include "transaction_id_define.h"
|
2022-04-19 10:56:16 +00:00
|
|
|
#include "split_util.h"
|
|
|
|
#include "synchronization_util.h"
|
2021-06-17 23:10:06 +00:00
|
|
|
|
2023-07-16 13:42:56 +00:00
|
|
|
#ifdef BACKLIGHT_ENABLE
|
|
|
|
# include "backlight.h"
|
|
|
|
#endif
|
|
|
|
#ifdef RGBLIGHT_ENABLE
|
|
|
|
# include "rgblight.h"
|
|
|
|
#endif
|
|
|
|
#ifdef LED_MATRIX_ENABLE
|
|
|
|
# include "led_matrix.h"
|
|
|
|
#endif
|
|
|
|
#ifdef RGB_MATRIX_ENABLE
|
|
|
|
# include "rgb_matrix.h"
|
|
|
|
#endif
|
|
|
|
#ifdef OLED_ENABLE
|
|
|
|
# include "oled_driver.h"
|
|
|
|
#endif
|
|
|
|
#ifdef ST7565_ENABLE
|
|
|
|
# include "st7565.h"
|
|
|
|
#endif
|
|
|
|
#ifdef ENCODER_ENABLE
|
|
|
|
# include "encoder.h"
|
|
|
|
#endif
|
|
|
|
#ifdef HAPTIC_ENABLE
|
|
|
|
# include "haptic.h"
|
|
|
|
#endif
|
|
|
|
#ifdef POINTING_DEVICE_ENABLE
|
|
|
|
# include "pointing_device.h"
|
|
|
|
#endif
|
|
|
|
#ifdef OS_DETECTION_ENABLE
|
|
|
|
# include "os_detection.h"
|
|
|
|
#endif
|
|
|
|
#ifdef WPM_ENABLE
|
|
|
|
# include "wpm.h"
|
|
|
|
#endif
|
|
|
|
|
2021-06-17 23:10:06 +00:00
|
|
|
#define SYNC_TIMER_OFFSET 2
|
|
|
|
|
|
|
|
#ifndef FORCED_SYNC_THROTTLE_MS
|
|
|
|
# define FORCED_SYNC_THROTTLE_MS 100
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // FORCED_SYNC_THROTTLE_MS
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
#define sizeof_member(type, member) sizeof(((type *)NULL)->member)
|
|
|
|
|
|
|
|
#define trans_initiator2target_initializer_cb(member, cb) \
|
2022-01-27 05:13:27 +00:00
|
|
|
{ sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), 0, 0, cb }
|
2021-06-17 23:10:06 +00:00
|
|
|
#define trans_initiator2target_initializer(member) trans_initiator2target_initializer_cb(member, NULL)
|
|
|
|
|
|
|
|
#define trans_target2initiator_initializer_cb(member, cb) \
|
2022-01-27 05:13:27 +00:00
|
|
|
{ 0, 0, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), cb }
|
2021-06-17 23:10:06 +00:00
|
|
|
#define trans_target2initiator_initializer(member) trans_target2initiator_initializer_cb(member, NULL)
|
|
|
|
|
2024-03-10 11:24:17 +00:00
|
|
|
#define trans_initiator2target_cb(cb) \
|
|
|
|
{ 0, 0, 0, 0, cb }
|
|
|
|
|
2021-11-01 19:18:33 +00:00
|
|
|
#define transport_write(id, data, length) transport_execute_transaction(id, data, length, NULL, 0)
|
|
|
|
#define transport_read(id, data, length) transport_execute_transaction(id, NULL, 0, data, length)
|
2024-03-10 11:24:17 +00:00
|
|
|
#define transport_exec(id) transport_execute_transaction(id, NULL, 0, NULL, 0)
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
|
|
|
|
// Forward-declare the RPC callback handlers
|
|
|
|
void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
|
|
|
|
void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// Helpers
|
|
|
|
|
Make solo half of split keyboards (more) usable. (#13523)
* Make solo half of split keyboards (more) usable.
Using only one half of a split keyboard (that's using the split_common
framework to communicate) is not a great experience, since several read
timeouts per scan cycle cause an unusably slow scan rate.
This change blocks all split communication attempts for 500 ms
(configurable) after an error occurs, causing the scan rate to become at
least _more_ usable, but might need some tweaking to work fully on most
keyboards. One read timeout still needs to occur after the 500 ms has
passed, and if that timeout isn't low enough, some scan cycles may still
be too slow.
* Fix lint complaint.
* Require 25 consecutive comm errors to see comms as disconnected.
The number of max errors can be overridden by defining
`SPLIT_MAX_CONNECTION_ERRORS`.
* Add comments to new defines, and ability to disable disconnection check.
Also increase `SPLIT_MAX_CONNECTION_ERRORS` to 40, since it's divisible
by most relevant numbers for the description.
* Make lint happy ...again
* Only update `connection_check_timer` when needed.
* Add new defines to split keyboard documentation.
* Move connection timeout logic to transport.c, add `is_transport_connected`.
* Use split_common disconnection logic in matrix.c.
Instead of doing more or less the same thing twice.
* Move disconnection logic to `transport_master`.
Is a cleaner implementation, and causes the scan rate while disconnected
to increase instead of decrease.
* Lint fixes.
* Lower default `SERIAL_USART_TIMEOUT` to 20 ms.
The read timeout must be low enough to not cause exessively long scan
cycles when using a solo split half. 10 ms was determined from testing
to work fine even with the slowest defined baudrate of 19200 (5 ms was
too low for that case), so 20 ms should be fine for most cases.
* Remove `SERIAL_USART_TIMEOUT` from ergodox_infinity/config.h
Was somewhat mistakenly included in an earlier PR.
* Fix building with `USE_I2C`.
* Reduce built firmware size.
Not really sure why this works, the idea was taken from tzarc's work on
split disconnection.
* Tweak and improve opt-out for split disconnection logic.
There are now two ways to opt out from this feature:
* Set `SPLIT_MAX_CONNECTION_ERRORS` to 0. This will completely disable
the connection status checks (also affects the slave matrix reset logic in
matrix.c, though).
* Set `SPLIT_CONNECTION_CHECK_TIMEOUT` to 0. This will only disable the
communication throttling while disconnected. Will make the firmware
smaller.
* Make split disconnection logic work with custom transports.
Includes a fallback implementation for keyboards using a custom
split_util.c but not a custom matrix.c (currently no such keyboard seems
to be merged, though).
* Remove unnecessary include of timer.h
Co-authored-by: Joel Challis <git@zvecr.com>
Co-authored-by: Joel Challis <git@zvecr.com>
2021-08-22 00:51:17 +00:00
|
|
|
static bool transaction_handler_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[], const char *prefix, bool (*handler)(matrix_row_t master_matrix[], matrix_row_t slave_matrix[])) {
|
|
|
|
int num_retries = is_transport_connected() ? 10 : 1;
|
|
|
|
for (int iter = 1; iter <= num_retries; ++iter) {
|
|
|
|
if (iter > 1) {
|
|
|
|
for (int i = 0; i < iter * iter; ++i) {
|
|
|
|
wait_us(10);
|
2021-06-17 23:10:06 +00:00
|
|
|
}
|
|
|
|
}
|
Make solo half of split keyboards (more) usable. (#13523)
* Make solo half of split keyboards (more) usable.
Using only one half of a split keyboard (that's using the split_common
framework to communicate) is not a great experience, since several read
timeouts per scan cycle cause an unusably slow scan rate.
This change blocks all split communication attempts for 500 ms
(configurable) after an error occurs, causing the scan rate to become at
least _more_ usable, but might need some tweaking to work fully on most
keyboards. One read timeout still needs to occur after the 500 ms has
passed, and if that timeout isn't low enough, some scan cycles may still
be too slow.
* Fix lint complaint.
* Require 25 consecutive comm errors to see comms as disconnected.
The number of max errors can be overridden by defining
`SPLIT_MAX_CONNECTION_ERRORS`.
* Add comments to new defines, and ability to disable disconnection check.
Also increase `SPLIT_MAX_CONNECTION_ERRORS` to 40, since it's divisible
by most relevant numbers for the description.
* Make lint happy ...again
* Only update `connection_check_timer` when needed.
* Add new defines to split keyboard documentation.
* Move connection timeout logic to transport.c, add `is_transport_connected`.
* Use split_common disconnection logic in matrix.c.
Instead of doing more or less the same thing twice.
* Move disconnection logic to `transport_master`.
Is a cleaner implementation, and causes the scan rate while disconnected
to increase instead of decrease.
* Lint fixes.
* Lower default `SERIAL_USART_TIMEOUT` to 20 ms.
The read timeout must be low enough to not cause exessively long scan
cycles when using a solo split half. 10 ms was determined from testing
to work fine even with the slowest defined baudrate of 19200 (5 ms was
too low for that case), so 20 ms should be fine for most cases.
* Remove `SERIAL_USART_TIMEOUT` from ergodox_infinity/config.h
Was somewhat mistakenly included in an earlier PR.
* Fix building with `USE_I2C`.
* Reduce built firmware size.
Not really sure why this works, the idea was taken from tzarc's work on
split disconnection.
* Tweak and improve opt-out for split disconnection logic.
There are now two ways to opt out from this feature:
* Set `SPLIT_MAX_CONNECTION_ERRORS` to 0. This will completely disable
the connection status checks (also affects the slave matrix reset logic in
matrix.c, though).
* Set `SPLIT_CONNECTION_CHECK_TIMEOUT` to 0. This will only disable the
communication throttling while disconnected. Will make the firmware
smaller.
* Make split disconnection logic work with custom transports.
Includes a fallback implementation for keyboards using a custom
split_util.c but not a custom matrix.c (currently no such keyboard seems
to be merged, though).
* Remove unnecessary include of timer.h
Co-authored-by: Joel Challis <git@zvecr.com>
Co-authored-by: Joel Challis <git@zvecr.com>
2021-08-22 00:51:17 +00:00
|
|
|
bool this_okay = true;
|
2022-04-19 10:56:16 +00:00
|
|
|
this_okay = handler(master_matrix, slave_matrix);
|
Make solo half of split keyboards (more) usable. (#13523)
* Make solo half of split keyboards (more) usable.
Using only one half of a split keyboard (that's using the split_common
framework to communicate) is not a great experience, since several read
timeouts per scan cycle cause an unusably slow scan rate.
This change blocks all split communication attempts for 500 ms
(configurable) after an error occurs, causing the scan rate to become at
least _more_ usable, but might need some tweaking to work fully on most
keyboards. One read timeout still needs to occur after the 500 ms has
passed, and if that timeout isn't low enough, some scan cycles may still
be too slow.
* Fix lint complaint.
* Require 25 consecutive comm errors to see comms as disconnected.
The number of max errors can be overridden by defining
`SPLIT_MAX_CONNECTION_ERRORS`.
* Add comments to new defines, and ability to disable disconnection check.
Also increase `SPLIT_MAX_CONNECTION_ERRORS` to 40, since it's divisible
by most relevant numbers for the description.
* Make lint happy ...again
* Only update `connection_check_timer` when needed.
* Add new defines to split keyboard documentation.
* Move connection timeout logic to transport.c, add `is_transport_connected`.
* Use split_common disconnection logic in matrix.c.
Instead of doing more or less the same thing twice.
* Move disconnection logic to `transport_master`.
Is a cleaner implementation, and causes the scan rate while disconnected
to increase instead of decrease.
* Lint fixes.
* Lower default `SERIAL_USART_TIMEOUT` to 20 ms.
The read timeout must be low enough to not cause exessively long scan
cycles when using a solo split half. 10 ms was determined from testing
to work fine even with the slowest defined baudrate of 19200 (5 ms was
too low for that case), so 20 ms should be fine for most cases.
* Remove `SERIAL_USART_TIMEOUT` from ergodox_infinity/config.h
Was somewhat mistakenly included in an earlier PR.
* Fix building with `USE_I2C`.
* Reduce built firmware size.
Not really sure why this works, the idea was taken from tzarc's work on
split disconnection.
* Tweak and improve opt-out for split disconnection logic.
There are now two ways to opt out from this feature:
* Set `SPLIT_MAX_CONNECTION_ERRORS` to 0. This will completely disable
the connection status checks (also affects the slave matrix reset logic in
matrix.c, though).
* Set `SPLIT_CONNECTION_CHECK_TIMEOUT` to 0. This will only disable the
communication throttling while disconnected. Will make the firmware
smaller.
* Make split disconnection logic work with custom transports.
Includes a fallback implementation for keyboards using a custom
split_util.c but not a custom matrix.c (currently no such keyboard seems
to be merged, though).
* Remove unnecessary include of timer.h
Co-authored-by: Joel Challis <git@zvecr.com>
Co-authored-by: Joel Challis <git@zvecr.com>
2021-08-22 00:51:17 +00:00
|
|
|
if (this_okay) return true;
|
2021-06-17 23:10:06 +00:00
|
|
|
}
|
Make solo half of split keyboards (more) usable. (#13523)
* Make solo half of split keyboards (more) usable.
Using only one half of a split keyboard (that's using the split_common
framework to communicate) is not a great experience, since several read
timeouts per scan cycle cause an unusably slow scan rate.
This change blocks all split communication attempts for 500 ms
(configurable) after an error occurs, causing the scan rate to become at
least _more_ usable, but might need some tweaking to work fully on most
keyboards. One read timeout still needs to occur after the 500 ms has
passed, and if that timeout isn't low enough, some scan cycles may still
be too slow.
* Fix lint complaint.
* Require 25 consecutive comm errors to see comms as disconnected.
The number of max errors can be overridden by defining
`SPLIT_MAX_CONNECTION_ERRORS`.
* Add comments to new defines, and ability to disable disconnection check.
Also increase `SPLIT_MAX_CONNECTION_ERRORS` to 40, since it's divisible
by most relevant numbers for the description.
* Make lint happy ...again
* Only update `connection_check_timer` when needed.
* Add new defines to split keyboard documentation.
* Move connection timeout logic to transport.c, add `is_transport_connected`.
* Use split_common disconnection logic in matrix.c.
Instead of doing more or less the same thing twice.
* Move disconnection logic to `transport_master`.
Is a cleaner implementation, and causes the scan rate while disconnected
to increase instead of decrease.
* Lint fixes.
* Lower default `SERIAL_USART_TIMEOUT` to 20 ms.
The read timeout must be low enough to not cause exessively long scan
cycles when using a solo split half. 10 ms was determined from testing
to work fine even with the slowest defined baudrate of 19200 (5 ms was
too low for that case), so 20 ms should be fine for most cases.
* Remove `SERIAL_USART_TIMEOUT` from ergodox_infinity/config.h
Was somewhat mistakenly included in an earlier PR.
* Fix building with `USE_I2C`.
* Reduce built firmware size.
Not really sure why this works, the idea was taken from tzarc's work on
split disconnection.
* Tweak and improve opt-out for split disconnection logic.
There are now two ways to opt out from this feature:
* Set `SPLIT_MAX_CONNECTION_ERRORS` to 0. This will completely disable
the connection status checks (also affects the slave matrix reset logic in
matrix.c, though).
* Set `SPLIT_CONNECTION_CHECK_TIMEOUT` to 0. This will only disable the
communication throttling while disconnected. Will make the firmware
smaller.
* Make split disconnection logic work with custom transports.
Includes a fallback implementation for keyboards using a custom
split_util.c but not a custom matrix.c (currently no such keyboard seems
to be merged, though).
* Remove unnecessary include of timer.h
Co-authored-by: Joel Challis <git@zvecr.com>
Co-authored-by: Joel Challis <git@zvecr.com>
2021-08-22 00:51:17 +00:00
|
|
|
dprintf("Failed to execute %s\n", prefix);
|
|
|
|
return false;
|
2021-06-17 23:10:06 +00:00
|
|
|
}
|
|
|
|
|
Make solo half of split keyboards (more) usable. (#13523)
* Make solo half of split keyboards (more) usable.
Using only one half of a split keyboard (that's using the split_common
framework to communicate) is not a great experience, since several read
timeouts per scan cycle cause an unusably slow scan rate.
This change blocks all split communication attempts for 500 ms
(configurable) after an error occurs, causing the scan rate to become at
least _more_ usable, but might need some tweaking to work fully on most
keyboards. One read timeout still needs to occur after the 500 ms has
passed, and if that timeout isn't low enough, some scan cycles may still
be too slow.
* Fix lint complaint.
* Require 25 consecutive comm errors to see comms as disconnected.
The number of max errors can be overridden by defining
`SPLIT_MAX_CONNECTION_ERRORS`.
* Add comments to new defines, and ability to disable disconnection check.
Also increase `SPLIT_MAX_CONNECTION_ERRORS` to 40, since it's divisible
by most relevant numbers for the description.
* Make lint happy ...again
* Only update `connection_check_timer` when needed.
* Add new defines to split keyboard documentation.
* Move connection timeout logic to transport.c, add `is_transport_connected`.
* Use split_common disconnection logic in matrix.c.
Instead of doing more or less the same thing twice.
* Move disconnection logic to `transport_master`.
Is a cleaner implementation, and causes the scan rate while disconnected
to increase instead of decrease.
* Lint fixes.
* Lower default `SERIAL_USART_TIMEOUT` to 20 ms.
The read timeout must be low enough to not cause exessively long scan
cycles when using a solo split half. 10 ms was determined from testing
to work fine even with the slowest defined baudrate of 19200 (5 ms was
too low for that case), so 20 ms should be fine for most cases.
* Remove `SERIAL_USART_TIMEOUT` from ergodox_infinity/config.h
Was somewhat mistakenly included in an earlier PR.
* Fix building with `USE_I2C`.
* Reduce built firmware size.
Not really sure why this works, the idea was taken from tzarc's work on
split disconnection.
* Tweak and improve opt-out for split disconnection logic.
There are now two ways to opt out from this feature:
* Set `SPLIT_MAX_CONNECTION_ERRORS` to 0. This will completely disable
the connection status checks (also affects the slave matrix reset logic in
matrix.c, though).
* Set `SPLIT_CONNECTION_CHECK_TIMEOUT` to 0. This will only disable the
communication throttling while disconnected. Will make the firmware
smaller.
* Make split disconnection logic work with custom transports.
Includes a fallback implementation for keyboards using a custom
split_util.c but not a custom matrix.c (currently no such keyboard seems
to be merged, though).
* Remove unnecessary include of timer.h
Co-authored-by: Joel Challis <git@zvecr.com>
Co-authored-by: Joel Challis <git@zvecr.com>
2021-08-22 00:51:17 +00:00
|
|
|
#define TRANSACTION_HANDLER_MASTER(prefix) \
|
|
|
|
do { \
|
|
|
|
if (!transaction_handler_master(master_matrix, slave_matrix, #prefix, &prefix##_handlers_master)) return false; \
|
2021-06-17 23:10:06 +00:00
|
|
|
} while (0)
|
|
|
|
|
2022-10-04 18:49:29 +00:00
|
|
|
/**
|
|
|
|
* @brief Constructs a transaction handler that doesn't acquire a lock to the
|
|
|
|
* split shared memory. Therefore the locking and unlocking has to be done
|
|
|
|
* manually inside the handler. Use this macro only if the handler is
|
|
|
|
* non-deterministic in runtime and thus needs a manual lock unlock
|
|
|
|
* implementation to hold the lock for the shortest possible time.
|
|
|
|
*/
|
2022-04-19 10:56:16 +00:00
|
|
|
#define TRANSACTION_HANDLER_SLAVE(prefix) \
|
2022-10-04 18:49:29 +00:00
|
|
|
do { \
|
|
|
|
prefix##_handlers_slave(master_matrix, slave_matrix); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Constructs a transaction handler that automatically acquires a lock to
|
|
|
|
* safely access the split shared memory and releases the lock again after
|
|
|
|
* processing the handler. Use this macro if the handler is fast and
|
|
|
|
* deterministic in runtime and thus holds the lock only for a very short time.
|
|
|
|
* If not fallback to manually locking and unlocking inside the handler.
|
|
|
|
*/
|
|
|
|
#define TRANSACTION_HANDLER_SLAVE_AUTOLOCK(prefix) \
|
2022-04-19 10:56:16 +00:00
|
|
|
do { \
|
|
|
|
split_shared_memory_lock(); \
|
|
|
|
prefix##_handlers_slave(master_matrix, slave_matrix); \
|
|
|
|
split_shared_memory_unlock(); \
|
2021-06-17 23:10:06 +00:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
inline static bool read_if_checksum_mismatch(int8_t trans_id_checksum, int8_t trans_id_retrieve, uint32_t *last_update, void *destination, const void *equiv_shmem, size_t length) {
|
|
|
|
uint8_t curr_checksum;
|
|
|
|
bool okay = transport_read(trans_id_checksum, &curr_checksum, sizeof(curr_checksum));
|
|
|
|
if (okay && (timer_elapsed32(*last_update) >= FORCED_SYNC_THROTTLE_MS || curr_checksum != crc8(equiv_shmem, length))) {
|
|
|
|
okay &= transport_read(trans_id_retrieve, destination, length);
|
|
|
|
okay &= curr_checksum == crc8(equiv_shmem, length);
|
|
|
|
if (okay) {
|
|
|
|
*last_update = timer_read32();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
memcpy(destination, equiv_shmem, length);
|
|
|
|
}
|
|
|
|
return okay;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline static bool send_if_condition(int8_t trans_id, uint32_t *last_update, bool condition, void *source, size_t length) {
|
|
|
|
bool okay = true;
|
|
|
|
if (timer_elapsed32(*last_update) >= FORCED_SYNC_THROTTLE_MS || condition) {
|
|
|
|
okay &= transport_write(trans_id, source, length);
|
|
|
|
if (okay) {
|
|
|
|
*last_update = timer_read32();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return okay;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline static bool send_if_data_mismatch(int8_t trans_id, uint32_t *last_update, void *source, const void *equiv_shmem, size_t length) {
|
|
|
|
// Just run a memcmp to compare the source and equivalent shmem location
|
|
|
|
return send_if_condition(trans_id, last_update, (memcmp(source, equiv_shmem, length) != 0), source, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// Slave matrix
|
|
|
|
|
|
|
|
static bool slave_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_update = 0;
|
2022-02-12 18:29:31 +00:00
|
|
|
static matrix_row_t last_matrix[(MATRIX_ROWS) / 2] = {0}; // last successfully-read matrix, so we can replicate if there are checksum errors
|
|
|
|
matrix_row_t temp_matrix[(MATRIX_ROWS) / 2]; // holding area while we test whether or not checksum is correct
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
bool okay = read_if_checksum_mismatch(GET_SLAVE_MATRIX_CHECKSUM, GET_SLAVE_MATRIX_DATA, &last_update, temp_matrix, split_shmem->smatrix.matrix, sizeof(split_shmem->smatrix.matrix));
|
|
|
|
if (okay) {
|
|
|
|
// Checksum matches the received data, save as the last matrix state
|
|
|
|
memcpy(last_matrix, temp_matrix, sizeof(temp_matrix));
|
|
|
|
}
|
|
|
|
// Copy out the last-known-good matrix state to the slave matrix
|
|
|
|
memcpy(slave_matrix, last_matrix, sizeof(last_matrix));
|
|
|
|
return okay;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void slave_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
memcpy(split_shmem->smatrix.matrix, slave_matrix, sizeof(split_shmem->smatrix.matrix));
|
|
|
|
split_shmem->smatrix.checksum = crc8(split_shmem->smatrix.matrix, sizeof(split_shmem->smatrix.matrix));
|
|
|
|
}
|
|
|
|
|
|
|
|
// clang-format off
|
Make solo half of split keyboards (more) usable. (#13523)
* Make solo half of split keyboards (more) usable.
Using only one half of a split keyboard (that's using the split_common
framework to communicate) is not a great experience, since several read
timeouts per scan cycle cause an unusably slow scan rate.
This change blocks all split communication attempts for 500 ms
(configurable) after an error occurs, causing the scan rate to become at
least _more_ usable, but might need some tweaking to work fully on most
keyboards. One read timeout still needs to occur after the 500 ms has
passed, and if that timeout isn't low enough, some scan cycles may still
be too slow.
* Fix lint complaint.
* Require 25 consecutive comm errors to see comms as disconnected.
The number of max errors can be overridden by defining
`SPLIT_MAX_CONNECTION_ERRORS`.
* Add comments to new defines, and ability to disable disconnection check.
Also increase `SPLIT_MAX_CONNECTION_ERRORS` to 40, since it's divisible
by most relevant numbers for the description.
* Make lint happy ...again
* Only update `connection_check_timer` when needed.
* Add new defines to split keyboard documentation.
* Move connection timeout logic to transport.c, add `is_transport_connected`.
* Use split_common disconnection logic in matrix.c.
Instead of doing more or less the same thing twice.
* Move disconnection logic to `transport_master`.
Is a cleaner implementation, and causes the scan rate while disconnected
to increase instead of decrease.
* Lint fixes.
* Lower default `SERIAL_USART_TIMEOUT` to 20 ms.
The read timeout must be low enough to not cause exessively long scan
cycles when using a solo split half. 10 ms was determined from testing
to work fine even with the slowest defined baudrate of 19200 (5 ms was
too low for that case), so 20 ms should be fine for most cases.
* Remove `SERIAL_USART_TIMEOUT` from ergodox_infinity/config.h
Was somewhat mistakenly included in an earlier PR.
* Fix building with `USE_I2C`.
* Reduce built firmware size.
Not really sure why this works, the idea was taken from tzarc's work on
split disconnection.
* Tweak and improve opt-out for split disconnection logic.
There are now two ways to opt out from this feature:
* Set `SPLIT_MAX_CONNECTION_ERRORS` to 0. This will completely disable
the connection status checks (also affects the slave matrix reset logic in
matrix.c, though).
* Set `SPLIT_CONNECTION_CHECK_TIMEOUT` to 0. This will only disable the
communication throttling while disconnected. Will make the firmware
smaller.
* Make split disconnection logic work with custom transports.
Includes a fallback implementation for keyboards using a custom
split_util.c but not a custom matrix.c (currently no such keyboard seems
to be merged, though).
* Remove unnecessary include of timer.h
Co-authored-by: Joel Challis <git@zvecr.com>
Co-authored-by: Joel Challis <git@zvecr.com>
2021-08-22 00:51:17 +00:00
|
|
|
#define TRANSACTIONS_SLAVE_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(slave_matrix)
|
2022-10-04 18:49:29 +00:00
|
|
|
#define TRANSACTIONS_SLAVE_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(slave_matrix)
|
2021-06-17 23:10:06 +00:00
|
|
|
#define TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS \
|
|
|
|
[GET_SLAVE_MATRIX_CHECKSUM] = trans_target2initiator_initializer(smatrix.checksum), \
|
|
|
|
[GET_SLAVE_MATRIX_DATA] = trans_target2initiator_initializer(smatrix.matrix),
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// Master matrix
|
|
|
|
|
|
|
|
#ifdef SPLIT_TRANSPORT_MIRROR
|
|
|
|
|
|
|
|
static bool master_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_update = 0;
|
|
|
|
return send_if_data_mismatch(PUT_MASTER_MATRIX, &last_update, master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void master_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
// Always copy to the master matrix
|
|
|
|
memcpy(master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix));
|
|
|
|
}
|
|
|
|
|
2021-11-01 19:18:33 +00:00
|
|
|
# define TRANSACTIONS_MASTER_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(master_matrix)
|
2022-10-04 18:49:29 +00:00
|
|
|
# define TRANSACTIONS_MASTER_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(master_matrix)
|
2021-06-17 23:10:06 +00:00
|
|
|
# define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS [PUT_MASTER_MATRIX] = trans_initiator2target_initializer(mmatrix.matrix),
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#else // SPLIT_TRANSPORT_MIRROR
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
# define TRANSACTIONS_MASTER_MATRIX_MASTER()
|
|
|
|
# define TRANSACTIONS_MASTER_MATRIX_SLAVE()
|
|
|
|
# define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // SPLIT_TRANSPORT_MIRROR
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// Encoders
|
|
|
|
|
|
|
|
#ifdef ENCODER_ENABLE
|
|
|
|
|
|
|
|
static bool encoder_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
2024-03-10 11:24:17 +00:00
|
|
|
static uint32_t last_update = 0;
|
|
|
|
static uint8_t last_checksum = 0;
|
2024-02-18 10:17:15 +00:00
|
|
|
encoder_events_t temp_events;
|
2021-06-17 23:10:06 +00:00
|
|
|
|
2024-02-18 10:17:15 +00:00
|
|
|
bool okay = read_if_checksum_mismatch(GET_ENCODERS_CHECKSUM, GET_ENCODERS_DATA, &last_update, &temp_events, &split_shmem->encoders.events, sizeof(temp_events));
|
|
|
|
if (okay) {
|
2024-03-10 11:24:17 +00:00
|
|
|
if (last_checksum != split_shmem->encoders.checksum) {
|
|
|
|
bool actioned = false;
|
|
|
|
uint8_t index;
|
|
|
|
bool clockwise;
|
|
|
|
while (okay && encoder_dequeue_event_advanced(&split_shmem->encoders.events, &index, &clockwise)) {
|
|
|
|
okay &= encoder_queue_event(index, clockwise);
|
|
|
|
actioned = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (actioned) {
|
|
|
|
okay &= transport_exec(CMD_ENCODER_DRAIN);
|
|
|
|
}
|
|
|
|
last_checksum = split_shmem->encoders.checksum;
|
|
|
|
}
|
2024-02-18 10:17:15 +00:00
|
|
|
}
|
2021-06-17 23:10:06 +00:00
|
|
|
return okay;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void encoder_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
// Always prepare the encoder state for read.
|
2024-02-18 10:17:15 +00:00
|
|
|
encoder_retrieve_events(&split_shmem->encoders.events);
|
2021-06-17 23:10:06 +00:00
|
|
|
// Now update the checksum given that the encoders has been written to
|
2024-02-18 10:17:15 +00:00
|
|
|
split_shmem->encoders.checksum = crc8(&split_shmem->encoders.events, sizeof(split_shmem->encoders.events));
|
|
|
|
}
|
|
|
|
|
2024-03-10 11:24:17 +00:00
|
|
|
static void encoder_handlers_slave_drain(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
|
|
|
|
encoder_signal_queue_drain();
|
2021-06-17 23:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// clang-format off
|
Make solo half of split keyboards (more) usable. (#13523)
* Make solo half of split keyboards (more) usable.
Using only one half of a split keyboard (that's using the split_common
framework to communicate) is not a great experience, since several read
timeouts per scan cycle cause an unusably slow scan rate.
This change blocks all split communication attempts for 500 ms
(configurable) after an error occurs, causing the scan rate to become at
least _more_ usable, but might need some tweaking to work fully on most
keyboards. One read timeout still needs to occur after the 500 ms has
passed, and if that timeout isn't low enough, some scan cycles may still
be too slow.
* Fix lint complaint.
* Require 25 consecutive comm errors to see comms as disconnected.
The number of max errors can be overridden by defining
`SPLIT_MAX_CONNECTION_ERRORS`.
* Add comments to new defines, and ability to disable disconnection check.
Also increase `SPLIT_MAX_CONNECTION_ERRORS` to 40, since it's divisible
by most relevant numbers for the description.
* Make lint happy ...again
* Only update `connection_check_timer` when needed.
* Add new defines to split keyboard documentation.
* Move connection timeout logic to transport.c, add `is_transport_connected`.
* Use split_common disconnection logic in matrix.c.
Instead of doing more or less the same thing twice.
* Move disconnection logic to `transport_master`.
Is a cleaner implementation, and causes the scan rate while disconnected
to increase instead of decrease.
* Lint fixes.
* Lower default `SERIAL_USART_TIMEOUT` to 20 ms.
The read timeout must be low enough to not cause exessively long scan
cycles when using a solo split half. 10 ms was determined from testing
to work fine even with the slowest defined baudrate of 19200 (5 ms was
too low for that case), so 20 ms should be fine for most cases.
* Remove `SERIAL_USART_TIMEOUT` from ergodox_infinity/config.h
Was somewhat mistakenly included in an earlier PR.
* Fix building with `USE_I2C`.
* Reduce built firmware size.
Not really sure why this works, the idea was taken from tzarc's work on
split disconnection.
* Tweak and improve opt-out for split disconnection logic.
There are now two ways to opt out from this feature:
* Set `SPLIT_MAX_CONNECTION_ERRORS` to 0. This will completely disable
the connection status checks (also affects the slave matrix reset logic in
matrix.c, though).
* Set `SPLIT_CONNECTION_CHECK_TIMEOUT` to 0. This will only disable the
communication throttling while disconnected. Will make the firmware
smaller.
* Make split disconnection logic work with custom transports.
Includes a fallback implementation for keyboards using a custom
split_util.c but not a custom matrix.c (currently no such keyboard seems
to be merged, though).
* Remove unnecessary include of timer.h
Co-authored-by: Joel Challis <git@zvecr.com>
Co-authored-by: Joel Challis <git@zvecr.com>
2021-08-22 00:51:17 +00:00
|
|
|
# define TRANSACTIONS_ENCODERS_MASTER() TRANSACTION_HANDLER_MASTER(encoder)
|
2022-10-04 18:49:29 +00:00
|
|
|
# define TRANSACTIONS_ENCODERS_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(encoder)
|
2021-06-17 23:10:06 +00:00
|
|
|
# define TRANSACTIONS_ENCODERS_REGISTRATIONS \
|
|
|
|
[GET_ENCODERS_CHECKSUM] = trans_target2initiator_initializer(encoders.checksum), \
|
2024-02-18 10:17:15 +00:00
|
|
|
[GET_ENCODERS_DATA] = trans_target2initiator_initializer(encoders.events), \
|
2024-03-10 11:24:17 +00:00
|
|
|
[CMD_ENCODER_DRAIN] = trans_initiator2target_cb(encoder_handlers_slave_drain),
|
2021-06-17 23:10:06 +00:00
|
|
|
// clang-format on
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#else // ENCODER_ENABLE
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
# define TRANSACTIONS_ENCODERS_MASTER()
|
|
|
|
# define TRANSACTIONS_ENCODERS_SLAVE()
|
|
|
|
# define TRANSACTIONS_ENCODERS_REGISTRATIONS
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // ENCODER_ENABLE
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// Sync timer
|
|
|
|
|
|
|
|
#ifndef DISABLE_SYNC_TIMER
|
|
|
|
|
|
|
|
static bool sync_timer_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_update = 0;
|
|
|
|
|
|
|
|
bool okay = true;
|
|
|
|
if (timer_elapsed32(last_update) >= FORCED_SYNC_THROTTLE_MS) {
|
|
|
|
uint32_t sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
|
|
|
|
okay &= transport_write(PUT_SYNC_TIMER, &sync_timer, sizeof(sync_timer));
|
|
|
|
if (okay) {
|
|
|
|
last_update = timer_read32();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return okay;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sync_timer_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_sync_timer = 0;
|
|
|
|
if (last_sync_timer != split_shmem->sync_timer) {
|
|
|
|
last_sync_timer = split_shmem->sync_timer;
|
|
|
|
sync_timer_update(last_sync_timer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-01 19:18:33 +00:00
|
|
|
# define TRANSACTIONS_SYNC_TIMER_MASTER() TRANSACTION_HANDLER_MASTER(sync_timer)
|
2022-10-04 18:49:29 +00:00
|
|
|
# define TRANSACTIONS_SYNC_TIMER_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(sync_timer)
|
2021-06-17 23:10:06 +00:00
|
|
|
# define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS [PUT_SYNC_TIMER] = trans_initiator2target_initializer(sync_timer),
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#else // DISABLE_SYNC_TIMER
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
# define TRANSACTIONS_SYNC_TIMER_MASTER()
|
|
|
|
# define TRANSACTIONS_SYNC_TIMER_SLAVE()
|
|
|
|
# define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // DISABLE_SYNC_TIMER
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// Layer state
|
|
|
|
|
|
|
|
#if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
|
|
|
|
|
|
|
|
static bool layer_state_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_layer_state_update = 0;
|
|
|
|
static uint32_t last_default_layer_state_update = 0;
|
|
|
|
|
|
|
|
bool okay = send_if_condition(PUT_LAYER_STATE, &last_layer_state_update, (layer_state != split_shmem->layers.layer_state), &layer_state, sizeof(layer_state));
|
|
|
|
if (okay) {
|
|
|
|
okay &= send_if_condition(PUT_DEFAULT_LAYER_STATE, &last_default_layer_state_update, (default_layer_state != split_shmem->layers.default_layer_state), &default_layer_state, sizeof(default_layer_state));
|
|
|
|
}
|
|
|
|
return okay;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void layer_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
layer_state = split_shmem->layers.layer_state;
|
|
|
|
default_layer_state = split_shmem->layers.default_layer_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
// clang-format off
|
Make solo half of split keyboards (more) usable. (#13523)
* Make solo half of split keyboards (more) usable.
Using only one half of a split keyboard (that's using the split_common
framework to communicate) is not a great experience, since several read
timeouts per scan cycle cause an unusably slow scan rate.
This change blocks all split communication attempts for 500 ms
(configurable) after an error occurs, causing the scan rate to become at
least _more_ usable, but might need some tweaking to work fully on most
keyboards. One read timeout still needs to occur after the 500 ms has
passed, and if that timeout isn't low enough, some scan cycles may still
be too slow.
* Fix lint complaint.
* Require 25 consecutive comm errors to see comms as disconnected.
The number of max errors can be overridden by defining
`SPLIT_MAX_CONNECTION_ERRORS`.
* Add comments to new defines, and ability to disable disconnection check.
Also increase `SPLIT_MAX_CONNECTION_ERRORS` to 40, since it's divisible
by most relevant numbers for the description.
* Make lint happy ...again
* Only update `connection_check_timer` when needed.
* Add new defines to split keyboard documentation.
* Move connection timeout logic to transport.c, add `is_transport_connected`.
* Use split_common disconnection logic in matrix.c.
Instead of doing more or less the same thing twice.
* Move disconnection logic to `transport_master`.
Is a cleaner implementation, and causes the scan rate while disconnected
to increase instead of decrease.
* Lint fixes.
* Lower default `SERIAL_USART_TIMEOUT` to 20 ms.
The read timeout must be low enough to not cause exessively long scan
cycles when using a solo split half. 10 ms was determined from testing
to work fine even with the slowest defined baudrate of 19200 (5 ms was
too low for that case), so 20 ms should be fine for most cases.
* Remove `SERIAL_USART_TIMEOUT` from ergodox_infinity/config.h
Was somewhat mistakenly included in an earlier PR.
* Fix building with `USE_I2C`.
* Reduce built firmware size.
Not really sure why this works, the idea was taken from tzarc's work on
split disconnection.
* Tweak and improve opt-out for split disconnection logic.
There are now two ways to opt out from this feature:
* Set `SPLIT_MAX_CONNECTION_ERRORS` to 0. This will completely disable
the connection status checks (also affects the slave matrix reset logic in
matrix.c, though).
* Set `SPLIT_CONNECTION_CHECK_TIMEOUT` to 0. This will only disable the
communication throttling while disconnected. Will make the firmware
smaller.
* Make split disconnection logic work with custom transports.
Includes a fallback implementation for keyboards using a custom
split_util.c but not a custom matrix.c (currently no such keyboard seems
to be merged, though).
* Remove unnecessary include of timer.h
Co-authored-by: Joel Challis <git@zvecr.com>
Co-authored-by: Joel Challis <git@zvecr.com>
2021-08-22 00:51:17 +00:00
|
|
|
# define TRANSACTIONS_LAYER_STATE_MASTER() TRANSACTION_HANDLER_MASTER(layer_state)
|
2022-10-04 18:49:29 +00:00
|
|
|
# define TRANSACTIONS_LAYER_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(layer_state)
|
2021-06-17 23:10:06 +00:00
|
|
|
# define TRANSACTIONS_LAYER_STATE_REGISTRATIONS \
|
|
|
|
[PUT_LAYER_STATE] = trans_initiator2target_initializer(layers.layer_state), \
|
|
|
|
[PUT_DEFAULT_LAYER_STATE] = trans_initiator2target_initializer(layers.default_layer_state),
|
|
|
|
// clang-format on
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#else // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
# define TRANSACTIONS_LAYER_STATE_MASTER()
|
|
|
|
# define TRANSACTIONS_LAYER_STATE_SLAVE()
|
|
|
|
# define TRANSACTIONS_LAYER_STATE_REGISTRATIONS
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// LED state
|
|
|
|
|
|
|
|
#ifdef SPLIT_LED_STATE_ENABLE
|
|
|
|
|
|
|
|
static bool led_state_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_update = 0;
|
|
|
|
uint8_t led_state = host_keyboard_leds();
|
|
|
|
return send_if_data_mismatch(PUT_LED_STATE, &last_update, &led_state, &split_shmem->led_state, sizeof(led_state));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void led_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
void set_split_host_keyboard_leds(uint8_t led_state);
|
|
|
|
set_split_host_keyboard_leds(split_shmem->led_state);
|
|
|
|
}
|
|
|
|
|
2021-11-01 19:18:33 +00:00
|
|
|
# define TRANSACTIONS_LED_STATE_MASTER() TRANSACTION_HANDLER_MASTER(led_state)
|
2022-10-04 18:49:29 +00:00
|
|
|
# define TRANSACTIONS_LED_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(led_state)
|
2021-06-17 23:10:06 +00:00
|
|
|
# define TRANSACTIONS_LED_STATE_REGISTRATIONS [PUT_LED_STATE] = trans_initiator2target_initializer(led_state),
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#else // SPLIT_LED_STATE_ENABLE
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
# define TRANSACTIONS_LED_STATE_MASTER()
|
|
|
|
# define TRANSACTIONS_LED_STATE_SLAVE()
|
|
|
|
# define TRANSACTIONS_LED_STATE_REGISTRATIONS
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // SPLIT_LED_STATE_ENABLE
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// Mods
|
|
|
|
|
|
|
|
#ifdef SPLIT_MODS_ENABLE
|
|
|
|
|
|
|
|
static bool mods_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_update = 0;
|
|
|
|
bool mods_need_sync = timer_elapsed32(last_update) >= FORCED_SYNC_THROTTLE_MS;
|
|
|
|
split_mods_sync_t new_mods;
|
|
|
|
new_mods.real_mods = get_mods();
|
|
|
|
if (!mods_need_sync && new_mods.real_mods != split_shmem->mods.real_mods) {
|
|
|
|
mods_need_sync = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_mods.weak_mods = get_weak_mods();
|
|
|
|
if (!mods_need_sync && new_mods.weak_mods != split_shmem->mods.weak_mods) {
|
|
|
|
mods_need_sync = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
# ifndef NO_ACTION_ONESHOT
|
|
|
|
new_mods.oneshot_mods = get_oneshot_mods();
|
|
|
|
if (!mods_need_sync && new_mods.oneshot_mods != split_shmem->mods.oneshot_mods) {
|
|
|
|
mods_need_sync = true;
|
|
|
|
}
|
2024-04-08 18:55:42 +00:00
|
|
|
new_mods.oneshot_locked_mods = get_oneshot_locked_mods();
|
|
|
|
if (!mods_need_sync && new_mods.oneshot_locked_mods != split_shmem->mods.oneshot_locked_mods) {
|
|
|
|
mods_need_sync = true;
|
|
|
|
}
|
2022-02-12 18:29:31 +00:00
|
|
|
# endif // NO_ACTION_ONESHOT
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
bool okay = true;
|
|
|
|
if (mods_need_sync) {
|
|
|
|
okay &= transport_write(PUT_MODS, &new_mods, sizeof(new_mods));
|
|
|
|
if (okay) {
|
|
|
|
last_update = timer_read32();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return okay;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mods_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
2022-10-04 18:49:29 +00:00
|
|
|
split_shared_memory_lock();
|
|
|
|
split_mods_sync_t mods;
|
|
|
|
memcpy(&mods, &split_shmem->mods, sizeof(split_mods_sync_t));
|
|
|
|
split_shared_memory_unlock();
|
|
|
|
|
|
|
|
set_mods(mods.real_mods);
|
|
|
|
set_weak_mods(mods.weak_mods);
|
2021-06-17 23:10:06 +00:00
|
|
|
# ifndef NO_ACTION_ONESHOT
|
2022-10-04 18:49:29 +00:00
|
|
|
set_oneshot_mods(mods.oneshot_mods);
|
2024-04-08 18:55:42 +00:00
|
|
|
set_oneshot_locked_mods(mods.oneshot_locked_mods);
|
2021-06-17 23:10:06 +00:00
|
|
|
# endif
|
|
|
|
}
|
|
|
|
|
2021-11-01 19:18:33 +00:00
|
|
|
# define TRANSACTIONS_MODS_MASTER() TRANSACTION_HANDLER_MASTER(mods)
|
|
|
|
# define TRANSACTIONS_MODS_SLAVE() TRANSACTION_HANDLER_SLAVE(mods)
|
2021-06-17 23:10:06 +00:00
|
|
|
# define TRANSACTIONS_MODS_REGISTRATIONS [PUT_MODS] = trans_initiator2target_initializer(mods),
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#else // SPLIT_MODS_ENABLE
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
# define TRANSACTIONS_MODS_MASTER()
|
|
|
|
# define TRANSACTIONS_MODS_SLAVE()
|
|
|
|
# define TRANSACTIONS_MODS_REGISTRATIONS
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // SPLIT_MODS_ENABLE
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// Backlight
|
|
|
|
|
|
|
|
#ifdef BACKLIGHT_ENABLE
|
|
|
|
|
|
|
|
static bool backlight_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_update = 0;
|
|
|
|
uint8_t level = is_backlight_enabled() ? get_backlight_level() : 0;
|
|
|
|
return send_if_condition(PUT_BACKLIGHT, &last_update, (level != split_shmem->backlight_level), &level, sizeof(level));
|
|
|
|
}
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
static void backlight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
2022-10-04 18:49:29 +00:00
|
|
|
split_shared_memory_lock();
|
|
|
|
uint8_t backlight_level = split_shmem->backlight_level;
|
|
|
|
split_shared_memory_unlock();
|
|
|
|
|
2023-05-31 18:46:03 +00:00
|
|
|
backlight_level_noeeprom(backlight_level);
|
2022-02-12 18:29:31 +00:00
|
|
|
}
|
2021-06-17 23:10:06 +00:00
|
|
|
|
2021-11-01 19:18:33 +00:00
|
|
|
# define TRANSACTIONS_BACKLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(backlight)
|
|
|
|
# define TRANSACTIONS_BACKLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(backlight)
|
2021-06-17 23:10:06 +00:00
|
|
|
# define TRANSACTIONS_BACKLIGHT_REGISTRATIONS [PUT_BACKLIGHT] = trans_initiator2target_initializer(backlight_level),
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#else // BACKLIGHT_ENABLE
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
# define TRANSACTIONS_BACKLIGHT_MASTER()
|
|
|
|
# define TRANSACTIONS_BACKLIGHT_SLAVE()
|
|
|
|
# define TRANSACTIONS_BACKLIGHT_REGISTRATIONS
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // BACKLIGHT_ENABLE
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// RGBLIGHT
|
|
|
|
|
|
|
|
#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
|
|
|
|
|
|
|
|
static bool rgblight_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_update = 0;
|
|
|
|
rgblight_syncinfo_t rgblight_sync;
|
|
|
|
rgblight_get_syncinfo(&rgblight_sync);
|
|
|
|
if (send_if_condition(PUT_RGBLIGHT, &last_update, (rgblight_sync.status.change_flags != 0), &rgblight_sync, sizeof(rgblight_sync))) {
|
|
|
|
rgblight_clear_change_flags();
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rgblight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
2022-10-04 18:49:29 +00:00
|
|
|
split_shared_memory_lock();
|
2021-06-17 23:10:06 +00:00
|
|
|
// Update the RGB with the new data
|
2022-10-04 18:49:29 +00:00
|
|
|
rgblight_syncinfo_t rgblight_sync;
|
|
|
|
memcpy(&rgblight_sync, &split_shmem->rgblight_sync, sizeof(rgblight_syncinfo_t));
|
|
|
|
split_shmem->rgblight_sync.status.change_flags = 0;
|
|
|
|
split_shared_memory_unlock();
|
|
|
|
|
|
|
|
if (rgblight_sync.status.change_flags != 0) {
|
|
|
|
rgblight_update_sync(&rgblight_sync, false);
|
2021-06-17 23:10:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-01 19:18:33 +00:00
|
|
|
# define TRANSACTIONS_RGBLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(rgblight)
|
|
|
|
# define TRANSACTIONS_RGBLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(rgblight)
|
2021-06-17 23:10:06 +00:00
|
|
|
# define TRANSACTIONS_RGBLIGHT_REGISTRATIONS [PUT_RGBLIGHT] = trans_initiator2target_initializer(rgblight_sync),
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#else // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
# define TRANSACTIONS_RGBLIGHT_MASTER()
|
|
|
|
# define TRANSACTIONS_RGBLIGHT_SLAVE()
|
|
|
|
# define TRANSACTIONS_RGBLIGHT_REGISTRATIONS
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// LED Matrix
|
|
|
|
|
|
|
|
#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
|
|
|
|
|
|
|
|
static bool led_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_update = 0;
|
|
|
|
led_matrix_sync_t led_matrix_sync;
|
|
|
|
memcpy(&led_matrix_sync.led_matrix, &led_matrix_eeconfig, sizeof(led_eeconfig_t));
|
|
|
|
led_matrix_sync.led_suspend_state = led_matrix_get_suspend_state();
|
|
|
|
return send_if_data_mismatch(PUT_LED_MATRIX, &last_update, &led_matrix_sync, &split_shmem->led_matrix_sync, sizeof(led_matrix_sync));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void led_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
2022-10-04 18:49:29 +00:00
|
|
|
split_shared_memory_lock();
|
2021-06-17 23:10:06 +00:00
|
|
|
memcpy(&led_matrix_eeconfig, &split_shmem->led_matrix_sync.led_matrix, sizeof(led_eeconfig_t));
|
2022-10-04 18:49:29 +00:00
|
|
|
bool led_suspend_state = split_shmem->led_matrix_sync.led_suspend_state;
|
|
|
|
split_shared_memory_unlock();
|
|
|
|
|
|
|
|
led_matrix_set_suspend_state(led_suspend_state);
|
2021-06-17 23:10:06 +00:00
|
|
|
}
|
|
|
|
|
2021-11-01 19:18:33 +00:00
|
|
|
# define TRANSACTIONS_LED_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(led_matrix)
|
|
|
|
# define TRANSACTIONS_LED_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(led_matrix)
|
2021-06-17 23:10:06 +00:00
|
|
|
# define TRANSACTIONS_LED_MATRIX_REGISTRATIONS [PUT_LED_MATRIX] = trans_initiator2target_initializer(led_matrix_sync),
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#else // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
# define TRANSACTIONS_LED_MATRIX_MASTER()
|
|
|
|
# define TRANSACTIONS_LED_MATRIX_SLAVE()
|
|
|
|
# define TRANSACTIONS_LED_MATRIX_REGISTRATIONS
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// RGB Matrix
|
|
|
|
|
|
|
|
#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
|
|
|
|
|
|
|
|
static bool rgb_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_update = 0;
|
|
|
|
rgb_matrix_sync_t rgb_matrix_sync;
|
|
|
|
memcpy(&rgb_matrix_sync.rgb_matrix, &rgb_matrix_config, sizeof(rgb_config_t));
|
|
|
|
rgb_matrix_sync.rgb_suspend_state = rgb_matrix_get_suspend_state();
|
|
|
|
return send_if_data_mismatch(PUT_RGB_MATRIX, &last_update, &rgb_matrix_sync, &split_shmem->rgb_matrix_sync, sizeof(rgb_matrix_sync));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rgb_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
2022-10-04 18:49:29 +00:00
|
|
|
split_shared_memory_lock();
|
2021-06-17 23:10:06 +00:00
|
|
|
memcpy(&rgb_matrix_config, &split_shmem->rgb_matrix_sync.rgb_matrix, sizeof(rgb_config_t));
|
2022-10-04 18:49:29 +00:00
|
|
|
bool rgb_suspend_state = split_shmem->rgb_matrix_sync.rgb_suspend_state;
|
|
|
|
split_shared_memory_unlock();
|
|
|
|
|
|
|
|
rgb_matrix_set_suspend_state(rgb_suspend_state);
|
2021-06-17 23:10:06 +00:00
|
|
|
}
|
|
|
|
|
2021-11-01 19:18:33 +00:00
|
|
|
# define TRANSACTIONS_RGB_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(rgb_matrix)
|
|
|
|
# define TRANSACTIONS_RGB_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(rgb_matrix)
|
2021-06-17 23:10:06 +00:00
|
|
|
# define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS [PUT_RGB_MATRIX] = trans_initiator2target_initializer(rgb_matrix_sync),
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#else // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
# define TRANSACTIONS_RGB_MATRIX_MASTER()
|
|
|
|
# define TRANSACTIONS_RGB_MATRIX_SLAVE()
|
|
|
|
# define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// WPM
|
|
|
|
|
|
|
|
#if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
|
|
|
|
|
|
|
|
static bool wpm_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_update = 0;
|
|
|
|
uint8_t current_wpm = get_current_wpm();
|
|
|
|
return send_if_condition(PUT_WPM, &last_update, (current_wpm != split_shmem->current_wpm), ¤t_wpm, sizeof(current_wpm));
|
|
|
|
}
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
static void wpm_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
set_current_wpm(split_shmem->current_wpm);
|
|
|
|
}
|
2021-06-17 23:10:06 +00:00
|
|
|
|
2021-11-01 19:18:33 +00:00
|
|
|
# define TRANSACTIONS_WPM_MASTER() TRANSACTION_HANDLER_MASTER(wpm)
|
2022-10-04 18:49:29 +00:00
|
|
|
# define TRANSACTIONS_WPM_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(wpm)
|
2021-06-17 23:10:06 +00:00
|
|
|
# define TRANSACTIONS_WPM_REGISTRATIONS [PUT_WPM] = trans_initiator2target_initializer(current_wpm),
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#else // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
# define TRANSACTIONS_WPM_MASTER()
|
|
|
|
# define TRANSACTIONS_WPM_SLAVE()
|
|
|
|
# define TRANSACTIONS_WPM_REGISTRATIONS
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
|
2021-06-17 23:10:06 +00:00
|
|
|
|
2021-08-15 05:39:08 +00:00
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// OLED
|
|
|
|
|
2021-08-24 06:28:26 +00:00
|
|
|
#if defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)
|
2021-08-15 05:39:08 +00:00
|
|
|
|
|
|
|
static bool oled_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_update = 0;
|
|
|
|
bool current_oled_state = is_oled_on();
|
|
|
|
return send_if_condition(PUT_OLED, &last_update, (current_oled_state != split_shmem->current_oled_state), ¤t_oled_state, sizeof(current_oled_state));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void oled_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
2022-10-04 18:49:29 +00:00
|
|
|
split_shared_memory_lock();
|
|
|
|
uint8_t current_oled_state = split_shmem->current_oled_state;
|
|
|
|
split_shared_memory_unlock();
|
|
|
|
|
|
|
|
if (current_oled_state) {
|
2021-08-15 05:39:08 +00:00
|
|
|
oled_on();
|
|
|
|
} else {
|
|
|
|
oled_off();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-01 19:18:33 +00:00
|
|
|
# define TRANSACTIONS_OLED_MASTER() TRANSACTION_HANDLER_MASTER(oled)
|
|
|
|
# define TRANSACTIONS_OLED_SLAVE() TRANSACTION_HANDLER_SLAVE(oled)
|
2021-08-15 05:39:08 +00:00
|
|
|
# define TRANSACTIONS_OLED_REGISTRATIONS [PUT_OLED] = trans_initiator2target_initializer(current_oled_state),
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#else // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)
|
2021-08-15 05:39:08 +00:00
|
|
|
|
|
|
|
# define TRANSACTIONS_OLED_MASTER()
|
|
|
|
# define TRANSACTIONS_OLED_SLAVE()
|
|
|
|
# define TRANSACTIONS_OLED_REGISTRATIONS
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)
|
2021-08-15 05:39:08 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// ST7565
|
|
|
|
|
|
|
|
#if defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)
|
|
|
|
|
|
|
|
static bool st7565_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_update = 0;
|
|
|
|
bool current_st7565_state = st7565_is_on();
|
|
|
|
return send_if_condition(PUT_ST7565, &last_update, (current_st7565_state != split_shmem->current_st7565_state), ¤t_st7565_state, sizeof(current_st7565_state));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void st7565_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
2022-10-04 18:49:29 +00:00
|
|
|
split_shared_memory_lock();
|
|
|
|
uint8_t current_st7565_state = split_shmem->current_st7565_state;
|
|
|
|
split_shared_memory_unlock();
|
|
|
|
|
|
|
|
if (current_st7565_state) {
|
2021-08-15 05:39:08 +00:00
|
|
|
st7565_on();
|
|
|
|
} else {
|
|
|
|
st7565_off();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-01 19:18:33 +00:00
|
|
|
# define TRANSACTIONS_ST7565_MASTER() TRANSACTION_HANDLER_MASTER(st7565)
|
2022-10-05 17:22:57 +00:00
|
|
|
# define TRANSACTIONS_ST7565_SLAVE() TRANSACTION_HANDLER_SLAVE(st7565)
|
2021-08-15 05:39:08 +00:00
|
|
|
# define TRANSACTIONS_ST7565_REGISTRATIONS [PUT_ST7565] = trans_initiator2target_initializer(current_st7565_state),
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#else // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)
|
2021-08-15 05:39:08 +00:00
|
|
|
|
|
|
|
# define TRANSACTIONS_ST7565_MASTER()
|
|
|
|
# define TRANSACTIONS_ST7565_SLAVE()
|
|
|
|
# define TRANSACTIONS_ST7565_REGISTRATIONS
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)
|
2021-08-15 05:39:08 +00:00
|
|
|
|
2021-12-27 01:05:51 +00:00
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// POINTING
|
|
|
|
|
|
|
|
#if defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
|
|
|
|
|
|
|
|
static bool pointing_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
# if defined(POINTING_DEVICE_LEFT)
|
|
|
|
if (is_keyboard_left()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
# elif defined(POINTING_DEVICE_RIGHT)
|
|
|
|
if (!is_keyboard_left()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
# endif
|
2024-05-17 21:59:45 +00:00
|
|
|
static uint32_t last_update = 0;
|
|
|
|
static uint32_t last_cpi_update = 0;
|
|
|
|
static uint16_t last_cpi = 0;
|
2021-12-27 01:05:51 +00:00
|
|
|
report_mouse_t temp_state;
|
|
|
|
uint16_t temp_cpi;
|
|
|
|
bool okay = read_if_checksum_mismatch(GET_POINTING_CHECKSUM, GET_POINTING_DATA, &last_update, &temp_state, &split_shmem->pointing.report, sizeof(temp_state));
|
|
|
|
if (okay) pointing_device_set_shared_report(temp_state);
|
|
|
|
temp_cpi = pointing_device_get_shared_cpi();
|
2024-05-17 21:59:45 +00:00
|
|
|
if (temp_cpi) {
|
2022-10-04 18:49:29 +00:00
|
|
|
split_shmem->pointing.cpi = temp_cpi;
|
2024-05-17 21:59:45 +00:00
|
|
|
okay = send_if_condition(PUT_POINTING_CPI, &last_cpi_update, last_cpi != temp_cpi, &split_shmem->pointing.cpi, sizeof(split_shmem->pointing.cpi));
|
2021-12-27 01:05:51 +00:00
|
|
|
if (okay) {
|
|
|
|
last_cpi = temp_cpi;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return okay;
|
|
|
|
}
|
|
|
|
|
2024-10-25 17:11:51 +00:00
|
|
|
extern const pointing_device_driver_t *pointing_device_driver;
|
2021-12-27 01:05:51 +00:00
|
|
|
|
|
|
|
static void pointing_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
# if defined(POINTING_DEVICE_LEFT)
|
|
|
|
if (!is_keyboard_left()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
# elif defined(POINTING_DEVICE_RIGHT)
|
|
|
|
if (is_keyboard_left()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
# endif
|
2022-01-26 19:24:29 +00:00
|
|
|
# if (POINTING_DEVICE_TASK_THROTTLE_MS > 0)
|
2021-12-27 01:05:51 +00:00
|
|
|
static uint32_t last_exec = 0;
|
|
|
|
if (timer_elapsed32(last_exec) < POINTING_DEVICE_TASK_THROTTLE_MS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
last_exec = timer_read32();
|
|
|
|
# endif
|
2022-10-04 18:49:29 +00:00
|
|
|
|
2024-10-25 17:11:51 +00:00
|
|
|
uint16_t temp_cpi = !pointing_device_driver->get_cpi ? 0 : pointing_device_driver->get_cpi(); // check for NULL
|
2022-10-04 18:49:29 +00:00
|
|
|
|
|
|
|
split_shared_memory_lock();
|
|
|
|
split_slave_pointing_sync_t pointing;
|
|
|
|
memcpy(&pointing, &split_shmem->pointing, sizeof(split_slave_pointing_sync_t));
|
|
|
|
split_shared_memory_unlock();
|
|
|
|
|
2024-10-25 17:11:51 +00:00
|
|
|
if (pointing.cpi && pointing.cpi != temp_cpi && pointing_device_driver->set_cpi) {
|
|
|
|
pointing_device_driver->set_cpi(pointing.cpi);
|
2021-12-27 01:05:51 +00:00
|
|
|
}
|
2022-10-04 18:49:29 +00:00
|
|
|
|
2024-10-25 17:11:51 +00:00
|
|
|
pointing.report = pointing_device_driver->get_report((report_mouse_t){0});
|
2021-12-27 01:05:51 +00:00
|
|
|
// Now update the checksum given that the pointing has been written to
|
2022-10-04 18:49:29 +00:00
|
|
|
pointing.checksum = crc8(&pointing.report, sizeof(report_mouse_t));
|
|
|
|
|
|
|
|
split_shared_memory_lock();
|
|
|
|
memcpy(&split_shmem->pointing, &pointing, sizeof(split_slave_pointing_sync_t));
|
|
|
|
split_shared_memory_unlock();
|
2021-12-27 01:05:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# define TRANSACTIONS_POINTING_MASTER() TRANSACTION_HANDLER_MASTER(pointing)
|
|
|
|
# define TRANSACTIONS_POINTING_SLAVE() TRANSACTION_HANDLER_SLAVE(pointing)
|
|
|
|
# define TRANSACTIONS_POINTING_REGISTRATIONS [GET_POINTING_CHECKSUM] = trans_target2initiator_initializer(pointing.checksum), [GET_POINTING_DATA] = trans_target2initiator_initializer(pointing.report), [PUT_POINTING_CPI] = trans_initiator2target_initializer(pointing.cpi),
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#else // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
|
2021-12-27 01:05:51 +00:00
|
|
|
|
|
|
|
# define TRANSACTIONS_POINTING_MASTER()
|
|
|
|
# define TRANSACTIONS_POINTING_SLAVE()
|
|
|
|
# define TRANSACTIONS_POINTING_REGISTRATIONS
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
|
2021-12-27 01:05:51 +00:00
|
|
|
|
2022-10-06 09:52:42 +00:00
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// WATCHDOG
|
|
|
|
|
|
|
|
#if defined(SPLIT_WATCHDOG_ENABLE)
|
|
|
|
|
|
|
|
static bool watchdog_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
bool okay = true;
|
|
|
|
if (!split_watchdog_check()) {
|
|
|
|
okay = transport_write(PUT_WATCHDOG, &okay, sizeof(okay));
|
|
|
|
split_watchdog_update(okay);
|
|
|
|
}
|
|
|
|
return okay;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void watchdog_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
split_watchdog_update(split_shmem->watchdog_pinged);
|
|
|
|
}
|
|
|
|
|
|
|
|
# define TRANSACTIONS_WATCHDOG_MASTER() TRANSACTION_HANDLER_MASTER(watchdog)
|
|
|
|
# define TRANSACTIONS_WATCHDOG_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(watchdog)
|
|
|
|
# define TRANSACTIONS_WATCHDOG_REGISTRATIONS [PUT_WATCHDOG] = trans_initiator2target_initializer(watchdog_pinged),
|
|
|
|
|
|
|
|
#else // defined(SPLIT_WATCHDOG_ENABLE)
|
|
|
|
|
|
|
|
# define TRANSACTIONS_WATCHDOG_MASTER()
|
|
|
|
# define TRANSACTIONS_WATCHDOG_SLAVE()
|
|
|
|
# define TRANSACTIONS_WATCHDOG_REGISTRATIONS
|
|
|
|
|
|
|
|
#endif // defined(SPLIT_WATCHDOG_ENABLE)
|
|
|
|
|
2023-01-01 00:56:32 +00:00
|
|
|
#if defined(HAPTIC_ENABLE) && defined(SPLIT_HAPTIC_ENABLE)
|
|
|
|
|
|
|
|
uint8_t split_haptic_play = 0xFF;
|
|
|
|
extern haptic_config_t haptic_config;
|
|
|
|
|
|
|
|
static bool haptic_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_update = 0;
|
|
|
|
split_slave_haptic_sync_t haptic_sync;
|
|
|
|
|
|
|
|
memcpy(&haptic_sync.haptic_config, &haptic_config, sizeof(haptic_config_t));
|
|
|
|
haptic_sync.haptic_play = split_haptic_play;
|
|
|
|
|
|
|
|
bool okay = send_if_data_mismatch(PUT_HAPTIC, &last_update, &haptic_sync, &split_shmem->haptic_sync, sizeof(haptic_sync));
|
|
|
|
|
|
|
|
split_haptic_play = 0xFF;
|
|
|
|
|
|
|
|
return okay;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void haptic_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
memcpy(&haptic_config, &split_shmem->haptic_sync.haptic_config, sizeof(haptic_config_t));
|
|
|
|
|
|
|
|
if (split_shmem->haptic_sync.haptic_play != 0xFF) {
|
|
|
|
haptic_set_mode(split_shmem->haptic_sync.haptic_play);
|
|
|
|
haptic_play();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
# define TRANSACTIONS_HAPTIC_MASTER() TRANSACTION_HANDLER_MASTER(haptic)
|
|
|
|
# define TRANSACTIONS_HAPTIC_SLAVE() TRANSACTION_HANDLER_SLAVE(haptic)
|
|
|
|
# define TRANSACTIONS_HAPTIC_REGISTRATIONS [PUT_HAPTIC] = trans_initiator2target_initializer(haptic_sync),
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
#else // defined(HAPTIC_ENABLE) && defined(SPLIT_HAPTIC_ENABLE)
|
|
|
|
|
|
|
|
# define TRANSACTIONS_HAPTIC_MASTER()
|
|
|
|
# define TRANSACTIONS_HAPTIC_SLAVE()
|
|
|
|
# define TRANSACTIONS_HAPTIC_REGISTRATIONS
|
|
|
|
|
|
|
|
#endif // defined(HAPTIC_ENABLE) && defined(SPLIT_HAPTIC_ENABLE)
|
|
|
|
|
2023-03-21 09:16:11 +00:00
|
|
|
#if defined(SPLIT_ACTIVITY_ENABLE)
|
|
|
|
|
|
|
|
static bool activity_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_update = 0;
|
|
|
|
split_slave_activity_sync_t activity_sync;
|
2023-03-31 01:27:39 +00:00
|
|
|
activity_sync.matrix_timestamp = last_matrix_activity_time();
|
|
|
|
activity_sync.encoder_timestamp = last_encoder_activity_time();
|
|
|
|
activity_sync.pointing_device_timestamp = last_pointing_device_activity_time();
|
2023-03-21 09:16:11 +00:00
|
|
|
return send_if_data_mismatch(PUT_ACTIVITY, &last_update, &activity_sync, &split_shmem->activity_sync, sizeof(activity_sync));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void activity_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
2023-03-31 01:27:39 +00:00
|
|
|
set_activity_timestamps(split_shmem->activity_sync.matrix_timestamp, split_shmem->activity_sync.encoder_timestamp, split_shmem->activity_sync.pointing_device_timestamp);
|
2023-03-21 09:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
# define TRANSACTIONS_ACTIVITY_MASTER() TRANSACTION_HANDLER_MASTER(activity)
|
|
|
|
# define TRANSACTIONS_ACTIVITY_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(activity)
|
|
|
|
# define TRANSACTIONS_ACTIVITY_REGISTRATIONS [PUT_ACTIVITY] = trans_initiator2target_initializer(activity_sync),
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
#else // defined(SPLIT_ACTIVITY_ENABLE)
|
|
|
|
|
|
|
|
# define TRANSACTIONS_ACTIVITY_MASTER()
|
|
|
|
# define TRANSACTIONS_ACTIVITY_SLAVE()
|
|
|
|
# define TRANSACTIONS_ACTIVITY_REGISTRATIONS
|
|
|
|
|
|
|
|
#endif // defined(SPLIT_ACTIVITY_ENABLE)
|
|
|
|
|
2023-04-03 22:48:51 +00:00
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// Detected OS
|
|
|
|
|
|
|
|
#if defined(OS_DETECTION_ENABLE) && defined(SPLIT_DETECTED_OS_ENABLE)
|
|
|
|
|
|
|
|
static bool detected_os_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
static uint32_t last_detected_os_update = 0;
|
|
|
|
os_variant_t detected_os = detected_host_os();
|
|
|
|
bool okay = send_if_condition(PUT_DETECTED_OS, &last_detected_os_update, (detected_os != split_shmem->detected_os), &detected_os, sizeof(os_variant_t));
|
|
|
|
return okay;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void detected_os_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
slave_update_detected_host_os(split_shmem->detected_os);
|
|
|
|
}
|
|
|
|
|
|
|
|
# define TRANSACTIONS_DETECTED_OS_MASTER() TRANSACTION_HANDLER_MASTER(detected_os)
|
|
|
|
# define TRANSACTIONS_DETECTED_OS_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(detected_os)
|
|
|
|
# define TRANSACTIONS_DETECTED_OS_REGISTRATIONS [PUT_DETECTED_OS] = trans_initiator2target_initializer(detected_os),
|
|
|
|
|
|
|
|
#else // defined(OS_DETECTION_ENABLE) && defined(SPLIT_DETECTED_OS_ENABLE)
|
|
|
|
|
|
|
|
# define TRANSACTIONS_DETECTED_OS_MASTER()
|
|
|
|
# define TRANSACTIONS_DETECTED_OS_SLAVE()
|
|
|
|
# define TRANSACTIONS_DETECTED_OS_REGISTRATIONS
|
|
|
|
|
|
|
|
#endif // defined(OS_DETECTION_ENABLE) && defined(SPLIT_DETECTED_OS_ENABLE)
|
|
|
|
|
2021-06-17 23:10:06 +00:00
|
|
|
////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = {
|
|
|
|
// Set defaults
|
2022-01-27 05:13:27 +00:00
|
|
|
[0 ...(NUM_TOTAL_TRANSACTIONS - 1)] = {0, 0, 0, 0, 0},
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
#ifdef USE_I2C
|
|
|
|
[I2C_EXECUTE_CALLBACK] = trans_initiator2target_initializer(transaction_id),
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // USE_I2C
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS
|
|
|
|
TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS
|
|
|
|
TRANSACTIONS_ENCODERS_REGISTRATIONS
|
|
|
|
TRANSACTIONS_SYNC_TIMER_REGISTRATIONS
|
|
|
|
TRANSACTIONS_LAYER_STATE_REGISTRATIONS
|
|
|
|
TRANSACTIONS_LED_STATE_REGISTRATIONS
|
|
|
|
TRANSACTIONS_MODS_REGISTRATIONS
|
|
|
|
TRANSACTIONS_BACKLIGHT_REGISTRATIONS
|
|
|
|
TRANSACTIONS_RGBLIGHT_REGISTRATIONS
|
|
|
|
TRANSACTIONS_LED_MATRIX_REGISTRATIONS
|
|
|
|
TRANSACTIONS_RGB_MATRIX_REGISTRATIONS
|
|
|
|
TRANSACTIONS_WPM_REGISTRATIONS
|
2021-08-15 05:39:08 +00:00
|
|
|
TRANSACTIONS_OLED_REGISTRATIONS
|
|
|
|
TRANSACTIONS_ST7565_REGISTRATIONS
|
2021-12-27 01:05:51 +00:00
|
|
|
TRANSACTIONS_POINTING_REGISTRATIONS
|
2022-10-06 09:52:42 +00:00
|
|
|
TRANSACTIONS_WATCHDOG_REGISTRATIONS
|
2023-01-01 00:56:32 +00:00
|
|
|
TRANSACTIONS_HAPTIC_REGISTRATIONS
|
2023-03-21 09:16:11 +00:00
|
|
|
TRANSACTIONS_ACTIVITY_REGISTRATIONS
|
2023-04-03 22:48:51 +00:00
|
|
|
TRANSACTIONS_DETECTED_OS_REGISTRATIONS
|
2021-06-17 23:10:06 +00:00
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
|
|
|
|
[PUT_RPC_INFO] = trans_initiator2target_initializer_cb(rpc_info, slave_rpc_info_callback),
|
|
|
|
[PUT_RPC_REQ_DATA] = trans_initiator2target_initializer(rpc_m2s_buffer),
|
2022-08-06 08:46:59 +00:00
|
|
|
[EXECUTE_RPC] = trans_initiator2target_initializer_cb(rpc_info.payload.transaction_id, slave_rpc_exec_callback),
|
2021-06-17 23:10:06 +00:00
|
|
|
[GET_RPC_RESP_DATA] = trans_target2initiator_initializer(rpc_s2m_buffer),
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
|
2021-06-17 23:10:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
bool transactions_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
TRANSACTIONS_SLAVE_MATRIX_MASTER();
|
|
|
|
TRANSACTIONS_MASTER_MATRIX_MASTER();
|
|
|
|
TRANSACTIONS_ENCODERS_MASTER();
|
|
|
|
TRANSACTIONS_SYNC_TIMER_MASTER();
|
|
|
|
TRANSACTIONS_LAYER_STATE_MASTER();
|
|
|
|
TRANSACTIONS_LED_STATE_MASTER();
|
|
|
|
TRANSACTIONS_MODS_MASTER();
|
|
|
|
TRANSACTIONS_BACKLIGHT_MASTER();
|
|
|
|
TRANSACTIONS_RGBLIGHT_MASTER();
|
|
|
|
TRANSACTIONS_LED_MATRIX_MASTER();
|
|
|
|
TRANSACTIONS_RGB_MATRIX_MASTER();
|
|
|
|
TRANSACTIONS_WPM_MASTER();
|
2021-08-15 05:39:08 +00:00
|
|
|
TRANSACTIONS_OLED_MASTER();
|
|
|
|
TRANSACTIONS_ST7565_MASTER();
|
2021-12-27 01:05:51 +00:00
|
|
|
TRANSACTIONS_POINTING_MASTER();
|
2022-10-06 09:52:42 +00:00
|
|
|
TRANSACTIONS_WATCHDOG_MASTER();
|
2023-01-01 00:56:32 +00:00
|
|
|
TRANSACTIONS_HAPTIC_MASTER();
|
2023-03-21 09:16:11 +00:00
|
|
|
TRANSACTIONS_ACTIVITY_MASTER();
|
2023-04-03 22:48:51 +00:00
|
|
|
TRANSACTIONS_DETECTED_OS_MASTER();
|
Make solo half of split keyboards (more) usable. (#13523)
* Make solo half of split keyboards (more) usable.
Using only one half of a split keyboard (that's using the split_common
framework to communicate) is not a great experience, since several read
timeouts per scan cycle cause an unusably slow scan rate.
This change blocks all split communication attempts for 500 ms
(configurable) after an error occurs, causing the scan rate to become at
least _more_ usable, but might need some tweaking to work fully on most
keyboards. One read timeout still needs to occur after the 500 ms has
passed, and if that timeout isn't low enough, some scan cycles may still
be too slow.
* Fix lint complaint.
* Require 25 consecutive comm errors to see comms as disconnected.
The number of max errors can be overridden by defining
`SPLIT_MAX_CONNECTION_ERRORS`.
* Add comments to new defines, and ability to disable disconnection check.
Also increase `SPLIT_MAX_CONNECTION_ERRORS` to 40, since it's divisible
by most relevant numbers for the description.
* Make lint happy ...again
* Only update `connection_check_timer` when needed.
* Add new defines to split keyboard documentation.
* Move connection timeout logic to transport.c, add `is_transport_connected`.
* Use split_common disconnection logic in matrix.c.
Instead of doing more or less the same thing twice.
* Move disconnection logic to `transport_master`.
Is a cleaner implementation, and causes the scan rate while disconnected
to increase instead of decrease.
* Lint fixes.
* Lower default `SERIAL_USART_TIMEOUT` to 20 ms.
The read timeout must be low enough to not cause exessively long scan
cycles when using a solo split half. 10 ms was determined from testing
to work fine even with the slowest defined baudrate of 19200 (5 ms was
too low for that case), so 20 ms should be fine for most cases.
* Remove `SERIAL_USART_TIMEOUT` from ergodox_infinity/config.h
Was somewhat mistakenly included in an earlier PR.
* Fix building with `USE_I2C`.
* Reduce built firmware size.
Not really sure why this works, the idea was taken from tzarc's work on
split disconnection.
* Tweak and improve opt-out for split disconnection logic.
There are now two ways to opt out from this feature:
* Set `SPLIT_MAX_CONNECTION_ERRORS` to 0. This will completely disable
the connection status checks (also affects the slave matrix reset logic in
matrix.c, though).
* Set `SPLIT_CONNECTION_CHECK_TIMEOUT` to 0. This will only disable the
communication throttling while disconnected. Will make the firmware
smaller.
* Make split disconnection logic work with custom transports.
Includes a fallback implementation for keyboards using a custom
split_util.c but not a custom matrix.c (currently no such keyboard seems
to be merged, though).
* Remove unnecessary include of timer.h
Co-authored-by: Joel Challis <git@zvecr.com>
Co-authored-by: Joel Challis <git@zvecr.com>
2021-08-22 00:51:17 +00:00
|
|
|
return true;
|
2021-06-17 23:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void transactions_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
|
|
|
|
TRANSACTIONS_SLAVE_MATRIX_SLAVE();
|
|
|
|
TRANSACTIONS_MASTER_MATRIX_SLAVE();
|
|
|
|
TRANSACTIONS_ENCODERS_SLAVE();
|
|
|
|
TRANSACTIONS_SYNC_TIMER_SLAVE();
|
|
|
|
TRANSACTIONS_LAYER_STATE_SLAVE();
|
|
|
|
TRANSACTIONS_LED_STATE_SLAVE();
|
|
|
|
TRANSACTIONS_MODS_SLAVE();
|
|
|
|
TRANSACTIONS_BACKLIGHT_SLAVE();
|
|
|
|
TRANSACTIONS_RGBLIGHT_SLAVE();
|
|
|
|
TRANSACTIONS_LED_MATRIX_SLAVE();
|
|
|
|
TRANSACTIONS_RGB_MATRIX_SLAVE();
|
|
|
|
TRANSACTIONS_WPM_SLAVE();
|
2021-08-15 05:39:08 +00:00
|
|
|
TRANSACTIONS_OLED_SLAVE();
|
|
|
|
TRANSACTIONS_ST7565_SLAVE();
|
2021-12-27 01:05:51 +00:00
|
|
|
TRANSACTIONS_POINTING_SLAVE();
|
2022-10-06 09:52:42 +00:00
|
|
|
TRANSACTIONS_WATCHDOG_SLAVE();
|
2023-01-01 00:56:32 +00:00
|
|
|
TRANSACTIONS_HAPTIC_SLAVE();
|
2023-03-21 09:16:11 +00:00
|
|
|
TRANSACTIONS_ACTIVITY_SLAVE();
|
2023-04-03 22:48:51 +00:00
|
|
|
TRANSACTIONS_DETECTED_OS_SLAVE();
|
2021-06-17 23:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
|
|
|
|
|
|
|
|
void transaction_register_rpc(int8_t transaction_id, slave_callback_t callback) {
|
|
|
|
// Prevent invoking RPC on QMK core sync data
|
|
|
|
if (transaction_id <= GET_RPC_RESP_DATA) return;
|
|
|
|
|
|
|
|
// Set the callback
|
|
|
|
split_transaction_table[transaction_id].slave_callback = callback;
|
|
|
|
split_transaction_table[transaction_id].initiator2target_offset = offsetof(split_shared_memory_t, rpc_m2s_buffer);
|
|
|
|
split_transaction_table[transaction_id].target2initiator_offset = offsetof(split_shared_memory_t, rpc_s2m_buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool transaction_rpc_exec(int8_t transaction_id, uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
|
Make solo half of split keyboards (more) usable. (#13523)
* Make solo half of split keyboards (more) usable.
Using only one half of a split keyboard (that's using the split_common
framework to communicate) is not a great experience, since several read
timeouts per scan cycle cause an unusably slow scan rate.
This change blocks all split communication attempts for 500 ms
(configurable) after an error occurs, causing the scan rate to become at
least _more_ usable, but might need some tweaking to work fully on most
keyboards. One read timeout still needs to occur after the 500 ms has
passed, and if that timeout isn't low enough, some scan cycles may still
be too slow.
* Fix lint complaint.
* Require 25 consecutive comm errors to see comms as disconnected.
The number of max errors can be overridden by defining
`SPLIT_MAX_CONNECTION_ERRORS`.
* Add comments to new defines, and ability to disable disconnection check.
Also increase `SPLIT_MAX_CONNECTION_ERRORS` to 40, since it's divisible
by most relevant numbers for the description.
* Make lint happy ...again
* Only update `connection_check_timer` when needed.
* Add new defines to split keyboard documentation.
* Move connection timeout logic to transport.c, add `is_transport_connected`.
* Use split_common disconnection logic in matrix.c.
Instead of doing more or less the same thing twice.
* Move disconnection logic to `transport_master`.
Is a cleaner implementation, and causes the scan rate while disconnected
to increase instead of decrease.
* Lint fixes.
* Lower default `SERIAL_USART_TIMEOUT` to 20 ms.
The read timeout must be low enough to not cause exessively long scan
cycles when using a solo split half. 10 ms was determined from testing
to work fine even with the slowest defined baudrate of 19200 (5 ms was
too low for that case), so 20 ms should be fine for most cases.
* Remove `SERIAL_USART_TIMEOUT` from ergodox_infinity/config.h
Was somewhat mistakenly included in an earlier PR.
* Fix building with `USE_I2C`.
* Reduce built firmware size.
Not really sure why this works, the idea was taken from tzarc's work on
split disconnection.
* Tweak and improve opt-out for split disconnection logic.
There are now two ways to opt out from this feature:
* Set `SPLIT_MAX_CONNECTION_ERRORS` to 0. This will completely disable
the connection status checks (also affects the slave matrix reset logic in
matrix.c, though).
* Set `SPLIT_CONNECTION_CHECK_TIMEOUT` to 0. This will only disable the
communication throttling while disconnected. Will make the firmware
smaller.
* Make split disconnection logic work with custom transports.
Includes a fallback implementation for keyboards using a custom
split_util.c but not a custom matrix.c (currently no such keyboard seems
to be merged, though).
* Remove unnecessary include of timer.h
Co-authored-by: Joel Challis <git@zvecr.com>
Co-authored-by: Joel Challis <git@zvecr.com>
2021-08-22 00:51:17 +00:00
|
|
|
// Prevent transaction attempts while transport is disconnected
|
|
|
|
if (!is_transport_connected()) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-06-17 23:10:06 +00:00
|
|
|
// Prevent invoking RPC on QMK core sync data
|
|
|
|
if (transaction_id <= GET_RPC_RESP_DATA) return false;
|
|
|
|
// Prevent sizing issues
|
|
|
|
if (initiator2target_buffer_size > RPC_M2S_BUFFER_SIZE) return false;
|
|
|
|
if (target2initiator_buffer_size > RPC_S2M_BUFFER_SIZE) return false;
|
|
|
|
|
|
|
|
// Prepare the metadata block
|
2022-08-06 08:46:59 +00:00
|
|
|
rpc_sync_info_t info = {.payload = {.transaction_id = transaction_id, .m2s_length = initiator2target_buffer_size, .s2m_length = target2initiator_buffer_size}};
|
|
|
|
info.checksum = crc8(&info.payload, sizeof(info.payload));
|
2021-06-17 23:10:06 +00:00
|
|
|
|
|
|
|
// Make sure the local side knows that we're not sending the full block of data
|
|
|
|
split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = initiator2target_buffer_size;
|
|
|
|
split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = target2initiator_buffer_size;
|
|
|
|
|
|
|
|
// Run through the sequence:
|
|
|
|
// * set the transaction ID and lengths
|
|
|
|
// * send the request data
|
|
|
|
// * execute RPC callback
|
|
|
|
// * retrieve the response data
|
|
|
|
if (!transport_write(PUT_RPC_INFO, &info, sizeof(info))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!transport_write(PUT_RPC_REQ_DATA, initiator2target_buffer, initiator2target_buffer_size)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!transport_write(EXECUTE_RPC, &transaction_id, sizeof(transaction_id))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!transport_read(GET_RPC_RESP_DATA, target2initiator_buffer, target2initiator_buffer_size)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
|
|
|
|
// The RPC info block contains the intended transaction ID, as well as the sizes for both inbound and outbound data.
|
|
|
|
// Ignore the args -- the `split_shmem` already has the info, we just need to act upon it.
|
|
|
|
// We must keep the `split_transaction_table` non-const, so that it is able to be modified at runtime.
|
|
|
|
|
2022-08-06 08:46:59 +00:00
|
|
|
split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = split_shmem->rpc_info.payload.m2s_length;
|
|
|
|
split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = split_shmem->rpc_info.payload.s2m_length;
|
2021-06-17 23:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
|
|
|
|
// We can assume that the buffer lengths are correctly set, now, given that sequentially the rpc_info callback was already executed.
|
|
|
|
// Go through the rpc_info and execute _that_ transaction's callback, with the scratch buffers as inputs.
|
2022-08-06 08:46:59 +00:00
|
|
|
// As a safety precaution we check that the received payload matches its checksum first.
|
|
|
|
if (crc8(&split_shmem->rpc_info.payload, sizeof(split_shmem->rpc_info.payload)) != split_shmem->rpc_info.checksum) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int8_t transaction_id = split_shmem->rpc_info.payload.transaction_id;
|
2021-06-17 23:10:06 +00:00
|
|
|
if (transaction_id < NUM_TOTAL_TRANSACTIONS) {
|
|
|
|
split_transaction_desc_t *trans = &split_transaction_table[transaction_id];
|
|
|
|
if (trans->slave_callback) {
|
2022-08-06 08:46:59 +00:00
|
|
|
trans->slave_callback(split_shmem->rpc_info.payload.m2s_length, split_shmem->rpc_m2s_buffer, split_shmem->rpc_info.payload.s2m_length, split_shmem->rpc_s2m_buffer);
|
2021-06-17 23:10:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-12 18:29:31 +00:00
|
|
|
#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
|