aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorNick Brassel <nick@tzarc.org>2021-06-18 09:10:06 +1000
committerGitHub <noreply@github.com>2021-06-18 09:10:06 +1000
commit172e6a703041363decd6fc829542f33180c13beb (patch)
treea5d4afaa672ab44826865fd76b201e3899083192 /docs
parentef92c9ee2cf4745637635ec1895399e4f013914c (diff)
downloadqmk_firmware-172e6a703041363decd6fc829542f33180c13beb.tar.gz
qmk_firmware-172e6a703041363decd6fc829542f33180c13beb.zip
Extensible split data sync (#11930)
* Extensible split data sync capability through transactions. - Split common transport has been split up between the transport layer and data layer. - Split "transactions" model used, with convergence between I2C and serial data definitions. - Slave matrix "generation count" is used to determine if the full slave matrix needs to be retrieved. - Encoders get the same "generation count" treatment. - All other blocks of data are synchronised when a change is detected. - All transmissions have a globally-configurable deadline before a transmission is forced (`FORCED_SYNC_THROTTLE_MS`, default 100ms). - Added atomicity for all core-synced data, preventing partial updates - Added retries to AVR i2c_master's i2c_start, to minimise the number of failed transactions when interrupts are disabled on the slave due to atomicity checks. - Some keyboards have had slight modifications made in order to ensure that they still build due to firmware size restrictions. * Fixup LED_MATRIX compile. * Parameterise ERROR_DISCONNECT_COUNT.
Diffstat (limited to 'docs')
-rw-r--r--docs/config_options.md26
-rw-r--r--docs/feature_split_keyboard.md114
2 files changed, 128 insertions, 12 deletions
diff --git a/docs/config_options.md b/docs/config_options.md
index 26fe8cea5..980195ac6 100644
--- a/docs/config_options.md
+++ b/docs/config_options.md
@@ -274,7 +274,7 @@ There are a few different ways to set handedness for split keyboards (listed in
274### Other Options 274### Other Options
275 275
276* `#define USE_I2C` 276* `#define USE_I2C`
277 * For using I2C instead of Serial (defaults to serial) 277 * For using I2C instead of Serial (default is serial; serial transport is supported on ARM -- I2C is AVR-only)
278 278
279* `#define SOFT_SERIAL_PIN D0` 279* `#define SOFT_SERIAL_PIN D0`
280 * When using serial, define this. `D0` or `D1`,`D2`,`D3`,`E6`. 280 * When using serial, define this. `D0` or `D1`,`D2`,`D3`,`E6`.
@@ -303,7 +303,7 @@ There are a few different ways to set handedness for split keyboards (listed in
303* `#define SPLIT_USB_DETECT` 303* `#define SPLIT_USB_DETECT`
304 * Detect (with timeout) USB connection when delegating master/slave 304 * Detect (with timeout) USB connection when delegating master/slave
305 * Default behavior for ARM 305 * Default behavior for ARM
306 * Required for AVR Teensy 306 * Required for AVR Teensy (without hardware mods)
307 307
308* `#define SPLIT_USB_TIMEOUT 2000` 308* `#define SPLIT_USB_TIMEOUT 2000`
309 * Maximum timeout when detecting master/slave when using `SPLIT_USB_DETECT` 309 * Maximum timeout when detecting master/slave when using `SPLIT_USB_DETECT`
@@ -311,6 +311,28 @@ There are a few different ways to set handedness for split keyboards (listed in
311* `#define SPLIT_USB_TIMEOUT_POLL 10` 311* `#define SPLIT_USB_TIMEOUT_POLL 10`
312 * Poll frequency when detecting master/slave when using `SPLIT_USB_DETECT` 312 * Poll frequency when detecting master/slave when using `SPLIT_USB_DETECT`
313 313
314* `#define FORCED_SYNC_THROTTLE_MS 100`
315 * Deadline for synchronizing data from master to slave when using the QMK-provided split transport.
316
317* `#define SPLIT_TRANSPORT_MIRROR`
318 * Mirrors the master-side matrix on the slave when using the QMK-provided split transport.
319
320* `#define SPLIT_LAYER_STATE_ENABLE`
321 * Ensures the current layer state is available on the slave when using the QMK-provided split transport.
322
323* `#define SPLIT_LED_STATE_ENABLE`
324 * Ensures the current host indicator state (caps/num/scroll) is available on the slave when using the QMK-provided split transport.
325
326* `#define SPLIT_MODS_ENABLE`
327 * Ensures the current modifier state (normal, weak, and oneshot) is available on the slave when using the QMK-provided split transport.
328
329* `#define SPLIT_WPM_ENABLE`
330 * Ensures the current WPM is available on the slave when using the QMK-provided split transport.
331
332* `#define SPLIT_TRANSACTION_IDS_KB .....`
333* `#define SPLIT_TRANSACTION_IDS_USER .....`
334 * Allows for custom data sync with the slave when using the QMK-provided split transport. See [custom data sync between sides](feature_split_keyboard.md#custom-data-sync) for more information.
335
314# The `rules.mk` File 336# The `rules.mk` File
315 337
316This is a [make](https://www.gnu.org/software/make/manual/make.html) file that is included by the top-level `Makefile`. It is used to set some information about the MCU that we will be compiling for as well as enabling and disabling certain features. 338This is a [make](https://www.gnu.org/software/make/manual/make.html) file that is included by the top-level `Makefile`. It is used to set some information about the MCU that we will be compiling for as well as enabling and disabling certain features.
diff --git a/docs/feature_split_keyboard.md b/docs/feature_split_keyboard.md
index 4ebf585f5..603c387c2 100644
--- a/docs/feature_split_keyboard.md
+++ b/docs/feature_split_keyboard.md
@@ -8,8 +8,7 @@ QMK Firmware has a generic implementation that is usable by any board, as well a
8 8
9For this, we will mostly be talking about the generic implementation used by the Let's Split and other keyboards. 9For this, we will mostly be talking about the generic implementation used by the Let's Split and other keyboards.
10 10
11!> ARM is not yet fully supported for Split Keyboards and has many limitations. Progress is being made, but we have not yet reached 100% feature parity. 11!> ARM split supports most QMK subsystems when using the 'serial' and 'serial_usart' drivers. I2C slave is currently unsupported.
12
13 12
14## Compatibility Overview 13## Compatibility Overview
15 14
@@ -169,7 +168,7 @@ Because not every split keyboard is identical, there are a number of additional
169#define USE_I2C 168#define USE_I2C
170``` 169```
171 170
172This enables I<sup>2</sup>C support for split keyboards. This isn't strictly for communication, but can be used for OLED or other I<sup>2</sup>C-based devices. 171This configures the use of I<sup>2</sup>C support for split keyboard transport (AVR only).
173 172
174```c 173```c
175#define SOFT_SERIAL_PIN D0 174#define SOFT_SERIAL_PIN D0
@@ -193,20 +192,115 @@ If you're having issues with serial communication, you can change this value, as
193* **`5`**: about 20kbps 192* **`5`**: about 20kbps
194 193
195```c 194```c
196#define SPLIT_MODS_ENABLE 195#define FORCED_SYNC_THROTTLE_MS 100
197``` 196```
198 197
199This enables transmitting modifier state (normal, weak and oneshot) to the non 198This sets the maximum number of milliseconds before forcing a synchronization of data from master to slave. Under normal circumstances this sync occurs whenever the data _changes_, for safety a data transfer occurs after this number of milliseconds if no change has been detected since the last sync.
200primary side of the split keyboard. This adds a few bytes of data to the split
201communication protocol and may impact the matrix scan speed when enabled.
202The purpose of this feature is to support cosmetic use of modifer state (e.g.
203displaying status on an OLED screen).
204 199
205```c 200```c
206#define SPLIT_TRANSPORT_MIRROR 201#define SPLIT_TRANSPORT_MIRROR
207``` 202```
208 203
209This mirrors the master side matrix to the slave side for features that react or require knowledge of master side key presses on the slave side. This adds a few bytes of data to the split communication protocol and may impact the matrix scan speed when enabled. The purpose of this feature is to support cosmetic use of key events (e.g. RGB reacting to Keypresses). 204This mirrors the master side matrix to the slave side for features that react or require knowledge of master side key presses on the slave side. The purpose of this feature is to support cosmetic use of key events (e.g. RGB reacting to keypresses). This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled.
205
206```c
207#define SPLIT_LAYER_STATE_ENABLE
208```
209
210This enables syncing of the layer state between both halves of the split keyboard. The main purpose of this feature is to enable support for use of things like OLED display of the currently active layer. This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled.
211
212```c
213#define SPLIT_LED_STATE_ENABLE
214```
215
216This enables syncing of the Host LED status (caps lock, num lock, etc) between both halves of the split keyboard. The main purpose of this feature is to enable support for use of things like OLED display of the Host LED status. This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled.
217
218```c
219#define SPLIT_MODS_ENABLE
220```
221
222This enables transmitting modifier state (normal, weak and oneshot) to the non primary side of the split keyboard. The purpose of this feature is to support cosmetic use of modifer state (e.g. displaying status on an OLED screen). This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled.
223
224```c
225#define SPLIT_WPM_ENABLE
226```
227
228This enables transmitting the current WPM to the slave side of the split keyboard. The purpose of this feature is to support cosmetic use of WPM (e.g. displaying the current value on an OLED screen). This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled.
229
230### Custom data sync between sides :id=custom-data-sync
231
232QMK's split transport allows for arbitrary data transactions at both the keyboard and user levels. This is modelled on a remote procedure call, with the master invoking a function on the slave side, with the ability to send data from master to slave, process it slave side, and send data back from slave to master.
233
234To leverage this, a keyboard or user/keymap can define a comma-separated list of _transaction IDs_:
235
236```c
237// for keyboard-level data sync:
238#define SPLIT_TRANSACTION_IDS_KB KEYBOARD_SYNC_A, KEYBOARD_SYNC_B
239// or, for user:
240#define SPLIT_TRANSACTION_IDS_USER USER_SYNC_A, USER_SYNC_B, USER_SYNC_C
241```
242
243These _transaction IDs_ then need a slave-side handler function to be registered with the split transport, for example:
244
245```c
246typedef struct _master_to_slave_t {
247 int m2s_data;
248} master_to_slave_t;
249
250typedef struct _slave_to_master_t {
251 int s2m_data;
252} slave_to_master_t;
253
254void user_sync_a_slave_handler(uint8_t in_buflen, const void* in_data, uint8_t out_buflen, void* out_data) {
255 const master_to_slave_t *m2s = (const master_to_slave_t*)in_data;
256 slave_to_master_t *s2m = (slave_to_master_t*)out_data;
257 s2m->s2m_data = m2s->m2s_data + 5; // whatever comes in, add 5 so it can be sent back
258}
259
260void keyboard_post_init_user(void) {
261 transaction_register_rpc(USER_SYNC_A, user_sync_a_slave_handler);
262}
263```
264
265The master side can then invoke the slave-side handler - for normal keyboard functionality to be minimally affected, any keyboard- or user-level code attempting to sync data should be throttled:
266
267```c
268void housekeeping_task_user(void) {
269 if (is_keyboard_master()) {
270 // Interact with slave every 500ms
271 static uint32_t last_sync = 0;
272 if (timer_elapsed32(last_sync) > 500) {
273 master_to_slave_t m2s = {6};
274 slave_to_master_t s2m = {0};
275 if(transaction_rpc_exec(USER_SYNC_A, sizeof(m2s), &m2s, sizeof(s2m), &s2m)) {
276 last_sync = timer_read32();
277 dprintf("Slave value: %d\n", s2m.s2m_data); // this will now be 11, as the slave adds 5
278 } else {
279 dprint("Slave sync failed!\n");
280 }
281 }
282 }
283}
284```
285
286!> It is recommended that any data sync between halves happens during the master side's _housekeeping task_. This ensures timely retries should failures occur.
287
288If only one-way data transfer is needed, helper methods are provided:
289
290```c
291bool transaction_rpc_exec(int8_t transaction_id, uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
292bool transaction_rpc_send(int8_t transaction_id, uint8_t initiator2target_buffer_size, const void *initiator2target_buffer);
293bool transaction_rpc_recv(int8_t transaction_id, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
294```
295
296By default, the inbound and outbound data is limited to a maximum of 32 bytes each. The sizes can be altered if required:
297
298```c
299// Master to slave:
300#define RPC_M2S_BUFFER_SIZE 48
301// Slave to master:
302#define RPC_S2M_BUFFER_SIZE 48
303```
210 304
211### Hardware Configuration Options 305### Hardware Configuration Options
212 306