transactions.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  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 "debug.h"
  19. #include "matrix.h"
  20. #include "quantum.h"
  21. #include "transactions.h"
  22. #include "transport.h"
  23. #include "transaction_id_define.h"
  24. #define SYNC_TIMER_OFFSET 2
  25. #ifndef FORCED_SYNC_THROTTLE_MS
  26. # define FORCED_SYNC_THROTTLE_MS 100
  27. #endif // FORCED_SYNC_THROTTLE_MS
  28. #define sizeof_member(type, member) sizeof(((type *)NULL)->member)
  29. #define trans_initiator2target_initializer_cb(member, cb) \
  30. { &dummy, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), 0, 0, cb }
  31. #define trans_initiator2target_initializer(member) trans_initiator2target_initializer_cb(member, NULL)
  32. #define trans_target2initiator_initializer_cb(member, cb) \
  33. { &dummy, 0, 0, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), cb }
  34. #define trans_target2initiator_initializer(member) trans_target2initiator_initializer_cb(member, NULL)
  35. #define transport_write(id, data, length) transport_execute_transaction(id, data, length, NULL, 0)
  36. #define transport_read(id, data, length) transport_execute_transaction(id, NULL, 0, data, length)
  37. static uint8_t crc8(const void *data, size_t len) {
  38. const uint8_t *p = (const uint8_t *)data;
  39. uint8_t crc = 0xff;
  40. size_t i, j;
  41. for (i = 0; i < len; i++) {
  42. crc ^= p[i];
  43. for (j = 0; j < 8; j++) {
  44. if ((crc & 0x80) != 0)
  45. crc = (uint8_t)((crc << 1) ^ 0x31);
  46. else
  47. crc <<= 1;
  48. }
  49. }
  50. return crc;
  51. }
  52. #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
  53. // Forward-declare the RPC callback handlers
  54. void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
  55. void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
  56. #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
  57. ////////////////////////////////////////////////////
  58. // Helpers
  59. 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[])) {
  60. if (okay) {
  61. bool this_okay = true;
  62. for (int iter = 1; iter <= 10; ++iter) {
  63. if (!this_okay) {
  64. for (int i = 0; i < iter * iter; ++i) {
  65. wait_us(10);
  66. }
  67. }
  68. ATOMIC_BLOCK_FORCEON { this_okay = handler(master_matrix, slave_matrix); };
  69. if (this_okay) break;
  70. }
  71. okay &= this_okay;
  72. if (!okay) {
  73. dprintf("Failed to execute %s\n", prefix);
  74. }
  75. }
  76. return okay;
  77. }
  78. #define TRANSACTION_HANDLER_MASTER(prefix) \
  79. do { \
  80. okay &= transaction_handler_master(okay, master_matrix, slave_matrix, #prefix, &prefix##_master); \
  81. } while (0)
  82. #define TRANSACTION_HANDLER_SLAVE(prefix) \
  83. do { \
  84. ATOMIC_BLOCK_FORCEON { prefix##_slave(master_matrix, slave_matrix); }; \
  85. } while (0)
  86. 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) {
  87. uint8_t curr_checksum;
  88. bool okay = transport_read(trans_id_checksum, &curr_checksum, sizeof(curr_checksum));
  89. if (okay && (timer_elapsed32(*last_update) >= FORCED_SYNC_THROTTLE_MS || curr_checksum != crc8(equiv_shmem, length))) {
  90. okay &= transport_read(trans_id_retrieve, destination, length);
  91. okay &= curr_checksum == crc8(equiv_shmem, length);
  92. if (okay) {
  93. *last_update = timer_read32();
  94. }
  95. } else {
  96. memcpy(destination, equiv_shmem, length);
  97. }
  98. return okay;
  99. }
  100. inline static bool send_if_condition(int8_t trans_id, uint32_t *last_update, bool condition, void *source, size_t length) {
  101. bool okay = true;
  102. if (timer_elapsed32(*last_update) >= FORCED_SYNC_THROTTLE_MS || condition) {
  103. okay &= transport_write(trans_id, source, length);
  104. if (okay) {
  105. *last_update = timer_read32();
  106. }
  107. }
  108. return okay;
  109. }
  110. inline static bool send_if_data_mismatch(int8_t trans_id, uint32_t *last_update, void *source, const void *equiv_shmem, size_t length) {
  111. // Just run a memcmp to compare the source and equivalent shmem location
  112. return send_if_condition(trans_id, last_update, (memcmp(source, equiv_shmem, length) != 0), source, length);
  113. }
  114. ////////////////////////////////////////////////////
  115. // Slave matrix
  116. static bool slave_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  117. static uint32_t last_update = 0;
  118. static matrix_row_t last_matrix[(MATRIX_ROWS) / 2] = {0}; // last successfully-read matrix, so we can replicate if there are checksum errors
  119. matrix_row_t temp_matrix[(MATRIX_ROWS) / 2]; // holding area while we test whether or not checksum is correct
  120. 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));
  121. if (okay) {
  122. // Checksum matches the received data, save as the last matrix state
  123. memcpy(last_matrix, temp_matrix, sizeof(temp_matrix));
  124. }
  125. // Copy out the last-known-good matrix state to the slave matrix
  126. memcpy(slave_matrix, last_matrix, sizeof(last_matrix));
  127. return okay;
  128. }
  129. static void slave_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  130. memcpy(split_shmem->smatrix.matrix, slave_matrix, sizeof(split_shmem->smatrix.matrix));
  131. split_shmem->smatrix.checksum = crc8(split_shmem->smatrix.matrix, sizeof(split_shmem->smatrix.matrix));
  132. }
  133. // clang-format off
  134. #define TRANSACTIONS_SLAVE_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(slave_matrix_handlers)
  135. #define TRANSACTIONS_SLAVE_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(slave_matrix_handlers)
  136. #define TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS \
  137. [GET_SLAVE_MATRIX_CHECKSUM] = trans_target2initiator_initializer(smatrix.checksum), \
  138. [GET_SLAVE_MATRIX_DATA] = trans_target2initiator_initializer(smatrix.matrix),
  139. // clang-format on
  140. ////////////////////////////////////////////////////
  141. // Master matrix
  142. #ifdef SPLIT_TRANSPORT_MIRROR
  143. static bool master_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  144. static uint32_t last_update = 0;
  145. return send_if_data_mismatch(PUT_MASTER_MATRIX, &last_update, master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix));
  146. }
  147. static void master_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  148. // Always copy to the master matrix
  149. memcpy(master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix));
  150. }
  151. # define TRANSACTIONS_MASTER_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(master_matrix_handlers)
  152. # define TRANSACTIONS_MASTER_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(master_matrix_handlers)
  153. # define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS [PUT_MASTER_MATRIX] = trans_initiator2target_initializer(mmatrix.matrix),
  154. #else // SPLIT_TRANSPORT_MIRROR
  155. # define TRANSACTIONS_MASTER_MATRIX_MASTER()
  156. # define TRANSACTIONS_MASTER_MATRIX_SLAVE()
  157. # define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS
  158. #endif // SPLIT_TRANSPORT_MIRROR
  159. ////////////////////////////////////////////////////
  160. // Encoders
  161. #ifdef ENCODER_ENABLE
  162. static bool encoder_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  163. static uint32_t last_update = 0;
  164. uint8_t temp_state[NUMBER_OF_ENCODERS];
  165. bool okay = read_if_checksum_mismatch(GET_ENCODERS_CHECKSUM, GET_ENCODERS_DATA, &last_update, temp_state, split_shmem->encoders.state, sizeof(temp_state));
  166. if (okay) encoder_update_raw(temp_state);
  167. return okay;
  168. }
  169. static void encoder_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  170. uint8_t encoder_state[NUMBER_OF_ENCODERS];
  171. encoder_state_raw(encoder_state);
  172. // Always prepare the encoder state for read.
  173. memcpy(split_shmem->encoders.state, encoder_state, sizeof(encoder_state));
  174. // Now update the checksum given that the encoders has been written to
  175. split_shmem->encoders.checksum = crc8(encoder_state, sizeof(encoder_state));
  176. }
  177. // clang-format off
  178. # define TRANSACTIONS_ENCODERS_MASTER() TRANSACTION_HANDLER_MASTER(encoder_handlers)
  179. # define TRANSACTIONS_ENCODERS_SLAVE() TRANSACTION_HANDLER_SLAVE(encoder_handlers)
  180. # define TRANSACTIONS_ENCODERS_REGISTRATIONS \
  181. [GET_ENCODERS_CHECKSUM] = trans_target2initiator_initializer(encoders.checksum), \
  182. [GET_ENCODERS_DATA] = trans_target2initiator_initializer(encoders.state),
  183. // clang-format on
  184. #else // ENCODER_ENABLE
  185. # define TRANSACTIONS_ENCODERS_MASTER()
  186. # define TRANSACTIONS_ENCODERS_SLAVE()
  187. # define TRANSACTIONS_ENCODERS_REGISTRATIONS
  188. #endif // ENCODER_ENABLE
  189. ////////////////////////////////////////////////////
  190. // Sync timer
  191. #ifndef DISABLE_SYNC_TIMER
  192. static bool sync_timer_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  193. static uint32_t last_update = 0;
  194. bool okay = true;
  195. if (timer_elapsed32(last_update) >= FORCED_SYNC_THROTTLE_MS) {
  196. uint32_t sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
  197. okay &= transport_write(PUT_SYNC_TIMER, &sync_timer, sizeof(sync_timer));
  198. if (okay) {
  199. last_update = timer_read32();
  200. }
  201. }
  202. return okay;
  203. }
  204. static void sync_timer_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  205. static uint32_t last_sync_timer = 0;
  206. if (last_sync_timer != split_shmem->sync_timer) {
  207. last_sync_timer = split_shmem->sync_timer;
  208. sync_timer_update(last_sync_timer);
  209. }
  210. }
  211. # define TRANSACTIONS_SYNC_TIMER_MASTER() TRANSACTION_HANDLER_MASTER(sync_timer_handlers)
  212. # define TRANSACTIONS_SYNC_TIMER_SLAVE() TRANSACTION_HANDLER_SLAVE(sync_timer_handlers)
  213. # define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS [PUT_SYNC_TIMER] = trans_initiator2target_initializer(sync_timer),
  214. #else // DISABLE_SYNC_TIMER
  215. # define TRANSACTIONS_SYNC_TIMER_MASTER()
  216. # define TRANSACTIONS_SYNC_TIMER_SLAVE()
  217. # define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS
  218. #endif // DISABLE_SYNC_TIMER
  219. ////////////////////////////////////////////////////
  220. // Layer state
  221. #if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
  222. static bool layer_state_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  223. static uint32_t last_layer_state_update = 0;
  224. static uint32_t last_default_layer_state_update = 0;
  225. bool okay = send_if_condition(PUT_LAYER_STATE, &last_layer_state_update, (layer_state != split_shmem->layers.layer_state), &layer_state, sizeof(layer_state));
  226. if (okay) {
  227. 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));
  228. }
  229. return okay;
  230. }
  231. static void layer_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  232. layer_state = split_shmem->layers.layer_state;
  233. default_layer_state = split_shmem->layers.default_layer_state;
  234. }
  235. // clang-format off
  236. # define TRANSACTIONS_LAYER_STATE_MASTER() TRANSACTION_HANDLER_MASTER(layer_state_handlers)
  237. # define TRANSACTIONS_LAYER_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE(layer_state_handlers)
  238. # define TRANSACTIONS_LAYER_STATE_REGISTRATIONS \
  239. [PUT_LAYER_STATE] = trans_initiator2target_initializer(layers.layer_state), \
  240. [PUT_DEFAULT_LAYER_STATE] = trans_initiator2target_initializer(layers.default_layer_state),
  241. // clang-format on
  242. #else // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
  243. # define TRANSACTIONS_LAYER_STATE_MASTER()
  244. # define TRANSACTIONS_LAYER_STATE_SLAVE()
  245. # define TRANSACTIONS_LAYER_STATE_REGISTRATIONS
  246. #endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
  247. ////////////////////////////////////////////////////
  248. // LED state
  249. #ifdef SPLIT_LED_STATE_ENABLE
  250. static bool led_state_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  251. static uint32_t last_update = 0;
  252. uint8_t led_state = host_keyboard_leds();
  253. return send_if_data_mismatch(PUT_LED_STATE, &last_update, &led_state, &split_shmem->led_state, sizeof(led_state));
  254. }
  255. static void led_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  256. void set_split_host_keyboard_leds(uint8_t led_state);
  257. set_split_host_keyboard_leds(split_shmem->led_state);
  258. }
  259. # define TRANSACTIONS_LED_STATE_MASTER() TRANSACTION_HANDLER_MASTER(led_state_handlers)
  260. # define TRANSACTIONS_LED_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE(led_state_handlers)
  261. # define TRANSACTIONS_LED_STATE_REGISTRATIONS [PUT_LED_STATE] = trans_initiator2target_initializer(led_state),
  262. #else // SPLIT_LED_STATE_ENABLE
  263. # define TRANSACTIONS_LED_STATE_MASTER()
  264. # define TRANSACTIONS_LED_STATE_SLAVE()
  265. # define TRANSACTIONS_LED_STATE_REGISTRATIONS
  266. #endif // SPLIT_LED_STATE_ENABLE
  267. ////////////////////////////////////////////////////
  268. // Mods
  269. #ifdef SPLIT_MODS_ENABLE
  270. static bool mods_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  271. static uint32_t last_update = 0;
  272. bool mods_need_sync = timer_elapsed32(last_update) >= FORCED_SYNC_THROTTLE_MS;
  273. split_mods_sync_t new_mods;
  274. new_mods.real_mods = get_mods();
  275. if (!mods_need_sync && new_mods.real_mods != split_shmem->mods.real_mods) {
  276. mods_need_sync = true;
  277. }
  278. new_mods.weak_mods = get_weak_mods();
  279. if (!mods_need_sync && new_mods.weak_mods != split_shmem->mods.weak_mods) {
  280. mods_need_sync = true;
  281. }
  282. # ifndef NO_ACTION_ONESHOT
  283. new_mods.oneshot_mods = get_oneshot_mods();
  284. if (!mods_need_sync && new_mods.oneshot_mods != split_shmem->mods.oneshot_mods) {
  285. mods_need_sync = true;
  286. }
  287. # endif // NO_ACTION_ONESHOT
  288. bool okay = true;
  289. if (mods_need_sync) {
  290. okay &= transport_write(PUT_MODS, &new_mods, sizeof(new_mods));
  291. if (okay) {
  292. last_update = timer_read32();
  293. }
  294. }
  295. return okay;
  296. }
  297. static void mods_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  298. set_mods(split_shmem->mods.real_mods);
  299. set_weak_mods(split_shmem->mods.weak_mods);
  300. # ifndef NO_ACTION_ONESHOT
  301. set_oneshot_mods(split_shmem->mods.oneshot_mods);
  302. # endif
  303. }
  304. # define TRANSACTIONS_MODS_MASTER() TRANSACTION_HANDLER_MASTER(mods_handlers)
  305. # define TRANSACTIONS_MODS_SLAVE() TRANSACTION_HANDLER_SLAVE(mods_handlers)
  306. # define TRANSACTIONS_MODS_REGISTRATIONS [PUT_MODS] = trans_initiator2target_initializer(mods),
  307. #else // SPLIT_MODS_ENABLE
  308. # define TRANSACTIONS_MODS_MASTER()
  309. # define TRANSACTIONS_MODS_SLAVE()
  310. # define TRANSACTIONS_MODS_REGISTRATIONS
  311. #endif // SPLIT_MODS_ENABLE
  312. ////////////////////////////////////////////////////
  313. // Backlight
  314. #ifdef BACKLIGHT_ENABLE
  315. static bool backlight_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  316. static uint32_t last_update = 0;
  317. uint8_t level = is_backlight_enabled() ? get_backlight_level() : 0;
  318. return send_if_condition(PUT_BACKLIGHT, &last_update, (level != split_shmem->backlight_level), &level, sizeof(level));
  319. }
  320. static void backlight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { backlight_set(split_shmem->backlight_level); }
  321. # define TRANSACTIONS_BACKLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(backlight_handlers)
  322. # define TRANSACTIONS_BACKLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(backlight_handlers)
  323. # define TRANSACTIONS_BACKLIGHT_REGISTRATIONS [PUT_BACKLIGHT] = trans_initiator2target_initializer(backlight_level),
  324. #else // BACKLIGHT_ENABLE
  325. # define TRANSACTIONS_BACKLIGHT_MASTER()
  326. # define TRANSACTIONS_BACKLIGHT_SLAVE()
  327. # define TRANSACTIONS_BACKLIGHT_REGISTRATIONS
  328. #endif // BACKLIGHT_ENABLE
  329. ////////////////////////////////////////////////////
  330. // RGBLIGHT
  331. #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
  332. static bool rgblight_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  333. static uint32_t last_update = 0;
  334. rgblight_syncinfo_t rgblight_sync;
  335. rgblight_get_syncinfo(&rgblight_sync);
  336. if (send_if_condition(PUT_RGBLIGHT, &last_update, (rgblight_sync.status.change_flags != 0), &rgblight_sync, sizeof(rgblight_sync))) {
  337. rgblight_clear_change_flags();
  338. } else {
  339. return false;
  340. }
  341. return true;
  342. }
  343. static void rgblight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  344. // Update the RGB with the new data
  345. if (split_shmem->rgblight_sync.status.change_flags != 0) {
  346. rgblight_update_sync(&split_shmem->rgblight_sync, false);
  347. split_shmem->rgblight_sync.status.change_flags = 0;
  348. }
  349. }
  350. # define TRANSACTIONS_RGBLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(rgblight_handlers)
  351. # define TRANSACTIONS_RGBLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(rgblight_handlers)
  352. # define TRANSACTIONS_RGBLIGHT_REGISTRATIONS [PUT_RGBLIGHT] = trans_initiator2target_initializer(rgblight_sync),
  353. #else // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
  354. # define TRANSACTIONS_RGBLIGHT_MASTER()
  355. # define TRANSACTIONS_RGBLIGHT_SLAVE()
  356. # define TRANSACTIONS_RGBLIGHT_REGISTRATIONS
  357. #endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
  358. ////////////////////////////////////////////////////
  359. // LED Matrix
  360. #if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
  361. static bool led_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  362. static uint32_t last_update = 0;
  363. led_matrix_sync_t led_matrix_sync;
  364. memcpy(&led_matrix_sync.led_matrix, &led_matrix_eeconfig, sizeof(led_eeconfig_t));
  365. led_matrix_sync.led_suspend_state = led_matrix_get_suspend_state();
  366. return send_if_data_mismatch(PUT_LED_MATRIX, &last_update, &led_matrix_sync, &split_shmem->led_matrix_sync, sizeof(led_matrix_sync));
  367. }
  368. static void led_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  369. memcpy(&led_matrix_eeconfig, &split_shmem->led_matrix_sync.led_matrix, sizeof(led_eeconfig_t));
  370. led_matrix_set_suspend_state(split_shmem->led_matrix_sync.led_suspend_state);
  371. }
  372. # define TRANSACTIONS_LED_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(led_matrix_handlers)
  373. # define TRANSACTIONS_LED_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(led_matrix_handlers)
  374. # define TRANSACTIONS_LED_MATRIX_REGISTRATIONS [PUT_LED_MATRIX] = trans_initiator2target_initializer(led_matrix_sync),
  375. #else // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
  376. # define TRANSACTIONS_LED_MATRIX_MASTER()
  377. # define TRANSACTIONS_LED_MATRIX_SLAVE()
  378. # define TRANSACTIONS_LED_MATRIX_REGISTRATIONS
  379. #endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
  380. ////////////////////////////////////////////////////
  381. // RGB Matrix
  382. #if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
  383. static bool rgb_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  384. static uint32_t last_update = 0;
  385. rgb_matrix_sync_t rgb_matrix_sync;
  386. memcpy(&rgb_matrix_sync.rgb_matrix, &rgb_matrix_config, sizeof(rgb_config_t));
  387. rgb_matrix_sync.rgb_suspend_state = rgb_matrix_get_suspend_state();
  388. return send_if_data_mismatch(PUT_RGB_MATRIX, &last_update, &rgb_matrix_sync, &split_shmem->rgb_matrix_sync, sizeof(rgb_matrix_sync));
  389. }
  390. static void rgb_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  391. memcpy(&rgb_matrix_config, &split_shmem->rgb_matrix_sync.rgb_matrix, sizeof(rgb_config_t));
  392. rgb_matrix_set_suspend_state(split_shmem->rgb_matrix_sync.rgb_suspend_state);
  393. }
  394. # define TRANSACTIONS_RGB_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(rgb_matrix_handlers)
  395. # define TRANSACTIONS_RGB_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(rgb_matrix_handlers)
  396. # define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS [PUT_RGB_MATRIX] = trans_initiator2target_initializer(rgb_matrix_sync),
  397. #else // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
  398. # define TRANSACTIONS_RGB_MATRIX_MASTER()
  399. # define TRANSACTIONS_RGB_MATRIX_SLAVE()
  400. # define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS
  401. #endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
  402. ////////////////////////////////////////////////////
  403. // WPM
  404. #if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
  405. static bool wpm_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  406. static uint32_t last_update = 0;
  407. uint8_t current_wpm = get_current_wpm();
  408. return send_if_condition(PUT_WPM, &last_update, (current_wpm != split_shmem->current_wpm), &current_wpm, sizeof(current_wpm));
  409. }
  410. static void wpm_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { set_current_wpm(split_shmem->current_wpm); }
  411. # define TRANSACTIONS_WPM_MASTER() TRANSACTION_HANDLER_MASTER(wpm_handlers)
  412. # define TRANSACTIONS_WPM_SLAVE() TRANSACTION_HANDLER_SLAVE(wpm_handlers)
  413. # define TRANSACTIONS_WPM_REGISTRATIONS [PUT_WPM] = trans_initiator2target_initializer(current_wpm),
  414. #else // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
  415. # define TRANSACTIONS_WPM_MASTER()
  416. # define TRANSACTIONS_WPM_SLAVE()
  417. # define TRANSACTIONS_WPM_REGISTRATIONS
  418. #endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
  419. ////////////////////////////////////////////////////
  420. uint8_t dummy;
  421. split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = {
  422. // Set defaults
  423. [0 ...(NUM_TOTAL_TRANSACTIONS - 1)] = {NULL, 0, 0, 0, 0, 0},
  424. #ifdef USE_I2C
  425. [I2C_EXECUTE_CALLBACK] = trans_initiator2target_initializer(transaction_id),
  426. #endif // USE_I2C
  427. // clang-format off
  428. TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS
  429. TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS
  430. TRANSACTIONS_ENCODERS_REGISTRATIONS
  431. TRANSACTIONS_SYNC_TIMER_REGISTRATIONS
  432. TRANSACTIONS_LAYER_STATE_REGISTRATIONS
  433. TRANSACTIONS_LED_STATE_REGISTRATIONS
  434. TRANSACTIONS_MODS_REGISTRATIONS
  435. TRANSACTIONS_BACKLIGHT_REGISTRATIONS
  436. TRANSACTIONS_RGBLIGHT_REGISTRATIONS
  437. TRANSACTIONS_LED_MATRIX_REGISTRATIONS
  438. TRANSACTIONS_RGB_MATRIX_REGISTRATIONS
  439. TRANSACTIONS_WPM_REGISTRATIONS
  440. // clang-format on
  441. #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
  442. [PUT_RPC_INFO] = trans_initiator2target_initializer_cb(rpc_info, slave_rpc_info_callback),
  443. [PUT_RPC_REQ_DATA] = trans_initiator2target_initializer(rpc_m2s_buffer),
  444. [EXECUTE_RPC] = trans_initiator2target_initializer_cb(rpc_info.transaction_id, slave_rpc_exec_callback),
  445. [GET_RPC_RESP_DATA] = trans_target2initiator_initializer(rpc_s2m_buffer),
  446. #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
  447. };
  448. bool transactions_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  449. bool okay = true;
  450. TRANSACTIONS_SLAVE_MATRIX_MASTER();
  451. TRANSACTIONS_MASTER_MATRIX_MASTER();
  452. TRANSACTIONS_ENCODERS_MASTER();
  453. TRANSACTIONS_SYNC_TIMER_MASTER();
  454. TRANSACTIONS_LAYER_STATE_MASTER();
  455. TRANSACTIONS_LED_STATE_MASTER();
  456. TRANSACTIONS_MODS_MASTER();
  457. TRANSACTIONS_BACKLIGHT_MASTER();
  458. TRANSACTIONS_RGBLIGHT_MASTER();
  459. TRANSACTIONS_LED_MATRIX_MASTER();
  460. TRANSACTIONS_RGB_MATRIX_MASTER();
  461. TRANSACTIONS_WPM_MASTER();
  462. return okay;
  463. }
  464. void transactions_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
  465. TRANSACTIONS_SLAVE_MATRIX_SLAVE();
  466. TRANSACTIONS_MASTER_MATRIX_SLAVE();
  467. TRANSACTIONS_ENCODERS_SLAVE();
  468. TRANSACTIONS_SYNC_TIMER_SLAVE();
  469. TRANSACTIONS_LAYER_STATE_SLAVE();
  470. TRANSACTIONS_LED_STATE_SLAVE();
  471. TRANSACTIONS_MODS_SLAVE();
  472. TRANSACTIONS_BACKLIGHT_SLAVE();
  473. TRANSACTIONS_RGBLIGHT_SLAVE();
  474. TRANSACTIONS_LED_MATRIX_SLAVE();
  475. TRANSACTIONS_RGB_MATRIX_SLAVE();
  476. TRANSACTIONS_WPM_SLAVE();
  477. }
  478. #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
  479. void transaction_register_rpc(int8_t transaction_id, slave_callback_t callback) {
  480. // Prevent invoking RPC on QMK core sync data
  481. if (transaction_id <= GET_RPC_RESP_DATA) return;
  482. // Set the callback
  483. split_transaction_table[transaction_id].slave_callback = callback;
  484. split_transaction_table[transaction_id].initiator2target_offset = offsetof(split_shared_memory_t, rpc_m2s_buffer);
  485. split_transaction_table[transaction_id].target2initiator_offset = offsetof(split_shared_memory_t, rpc_s2m_buffer);
  486. }
  487. 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) {
  488. // Prevent invoking RPC on QMK core sync data
  489. if (transaction_id <= GET_RPC_RESP_DATA) return false;
  490. // Prevent sizing issues
  491. if (initiator2target_buffer_size > RPC_M2S_BUFFER_SIZE) return false;
  492. if (target2initiator_buffer_size > RPC_S2M_BUFFER_SIZE) return false;
  493. // Prepare the metadata block
  494. rpc_sync_info_t info = {.transaction_id = transaction_id, .m2s_length = initiator2target_buffer_size, .s2m_length = target2initiator_buffer_size};
  495. // Make sure the local side knows that we're not sending the full block of data
  496. split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = initiator2target_buffer_size;
  497. split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = target2initiator_buffer_size;
  498. // Run through the sequence:
  499. // * set the transaction ID and lengths
  500. // * send the request data
  501. // * execute RPC callback
  502. // * retrieve the response data
  503. if (!transport_write(PUT_RPC_INFO, &info, sizeof(info))) {
  504. return false;
  505. }
  506. if (!transport_write(PUT_RPC_REQ_DATA, initiator2target_buffer, initiator2target_buffer_size)) {
  507. return false;
  508. }
  509. if (!transport_write(EXECUTE_RPC, &transaction_id, sizeof(transaction_id))) {
  510. return false;
  511. }
  512. if (!transport_read(GET_RPC_RESP_DATA, target2initiator_buffer, target2initiator_buffer_size)) {
  513. return false;
  514. }
  515. return true;
  516. }
  517. void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
  518. // The RPC info block contains the intended transaction ID, as well as the sizes for both inbound and outbound data.
  519. // Ignore the args -- the `split_shmem` already has the info, we just need to act upon it.
  520. // We must keep the `split_transaction_table` non-const, so that it is able to be modified at runtime.
  521. split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = split_shmem->rpc_info.m2s_length;
  522. split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = split_shmem->rpc_info.s2m_length;
  523. }
  524. void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
  525. // We can assume that the buffer lengths are correctly set, now, given that sequentially the rpc_info callback was already executed.
  526. // Go through the rpc_info and execute _that_ transaction's callback, with the scratch buffers as inputs.
  527. int8_t transaction_id = split_shmem->rpc_info.transaction_id;
  528. if (transaction_id < NUM_TOTAL_TRANSACTIONS) {
  529. split_transaction_desc_t *trans = &split_transaction_table[transaction_id];
  530. if (trans->slave_callback) {
  531. 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);
  532. }
  533. }
  534. }
  535. #endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)