diff options
| author | Nick Brassel <nick@tzarc.org> | 2021-06-18 09:10:06 +1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-06-18 09:10:06 +1000 |
| commit | 172e6a703041363decd6fc829542f33180c13beb (patch) | |
| tree | a5d4afaa672ab44826865fd76b201e3899083192 /quantum/split_common | |
| parent | ef92c9ee2cf4745637635ec1895399e4f013914c (diff) | |
| download | qmk_firmware-172e6a703041363decd6fc829542f33180c13beb.tar.gz qmk_firmware-172e6a703041363decd6fc829542f33180c13beb.zip | |
Extensible split data sync (#11930)
* Extensible split data sync capability through transactions.
- Split common transport has been split up between the transport layer
and data layer.
- Split "transactions" model used, with convergence between I2C and
serial data definitions.
- Slave matrix "generation count" is used to determine if the full slave
matrix needs to be retrieved.
- Encoders get the same "generation count" treatment.
- All other blocks of data are synchronised when a change is detected.
- All transmissions have a globally-configurable deadline before a
transmission is forced (`FORCED_SYNC_THROTTLE_MS`, default 100ms).
- Added atomicity for all core-synced data, preventing partial updates
- Added retries to AVR i2c_master's i2c_start, to minimise the number of
failed transactions when interrupts are disabled on the slave due to
atomicity checks.
- Some keyboards have had slight modifications made in order to ensure
that they still build due to firmware size restrictions.
* Fixup LED_MATRIX compile.
* Parameterise ERROR_DISCONNECT_COUNT.
Diffstat (limited to 'quantum/split_common')
| -rw-r--r-- | quantum/split_common/matrix.c | 6 | ||||
| -rw-r--r-- | quantum/split_common/post_config.h | 9 | ||||
| -rw-r--r-- | quantum/split_common/transaction_id_define.h | 94 | ||||
| -rw-r--r-- | quantum/split_common/transactions.c | 670 | ||||
| -rw-r--r-- | quantum/split_common/transactions.h | 54 | ||||
| -rw-r--r-- | quantum/split_common/transport.c | 484 | ||||
| -rw-r--r-- | quantum/split_common/transport.h | 165 |
7 files changed, 1062 insertions, 420 deletions
diff --git a/quantum/split_common/matrix.c b/quantum/split_common/matrix.c index 2cf7b7058..56d91b07f 100644 --- a/quantum/split_common/matrix.c +++ b/quantum/split_common/matrix.c | |||
| @@ -23,9 +23,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 23 | #include "quantum.h" | 23 | #include "quantum.h" |
| 24 | #include "split_util.h" | 24 | #include "split_util.h" |
| 25 | #include "config.h" | 25 | #include "config.h" |
| 26 | #include "transport.h" | 26 | #include "transactions.h" |
| 27 | 27 | ||
| 28 | #define ERROR_DISCONNECT_COUNT 5 | 28 | #ifndef ERROR_DISCONNECT_COUNT |
| 29 | # define ERROR_DISCONNECT_COUNT 5 | ||
| 30 | #endif // ERROR_DISCONNECT_COUNT | ||
| 29 | 31 | ||
| 30 | #define ROWS_PER_HAND (MATRIX_ROWS / 2) | 32 | #define ROWS_PER_HAND (MATRIX_ROWS / 2) |
| 31 | 33 | ||
diff --git a/quantum/split_common/post_config.h b/quantum/split_common/post_config.h index 4ae1d5273..a4c0a1956 100644 --- a/quantum/split_common/post_config.h +++ b/quantum/split_common/post_config.h | |||
| @@ -7,13 +7,4 @@ | |||
| 7 | # ifndef F_SCL | 7 | # ifndef F_SCL |
| 8 | # define F_SCL 100000UL // SCL frequency | 8 | # define F_SCL 100000UL // SCL frequency |
| 9 | # endif | 9 | # endif |
| 10 | |||
| 11 | #else // use serial | ||
| 12 | // When using serial, the user must define RGBLIGHT_SPLIT explicitly | ||
| 13 | // in config.h as needed. | ||
| 14 | // see quantum/rgblight_post_config.h | ||
| 15 | # if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | ||
| 16 | // When using serial and RGBLIGHT_SPLIT need separate transaction | ||
| 17 | # define SERIAL_USE_MULTI_TRANSACTION | ||
| 18 | # endif | ||
| 19 | #endif | 10 | #endif |
diff --git a/quantum/split_common/transaction_id_define.h b/quantum/split_common/transaction_id_define.h new file mode 100644 index 000000000..464c73478 --- /dev/null +++ b/quantum/split_common/transaction_id_define.h | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 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 2 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 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | enum serial_transaction_id { | ||
| 20 | #ifdef USE_I2C | ||
| 21 | I2C_EXECUTE_CALLBACK, | ||
| 22 | #endif // USE_I2C | ||
| 23 | |||
| 24 | GET_SLAVE_MATRIX_CHECKSUM, | ||
| 25 | GET_SLAVE_MATRIX_DATA, | ||
| 26 | |||
| 27 | #ifdef SPLIT_TRANSPORT_MIRROR | ||
| 28 | PUT_MASTER_MATRIX, | ||
| 29 | #endif // SPLIT_TRANSPORT_MIRROR | ||
| 30 | |||
| 31 | #ifdef ENCODER_ENABLE | ||
| 32 | GET_ENCODERS_CHECKSUM, | ||
| 33 | GET_ENCODERS_DATA, | ||
| 34 | #endif // ENCODER_ENABLE | ||
| 35 | |||
| 36 | #ifndef DISABLE_SYNC_TIMER | ||
| 37 | PUT_SYNC_TIMER, | ||
| 38 | #endif // DISABLE_SYNC_TIMER | ||
| 39 | |||
| 40 | #if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE) | ||
| 41 | PUT_LAYER_STATE, | ||
| 42 | PUT_DEFAULT_LAYER_STATE, | ||
| 43 | #endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE) | ||
| 44 | |||
| 45 | #ifdef SPLIT_LED_STATE_ENABLE | ||
| 46 | PUT_LED_STATE, | ||
| 47 | #endif // SPLIT_LED_STATE_ENABLE | ||
| 48 | |||
| 49 | #ifdef SPLIT_MODS_ENABLE | ||
| 50 | PUT_MODS, | ||
| 51 | #endif // SPLIT_MODS_ENABLE | ||
| 52 | |||
| 53 | #ifdef BACKLIGHT_ENABLE | ||
| 54 | PUT_BACKLIGHT, | ||
| 55 | #endif // BACKLIGHT_ENABLE | ||
| 56 | |||
| 57 | #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | ||
| 58 | PUT_RGBLIGHT, | ||
| 59 | #endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | ||
| 60 | |||
| 61 | #if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 62 | PUT_LED_MATRIX, | ||
| 63 | #endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 64 | |||
| 65 | #if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 66 | PUT_RGB_MATRIX, | ||
| 67 | #endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | ||
| 68 | |||
| 69 | #if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE) | ||
| 70 | PUT_WPM, | ||
| 71 | #endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE) | ||
| 72 | |||
| 73 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | ||
| 74 | PUT_RPC_INFO, | ||
| 75 | PUT_RPC_REQ_DATA, | ||
| 76 | EXECUTE_RPC, | ||
| 77 | GET_RPC_RESP_DATA, | ||
| 78 | #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | ||
| 79 | |||
| 80 | // keyboard-specific | ||
| 81 | #ifdef SPLIT_TRANSACTION_IDS_KB | ||
| 82 | SPLIT_TRANSACTION_IDS_KB, | ||
| 83 | #endif // SPLIT_TRANSACTION_IDS_KB | ||
| 84 | |||
| 85 | // user/keymap-specific | ||
| 86 | #ifdef SPLIT_TRANSACTION_IDS_USER | ||
| 87 | SPLIT_TRANSACTION_IDS_USER, | ||
| 88 | #endif // SPLIT_TRANSACTION_IDS_USER | ||
| 89 | |||
| 90 | NUM_TOTAL_TRANSACTIONS | ||
| 91 | }; | ||
| 92 | |||
| 93 | // Ensure we only use 5 bits for transaction | ||
| 94 | _Static_assert(NUM_TOTAL_TRANSACTIONS <= (1 << 5), "Max number of usable transactions exceeded"); | ||
diff --git a/quantum/split_common/transactions.c b/quantum/split_common/transactions.c new file mode 100644 index 000000000..99a8623b3 --- /dev/null +++ b/quantum/split_common/transactions.c | |||
| @@ -0,0 +1,670 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 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 2 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 | |||
| 17 | #include <string.h> | ||
| 18 | #include <stddef.h> | ||
| 19 | |||
| 20 | #include "debug.h" | ||
| 21 | #include "matrix.h" | ||
| 22 | #include "quantum.h" | ||
| 23 | #include "transactions.h" | ||
| 24 | #include "transport.h" | ||
| 25 | #include "transaction_id_define.h" | ||
| 26 | |||
| 27 | #define SYNC_TIMER_OFFSET 2 | ||
| 28 | |||
| 29 | #ifndef FORCED_SYNC_THROTTLE_MS | ||
| 30 | # define FORCED_SYNC_THROTTLE_MS 100 | ||
| 31 | #endif // FORCED_SYNC_THROTTLE_MS | ||
| 32 | |||
| 33 | #define sizeof_member(type, member) sizeof(((type *)NULL)->member) | ||
| 34 | |||
| 35 | #define trans_initiator2target_initializer_cb(member, cb) \ | ||
| 36 | { &dummy, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), 0, 0, cb } | ||
| 37 | #define trans_initiator2target_initializer(member) trans_initiator2target_initializer_cb(member, NULL) | ||
| 38 | |||
| 39 | #define trans_target2initiator_initializer_cb(member, cb) \ | ||
| 40 | { &dummy, 0, 0, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), cb } | ||
| 41 | #define trans_target2initiator_initializer(member) trans_target2initiator_initializer_cb(member, NULL) | ||
| 42 | |||
| 43 | #define transport_write(id, data, length) transport_execute_transaction(id, data, length, NULL, 0) | ||
| 44 | #define transport_read(id, data, length) transport_execute_transaction(id, NULL, 0, data, length) | ||
| 45 | |||
| 46 | static uint8_t crc8(const void *data, size_t len) { | ||
| 47 | const uint8_t *p = (const uint8_t *)data; | ||
| 48 | uint8_t crc = 0xff; | ||
| 49 | size_t i, j; | ||
| 50 | for (i = 0; i < len; i++) { | ||
| 51 | crc ^= p[i]; | ||
| 52 | for (j = 0; j < 8; j++) { | ||
| 53 | if ((crc & 0x80) != 0) | ||
| 54 | crc = (uint8_t)((crc << 1) ^ 0x31); | ||
| 55 | else | ||
| 56 | crc <<= 1; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | return crc; | ||
| 60 | } | ||
| 61 | |||
| 62 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | ||
| 63 | // Forward-declare the RPC callback handlers | ||
| 64 | void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer); | ||
| 65 | void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer); | ||
| 66 | #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | ||
| 67 | |||
| 68 | //////////////////////////////////////////////////// | ||
| 69 | // Helpers | ||
| 70 | |||
| 71 | bool transaction_handler_master(bool okay, 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[])) { | ||
| 72 | if (okay) { | ||
| 73 | bool this_okay = true; | ||
| 74 | for (int iter = 1; iter <= 10; ++iter) { | ||
| 75 | if (!this_okay) { | ||
| 76 | for (int i = 0; i < iter * iter; ++i) { | ||
| 77 | wait_us(10); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | ATOMIC_BLOCK_FORCEON { this_okay = handler(master_matrix, slave_matrix); }; | ||
| 81 | if (this_okay) break; | ||
| 82 | } | ||
| 83 | okay &= this_okay; | ||
| 84 | if (!okay) { | ||
| 85 | dprintf("Failed to execute %s\n", prefix); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | return okay; | ||
| 89 | } | ||
| 90 | |||
| 91 | #define TRANSACTION_HANDLER_MASTER(prefix) \ | ||
| 92 | do { \ | ||
| 93 | okay &= transaction_handler_master(okay, master_matrix, slave_matrix, #prefix, &prefix##_master); \ | ||
| 94 | } while (0) | ||
| 95 | |||
| 96 | #define TRANSACTION_HANDLER_SLAVE(prefix) \ | ||
| 97 | do { \ | ||
| 98 | ATOMIC_BLOCK_FORCEON { prefix##_slave(master_matrix, slave_matrix); }; \ | ||
| 99 | } while (0) | ||
| 100 | |||
| 101 | 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) { | ||
| 102 | uint8_t curr_checksum; | ||
| 103 | bool okay = transport_read(trans_id_checksum, &curr_checksum, sizeof(curr_checksum)); | ||
| 104 | if (okay && (timer_elapsed32(*last_update) >= FORCED_SYNC_THROTTLE_MS || curr_checksum != crc8(equiv_shmem, length))) { | ||
| 105 | okay &= transport_read(trans_id_retrieve, destination, length); | ||
| 106 | okay &= curr_checksum == crc8(equiv_shmem, length); | ||
| 107 | if (okay) { | ||
| 108 | *last_update = timer_read32(); | ||
| 109 | } | ||
| 110 | } else { | ||
| 111 | memcpy(destination, equiv_shmem, length); | ||
| 112 | } | ||
| 113 | return okay; | ||
| 114 | } | ||
| 115 | |||
| 116 | inline static bool send_if_condition(int8_t trans_id, uint32_t *last_update, bool condition, void *source, size_t length) { | ||
| 117 | bool okay = true; | ||
| 118 | if (timer_elapsed32(*last_update) >= FORCED_SYNC_THROTTLE_MS || condition) { | ||
| 119 | okay &= transport_write(trans_id, source, length); | ||
| 120 | if (okay) { | ||
| 121 | *last_update = timer_read32(); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | return okay; | ||
| 125 | } | ||
| 126 | |||
| 127 | inline static bool send_if_data_mismatch(int8_t trans_id, uint32_t *last_update, void *source, const void *equiv_shmem, size_t length) { | ||
| 128 | // Just run a memcmp to compare the source and equivalent shmem location | ||
| 129 | return send_if_condition(trans_id, last_update, (memcmp(source, equiv_shmem, length) != 0), source, length); | ||
| 130 | } | ||
| 131 | |||
| 132 | //////////////////////////////////////////////////// | ||
| 133 | // Slave matrix | ||
| 134 | |||
| 135 | static bool slave_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 136 | static uint32_t last_update = 0; | ||
| 137 | static matrix_row_t last_matrix[(MATRIX_ROWS) / 2] = {0}; // last successfully-read matrix, so we can replicate if there are checksum errors | ||
| 138 | matrix_row_t temp_matrix[(MATRIX_ROWS) / 2]; // holding area while we test whether or not checksum is correct | ||
| 139 | |||
| 140 | 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)); | ||
| 141 | if (okay) { | ||
| 142 | // Checksum matches the received data, save as the last matrix state | ||
| 143 | memcpy(last_matrix, temp_matrix, sizeof(temp_matrix)); | ||
| 144 | } | ||
| 145 | // Copy out the last-known-good matrix state to the slave matrix | ||
| 146 | memcpy(slave_matrix, last_matrix, sizeof(last_matrix)); | ||
| 147 | return okay; | ||
| 148 | } | ||
| 149 | |||
| 150 | static void slave_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 151 | memcpy(split_shmem->smatrix.matrix, slave_matrix, sizeof(split_shmem->smatrix.matrix)); | ||
| 152 | split_shmem->smatrix.checksum = crc8(split_shmem->smatrix.matrix, sizeof(split_shmem->smatrix.matrix)); | ||
| 153 | } | ||
| 154 | |||
| 155 | // clang-format off | ||
| 156 | #define TRANSACTIONS_SLAVE_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(slave_matrix_handlers) | ||
| 157 | #define TRANSACTIONS_SLAVE_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(slave_matrix_handlers) | ||
| 158 | #define TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS \ | ||
| 159 | [GET_SLAVE_MATRIX_CHECKSUM] = trans_target2initiator_initializer(smatrix.checksum), \ | ||
| 160 | [GET_SLAVE_MATRIX_DATA] = trans_target2initiator_initializer(smatrix.matrix), | ||
| 161 | // clang-format on | ||
| 162 | |||
| 163 | //////////////////////////////////////////////////// | ||
| 164 | // Master matrix | ||
| 165 | |||
| 166 | #ifdef SPLIT_TRANSPORT_MIRROR | ||
| 167 | |||
| 168 | static bool master_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 169 | static uint32_t last_update = 0; | ||
| 170 | return send_if_data_mismatch(PUT_MASTER_MATRIX, &last_update, master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix)); | ||
| 171 | } | ||
| 172 | |||
| 173 | static void master_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 174 | // Always copy to the master matrix | ||
| 175 | memcpy(master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix)); | ||
| 176 | } | ||
| 177 | |||
| 178 | # define TRANSACTIONS_MASTER_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(master_matrix_handlers) | ||
| 179 | # define TRANSACTIONS_MASTER_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(master_matrix_handlers) | ||
| 180 | # define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS [PUT_MASTER_MATRIX] = trans_initiator2target_initializer(mmatrix.matrix), | ||
| 181 | |||
| 182 | #else // SPLIT_TRANSPORT_MIRROR | ||
| 183 | |||
| 184 | # define TRANSACTIONS_MASTER_MATRIX_MASTER() | ||
| 185 | # define TRANSACTIONS_MASTER_MATRIX_SLAVE() | ||
| 186 | # define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS | ||
| 187 | |||
| 188 | #endif // SPLIT_TRANSPORT_MIRROR | ||
| 189 | |||
| 190 | //////////////////////////////////////////////////// | ||
| 191 | // Encoders | ||
| 192 | |||
| 193 | #ifdef ENCODER_ENABLE | ||
| 194 | |||
| 195 | static bool encoder_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 196 | static uint32_t last_update = 0; | ||
| 197 | uint8_t temp_state[NUMBER_OF_ENCODERS]; | ||
| 198 | |||
| 199 | bool okay = read_if_checksum_mismatch(GET_ENCODERS_CHECKSUM, GET_ENCODERS_DATA, &last_update, temp_state, split_shmem->encoders.state, sizeof(temp_state)); | ||
| 200 | if (okay) encoder_update_raw(temp_state); | ||
| 201 | return okay; | ||
| 202 | } | ||
| 203 | |||
| 204 | static void encoder_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 205 | uint8_t encoder_state[NUMBER_OF_ENCODERS]; | ||
| 206 | encoder_state_raw(encoder_state); | ||
| 207 | // Always prepare the encoder state for read. | ||
| 208 | memcpy(split_shmem->encoders.state, encoder_state, sizeof(encoder_state)); | ||
| 209 | // Now update the checksum given that the encoders has been written to | ||
| 210 | split_shmem->encoders.checksum = crc8(encoder_state, sizeof(encoder_state)); | ||
| 211 | } | ||
| 212 | |||
| 213 | // clang-format off | ||
| 214 | # define TRANSACTIONS_ENCODERS_MASTER() TRANSACTION_HANDLER_MASTER(encoder_handlers) | ||
| 215 | # define TRANSACTIONS_ENCODERS_SLAVE() TRANSACTION_HANDLER_SLAVE(encoder_handlers) | ||
| 216 | # define TRANSACTIONS_ENCODERS_REGISTRATIONS \ | ||
| 217 | [GET_ENCODERS_CHECKSUM] = trans_target2initiator_initializer(encoders.checksum), \ | ||
| 218 | [GET_ENCODERS_DATA] = trans_target2initiator_initializer(encoders.state), | ||
| 219 | // clang-format on | ||
| 220 | |||
| 221 | #else // ENCODER_ENABLE | ||
| 222 | |||
| 223 | # define TRANSACTIONS_ENCODERS_MASTER() | ||
| 224 | # define TRANSACTIONS_ENCODERS_SLAVE() | ||
| 225 | # define TRANSACTIONS_ENCODERS_REGISTRATIONS | ||
| 226 | |||
| 227 | #endif // ENCODER_ENABLE | ||
| 228 | |||
| 229 | //////////////////////////////////////////////////// | ||
| 230 | // Sync timer | ||
| 231 | |||
| 232 | #ifndef DISABLE_SYNC_TIMER | ||
| 233 | |||
| 234 | static bool sync_timer_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 235 | static uint32_t last_update = 0; | ||
| 236 | |||
| 237 | bool okay = true; | ||
| 238 | if (timer_elapsed32(last_update) >= FORCED_SYNC_THROTTLE_MS) { | ||
| 239 | uint32_t sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET; | ||
| 240 | okay &= transport_write(PUT_SYNC_TIMER, &sync_timer, sizeof(sync_timer)); | ||
| 241 | if (okay) { | ||
| 242 | last_update = timer_read32(); | ||
| 243 | } | ||
| 244 | } | ||
| 245 | return okay; | ||
| 246 | } | ||
| 247 | |||
| 248 | static void sync_timer_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 249 | static uint32_t last_sync_timer = 0; | ||
| 250 | if (last_sync_timer != split_shmem->sync_timer) { | ||
| 251 | last_sync_timer = split_shmem->sync_timer; | ||
| 252 | sync_timer_update(last_sync_timer); | ||
| 253 | } | ||
| 254 | } | ||
| 255 | |||
| 256 | # define TRANSACTIONS_SYNC_TIMER_MASTER() TRANSACTION_HANDLER_MASTER(sync_timer_handlers) | ||
| 257 | # define TRANSACTIONS_SYNC_TIMER_SLAVE() TRANSACTION_HANDLER_SLAVE(sync_timer_handlers) | ||
| 258 | # define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS [PUT_SYNC_TIMER] = trans_initiator2target_initializer(sync_timer), | ||
| 259 | |||
| 260 | #else // DISABLE_SYNC_TIMER | ||
| 261 | |||
| 262 | # define TRANSACTIONS_SYNC_TIMER_MASTER() | ||
| 263 | # define TRANSACTIONS_SYNC_TIMER_SLAVE() | ||
| 264 | # define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS | ||
| 265 | |||
| 266 | #endif // DISABLE_SYNC_TIMER | ||
| 267 | |||
| 268 | //////////////////////////////////////////////////// | ||
| 269 | // Layer state | ||
| 270 | |||
| 271 | #if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE) | ||
| 272 | |||
| 273 | static bool layer_state_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 274 | static uint32_t last_layer_state_update = 0; | ||
| 275 | static uint32_t last_default_layer_state_update = 0; | ||
| 276 | |||
| 277 | bool okay = send_if_condition(PUT_LAYER_STATE, &last_layer_state_update, (layer_state != split_shmem->layers.layer_state), &layer_state, sizeof(layer_state)); | ||
| 278 | if (okay) { | ||
| 279 | 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)); | ||
| 280 | } | ||
| 281 | return okay; | ||
| 282 | } | ||
| 283 | |||
| 284 | static void layer_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 285 | layer_state = split_shmem->layers.layer_state; | ||
| 286 | default_layer_state = split_shmem->layers.default_layer_state; | ||
| 287 | } | ||
| 288 | |||
| 289 | // clang-format off | ||
| 290 | # define TRANSACTIONS_LAYER_STATE_MASTER() TRANSACTION_HANDLER_MASTER(layer_state_handlers) | ||
| 291 | # define TRANSACTIONS_LAYER_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE(layer_state_handlers) | ||
| 292 | # define TRANSACTIONS_LAYER_STATE_REGISTRATIONS \ | ||
| 293 | [PUT_LAYER_STATE] = trans_initiator2target_initializer(layers.layer_state), \ | ||
| 294 | [PUT_DEFAULT_LAYER_STATE] = trans_initiator2target_initializer(layers.default_layer_state), | ||
| 295 | // clang-format on | ||
| 296 | |||
| 297 | #else // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE) | ||
| 298 | |||
| 299 | # define TRANSACTIONS_LAYER_STATE_MASTER() | ||
| 300 | # define TRANSACTIONS_LAYER_STATE_SLAVE() | ||
| 301 | # define TRANSACTIONS_LAYER_STATE_REGISTRATIONS | ||
| 302 | |||
| 303 | #endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE) | ||
| 304 | |||
| 305 | //////////////////////////////////////////////////// | ||
| 306 | // LED state | ||
| 307 | |||
| 308 | #ifdef SPLIT_LED_STATE_ENABLE | ||
| 309 | |||
| 310 | static bool led_state_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 311 | static uint32_t last_update = 0; | ||
| 312 | uint8_t led_state = host_keyboard_leds(); | ||
| 313 | return send_if_data_mismatch(PUT_LED_STATE, &last_update, &led_state, &split_shmem->led_state, sizeof(led_state)); | ||
| 314 | } | ||
| 315 | |||
| 316 | static void led_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 317 | void set_split_host_keyboard_leds(uint8_t led_state); | ||
| 318 | set_split_host_keyboard_leds(split_shmem->led_state); | ||
| 319 | } | ||
| 320 | |||
| 321 | # define TRANSACTIONS_LED_STATE_MASTER() TRANSACTION_HANDLER_MASTER(led_state_handlers) | ||
| 322 | # define TRANSACTIONS_LED_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE(led_state_handlers) | ||
| 323 | # define TRANSACTIONS_LED_STATE_REGISTRATIONS [PUT_LED_STATE] = trans_initiator2target_initializer(led_state), | ||
| 324 | |||
| 325 | #else // SPLIT_LED_STATE_ENABLE | ||
| 326 | |||
| 327 | # define TRANSACTIONS_LED_STATE_MASTER() | ||
| 328 | # define TRANSACTIONS_LED_STATE_SLAVE() | ||
| 329 | # define TRANSACTIONS_LED_STATE_REGISTRATIONS | ||
| 330 | |||
| 331 | #endif // SPLIT_LED_STATE_ENABLE | ||
| 332 | |||
| 333 | //////////////////////////////////////////////////// | ||
| 334 | // Mods | ||
| 335 | |||
| 336 | #ifdef SPLIT_MODS_ENABLE | ||
| 337 | |||
| 338 | static bool mods_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 339 | static uint32_t last_update = 0; | ||
| 340 | bool mods_need_sync = timer_elapsed32(last_update) >= FORCED_SYNC_THROTTLE_MS; | ||
| 341 | split_mods_sync_t new_mods; | ||
| 342 | new_mods.real_mods = get_mods(); | ||
| 343 | if (!mods_need_sync && new_mods.real_mods != split_shmem->mods.real_mods) { | ||
| 344 | mods_need_sync = true; | ||
| 345 | } | ||
| 346 | |||
| 347 | new_mods.weak_mods = get_weak_mods(); | ||
| 348 | if (!mods_need_sync && new_mods.weak_mods != split_shmem->mods.weak_mods) { | ||
| 349 | mods_need_sync = true; | ||
| 350 | } | ||
| 351 | |||
| 352 | # ifndef NO_ACTION_ONESHOT | ||
| 353 | new_mods.oneshot_mods = get_oneshot_mods(); | ||
| 354 | if (!mods_need_sync && new_mods.oneshot_mods != split_shmem->mods.oneshot_mods) { | ||
| 355 | mods_need_sync = true; | ||
| 356 | } | ||
| 357 | # endif // NO_ACTION_ONESHOT | ||
| 358 | |||
| 359 | bool okay = true; | ||
| 360 | if (mods_need_sync) { | ||
| 361 | okay &= transport_write(PUT_MODS, &new_mods, sizeof(new_mods)); | ||
| 362 | if (okay) { | ||
| 363 | last_update = timer_read32(); | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | return okay; | ||
| 368 | } | ||
| 369 | |||
| 370 | static void mods_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 371 | set_mods(split_shmem->mods.real_mods); | ||
| 372 | set_weak_mods(split_shmem->mods.weak_mods); | ||
| 373 | # ifndef NO_ACTION_ONESHOT | ||
| 374 | set_oneshot_mods(split_shmem->mods.oneshot_mods); | ||
| 375 | # endif | ||
| 376 | } | ||
| 377 | |||
| 378 | # define TRANSACTIONS_MODS_MASTER() TRANSACTION_HANDLER_MASTER(mods_handlers) | ||
| 379 | # define TRANSACTIONS_MODS_SLAVE() TRANSACTION_HANDLER_SLAVE(mods_handlers) | ||
| 380 | # define TRANSACTIONS_MODS_REGISTRATIONS [PUT_MODS] = trans_initiator2target_initializer(mods), | ||
| 381 | |||
| 382 | #else // SPLIT_MODS_ENABLE | ||
| 383 | |||
| 384 | # define TRANSACTIONS_MODS_MASTER() | ||
| 385 | # define TRANSACTIONS_MODS_SLAVE() | ||
| 386 | # define TRANSACTIONS_MODS_REGISTRATIONS | ||
| 387 | |||
| 388 | #endif // SPLIT_MODS_ENABLE | ||
| 389 | |||
| 390 | //////////////////////////////////////////////////// | ||
| 391 | // Backlight | ||
| 392 | |||
| 393 | #ifdef BACKLIGHT_ENABLE | ||
| 394 | |||
| 395 | static bool backlight_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 396 | static uint32_t last_update = 0; | ||
| 397 | uint8_t level = is_backlight_enabled() ? get_backlight_level() : 0; | ||
| 398 | return send_if_condition(PUT_BACKLIGHT, &last_update, (level != split_shmem->backlight_level), &level, sizeof(level)); | ||
| 399 | } | ||
| 400 | |||
| 401 | static void backlight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { backlight_set(split_shmem->backlight_level); } | ||
| 402 | |||
| 403 | # define TRANSACTIONS_BACKLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(backlight_handlers) | ||
| 404 | # define TRANSACTIONS_BACKLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(backlight_handlers) | ||
| 405 | # define TRANSACTIONS_BACKLIGHT_REGISTRATIONS [PUT_BACKLIGHT] = trans_initiator2target_initializer(backlight_level), | ||
| 406 | |||
| 407 | #else // BACKLIGHT_ENABLE | ||
| 408 | |||
| 409 | # define TRANSACTIONS_BACKLIGHT_MASTER() | ||
| 410 | # define TRANSACTIONS_BACKLIGHT_SLAVE() | ||
| 411 | # define TRANSACTIONS_BACKLIGHT_REGISTRATIONS | ||
| 412 | |||
| 413 | #endif // BACKLIGHT_ENABLE | ||
| 414 | |||
| 415 | //////////////////////////////////////////////////// | ||
| 416 | // RGBLIGHT | ||
| 417 | |||
| 418 | #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | ||
| 419 | |||
| 420 | static bool rgblight_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 421 | static uint32_t last_update = 0; | ||
| 422 | rgblight_syncinfo_t rgblight_sync; | ||
| 423 | rgblight_get_syncinfo(&rgblight_sync); | ||
| 424 | if (send_if_condition(PUT_RGBLIGHT, &last_update, (rgblight_sync.status.change_flags != 0), &rgblight_sync, sizeof(rgblight_sync))) { | ||
| 425 | rgblight_clear_change_flags(); | ||
| 426 | } else { | ||
| 427 | return false; | ||
| 428 | } | ||
| 429 | return true; | ||
| 430 | } | ||
| 431 | |||
| 432 | static void rgblight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 433 | // Update the RGB with the new data | ||
| 434 | if (split_shmem->rgblight_sync.status.change_flags != 0) { | ||
| 435 | rgblight_update_sync(&split_shmem->rgblight_sync, false); | ||
| 436 | split_shmem->rgblight_sync.status.change_flags = 0; | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 440 | # define TRANSACTIONS_RGBLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(rgblight_handlers) | ||
| 441 | # define TRANSACTIONS_RGBLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(rgblight_handlers) | ||
| 442 | # define TRANSACTIONS_RGBLIGHT_REGISTRATIONS [PUT_RGBLIGHT] = trans_initiator2target_initializer(rgblight_sync), | ||
| 443 | |||
| 444 | #else // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | ||
| 445 | |||
| 446 | # define TRANSACTIONS_RGBLIGHT_MASTER() | ||
| 447 | # define TRANSACTIONS_RGBLIGHT_SLAVE() | ||
| 448 | # define TRANSACTIONS_RGBLIGHT_REGISTRATIONS | ||
| 449 | |||
| 450 | #endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | ||
| 451 | |||
| 452 | //////////////////////////////////////////////////// | ||
| 453 | // LED Matrix | ||
| 454 | |||
| 455 | #if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 456 | |||
| 457 | static bool led_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 458 | static uint32_t last_update = 0; | ||
| 459 | led_matrix_sync_t led_matrix_sync; | ||
| 460 | memcpy(&led_matrix_sync.led_matrix, &led_matrix_eeconfig, sizeof(led_eeconfig_t)); | ||
| 461 | led_matrix_sync.led_suspend_state = led_matrix_get_suspend_state(); | ||
| 462 | return send_if_data_mismatch(PUT_LED_MATRIX, &last_update, &led_matrix_sync, &split_shmem->led_matrix_sync, sizeof(led_matrix_sync)); | ||
| 463 | } | ||
| 464 | |||
| 465 | static void led_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 466 | memcpy(&led_matrix_eeconfig, &split_shmem->led_matrix_sync.led_matrix, sizeof(led_eeconfig_t)); | ||
| 467 | led_matrix_set_suspend_state(split_shmem->led_matrix_sync.led_suspend_state); | ||
| 468 | } | ||
| 469 | |||
| 470 | # define TRANSACTIONS_LED_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(led_matrix_handlers) | ||
| 471 | # define TRANSACTIONS_LED_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(led_matrix_handlers) | ||
| 472 | # define TRANSACTIONS_LED_MATRIX_REGISTRATIONS [PUT_LED_MATRIX] = trans_initiator2target_initializer(led_matrix_sync), | ||
| 473 | |||
| 474 | #else // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 475 | |||
| 476 | # define TRANSACTIONS_LED_MATRIX_MASTER() | ||
| 477 | # define TRANSACTIONS_LED_MATRIX_SLAVE() | ||
| 478 | # define TRANSACTIONS_LED_MATRIX_REGISTRATIONS | ||
| 479 | |||
| 480 | #endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 481 | |||
| 482 | //////////////////////////////////////////////////// | ||
| 483 | // RGB Matrix | ||
| 484 | |||
| 485 | #if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 486 | |||
| 487 | static bool rgb_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 488 | static uint32_t last_update = 0; | ||
| 489 | rgb_matrix_sync_t rgb_matrix_sync; | ||
| 490 | memcpy(&rgb_matrix_sync.rgb_matrix, &rgb_matrix_config, sizeof(rgb_config_t)); | ||
| 491 | rgb_matrix_sync.rgb_suspend_state = rgb_matrix_get_suspend_state(); | ||
| 492 | return send_if_data_mismatch(PUT_RGB_MATRIX, &last_update, &rgb_matrix_sync, &split_shmem->rgb_matrix_sync, sizeof(rgb_matrix_sync)); | ||
| 493 | } | ||
| 494 | |||
| 495 | static void rgb_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 496 | memcpy(&rgb_matrix_config, &split_shmem->rgb_matrix_sync.rgb_matrix, sizeof(rgb_config_t)); | ||
| 497 | rgb_matrix_set_suspend_state(split_shmem->rgb_matrix_sync.rgb_suspend_state); | ||
| 498 | } | ||
| 499 | |||
| 500 | # define TRANSACTIONS_RGB_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(rgb_matrix_handlers) | ||
| 501 | # define TRANSACTIONS_RGB_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(rgb_matrix_handlers) | ||
| 502 | # define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS [PUT_RGB_MATRIX] = trans_initiator2target_initializer(rgb_matrix_sync), | ||
| 503 | |||
| 504 | #else // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 505 | |||
| 506 | # define TRANSACTIONS_RGB_MATRIX_MASTER() | ||
| 507 | # define TRANSACTIONS_RGB_MATRIX_SLAVE() | ||
| 508 | # define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS | ||
| 509 | |||
| 510 | #endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 511 | |||
| 512 | //////////////////////////////////////////////////// | ||
| 513 | // WPM | ||
| 514 | |||
| 515 | #if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE) | ||
| 516 | |||
| 517 | static bool wpm_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 518 | static uint32_t last_update = 0; | ||
| 519 | uint8_t current_wpm = get_current_wpm(); | ||
| 520 | return send_if_condition(PUT_WPM, &last_update, (current_wpm != split_shmem->current_wpm), ¤t_wpm, sizeof(current_wpm)); | ||
| 521 | } | ||
| 522 | |||
| 523 | static void wpm_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { set_current_wpm(split_shmem->current_wpm); } | ||
| 524 | |||
| 525 | # define TRANSACTIONS_WPM_MASTER() TRANSACTION_HANDLER_MASTER(wpm_handlers) | ||
| 526 | # define TRANSACTIONS_WPM_SLAVE() TRANSACTION_HANDLER_SLAVE(wpm_handlers) | ||
| 527 | # define TRANSACTIONS_WPM_REGISTRATIONS [PUT_WPM] = trans_initiator2target_initializer(current_wpm), | ||
| 528 | |||
| 529 | #else // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE) | ||
| 530 | |||
| 531 | # define TRANSACTIONS_WPM_MASTER() | ||
| 532 | # define TRANSACTIONS_WPM_SLAVE() | ||
| 533 | # define TRANSACTIONS_WPM_REGISTRATIONS | ||
| 534 | |||
| 535 | #endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE) | ||
| 536 | |||
| 537 | //////////////////////////////////////////////////// | ||
| 538 | |||
| 539 | uint8_t dummy; | ||
| 540 | split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = { | ||
| 541 | // Set defaults | ||
| 542 | [0 ...(NUM_TOTAL_TRANSACTIONS - 1)] = {NULL, 0, 0, 0, 0, 0}, | ||
| 543 | |||
| 544 | #ifdef USE_I2C | ||
| 545 | [I2C_EXECUTE_CALLBACK] = trans_initiator2target_initializer(transaction_id), | ||
| 546 | #endif // USE_I2C | ||
| 547 | |||
| 548 | // clang-format off | ||
| 549 | TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS | ||
| 550 | TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS | ||
| 551 | TRANSACTIONS_ENCODERS_REGISTRATIONS | ||
| 552 | TRANSACTIONS_SYNC_TIMER_REGISTRATIONS | ||
| 553 | TRANSACTIONS_LAYER_STATE_REGISTRATIONS | ||
| 554 | TRANSACTIONS_LED_STATE_REGISTRATIONS | ||
| 555 | TRANSACTIONS_MODS_REGISTRATIONS | ||
| 556 | TRANSACTIONS_BACKLIGHT_REGISTRATIONS | ||
| 557 | TRANSACTIONS_RGBLIGHT_REGISTRATIONS | ||
| 558 | TRANSACTIONS_LED_MATRIX_REGISTRATIONS | ||
| 559 | TRANSACTIONS_RGB_MATRIX_REGISTRATIONS | ||
| 560 | TRANSACTIONS_WPM_REGISTRATIONS | ||
| 561 | // clang-format on | ||
| 562 | |||
| 563 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | ||
| 564 | [PUT_RPC_INFO] = trans_initiator2target_initializer_cb(rpc_info, slave_rpc_info_callback), | ||
| 565 | [PUT_RPC_REQ_DATA] = trans_initiator2target_initializer(rpc_m2s_buffer), | ||
| 566 | [EXECUTE_RPC] = trans_initiator2target_initializer_cb(rpc_info.transaction_id, slave_rpc_exec_callback), | ||
| 567 | [GET_RPC_RESP_DATA] = trans_target2initiator_initializer(rpc_s2m_buffer), | ||
| 568 | #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | ||
| 569 | }; | ||
| 570 | |||
| 571 | bool transactions_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 572 | bool okay = true; | ||
| 573 | TRANSACTIONS_SLAVE_MATRIX_MASTER(); | ||
| 574 | TRANSACTIONS_MASTER_MATRIX_MASTER(); | ||
| 575 | TRANSACTIONS_ENCODERS_MASTER(); | ||
| 576 | TRANSACTIONS_SYNC_TIMER_MASTER(); | ||
| 577 | TRANSACTIONS_LAYER_STATE_MASTER(); | ||
| 578 | TRANSACTIONS_LED_STATE_MASTER(); | ||
| 579 | TRANSACTIONS_MODS_MASTER(); | ||
| 580 | TRANSACTIONS_BACKLIGHT_MASTER(); | ||
| 581 | TRANSACTIONS_RGBLIGHT_MASTER(); | ||
| 582 | TRANSACTIONS_LED_MATRIX_MASTER(); | ||
| 583 | TRANSACTIONS_RGB_MATRIX_MASTER(); | ||
| 584 | TRANSACTIONS_WPM_MASTER(); | ||
| 585 | return okay; | ||
| 586 | } | ||
| 587 | |||
| 588 | void transactions_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 589 | TRANSACTIONS_SLAVE_MATRIX_SLAVE(); | ||
| 590 | TRANSACTIONS_MASTER_MATRIX_SLAVE(); | ||
| 591 | TRANSACTIONS_ENCODERS_SLAVE(); | ||
| 592 | TRANSACTIONS_SYNC_TIMER_SLAVE(); | ||
| 593 | TRANSACTIONS_LAYER_STATE_SLAVE(); | ||
| 594 | TRANSACTIONS_LED_STATE_SLAVE(); | ||
| 595 | TRANSACTIONS_MODS_SLAVE(); | ||
| 596 | TRANSACTIONS_BACKLIGHT_SLAVE(); | ||
| 597 | TRANSACTIONS_RGBLIGHT_SLAVE(); | ||
| 598 | TRANSACTIONS_LED_MATRIX_SLAVE(); | ||
| 599 | TRANSACTIONS_RGB_MATRIX_SLAVE(); | ||
| 600 | TRANSACTIONS_WPM_SLAVE(); | ||
| 601 | } | ||
| 602 | |||
| 603 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | ||
| 604 | |||
| 605 | void transaction_register_rpc(int8_t transaction_id, slave_callback_t callback) { | ||
| 606 | // Prevent invoking RPC on QMK core sync data | ||
| 607 | if (transaction_id <= GET_RPC_RESP_DATA) return; | ||
| 608 | |||
| 609 | // Set the callback | ||
| 610 | split_transaction_table[transaction_id].slave_callback = callback; | ||
| 611 | split_transaction_table[transaction_id].initiator2target_offset = offsetof(split_shared_memory_t, rpc_m2s_buffer); | ||
| 612 | split_transaction_table[transaction_id].target2initiator_offset = offsetof(split_shared_memory_t, rpc_s2m_buffer); | ||
| 613 | } | ||
| 614 | |||
| 615 | 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) { | ||
| 616 | // Prevent invoking RPC on QMK core sync data | ||
| 617 | if (transaction_id <= GET_RPC_RESP_DATA) return false; | ||
| 618 | // Prevent sizing issues | ||
| 619 | if (initiator2target_buffer_size > RPC_M2S_BUFFER_SIZE) return false; | ||
| 620 | if (target2initiator_buffer_size > RPC_S2M_BUFFER_SIZE) return false; | ||
| 621 | |||
| 622 | // Prepare the metadata block | ||
| 623 | rpc_sync_info_t info = {.transaction_id = transaction_id, .m2s_length = initiator2target_buffer_size, .s2m_length = target2initiator_buffer_size}; | ||
| 624 | |||
| 625 | // Make sure the local side knows that we're not sending the full block of data | ||
| 626 | split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = initiator2target_buffer_size; | ||
| 627 | split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = target2initiator_buffer_size; | ||
| 628 | |||
| 629 | // Run through the sequence: | ||
| 630 | // * set the transaction ID and lengths | ||
| 631 | // * send the request data | ||
| 632 | // * execute RPC callback | ||
| 633 | // * retrieve the response data | ||
| 634 | if (!transport_write(PUT_RPC_INFO, &info, sizeof(info))) { | ||
| 635 | return false; | ||
| 636 | } | ||
| 637 | if (!transport_write(PUT_RPC_REQ_DATA, initiator2target_buffer, initiator2target_buffer_size)) { | ||
| 638 | return false; | ||
| 639 | } | ||
| 640 | if (!transport_write(EXECUTE_RPC, &transaction_id, sizeof(transaction_id))) { | ||
| 641 | return false; | ||
| 642 | } | ||
| 643 | if (!transport_read(GET_RPC_RESP_DATA, target2initiator_buffer, target2initiator_buffer_size)) { | ||
| 644 | return false; | ||
| 645 | } | ||
| 646 | return true; | ||
| 647 | } | ||
| 648 | |||
| 649 | void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) { | ||
| 650 | // The RPC info block contains the intended transaction ID, as well as the sizes for both inbound and outbound data. | ||
| 651 | // Ignore the args -- the `split_shmem` already has the info, we just need to act upon it. | ||
| 652 | // We must keep the `split_transaction_table` non-const, so that it is able to be modified at runtime. | ||
| 653 | |||
| 654 | split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = split_shmem->rpc_info.m2s_length; | ||
| 655 | split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = split_shmem->rpc_info.s2m_length; | ||
| 656 | } | ||
| 657 | |||
| 658 | void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) { | ||
| 659 | // We can assume that the buffer lengths are correctly set, now, given that sequentially the rpc_info callback was already executed. | ||
| 660 | // Go through the rpc_info and execute _that_ transaction's callback, with the scratch buffers as inputs. | ||
| 661 | int8_t transaction_id = split_shmem->rpc_info.transaction_id; | ||
| 662 | if (transaction_id < NUM_TOTAL_TRANSACTIONS) { | ||
| 663 | split_transaction_desc_t *trans = &split_transaction_table[transaction_id]; | ||
| 664 | if (trans->slave_callback) { | ||
| 665 | trans->slave_callback(split_shmem->rpc_info.m2s_length, split_shmem->rpc_m2s_buffer, split_shmem->rpc_info.s2m_length, split_shmem->rpc_s2m_buffer); | ||
| 666 | } | ||
| 667 | } | ||
| 668 | } | ||
| 669 | |||
| 670 | #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | ||
diff --git a/quantum/split_common/transactions.h b/quantum/split_common/transactions.h new file mode 100644 index 000000000..4306ba1d8 --- /dev/null +++ b/quantum/split_common/transactions.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 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 2 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 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #include "stdint.h" | ||
| 20 | #include "stdbool.h" | ||
| 21 | |||
| 22 | #include "matrix.h" | ||
| 23 | #include "transaction_id_define.h" | ||
| 24 | #include "transport.h" | ||
| 25 | |||
| 26 | typedef void (*slave_callback_t)(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer); | ||
| 27 | |||
| 28 | // Split transaction Descriptor | ||
| 29 | typedef struct _split_transaction_desc_t { | ||
| 30 | uint8_t * status; | ||
| 31 | uint8_t initiator2target_buffer_size; | ||
| 32 | uint16_t initiator2target_offset; | ||
| 33 | uint8_t target2initiator_buffer_size; | ||
| 34 | uint16_t target2initiator_offset; | ||
| 35 | slave_callback_t slave_callback; | ||
| 36 | } split_transaction_desc_t; | ||
| 37 | |||
| 38 | // Forward declaration for the split transactions | ||
| 39 | extern split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS]; | ||
| 40 | |||
| 41 | #define split_shmem_offset_ptr(offset) ((void *)(((uint8_t *)split_shmem) + (offset))) | ||
| 42 | #define split_trans_initiator2target_buffer(trans) (split_shmem_offset_ptr((trans)->initiator2target_offset)) | ||
| 43 | #define split_trans_target2initiator_buffer(trans) (split_shmem_offset_ptr((trans)->target2initiator_offset)) | ||
| 44 | |||
| 45 | // returns false if valid data not received from slave | ||
| 46 | bool transactions_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]); | ||
| 47 | void transactions_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]); | ||
| 48 | |||
| 49 | void transaction_register_rpc(int8_t transaction_id, slave_callback_t callback); | ||
| 50 | |||
| 51 | 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); | ||
| 52 | |||
| 53 | #define transaction_rpc_send(transaction_id, initiator2target_buffer_size, initiator2target_buffer) transaction_rpc_exec(transaction_id, initiator2target_buffer_size, initiator2target_buffer, 0, NULL) | ||
| 54 | #define transaction_rpc_recv(transaction_id, target2initiator_buffer_size, target2initiator_buffer) transaction_rpc_exec(transaction_id, 0, NULL, target2initiator_buffer_size, target2initiator_buffer) | ||
diff --git a/quantum/split_common/transport.c b/quantum/split_common/transport.c index 9ed0f7591..a711ef85f 100644 --- a/quantum/split_common/transport.c +++ b/quantum/split_common/transport.c | |||
| @@ -1,452 +1,118 @@ | |||
| 1 | #include <string.h> | 1 | /* Copyright 2021 QMK |
| 2 | #include <stddef.h> | 2 | * |
| 3 | 3 | * This program is free software: you can redistribute it and/or modify | |
| 4 | #include "config.h" | 4 | * it under the terms of the GNU General Public License as published by |
| 5 | #include "matrix.h" | 5 | * the Free Software Foundation, either version 2 of the License, or |
| 6 | #include "quantum.h" | 6 | * (at your option) any later version. |
| 7 | 7 | * | |
| 8 | #define ROWS_PER_HAND (MATRIX_ROWS / 2) | 8 | * This program is distributed in the hope that it will be useful, |
| 9 | #define SYNC_TIMER_OFFSET 2 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 11 | #ifdef RGBLIGHT_ENABLE | 11 | * GNU General Public License for more details. |
| 12 | # include "rgblight.h" | 12 | * |
| 13 | #endif | 13 | * You should have received a copy of the GNU General Public License |
| 14 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 15 | #ifdef BACKLIGHT_ENABLE | 15 | */ |
| 16 | # include "backlight.h" | ||
| 17 | #endif | ||
| 18 | |||
| 19 | #ifdef ENCODER_ENABLE | ||
| 20 | # include "encoder.h" | ||
| 21 | static pin_t encoders_pad[] = ENCODERS_PAD_A; | ||
| 22 | # define NUMBER_OF_ENCODERS (sizeof(encoders_pad) / sizeof(pin_t)) | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 26 | # include "led_matrix.h" | ||
| 27 | #endif | ||
| 28 | #if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 29 | # include "rgb_matrix.h" | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #if defined(USE_I2C) | ||
| 33 | 16 | ||
| 34 | # include "i2c_master.h" | 17 | #include <string.h> |
| 35 | # include "i2c_slave.h" | 18 | #include <debug.h> |
| 36 | |||
| 37 | typedef struct _I2C_slave_buffer_t { | ||
| 38 | # ifndef DISABLE_SYNC_TIMER | ||
| 39 | uint32_t sync_timer; | ||
| 40 | # endif | ||
| 41 | # ifdef SPLIT_TRANSPORT_MIRROR | ||
| 42 | matrix_row_t mmatrix[ROWS_PER_HAND]; | ||
| 43 | # endif | ||
| 44 | matrix_row_t smatrix[ROWS_PER_HAND]; | ||
| 45 | # ifdef SPLIT_MODS_ENABLE | ||
| 46 | uint8_t real_mods; | ||
| 47 | uint8_t weak_mods; | ||
| 48 | # ifndef NO_ACTION_ONESHOT | ||
| 49 | uint8_t oneshot_mods; | ||
| 50 | # endif | ||
| 51 | # endif | ||
| 52 | # ifdef BACKLIGHT_ENABLE | ||
| 53 | uint8_t backlight_level; | ||
| 54 | # endif | ||
| 55 | # if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | ||
| 56 | rgblight_syncinfo_t rgblight_sync; | ||
| 57 | # endif | ||
| 58 | # ifdef ENCODER_ENABLE | ||
| 59 | uint8_t encoder_state[NUMBER_OF_ENCODERS]; | ||
| 60 | # endif | ||
| 61 | # ifdef WPM_ENABLE | ||
| 62 | uint8_t current_wpm; | ||
| 63 | # endif | ||
| 64 | # if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 65 | led_eeconfig_t led_matrix; | ||
| 66 | bool led_suspend_state; | ||
| 67 | # endif | ||
| 68 | # if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 69 | rgb_config_t rgb_matrix; | ||
| 70 | bool rgb_suspend_state; | ||
| 71 | # endif | ||
| 72 | } I2C_slave_buffer_t; | ||
| 73 | 19 | ||
| 74 | static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_reg; | 20 | #include "transactions.h" |
| 21 | #include "transport.h" | ||
| 22 | #include "transaction_id_define.h" | ||
| 23 | #include "atomic_util.h" | ||
| 75 | 24 | ||
| 76 | # define I2C_SYNC_TIME_START offsetof(I2C_slave_buffer_t, sync_timer) | 25 | #ifdef USE_I2C |
| 77 | # define I2C_KEYMAP_MASTER_START offsetof(I2C_slave_buffer_t, mmatrix) | ||
| 78 | # define I2C_KEYMAP_SLAVE_START offsetof(I2C_slave_buffer_t, smatrix) | ||
| 79 | # define I2C_REAL_MODS_START offsetof(I2C_slave_buffer_t, real_mods) | ||
| 80 | # define I2C_WEAK_MODS_START offsetof(I2C_slave_buffer_t, weak_mods) | ||
| 81 | # define I2C_ONESHOT_MODS_START offsetof(I2C_slave_buffer_t, oneshot_mods) | ||
| 82 | # define I2C_BACKLIGHT_START offsetof(I2C_slave_buffer_t, backlight_level) | ||
| 83 | # define I2C_RGB_START offsetof(I2C_slave_buffer_t, rgblight_sync) | ||
| 84 | # define I2C_ENCODER_START offsetof(I2C_slave_buffer_t, encoder_state) | ||
| 85 | # define I2C_WPM_START offsetof(I2C_slave_buffer_t, current_wpm) | ||
| 86 | # define I2C_LED_MATRIX_START offsetof(I2C_slave_buffer_t, led_matrix) | ||
| 87 | # define I2C_LED_SUSPEND_START offsetof(I2C_slave_buffer_t, led_suspend_state) | ||
| 88 | # define I2C_RGB_MATRIX_START offsetof(I2C_slave_buffer_t, rgb_matrix) | ||
| 89 | # define I2C_RGB_SUSPEND_START offsetof(I2C_slave_buffer_t, rgb_suspend_state) | ||
| 90 | 26 | ||
| 91 | # define TIMEOUT 100 | 27 | # ifndef SLAVE_I2C_TIMEOUT |
| 28 | # define SLAVE_I2C_TIMEOUT 100 | ||
| 29 | # endif // SLAVE_I2C_TIMEOUT | ||
| 92 | 30 | ||
| 93 | # ifndef SLAVE_I2C_ADDRESS | 31 | # ifndef SLAVE_I2C_ADDRESS |
| 94 | # define SLAVE_I2C_ADDRESS 0x32 | 32 | # define SLAVE_I2C_ADDRESS 0x32 |
| 95 | # endif | 33 | # endif |
| 96 | 34 | ||
| 97 | // Get rows from other half over i2c | 35 | # include "i2c_master.h" |
| 98 | bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | 36 | # include "i2c_slave.h" |
| 99 | i2c_readReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_SLAVE_START, (void *)slave_matrix, sizeof(i2c_buffer->smatrix), TIMEOUT); | ||
| 100 | # ifdef SPLIT_TRANSPORT_MIRROR | ||
| 101 | i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_MASTER_START, (void *)master_matrix, sizeof(i2c_buffer->mmatrix), TIMEOUT); | ||
| 102 | # endif | ||
| 103 | 37 | ||
| 104 | // write backlight info | 38 | // Ensure the I2C buffer has enough space |
| 105 | # ifdef BACKLIGHT_ENABLE | 39 | _Static_assert(sizeof(split_shared_memory_t) <= I2C_SLAVE_REG_COUNT, "split_shared_memory_t too large for I2C_SLAVE_REG_COUNT"); |
| 106 | uint8_t level = is_backlight_enabled() ? get_backlight_level() : 0; | ||
| 107 | if (level != i2c_buffer->backlight_level) { | ||
| 108 | if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_BACKLIGHT_START, (void *)&level, sizeof(level), TIMEOUT) >= 0) { | ||
| 109 | i2c_buffer->backlight_level = level; | ||
| 110 | } | ||
| 111 | } | ||
| 112 | # endif | ||
| 113 | 40 | ||
| 114 | # if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | 41 | split_shared_memory_t *const split_shmem = (split_shared_memory_t *)i2c_slave_reg; |
| 115 | if (rgblight_get_change_flags()) { | ||
| 116 | rgblight_syncinfo_t rgblight_sync; | ||
| 117 | rgblight_get_syncinfo(&rgblight_sync); | ||
| 118 | if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_RGB_START, (void *)&rgblight_sync, sizeof(rgblight_sync), TIMEOUT) >= 0) { | ||
| 119 | rgblight_clear_change_flags(); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | # endif | ||
| 123 | 42 | ||
| 124 | # ifdef ENCODER_ENABLE | 43 | void transport_master_init(void) { i2c_init(); } |
| 125 | i2c_readReg(SLAVE_I2C_ADDRESS, I2C_ENCODER_START, (void *)i2c_buffer->encoder_state, sizeof(i2c_buffer->encoder_state), TIMEOUT); | 44 | void transport_slave_init(void) { i2c_slave_init(SLAVE_I2C_ADDRESS); } |
| 126 | encoder_update_raw(i2c_buffer->encoder_state); | ||
| 127 | # endif | ||
| 128 | 45 | ||
| 129 | # ifdef WPM_ENABLE | 46 | i2c_status_t transport_trigger_callback(int8_t id) { |
| 130 | uint8_t current_wpm = get_current_wpm(); | 47 | // If there's no callback, indicate that we were successful |
| 131 | if (current_wpm != i2c_buffer->current_wpm) { | 48 | if (!split_transaction_table[id].slave_callback) { |
| 132 | if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_WPM_START, (void *)¤t_wpm, sizeof(current_wpm), TIMEOUT) >= 0) { | 49 | return I2C_STATUS_SUCCESS; |
| 133 | i2c_buffer->current_wpm = current_wpm; | ||
| 134 | } | ||
| 135 | } | 50 | } |
| 136 | # endif | ||
| 137 | 51 | ||
| 138 | # ifdef SPLIT_MODS_ENABLE | 52 | // Kick off the "callback executor", now that data has been written to the slave |
| 139 | uint8_t real_mods = get_mods(); | 53 | split_shmem->transaction_id = id; |
| 140 | if (real_mods != i2c_buffer->real_mods) { | 54 | split_transaction_desc_t *trans = &split_transaction_table[I2C_EXECUTE_CALLBACK]; |
| 141 | if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_REAL_MODS_START, (void *)&real_mods, sizeof(real_mods), TIMEOUT) >= 0) { | 55 | return i2c_writeReg(SLAVE_I2C_ADDRESS, trans->initiator2target_offset, split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size, SLAVE_I2C_TIMEOUT); |
| 142 | i2c_buffer->real_mods = real_mods; | 56 | } |
| 57 | |||
| 58 | bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, uint16_t initiator2target_length, void *target2initiator_buf, uint16_t target2initiator_length) { | ||
| 59 | i2c_status_t status; | ||
| 60 | split_transaction_desc_t *trans = &split_transaction_table[id]; | ||
| 61 | if (initiator2target_length > 0) { | ||
| 62 | size_t len = trans->initiator2target_buffer_size < initiator2target_length ? trans->initiator2target_buffer_size : initiator2target_length; | ||
| 63 | memcpy(split_trans_initiator2target_buffer(trans), initiator2target_buf, len); | ||
| 64 | if ((status = i2c_writeReg(SLAVE_I2C_ADDRESS, trans->initiator2target_offset, split_trans_initiator2target_buffer(trans), len, SLAVE_I2C_TIMEOUT)) < 0) { | ||
| 65 | return false; | ||
| 143 | } | 66 | } |
| 144 | } | 67 | } |
| 145 | 68 | ||
| 146 | uint8_t weak_mods = get_weak_mods(); | 69 | // If we need to execute a callback on the slave, do so |
| 147 | if (weak_mods != i2c_buffer->weak_mods) { | 70 | if ((status = transport_trigger_callback(id)) < 0) { |
| 148 | if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_WEAK_MODS_START, (void *)&weak_mods, sizeof(weak_mods), TIMEOUT) >= 0) { | 71 | return false; |
| 149 | i2c_buffer->weak_mods = weak_mods; | ||
| 150 | } | ||
| 151 | } | 72 | } |
| 152 | 73 | ||
| 153 | # ifndef NO_ACTION_ONESHOT | 74 | if (target2initiator_length > 0) { |
| 154 | uint8_t oneshot_mods = get_oneshot_mods(); | 75 | size_t len = trans->target2initiator_buffer_size < target2initiator_length ? trans->target2initiator_buffer_size : target2initiator_length; |
| 155 | if (oneshot_mods != i2c_buffer->oneshot_mods) { | 76 | if ((status = i2c_readReg(SLAVE_I2C_ADDRESS, trans->target2initiator_offset, split_trans_target2initiator_buffer(trans), len, SLAVE_I2C_TIMEOUT)) < 0) { |
| 156 | if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_ONESHOT_MODS_START, (void *)&oneshot_mods, sizeof(oneshot_mods), TIMEOUT) >= 0) { | 77 | return false; |
| 157 | i2c_buffer->oneshot_mods = oneshot_mods; | ||
| 158 | } | 78 | } |
| 79 | memcpy(target2initiator_buf, split_trans_target2initiator_buffer(trans), len); | ||
| 159 | } | 80 | } |
| 160 | # endif | ||
| 161 | # endif | ||
| 162 | 81 | ||
| 163 | # if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 164 | i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_LED_MATRIX_START, (void *)led_matrix_eeconfig, sizeof(i2c_buffer->led_matrix), TIMEOUT); | ||
| 165 | bool suspend_state = led_matrix_get_suspend_state(); | ||
| 166 | i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_LED_SUSPEND_START, (void *)suspend_state, sizeof(i2c_buffer->led_suspend_state), TIMEOUT); | ||
| 167 | # endif | ||
| 168 | # if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 169 | i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_RGB_MATRIX_START, (void *)rgb_matrix_config, sizeof(i2c_buffer->rgb_matrix), TIMEOUT); | ||
| 170 | bool suspend_state = rgb_matrix_get_suspend_state(); | ||
| 171 | i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_RGB_SUSPEND_START, (void *)suspend_state, sizeof(i2c_buffer->rgb_suspend_state), TIMEOUT); | ||
| 172 | # endif | ||
| 173 | |||
| 174 | # ifndef DISABLE_SYNC_TIMER | ||
| 175 | i2c_buffer->sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET; | ||
| 176 | i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_SYNC_TIME_START, (void *)&i2c_buffer->sync_timer, sizeof(i2c_buffer->sync_timer), TIMEOUT); | ||
| 177 | # endif | ||
| 178 | return true; | 82 | return true; |
| 179 | } | 83 | } |
| 180 | 84 | ||
| 181 | void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | 85 | #else // USE_I2C |
| 182 | # ifndef DISABLE_SYNC_TIMER | ||
| 183 | sync_timer_update(i2c_buffer->sync_timer); | ||
| 184 | # endif | ||
| 185 | // Copy matrix to I2C buffer | ||
| 186 | memcpy((void *)i2c_buffer->smatrix, (void *)slave_matrix, sizeof(i2c_buffer->smatrix)); | ||
| 187 | # ifdef SPLIT_TRANSPORT_MIRROR | ||
| 188 | memcpy((void *)master_matrix, (void *)i2c_buffer->mmatrix, sizeof(i2c_buffer->mmatrix)); | ||
| 189 | # endif | ||
| 190 | |||
| 191 | // Read Backlight Info | ||
| 192 | # ifdef BACKLIGHT_ENABLE | ||
| 193 | backlight_set(i2c_buffer->backlight_level); | ||
| 194 | # endif | ||
| 195 | |||
| 196 | # if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | ||
| 197 | // Update the RGB with the new data | ||
| 198 | if (i2c_buffer->rgblight_sync.status.change_flags != 0) { | ||
| 199 | rgblight_update_sync(&i2c_buffer->rgblight_sync, false); | ||
| 200 | i2c_buffer->rgblight_sync.status.change_flags = 0; | ||
| 201 | } | ||
| 202 | # endif | ||
| 203 | |||
| 204 | # ifdef ENCODER_ENABLE | ||
| 205 | encoder_state_raw(i2c_buffer->encoder_state); | ||
| 206 | # endif | ||
| 207 | |||
| 208 | # ifdef WPM_ENABLE | ||
| 209 | set_current_wpm(i2c_buffer->current_wpm); | ||
| 210 | # endif | ||
| 211 | |||
| 212 | # ifdef SPLIT_MODS_ENABLE | ||
| 213 | set_mods(i2c_buffer->real_mods); | ||
| 214 | set_weak_mods(i2c_buffer->weak_mods); | ||
| 215 | # ifndef NO_ACTION_ONESHOT | ||
| 216 | set_oneshot_mods(i2c_buffer->oneshot_mods); | ||
| 217 | # endif | ||
| 218 | # endif | ||
| 219 | |||
| 220 | # if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 221 | memcpy((void *)i2c_buffer->led_matrix, (void *)led_matrix_eeconfig, sizeof(i2c_buffer->led_matrix)); | ||
| 222 | led_matrix_set_suspend_state(i2c_buffer->led_suspend_state); | ||
| 223 | # endif | ||
| 224 | # if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 225 | memcpy((void *)i2c_buffer->rgb_matrix, (void *)rgb_matrix_config, sizeof(i2c_buffer->rgb_matrix)); | ||
| 226 | rgb_matrix_set_suspend_state(i2c_buffer->rgb_suspend_state); | ||
| 227 | # endif | ||
| 228 | } | ||
| 229 | |||
| 230 | void transport_master_init(void) { i2c_init(); } | ||
| 231 | |||
| 232 | void transport_slave_init(void) { i2c_slave_init(SLAVE_I2C_ADDRESS); } | ||
| 233 | |||
| 234 | #else // USE_SERIAL | ||
| 235 | 86 | ||
| 236 | # include "serial.h" | 87 | # include "serial.h" |
| 237 | 88 | ||
| 238 | typedef struct _Serial_s2m_buffer_t { | 89 | static split_shared_memory_t shared_memory; |
| 239 | // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack | 90 | split_shared_memory_t *const split_shmem = &shared_memory; |
| 240 | matrix_row_t smatrix[ROWS_PER_HAND]; | ||
| 241 | |||
| 242 | # ifdef ENCODER_ENABLE | ||
| 243 | uint8_t encoder_state[NUMBER_OF_ENCODERS]; | ||
| 244 | # endif | ||
| 245 | |||
| 246 | } Serial_s2m_buffer_t; | ||
| 247 | |||
| 248 | typedef struct _Serial_m2s_buffer_t { | ||
| 249 | # ifdef SPLIT_MODS_ENABLE | ||
| 250 | uint8_t real_mods; | ||
| 251 | uint8_t weak_mods; | ||
| 252 | # ifndef NO_ACTION_ONESHOT | ||
| 253 | uint8_t oneshot_mods; | ||
| 254 | # endif | ||
| 255 | # endif | ||
| 256 | # ifndef DISABLE_SYNC_TIMER | ||
| 257 | uint32_t sync_timer; | ||
| 258 | # endif | ||
| 259 | # ifdef SPLIT_TRANSPORT_MIRROR | ||
| 260 | matrix_row_t mmatrix[ROWS_PER_HAND]; | ||
| 261 | # endif | ||
| 262 | # ifdef BACKLIGHT_ENABLE | ||
| 263 | uint8_t backlight_level; | ||
| 264 | # endif | ||
| 265 | # ifdef WPM_ENABLE | ||
| 266 | uint8_t current_wpm; | ||
| 267 | # endif | ||
| 268 | # if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 269 | led_eeconfig_t led_matrix; | ||
| 270 | bool led_suspend_state; | ||
| 271 | # endif | ||
| 272 | # if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 273 | rgb_config_t rgb_matrix; | ||
| 274 | bool rgb_suspend_state; | ||
| 275 | # endif | ||
| 276 | } Serial_m2s_buffer_t; | ||
| 277 | |||
| 278 | # if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | ||
| 279 | // When MCUs on both sides drive their respective RGB LED chains, | ||
| 280 | // it is necessary to synchronize, so it is necessary to communicate RGB | ||
| 281 | // information. In that case, define RGBLIGHT_SPLIT with info on the number | ||
| 282 | // of LEDs on each half. | ||
| 283 | // | ||
| 284 | // Otherwise, if the master side MCU drives both sides RGB LED chains, | ||
| 285 | // there is no need to communicate. | ||
| 286 | |||
| 287 | typedef struct _Serial_rgblight_t { | ||
| 288 | rgblight_syncinfo_t rgblight_sync; | ||
| 289 | } Serial_rgblight_t; | ||
| 290 | 91 | ||
| 291 | volatile Serial_rgblight_t serial_rgblight = {}; | 92 | void transport_master_init(void) { soft_serial_initiator_init(); } |
| 292 | uint8_t volatile status_rgblight = 0; | 93 | void transport_slave_init(void) { soft_serial_target_init(); } |
| 293 | # endif | ||
| 294 | |||
| 295 | volatile Serial_s2m_buffer_t serial_s2m_buffer = {}; | ||
| 296 | volatile Serial_m2s_buffer_t serial_m2s_buffer = {}; | ||
| 297 | uint8_t volatile status0 = 0; | ||
| 298 | |||
| 299 | enum serial_transaction_id { | ||
| 300 | GET_SLAVE_MATRIX = 0, | ||
| 301 | # if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | ||
| 302 | PUT_RGBLIGHT, | ||
| 303 | # endif | ||
| 304 | }; | ||
| 305 | |||
| 306 | SSTD_t transactions[] = { | ||
| 307 | [GET_SLAVE_MATRIX] = | ||
| 308 | { | ||
| 309 | (uint8_t *)&status0, | ||
| 310 | sizeof(serial_m2s_buffer), | ||
| 311 | (uint8_t *)&serial_m2s_buffer, | ||
| 312 | sizeof(serial_s2m_buffer), | ||
| 313 | (uint8_t *)&serial_s2m_buffer, | ||
| 314 | }, | ||
| 315 | # if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | ||
| 316 | [PUT_RGBLIGHT] = | ||
| 317 | { | ||
| 318 | (uint8_t *)&status_rgblight, sizeof(serial_rgblight), (uint8_t *)&serial_rgblight, 0, NULL // no slave to master transfer | ||
| 319 | }, | ||
| 320 | # endif | ||
| 321 | }; | ||
| 322 | |||
| 323 | void transport_master_init(void) { soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); } | ||
| 324 | |||
| 325 | void transport_slave_init(void) { soft_serial_target_init(transactions, TID_LIMIT(transactions)); } | ||
| 326 | 94 | ||
| 327 | # if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | 95 | bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, uint16_t initiator2target_length, void *target2initiator_buf, uint16_t target2initiator_length) { |
| 328 | 96 | split_transaction_desc_t *trans = &split_transaction_table[id]; | |
| 329 | // rgblight synchronization information communication. | 97 | if (initiator2target_length > 0) { |
| 330 | 98 | size_t len = trans->initiator2target_buffer_size < initiator2target_length ? trans->initiator2target_buffer_size : initiator2target_length; | |
| 331 | void transport_rgblight_master(void) { | 99 | memcpy(split_trans_initiator2target_buffer(trans), initiator2target_buf, len); |
| 332 | if (rgblight_get_change_flags()) { | ||
| 333 | rgblight_get_syncinfo((rgblight_syncinfo_t *)&serial_rgblight.rgblight_sync); | ||
| 334 | if (soft_serial_transaction(PUT_RGBLIGHT) == TRANSACTION_END) { | ||
| 335 | rgblight_clear_change_flags(); | ||
| 336 | } | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 340 | void transport_rgblight_slave(void) { | ||
| 341 | if (status_rgblight == TRANSACTION_ACCEPTED) { | ||
| 342 | rgblight_update_sync((rgblight_syncinfo_t *)&serial_rgblight.rgblight_sync, false); | ||
| 343 | status_rgblight = TRANSACTION_END; | ||
| 344 | } | 100 | } |
| 345 | } | ||
| 346 | 101 | ||
| 347 | # else | 102 | if (soft_serial_transaction(id) != TRANSACTION_END) { |
| 348 | # define transport_rgblight_master() | ||
| 349 | # define transport_rgblight_slave() | ||
| 350 | # endif | ||
| 351 | |||
| 352 | bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | ||
| 353 | # ifndef SERIAL_USE_MULTI_TRANSACTION | ||
| 354 | if (soft_serial_transaction() != TRANSACTION_END) { | ||
| 355 | return false; | ||
| 356 | } | ||
| 357 | # else | ||
| 358 | transport_rgblight_master(); | ||
| 359 | if (soft_serial_transaction(GET_SLAVE_MATRIX) != TRANSACTION_END) { | ||
| 360 | return false; | 103 | return false; |
| 361 | } | 104 | } |
| 362 | # endif | ||
| 363 | 105 | ||
| 364 | // TODO: if MATRIX_COLS > 8 change to unpack() | 106 | if (target2initiator_length > 0) { |
| 365 | for (int i = 0; i < ROWS_PER_HAND; ++i) { | 107 | size_t len = trans->target2initiator_buffer_size < target2initiator_length ? trans->target2initiator_buffer_size : target2initiator_length; |
| 366 | slave_matrix[i] = serial_s2m_buffer.smatrix[i]; | 108 | memcpy(target2initiator_buf, split_trans_target2initiator_buffer(trans), len); |
| 367 | # ifdef SPLIT_TRANSPORT_MIRROR | ||
| 368 | serial_m2s_buffer.mmatrix[i] = master_matrix[i]; | ||
| 369 | # endif | ||
| 370 | } | 109 | } |
| 371 | 110 | ||
| 372 | # ifdef BACKLIGHT_ENABLE | ||
| 373 | // Write backlight level for slave to read | ||
| 374 | serial_m2s_buffer.backlight_level = is_backlight_enabled() ? get_backlight_level() : 0; | ||
| 375 | # endif | ||
| 376 | |||
| 377 | # ifdef ENCODER_ENABLE | ||
| 378 | encoder_update_raw((uint8_t *)serial_s2m_buffer.encoder_state); | ||
| 379 | # endif | ||
| 380 | |||
| 381 | # ifdef WPM_ENABLE | ||
| 382 | // Write wpm to slave | ||
| 383 | serial_m2s_buffer.current_wpm = get_current_wpm(); | ||
| 384 | # endif | ||
| 385 | |||
| 386 | # ifdef SPLIT_MODS_ENABLE | ||
| 387 | serial_m2s_buffer.real_mods = get_mods(); | ||
| 388 | serial_m2s_buffer.weak_mods = get_weak_mods(); | ||
| 389 | # ifndef NO_ACTION_ONESHOT | ||
| 390 | serial_m2s_buffer.oneshot_mods = get_oneshot_mods(); | ||
| 391 | # endif | ||
| 392 | # endif | ||
| 393 | |||
| 394 | # if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 395 | serial_m2s_buffer.led_matrix = led_matrix_eeconfig; | ||
| 396 | serial_m2s_buffer.led_suspend_state = led_matrix_get_suspend_state(); | ||
| 397 | # endif | ||
| 398 | # if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 399 | serial_m2s_buffer.rgb_matrix = rgb_matrix_config; | ||
| 400 | serial_m2s_buffer.rgb_suspend_state = rgb_matrix_get_suspend_state(); | ||
| 401 | # endif | ||
| 402 | |||
| 403 | # ifndef DISABLE_SYNC_TIMER | ||
| 404 | serial_m2s_buffer.sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET; | ||
| 405 | # endif | ||
| 406 | return true; | 111 | return true; |
| 407 | } | 112 | } |
| 408 | 113 | ||
| 409 | void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { | 114 | #endif // USE_I2C |
| 410 | transport_rgblight_slave(); | ||
| 411 | # ifndef DISABLE_SYNC_TIMER | ||
| 412 | sync_timer_update(serial_m2s_buffer.sync_timer); | ||
| 413 | # endif | ||
| 414 | |||
| 415 | // TODO: if MATRIX_COLS > 8 change to pack() | ||
| 416 | for (int i = 0; i < ROWS_PER_HAND; ++i) { | ||
| 417 | serial_s2m_buffer.smatrix[i] = slave_matrix[i]; | ||
| 418 | # ifdef SPLIT_TRANSPORT_MIRROR | ||
| 419 | master_matrix[i] = serial_m2s_buffer.mmatrix[i]; | ||
| 420 | # endif | ||
| 421 | } | ||
| 422 | # ifdef BACKLIGHT_ENABLE | ||
| 423 | backlight_set(serial_m2s_buffer.backlight_level); | ||
| 424 | # endif | ||
| 425 | |||
| 426 | # ifdef ENCODER_ENABLE | ||
| 427 | encoder_state_raw((uint8_t *)serial_s2m_buffer.encoder_state); | ||
| 428 | # endif | ||
| 429 | 115 | ||
| 430 | # ifdef WPM_ENABLE | 116 | bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { return transactions_master(master_matrix, slave_matrix); } |
| 431 | set_current_wpm(serial_m2s_buffer.current_wpm); | ||
| 432 | # endif | ||
| 433 | |||
| 434 | # ifdef SPLIT_MODS_ENABLE | ||
| 435 | set_mods(serial_m2s_buffer.real_mods); | ||
| 436 | set_weak_mods(serial_m2s_buffer.weak_mods); | ||
| 437 | # ifndef NO_ACTION_ONESHOT | ||
| 438 | set_oneshot_mods(serial_m2s_buffer.oneshot_mods); | ||
| 439 | # endif | ||
| 440 | # endif | ||
| 441 | |||
| 442 | # if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 443 | led_matrix_eeconfig = serial_m2s_buffer.led_matrix; | ||
| 444 | led_matrix_set_suspend_state(serial_m2s_buffer.led_suspend_state); | ||
| 445 | # endif | ||
| 446 | # if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 447 | rgb_matrix_config = serial_m2s_buffer.rgb_matrix; | ||
| 448 | rgb_matrix_set_suspend_state(serial_m2s_buffer.rgb_suspend_state); | ||
| 449 | # endif | ||
| 450 | } | ||
| 451 | 117 | ||
| 452 | #endif | 118 | void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { transactions_slave(master_matrix, slave_matrix); } \ No newline at end of file |
diff --git a/quantum/split_common/transport.h b/quantum/split_common/transport.h index a9f66301b..2e07f6b25 100644 --- a/quantum/split_common/transport.h +++ b/quantum/split_common/transport.h | |||
| @@ -1,10 +1,175 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 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 2 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 | |||
| 1 | #pragma once | 17 | #pragma once |
| 2 | 18 | ||
| 19 | #include "stdint.h" | ||
| 20 | #include "stdbool.h" | ||
| 21 | |||
| 22 | #include "progmem.h" | ||
| 23 | #include "action_layer.h" | ||
| 3 | #include "matrix.h" | 24 | #include "matrix.h" |
| 4 | 25 | ||
| 26 | #ifndef RPC_M2S_BUFFER_SIZE | ||
| 27 | # define RPC_M2S_BUFFER_SIZE 32 | ||
| 28 | #endif // RPC_M2S_BUFFER_SIZE | ||
| 29 | |||
| 30 | #ifndef RPC_S2M_BUFFER_SIZE | ||
| 31 | # define RPC_S2M_BUFFER_SIZE 32 | ||
| 32 | #endif // RPC_S2M_BUFFER_SIZE | ||
| 33 | |||
| 5 | void transport_master_init(void); | 34 | void transport_master_init(void); |
| 6 | void transport_slave_init(void); | 35 | void transport_slave_init(void); |
| 7 | 36 | ||
| 8 | // returns false if valid data not received from slave | 37 | // returns false if valid data not received from slave |
| 9 | bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]); | 38 | bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]); |
| 10 | void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]); | 39 | void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]); |
| 40 | |||
| 41 | bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, uint16_t initiator2target_length, void *target2initiator_buf, uint16_t target2initiator_length); | ||
| 42 | |||
| 43 | #ifdef ENCODER_ENABLE | ||
| 44 | # include "encoder.h" | ||
| 45 | # define NUMBER_OF_ENCODERS (sizeof((pin_t[])ENCODERS_PAD_A) / sizeof(pin_t)) | ||
| 46 | #endif // ENCODER_ENABLE | ||
| 47 | |||
| 48 | #ifdef BACKLIGHT_ENABLE | ||
| 49 | # include "backlight.h" | ||
| 50 | #endif // BACKLIGHT_ENABLE | ||
| 51 | |||
| 52 | #ifdef RGBLIGHT_ENABLE | ||
| 53 | # include "rgblight.h" | ||
| 54 | #endif // RGBLIGHT_ENABLE | ||
| 55 | |||
| 56 | typedef struct _split_slave_matrix_sync_t { | ||
| 57 | uint8_t checksum; | ||
| 58 | matrix_row_t matrix[(MATRIX_ROWS) / 2]; | ||
| 59 | } split_slave_matrix_sync_t; | ||
| 60 | |||
| 61 | #ifdef SPLIT_TRANSPORT_MIRROR | ||
| 62 | typedef struct _split_master_matrix_sync_t { | ||
| 63 | matrix_row_t matrix[(MATRIX_ROWS) / 2]; | ||
| 64 | } split_master_matrix_sync_t; | ||
| 65 | #endif // SPLIT_TRANSPORT_MIRROR | ||
| 66 | |||
| 67 | #ifdef ENCODER_ENABLE | ||
| 68 | typedef struct _split_slave_encoder_sync_t { | ||
| 69 | uint8_t checksum; | ||
| 70 | uint8_t state[NUMBER_OF_ENCODERS]; | ||
| 71 | } split_slave_encoder_sync_t; | ||
| 72 | #endif // ENCODER_ENABLE | ||
| 73 | |||
| 74 | #if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE) | ||
| 75 | typedef struct _split_layers_sync_t { | ||
| 76 | layer_state_t layer_state; | ||
| 77 | layer_state_t default_layer_state; | ||
| 78 | } split_layers_sync_t; | ||
| 79 | #endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE) | ||
| 80 | |||
| 81 | #if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 82 | # include "led_matrix.h" | ||
| 83 | |||
| 84 | typedef struct _led_matrix_sync_t { | ||
| 85 | led_eeconfig_t led_matrix; | ||
| 86 | bool led_suspend_state; | ||
| 87 | } led_matrix_sync_t; | ||
| 88 | #endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 89 | |||
| 90 | #if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 91 | # include "rgb_matrix.h" | ||
| 92 | |||
| 93 | typedef struct _rgb_matrix_sync_t { | ||
| 94 | rgb_config_t rgb_matrix; | ||
| 95 | bool rgb_suspend_state; | ||
| 96 | } rgb_matrix_sync_t; | ||
| 97 | #endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 98 | |||
| 99 | #ifdef SPLIT_MODS_ENABLE | ||
| 100 | typedef struct _split_mods_sync_t { | ||
| 101 | uint8_t real_mods; | ||
| 102 | uint8_t weak_mods; | ||
| 103 | # ifndef NO_ACTION_ONESHOT | ||
| 104 | uint8_t oneshot_mods; | ||
| 105 | # endif // NO_ACTION_ONESHOT | ||
| 106 | } split_mods_sync_t; | ||
| 107 | #endif // SPLIT_MODS_ENABLE | ||
| 108 | |||
| 109 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | ||
| 110 | typedef struct _rpc_sync_info_t { | ||
| 111 | int8_t transaction_id; | ||
| 112 | uint8_t m2s_length; | ||
| 113 | uint8_t s2m_length; | ||
| 114 | } rpc_sync_info_t; | ||
| 115 | #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | ||
| 116 | |||
| 117 | typedef struct _split_shared_memory_t { | ||
| 118 | #ifdef USE_I2C | ||
| 119 | int8_t transaction_id; | ||
| 120 | #endif // USE_I2C | ||
| 121 | |||
| 122 | split_slave_matrix_sync_t smatrix; | ||
| 123 | |||
| 124 | #ifdef SPLIT_TRANSPORT_MIRROR | ||
| 125 | split_master_matrix_sync_t mmatrix; | ||
| 126 | #endif // SPLIT_TRANSPORT_MIRROR | ||
| 127 | |||
| 128 | #ifdef ENCODER_ENABLE | ||
| 129 | split_slave_encoder_sync_t encoders; | ||
| 130 | #endif // ENCODER_ENABLE | ||
| 131 | |||
| 132 | #ifndef DISABLE_SYNC_TIMER | ||
| 133 | uint32_t sync_timer; | ||
| 134 | #endif // DISABLE_SYNC_TIMER | ||
| 135 | |||
| 136 | #if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE) | ||
| 137 | split_layers_sync_t layers; | ||
| 138 | #endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE) | ||
| 139 | |||
| 140 | #ifdef SPLIT_LED_STATE_ENABLE | ||
| 141 | uint8_t led_state; | ||
| 142 | #endif // SPLIT_LED_STATE_ENABLE | ||
| 143 | |||
| 144 | #ifdef SPLIT_MODS_ENABLE | ||
| 145 | split_mods_sync_t mods; | ||
| 146 | #endif // SPLIT_MODS_ENABLE | ||
| 147 | |||
| 148 | #ifdef BACKLIGHT_ENABLE | ||
| 149 | uint8_t backlight_level; | ||
| 150 | #endif // BACKLIGHT_ENABLE | ||
| 151 | |||
| 152 | #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | ||
| 153 | rgblight_syncinfo_t rgblight_sync; | ||
| 154 | #endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) | ||
| 155 | |||
| 156 | #if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 157 | led_matrix_sync_t led_matrix_sync; | ||
| 158 | #endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) | ||
| 159 | |||
| 160 | #if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 161 | rgb_matrix_sync_t rgb_matrix_sync; | ||
| 162 | #endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) | ||
| 163 | |||
| 164 | #if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE) | ||
| 165 | uint8_t current_wpm; | ||
| 166 | #endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE) | ||
| 167 | |||
| 168 | #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | ||
| 169 | rpc_sync_info_t rpc_info; | ||
| 170 | uint8_t rpc_m2s_buffer[RPC_M2S_BUFFER_SIZE]; | ||
| 171 | uint8_t rpc_s2m_buffer[RPC_S2M_BUFFER_SIZE]; | ||
| 172 | #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) | ||
| 173 | } split_shared_memory_t; | ||
| 174 | |||
| 175 | extern split_shared_memory_t *const split_shmem; \ No newline at end of file | ||
