transactions.c (44751B)
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 <stdint.h> 18 #include <string.h> 19 #include <stddef.h> 20 21 #include "crc.h" 22 #include "debug.h" 23 #include "matrix.h" 24 #include "host.h" 25 #include "action_util.h" 26 #include "sync_timer.h" 27 #include "wait.h" 28 #include "transactions.h" 29 #include "transport.h" 30 #include "transaction_id_define.h" 31 #include "split_util.h" 32 #include "synchronization_util.h" 33 34 #ifdef BACKLIGHT_ENABLE 35 # include "backlight.h" 36 #endif 37 #ifdef RGBLIGHT_ENABLE 38 # include "rgblight.h" 39 #endif 40 #ifdef LED_MATRIX_ENABLE 41 # include "led_matrix.h" 42 #endif 43 #ifdef RGB_MATRIX_ENABLE 44 # include "rgb_matrix.h" 45 #endif 46 #ifdef OLED_ENABLE 47 # include "oled_driver.h" 48 #endif 49 #ifdef ST7565_ENABLE 50 # include "st7565.h" 51 #endif 52 #ifdef ENCODER_ENABLE 53 # include "encoder.h" 54 #endif 55 #ifdef HAPTIC_ENABLE 56 # include "haptic.h" 57 #endif 58 #ifdef POINTING_DEVICE_ENABLE 59 # include "pointing_device.h" 60 #endif 61 #ifdef OS_DETECTION_ENABLE 62 # include "os_detection.h" 63 #endif 64 #ifdef WPM_ENABLE 65 # include "wpm.h" 66 #endif 67 68 #define SYNC_TIMER_OFFSET 2 69 70 #ifndef FORCED_SYNC_THROTTLE_MS 71 # define FORCED_SYNC_THROTTLE_MS 100 72 #endif // FORCED_SYNC_THROTTLE_MS 73 74 #define sizeof_member(type, member) sizeof(((type *)NULL)->member) 75 76 #define trans_initiator2target_initializer_cb(member, cb) {sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), 0, 0, cb} 77 #define trans_initiator2target_initializer(member) trans_initiator2target_initializer_cb(member, NULL) 78 79 #define trans_target2initiator_initializer_cb(member, cb) {0, 0, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), cb} 80 #define trans_target2initiator_initializer(member) trans_target2initiator_initializer_cb(member, NULL) 81 82 #define trans_initiator2target_cb(cb) {0, 0, 0, 0, cb} 83 84 #define transport_write(id, data, length) transport_execute_transaction(id, data, length, NULL, 0) 85 #define transport_read(id, data, length) transport_execute_transaction(id, NULL, 0, data, length) 86 #define transport_exec(id) transport_execute_transaction(id, NULL, 0, NULL, 0) 87 88 #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) 89 // Forward-declare the RPC callback handlers 90 void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer); 91 void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer); 92 #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) 93 94 //////////////////////////////////////////////////// 95 // Helpers 96 97 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[])) { 98 int num_retries = is_transport_connected() ? 10 : 1; 99 for (int iter = 1; iter <= num_retries; ++iter) { 100 if (iter > 1) { 101 for (int i = 0; i < iter * iter; ++i) { 102 wait_us(10); 103 } 104 } 105 bool this_okay = true; 106 this_okay = handler(master_matrix, slave_matrix); 107 if (this_okay) return true; 108 } 109 dprintf("Failed to execute %s\n", prefix); 110 return false; 111 } 112 113 #define TRANSACTION_HANDLER_MASTER(prefix) \ 114 do { \ 115 if (!transaction_handler_master(master_matrix, slave_matrix, #prefix, &prefix##_handlers_master)) return false; \ 116 } while (0) 117 118 /** 119 * @brief Constructs a transaction handler that doesn't acquire a lock to the 120 * split shared memory. Therefore the locking and unlocking has to be done 121 * manually inside the handler. Use this macro only if the handler is 122 * non-deterministic in runtime and thus needs a manual lock unlock 123 * implementation to hold the lock for the shortest possible time. 124 */ 125 #define TRANSACTION_HANDLER_SLAVE(prefix) \ 126 do { \ 127 prefix##_handlers_slave(master_matrix, slave_matrix); \ 128 } while (0) 129 130 /** 131 * @brief Constructs a transaction handler that automatically acquires a lock to 132 * safely access the split shared memory and releases the lock again after 133 * processing the handler. Use this macro if the handler is fast and 134 * deterministic in runtime and thus holds the lock only for a very short time. 135 * If not fallback to manually locking and unlocking inside the handler. 136 */ 137 #define TRANSACTION_HANDLER_SLAVE_AUTOLOCK(prefix) \ 138 do { \ 139 split_shared_memory_lock(); \ 140 prefix##_handlers_slave(master_matrix, slave_matrix); \ 141 split_shared_memory_unlock(); \ 142 } while (0) 143 144 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) { 145 uint8_t curr_checksum; 146 bool okay = transport_read(trans_id_checksum, &curr_checksum, sizeof(curr_checksum)); 147 if (okay && (timer_elapsed32(*last_update) >= FORCED_SYNC_THROTTLE_MS || curr_checksum != crc8(equiv_shmem, length))) { 148 okay &= transport_read(trans_id_retrieve, destination, length); 149 okay &= curr_checksum == crc8(equiv_shmem, length); 150 if (okay) { 151 *last_update = timer_read32(); 152 } 153 } else { 154 memcpy(destination, equiv_shmem, length); 155 } 156 return okay; 157 } 158 159 inline static bool send_if_condition(int8_t trans_id, uint32_t *last_update, bool condition, void *source, size_t length) { 160 bool okay = true; 161 if (timer_elapsed32(*last_update) >= FORCED_SYNC_THROTTLE_MS || condition) { 162 okay &= transport_write(trans_id, source, length); 163 if (okay) { 164 *last_update = timer_read32(); 165 } 166 } 167 return okay; 168 } 169 170 inline static bool send_if_data_mismatch(int8_t trans_id, uint32_t *last_update, void *source, const void *equiv_shmem, size_t length) { 171 // Just run a memcmp to compare the source and equivalent shmem location 172 return send_if_condition(trans_id, last_update, (memcmp(source, equiv_shmem, length) != 0), source, length); 173 } 174 175 //////////////////////////////////////////////////// 176 // Slave matrix 177 178 static bool slave_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 179 static uint32_t last_update = 0; 180 static matrix_row_t last_matrix[(MATRIX_ROWS) / 2] = {0}; // last successfully-read matrix, so we can replicate if there are checksum errors 181 matrix_row_t temp_matrix[(MATRIX_ROWS) / 2]; // holding area while we test whether or not checksum is correct 182 183 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)); 184 if (okay) { 185 // Checksum matches the received data, save as the last matrix state 186 memcpy(last_matrix, temp_matrix, sizeof(temp_matrix)); 187 } 188 // Copy out the last-known-good matrix state to the slave matrix 189 memcpy(slave_matrix, last_matrix, sizeof(last_matrix)); 190 return okay; 191 } 192 193 static void slave_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 194 memcpy(split_shmem->smatrix.matrix, slave_matrix, sizeof(split_shmem->smatrix.matrix)); 195 split_shmem->smatrix.checksum = crc8(split_shmem->smatrix.matrix, sizeof(split_shmem->smatrix.matrix)); 196 } 197 198 // clang-format off 199 #define TRANSACTIONS_SLAVE_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(slave_matrix) 200 #define TRANSACTIONS_SLAVE_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(slave_matrix) 201 #define TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS \ 202 [GET_SLAVE_MATRIX_CHECKSUM] = trans_target2initiator_initializer(smatrix.checksum), \ 203 [GET_SLAVE_MATRIX_DATA] = trans_target2initiator_initializer(smatrix.matrix), 204 // clang-format on 205 206 //////////////////////////////////////////////////// 207 // Master matrix 208 209 #ifdef SPLIT_TRANSPORT_MIRROR 210 211 static bool master_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 212 static uint32_t last_update = 0; 213 return send_if_data_mismatch(PUT_MASTER_MATRIX, &last_update, master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix)); 214 } 215 216 static void master_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 217 // Always copy to the master matrix 218 memcpy(master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix)); 219 } 220 221 # define TRANSACTIONS_MASTER_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(master_matrix) 222 # define TRANSACTIONS_MASTER_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(master_matrix) 223 # define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS [PUT_MASTER_MATRIX] = trans_initiator2target_initializer(mmatrix.matrix), 224 225 #else // SPLIT_TRANSPORT_MIRROR 226 227 # define TRANSACTIONS_MASTER_MATRIX_MASTER() 228 # define TRANSACTIONS_MASTER_MATRIX_SLAVE() 229 # define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS 230 231 #endif // SPLIT_TRANSPORT_MIRROR 232 233 //////////////////////////////////////////////////// 234 // Encoders 235 236 #ifdef ENCODER_ENABLE 237 238 static bool encoder_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 239 static uint32_t last_update = 0; 240 static uint8_t last_checksum = 0; 241 encoder_events_t temp_events; 242 243 bool okay = read_if_checksum_mismatch(GET_ENCODERS_CHECKSUM, GET_ENCODERS_DATA, &last_update, &temp_events, &split_shmem->encoders.events, sizeof(temp_events)); 244 if (okay) { 245 if (last_checksum != split_shmem->encoders.checksum) { 246 bool actioned = false; 247 uint8_t index; 248 bool clockwise; 249 while (okay && encoder_dequeue_event_advanced(&split_shmem->encoders.events, &index, &clockwise)) { 250 okay &= encoder_queue_event(index, clockwise); 251 actioned = true; 252 } 253 254 if (actioned) { 255 okay &= transport_exec(CMD_ENCODER_DRAIN); 256 } 257 last_checksum = split_shmem->encoders.checksum; 258 } 259 } 260 return okay; 261 } 262 263 static void encoder_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 264 // Always prepare the encoder state for read. 265 encoder_retrieve_events(&split_shmem->encoders.events); 266 // Now update the checksum given that the encoders has been written to 267 split_shmem->encoders.checksum = crc8(&split_shmem->encoders.events, sizeof(split_shmem->encoders.events)); 268 } 269 270 static void encoder_handlers_slave_drain(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) { 271 encoder_signal_queue_drain(); 272 } 273 274 // clang-format off 275 # define TRANSACTIONS_ENCODERS_MASTER() TRANSACTION_HANDLER_MASTER(encoder) 276 # define TRANSACTIONS_ENCODERS_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(encoder) 277 # define TRANSACTIONS_ENCODERS_REGISTRATIONS \ 278 [GET_ENCODERS_CHECKSUM] = trans_target2initiator_initializer(encoders.checksum), \ 279 [GET_ENCODERS_DATA] = trans_target2initiator_initializer(encoders.events), \ 280 [CMD_ENCODER_DRAIN] = trans_initiator2target_cb(encoder_handlers_slave_drain), 281 // clang-format on 282 283 #else // ENCODER_ENABLE 284 285 # define TRANSACTIONS_ENCODERS_MASTER() 286 # define TRANSACTIONS_ENCODERS_SLAVE() 287 # define TRANSACTIONS_ENCODERS_REGISTRATIONS 288 289 #endif // ENCODER_ENABLE 290 291 //////////////////////////////////////////////////// 292 // Sync timer 293 294 #ifndef DISABLE_SYNC_TIMER 295 296 static bool sync_timer_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 297 static uint32_t last_update = 0; 298 299 bool okay = true; 300 if (timer_elapsed32(last_update) >= FORCED_SYNC_THROTTLE_MS) { 301 uint32_t sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET; 302 okay &= transport_write(PUT_SYNC_TIMER, &sync_timer, sizeof(sync_timer)); 303 if (okay) { 304 last_update = timer_read32(); 305 } 306 } 307 return okay; 308 } 309 310 static void sync_timer_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 311 static uint32_t last_sync_timer = 0; 312 if (last_sync_timer != split_shmem->sync_timer) { 313 last_sync_timer = split_shmem->sync_timer; 314 sync_timer_update(last_sync_timer); 315 } 316 } 317 318 # define TRANSACTIONS_SYNC_TIMER_MASTER() TRANSACTION_HANDLER_MASTER(sync_timer) 319 # define TRANSACTIONS_SYNC_TIMER_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(sync_timer) 320 # define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS [PUT_SYNC_TIMER] = trans_initiator2target_initializer(sync_timer), 321 322 #else // DISABLE_SYNC_TIMER 323 324 # define TRANSACTIONS_SYNC_TIMER_MASTER() 325 # define TRANSACTIONS_SYNC_TIMER_SLAVE() 326 # define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS 327 328 #endif // DISABLE_SYNC_TIMER 329 330 //////////////////////////////////////////////////// 331 // Layer state 332 333 #if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE) 334 335 static bool layer_state_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 336 static uint32_t last_layer_state_update = 0; 337 static uint32_t last_default_layer_state_update = 0; 338 339 bool okay = send_if_condition(PUT_LAYER_STATE, &last_layer_state_update, (layer_state != split_shmem->layers.layer_state), &layer_state, sizeof(layer_state)); 340 if (okay) { 341 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)); 342 } 343 return okay; 344 } 345 346 static void layer_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 347 layer_state = split_shmem->layers.layer_state; 348 default_layer_state = split_shmem->layers.default_layer_state; 349 } 350 351 // clang-format off 352 # define TRANSACTIONS_LAYER_STATE_MASTER() TRANSACTION_HANDLER_MASTER(layer_state) 353 # define TRANSACTIONS_LAYER_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(layer_state) 354 # define TRANSACTIONS_LAYER_STATE_REGISTRATIONS \ 355 [PUT_LAYER_STATE] = trans_initiator2target_initializer(layers.layer_state), \ 356 [PUT_DEFAULT_LAYER_STATE] = trans_initiator2target_initializer(layers.default_layer_state), 357 // clang-format on 358 359 #else // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE) 360 361 # define TRANSACTIONS_LAYER_STATE_MASTER() 362 # define TRANSACTIONS_LAYER_STATE_SLAVE() 363 # define TRANSACTIONS_LAYER_STATE_REGISTRATIONS 364 365 #endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE) 366 367 //////////////////////////////////////////////////// 368 // LED state 369 370 #ifdef SPLIT_LED_STATE_ENABLE 371 372 static bool led_state_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 373 static uint32_t last_update = 0; 374 uint8_t led_state = host_keyboard_leds(); 375 return send_if_data_mismatch(PUT_LED_STATE, &last_update, &led_state, &split_shmem->led_state, sizeof(led_state)); 376 } 377 378 static void led_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 379 void set_split_host_keyboard_leds(uint8_t led_state); 380 set_split_host_keyboard_leds(split_shmem->led_state); 381 } 382 383 # define TRANSACTIONS_LED_STATE_MASTER() TRANSACTION_HANDLER_MASTER(led_state) 384 # define TRANSACTIONS_LED_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(led_state) 385 # define TRANSACTIONS_LED_STATE_REGISTRATIONS [PUT_LED_STATE] = trans_initiator2target_initializer(led_state), 386 387 #else // SPLIT_LED_STATE_ENABLE 388 389 # define TRANSACTIONS_LED_STATE_MASTER() 390 # define TRANSACTIONS_LED_STATE_SLAVE() 391 # define TRANSACTIONS_LED_STATE_REGISTRATIONS 392 393 #endif // SPLIT_LED_STATE_ENABLE 394 395 //////////////////////////////////////////////////// 396 // Mods 397 398 #ifdef SPLIT_MODS_ENABLE 399 400 static bool mods_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 401 static uint32_t last_update = 0; 402 bool mods_need_sync = timer_elapsed32(last_update) >= FORCED_SYNC_THROTTLE_MS; 403 split_mods_sync_t new_mods; 404 new_mods.real_mods = get_mods(); 405 if (!mods_need_sync && new_mods.real_mods != split_shmem->mods.real_mods) { 406 mods_need_sync = true; 407 } 408 409 new_mods.weak_mods = get_weak_mods(); 410 if (!mods_need_sync && new_mods.weak_mods != split_shmem->mods.weak_mods) { 411 mods_need_sync = true; 412 } 413 414 # ifndef NO_ACTION_ONESHOT 415 new_mods.oneshot_mods = get_oneshot_mods(); 416 if (!mods_need_sync && new_mods.oneshot_mods != split_shmem->mods.oneshot_mods) { 417 mods_need_sync = true; 418 } 419 new_mods.oneshot_locked_mods = get_oneshot_locked_mods(); 420 if (!mods_need_sync && new_mods.oneshot_locked_mods != split_shmem->mods.oneshot_locked_mods) { 421 mods_need_sync = true; 422 } 423 # endif // NO_ACTION_ONESHOT 424 425 bool okay = true; 426 if (mods_need_sync) { 427 okay &= transport_write(PUT_MODS, &new_mods, sizeof(new_mods)); 428 if (okay) { 429 last_update = timer_read32(); 430 } 431 } 432 433 return okay; 434 } 435 436 static void mods_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 437 split_shared_memory_lock(); 438 split_mods_sync_t mods; 439 memcpy(&mods, &split_shmem->mods, sizeof(split_mods_sync_t)); 440 split_shared_memory_unlock(); 441 442 set_mods(mods.real_mods); 443 set_weak_mods(mods.weak_mods); 444 # ifndef NO_ACTION_ONESHOT 445 set_oneshot_mods(mods.oneshot_mods); 446 set_oneshot_locked_mods(mods.oneshot_locked_mods); 447 # endif 448 } 449 450 # define TRANSACTIONS_MODS_MASTER() TRANSACTION_HANDLER_MASTER(mods) 451 # define TRANSACTIONS_MODS_SLAVE() TRANSACTION_HANDLER_SLAVE(mods) 452 # define TRANSACTIONS_MODS_REGISTRATIONS [PUT_MODS] = trans_initiator2target_initializer(mods), 453 454 #else // SPLIT_MODS_ENABLE 455 456 # define TRANSACTIONS_MODS_MASTER() 457 # define TRANSACTIONS_MODS_SLAVE() 458 # define TRANSACTIONS_MODS_REGISTRATIONS 459 460 #endif // SPLIT_MODS_ENABLE 461 462 //////////////////////////////////////////////////// 463 // Backlight 464 465 #ifdef BACKLIGHT_ENABLE 466 467 static bool backlight_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 468 static uint32_t last_update = 0; 469 uint8_t level = is_backlight_enabled() ? get_backlight_level() : 0; 470 return send_if_condition(PUT_BACKLIGHT, &last_update, (level != split_shmem->backlight_level), &level, sizeof(level)); 471 } 472 473 static void backlight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 474 split_shared_memory_lock(); 475 uint8_t backlight_level = split_shmem->backlight_level; 476 split_shared_memory_unlock(); 477 478 backlight_level_noeeprom(backlight_level); 479 } 480 481 # define TRANSACTIONS_BACKLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(backlight) 482 # define TRANSACTIONS_BACKLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(backlight) 483 # define TRANSACTIONS_BACKLIGHT_REGISTRATIONS [PUT_BACKLIGHT] = trans_initiator2target_initializer(backlight_level), 484 485 #else // BACKLIGHT_ENABLE 486 487 # define TRANSACTIONS_BACKLIGHT_MASTER() 488 # define TRANSACTIONS_BACKLIGHT_SLAVE() 489 # define TRANSACTIONS_BACKLIGHT_REGISTRATIONS 490 491 #endif // BACKLIGHT_ENABLE 492 493 //////////////////////////////////////////////////// 494 // RGBLIGHT 495 496 #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) 497 498 static bool rgblight_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 499 static uint32_t last_update = 0; 500 rgblight_syncinfo_t rgblight_sync; 501 rgblight_get_syncinfo(&rgblight_sync); 502 if (send_if_condition(PUT_RGBLIGHT, &last_update, (rgblight_sync.status.change_flags != 0), &rgblight_sync, sizeof(rgblight_sync))) { 503 rgblight_clear_change_flags(); 504 } else { 505 return false; 506 } 507 return true; 508 } 509 510 static void rgblight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 511 split_shared_memory_lock(); 512 // Update the RGB with the new data 513 rgblight_syncinfo_t rgblight_sync; 514 memcpy(&rgblight_sync, &split_shmem->rgblight_sync, sizeof(rgblight_syncinfo_t)); 515 split_shmem->rgblight_sync.status.change_flags = 0; 516 split_shared_memory_unlock(); 517 518 if (rgblight_sync.status.change_flags != 0) { 519 rgblight_update_sync(&rgblight_sync, false); 520 } 521 } 522 523 # define TRANSACTIONS_RGBLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(rgblight) 524 # define TRANSACTIONS_RGBLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(rgblight) 525 # define TRANSACTIONS_RGBLIGHT_REGISTRATIONS [PUT_RGBLIGHT] = trans_initiator2target_initializer(rgblight_sync), 526 527 #else // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) 528 529 # define TRANSACTIONS_RGBLIGHT_MASTER() 530 # define TRANSACTIONS_RGBLIGHT_SLAVE() 531 # define TRANSACTIONS_RGBLIGHT_REGISTRATIONS 532 533 #endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) 534 535 //////////////////////////////////////////////////// 536 // LED Matrix 537 538 #if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) 539 540 static bool led_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 541 static uint32_t last_update = 0; 542 led_matrix_sync_t led_matrix_sync; 543 memcpy(&led_matrix_sync.led_matrix, &led_matrix_eeconfig, sizeof(led_eeconfig_t)); 544 led_matrix_sync.led_suspend_state = led_matrix_get_suspend_state(); 545 return send_if_data_mismatch(PUT_LED_MATRIX, &last_update, &led_matrix_sync, &split_shmem->led_matrix_sync, sizeof(led_matrix_sync)); 546 } 547 548 static void led_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 549 split_shared_memory_lock(); 550 memcpy(&led_matrix_eeconfig, &split_shmem->led_matrix_sync.led_matrix, sizeof(led_eeconfig_t)); 551 bool led_suspend_state = split_shmem->led_matrix_sync.led_suspend_state; 552 split_shared_memory_unlock(); 553 554 led_matrix_set_suspend_state(led_suspend_state); 555 } 556 557 # define TRANSACTIONS_LED_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(led_matrix) 558 # define TRANSACTIONS_LED_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(led_matrix) 559 # define TRANSACTIONS_LED_MATRIX_REGISTRATIONS [PUT_LED_MATRIX] = trans_initiator2target_initializer(led_matrix_sync), 560 561 #else // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) 562 563 # define TRANSACTIONS_LED_MATRIX_MASTER() 564 # define TRANSACTIONS_LED_MATRIX_SLAVE() 565 # define TRANSACTIONS_LED_MATRIX_REGISTRATIONS 566 567 #endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) 568 569 //////////////////////////////////////////////////// 570 // RGB Matrix 571 572 #if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) 573 574 static bool rgb_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 575 static uint32_t last_update = 0; 576 rgb_matrix_sync_t rgb_matrix_sync; 577 memcpy(&rgb_matrix_sync.rgb_matrix, &rgb_matrix_config, sizeof(rgb_config_t)); 578 rgb_matrix_sync.rgb_suspend_state = rgb_matrix_get_suspend_state(); 579 return send_if_data_mismatch(PUT_RGB_MATRIX, &last_update, &rgb_matrix_sync, &split_shmem->rgb_matrix_sync, sizeof(rgb_matrix_sync)); 580 } 581 582 static void rgb_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 583 split_shared_memory_lock(); 584 memcpy(&rgb_matrix_config, &split_shmem->rgb_matrix_sync.rgb_matrix, sizeof(rgb_config_t)); 585 bool rgb_suspend_state = split_shmem->rgb_matrix_sync.rgb_suspend_state; 586 split_shared_memory_unlock(); 587 588 rgb_matrix_set_suspend_state(rgb_suspend_state); 589 } 590 591 # define TRANSACTIONS_RGB_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(rgb_matrix) 592 # define TRANSACTIONS_RGB_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(rgb_matrix) 593 # define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS [PUT_RGB_MATRIX] = trans_initiator2target_initializer(rgb_matrix_sync), 594 595 #else // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) 596 597 # define TRANSACTIONS_RGB_MATRIX_MASTER() 598 # define TRANSACTIONS_RGB_MATRIX_SLAVE() 599 # define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS 600 601 #endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) 602 603 //////////////////////////////////////////////////// 604 // WPM 605 606 #if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE) 607 608 static bool wpm_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 609 static uint32_t last_update = 0; 610 uint8_t current_wpm = get_current_wpm(); 611 return send_if_condition(PUT_WPM, &last_update, (current_wpm != split_shmem->current_wpm), ¤t_wpm, sizeof(current_wpm)); 612 } 613 614 static void wpm_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 615 set_current_wpm(split_shmem->current_wpm); 616 } 617 618 # define TRANSACTIONS_WPM_MASTER() TRANSACTION_HANDLER_MASTER(wpm) 619 # define TRANSACTIONS_WPM_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(wpm) 620 # define TRANSACTIONS_WPM_REGISTRATIONS [PUT_WPM] = trans_initiator2target_initializer(current_wpm), 621 622 #else // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE) 623 624 # define TRANSACTIONS_WPM_MASTER() 625 # define TRANSACTIONS_WPM_SLAVE() 626 # define TRANSACTIONS_WPM_REGISTRATIONS 627 628 #endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE) 629 630 //////////////////////////////////////////////////// 631 // OLED 632 633 #if defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE) 634 635 static bool oled_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 636 static uint32_t last_update = 0; 637 bool current_oled_state = is_oled_on(); 638 return send_if_condition(PUT_OLED, &last_update, (current_oled_state != split_shmem->current_oled_state), ¤t_oled_state, sizeof(current_oled_state)); 639 } 640 641 static void oled_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 642 split_shared_memory_lock(); 643 uint8_t current_oled_state = split_shmem->current_oled_state; 644 split_shared_memory_unlock(); 645 646 if (current_oled_state) { 647 oled_on(); 648 } else { 649 oled_off(); 650 } 651 } 652 653 # define TRANSACTIONS_OLED_MASTER() TRANSACTION_HANDLER_MASTER(oled) 654 # define TRANSACTIONS_OLED_SLAVE() TRANSACTION_HANDLER_SLAVE(oled) 655 # define TRANSACTIONS_OLED_REGISTRATIONS [PUT_OLED] = trans_initiator2target_initializer(current_oled_state), 656 657 #else // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE) 658 659 # define TRANSACTIONS_OLED_MASTER() 660 # define TRANSACTIONS_OLED_SLAVE() 661 # define TRANSACTIONS_OLED_REGISTRATIONS 662 663 #endif // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE) 664 665 //////////////////////////////////////////////////// 666 // ST7565 667 668 #if defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE) 669 670 static bool st7565_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 671 static uint32_t last_update = 0; 672 bool current_st7565_state = st7565_is_on(); 673 return send_if_condition(PUT_ST7565, &last_update, (current_st7565_state != split_shmem->current_st7565_state), ¤t_st7565_state, sizeof(current_st7565_state)); 674 } 675 676 static void st7565_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 677 split_shared_memory_lock(); 678 uint8_t current_st7565_state = split_shmem->current_st7565_state; 679 split_shared_memory_unlock(); 680 681 if (current_st7565_state) { 682 st7565_on(); 683 } else { 684 st7565_off(); 685 } 686 } 687 688 # define TRANSACTIONS_ST7565_MASTER() TRANSACTION_HANDLER_MASTER(st7565) 689 # define TRANSACTIONS_ST7565_SLAVE() TRANSACTION_HANDLER_SLAVE(st7565) 690 # define TRANSACTIONS_ST7565_REGISTRATIONS [PUT_ST7565] = trans_initiator2target_initializer(current_st7565_state), 691 692 #else // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE) 693 694 # define TRANSACTIONS_ST7565_MASTER() 695 # define TRANSACTIONS_ST7565_SLAVE() 696 # define TRANSACTIONS_ST7565_REGISTRATIONS 697 698 #endif // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE) 699 700 //////////////////////////////////////////////////// 701 // POINTING 702 703 #if defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) 704 705 static bool pointing_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 706 # if defined(POINTING_DEVICE_LEFT) 707 if (is_keyboard_left()) { 708 return true; 709 } 710 # elif defined(POINTING_DEVICE_RIGHT) 711 if (!is_keyboard_left()) { 712 return true; 713 } 714 # endif 715 static uint32_t last_update = 0; 716 static uint32_t last_cpi_update = 0; 717 static uint16_t last_cpi = 0; 718 report_mouse_t temp_state; 719 uint16_t temp_cpi; 720 bool okay = read_if_checksum_mismatch(GET_POINTING_CHECKSUM, GET_POINTING_DATA, &last_update, &temp_state, &split_shmem->pointing.report, sizeof(temp_state)); 721 if (okay) pointing_device_set_shared_report(temp_state); 722 temp_cpi = pointing_device_get_shared_cpi(); 723 if (temp_cpi) { 724 split_shmem->pointing.cpi = temp_cpi; 725 okay = send_if_condition(PUT_POINTING_CPI, &last_cpi_update, last_cpi != temp_cpi, &split_shmem->pointing.cpi, sizeof(split_shmem->pointing.cpi)); 726 if (okay) { 727 last_cpi = temp_cpi; 728 } 729 } 730 return okay; 731 } 732 733 extern const pointing_device_driver_t *pointing_device_driver; 734 735 static void pointing_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 736 # if defined(POINTING_DEVICE_LEFT) 737 if (!is_keyboard_left()) { 738 return; 739 } 740 # elif defined(POINTING_DEVICE_RIGHT) 741 if (is_keyboard_left()) { 742 return; 743 } 744 # endif 745 # if (POINTING_DEVICE_TASK_THROTTLE_MS > 0) 746 static uint32_t last_exec = 0; 747 if (timer_elapsed32(last_exec) < POINTING_DEVICE_TASK_THROTTLE_MS) { 748 return; 749 } 750 last_exec = timer_read32(); 751 # endif 752 753 uint16_t temp_cpi = !pointing_device_driver->get_cpi ? 0 : pointing_device_driver->get_cpi(); // check for NULL 754 755 split_shared_memory_lock(); 756 split_slave_pointing_sync_t pointing; 757 memcpy(&pointing, &split_shmem->pointing, sizeof(split_slave_pointing_sync_t)); 758 split_shared_memory_unlock(); 759 760 if (pointing.cpi && pointing.cpi != temp_cpi && pointing_device_driver->set_cpi) { 761 pointing_device_driver->set_cpi(pointing.cpi); 762 } 763 764 pointing.report = pointing_device_driver->get_report((report_mouse_t){0}); 765 // Now update the checksum given that the pointing has been written to 766 pointing.checksum = crc8(&pointing.report, sizeof(report_mouse_t)); 767 768 split_shared_memory_lock(); 769 memcpy(&split_shmem->pointing, &pointing, sizeof(split_slave_pointing_sync_t)); 770 split_shared_memory_unlock(); 771 } 772 773 # define TRANSACTIONS_POINTING_MASTER() TRANSACTION_HANDLER_MASTER(pointing) 774 # define TRANSACTIONS_POINTING_SLAVE() TRANSACTION_HANDLER_SLAVE(pointing) 775 # 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), 776 777 #else // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) 778 779 # define TRANSACTIONS_POINTING_MASTER() 780 # define TRANSACTIONS_POINTING_SLAVE() 781 # define TRANSACTIONS_POINTING_REGISTRATIONS 782 783 #endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE) 784 785 //////////////////////////////////////////////////// 786 // WATCHDOG 787 788 #if defined(SPLIT_WATCHDOG_ENABLE) 789 790 static bool watchdog_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 791 bool okay = true; 792 if (!split_watchdog_check()) { 793 okay = transport_write(PUT_WATCHDOG, &okay, sizeof(okay)); 794 split_watchdog_update(okay); 795 } 796 return okay; 797 } 798 799 static void watchdog_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 800 split_watchdog_update(split_shmem->watchdog_pinged); 801 } 802 803 # define TRANSACTIONS_WATCHDOG_MASTER() TRANSACTION_HANDLER_MASTER(watchdog) 804 # define TRANSACTIONS_WATCHDOG_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(watchdog) 805 # define TRANSACTIONS_WATCHDOG_REGISTRATIONS [PUT_WATCHDOG] = trans_initiator2target_initializer(watchdog_pinged), 806 807 #else // defined(SPLIT_WATCHDOG_ENABLE) 808 809 # define TRANSACTIONS_WATCHDOG_MASTER() 810 # define TRANSACTIONS_WATCHDOG_SLAVE() 811 # define TRANSACTIONS_WATCHDOG_REGISTRATIONS 812 813 #endif // defined(SPLIT_WATCHDOG_ENABLE) 814 815 #if defined(HAPTIC_ENABLE) && defined(SPLIT_HAPTIC_ENABLE) 816 817 uint8_t split_haptic_play = 0xFF; 818 extern haptic_config_t haptic_config; 819 820 static bool haptic_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 821 static uint32_t last_update = 0; 822 split_slave_haptic_sync_t haptic_sync; 823 824 memcpy(&haptic_sync.haptic_config, &haptic_config, sizeof(haptic_config_t)); 825 haptic_sync.haptic_play = split_haptic_play; 826 827 bool okay = send_if_data_mismatch(PUT_HAPTIC, &last_update, &haptic_sync, &split_shmem->haptic_sync, sizeof(haptic_sync)); 828 829 split_haptic_play = 0xFF; 830 831 return okay; 832 } 833 834 static void haptic_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 835 memcpy(&haptic_config, &split_shmem->haptic_sync.haptic_config, sizeof(haptic_config_t)); 836 837 if (split_shmem->haptic_sync.haptic_play != 0xFF) { 838 haptic_set_mode(split_shmem->haptic_sync.haptic_play); 839 haptic_play(); 840 } 841 } 842 843 // clang-format off 844 # define TRANSACTIONS_HAPTIC_MASTER() TRANSACTION_HANDLER_MASTER(haptic) 845 # define TRANSACTIONS_HAPTIC_SLAVE() TRANSACTION_HANDLER_SLAVE(haptic) 846 # define TRANSACTIONS_HAPTIC_REGISTRATIONS [PUT_HAPTIC] = trans_initiator2target_initializer(haptic_sync), 847 // clang-format on 848 849 #else // defined(HAPTIC_ENABLE) && defined(SPLIT_HAPTIC_ENABLE) 850 851 # define TRANSACTIONS_HAPTIC_MASTER() 852 # define TRANSACTIONS_HAPTIC_SLAVE() 853 # define TRANSACTIONS_HAPTIC_REGISTRATIONS 854 855 #endif // defined(HAPTIC_ENABLE) && defined(SPLIT_HAPTIC_ENABLE) 856 857 #if defined(SPLIT_ACTIVITY_ENABLE) 858 859 static bool activity_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 860 static uint32_t last_update = 0; 861 split_slave_activity_sync_t activity_sync; 862 activity_sync.matrix_timestamp = last_matrix_activity_time(); 863 activity_sync.encoder_timestamp = last_encoder_activity_time(); 864 activity_sync.pointing_device_timestamp = last_pointing_device_activity_time(); 865 return send_if_data_mismatch(PUT_ACTIVITY, &last_update, &activity_sync, &split_shmem->activity_sync, sizeof(activity_sync)); 866 } 867 868 static void activity_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 869 set_activity_timestamps(split_shmem->activity_sync.matrix_timestamp, split_shmem->activity_sync.encoder_timestamp, split_shmem->activity_sync.pointing_device_timestamp); 870 } 871 872 // clang-format off 873 # define TRANSACTIONS_ACTIVITY_MASTER() TRANSACTION_HANDLER_MASTER(activity) 874 # define TRANSACTIONS_ACTIVITY_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(activity) 875 # define TRANSACTIONS_ACTIVITY_REGISTRATIONS [PUT_ACTIVITY] = trans_initiator2target_initializer(activity_sync), 876 // clang-format on 877 878 #else // defined(SPLIT_ACTIVITY_ENABLE) 879 880 # define TRANSACTIONS_ACTIVITY_MASTER() 881 # define TRANSACTIONS_ACTIVITY_SLAVE() 882 # define TRANSACTIONS_ACTIVITY_REGISTRATIONS 883 884 #endif // defined(SPLIT_ACTIVITY_ENABLE) 885 886 //////////////////////////////////////////////////// 887 // Detected OS 888 889 #if defined(OS_DETECTION_ENABLE) && defined(SPLIT_DETECTED_OS_ENABLE) 890 891 static bool detected_os_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 892 static uint32_t last_detected_os_update = 0; 893 os_variant_t detected_os = detected_host_os(); 894 bool okay = send_if_condition(PUT_DETECTED_OS, &last_detected_os_update, (detected_os != split_shmem->detected_os), &detected_os, sizeof(os_variant_t)); 895 return okay; 896 } 897 898 static void detected_os_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 899 slave_update_detected_host_os(split_shmem->detected_os); 900 } 901 902 # define TRANSACTIONS_DETECTED_OS_MASTER() TRANSACTION_HANDLER_MASTER(detected_os) 903 # define TRANSACTIONS_DETECTED_OS_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(detected_os) 904 # define TRANSACTIONS_DETECTED_OS_REGISTRATIONS [PUT_DETECTED_OS] = trans_initiator2target_initializer(detected_os), 905 906 #else // defined(OS_DETECTION_ENABLE) && defined(SPLIT_DETECTED_OS_ENABLE) 907 908 # define TRANSACTIONS_DETECTED_OS_MASTER() 909 # define TRANSACTIONS_DETECTED_OS_SLAVE() 910 # define TRANSACTIONS_DETECTED_OS_REGISTRATIONS 911 912 #endif // defined(OS_DETECTION_ENABLE) && defined(SPLIT_DETECTED_OS_ENABLE) 913 914 //////////////////////////////////////////////////// 915 916 split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = { 917 // Set defaults 918 [0 ...(NUM_TOTAL_TRANSACTIONS - 1)] = {0, 0, 0, 0, 0}, 919 920 #ifdef USE_I2C 921 [I2C_EXECUTE_CALLBACK] = trans_initiator2target_initializer(transaction_id), 922 #endif // USE_I2C 923 924 // clang-format off 925 TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS 926 TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS 927 TRANSACTIONS_ENCODERS_REGISTRATIONS 928 TRANSACTIONS_SYNC_TIMER_REGISTRATIONS 929 TRANSACTIONS_LAYER_STATE_REGISTRATIONS 930 TRANSACTIONS_LED_STATE_REGISTRATIONS 931 TRANSACTIONS_MODS_REGISTRATIONS 932 TRANSACTIONS_BACKLIGHT_REGISTRATIONS 933 TRANSACTIONS_RGBLIGHT_REGISTRATIONS 934 TRANSACTIONS_LED_MATRIX_REGISTRATIONS 935 TRANSACTIONS_RGB_MATRIX_REGISTRATIONS 936 TRANSACTIONS_WPM_REGISTRATIONS 937 TRANSACTIONS_OLED_REGISTRATIONS 938 TRANSACTIONS_ST7565_REGISTRATIONS 939 TRANSACTIONS_POINTING_REGISTRATIONS 940 TRANSACTIONS_WATCHDOG_REGISTRATIONS 941 TRANSACTIONS_HAPTIC_REGISTRATIONS 942 TRANSACTIONS_ACTIVITY_REGISTRATIONS 943 TRANSACTIONS_DETECTED_OS_REGISTRATIONS 944 // clang-format on 945 946 #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) 947 [PUT_RPC_INFO] = trans_initiator2target_initializer_cb(rpc_info, slave_rpc_info_callback), 948 [PUT_RPC_REQ_DATA] = trans_initiator2target_initializer(rpc_m2s_buffer), 949 [EXECUTE_RPC] = trans_initiator2target_initializer_cb(rpc_info.payload.transaction_id, slave_rpc_exec_callback), 950 [GET_RPC_RESP_DATA] = trans_target2initiator_initializer(rpc_s2m_buffer), 951 #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) 952 }; 953 954 bool transactions_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 955 TRANSACTIONS_SLAVE_MATRIX_MASTER(); 956 TRANSACTIONS_MASTER_MATRIX_MASTER(); 957 TRANSACTIONS_ENCODERS_MASTER(); 958 TRANSACTIONS_SYNC_TIMER_MASTER(); 959 TRANSACTIONS_LAYER_STATE_MASTER(); 960 TRANSACTIONS_LED_STATE_MASTER(); 961 TRANSACTIONS_MODS_MASTER(); 962 TRANSACTIONS_BACKLIGHT_MASTER(); 963 TRANSACTIONS_RGBLIGHT_MASTER(); 964 TRANSACTIONS_LED_MATRIX_MASTER(); 965 TRANSACTIONS_RGB_MATRIX_MASTER(); 966 TRANSACTIONS_WPM_MASTER(); 967 TRANSACTIONS_OLED_MASTER(); 968 TRANSACTIONS_ST7565_MASTER(); 969 TRANSACTIONS_POINTING_MASTER(); 970 TRANSACTIONS_WATCHDOG_MASTER(); 971 TRANSACTIONS_HAPTIC_MASTER(); 972 TRANSACTIONS_ACTIVITY_MASTER(); 973 TRANSACTIONS_DETECTED_OS_MASTER(); 974 return true; 975 } 976 977 void transactions_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 978 TRANSACTIONS_SLAVE_MATRIX_SLAVE(); 979 TRANSACTIONS_MASTER_MATRIX_SLAVE(); 980 TRANSACTIONS_ENCODERS_SLAVE(); 981 TRANSACTIONS_SYNC_TIMER_SLAVE(); 982 TRANSACTIONS_LAYER_STATE_SLAVE(); 983 TRANSACTIONS_LED_STATE_SLAVE(); 984 TRANSACTIONS_MODS_SLAVE(); 985 TRANSACTIONS_BACKLIGHT_SLAVE(); 986 TRANSACTIONS_RGBLIGHT_SLAVE(); 987 TRANSACTIONS_LED_MATRIX_SLAVE(); 988 TRANSACTIONS_RGB_MATRIX_SLAVE(); 989 TRANSACTIONS_WPM_SLAVE(); 990 TRANSACTIONS_OLED_SLAVE(); 991 TRANSACTIONS_ST7565_SLAVE(); 992 TRANSACTIONS_POINTING_SLAVE(); 993 TRANSACTIONS_WATCHDOG_SLAVE(); 994 TRANSACTIONS_HAPTIC_SLAVE(); 995 TRANSACTIONS_ACTIVITY_SLAVE(); 996 TRANSACTIONS_DETECTED_OS_SLAVE(); 997 } 998 999 #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) 1000 1001 void transaction_register_rpc(int8_t transaction_id, slave_callback_t callback) { 1002 // Prevent invoking RPC on QMK core sync data 1003 if (transaction_id <= GET_RPC_RESP_DATA) return; 1004 1005 // Set the callback 1006 split_transaction_table[transaction_id].slave_callback = callback; 1007 split_transaction_table[transaction_id].initiator2target_offset = offsetof(split_shared_memory_t, rpc_m2s_buffer); 1008 split_transaction_table[transaction_id].target2initiator_offset = offsetof(split_shared_memory_t, rpc_s2m_buffer); 1009 } 1010 1011 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) { 1012 // Prevent transaction attempts while transport is disconnected 1013 if (!is_transport_connected()) { 1014 return false; 1015 } 1016 // Prevent invoking RPC on QMK core sync data 1017 if (transaction_id <= GET_RPC_RESP_DATA) return false; 1018 // Prevent sizing issues 1019 if (initiator2target_buffer_size > RPC_M2S_BUFFER_SIZE) return false; 1020 if (target2initiator_buffer_size > RPC_S2M_BUFFER_SIZE) return false; 1021 1022 // Prepare the metadata block 1023 rpc_sync_info_t info = {.payload = {.transaction_id = transaction_id, .m2s_length = initiator2target_buffer_size, .s2m_length = target2initiator_buffer_size}}; 1024 info.checksum = crc8(&info.payload, sizeof(info.payload)); 1025 1026 // Make sure the local side knows that we're not sending the full block of data 1027 split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = initiator2target_buffer_size; 1028 split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = target2initiator_buffer_size; 1029 1030 // Run through the sequence: 1031 // * set the transaction ID and lengths 1032 // * send the request data 1033 // * execute RPC callback 1034 // * retrieve the response data 1035 if (!transport_write(PUT_RPC_INFO, &info, sizeof(info))) { 1036 return false; 1037 } 1038 if (!transport_write(PUT_RPC_REQ_DATA, initiator2target_buffer, initiator2target_buffer_size)) { 1039 return false; 1040 } 1041 if (!transport_write(EXECUTE_RPC, &transaction_id, sizeof(transaction_id))) { 1042 return false; 1043 } 1044 if (!transport_read(GET_RPC_RESP_DATA, target2initiator_buffer, target2initiator_buffer_size)) { 1045 return false; 1046 } 1047 return true; 1048 } 1049 1050 void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) { 1051 // The RPC info block contains the intended transaction ID, as well as the sizes for both inbound and outbound data. 1052 // Ignore the args -- the `split_shmem` already has the info, we just need to act upon it. 1053 // We must keep the `split_transaction_table` non-const, so that it is able to be modified at runtime. 1054 1055 split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = split_shmem->rpc_info.payload.m2s_length; 1056 split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = split_shmem->rpc_info.payload.s2m_length; 1057 } 1058 1059 void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) { 1060 // We can assume that the buffer lengths are correctly set, now, given that sequentially the rpc_info callback was already executed. 1061 // Go through the rpc_info and execute _that_ transaction's callback, with the scratch buffers as inputs. 1062 // As a safety precaution we check that the received payload matches its checksum first. 1063 if (crc8(&split_shmem->rpc_info.payload, sizeof(split_shmem->rpc_info.payload)) != split_shmem->rpc_info.checksum) { 1064 return; 1065 } 1066 1067 int8_t transaction_id = split_shmem->rpc_info.payload.transaction_id; 1068 if (transaction_id < NUM_TOTAL_TRANSACTIONS) { 1069 split_transaction_desc_t *trans = &split_transaction_table[transaction_id]; 1070 if (trans->slave_callback) { 1071 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); 1072 } 1073 } 1074 } 1075 1076 #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)