aboutsummaryrefslogtreecommitdiff
path: root/quantum/split_common
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/split_common')
-rw-r--r--quantum/split_common/matrix.c6
-rw-r--r--quantum/split_common/post_config.h9
-rw-r--r--quantum/split_common/transaction_id_define.h94
-rw-r--r--quantum/split_common/transactions.c670
-rw-r--r--quantum/split_common/transactions.h54
-rw-r--r--quantum/split_common/transport.c484
-rw-r--r--quantum/split_common/transport.h165
7 files changed, 1062 insertions, 420 deletions
diff --git a/quantum/split_common/matrix.c b/quantum/split_common/matrix.c
index 2cf7b7058..56d91b07f 100644
--- a/quantum/split_common/matrix.c
+++ b/quantum/split_common/matrix.c
@@ -23,9 +23,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
23#include "quantum.h" 23#include "quantum.h"
24#include "split_util.h" 24#include "split_util.h"
25#include "config.h" 25#include "config.h"
26#include "transport.h" 26#include "transactions.h"
27 27
28#define ERROR_DISCONNECT_COUNT 5 28#ifndef ERROR_DISCONNECT_COUNT
29# define ERROR_DISCONNECT_COUNT 5
30#endif // ERROR_DISCONNECT_COUNT
29 31
30#define ROWS_PER_HAND (MATRIX_ROWS / 2) 32#define ROWS_PER_HAND (MATRIX_ROWS / 2)
31 33
diff --git a/quantum/split_common/post_config.h b/quantum/split_common/post_config.h
index 4ae1d5273..a4c0a1956 100644
--- a/quantum/split_common/post_config.h
+++ b/quantum/split_common/post_config.h
@@ -7,13 +7,4 @@
7# ifndef F_SCL 7# ifndef F_SCL
8# define F_SCL 100000UL // SCL frequency 8# define F_SCL 100000UL // SCL frequency
9# endif 9# endif
10
11#else // use serial
12// When using serial, the user must define RGBLIGHT_SPLIT explicitly
13// in config.h as needed.
14// see quantum/rgblight_post_config.h
15# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
16// When using serial and RGBLIGHT_SPLIT need separate transaction
17# define SERIAL_USE_MULTI_TRANSACTION
18# endif
19#endif 10#endif
diff --git a/quantum/split_common/transaction_id_define.h b/quantum/split_common/transaction_id_define.h
new file mode 100644
index 000000000..464c73478
--- /dev/null
+++ b/quantum/split_common/transaction_id_define.h
@@ -0,0 +1,94 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19enum serial_transaction_id {
20#ifdef USE_I2C
21 I2C_EXECUTE_CALLBACK,
22#endif // USE_I2C
23
24 GET_SLAVE_MATRIX_CHECKSUM,
25 GET_SLAVE_MATRIX_DATA,
26
27#ifdef SPLIT_TRANSPORT_MIRROR
28 PUT_MASTER_MATRIX,
29#endif // SPLIT_TRANSPORT_MIRROR
30
31#ifdef ENCODER_ENABLE
32 GET_ENCODERS_CHECKSUM,
33 GET_ENCODERS_DATA,
34#endif // ENCODER_ENABLE
35
36#ifndef DISABLE_SYNC_TIMER
37 PUT_SYNC_TIMER,
38#endif // DISABLE_SYNC_TIMER
39
40#if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
41 PUT_LAYER_STATE,
42 PUT_DEFAULT_LAYER_STATE,
43#endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
44
45#ifdef SPLIT_LED_STATE_ENABLE
46 PUT_LED_STATE,
47#endif // SPLIT_LED_STATE_ENABLE
48
49#ifdef SPLIT_MODS_ENABLE
50 PUT_MODS,
51#endif // SPLIT_MODS_ENABLE
52
53#ifdef BACKLIGHT_ENABLE
54 PUT_BACKLIGHT,
55#endif // BACKLIGHT_ENABLE
56
57#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
58 PUT_RGBLIGHT,
59#endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
60
61#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
62 PUT_LED_MATRIX,
63#endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
64
65#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
66 PUT_RGB_MATRIX,
67#endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
68
69#if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
70 PUT_WPM,
71#endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
72
73#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
74 PUT_RPC_INFO,
75 PUT_RPC_REQ_DATA,
76 EXECUTE_RPC,
77 GET_RPC_RESP_DATA,
78#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
79
80// keyboard-specific
81#ifdef SPLIT_TRANSACTION_IDS_KB
82 SPLIT_TRANSACTION_IDS_KB,
83#endif // SPLIT_TRANSACTION_IDS_KB
84
85// user/keymap-specific
86#ifdef SPLIT_TRANSACTION_IDS_USER
87 SPLIT_TRANSACTION_IDS_USER,
88#endif // SPLIT_TRANSACTION_IDS_USER
89
90 NUM_TOTAL_TRANSACTIONS
91};
92
93// Ensure we only use 5 bits for transaction
94_Static_assert(NUM_TOTAL_TRANSACTIONS <= (1 << 5), "Max number of usable transactions exceeded");
diff --git a/quantum/split_common/transactions.c b/quantum/split_common/transactions.c
new file mode 100644
index 000000000..99a8623b3
--- /dev/null
+++ b/quantum/split_common/transactions.c
@@ -0,0 +1,670 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <string.h>
18#include <stddef.h>
19
20#include "debug.h"
21#include "matrix.h"
22#include "quantum.h"
23#include "transactions.h"
24#include "transport.h"
25#include "transaction_id_define.h"
26
27#define SYNC_TIMER_OFFSET 2
28
29#ifndef FORCED_SYNC_THROTTLE_MS
30# define FORCED_SYNC_THROTTLE_MS 100
31#endif // FORCED_SYNC_THROTTLE_MS
32
33#define sizeof_member(type, member) sizeof(((type *)NULL)->member)
34
35#define trans_initiator2target_initializer_cb(member, cb) \
36 { &dummy, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), 0, 0, cb }
37#define trans_initiator2target_initializer(member) trans_initiator2target_initializer_cb(member, NULL)
38
39#define trans_target2initiator_initializer_cb(member, cb) \
40 { &dummy, 0, 0, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), cb }
41#define trans_target2initiator_initializer(member) trans_target2initiator_initializer_cb(member, NULL)
42
43#define transport_write(id, data, length) transport_execute_transaction(id, data, length, NULL, 0)
44#define transport_read(id, data, length) transport_execute_transaction(id, NULL, 0, data, length)
45
46static uint8_t crc8(const void *data, size_t len) {
47 const uint8_t *p = (const uint8_t *)data;
48 uint8_t crc = 0xff;
49 size_t i, j;
50 for (i = 0; i < len; i++) {
51 crc ^= p[i];
52 for (j = 0; j < 8; j++) {
53 if ((crc & 0x80) != 0)
54 crc = (uint8_t)((crc << 1) ^ 0x31);
55 else
56 crc <<= 1;
57 }
58 }
59 return crc;
60}
61
62#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
63// Forward-declare the RPC callback handlers
64void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
65void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
66#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
67
68////////////////////////////////////////////////////
69// Helpers
70
71bool 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[])) {
72 if (okay) {
73 bool this_okay = true;
74 for (int iter = 1; iter <= 10; ++iter) {
75 if (!this_okay) {
76 for (int i = 0; i < iter * iter; ++i) {
77 wait_us(10);
78 }
79 }
80 ATOMIC_BLOCK_FORCEON { this_okay = handler(master_matrix, slave_matrix); };
81 if (this_okay) break;
82 }
83 okay &= this_okay;
84 if (!okay) {
85 dprintf("Failed to execute %s\n", prefix);
86 }
87 }
88 return okay;
89}
90
91#define TRANSACTION_HANDLER_MASTER(prefix) \
92 do { \
93 okay &= transaction_handler_master(okay, master_matrix, slave_matrix, #prefix, &prefix##_master); \
94 } while (0)
95
96#define TRANSACTION_HANDLER_SLAVE(prefix) \
97 do { \
98 ATOMIC_BLOCK_FORCEON { prefix##_slave(master_matrix, slave_matrix); }; \
99 } while (0)
100
101inline 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) {
102 uint8_t curr_checksum;
103 bool okay = transport_read(trans_id_checksum, &curr_checksum, sizeof(curr_checksum));
104 if (okay && (timer_elapsed32(*last_update) >= FORCED_SYNC_THROTTLE_MS || curr_checksum != crc8(equiv_shmem, length))) {
105 okay &= transport_read(trans_id_retrieve, destination, length);
106 okay &= curr_checksum == crc8(equiv_shmem, length);
107 if (okay) {
108 *last_update = timer_read32();
109 }
110 } else {
111 memcpy(destination, equiv_shmem, length);
112 }
113 return okay;
114}
115
116inline static bool send_if_condition(int8_t trans_id, uint32_t *last_update, bool condition, void *source, size_t length) {
117 bool okay = true;
118 if (timer_elapsed32(*last_update) >= FORCED_SYNC_THROTTLE_MS || condition) {
119 okay &= transport_write(trans_id, source, length);
120 if (okay) {
121 *last_update = timer_read32();
122 }
123 }
124 return okay;
125}
126
127inline static bool send_if_data_mismatch(int8_t trans_id, uint32_t *last_update, void *source, const void *equiv_shmem, size_t length) {
128 // Just run a memcmp to compare the source and equivalent shmem location
129 return send_if_condition(trans_id, last_update, (memcmp(source, equiv_shmem, length) != 0), source, length);
130}
131
132////////////////////////////////////////////////////
133// Slave matrix
134
135static bool slave_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
136 static uint32_t last_update = 0;
137 static matrix_row_t last_matrix[(MATRIX_ROWS) / 2] = {0}; // last successfully-read matrix, so we can replicate if there are checksum errors
138 matrix_row_t temp_matrix[(MATRIX_ROWS) / 2]; // holding area while we test whether or not checksum is correct
139
140 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));
141 if (okay) {
142 // Checksum matches the received data, save as the last matrix state
143 memcpy(last_matrix, temp_matrix, sizeof(temp_matrix));
144 }
145 // Copy out the last-known-good matrix state to the slave matrix
146 memcpy(slave_matrix, last_matrix, sizeof(last_matrix));
147 return okay;
148}
149
150static void slave_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
151 memcpy(split_shmem->smatrix.matrix, slave_matrix, sizeof(split_shmem->smatrix.matrix));
152 split_shmem->smatrix.checksum = crc8(split_shmem->smatrix.matrix, sizeof(split_shmem->smatrix.matrix));
153}
154
155// clang-format off
156#define TRANSACTIONS_SLAVE_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(slave_matrix_handlers)
157#define TRANSACTIONS_SLAVE_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(slave_matrix_handlers)
158#define TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS \
159 [GET_SLAVE_MATRIX_CHECKSUM] = trans_target2initiator_initializer(smatrix.checksum), \
160 [GET_SLAVE_MATRIX_DATA] = trans_target2initiator_initializer(smatrix.matrix),
161// clang-format on
162
163////////////////////////////////////////////////////
164// Master matrix
165
166#ifdef SPLIT_TRANSPORT_MIRROR
167
168static bool master_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
169 static uint32_t last_update = 0;
170 return send_if_data_mismatch(PUT_MASTER_MATRIX, &last_update, master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix));
171}
172
173static void master_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
174 // Always copy to the master matrix
175 memcpy(master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix));
176}
177
178# define TRANSACTIONS_MASTER_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(master_matrix_handlers)
179# define TRANSACTIONS_MASTER_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(master_matrix_handlers)
180# define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS [PUT_MASTER_MATRIX] = trans_initiator2target_initializer(mmatrix.matrix),
181
182#else // SPLIT_TRANSPORT_MIRROR
183
184# define TRANSACTIONS_MASTER_MATRIX_MASTER()
185# define TRANSACTIONS_MASTER_MATRIX_SLAVE()
186# define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS
187
188#endif // SPLIT_TRANSPORT_MIRROR
189
190////////////////////////////////////////////////////
191// Encoders
192
193#ifdef ENCODER_ENABLE
194
195static bool encoder_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
196 static uint32_t last_update = 0;
197 uint8_t temp_state[NUMBER_OF_ENCODERS];
198
199 bool okay = read_if_checksum_mismatch(GET_ENCODERS_CHECKSUM, GET_ENCODERS_DATA, &last_update, temp_state, split_shmem->encoders.state, sizeof(temp_state));
200 if (okay) encoder_update_raw(temp_state);
201 return okay;
202}
203
204static void encoder_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
205 uint8_t encoder_state[NUMBER_OF_ENCODERS];
206 encoder_state_raw(encoder_state);
207 // Always prepare the encoder state for read.
208 memcpy(split_shmem->encoders.state, encoder_state, sizeof(encoder_state));
209 // Now update the checksum given that the encoders has been written to
210 split_shmem->encoders.checksum = crc8(encoder_state, sizeof(encoder_state));
211}
212
213// clang-format off
214# define TRANSACTIONS_ENCODERS_MASTER() TRANSACTION_HANDLER_MASTER(encoder_handlers)
215# define TRANSACTIONS_ENCODERS_SLAVE() TRANSACTION_HANDLER_SLAVE(encoder_handlers)
216# define TRANSACTIONS_ENCODERS_REGISTRATIONS \
217 [GET_ENCODERS_CHECKSUM] = trans_target2initiator_initializer(encoders.checksum), \
218 [GET_ENCODERS_DATA] = trans_target2initiator_initializer(encoders.state),
219// clang-format on
220
221#else // ENCODER_ENABLE
222
223# define TRANSACTIONS_ENCODERS_MASTER()
224# define TRANSACTIONS_ENCODERS_SLAVE()
225# define TRANSACTIONS_ENCODERS_REGISTRATIONS
226
227#endif // ENCODER_ENABLE
228
229////////////////////////////////////////////////////
230// Sync timer
231
232#ifndef DISABLE_SYNC_TIMER
233
234static bool sync_timer_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
235 static uint32_t last_update = 0;
236
237 bool okay = true;
238 if (timer_elapsed32(last_update) >= FORCED_SYNC_THROTTLE_MS) {
239 uint32_t sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
240 okay &= transport_write(PUT_SYNC_TIMER, &sync_timer, sizeof(sync_timer));
241 if (okay) {
242 last_update = timer_read32();
243 }
244 }
245 return okay;
246}
247
248static void sync_timer_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
249 static uint32_t last_sync_timer = 0;
250 if (last_sync_timer != split_shmem->sync_timer) {
251 last_sync_timer = split_shmem->sync_timer;
252 sync_timer_update(last_sync_timer);
253 }
254}
255
256# define TRANSACTIONS_SYNC_TIMER_MASTER() TRANSACTION_HANDLER_MASTER(sync_timer_handlers)
257# define TRANSACTIONS_SYNC_TIMER_SLAVE() TRANSACTION_HANDLER_SLAVE(sync_timer_handlers)
258# define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS [PUT_SYNC_TIMER] = trans_initiator2target_initializer(sync_timer),
259
260#else // DISABLE_SYNC_TIMER
261
262# define TRANSACTIONS_SYNC_TIMER_MASTER()
263# define TRANSACTIONS_SYNC_TIMER_SLAVE()
264# define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS
265
266#endif // DISABLE_SYNC_TIMER
267
268////////////////////////////////////////////////////
269// Layer state
270
271#if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
272
273static bool layer_state_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
274 static uint32_t last_layer_state_update = 0;
275 static uint32_t last_default_layer_state_update = 0;
276
277 bool okay = send_if_condition(PUT_LAYER_STATE, &last_layer_state_update, (layer_state != split_shmem->layers.layer_state), &layer_state, sizeof(layer_state));
278 if (okay) {
279 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));
280 }
281 return okay;
282}
283
284static void layer_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
285 layer_state = split_shmem->layers.layer_state;
286 default_layer_state = split_shmem->layers.default_layer_state;
287}
288
289// clang-format off
290# define TRANSACTIONS_LAYER_STATE_MASTER() TRANSACTION_HANDLER_MASTER(layer_state_handlers)
291# define TRANSACTIONS_LAYER_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE(layer_state_handlers)
292# define TRANSACTIONS_LAYER_STATE_REGISTRATIONS \
293 [PUT_LAYER_STATE] = trans_initiator2target_initializer(layers.layer_state), \
294 [PUT_DEFAULT_LAYER_STATE] = trans_initiator2target_initializer(layers.default_layer_state),
295// clang-format on
296
297#else // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
298
299# define TRANSACTIONS_LAYER_STATE_MASTER()
300# define TRANSACTIONS_LAYER_STATE_SLAVE()
301# define TRANSACTIONS_LAYER_STATE_REGISTRATIONS
302
303#endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
304
305////////////////////////////////////////////////////
306// LED state
307
308#ifdef SPLIT_LED_STATE_ENABLE
309
310static bool led_state_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
311 static uint32_t last_update = 0;
312 uint8_t led_state = host_keyboard_leds();
313 return send_if_data_mismatch(PUT_LED_STATE, &last_update, &led_state, &split_shmem->led_state, sizeof(led_state));
314}
315
316static void led_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
317 void set_split_host_keyboard_leds(uint8_t led_state);
318 set_split_host_keyboard_leds(split_shmem->led_state);
319}
320
321# define TRANSACTIONS_LED_STATE_MASTER() TRANSACTION_HANDLER_MASTER(led_state_handlers)
322# define TRANSACTIONS_LED_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE(led_state_handlers)
323# define TRANSACTIONS_LED_STATE_REGISTRATIONS [PUT_LED_STATE] = trans_initiator2target_initializer(led_state),
324
325#else // SPLIT_LED_STATE_ENABLE
326
327# define TRANSACTIONS_LED_STATE_MASTER()
328# define TRANSACTIONS_LED_STATE_SLAVE()
329# define TRANSACTIONS_LED_STATE_REGISTRATIONS
330
331#endif // SPLIT_LED_STATE_ENABLE
332
333////////////////////////////////////////////////////
334// Mods
335
336#ifdef SPLIT_MODS_ENABLE
337
338static bool mods_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
339 static uint32_t last_update = 0;
340 bool mods_need_sync = timer_elapsed32(last_update) >= FORCED_SYNC_THROTTLE_MS;
341 split_mods_sync_t new_mods;
342 new_mods.real_mods = get_mods();
343 if (!mods_need_sync && new_mods.real_mods != split_shmem->mods.real_mods) {
344 mods_need_sync = true;
345 }
346
347 new_mods.weak_mods = get_weak_mods();
348 if (!mods_need_sync && new_mods.weak_mods != split_shmem->mods.weak_mods) {
349 mods_need_sync = true;
350 }
351
352# ifndef NO_ACTION_ONESHOT
353 new_mods.oneshot_mods = get_oneshot_mods();
354 if (!mods_need_sync && new_mods.oneshot_mods != split_shmem->mods.oneshot_mods) {
355 mods_need_sync = true;
356 }
357# endif // NO_ACTION_ONESHOT
358
359 bool okay = true;
360 if (mods_need_sync) {
361 okay &= transport_write(PUT_MODS, &new_mods, sizeof(new_mods));
362 if (okay) {
363 last_update = timer_read32();
364 }
365 }
366
367 return okay;
368}
369
370static void mods_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
371 set_mods(split_shmem->mods.real_mods);
372 set_weak_mods(split_shmem->mods.weak_mods);
373# ifndef NO_ACTION_ONESHOT
374 set_oneshot_mods(split_shmem->mods.oneshot_mods);
375# endif
376}
377
378# define TRANSACTIONS_MODS_MASTER() TRANSACTION_HANDLER_MASTER(mods_handlers)
379# define TRANSACTIONS_MODS_SLAVE() TRANSACTION_HANDLER_SLAVE(mods_handlers)
380# define TRANSACTIONS_MODS_REGISTRATIONS [PUT_MODS] = trans_initiator2target_initializer(mods),
381
382#else // SPLIT_MODS_ENABLE
383
384# define TRANSACTIONS_MODS_MASTER()
385# define TRANSACTIONS_MODS_SLAVE()
386# define TRANSACTIONS_MODS_REGISTRATIONS
387
388#endif // SPLIT_MODS_ENABLE
389
390////////////////////////////////////////////////////
391// Backlight
392
393#ifdef BACKLIGHT_ENABLE
394
395static bool backlight_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
396 static uint32_t last_update = 0;
397 uint8_t level = is_backlight_enabled() ? get_backlight_level() : 0;
398 return send_if_condition(PUT_BACKLIGHT, &last_update, (level != split_shmem->backlight_level), &level, sizeof(level));
399}
400
401static void backlight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { backlight_set(split_shmem->backlight_level); }
402
403# define TRANSACTIONS_BACKLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(backlight_handlers)
404# define TRANSACTIONS_BACKLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(backlight_handlers)
405# define TRANSACTIONS_BACKLIGHT_REGISTRATIONS [PUT_BACKLIGHT] = trans_initiator2target_initializer(backlight_level),
406
407#else // BACKLIGHT_ENABLE
408
409# define TRANSACTIONS_BACKLIGHT_MASTER()
410# define TRANSACTIONS_BACKLIGHT_SLAVE()
411# define TRANSACTIONS_BACKLIGHT_REGISTRATIONS
412
413#endif // BACKLIGHT_ENABLE
414
415////////////////////////////////////////////////////
416// RGBLIGHT
417
418#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
419
420static bool rgblight_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
421 static uint32_t last_update = 0;
422 rgblight_syncinfo_t rgblight_sync;
423 rgblight_get_syncinfo(&rgblight_sync);
424 if (send_if_condition(PUT_RGBLIGHT, &last_update, (rgblight_sync.status.change_flags != 0), &rgblight_sync, sizeof(rgblight_sync))) {
425 rgblight_clear_change_flags();
426 } else {
427 return false;
428 }
429 return true;
430}
431
432static void rgblight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
433 // Update the RGB with the new data
434 if (split_shmem->rgblight_sync.status.change_flags != 0) {
435 rgblight_update_sync(&split_shmem->rgblight_sync, false);
436 split_shmem->rgblight_sync.status.change_flags = 0;
437 }
438}
439
440# define TRANSACTIONS_RGBLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(rgblight_handlers)
441# define TRANSACTIONS_RGBLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(rgblight_handlers)
442# define TRANSACTIONS_RGBLIGHT_REGISTRATIONS [PUT_RGBLIGHT] = trans_initiator2target_initializer(rgblight_sync),
443
444#else // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
445
446# define TRANSACTIONS_RGBLIGHT_MASTER()
447# define TRANSACTIONS_RGBLIGHT_SLAVE()
448# define TRANSACTIONS_RGBLIGHT_REGISTRATIONS
449
450#endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
451
452////////////////////////////////////////////////////
453// LED Matrix
454
455#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
456
457static bool led_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
458 static uint32_t last_update = 0;
459 led_matrix_sync_t led_matrix_sync;
460 memcpy(&led_matrix_sync.led_matrix, &led_matrix_eeconfig, sizeof(led_eeconfig_t));
461 led_matrix_sync.led_suspend_state = led_matrix_get_suspend_state();
462 return send_if_data_mismatch(PUT_LED_MATRIX, &last_update, &led_matrix_sync, &split_shmem->led_matrix_sync, sizeof(led_matrix_sync));
463}
464
465static void led_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
466 memcpy(&led_matrix_eeconfig, &split_shmem->led_matrix_sync.led_matrix, sizeof(led_eeconfig_t));
467 led_matrix_set_suspend_state(split_shmem->led_matrix_sync.led_suspend_state);
468}
469
470# define TRANSACTIONS_LED_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(led_matrix_handlers)
471# define TRANSACTIONS_LED_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(led_matrix_handlers)
472# define TRANSACTIONS_LED_MATRIX_REGISTRATIONS [PUT_LED_MATRIX] = trans_initiator2target_initializer(led_matrix_sync),
473
474#else // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
475
476# define TRANSACTIONS_LED_MATRIX_MASTER()
477# define TRANSACTIONS_LED_MATRIX_SLAVE()
478# define TRANSACTIONS_LED_MATRIX_REGISTRATIONS
479
480#endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
481
482////////////////////////////////////////////////////
483// RGB Matrix
484
485#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
486
487static bool rgb_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
488 static uint32_t last_update = 0;
489 rgb_matrix_sync_t rgb_matrix_sync;
490 memcpy(&rgb_matrix_sync.rgb_matrix, &rgb_matrix_config, sizeof(rgb_config_t));
491 rgb_matrix_sync.rgb_suspend_state = rgb_matrix_get_suspend_state();
492 return send_if_data_mismatch(PUT_RGB_MATRIX, &last_update, &rgb_matrix_sync, &split_shmem->rgb_matrix_sync, sizeof(rgb_matrix_sync));
493}
494
495static void rgb_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
496 memcpy(&rgb_matrix_config, &split_shmem->rgb_matrix_sync.rgb_matrix, sizeof(rgb_config_t));
497 rgb_matrix_set_suspend_state(split_shmem->rgb_matrix_sync.rgb_suspend_state);
498}
499
500# define TRANSACTIONS_RGB_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(rgb_matrix_handlers)
501# define TRANSACTIONS_RGB_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(rgb_matrix_handlers)
502# define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS [PUT_RGB_MATRIX] = trans_initiator2target_initializer(rgb_matrix_sync),
503
504#else // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
505
506# define TRANSACTIONS_RGB_MATRIX_MASTER()
507# define TRANSACTIONS_RGB_MATRIX_SLAVE()
508# define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS
509
510#endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
511
512////////////////////////////////////////////////////
513// WPM
514
515#if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
516
517static bool wpm_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
518 static uint32_t last_update = 0;
519 uint8_t current_wpm = get_current_wpm();
520 return send_if_condition(PUT_WPM, &last_update, (current_wpm != split_shmem->current_wpm), &current_wpm, sizeof(current_wpm));
521}
522
523static void wpm_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { set_current_wpm(split_shmem->current_wpm); }
524
525# define TRANSACTIONS_WPM_MASTER() TRANSACTION_HANDLER_MASTER(wpm_handlers)
526# define TRANSACTIONS_WPM_SLAVE() TRANSACTION_HANDLER_SLAVE(wpm_handlers)
527# define TRANSACTIONS_WPM_REGISTRATIONS [PUT_WPM] = trans_initiator2target_initializer(current_wpm),
528
529#else // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
530
531# define TRANSACTIONS_WPM_MASTER()
532# define TRANSACTIONS_WPM_SLAVE()
533# define TRANSACTIONS_WPM_REGISTRATIONS
534
535#endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
536
537////////////////////////////////////////////////////
538
539uint8_t dummy;
540split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = {
541 // Set defaults
542 [0 ...(NUM_TOTAL_TRANSACTIONS - 1)] = {NULL, 0, 0, 0, 0, 0},
543
544#ifdef USE_I2C
545 [I2C_EXECUTE_CALLBACK] = trans_initiator2target_initializer(transaction_id),
546#endif // USE_I2C
547
548 // clang-format off
549 TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS
550 TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS
551 TRANSACTIONS_ENCODERS_REGISTRATIONS
552 TRANSACTIONS_SYNC_TIMER_REGISTRATIONS
553 TRANSACTIONS_LAYER_STATE_REGISTRATIONS
554 TRANSACTIONS_LED_STATE_REGISTRATIONS
555 TRANSACTIONS_MODS_REGISTRATIONS
556 TRANSACTIONS_BACKLIGHT_REGISTRATIONS
557 TRANSACTIONS_RGBLIGHT_REGISTRATIONS
558 TRANSACTIONS_LED_MATRIX_REGISTRATIONS
559 TRANSACTIONS_RGB_MATRIX_REGISTRATIONS
560 TRANSACTIONS_WPM_REGISTRATIONS
561// clang-format on
562
563#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
564 [PUT_RPC_INFO] = trans_initiator2target_initializer_cb(rpc_info, slave_rpc_info_callback),
565 [PUT_RPC_REQ_DATA] = trans_initiator2target_initializer(rpc_m2s_buffer),
566 [EXECUTE_RPC] = trans_initiator2target_initializer_cb(rpc_info.transaction_id, slave_rpc_exec_callback),
567 [GET_RPC_RESP_DATA] = trans_target2initiator_initializer(rpc_s2m_buffer),
568#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
569};
570
571bool transactions_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
572 bool okay = true;
573 TRANSACTIONS_SLAVE_MATRIX_MASTER();
574 TRANSACTIONS_MASTER_MATRIX_MASTER();
575 TRANSACTIONS_ENCODERS_MASTER();
576 TRANSACTIONS_SYNC_TIMER_MASTER();
577 TRANSACTIONS_LAYER_STATE_MASTER();
578 TRANSACTIONS_LED_STATE_MASTER();
579 TRANSACTIONS_MODS_MASTER();
580 TRANSACTIONS_BACKLIGHT_MASTER();
581 TRANSACTIONS_RGBLIGHT_MASTER();
582 TRANSACTIONS_LED_MATRIX_MASTER();
583 TRANSACTIONS_RGB_MATRIX_MASTER();
584 TRANSACTIONS_WPM_MASTER();
585 return okay;
586}
587
588void transactions_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
589 TRANSACTIONS_SLAVE_MATRIX_SLAVE();
590 TRANSACTIONS_MASTER_MATRIX_SLAVE();
591 TRANSACTIONS_ENCODERS_SLAVE();
592 TRANSACTIONS_SYNC_TIMER_SLAVE();
593 TRANSACTIONS_LAYER_STATE_SLAVE();
594 TRANSACTIONS_LED_STATE_SLAVE();
595 TRANSACTIONS_MODS_SLAVE();
596 TRANSACTIONS_BACKLIGHT_SLAVE();
597 TRANSACTIONS_RGBLIGHT_SLAVE();
598 TRANSACTIONS_LED_MATRIX_SLAVE();
599 TRANSACTIONS_RGB_MATRIX_SLAVE();
600 TRANSACTIONS_WPM_SLAVE();
601}
602
603#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
604
605void transaction_register_rpc(int8_t transaction_id, slave_callback_t callback) {
606 // Prevent invoking RPC on QMK core sync data
607 if (transaction_id <= GET_RPC_RESP_DATA) return;
608
609 // Set the callback
610 split_transaction_table[transaction_id].slave_callback = callback;
611 split_transaction_table[transaction_id].initiator2target_offset = offsetof(split_shared_memory_t, rpc_m2s_buffer);
612 split_transaction_table[transaction_id].target2initiator_offset = offsetof(split_shared_memory_t, rpc_s2m_buffer);
613}
614
615bool transaction_rpc_exec(int8_t transaction_id, uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
616 // Prevent invoking RPC on QMK core sync data
617 if (transaction_id <= GET_RPC_RESP_DATA) return false;
618 // Prevent sizing issues
619 if (initiator2target_buffer_size > RPC_M2S_BUFFER_SIZE) return false;
620 if (target2initiator_buffer_size > RPC_S2M_BUFFER_SIZE) return false;
621
622 // Prepare the metadata block
623 rpc_sync_info_t info = {.transaction_id = transaction_id, .m2s_length = initiator2target_buffer_size, .s2m_length = target2initiator_buffer_size};
624
625 // Make sure the local side knows that we're not sending the full block of data
626 split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = initiator2target_buffer_size;
627 split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = target2initiator_buffer_size;
628
629 // Run through the sequence:
630 // * set the transaction ID and lengths
631 // * send the request data
632 // * execute RPC callback
633 // * retrieve the response data
634 if (!transport_write(PUT_RPC_INFO, &info, sizeof(info))) {
635 return false;
636 }
637 if (!transport_write(PUT_RPC_REQ_DATA, initiator2target_buffer, initiator2target_buffer_size)) {
638 return false;
639 }
640 if (!transport_write(EXECUTE_RPC, &transaction_id, sizeof(transaction_id))) {
641 return false;
642 }
643 if (!transport_read(GET_RPC_RESP_DATA, target2initiator_buffer, target2initiator_buffer_size)) {
644 return false;
645 }
646 return true;
647}
648
649void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
650 // The RPC info block contains the intended transaction ID, as well as the sizes for both inbound and outbound data.
651 // Ignore the args -- the `split_shmem` already has the info, we just need to act upon it.
652 // We must keep the `split_transaction_table` non-const, so that it is able to be modified at runtime.
653
654 split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = split_shmem->rpc_info.m2s_length;
655 split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = split_shmem->rpc_info.s2m_length;
656}
657
658void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
659 // We can assume that the buffer lengths are correctly set, now, given that sequentially the rpc_info callback was already executed.
660 // Go through the rpc_info and execute _that_ transaction's callback, with the scratch buffers as inputs.
661 int8_t transaction_id = split_shmem->rpc_info.transaction_id;
662 if (transaction_id < NUM_TOTAL_TRANSACTIONS) {
663 split_transaction_desc_t *trans = &split_transaction_table[transaction_id];
664 if (trans->slave_callback) {
665 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);
666 }
667 }
668}
669
670#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
diff --git a/quantum/split_common/transactions.h b/quantum/split_common/transactions.h
new file mode 100644
index 000000000..4306ba1d8
--- /dev/null
+++ b/quantum/split_common/transactions.h
@@ -0,0 +1,54 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include "stdint.h"
20#include "stdbool.h"
21
22#include "matrix.h"
23#include "transaction_id_define.h"
24#include "transport.h"
25
26typedef void (*slave_callback_t)(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
27
28// Split transaction Descriptor
29typedef struct _split_transaction_desc_t {
30 uint8_t * status;
31 uint8_t initiator2target_buffer_size;
32 uint16_t initiator2target_offset;
33 uint8_t target2initiator_buffer_size;
34 uint16_t target2initiator_offset;
35 slave_callback_t slave_callback;
36} split_transaction_desc_t;
37
38// Forward declaration for the split transactions
39extern split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS];
40
41#define split_shmem_offset_ptr(offset) ((void *)(((uint8_t *)split_shmem) + (offset)))
42#define split_trans_initiator2target_buffer(trans) (split_shmem_offset_ptr((trans)->initiator2target_offset))
43#define split_trans_target2initiator_buffer(trans) (split_shmem_offset_ptr((trans)->target2initiator_offset))
44
45// returns false if valid data not received from slave
46bool transactions_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]);
47void transactions_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]);
48
49void transaction_register_rpc(int8_t transaction_id, slave_callback_t callback);
50
51bool transaction_rpc_exec(int8_t transaction_id, uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
52
53#define transaction_rpc_send(transaction_id, initiator2target_buffer_size, initiator2target_buffer) transaction_rpc_exec(transaction_id, initiator2target_buffer_size, initiator2target_buffer, 0, NULL)
54#define transaction_rpc_recv(transaction_id, target2initiator_buffer_size, target2initiator_buffer) transaction_rpc_exec(transaction_id, 0, NULL, target2initiator_buffer_size, target2initiator_buffer)
diff --git a/quantum/split_common/transport.c b/quantum/split_common/transport.c
index 9ed0f7591..a711ef85f 100644
--- a/quantum/split_common/transport.c
+++ b/quantum/split_common/transport.c
@@ -1,452 +1,118 @@
1#include <string.h> 1/* Copyright 2021 QMK
2#include <stddef.h> 2 *
3 3 * This program is free software: you can redistribute it and/or modify
4#include "config.h" 4 * it under the terms of the GNU General Public License as published by
5#include "matrix.h" 5 * the Free Software Foundation, either version 2 of the License, or
6#include "quantum.h" 6 * (at your option) any later version.
7 7 *
8#define ROWS_PER_HAND (MATRIX_ROWS / 2) 8 * This program is distributed in the hope that it will be useful,
9#define SYNC_TIMER_OFFSET 2 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11#ifdef RGBLIGHT_ENABLE 11 * GNU General Public License for more details.
12# include "rgblight.h" 12 *
13#endif 13 * You should have received a copy of the GNU General Public License
14 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15#ifdef BACKLIGHT_ENABLE 15 */
16# include "backlight.h"
17#endif
18
19#ifdef ENCODER_ENABLE
20# include "encoder.h"
21static pin_t encoders_pad[] = ENCODERS_PAD_A;
22# define NUMBER_OF_ENCODERS (sizeof(encoders_pad) / sizeof(pin_t))
23#endif
24
25#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
26# include "led_matrix.h"
27#endif
28#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
29# include "rgb_matrix.h"
30#endif
31
32#if defined(USE_I2C)
33 16
34# include "i2c_master.h" 17#include <string.h>
35# include "i2c_slave.h" 18#include <debug.h>
36
37typedef struct _I2C_slave_buffer_t {
38# ifndef DISABLE_SYNC_TIMER
39 uint32_t sync_timer;
40# endif
41# ifdef SPLIT_TRANSPORT_MIRROR
42 matrix_row_t mmatrix[ROWS_PER_HAND];
43# endif
44 matrix_row_t smatrix[ROWS_PER_HAND];
45# ifdef SPLIT_MODS_ENABLE
46 uint8_t real_mods;
47 uint8_t weak_mods;
48# ifndef NO_ACTION_ONESHOT
49 uint8_t oneshot_mods;
50# endif
51# endif
52# ifdef BACKLIGHT_ENABLE
53 uint8_t backlight_level;
54# endif
55# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
56 rgblight_syncinfo_t rgblight_sync;
57# endif
58# ifdef ENCODER_ENABLE
59 uint8_t encoder_state[NUMBER_OF_ENCODERS];
60# endif
61# ifdef WPM_ENABLE
62 uint8_t current_wpm;
63# endif
64# if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
65 led_eeconfig_t led_matrix;
66 bool led_suspend_state;
67# endif
68# if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
69 rgb_config_t rgb_matrix;
70 bool rgb_suspend_state;
71# endif
72} I2C_slave_buffer_t;
73 19
74static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_reg; 20#include "transactions.h"
21#include "transport.h"
22#include "transaction_id_define.h"
23#include "atomic_util.h"
75 24
76# define I2C_SYNC_TIME_START offsetof(I2C_slave_buffer_t, sync_timer) 25#ifdef USE_I2C
77# define I2C_KEYMAP_MASTER_START offsetof(I2C_slave_buffer_t, mmatrix)
78# define I2C_KEYMAP_SLAVE_START offsetof(I2C_slave_buffer_t, smatrix)
79# define I2C_REAL_MODS_START offsetof(I2C_slave_buffer_t, real_mods)
80# define I2C_WEAK_MODS_START offsetof(I2C_slave_buffer_t, weak_mods)
81# define I2C_ONESHOT_MODS_START offsetof(I2C_slave_buffer_t, oneshot_mods)
82# define I2C_BACKLIGHT_START offsetof(I2C_slave_buffer_t, backlight_level)
83# define I2C_RGB_START offsetof(I2C_slave_buffer_t, rgblight_sync)
84# define I2C_ENCODER_START offsetof(I2C_slave_buffer_t, encoder_state)
85# define I2C_WPM_START offsetof(I2C_slave_buffer_t, current_wpm)
86# define I2C_LED_MATRIX_START offsetof(I2C_slave_buffer_t, led_matrix)
87# define I2C_LED_SUSPEND_START offsetof(I2C_slave_buffer_t, led_suspend_state)
88# define I2C_RGB_MATRIX_START offsetof(I2C_slave_buffer_t, rgb_matrix)
89# define I2C_RGB_SUSPEND_START offsetof(I2C_slave_buffer_t, rgb_suspend_state)
90 26
91# define TIMEOUT 100 27# ifndef SLAVE_I2C_TIMEOUT
28# define SLAVE_I2C_TIMEOUT 100
29# endif // SLAVE_I2C_TIMEOUT
92 30
93# ifndef SLAVE_I2C_ADDRESS 31# ifndef SLAVE_I2C_ADDRESS
94# define SLAVE_I2C_ADDRESS 0x32 32# define SLAVE_I2C_ADDRESS 0x32
95# endif 33# endif
96 34
97// Get rows from other half over i2c 35# include "i2c_master.h"
98bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 36# include "i2c_slave.h"
99 i2c_readReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_SLAVE_START, (void *)slave_matrix, sizeof(i2c_buffer->smatrix), TIMEOUT);
100# ifdef SPLIT_TRANSPORT_MIRROR
101 i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_MASTER_START, (void *)master_matrix, sizeof(i2c_buffer->mmatrix), TIMEOUT);
102# endif
103 37
104 // write backlight info 38// Ensure the I2C buffer has enough space
105# ifdef BACKLIGHT_ENABLE 39_Static_assert(sizeof(split_shared_memory_t) <= I2C_SLAVE_REG_COUNT, "split_shared_memory_t too large for I2C_SLAVE_REG_COUNT");
106 uint8_t level = is_backlight_enabled() ? get_backlight_level() : 0;
107 if (level != i2c_buffer->backlight_level) {
108 if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_BACKLIGHT_START, (void *)&level, sizeof(level), TIMEOUT) >= 0) {
109 i2c_buffer->backlight_level = level;
110 }
111 }
112# endif
113 40
114# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) 41split_shared_memory_t *const split_shmem = (split_shared_memory_t *)i2c_slave_reg;
115 if (rgblight_get_change_flags()) {
116 rgblight_syncinfo_t rgblight_sync;
117 rgblight_get_syncinfo(&rgblight_sync);
118 if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_RGB_START, (void *)&rgblight_sync, sizeof(rgblight_sync), TIMEOUT) >= 0) {
119 rgblight_clear_change_flags();
120 }
121 }
122# endif
123 42
124# ifdef ENCODER_ENABLE 43void transport_master_init(void) { i2c_init(); }
125 i2c_readReg(SLAVE_I2C_ADDRESS, I2C_ENCODER_START, (void *)i2c_buffer->encoder_state, sizeof(i2c_buffer->encoder_state), TIMEOUT); 44void transport_slave_init(void) { i2c_slave_init(SLAVE_I2C_ADDRESS); }
126 encoder_update_raw(i2c_buffer->encoder_state);
127# endif
128 45
129# ifdef WPM_ENABLE 46i2c_status_t transport_trigger_callback(int8_t id) {
130 uint8_t current_wpm = get_current_wpm(); 47 // If there's no callback, indicate that we were successful
131 if (current_wpm != i2c_buffer->current_wpm) { 48 if (!split_transaction_table[id].slave_callback) {
132 if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_WPM_START, (void *)&current_wpm, sizeof(current_wpm), TIMEOUT) >= 0) { 49 return I2C_STATUS_SUCCESS;
133 i2c_buffer->current_wpm = current_wpm;
134 }
135 } 50 }
136# endif
137 51
138# ifdef SPLIT_MODS_ENABLE 52 // Kick off the "callback executor", now that data has been written to the slave
139 uint8_t real_mods = get_mods(); 53 split_shmem->transaction_id = id;
140 if (real_mods != i2c_buffer->real_mods) { 54 split_transaction_desc_t *trans = &split_transaction_table[I2C_EXECUTE_CALLBACK];
141 if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_REAL_MODS_START, (void *)&real_mods, sizeof(real_mods), TIMEOUT) >= 0) { 55 return i2c_writeReg(SLAVE_I2C_ADDRESS, trans->initiator2target_offset, split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size, SLAVE_I2C_TIMEOUT);
142 i2c_buffer->real_mods = real_mods; 56}
57
58bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, uint16_t initiator2target_length, void *target2initiator_buf, uint16_t target2initiator_length) {
59 i2c_status_t status;
60 split_transaction_desc_t *trans = &split_transaction_table[id];
61 if (initiator2target_length > 0) {
62 size_t len = trans->initiator2target_buffer_size < initiator2target_length ? trans->initiator2target_buffer_size : initiator2target_length;
63 memcpy(split_trans_initiator2target_buffer(trans), initiator2target_buf, len);
64 if ((status = i2c_writeReg(SLAVE_I2C_ADDRESS, trans->initiator2target_offset, split_trans_initiator2target_buffer(trans), len, SLAVE_I2C_TIMEOUT)) < 0) {
65 return false;
143 } 66 }
144 } 67 }
145 68
146 uint8_t weak_mods = get_weak_mods(); 69 // If we need to execute a callback on the slave, do so
147 if (weak_mods != i2c_buffer->weak_mods) { 70 if ((status = transport_trigger_callback(id)) < 0) {
148 if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_WEAK_MODS_START, (void *)&weak_mods, sizeof(weak_mods), TIMEOUT) >= 0) { 71 return false;
149 i2c_buffer->weak_mods = weak_mods;
150 }
151 } 72 }
152 73
153# ifndef NO_ACTION_ONESHOT 74 if (target2initiator_length > 0) {
154 uint8_t oneshot_mods = get_oneshot_mods(); 75 size_t len = trans->target2initiator_buffer_size < target2initiator_length ? trans->target2initiator_buffer_size : target2initiator_length;
155 if (oneshot_mods != i2c_buffer->oneshot_mods) { 76 if ((status = i2c_readReg(SLAVE_I2C_ADDRESS, trans->target2initiator_offset, split_trans_target2initiator_buffer(trans), len, SLAVE_I2C_TIMEOUT)) < 0) {
156 if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_ONESHOT_MODS_START, (void *)&oneshot_mods, sizeof(oneshot_mods), TIMEOUT) >= 0) { 77 return false;
157 i2c_buffer->oneshot_mods = oneshot_mods;
158 } 78 }
79 memcpy(target2initiator_buf, split_trans_target2initiator_buffer(trans), len);
159 } 80 }
160# endif
161# endif
162 81
163# if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
164 i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_LED_MATRIX_START, (void *)led_matrix_eeconfig, sizeof(i2c_buffer->led_matrix), TIMEOUT);
165 bool suspend_state = led_matrix_get_suspend_state();
166 i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_LED_SUSPEND_START, (void *)suspend_state, sizeof(i2c_buffer->led_suspend_state), TIMEOUT);
167# endif
168# if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
169 i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_RGB_MATRIX_START, (void *)rgb_matrix_config, sizeof(i2c_buffer->rgb_matrix), TIMEOUT);
170 bool suspend_state = rgb_matrix_get_suspend_state();
171 i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_RGB_SUSPEND_START, (void *)suspend_state, sizeof(i2c_buffer->rgb_suspend_state), TIMEOUT);
172# endif
173
174# ifndef DISABLE_SYNC_TIMER
175 i2c_buffer->sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
176 i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_SYNC_TIME_START, (void *)&i2c_buffer->sync_timer, sizeof(i2c_buffer->sync_timer), TIMEOUT);
177# endif
178 return true; 82 return true;
179} 83}
180 84
181void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 85#else // USE_I2C
182# ifndef DISABLE_SYNC_TIMER
183 sync_timer_update(i2c_buffer->sync_timer);
184# endif
185 // Copy matrix to I2C buffer
186 memcpy((void *)i2c_buffer->smatrix, (void *)slave_matrix, sizeof(i2c_buffer->smatrix));
187# ifdef SPLIT_TRANSPORT_MIRROR
188 memcpy((void *)master_matrix, (void *)i2c_buffer->mmatrix, sizeof(i2c_buffer->mmatrix));
189# endif
190
191// Read Backlight Info
192# ifdef BACKLIGHT_ENABLE
193 backlight_set(i2c_buffer->backlight_level);
194# endif
195
196# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
197 // Update the RGB with the new data
198 if (i2c_buffer->rgblight_sync.status.change_flags != 0) {
199 rgblight_update_sync(&i2c_buffer->rgblight_sync, false);
200 i2c_buffer->rgblight_sync.status.change_flags = 0;
201 }
202# endif
203
204# ifdef ENCODER_ENABLE
205 encoder_state_raw(i2c_buffer->encoder_state);
206# endif
207
208# ifdef WPM_ENABLE
209 set_current_wpm(i2c_buffer->current_wpm);
210# endif
211
212# ifdef SPLIT_MODS_ENABLE
213 set_mods(i2c_buffer->real_mods);
214 set_weak_mods(i2c_buffer->weak_mods);
215# ifndef NO_ACTION_ONESHOT
216 set_oneshot_mods(i2c_buffer->oneshot_mods);
217# endif
218# endif
219
220# if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
221 memcpy((void *)i2c_buffer->led_matrix, (void *)led_matrix_eeconfig, sizeof(i2c_buffer->led_matrix));
222 led_matrix_set_suspend_state(i2c_buffer->led_suspend_state);
223# endif
224# if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
225 memcpy((void *)i2c_buffer->rgb_matrix, (void *)rgb_matrix_config, sizeof(i2c_buffer->rgb_matrix));
226 rgb_matrix_set_suspend_state(i2c_buffer->rgb_suspend_state);
227# endif
228}
229
230void transport_master_init(void) { i2c_init(); }
231
232void transport_slave_init(void) { i2c_slave_init(SLAVE_I2C_ADDRESS); }
233
234#else // USE_SERIAL
235 86
236# include "serial.h" 87# include "serial.h"
237 88
238typedef struct _Serial_s2m_buffer_t { 89static split_shared_memory_t shared_memory;
239 // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack 90split_shared_memory_t *const split_shmem = &shared_memory;
240 matrix_row_t smatrix[ROWS_PER_HAND];
241
242# ifdef ENCODER_ENABLE
243 uint8_t encoder_state[NUMBER_OF_ENCODERS];
244# endif
245
246} Serial_s2m_buffer_t;
247
248typedef struct _Serial_m2s_buffer_t {
249# ifdef SPLIT_MODS_ENABLE
250 uint8_t real_mods;
251 uint8_t weak_mods;
252# ifndef NO_ACTION_ONESHOT
253 uint8_t oneshot_mods;
254# endif
255# endif
256# ifndef DISABLE_SYNC_TIMER
257 uint32_t sync_timer;
258# endif
259# ifdef SPLIT_TRANSPORT_MIRROR
260 matrix_row_t mmatrix[ROWS_PER_HAND];
261# endif
262# ifdef BACKLIGHT_ENABLE
263 uint8_t backlight_level;
264# endif
265# ifdef WPM_ENABLE
266 uint8_t current_wpm;
267# endif
268# if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
269 led_eeconfig_t led_matrix;
270 bool led_suspend_state;
271# endif
272# if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
273 rgb_config_t rgb_matrix;
274 bool rgb_suspend_state;
275# endif
276} Serial_m2s_buffer_t;
277
278# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
279// When MCUs on both sides drive their respective RGB LED chains,
280// it is necessary to synchronize, so it is necessary to communicate RGB
281// information. In that case, define RGBLIGHT_SPLIT with info on the number
282// of LEDs on each half.
283//
284// Otherwise, if the master side MCU drives both sides RGB LED chains,
285// there is no need to communicate.
286
287typedef struct _Serial_rgblight_t {
288 rgblight_syncinfo_t rgblight_sync;
289} Serial_rgblight_t;
290 91
291volatile Serial_rgblight_t serial_rgblight = {}; 92void transport_master_init(void) { soft_serial_initiator_init(); }
292uint8_t volatile status_rgblight = 0; 93void transport_slave_init(void) { soft_serial_target_init(); }
293# endif
294
295volatile Serial_s2m_buffer_t serial_s2m_buffer = {};
296volatile Serial_m2s_buffer_t serial_m2s_buffer = {};
297uint8_t volatile status0 = 0;
298
299enum serial_transaction_id {
300 GET_SLAVE_MATRIX = 0,
301# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
302 PUT_RGBLIGHT,
303# endif
304};
305
306SSTD_t transactions[] = {
307 [GET_SLAVE_MATRIX] =
308 {
309 (uint8_t *)&status0,
310 sizeof(serial_m2s_buffer),
311 (uint8_t *)&serial_m2s_buffer,
312 sizeof(serial_s2m_buffer),
313 (uint8_t *)&serial_s2m_buffer,
314 },
315# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
316 [PUT_RGBLIGHT] =
317 {
318 (uint8_t *)&status_rgblight, sizeof(serial_rgblight), (uint8_t *)&serial_rgblight, 0, NULL // no slave to master transfer
319 },
320# endif
321};
322
323void transport_master_init(void) { soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); }
324
325void transport_slave_init(void) { soft_serial_target_init(transactions, TID_LIMIT(transactions)); }
326 94
327# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) 95bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, uint16_t initiator2target_length, void *target2initiator_buf, uint16_t target2initiator_length) {
328 96 split_transaction_desc_t *trans = &split_transaction_table[id];
329// rgblight synchronization information communication. 97 if (initiator2target_length > 0) {
330 98 size_t len = trans->initiator2target_buffer_size < initiator2target_length ? trans->initiator2target_buffer_size : initiator2target_length;
331void transport_rgblight_master(void) { 99 memcpy(split_trans_initiator2target_buffer(trans), initiator2target_buf, len);
332 if (rgblight_get_change_flags()) {
333 rgblight_get_syncinfo((rgblight_syncinfo_t *)&serial_rgblight.rgblight_sync);
334 if (soft_serial_transaction(PUT_RGBLIGHT) == TRANSACTION_END) {
335 rgblight_clear_change_flags();
336 }
337 }
338}
339
340void transport_rgblight_slave(void) {
341 if (status_rgblight == TRANSACTION_ACCEPTED) {
342 rgblight_update_sync((rgblight_syncinfo_t *)&serial_rgblight.rgblight_sync, false);
343 status_rgblight = TRANSACTION_END;
344 } 100 }
345}
346 101
347# else 102 if (soft_serial_transaction(id) != TRANSACTION_END) {
348# define transport_rgblight_master()
349# define transport_rgblight_slave()
350# endif
351
352bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
353# ifndef SERIAL_USE_MULTI_TRANSACTION
354 if (soft_serial_transaction() != TRANSACTION_END) {
355 return false;
356 }
357# else
358 transport_rgblight_master();
359 if (soft_serial_transaction(GET_SLAVE_MATRIX) != TRANSACTION_END) {
360 return false; 103 return false;
361 } 104 }
362# endif
363 105
364 // TODO: if MATRIX_COLS > 8 change to unpack() 106 if (target2initiator_length > 0) {
365 for (int i = 0; i < ROWS_PER_HAND; ++i) { 107 size_t len = trans->target2initiator_buffer_size < target2initiator_length ? trans->target2initiator_buffer_size : target2initiator_length;
366 slave_matrix[i] = serial_s2m_buffer.smatrix[i]; 108 memcpy(target2initiator_buf, split_trans_target2initiator_buffer(trans), len);
367# ifdef SPLIT_TRANSPORT_MIRROR
368 serial_m2s_buffer.mmatrix[i] = master_matrix[i];
369# endif
370 } 109 }
371 110
372# ifdef BACKLIGHT_ENABLE
373 // Write backlight level for slave to read
374 serial_m2s_buffer.backlight_level = is_backlight_enabled() ? get_backlight_level() : 0;
375# endif
376
377# ifdef ENCODER_ENABLE
378 encoder_update_raw((uint8_t *)serial_s2m_buffer.encoder_state);
379# endif
380
381# ifdef WPM_ENABLE
382 // Write wpm to slave
383 serial_m2s_buffer.current_wpm = get_current_wpm();
384# endif
385
386# ifdef SPLIT_MODS_ENABLE
387 serial_m2s_buffer.real_mods = get_mods();
388 serial_m2s_buffer.weak_mods = get_weak_mods();
389# ifndef NO_ACTION_ONESHOT
390 serial_m2s_buffer.oneshot_mods = get_oneshot_mods();
391# endif
392# endif
393
394# if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
395 serial_m2s_buffer.led_matrix = led_matrix_eeconfig;
396 serial_m2s_buffer.led_suspend_state = led_matrix_get_suspend_state();
397# endif
398# if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
399 serial_m2s_buffer.rgb_matrix = rgb_matrix_config;
400 serial_m2s_buffer.rgb_suspend_state = rgb_matrix_get_suspend_state();
401# endif
402
403# ifndef DISABLE_SYNC_TIMER
404 serial_m2s_buffer.sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
405# endif
406 return true; 111 return true;
407} 112}
408 113
409void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 114#endif // USE_I2C
410 transport_rgblight_slave();
411# ifndef DISABLE_SYNC_TIMER
412 sync_timer_update(serial_m2s_buffer.sync_timer);
413# endif
414
415 // TODO: if MATRIX_COLS > 8 change to pack()
416 for (int i = 0; i < ROWS_PER_HAND; ++i) {
417 serial_s2m_buffer.smatrix[i] = slave_matrix[i];
418# ifdef SPLIT_TRANSPORT_MIRROR
419 master_matrix[i] = serial_m2s_buffer.mmatrix[i];
420# endif
421 }
422# ifdef BACKLIGHT_ENABLE
423 backlight_set(serial_m2s_buffer.backlight_level);
424# endif
425
426# ifdef ENCODER_ENABLE
427 encoder_state_raw((uint8_t *)serial_s2m_buffer.encoder_state);
428# endif
429 115
430# ifdef WPM_ENABLE 116bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { return transactions_master(master_matrix, slave_matrix); }
431 set_current_wpm(serial_m2s_buffer.current_wpm);
432# endif
433
434# ifdef SPLIT_MODS_ENABLE
435 set_mods(serial_m2s_buffer.real_mods);
436 set_weak_mods(serial_m2s_buffer.weak_mods);
437# ifndef NO_ACTION_ONESHOT
438 set_oneshot_mods(serial_m2s_buffer.oneshot_mods);
439# endif
440# endif
441
442# if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
443 led_matrix_eeconfig = serial_m2s_buffer.led_matrix;
444 led_matrix_set_suspend_state(serial_m2s_buffer.led_suspend_state);
445# endif
446# if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
447 rgb_matrix_config = serial_m2s_buffer.rgb_matrix;
448 rgb_matrix_set_suspend_state(serial_m2s_buffer.rgb_suspend_state);
449# endif
450}
451 117
452#endif 118void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { transactions_slave(master_matrix, slave_matrix); } \ No newline at end of file
diff --git a/quantum/split_common/transport.h b/quantum/split_common/transport.h
index a9f66301b..2e07f6b25 100644
--- a/quantum/split_common/transport.h
+++ b/quantum/split_common/transport.h
@@ -1,10 +1,175 @@
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
1#pragma once 17#pragma once
2 18
19#include "stdint.h"
20#include "stdbool.h"
21
22#include "progmem.h"
23#include "action_layer.h"
3#include "matrix.h" 24#include "matrix.h"
4 25
26#ifndef RPC_M2S_BUFFER_SIZE
27# define RPC_M2S_BUFFER_SIZE 32
28#endif // RPC_M2S_BUFFER_SIZE
29
30#ifndef RPC_S2M_BUFFER_SIZE
31# define RPC_S2M_BUFFER_SIZE 32
32#endif // RPC_S2M_BUFFER_SIZE
33
5void transport_master_init(void); 34void transport_master_init(void);
6void transport_slave_init(void); 35void transport_slave_init(void);
7 36
8// returns false if valid data not received from slave 37// returns false if valid data not received from slave
9bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]); 38bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]);
10void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]); 39void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]);
40
41bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, uint16_t initiator2target_length, void *target2initiator_buf, uint16_t target2initiator_length);
42
43#ifdef ENCODER_ENABLE
44# include "encoder.h"
45# define NUMBER_OF_ENCODERS (sizeof((pin_t[])ENCODERS_PAD_A) / sizeof(pin_t))
46#endif // ENCODER_ENABLE
47
48#ifdef BACKLIGHT_ENABLE
49# include "backlight.h"
50#endif // BACKLIGHT_ENABLE
51
52#ifdef RGBLIGHT_ENABLE
53# include "rgblight.h"
54#endif // RGBLIGHT_ENABLE
55
56typedef struct _split_slave_matrix_sync_t {
57 uint8_t checksum;
58 matrix_row_t matrix[(MATRIX_ROWS) / 2];
59} split_slave_matrix_sync_t;
60
61#ifdef SPLIT_TRANSPORT_MIRROR
62typedef struct _split_master_matrix_sync_t {
63 matrix_row_t matrix[(MATRIX_ROWS) / 2];
64} split_master_matrix_sync_t;
65#endif // SPLIT_TRANSPORT_MIRROR
66
67#ifdef ENCODER_ENABLE
68typedef struct _split_slave_encoder_sync_t {
69 uint8_t checksum;
70 uint8_t state[NUMBER_OF_ENCODERS];
71} split_slave_encoder_sync_t;
72#endif // ENCODER_ENABLE
73
74#if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
75typedef struct _split_layers_sync_t {
76 layer_state_t layer_state;
77 layer_state_t default_layer_state;
78} split_layers_sync_t;
79#endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
80
81#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
82# include "led_matrix.h"
83
84typedef struct _led_matrix_sync_t {
85 led_eeconfig_t led_matrix;
86 bool led_suspend_state;
87} led_matrix_sync_t;
88#endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
89
90#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
91# include "rgb_matrix.h"
92
93typedef struct _rgb_matrix_sync_t {
94 rgb_config_t rgb_matrix;
95 bool rgb_suspend_state;
96} rgb_matrix_sync_t;
97#endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
98
99#ifdef SPLIT_MODS_ENABLE
100typedef struct _split_mods_sync_t {
101 uint8_t real_mods;
102 uint8_t weak_mods;
103# ifndef NO_ACTION_ONESHOT
104 uint8_t oneshot_mods;
105# endif // NO_ACTION_ONESHOT
106} split_mods_sync_t;
107#endif // SPLIT_MODS_ENABLE
108
109#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
110typedef struct _rpc_sync_info_t {
111 int8_t transaction_id;
112 uint8_t m2s_length;
113 uint8_t s2m_length;
114} rpc_sync_info_t;
115#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
116
117typedef struct _split_shared_memory_t {
118#ifdef USE_I2C
119 int8_t transaction_id;
120#endif // USE_I2C
121
122 split_slave_matrix_sync_t smatrix;
123
124#ifdef SPLIT_TRANSPORT_MIRROR
125 split_master_matrix_sync_t mmatrix;
126#endif // SPLIT_TRANSPORT_MIRROR
127
128#ifdef ENCODER_ENABLE
129 split_slave_encoder_sync_t encoders;
130#endif // ENCODER_ENABLE
131
132#ifndef DISABLE_SYNC_TIMER
133 uint32_t sync_timer;
134#endif // DISABLE_SYNC_TIMER
135
136#if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
137 split_layers_sync_t layers;
138#endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
139
140#ifdef SPLIT_LED_STATE_ENABLE
141 uint8_t led_state;
142#endif // SPLIT_LED_STATE_ENABLE
143
144#ifdef SPLIT_MODS_ENABLE
145 split_mods_sync_t mods;
146#endif // SPLIT_MODS_ENABLE
147
148#ifdef BACKLIGHT_ENABLE
149 uint8_t backlight_level;
150#endif // BACKLIGHT_ENABLE
151
152#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
153 rgblight_syncinfo_t rgblight_sync;
154#endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
155
156#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
157 led_matrix_sync_t led_matrix_sync;
158#endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
159
160#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
161 rgb_matrix_sync_t rgb_matrix_sync;
162#endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
163
164#if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
165 uint8_t current_wpm;
166#endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
167
168#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
169 rpc_sync_info_t rpc_info;
170 uint8_t rpc_m2s_buffer[RPC_M2S_BUFFER_SIZE];
171 uint8_t rpc_s2m_buffer[RPC_S2M_BUFFER_SIZE];
172#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
173} split_shared_memory_t;
174
175extern split_shared_memory_t *const split_shmem; \ No newline at end of file