transactions.c 34 KB

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