1
0
Fork 0

[Core] Split support for pointing devices. (#15304)

* Draft implementation

* formatting

* fix combined buttons

* remove pimoroni throttle

* sync pointing on a throttle loop with checksum

* no longer used

* doh

Co-authored-by: Drashna Jaelre <drashna@live.com>

* switch pimoroni to a cpi equivalent

* add cpi support

* allow user modification of seperate mouse reports

* a little tidy up

* add *_RIGHT defines.

* docs

* doxygen comments

* basic changelog

* clean up pimoroni

* small doc fixes

* Update docs/feature_pointing_device.md

Co-authored-by: Drashna Jaelre <drashna@live.com>

* performance tweak if side has usb

* Don't run init funtions on wrong side

* renamed some variables for consistency

* fix pimoroni typos

* Clamp instead of OR

* Promote combined values to uint16_t

* Update pointing_device.c

Co-authored-by: Drashna Jaelre <drashna@live.com>
Co-authored-by: Nick Brassel <nick@tzarc.org>
This commit is contained in:
Dasky 2021-12-27 01:05:51 +00:00 committed by GitHub
parent 76a673233c
commit 7f7364c559
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 625 additions and 65 deletions

View file

@ -0,0 +1,13 @@
### Split Common core now supports Pointing Devices ([#15304](https://github.com/qmk/qmk_firmware/pull/15304))
Pointing devices can now be shared across a split keyboard with support for a single pointing device or a pointing device on each side.
This feature can be enabled with `#define SPLIT_POINTING_ENABLE` and one of the following options:
| Setting | Description |
|---------------------------|------------------------------------|
|`POINTING_DEVICE_LEFT` | Pointing device on the left side |
|`POINTING_DEVICE_RIGHT` | Pointing device on the right side |
|`POINTING_DEVICE_COMBINED` | Pointing device on both sides |
See the [Pointing Device](../feature_pointing_device.md) documentation for further configuration options.

View file

@ -127,8 +127,7 @@ The Pimoroni Trackball module is a I2C based breakout board with an RGB enable t
| Setting | Description | Default | | Setting | Description | Default |
|-------------------------------------|------------------------------------------------------------------------------------|---------| |-------------------------------------|------------------------------------------------------------------------------------|---------|
|`PIMORONI_TRACKBALL_ADDRESS` | (Required) Sets the I2C Address for the Pimoroni Trackball. | `0x0A` | |`PIMORONI_TRACKBALL_ADDRESS` | (Required) Sets the I2C Address for the Pimoroni Trackball. | `0x0A` |
|`PIMORONI_TRACKBALL_TIMEOUT` | (Optional) The timeout for i2c communication with the trackpad in milliseconds. | `100` | |`PIMORONI_TRACKBALL_TIMEOUT` | (Optional) The timeout for i2c communication with the trackball in milliseconds. | `100` |
|`PIMORONI_TRACKBALL_INTERVAL_MS` | (Optional) The update/read interval for the sensor in milliseconds. | `8` |
|`PIMORONI_TRACKBALL_SCALE` | (Optional) The multiplier used to generate reports from the sensor. | `5` | |`PIMORONI_TRACKBALL_SCALE` | (Optional) The multiplier used to generate reports from the sensor. | `5` |
|`PIMORONI_TRACKBALL_DEBOUNCE_CYCLES` | (Optional) The number of scan cycles used for debouncing on the ball press. | `20` | |`PIMORONI_TRACKBALL_DEBOUNCE_CYCLES` | (Optional) The number of scan cycles used for debouncing on the ball press. | `20` |
|`PIMORONI_TRACKBALL_ERROR_COUNT` | (Optional) Specifies the number of read/write errors until the sensor is disabled. | `10` | |`PIMORONI_TRACKBALL_ERROR_COUNT` | (Optional) Specifies the number of read/write errors until the sensor is disabled. | `10` |
@ -172,13 +171,34 @@ void pointing_device_driver_set_cpi(uint16_t cpi) {}
## Common Configuration ## Common Configuration
| Setting | Description | Default | | Setting | Description | Default |
|-------------------------------|-----------------------------------------------------------------------|---------------| |----------------------------------|-----------------------------------------------------------------------|-------------------|
|`POINTING_DEVICE_ROTATION_90` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ | |`POINTING_DEVICE_ROTATION_90` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ |
|`POINTING_DEVICE_ROTATION_180` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ | |`POINTING_DEVICE_ROTATION_180` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ |
|`POINTING_DEVICE_ROTATION_270` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ | |`POINTING_DEVICE_ROTATION_270` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ |
|`POINTING_DEVICE_INVERT_X` | (Optional) Inverts the X axis report. | _not defined_ | |`POINTING_DEVICE_INVERT_X` | (Optional) Inverts the X axis report. | _not defined_ |
|`POINTING_DEVICE_INVERT_Y` | (Optional) Inverts the Y axis report. | _not defined_ | |`POINTING_DEVICE_INVERT_Y` | (Optional) Inverts the Y axis report. | _not defined_ |
|`POINTING_DEVICE_MOTION_PIN` | (Optional) If supported, will only read from sensor if pin is active. | _not defined_ | |`POINTING_DEVICE_MOTION_PIN` | (Optional) If supported, will only read from sensor if pin is active. | _not defined_ |
|`POINTING_DEVICE_TASK_THROTTLE_MS` | (Optional) Limits the frequency that the sensor is polled for motion. | _not defined_ |
!> When using `SPLIT_POINTING_ENABLE` the `POINTING_DEVICE_MOTION_PIN` functionality is not supported and would recommend `POINTING_DEVICE_TASK_THROTTLE_MS` be set to `1`. Increasing this value will increase transport performance at the cost of possible mouse responsiveness.
## Split Keyboard Configuration
The following configuration options are only available when using `SPLIT_POINTING_ENABLE` see [data sync options](feature_split_keyboard.md?id=data-sync-options). The rotation and invert `*_RIGHT` options are only used with `POINTING_DEVICE_COMBINED`. If using `POINTING_DEVICE_LEFT` or `POINTING_DEVICE_RIGHT` use the common configuration above to configure your pointing device.
| Setting | Description | Default |
|----------------------------------------|-----------------------------------------------------------------------|---------------|
|`POINTING_DEVICE_LEFT` | Pointing device on the left side (Required - pick one only) | _not defined_ |
|`POINTING_DEVICE_RIGHT` | Pointing device on the right side (Required - pick one only) | _not defined_ |
|`POINTING_DEVICE_COMBINED` | Pointing device on both sides (Required - pick one only) | _not defined_ |
|`POINTING_DEVICE_ROTATION_90_RIGHT` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ |
|`POINTING_DEVICE_ROTATION_180_RIGHT` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ |
|`POINTING_DEVICE_ROTATION_270_RIGHT` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ |
|`POINTING_DEVICE_INVERT_X_RIGHT` | (Optional) Inverts the X axis report. | _not defined_ |
|`POINTING_DEVICE_INVERT_Y_RIGHT` | (Optional) Inverts the Y axis report. | _not defined_ |
!> If there is a `_RIGHT` configuration option or callback, the [common configuration](feature_pointing_device.md?id=common-configuration) option will work for the left. For correct left/right detection you should setup a [handedness option](feature_split_keyboard?id=setting-handedness), `EE_HANDS` is usually a good option for an existing board that doesn't do handedness by hardware.
## Callbacks and Functions ## Callbacks and Functions
@ -196,6 +216,21 @@ void pointing_device_driver_set_cpi(uint16_t cpi) {}
| `pointing_device_set_report(mouse_report)` | Sets the mouse report to the assigned `mouse_report_t` data structured passed to the function. | | `pointing_device_set_report(mouse_report)` | Sets the mouse report to the assigned `mouse_report_t` data structured passed to the function. |
| `pointing_device_send(void)` | Sends the current mouse report to the host system. Function can be replaced. | | `pointing_device_send(void)` | Sends the current mouse report to the host system. Function can be replaced. |
| `has_mouse_report_changed(old, new)` | Compares the old and new `mouse_report_t` data and returns true only if it has changed. | | `has_mouse_report_changed(old, new)` | Compares the old and new `mouse_report_t` data and returns true only if it has changed. |
| `pointing_device_adjust_by_defines(mouse_report)` | Applies rotations and invert configurations to a raw mouse report. |
## Split Keyboard Callbacks and Functions
The combined functions below are only available when using `SPLIT_POINTING_ENABLE` and `POINTING_DEVICE_COMBINED`. The 2 callbacks `pointing_device_task_combined_*` replace the single sided equivalents above. See the [combined pointing devices example](feature_pointing_device.md?id=combined-pointing-devices)
| Function | Description |
|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|
| `pointing_device_set_shared_report(mouse_report)` | Sets the shared mouse report to the assigned `mouse_report_t` data structured passed to the function. |
| `pointing_device_set_cpi_on_side(bool, uint16_t)` | Sets the CPI/DPI of one side, if supported. Passing `true` will set the left and `false` the right` |
| `pointing_device_combine_reports(left_report, right_report)` | Returns a combined mouse_report of left_report and right_report (as a `mouse_report_t` data structure) |
| `pointing_device_task_combined_kb(left_report, right_report)` | Callback, so keyboard code can intercept and modify the data. Returns a combined mouse report. |
| `pointing_device_task_combined_user(left_report, right_report)` | Callback, so user code can intercept and modify. Returns a combined mouse report using `pointing_device_combine_reports` |
| `pointing_device_adjust_by_defines_right(mouse_report)` | Applies right side rotations and invert configurations to a raw mouse report. |
# Manipulating Mouse Reports # Manipulating Mouse Reports
@ -242,3 +277,62 @@ case MS_SPECIAL:
``` ```
Recall that the mouse report is set to zero (except the buttons) whenever it is sent, so the scrolling would only occur once in each case. Recall that the mouse report is set to zero (except the buttons) whenever it is sent, so the scrolling would only occur once in each case.
## Split Examples
The following examples make use the `SPLIT_POINTING_ENABLE` functionality and show how to manipulate the mouse report for a scrolling mode.
### Single Pointing Device
The following example will work with either `POINTING_DEVICE_LEFT` or `POINTING_DEVICE_RIGHT` and enables scrolling mode while on a particular layer.
```c
static bool scrolling_mode = false;
layer_state_t layer_state_set_user(layer_state_t state) {
switch (get_highest_layer(state)) {
case _RAISE: // If we're on the _RAISE layer enable scrolling mode
scrolling_mode = true;
pointing_device_set_cpi(2000);
break;
default:
if (scrolling_mode) { // check if we were scrolling before and set disable if so
scrolling_mode = false;
pointing_device_set_cpi(8000);
}
break;
}
return state;
}
report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) {
if (scrolling_mode) {
mouse_report.h = mouse_report.x;
mouse_report.v = mouse_report.y;
mouse_report.x = 0;
mouse_report.y = 0;
}
return mouse_report;
}
```
### Combined Pointing Devices
The following example requires `POINTING_DEVICE_COMBINED` and sets the left side pointing device to scroll only.
```c
void keyboard_post_init_user(void) {
pointing_device_set_cpi_on_side(true, 1000); //Set cpi on left side to a low value for slower scrolling.
pointing_device_set_cpi_on_side(false, 8000); //Set cpi on right side to a reasonable value for mousing.
}
report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report) {
left_report.h = left_report.x;
left_report.v = left_report.y;
left_report.x = 0;
left_report.y = 0;
return pointing_device_combine_reports(left_report, right_report);
}
```

View file

@ -266,6 +266,14 @@ This enables transmitting the current OLED on/off status to the slave side of th
This enables transmitting the current ST7565 on/off status to the slave side of the split keyboard. The purpose of this feature is to support state (on/off state only) syncing. This enables transmitting the current ST7565 on/off status to the slave side of the split keyboard. The purpose of this feature is to support state (on/off state only) syncing.
```c
#define SPLIT_POINTING_ENABLE
```
This enables transmitting the pointing device status to the master side of the split keyboard. The purpose of this feature is to enable use pointing devices on the slave side.
!> There is additional required configuration for `SPLIT_POINTING_ENABLE` outlined in the [pointing device documentation](feature_pointing_device.md?id=split-keyboard-configuration).
### Custom data sync between sides :id=custom-data-sync ### Custom data sync between sides :id=custom-data-sync
QMK'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. QMK'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.

View file

@ -33,8 +33,24 @@
static uint16_t precision = 128; static uint16_t precision = 128;
float pimoroni_trackball_get_precision(void) { return ((float)precision / 128); } uint16_t pimoroni_trackball_get_cpi(void) { return (precision * 125); }
void pimoroni_trackball_set_precision(float floatprecision) { precision = (floatprecision * 128); } /**
* @brief Sets the scaling value for pimoroni trackball
*
* Sets a scaling value for pimoroni trackball to allow runtime adjustment. This isn't used by the sensor and is an
* approximation so the functions are consistent across drivers.
*
* NOTE: This rounds down to the nearest number divisable by 125 that's a positive integer, values below 125 are clamped to 125.
*
* @param cpi uint16_t
*/
void pimoroni_trackball_set_cpi(uint16_t cpi) {
if (cpi < 249) {
precision = 1;
} else {
precision = (cpi - (cpi % 125)) / 125;
}
}
void pimoroni_trackball_set_rgbw(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { void pimoroni_trackball_set_rgbw(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
uint8_t data[4] = {r, g, b, w}; uint8_t data[4] = {r, g, b, w};
@ -60,7 +76,7 @@ i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data) {
return status; return status;
} }
__attribute__((weak)) void pimironi_trackball_device_init(void) { __attribute__((weak)) void pimoroni_trackball_device_init(void) {
i2c_init(); i2c_init();
pimoroni_trackball_set_rgbw(0x00, 0x00, 0x00, 0x00); pimoroni_trackball_set_rgbw(0x00, 0x00, 0x00, 0x00);
} }

View file

@ -23,9 +23,6 @@
#ifndef PIMORONI_TRACKBALL_ADDRESS #ifndef PIMORONI_TRACKBALL_ADDRESS
# define PIMORONI_TRACKBALL_ADDRESS 0x0A # define PIMORONI_TRACKBALL_ADDRESS 0x0A
#endif #endif
#ifndef PIMORONI_TRACKBALL_INTERVAL_MS
# define PIMORONI_TRACKBALL_INTERVAL_MS 8
#endif
#ifndef PIMORONI_TRACKBALL_SCALE #ifndef PIMORONI_TRACKBALL_SCALE
# define PIMORONI_TRACKBALL_SCALE 5 # define PIMORONI_TRACKBALL_SCALE 5
#endif #endif
@ -52,10 +49,10 @@ typedef struct {
uint8_t click; uint8_t click;
} pimoroni_data_t; } pimoroni_data_t;
void pimironi_trackball_device_init(void); void pimoroni_trackball_device_init(void);
void pimoroni_trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white); void pimoroni_trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white);
int16_t pimoroni_trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale); int16_t pimoroni_trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale);
void pimoroni_trackball_adapt_values(int8_t* mouse, int16_t* offset); void pimoroni_trackball_adapt_values(int8_t* mouse, int16_t* offset);
float pimoroni_trackball_get_precision(void); uint16_t pimoroni_trackball_get_cpi(void);
void pimoroni_trackball_set_precision(float precision); void pimoroni_trackball_set_cpi(uint16_t cpi);
i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data); i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data);

View file

@ -18,24 +18,105 @@
#include "pointing_device.h" #include "pointing_device.h"
#include <string.h> #include <string.h>
#include "timer.h"
#ifdef MOUSEKEY_ENABLE #ifdef MOUSEKEY_ENABLE
# include "mousekey.h" # include "mousekey.h"
#endif #endif
#if (defined(POINTING_DEVICE_ROTATION_90) + defined(POINTING_DEVICE_ROTATION_180) + defined(POINTING_DEVICE_ROTATION_270)) > 1 #if (defined(POINTING_DEVICE_ROTATION_90) + defined(POINTING_DEVICE_ROTATION_180) + defined(POINTING_DEVICE_ROTATION_270)) > 1
# error More than one rotation selected. This is not supported. # error More than one rotation selected. This is not supported.
#endif #endif
#if defined(SPLIT_POINTING_ENABLE)
# include "transactions.h"
# include "keyboard.h"
static report_mouse_t mouseReport = {}; report_mouse_t shared_mouse_report = {};
uint16_t shared_cpi = 0;
/**
* @brief Sets the shared mouse report used be pointing device task
*
* NOTE : Only available when using SPLIT_POINTING_ENABLE
*
* @param[in] new_mouse_report report_mouse_t
*/
void pointing_device_set_shared_report(report_mouse_t new_mouse_report) { shared_mouse_report = new_mouse_report; }
/**
* @brief Gets current pointing device CPI if supported
*
* Gets current cpi of the shared report and returns it as uint16_t
*
* NOTE : Only available when using SPLIT_POINTING_ENABLE
*
* @return cpi value as uint16_t
*/
uint16_t pointing_device_get_shared_cpi(void) { return shared_cpi; }
# if defined(POINTING_DEVICE_LEFT)
# define POINTING_DEVICE_THIS_SIDE is_keyboard_left()
# elif defined(POINTING_DEVICE_RIGHT)
# define POINTING_DEVICE_THIS_SIDE !is_keyboard_left()
# elif defined(POINTING_DEVICE_COMBINED)
# define POINTING_DEVICE_THIS_SIDE true
# endif
#endif // defined(SPLIT_POINTING_ENABLE)
static report_mouse_t local_mouse_report = {};
extern const pointing_device_driver_t pointing_device_driver; extern const pointing_device_driver_t pointing_device_driver;
/**
* @brief Compares 2 mouse reports for difference and returns result
*
* @param[in] new report_mouse_t
* @param[in] old report_mouse_t
* @return bool result
*/
__attribute__((weak)) bool has_mouse_report_changed(report_mouse_t new, report_mouse_t old) { return memcmp(&new, &old, sizeof(new)); } __attribute__((weak)) bool has_mouse_report_changed(report_mouse_t new, report_mouse_t old) { return memcmp(&new, &old, sizeof(new)); }
/**
* @brief Keyboard level code pointing device initialisation
*
*/
__attribute__((weak)) void pointing_device_init_kb(void) {} __attribute__((weak)) void pointing_device_init_kb(void) {}
/**
* @brief User level code pointing device initialisation
*
*/
__attribute__((weak)) void pointing_device_init_user(void) {} __attribute__((weak)) void pointing_device_init_user(void) {}
/**
* @brief Weak function allowing for keyboard level mouse report modification
*
* Takes report_mouse_t struct allowing modification at keyboard level then returns report_mouse_t.
*
* @param[in] mouse_report report_mouse_t
* @return report_mouse_t
*/
__attribute__((weak)) report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { return pointing_device_task_user(mouse_report); } __attribute__((weak)) report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { return pointing_device_task_user(mouse_report); }
/**
* @brief Weak function allowing for user level mouse report modification
*
* Takes report_mouse_t struct allowing modification at user level then returns report_mouse_t.
*
* @param[in] mouse_report report_mouse_t
* @return report_mouse_t
*/
__attribute__((weak)) report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) { return mouse_report; } __attribute__((weak)) report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) { return mouse_report; }
/**
* @brief Handles pointing device buttons
*
* Returns modified button bitmask using bool pressed and selected pointing_device_buttons_t button in uint8_t buttons bitmask.
*
* @param buttons[in] uint8_t bitmask
* @param pressed[in] bool
* @param button[in] pointing_device_buttons_t value
* @return Modified uint8_t bitmask buttons
*/
__attribute__((weak)) uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button) { __attribute__((weak)) uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button) {
if (pressed) { if (pressed) {
buttons |= 1 << (button); buttons |= 1 << (button);
@ -45,7 +126,17 @@ __attribute__((weak)) uint8_t pointing_device_handle_buttons(uint8_t buttons, bo
return buttons; return buttons;
} }
/**
* @brief Initialises pointing device
*
* Initialises pointing device, perform driver init and optional keyboard/user level code.
*/
__attribute__((weak)) void pointing_device_init(void) { __attribute__((weak)) void pointing_device_init(void) {
#if defined(SPLIT_POINTING_ENABLE)
if (!(POINTING_DEVICE_THIS_SIDE)) {
return;
}
#endif
pointing_device_driver.init(); pointing_device_driver.init();
#ifdef POINTING_DEVICE_MOTION_PIN #ifdef POINTING_DEVICE_MOTION_PIN
setPinInputHigh(POINTING_DEVICE_MOTION_PIN); setPinInputHigh(POINTING_DEVICE_MOTION_PIN);
@ -54,67 +145,299 @@ __attribute__((weak)) void pointing_device_init(void) {
pointing_device_init_user(); pointing_device_init_user();
} }
/**
* @brief Sends processed mouse report to host
*
* This sends the mouse report generated by pointing_device_task if changed since the last report. Once send zeros mouse report except buttons.
*
*/
__attribute__((weak)) void pointing_device_send(void) { __attribute__((weak)) void pointing_device_send(void) {
static report_mouse_t old_report = {}; static report_mouse_t old_report = {};
// If you need to do other things, like debugging, this is the place to do it. // If you need to do other things, like debugging, this is the place to do it.
if (has_mouse_report_changed(mouseReport, old_report)) { if (has_mouse_report_changed(local_mouse_report, old_report)) {
host_mouse_send(&mouseReport); host_mouse_send(&local_mouse_report);
} }
// send it and 0 it out except for buttons, so those stay until they are explicity over-ridden using update_pointing_device // send it and 0 it out except for buttons, so those stay until they are explicity over-ridden using update_pointing_device
mouseReport.x = 0; local_mouse_report.x = 0;
mouseReport.y = 0; local_mouse_report.y = 0;
mouseReport.v = 0; local_mouse_report.v = 0;
mouseReport.h = 0; local_mouse_report.h = 0;
memcpy(&old_report, &mouseReport, sizeof(mouseReport)); memcpy(&old_report, &local_mouse_report, sizeof(local_mouse_report));
} }
__attribute__((weak)) void pointing_device_task(void) { /**
// Gather report info * @brief Adjust mouse report by any optional common pointing configuration defines
#ifdef POINTING_DEVICE_MOTION_PIN *
if (!readPin(POINTING_DEVICE_MOTION_PIN)) * This applies rotation or inversion to the mouse report as selected by the pointing device common configuration defines.
#endif *
mouseReport = pointing_device_driver.get_report(mouseReport); * @param mouse_report[in] takes a report_mouse_t to be adjusted
* @return report_mouse_t with adjusted values
*/
report_mouse_t pointing_device_adjust_by_defines(report_mouse_t mouse_report) {
// Support rotation of the sensor data // Support rotation of the sensor data
#if defined(POINTING_DEVICE_ROTATION_90) || defined(POINTING_DEVICE_ROTATION_180) || defined(POINTING_DEVICE_ROTATION_270) #if defined(POINTING_DEVICE_ROTATION_90) || defined(POINTING_DEVICE_ROTATION_180) || defined(POINTING_DEVICE_ROTATION_270)
int8_t x = mouseReport.x, y = mouseReport.y; int8_t x = mouse_report.x, y = mouse_report.y;
# if defined(POINTING_DEVICE_ROTATION_90) # if defined(POINTING_DEVICE_ROTATION_90)
mouseReport.x = y; mouse_report.x = y;
mouseReport.y = -x; mouse_report.y = -x;
# elif defined(POINTING_DEVICE_ROTATION_180) # elif defined(POINTING_DEVICE_ROTATION_180)
mouseReport.x = -x; mouse_report.x = -x;
mouseReport.y = -y; mouse_report.y = -y;
# elif defined(POINTING_DEVICE_ROTATION_270) # elif defined(POINTING_DEVICE_ROTATION_270)
mouseReport.x = -y; mouse_report.x = -y;
mouseReport.y = x; mouse_report.y = x;
# else # else
# error "How the heck did you get here?!" # error "How the heck did you get here?!"
# endif # endif
#endif #endif
// Support Inverting the X and Y Axises // Support Inverting the X and Y Axises
#if defined(POINTING_DEVICE_INVERT_X) #if defined(POINTING_DEVICE_INVERT_X)
mouseReport.x = -mouseReport.x; mouse_report.x = -mouse_report.x;
#endif #endif
#if defined(POINTING_DEVICE_INVERT_Y) #if defined(POINTING_DEVICE_INVERT_Y)
mouseReport.y = -mouseReport.y; mouse_report.y = -mouse_report.y;
#endif
return mouse_report;
}
/**
* @brief Retrieves and processes pointing device data.
*
* This function is part of the keyboard loop and retrieves the mouse report from the pointing device driver.
* It applies any optional configuration e.g. rotation or axis inversion and then initiates a send.
*
*/
__attribute__((weak)) void pointing_device_task(void) {
#if defined(SPLIT_POINTING_ENABLE)
// Don't poll the target side pointing device.
if (!is_keyboard_master()) {
return;
};
#endif #endif
#if defined(POINTING_DEVICE_TASK_THROTTLE_MS)
static uint32_t last_exec = 0;
if (timer_elapsed32(last_exec) < POINTING_DEVICE_TASK_THROTTLE_MS) {
return;
}
last_exec = timer_read32();
#else
# if defined(SPLIT_POINTING_ENABLE)
# pragma message("It's recommended you enable a throttle when sharing pointing devices.")
# endif
#endif
// Gather report info
#ifdef POINTING_DEVICE_MOTION_PIN
# if defined(SPLIT_POINTING_ENABLE)
# error POINTING_DEVICE_MOTION_PIN not supported when sharing the pointing device report between sides.
# endif
if (!readPin(POINTING_DEVICE_MOTION_PIN))
#endif
#if defined(SPLIT_POINTING_ENABLE)
# if defined(POINTING_DEVICE_COMBINED)
static uint8_t old_buttons = 0;
local_mouse_report.buttons = old_buttons;
local_mouse_report = pointing_device_driver.get_report(local_mouse_report);
old_buttons = local_mouse_report.buttons;
# elif defined(POINTING_DEVICE_LEFT) || defined(POINTING_DEVICE_RIGHT)
local_mouse_report = POINTING_DEVICE_THIS_SIDE ? pointing_device_driver.get_report(local_mouse_report) : shared_mouse_report;
# else
# error "You need to define the side(s) the pointing device is on. POINTING_DEVICE_COMBINED / POINTING_DEVICE_LEFT / POINTING_DEVICE_RIGHT"
# endif
#else
local_mouse_report = pointing_device_driver.get_report(local_mouse_report);
#endif // defined(SPLIT_POINTING_ENABLE)
// allow kb to intercept and modify report // allow kb to intercept and modify report
mouseReport = pointing_device_task_kb(mouseReport); #if defined(SPLIT_POINTING_ENABLE) && defined(POINTING_DEVICE_COMBINED)
if (is_keyboard_left()) {
local_mouse_report = pointing_device_adjust_by_defines(local_mouse_report);
shared_mouse_report = pointing_device_adjust_by_defines_right(shared_mouse_report);
} else {
local_mouse_report = pointing_device_adjust_by_defines_right(local_mouse_report);
shared_mouse_report = pointing_device_adjust_by_defines(shared_mouse_report);
}
local_mouse_report = is_keyboard_left() ? pointing_device_task_combined_kb(local_mouse_report, shared_mouse_report) : pointing_device_task_combined_kb(shared_mouse_report, local_mouse_report);
#else
local_mouse_report = pointing_device_adjust_by_defines(local_mouse_report);
local_mouse_report = pointing_device_task_kb(local_mouse_report);
#endif
// combine with mouse report to ensure that the combined is sent correctly // combine with mouse report to ensure that the combined is sent correctly
#ifdef MOUSEKEY_ENABLE #ifdef MOUSEKEY_ENABLE
report_mouse_t mousekey_report = mousekey_get_report(); report_mouse_t mousekey_report = mousekey_get_report();
mouseReport.buttons = mouseReport.buttons | mousekey_report.buttons; local_mouse_report.buttons = local_mouse_report.buttons | mousekey_report.buttons;
#endif #endif
pointing_device_send(); pointing_device_send();
} }
report_mouse_t pointing_device_get_report(void) { return mouseReport; } /**
* @brief Gets current mouse report used by pointing device task
*
* @return report_mouse_t
*/
report_mouse_t pointing_device_get_report(void) { return local_mouse_report; }
void pointing_device_set_report(report_mouse_t newMouseReport) { mouseReport = newMouseReport; } /**
* @brief Sets mouse report used be pointing device task
*
* @param[in] new_mouse_report
*/
void pointing_device_set_report(report_mouse_t new_mouse_report) { local_mouse_report = new_mouse_report; }
uint16_t pointing_device_get_cpi(void) { return pointing_device_driver.get_cpi(); } /**
* @brief Gets current pointing device CPI if supported
*
* Gets current cpi from pointing device driver if supported and returns it as uint16_t
*
* @return cpi value as uint16_t
*/
uint16_t pointing_device_get_cpi(void) {
#if defined(SPLIT_POINTING_ENABLE)
return POINTING_DEVICE_THIS_SIDE ? pointing_device_driver.get_cpi() : shared_cpi;
#else
return pointing_device_driver.get_cpi();
#endif
}
void pointing_device_set_cpi(uint16_t cpi) { pointing_device_driver.set_cpi(cpi); } /**
* @brief Set pointing device CPI if supported
*
* Takes a uint16_t value to set pointing device cpi if supported by driver.
*
* @param[in] cpi uint16_t value.
*/
void pointing_device_set_cpi(uint16_t cpi) {
#if defined(SPLIT_POINTING_ENABLE)
if (POINTING_DEVICE_THIS_SIDE) {
pointing_device_driver.set_cpi(cpi);
} else {
shared_cpi = cpi;
}
#else
pointing_device_driver.set_cpi(cpi);
#endif
}
#if defined(SPLIT_POINTING_ENABLE) && defined(POINTING_DEVICE_COMBINED)
/**
* @brief Set pointing device CPI if supported
*
* Takes a bool and uint16_t and allows setting cpi for a single side when using 2 pointing devices with a split keyboard.
*
* NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED
*
* @param[in] left true = left, false = right.
* @param[in] cpi uint16_t value.
*/
void pointing_device_set_cpi_on_side(bool left, uint16_t cpi) {
bool local = (is_keyboard_left() & left) ? true : false;
if (local) {
pointing_device_driver.set_cpi(cpi);
} else {
shared_cpi = cpi;
}
}
/**
* @brief clamps int16_t to int8_t
*
* @param[in] int16_t value
* @return int8_t clamped value
*/
static inline int8_t pointing_device_movement_clamp(int16_t value) {
if (value < INT8_MIN) {
return INT8_MIN;
} else if (value > INT8_MAX) {
return INT8_MAX;
} else {
return value;
}
}
/**
* @brief combines 2 mouse reports and returns 2
*
* Combines 2 report_mouse_t structs, clamping movement values to int8_t and ignores report_id then returns the resulting report_mouse_t struct.
*
* NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED
*
* @param[in] left_report left report_mouse_t
* @param[in] right_report right report_mouse_t
* @return combined report_mouse_t of left_report and right_report
*/
report_mouse_t pointing_device_combine_reports(report_mouse_t left_report, report_mouse_t right_report) {
left_report.x = pointing_device_movement_clamp((int16_t)left_report.x + right_report.x);
left_report.y = pointing_device_movement_clamp((int16_t)left_report.y + right_report.y);
left_report.h = pointing_device_movement_clamp((int16_t)left_report.h + right_report.h);
left_report.v = pointing_device_movement_clamp((int16_t)left_report.v + right_report.v);
left_report.buttons |= right_report.buttons;
return left_report;
}
/**
* @brief Adjust mouse report by any optional right pointing configuration defines
*
* This applies rotation or inversion to the mouse report as selected by the pointing device common configuration defines.
*
* NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED
*
* @param[in] mouse_report report_mouse_t to be adjusted
* @return report_mouse_t with adjusted values
*/
report_mouse_t pointing_device_adjust_by_defines_right(report_mouse_t mouse_report) {
// Support rotation of the sensor data
# if defined(POINTING_DEVICE_ROTATION_90_RIGHT) || defined(POINTING_DEVICE_ROTATION_RIGHT) || defined(POINTING_DEVICE_ROTATION_RIGHT)
int8_t x = mouse_report.x, y = mouse_report.y;
# if defined(POINTING_DEVICE_ROTATION_90_RIGHT)
mouse_report.x = y;
mouse_report.y = -x;
# elif defined(POINTING_DEVICE_ROTATION_180_RIGHT)
mouse_report.x = -x;
mouse_report.y = -y;
# elif defined(POINTING_DEVICE_ROTATION_270_RIGHT)
mouse_report.x = -y;
mouse_report.y = x;
# else
# error "How the heck did you get here?!"
# endif
# endif
// Support Inverting the X and Y Axises
# if defined(POINTING_DEVICE_INVERT_X_RIGHT)
mouse_report.x = -mouse_report.x;
# endif
# if defined(POINTING_DEVICE_INVERT_Y_RIGHT)
mouse_report.y = -mouse_report.y;
# endif
return mouse_report;
}
/**
* @brief Weak function allowing for keyboard level mouse report modification
*
* Takes 2 report_mouse_t structs allowing individual modification of sides at keyboard level then returns pointing_device_task_combined_user.
*
* NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED
*
* @param[in] left_report report_mouse_t
* @param[in] right_report report_mouse_t
* @return pointing_device_task_combined_user(left_report, right_report) by default
*/
__attribute__((weak)) report_mouse_t pointing_device_task_combined_kb(report_mouse_t left_report, report_mouse_t right_report) { return pointing_device_task_combined_user(left_report, right_report); }
/**
* @brief Weak function allowing for user level mouse report modification
*
* Takes 2 report_mouse_t structs allowing individual modification of sides at user level then returns pointing_device_combine_reports.
*
* NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED
*
* @param[in] left_report report_mouse_t
* @param[in] right_report report_mouse_t
* @return pointing_device_combine_reports(left_report, right_report) by default
*/
__attribute__((weak)) report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report) { return pointing_device_combine_reports(left_report, right_report); }
#endif

View file

@ -86,3 +86,16 @@ void pointing_device_init_user(void);
report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report); report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report);
report_mouse_t pointing_device_task_user(report_mouse_t mouse_report); report_mouse_t pointing_device_task_user(report_mouse_t mouse_report);
uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button); uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button);
report_mouse_t pointing_device_adjust_by_defines(report_mouse_t mouse_report);
#if defined(SPLIT_POINTING_ENABLE)
void pointing_device_set_shared_report(report_mouse_t report);
uint16_t pointing_device_get_shared_cpi(void);
# if defined(POINTING_DEVICE_COMBINED)
void pointing_device_set_cpi_on_side(bool left, uint16_t cpi);
report_mouse_t pointing_device_combine_reports(report_mouse_t left_report, report_mouse_t right_report);
report_mouse_t pointing_device_task_combined_kb(report_mouse_t left_report, report_mouse_t right_report);
report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report);
report_mouse_t pointing_device_adjust_by_defines_right(report_mouse_t mouse_report);
# endif //defined(POINTING_DEVICE_COMBINED)
#endif //defined(SPLIT_POINTING_ENABLE)

View file

@ -165,14 +165,13 @@ const pointing_device_driver_t pointing_device_driver = {
// clang-format on // clang-format on
#elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball) #elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball)
report_mouse_t pimorono_trackball_get_report(report_mouse_t mouse_report) { report_mouse_t pimoroni_trackball_get_report(report_mouse_t mouse_report) {
static fast_timer_t throttle = 0;
static uint16_t debounce = 0; static uint16_t debounce = 0;
static uint8_t error_count = 0; static uint8_t error_count = 0;
pimoroni_data_t pimoroni_data = {0}; pimoroni_data_t pimoroni_data = {0};
static int16_t x_offset = 0, y_offset = 0; static int16_t x_offset = 0, y_offset = 0;
if (error_count < PIMORONI_TRACKBALL_ERROR_COUNT && timer_elapsed_fast(throttle) >= PIMORONI_TRACKBALL_INTERVAL_MS) { if (error_count < PIMORONI_TRACKBALL_ERROR_COUNT) {
i2c_status_t status = read_pimoroni_trackball(&pimoroni_data); i2c_status_t status = read_pimoroni_trackball(&pimoroni_data);
if (status == I2C_STATUS_SUCCESS) { if (status == I2C_STATUS_SUCCESS) {
@ -195,17 +194,16 @@ report_mouse_t pimorono_trackball_get_report(report_mouse_t mouse_report) {
} else { } else {
error_count++; error_count++;
} }
throttle = timer_read_fast();
} }
return mouse_report; return mouse_report;
} }
// clang-format off // clang-format off
const pointing_device_driver_t pointing_device_driver = { const pointing_device_driver_t pointing_device_driver = {
.init = pimironi_trackball_device_init, .init = pimoroni_trackball_device_init,
.get_report = pimorono_trackball_get_report, .get_report = pimoroni_trackball_get_report,
.set_cpi = NULL, .set_cpi = pimoroni_trackball_set_cpi,
.get_cpi = NULL .get_cpi = pimoroni_trackball_get_cpi
}; };
// clang-format on // clang-format on
#elif defined(POINTING_DEVICE_DRIVER_pmw3360) #elif defined(POINTING_DEVICE_DRIVER_pmw3360)

View file

@ -78,6 +78,12 @@ enum serial_transaction_id {
PUT_ST7565, PUT_ST7565,
#endif // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE) #endif // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)
#if defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
GET_POINTING_CHECKSUM,
GET_POINTING_DATA,
PUT_POINTING_CPI,
#endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
PUT_RPC_INFO, PUT_RPC_INFO,
PUT_RPC_REQ_DATA, PUT_RPC_REQ_DATA,

View file

@ -578,6 +578,82 @@ static void st7565_handlers_slave(matrix_row_t master_matrix[], matrix_row_t sla
#endif // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE) #endif // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)
////////////////////////////////////////////////////
// POINTING
#if defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
static bool pointing_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
# if defined(POINTING_DEVICE_LEFT)
if (is_keyboard_left()) {
return true;
}
# elif defined(POINTING_DEVICE_RIGHT)
if (!is_keyboard_left()) {
return true;
}
# endif
static uint32_t last_update = 0;
static uint16_t last_cpi = 0;
report_mouse_t temp_state;
uint16_t temp_cpi;
bool okay = read_if_checksum_mismatch(GET_POINTING_CHECKSUM, GET_POINTING_DATA, &last_update, &temp_state, &split_shmem->pointing.report, sizeof(temp_state));
if (okay) pointing_device_set_shared_report(temp_state);
temp_cpi = pointing_device_get_shared_cpi();
if (temp_cpi && memcmp(&last_cpi, &temp_cpi, sizeof(temp_cpi)) != 0) {
memcpy(&split_shmem->pointing.cpi, &temp_cpi, sizeof(temp_cpi));
okay = transport_write(PUT_POINTING_CPI, &split_shmem->pointing.cpi, sizeof(split_shmem->pointing.cpi));
if (okay) {
last_cpi = temp_cpi;
}
}
return okay;
}
extern const pointing_device_driver_t pointing_device_driver;
static void pointing_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
# if defined(POINTING_DEVICE_LEFT)
if (!is_keyboard_left()) {
return;
}
# elif defined(POINTING_DEVICE_RIGHT)
if (is_keyboard_left()) {
return;
}
# endif
report_mouse_t temp_report;
uint16_t temp_cpi;
# ifdef POINTING_DEVICE_TASK_THROTTLE_MS
static uint32_t last_exec = 0;
if (timer_elapsed32(last_exec) < POINTING_DEVICE_TASK_THROTTLE_MS) {
return;
}
last_exec = timer_read32();
# endif
temp_cpi = pointing_device_driver.get_cpi();
if (split_shmem->pointing.cpi && memcmp(&split_shmem->pointing.cpi, &temp_cpi, sizeof(temp_cpi)) != 0) {
pointing_device_driver.set_cpi(split_shmem->pointing.cpi);
}
memset(&temp_report, 0, sizeof(temp_report));
temp_report = pointing_device_driver.get_report(temp_report);
memcpy(&split_shmem->pointing.report, &temp_report, sizeof(temp_report));
// Now update the checksum given that the pointing has been written to
split_shmem->pointing.checksum = crc8(&temp_report, sizeof(temp_report));
}
# define TRANSACTIONS_POINTING_MASTER() TRANSACTION_HANDLER_MASTER(pointing)
# define TRANSACTIONS_POINTING_SLAVE() TRANSACTION_HANDLER_SLAVE(pointing)
# 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),
#else // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
# define TRANSACTIONS_POINTING_MASTER()
# define TRANSACTIONS_POINTING_SLAVE()
# define TRANSACTIONS_POINTING_REGISTRATIONS
#endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
uint8_t dummy; uint8_t dummy;
@ -604,6 +680,7 @@ split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = {
TRANSACTIONS_WPM_REGISTRATIONS TRANSACTIONS_WPM_REGISTRATIONS
TRANSACTIONS_OLED_REGISTRATIONS TRANSACTIONS_OLED_REGISTRATIONS
TRANSACTIONS_ST7565_REGISTRATIONS TRANSACTIONS_ST7565_REGISTRATIONS
TRANSACTIONS_POINTING_REGISTRATIONS
// clang-format on // clang-format on
#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
@ -629,6 +706,7 @@ bool transactions_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix
TRANSACTIONS_WPM_MASTER(); TRANSACTIONS_WPM_MASTER();
TRANSACTIONS_OLED_MASTER(); TRANSACTIONS_OLED_MASTER();
TRANSACTIONS_ST7565_MASTER(); TRANSACTIONS_ST7565_MASTER();
TRANSACTIONS_POINTING_MASTER();
return true; return true;
} }
@ -647,6 +725,7 @@ void transactions_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[
TRANSACTIONS_WPM_SLAVE(); TRANSACTIONS_WPM_SLAVE();
TRANSACTIONS_OLED_SLAVE(); TRANSACTIONS_OLED_SLAVE();
TRANSACTIONS_ST7565_SLAVE(); TRANSACTIONS_ST7565_SLAVE();
TRANSACTIONS_POINTING_SLAVE();
} }
#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)

View file

@ -106,6 +106,15 @@ typedef struct _split_mods_sync_t {
} split_mods_sync_t; } split_mods_sync_t;
#endif // SPLIT_MODS_ENABLE #endif // SPLIT_MODS_ENABLE
#if defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
# include "pointing_device.h"
typedef struct _split_slave_pointing_sync_t {
uint8_t checksum;
report_mouse_t report;
uint16_t cpi;
} split_slave_pointing_sync_t;
#endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
typedef struct _rpc_sync_info_t { typedef struct _rpc_sync_info_t {
int8_t transaction_id; int8_t transaction_id;
@ -173,6 +182,10 @@ typedef struct _split_shared_memory_t {
uint8_t current_st7565_state; uint8_t current_st7565_state;
#endif // ST7565_ENABLE(OLED_ENABLE) && defined(SPLIT_ST7565_ENABLE) #endif // ST7565_ENABLE(OLED_ENABLE) && defined(SPLIT_ST7565_ENABLE)
#if defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
split_slave_pointing_sync_t pointing;
#endif // defined(POINTING_DEVICE_ENABLE) && defined(SPLIT_POINTING_ENABLE)
#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) #if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
rpc_sync_info_t rpc_info; rpc_sync_info_t rpc_info;
uint8_t rpc_m2s_buffer[RPC_M2S_BUFFER_SIZE]; uint8_t rpc_m2s_buffer[RPC_M2S_BUFFER_SIZE];