transactions.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904
  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. #include <string.h>
  17. #include <stddef.h>
  18. #include "crc.h"
  19. #include "debug.h"
  20. #include "matrix.h"
  21. #include "quantum.h"
  22. #include "transactions.h"
  23. #include "transport.h"
  24. #include "transaction_id_define.h"
  25. #include "split_util.h"
  26. #include "synchronization_util.h"
  27. #define SYNC_TIMER_OFFSET 2
  28. #ifndef FORCED_SYNC_THROTTLE_MS
  29. # define FORCED_SYNC_THROTTLE_MS 100
  30. #endif // FORCED_SYNC_THROTTLE_MS
  31. #define sizeof_member(type, member) sizeof(((type *)NULL)->member)
  32. #define trans_initiator2target_initializer_cb(member, cb) \
  33. { sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), 0, 0, cb }
  34. #define trans_initiator2target_initializer(member) trans_initiator2target_initializer_cb(member, NULL)
  35. #define trans_target2initiator_initializer_cb(member, cb) \
  36. { 0, 0, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), cb }
  37. #define trans_target2initiator_initializer(member) trans_target2initiator_initializer_cb(member, NULL)
  38. #define transport_write(id, data, length) transport_execute_transaction(id, data, length, NULL, 0)
  39. #define transport_read(id, data, length) transport_execute_transaction(id, NULL, 0, data, length)
  40. #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
  41. // Forward-declare the RPC callback handlers
  42. void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
  43. void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
  44. #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
  45. ////////////////////////////////////////////////////
  46. // Helpers
  47. 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[])) {
  48. int num_retries = is_transport_connected() ? 10 : 1;
  49. for (int iter = 1; iter <= num_retries; ++iter) {
  50. if (iter > 1) {
  51. for (int i = 0; i < iter * iter; ++i) {
  52. wait_us(10);
  53. }
  54. }
  55. bool this_okay = true;
  56. this_okay = handler(master_matrix, slave_matrix);
  57. if (this_okay) return true;
  58. }
  59. dprintf("Failed to execute %s\n", prefix);
  60. return false;
  61. }
  62. #define TRANSACTION_HANDLER_MASTER(prefix) \
  63. do { \
  64. if (!transaction_handler_master(master_matrix, slave_matrix, #prefix, &prefix##_handlers_master)) return false; \
  65. } while (0)
  66. /**
  67. * @brief Constructs a transaction handler that doesn't acquire a lock to the
  68. * split shared memory. Therefore the locking and unlocking has to be done
  69. * manually inside the handler. Use this macro only if the handler is
  70. * non-deterministic in runtime and thus needs a manual lock unlock
  71. * implementation to hold the lock for the shortest possible time.
  72. */
  73. #define TRANSACTION_HANDLER_SLAVE(prefix) \
  74. do { \
  75. prefix##_handlers_slave(master_matrix, slave_matrix); \
  76. } while (0)
  77. /**
  78. * @brief Constructs a transaction handler that automatically acquires a lock to
  79. * safely access the split shared memory and releases the lock again after
  80. * processing the handler. Use this macro if the handler is fast and
  81. * deterministic in runtime and thus holds the lock only for a very short time.
  82. * If not fallback to manually locking and unlocking inside the handler.
  83. */
  84. #define TRANSACTION_HANDLER_SLAVE_AUTOLOCK(prefix) \
  85. do { \
  86. split_shared_memory_lock(); \
  87. prefix##_handlers_slave(master_matrix, slave_matrix); \
  88. split_shared_memory_unlock(); \
  89. } while (0)
  90. 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) {
  91. uint8_t curr_checksum;
  92. bool okay = transport_read(trans_id_checksum, &curr_checksum, sizeof(curr_checksum));
  93. if (okay && (timer_elapsed32(*last_update) >= FORCED_SYNC_THROTTLE_MS || curr_checksum != crc8(equiv_shmem, length))) {
  94. okay &= transport_read(trans_id_retrieve, destination, length);
  95. okay &= curr_checksum == crc8(equiv_shmem, length);
  96. if (okay) {
  97. *last_update = timer_read32();
  98. }
  99. } else {
  100. memcpy(destination, equiv_shmem, length);
  101. }
  102. return okay;
  103. }
  104. inline static bool send_if_condition(int8_t trans_id, uint32_t *last_update, bool condition, void *source, size_t length) {
  105. bool okay = true;
  106. if (timer_elapsed32(*last_update) >= FORCED_SYNC_THROTTLE_MS || condition) {
  107. okay &= transport_write(trans_id, source, length);
  108. if (okay) {
  109. *last_update = timer_read32();
  110. }
  111. }
  112. return okay;
  113. }
  114. inline static bool send_if_data_mismatch(int8_t trans_id, uint32_t *last_update, void *source, const void *equiv_shmem, size_t length) {
  115. // Just run a memcmp to compare the source and equivalent shmem location
  116. return send_if_condition(trans_id, last_update, (memcmp(source, equiv_shmem, length) != 0), source, length);
  117. }
  118. ////////////////////////////////////////////////////
  119. // Slave matrix
  120. static bool slave_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  121. static uint32_t last_update = 0;
  122. static matrix_row_t last_matrix[(MATRIX_ROWS) / 2] = {0}; // last successfully-read matrix, so we can replicate if there are checksum errors
  123. matrix_row_t temp_matrix[(MATRIX_ROWS) / 2]; // holding area while we test whether or not checksum is correct
  124. 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));
  125. if (okay) {
  126. // Checksum matches the received data, save as the last matrix state
  127. memcpy(last_matrix, temp_matrix, sizeof(temp_matrix));
  128. }
  129. // Copy out the last-known-good matrix state to the slave matrix
  130. memcpy(slave_matrix, last_matrix, sizeof(last_matrix));
  131. return okay;
  132. }
  133. static void slave_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  134. memcpy(split_shmem->smatrix.matrix, slave_matrix, sizeof(split_shmem->smatrix.matrix));
  135. split_shmem->smatrix.checksum = crc8(split_shmem->smatrix.matrix, sizeof(split_shmem->smatrix.matrix));
  136. }
  137. // clang-format off
  138. #define TRANSACTIONS_SLAVE_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(slave_matrix)
  139. #define TRANSACTIONS_SLAVE_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(slave_matrix)
  140. #define TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS \
  141. [GET_SLAVE_MATRIX_CHECKSUM] = trans_target2initiator_initializer(smatrix.checksum), \
  142. [GET_SLAVE_MATRIX_DATA] = trans_target2initiator_initializer(smatrix.matrix),
  143. // clang-format on
  144. ////////////////////////////////////////////////////
  145. // Master matrix
  146. #ifdef SPLIT_TRANSPORT_MIRROR
  147. static bool master_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  148. static uint32_t last_update = 0;
  149. return send_if_data_mismatch(PUT_MASTER_MATRIX, &last_update, master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix));
  150. }
  151. static void master_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  152. // Always copy to the master matrix
  153. memcpy(master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix));
  154. }
  155. # define TRANSACTIONS_MASTER_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(master_matrix)
  156. # define TRANSACTIONS_MASTER_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(master_matrix)
  157. # define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS [PUT_MASTER_MATRIX] = trans_initiator2target_initializer(mmatrix.matrix),
  158. #else // SPLIT_TRANSPORT_MIRROR
  159. # define TRANSACTIONS_MASTER_MATRIX_MASTER()
  160. # define TRANSACTIONS_MASTER_MATRIX_SLAVE()
  161. # define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS
  162. #endif // SPLIT_TRANSPORT_MIRROR
  163. ////////////////////////////////////////////////////
  164. // Encoders
  165. #ifdef ENCODER_ENABLE
  166. static bool encoder_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  167. static uint32_t last_update = 0;
  168. uint8_t temp_state[NUM_ENCODERS_MAX_PER_SIDE];
  169. bool okay = read_if_checksum_mismatch(GET_ENCODERS_CHECKSUM, GET_ENCODERS_DATA, &last_update, temp_state, split_shmem->encoders.state, sizeof(temp_state));
  170. if (okay) encoder_update_raw(temp_state);
  171. return okay;
  172. }
  173. static void encoder_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  174. uint8_t encoder_state[NUM_ENCODERS_MAX_PER_SIDE];
  175. encoder_state_raw(encoder_state);
  176. // Always prepare the encoder state for read.
  177. memcpy(split_shmem->encoders.state, encoder_state, sizeof(encoder_state));
  178. // Now update the checksum given that the encoders has been written to
  179. split_shmem->encoders.checksum = crc8(encoder_state, sizeof(encoder_state));
  180. }
  181. // clang-format off
  182. # define TRANSACTIONS_ENCODERS_MASTER() TRANSACTION_HANDLER_MASTER(encoder)
  183. # define TRANSACTIONS_ENCODERS_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(encoder)
  184. # define TRANSACTIONS_ENCODERS_REGISTRATIONS \
  185. [GET_ENCODERS_CHECKSUM] = trans_target2initiator_initializer(encoders.checksum), \
  186. [GET_ENCODERS_DATA] = trans_target2initiator_initializer(encoders.state),
  187. // clang-format on
  188. #else // ENCODER_ENABLE
  189. # define TRANSACTIONS_ENCODERS_MASTER()
  190. # define TRANSACTIONS_ENCODERS_SLAVE()
  191. # define TRANSACTIONS_ENCODERS_REGISTRATIONS
  192. #endif // ENCODER_ENABLE
  193. ////////////////////////////////////////////////////
  194. // Sync timer
  195. #ifndef DISABLE_SYNC_TIMER
  196. static bool sync_timer_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  197. static uint32_t last_update = 0;
  198. bool okay = true;
  199. if (timer_elapsed32(last_update) >= FORCED_SYNC_THROTTLE_MS) {
  200. uint32_t sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
  201. okay &= transport_write(PUT_SYNC_TIMER, &sync_timer, sizeof(sync_timer));
  202. if (okay) {
  203. last_update = timer_read32();
  204. }
  205. }
  206. return okay;
  207. }
  208. static void sync_timer_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  209. static uint32_t last_sync_timer = 0;
  210. if (last_sync_timer != split_shmem->sync_timer) {
  211. last_sync_timer = split_shmem->sync_timer;
  212. sync_timer_update(last_sync_timer);
  213. }
  214. }
  215. # define TRANSACTIONS_SYNC_TIMER_MASTER() TRANSACTION_HANDLER_MASTER(sync_timer)
  216. # define TRANSACTIONS_SYNC_TIMER_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(sync_timer)
  217. # define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS [PUT_SYNC_TIMER] = trans_initiator2target_initializer(sync_timer),
  218. #else // DISABLE_SYNC_TIMER
  219. # define TRANSACTIONS_SYNC_TIMER_MASTER()
  220. # define TRANSACTIONS_SYNC_TIMER_SLAVE()
  221. # define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS
  222. #endif // DISABLE_SYNC_TIMER
  223. ////////////////////////////////////////////////////
  224. // Layer state
  225. #if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
  226. static bool layer_state_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  227. static uint32_t last_layer_state_update = 0;
  228. static uint32_t last_default_layer_state_update = 0;
  229. bool okay = send_if_condition(PUT_LAYER_STATE, &last_layer_state_update, (layer_state != split_shmem->layers.layer_state), &layer_state, sizeof(layer_state));
  230. if (okay) {
  231. 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));
  232. }
  233. return okay;
  234. }
  235. static void layer_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  236. layer_state = split_shmem->layers.layer_state;
  237. default_layer_state = split_shmem->layers.default_layer_state;
  238. }
  239. // clang-format off
  240. # define TRANSACTIONS_LAYER_STATE_MASTER() TRANSACTION_HANDLER_MASTER(layer_state)
  241. # define TRANSACTIONS_LAYER_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(layer_state)
  242. # define TRANSACTIONS_LAYER_STATE_REGISTRATIONS \
  243. [PUT_LAYER_STATE] = trans_initiator2target_initializer(layers.layer_state), \
  244. [PUT_DEFAULT_LAYER_STATE] = trans_initiator2target_initializer(layers.default_layer_state),
  245. // clang-format on
  246. #else // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
  247. # define TRANSACTIONS_LAYER_STATE_MASTER()
  248. # define TRANSACTIONS_LAYER_STATE_SLAVE()
  249. # define TRANSACTIONS_LAYER_STATE_REGISTRATIONS
  250. #endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
  251. ////////////////////////////////////////////////////
  252. // LED state
  253. #ifdef SPLIT_LED_STATE_ENABLE
  254. static bool led_state_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  255. static uint32_t last_update = 0;
  256. uint8_t led_state = host_keyboard_leds();
  257. return send_if_data_mismatch(PUT_LED_STATE, &last_update, &led_state, &split_shmem->led_state, sizeof(led_state));
  258. }
  259. static void led_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  260. void set_split_host_keyboard_leds(uint8_t led_state);
  261. set_split_host_keyboard_leds(split_shmem->led_state);
  262. }
  263. # define TRANSACTIONS_LED_STATE_MASTER() TRANSACTION_HANDLER_MASTER(led_state)
  264. # define TRANSACTIONS_LED_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(led_state)
  265. # define TRANSACTIONS_LED_STATE_REGISTRATIONS [PUT_LED_STATE] = trans_initiator2target_initializer(led_state),
  266. #else // SPLIT_LED_STATE_ENABLE
  267. # define TRANSACTIONS_LED_STATE_MASTER()
  268. # define TRANSACTIONS_LED_STATE_SLAVE()
  269. # define TRANSACTIONS_LED_STATE_REGISTRATIONS
  270. #endif // SPLIT_LED_STATE_ENABLE
  271. ////////////////////////////////////////////////////
  272. // Mods
  273. #ifdef SPLIT_MODS_ENABLE
  274. static bool mods_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  275. static uint32_t last_update = 0;
  276. bool mods_need_sync = timer_elapsed32(last_update) >= FORCED_SYNC_THROTTLE_MS;
  277. split_mods_sync_t new_mods;
  278. new_mods.real_mods = get_mods();
  279. if (!mods_need_sync && new_mods.real_mods != split_shmem->mods.real_mods) {
  280. mods_need_sync = true;
  281. }
  282. new_mods.weak_mods = get_weak_mods();
  283. if (!mods_need_sync && new_mods.weak_mods != split_shmem->mods.weak_mods) {
  284. mods_need_sync = true;
  285. }
  286. # ifndef NO_ACTION_ONESHOT
  287. new_mods.oneshot_mods = get_oneshot_mods();
  288. if (!mods_need_sync && new_mods.oneshot_mods != split_shmem->mods.oneshot_mods) {
  289. mods_need_sync = true;
  290. }
  291. # endif // NO_ACTION_ONESHOT
  292. bool okay = true;
  293. if (mods_need_sync) {
  294. okay &= transport_write(PUT_MODS, &new_mods, sizeof(new_mods));
  295. if (okay) {
  296. last_update = timer_read32();
  297. }
  298. }
  299. return okay;
  300. }
  301. static void mods_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  302. split_shared_memory_lock();
  303. split_mods_sync_t mods;
  304. memcpy(&mods, &split_shmem->mods, sizeof(split_mods_sync_t));
  305. split_shared_memory_unlock();
  306. set_mods(mods.real_mods);
  307. set_weak_mods(mods.weak_mods);
  308. # ifndef NO_ACTION_ONESHOT
  309. set_oneshot_mods(mods.oneshot_mods);
  310. # endif
  311. }
  312. # define TRANSACTIONS_MODS_MASTER() TRANSACTION_HANDLER_MASTER(mods)
  313. # define TRANSACTIONS_MODS_SLAVE() TRANSACTION_HANDLER_SLAVE(mods)
  314. # define TRANSACTIONS_MODS_REGISTRATIONS [PUT_MODS] = trans_initiator2target_initializer(mods),
  315. #else // SPLIT_MODS_ENABLE
  316. # define TRANSACTIONS_MODS_MASTER()
  317. # define TRANSACTIONS_MODS_SLAVE()
  318. # define TRANSACTIONS_MODS_REGISTRATIONS
  319. #endif // SPLIT_MODS_ENABLE
  320. ////////////////////////////////////////////////////
  321. // Backlight
  322. #ifdef BACKLIGHT_ENABLE
  323. static bool backlight_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  324. static uint32_t last_update = 0;
  325. uint8_t level = is_backlight_enabled() ? get_backlight_level() : 0;
  326. return send_if_condition(PUT_BACKLIGHT, &last_update, (level != split_shmem->backlight_level), &level, sizeof(level));
  327. }
  328. static void backlight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  329. split_shared_memory_lock();
  330. uint8_t backlight_level = split_shmem->backlight_level;
  331. split_shared_memory_unlock();
  332. backlight_set(backlight_level);
  333. }
  334. # define TRANSACTIONS_BACKLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(backlight)
  335. # define TRANSACTIONS_BACKLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(backlight)
  336. # define TRANSACTIONS_BACKLIGHT_REGISTRATIONS [PUT_BACKLIGHT] = trans_initiator2target_initializer(backlight_level),
  337. #else // BACKLIGHT_ENABLE
  338. # define TRANSACTIONS_BACKLIGHT_MASTER()
  339. # define TRANSACTIONS_BACKLIGHT_SLAVE()
  340. # define TRANSACTIONS_BACKLIGHT_REGISTRATIONS
  341. #endif // BACKLIGHT_ENABLE
  342. ////////////////////////////////////////////////////
  343. // RGBLIGHT
  344. #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
  345. static bool rgblight_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  346. static uint32_t last_update = 0;
  347. rgblight_syncinfo_t rgblight_sync;
  348. rgblight_get_syncinfo(&rgblight_sync);
  349. if (send_if_condition(PUT_RGBLIGHT, &last_update, (rgblight_sync.status.change_flags != 0), &rgblight_sync, sizeof(rgblight_sync))) {
  350. rgblight_clear_change_flags();
  351. } else {
  352. return false;
  353. }
  354. return true;
  355. }
  356. static void rgblight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  357. split_shared_memory_lock();
  358. // Update the RGB with the new data
  359. rgblight_syncinfo_t rgblight_sync;
  360. memcpy(&rgblight_sync, &split_shmem->rgblight_sync, sizeof(rgblight_syncinfo_t));
  361. split_shmem->rgblight_sync.status.change_flags = 0;
  362. split_shared_memory_unlock();
  363. if (rgblight_sync.status.change_flags != 0) {
  364. rgblight_update_sync(&rgblight_sync, false);
  365. }
  366. }
  367. # define TRANSACTIONS_RGBLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(rgblight)
  368. # define TRANSACTIONS_RGBLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(rgblight)
  369. # define TRANSACTIONS_RGBLIGHT_REGISTRATIONS [PUT_RGBLIGHT] = trans_initiator2target_initializer(rgblight_sync),
  370. #else // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
  371. # define TRANSACTIONS_RGBLIGHT_MASTER()
  372. # define TRANSACTIONS_RGBLIGHT_SLAVE()
  373. # define TRANSACTIONS_RGBLIGHT_REGISTRATIONS
  374. #endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
  375. ////////////////////////////////////////////////////
  376. // LED Matrix
  377. #if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
  378. static bool led_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  379. static uint32_t last_update = 0;
  380. led_matrix_sync_t led_matrix_sync;
  381. memcpy(&led_matrix_sync.led_matrix, &led_matrix_eeconfig, sizeof(led_eeconfig_t));
  382. led_matrix_sync.led_suspend_state = led_matrix_get_suspend_state();
  383. return send_if_data_mismatch(PUT_LED_MATRIX, &last_update, &led_matrix_sync, &split_shmem->led_matrix_sync, sizeof(led_matrix_sync));
  384. }
  385. static void led_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  386. split_shared_memory_lock();
  387. memcpy(&led_matrix_eeconfig, &split_shmem->led_matrix_sync.led_matrix, sizeof(led_eeconfig_t));
  388. bool led_suspend_state = split_shmem->led_matrix_sync.led_suspend_state;
  389. split_shared_memory_unlock();
  390. led_matrix_set_suspend_state(led_suspend_state);
  391. }
  392. # define TRANSACTIONS_LED_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(led_matrix)
  393. # define TRANSACTIONS_LED_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(led_matrix)
  394. # define TRANSACTIONS_LED_MATRIX_REGISTRATIONS [PUT_LED_MATRIX] = trans_initiator2target_initializer(led_matrix_sync),
  395. #else // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
  396. # define TRANSACTIONS_LED_MATRIX_MASTER()
  397. # define TRANSACTIONS_LED_MATRIX_SLAVE()
  398. # define TRANSACTIONS_LED_MATRIX_REGISTRATIONS
  399. #endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
  400. ////////////////////////////////////////////////////
  401. // RGB Matrix
  402. #if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
  403. static bool rgb_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  404. static uint32_t last_update = 0;
  405. rgb_matrix_sync_t rgb_matrix_sync;
  406. memcpy(&rgb_matrix_sync.rgb_matrix, &rgb_matrix_config, sizeof(rgb_config_t));
  407. rgb_matrix_sync.rgb_suspend_state = rgb_matrix_get_suspend_state();
  408. return send_if_data_mismatch(PUT_RGB_MATRIX, &last_update, &rgb_matrix_sync, &split_shmem->rgb_matrix_sync, sizeof(rgb_matrix_sync));
  409. }
  410. static void rgb_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  411. split_shared_memory_lock();
  412. memcpy(&rgb_matrix_config, &split_shmem->rgb_matrix_sync.rgb_matrix, sizeof(rgb_config_t));
  413. bool rgb_suspend_state = split_shmem->rgb_matrix_sync.rgb_suspend_state;
  414. split_shared_memory_unlock();
  415. rgb_matrix_set_suspend_state(rgb_suspend_state);
  416. }
  417. # define TRANSACTIONS_RGB_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(rgb_matrix)
  418. # define TRANSACTIONS_RGB_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(rgb_matrix)
  419. # define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS [PUT_RGB_MATRIX] = trans_initiator2target_initializer(rgb_matrix_sync),
  420. #else // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
  421. # define TRANSACTIONS_RGB_MATRIX_MASTER()
  422. # define TRANSACTIONS_RGB_MATRIX_SLAVE()
  423. # define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS
  424. #endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
  425. ////////////////////////////////////////////////////
  426. // WPM
  427. #if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
  428. static bool wpm_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  429. static uint32_t last_update = 0;
  430. uint8_t current_wpm = get_current_wpm();
  431. return send_if_condition(PUT_WPM, &last_update, (current_wpm != split_shmem->current_wpm), &current_wpm, sizeof(current_wpm));
  432. }
  433. static void wpm_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  434. set_current_wpm(split_shmem->current_wpm);
  435. }
  436. # define TRANSACTIONS_WPM_MASTER() TRANSACTION_HANDLER_MASTER(wpm)
  437. # define TRANSACTIONS_WPM_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(wpm)
  438. # define TRANSACTIONS_WPM_REGISTRATIONS [PUT_WPM] = trans_initiator2target_initializer(current_wpm),
  439. #else // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
  440. # define TRANSACTIONS_WPM_MASTER()
  441. # define TRANSACTIONS_WPM_SLAVE()
  442. # define TRANSACTIONS_WPM_REGISTRATIONS
  443. #endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
  444. ////////////////////////////////////////////////////
  445. // OLED
  446. #if defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)
  447. static bool oled_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  448. static uint32_t last_update = 0;
  449. bool current_oled_state = is_oled_on();
  450. return send_if_condition(PUT_OLED, &last_update, (current_oled_state != split_shmem->current_oled_state), &current_oled_state, sizeof(current_oled_state));
  451. }
  452. static void oled_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  453. split_shared_memory_lock();
  454. uint8_t current_oled_state = split_shmem->current_oled_state;
  455. split_shared_memory_unlock();
  456. if (current_oled_state) {
  457. oled_on();
  458. } else {
  459. oled_off();
  460. }
  461. }
  462. # define TRANSACTIONS_OLED_MASTER() TRANSACTION_HANDLER_MASTER(oled)
  463. # define TRANSACTIONS_OLED_SLAVE() TRANSACTION_HANDLER_SLAVE(oled)
  464. # define TRANSACTIONS_OLED_REGISTRATIONS [PUT_OLED] = trans_initiator2target_initializer(current_oled_state),
  465. #else // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)
  466. # define TRANSACTIONS_OLED_MASTER()
  467. # define TRANSACTIONS_OLED_SLAVE()
  468. # define TRANSACTIONS_OLED_REGISTRATIONS
  469. #endif // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)
  470. ////////////////////////////////////////////////////
  471. // ST7565
  472. #if defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)
  473. static bool st7565_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  474. static uint32_t last_update = 0;
  475. bool current_st7565_state = st7565_is_on();
  476. return send_if_condition(PUT_ST7565, &last_update, (current_st7565_state != split_shmem->current_st7565_state), &current_st7565_state, sizeof(current_st7565_state));
  477. }
  478. static void st7565_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  479. split_shared_memory_lock();
  480. uint8_t current_st7565_state = split_shmem->current_st7565_state;
  481. split_shared_memory_unlock();
  482. if (current_st7565_state) {
  483. st7565_on();
  484. } else {
  485. st7565_off();
  486. }
  487. }
  488. # define TRANSACTIONS_ST7565_MASTER() TRANSACTION_HANDLER_MASTER(st7565)
  489. # define TRANSACTIONS_ST7565_SLAVE() TRANSACTION_HANDLER_SLAVE(st7565)
  490. # define TRANSACTIONS_ST7565_REGISTRATIONS [PUT_ST7565] = trans_initiator2target_initializer(current_st7565_state),
  491. #else // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)
  492. # define TRANSACTIONS_ST7565_MASTER()
  493. # define TRANSACTIONS_ST7565_SLAVE()
  494. # define TRANSACTIONS_ST7565_REGISTRATIONS
  495. #endif // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)
  496. ////////////////////////////////////////////////////
  497. // POINTING
  498. #if defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
  499. static bool pointing_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  500. # if defined(POINTING_DEVICE_LEFT)
  501. if (is_keyboard_left()) {
  502. return true;
  503. }
  504. # elif defined(POINTING_DEVICE_RIGHT)
  505. if (!is_keyboard_left()) {
  506. return true;
  507. }
  508. # endif
  509. static uint32_t last_update = 0;
  510. static uint16_t last_cpi = 0;
  511. report_mouse_t temp_state;
  512. uint16_t temp_cpi;
  513. bool okay = read_if_checksum_mismatch(GET_POINTING_CHECKSUM, GET_POINTING_DATA, &last_update, &temp_state, &split_shmem->pointing.report, sizeof(temp_state));
  514. if (okay) pointing_device_set_shared_report(temp_state);
  515. temp_cpi = pointing_device_get_shared_cpi();
  516. if (temp_cpi && last_cpi != temp_cpi) {
  517. split_shmem->pointing.cpi = temp_cpi;
  518. okay = transport_write(PUT_POINTING_CPI, &split_shmem->pointing.cpi, sizeof(split_shmem->pointing.cpi));
  519. if (okay) {
  520. last_cpi = temp_cpi;
  521. }
  522. }
  523. return okay;
  524. }
  525. extern const pointing_device_driver_t pointing_device_driver;
  526. static void pointing_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  527. # if defined(POINTING_DEVICE_LEFT)
  528. if (!is_keyboard_left()) {
  529. return;
  530. }
  531. # elif defined(POINTING_DEVICE_RIGHT)
  532. if (is_keyboard_left()) {
  533. return;
  534. }
  535. # endif
  536. # if (POINTING_DEVICE_TASK_THROTTLE_MS > 0)
  537. static uint32_t last_exec = 0;
  538. if (timer_elapsed32(last_exec) < POINTING_DEVICE_TASK_THROTTLE_MS) {
  539. return;
  540. }
  541. last_exec = timer_read32();
  542. # endif
  543. uint16_t temp_cpi = !pointing_device_driver.get_cpi ? 0 : pointing_device_driver.get_cpi(); // check for NULL
  544. split_shared_memory_lock();
  545. split_slave_pointing_sync_t pointing;
  546. memcpy(&pointing, &split_shmem->pointing, sizeof(split_slave_pointing_sync_t));
  547. split_shared_memory_unlock();
  548. if (pointing.cpi && pointing.cpi != temp_cpi && pointing_device_driver.set_cpi) {
  549. pointing_device_driver.set_cpi(pointing.cpi);
  550. }
  551. pointing.report = pointing_device_driver.get_report((report_mouse_t){0});
  552. // Now update the checksum given that the pointing has been written to
  553. pointing.checksum = crc8(&pointing.report, sizeof(report_mouse_t));
  554. split_shared_memory_lock();
  555. memcpy(&split_shmem->pointing, &pointing, sizeof(split_slave_pointing_sync_t));
  556. split_shared_memory_unlock();
  557. }
  558. # define TRANSACTIONS_POINTING_MASTER() TRANSACTION_HANDLER_MASTER(pointing)
  559. # define TRANSACTIONS_POINTING_SLAVE() TRANSACTION_HANDLER_SLAVE(pointing)
  560. # 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),
  561. #else // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
  562. # define TRANSACTIONS_POINTING_MASTER()
  563. # define TRANSACTIONS_POINTING_SLAVE()
  564. # define TRANSACTIONS_POINTING_REGISTRATIONS
  565. #endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
  566. ////////////////////////////////////////////////////
  567. // WATCHDOG
  568. #if defined(SPLIT_WATCHDOG_ENABLE)
  569. static bool watchdog_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  570. bool okay = true;
  571. if (!split_watchdog_check()) {
  572. okay = transport_write(PUT_WATCHDOG, &okay, sizeof(okay));
  573. split_watchdog_update(okay);
  574. }
  575. return okay;
  576. }
  577. static void watchdog_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  578. split_watchdog_update(split_shmem->watchdog_pinged);
  579. }
  580. # define TRANSACTIONS_WATCHDOG_MASTER() TRANSACTION_HANDLER_MASTER(watchdog)
  581. # define TRANSACTIONS_WATCHDOG_SLAVE() TRANSACTION_HANDLER_SLAVE_AUTOLOCK(watchdog)
  582. # define TRANSACTIONS_WATCHDOG_REGISTRATIONS [PUT_WATCHDOG] = trans_initiator2target_initializer(watchdog_pinged),
  583. #else // defined(SPLIT_WATCHDOG_ENABLE)
  584. # define TRANSACTIONS_WATCHDOG_MASTER()
  585. # define TRANSACTIONS_WATCHDOG_SLAVE()
  586. # define TRANSACTIONS_WATCHDOG_REGISTRATIONS
  587. #endif // defined(SPLIT_WATCHDOG_ENABLE)
  588. ////////////////////////////////////////////////////
  589. split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = {
  590. // Set defaults
  591. [0 ...(NUM_TOTAL_TRANSACTIONS - 1)] = {0, 0, 0, 0, 0},
  592. #ifdef USE_I2C
  593. [I2C_EXECUTE_CALLBACK] = trans_initiator2target_initializer(transaction_id),
  594. #endif // USE_I2C
  595. // clang-format off
  596. TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS
  597. TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS
  598. TRANSACTIONS_ENCODERS_REGISTRATIONS
  599. TRANSACTIONS_SYNC_TIMER_REGISTRATIONS
  600. TRANSACTIONS_LAYER_STATE_REGISTRATIONS
  601. TRANSACTIONS_LED_STATE_REGISTRATIONS
  602. TRANSACTIONS_MODS_REGISTRATIONS
  603. TRANSACTIONS_BACKLIGHT_REGISTRATIONS
  604. TRANSACTIONS_RGBLIGHT_REGISTRATIONS
  605. TRANSACTIONS_LED_MATRIX_REGISTRATIONS
  606. TRANSACTIONS_RGB_MATRIX_REGISTRATIONS
  607. TRANSACTIONS_WPM_REGISTRATIONS
  608. TRANSACTIONS_OLED_REGISTRATIONS
  609. TRANSACTIONS_ST7565_REGISTRATIONS
  610. TRANSACTIONS_POINTING_REGISTRATIONS
  611. TRANSACTIONS_WATCHDOG_REGISTRATIONS
  612. // clang-format on
  613. #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
  614. [PUT_RPC_INFO] = trans_initiator2target_initializer_cb(rpc_info, slave_rpc_info_callback),
  615. [PUT_RPC_REQ_DATA] = trans_initiator2target_initializer(rpc_m2s_buffer),
  616. [EXECUTE_RPC] = trans_initiator2target_initializer_cb(rpc_info.payload.transaction_id, slave_rpc_exec_callback),
  617. [GET_RPC_RESP_DATA] = trans_target2initiator_initializer(rpc_s2m_buffer),
  618. #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
  619. };
  620. bool transactions_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  621. TRANSACTIONS_SLAVE_MATRIX_MASTER();
  622. TRANSACTIONS_MASTER_MATRIX_MASTER();
  623. TRANSACTIONS_ENCODERS_MASTER();
  624. TRANSACTIONS_SYNC_TIMER_MASTER();
  625. TRANSACTIONS_LAYER_STATE_MASTER();
  626. TRANSACTIONS_LED_STATE_MASTER();
  627. TRANSACTIONS_MODS_MASTER();
  628. TRANSACTIONS_BACKLIGHT_MASTER();
  629. TRANSACTIONS_RGBLIGHT_MASTER();
  630. TRANSACTIONS_LED_MATRIX_MASTER();
  631. TRANSACTIONS_RGB_MATRIX_MASTER();
  632. TRANSACTIONS_WPM_MASTER();
  633. TRANSACTIONS_OLED_MASTER();
  634. TRANSACTIONS_ST7565_MASTER();
  635. TRANSACTIONS_POINTING_MASTER();
  636. TRANSACTIONS_WATCHDOG_MASTER();
  637. return true;
  638. }
  639. void transactions_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  640. TRANSACTIONS_SLAVE_MATRIX_SLAVE();
  641. TRANSACTIONS_MASTER_MATRIX_SLAVE();
  642. TRANSACTIONS_ENCODERS_SLAVE();
  643. TRANSACTIONS_SYNC_TIMER_SLAVE();
  644. TRANSACTIONS_LAYER_STATE_SLAVE();
  645. TRANSACTIONS_LED_STATE_SLAVE();
  646. TRANSACTIONS_MODS_SLAVE();
  647. TRANSACTIONS_BACKLIGHT_SLAVE();
  648. TRANSACTIONS_RGBLIGHT_SLAVE();
  649. TRANSACTIONS_LED_MATRIX_SLAVE();
  650. TRANSACTIONS_RGB_MATRIX_SLAVE();
  651. TRANSACTIONS_WPM_SLAVE();
  652. TRANSACTIONS_OLED_SLAVE();
  653. TRANSACTIONS_ST7565_SLAVE();
  654. TRANSACTIONS_POINTING_SLAVE();
  655. TRANSACTIONS_WATCHDOG_SLAVE();
  656. }
  657. #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
  658. void transaction_register_rpc(int8_t transaction_id, slave_callback_t callback) {
  659. // Prevent invoking RPC on QMK core sync data
  660. if (transaction_id <= GET_RPC_RESP_DATA) return;
  661. // Set the callback
  662. split_transaction_table[transaction_id].slave_callback = callback;
  663. split_transaction_table[transaction_id].initiator2target_offset = offsetof(split_shared_memory_t, rpc_m2s_buffer);
  664. split_transaction_table[transaction_id].target2initiator_offset = offsetof(split_shared_memory_t, rpc_s2m_buffer);
  665. }
  666. 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) {
  667. // Prevent transaction attempts while transport is disconnected
  668. if (!is_transport_connected()) {
  669. return false;
  670. }
  671. // Prevent invoking RPC on QMK core sync data
  672. if (transaction_id <= GET_RPC_RESP_DATA) return false;
  673. // Prevent sizing issues
  674. if (initiator2target_buffer_size > RPC_M2S_BUFFER_SIZE) return false;
  675. if (target2initiator_buffer_size > RPC_S2M_BUFFER_SIZE) return false;
  676. // Prepare the metadata block
  677. rpc_sync_info_t info = {.payload = {.transaction_id = transaction_id, .m2s_length = initiator2target_buffer_size, .s2m_length = target2initiator_buffer_size}};
  678. info.checksum = crc8(&info.payload, sizeof(info.payload));
  679. // Make sure the local side knows that we're not sending the full block of data
  680. split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = initiator2target_buffer_size;
  681. split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = target2initiator_buffer_size;
  682. // Run through the sequence:
  683. // * set the transaction ID and lengths
  684. // * send the request data
  685. // * execute RPC callback
  686. // * retrieve the response data
  687. if (!transport_write(PUT_RPC_INFO, &info, sizeof(info))) {
  688. return false;
  689. }
  690. if (!transport_write(PUT_RPC_REQ_DATA, initiator2target_buffer, initiator2target_buffer_size)) {
  691. return false;
  692. }
  693. if (!transport_write(EXECUTE_RPC, &transaction_id, sizeof(transaction_id))) {
  694. return false;
  695. }
  696. if (!transport_read(GET_RPC_RESP_DATA, target2initiator_buffer, target2initiator_buffer_size)) {
  697. return false;
  698. }
  699. return true;
  700. }
  701. void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
  702. // The RPC info block contains the intended transaction ID, as well as the sizes for both inbound and outbound data.
  703. // Ignore the args -- the `split_shmem` already has the info, we just need to act upon it.
  704. // We must keep the `split_transaction_table` non-const, so that it is able to be modified at runtime.
  705. split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = split_shmem->rpc_info.payload.m2s_length;
  706. split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = split_shmem->rpc_info.payload.s2m_length;
  707. }
  708. void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
  709. // We can assume that the buffer lengths are correctly set, now, given that sequentially the rpc_info callback was already executed.
  710. // Go through the rpc_info and execute _that_ transaction's callback, with the scratch buffers as inputs.
  711. // As a safety precaution we check that the received payload matches its checksum first.
  712. if (crc8(&split_shmem->rpc_info.payload, sizeof(split_shmem->rpc_info.payload)) != split_shmem->rpc_info.checksum) {
  713. return;
  714. }
  715. int8_t transaction_id = split_shmem->rpc_info.payload.transaction_id;
  716. if (transaction_id < NUM_TOTAL_TRANSACTIONS) {
  717. split_transaction_desc_t *trans = &split_transaction_table[transaction_id];
  718. if (trans->slave_callback) {
  719. 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);
  720. }
  721. }
  722. }
  723. #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)