transactions.c 42 KB

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