aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common_features.mk39
-rw-r--r--docs/feature_pointing_device.md202
-rw-r--r--drivers/sensors/adns5050.c157
-rw-r--r--drivers/sensors/adns5050.h75
-rw-r--r--drivers/sensors/adns9800.c175
-rw-r--r--drivers/sensors/adns9800.h42
-rw-r--r--drivers/sensors/adns9800_srom_A6.h2
-rw-r--r--drivers/sensors/analog_joystick.c94
-rw-r--r--drivers/sensors/analog_joystick.h51
-rw-r--r--drivers/sensors/cirque_pinnacle.c232
-rw-r--r--drivers/sensors/cirque_pinnacle.h74
-rw-r--r--drivers/sensors/cirque_pinnacle_i2c.c43
-rw-r--r--drivers/sensors/cirque_pinnacle_spi.c52
-rw-r--r--drivers/sensors/pimoroni_trackball.c187
-rw-r--r--drivers/sensors/pimoroni_trackball.h48
-rw-r--r--drivers/sensors/pmw3360.c140
-rw-r--r--drivers/sensors/pmw3360.h38
-rw-r--r--drivers/sensors/pmw3360_firmware.h5
-rw-r--r--drivers/sensors/pmw3389_firmware.h303
-rw-r--r--keyboards/40percentclub/nano/keymaps/drashna/config.h (renamed from keyboards/oddball/pmw/pmw.h)21
-rw-r--r--keyboards/40percentclub/nano/keymaps/drashna/keymap.c95
-rw-r--r--keyboards/40percentclub/nano/keymaps/drashna/rules.mk11
-rw-r--r--keyboards/handwired/tractyl_manuform/5x6_right/config.h1
-rw-r--r--keyboards/handwired/tractyl_manuform/5x6_right/keymaps/drashna/keymap.c11
-rw-r--r--keyboards/handwired/tractyl_manuform/5x6_right/rules.mk4
-rw-r--r--keyboards/handwired/tractyl_manuform/tm_sync.c3
-rw-r--r--keyboards/handwired/tractyl_manuform/tractyl_manuform.c81
-rw-r--r--keyboards/oddball/config.h3
-rw-r--r--keyboards/oddball/keymaps/default/config.h1
-rw-r--r--keyboards/oddball/keymaps/default/rules.mk1
-rw-r--r--keyboards/oddball/keymaps/pmw3360/config.h1
-rw-r--r--keyboards/oddball/keymaps/pmw3360/rules.mk1
-rw-r--r--keyboards/oddball/oddball.c54
-rw-r--r--keyboards/oddball/optical_sensor/optical_sensor.h53
-rw-r--r--keyboards/oddball/pmw/pmw.c226
-rw-r--r--keyboards/oddball/pmw/pmw3360_srom_0x04.h280
-rw-r--r--keyboards/oddball/rules.mk4
-rw-r--r--keyboards/ploopyco/mouse/mouse.c117
-rw-r--r--keyboards/ploopyco/mouse/mouse.h6
-rw-r--r--keyboards/ploopyco/mouse/rules.mk5
-rw-r--r--keyboards/ploopyco/trackball/rules.mk5
-rw-r--r--keyboards/ploopyco/trackball/trackball.c105
-rw-r--r--keyboards/ploopyco/trackball/trackball.h6
-rw-r--r--keyboards/ploopyco/trackball_mini/config.h6
-rw-r--r--keyboards/ploopyco/trackball_mini/keymaps/drag_scroll/keymap.c2
-rw-r--r--keyboards/ploopyco/trackball_mini/rules.mk6
-rw-r--r--keyboards/ploopyco/trackball_mini/trackball_mini.c108
-rw-r--r--keyboards/ploopyco/trackball_mini/trackball_mini.h5
-rw-r--r--keyboards/ploopyco/trackball_nano/config.h6
-rw-r--r--keyboards/ploopyco/trackball_nano/keymaps/maddie/keymap.c22
-rw-r--r--keyboards/ploopyco/trackball_nano/rules.mk7
-rw-r--r--keyboards/ploopyco/trackball_nano/trackball_nano.c116
-rw-r--r--keyboards/ploopyco/trackball_nano/trackball_nano.h13
-rw-r--r--keyboards/tkw/grandiceps/rev2/rules.mk3
-rw-r--r--layouts/community/ergodox/drashna/keymap.c32
-rw-r--r--quantum/pointing_device.c123
-rw-r--r--quantum/pointing_device.h59
-rw-r--r--quantum/pointing_device_drivers.c262
-rw-r--r--quantum/quantum.c4
-rw-r--r--quantum/quantum.h4
60 files changed, 2117 insertions, 1715 deletions
diff --git a/common_features.mk b/common_features.mk
index 7abdce302..896fbb012 100644
--- a/common_features.mk
+++ b/common_features.mk
@@ -107,10 +107,43 @@ ifeq ($(strip $(MOUSEKEY_ENABLE)), yes)
107 SRC += $(QUANTUM_DIR)/mousekey.c 107 SRC += $(QUANTUM_DIR)/mousekey.c
108endif 108endif
109 109
110VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick cirque_pinnacle_i2c cirque_pinnacle_spi pmw3360 pimoroni_trackball custom
111POINTING_DEVICE_DRIVER ?= custom
110ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes) 112ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
111 OPT_DEFS += -DPOINTING_DEVICE_ENABLE 113 ifeq ($(filter $(POINTING_DEVICE_DRIVER),$(VALID_POINTING_DEVICE_DRIVER_TYPES)),)
112 MOUSE_ENABLE := yes 114 $(error POINTING_DEVICE_DRIVER="$(POINTING_DEVICE_DRIVER)" is not a valid pointing device type)
113 SRC += $(QUANTUM_DIR)/pointing_device.c 115 else
116 OPT_DEFS += -DPOINTING_DEVICE_ENABLE
117 MOUSE_ENABLE := yes
118 SRC += $(QUANTUM_DIR)/pointing_device.c
119 SRC += $(QUANTUM_DIR)/pointing_device_drivers.c
120 ifneq ($(strip $(POINTING_DEVICE_DRIVER)), custom)
121 SRC += drivers/sensors/$(strip $(POINTING_DEVICE_DRIVER)).c
122 OPT_DEFS += -DPOINTING_DEVICE_DRIVER_$(strip $(shell echo $(POINTING_DEVICE_DRIVER) | tr '[:lower:]' '[:upper:]'))
123 endif
124 OPT_DEFS += -DPOINTING_DEVICE_DRIVER_$(strip $(POINTING_DEVICE_DRIVER))
125 ifeq ($(strip $(POINTING_DEVICE_DRIVER)), adns9800)
126 OPT_DEFS += -DSTM32_SPI -DHAL_USE_SPI=TRUE
127 QUANTUM_LIB_SRC += spi_master.c
128 else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), analog_joystick)
129 OPT_DEFS += -DSTM32_ADC -DHAL_USE_ADC=TRUE
130 LIB_SRC += analog.c
131 else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), cirque_pinnacle_i2c)
132 OPT_DEFS += -DSTM32_I2C -DHAL_USE_I2C=TRUE
133 SRC += drivers/sensors/cirque_pinnacle.c
134 QUANTUM_LIB_SRC += i2c_master.c
135 else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), cirque_pinnacle_spi)
136 OPT_DEFS += -DSTM32_SPI -DHAL_USE_SPI=TRUE
137 SRC += drivers/sensors/cirque_pinnacle.c
138 QUANTUM_LIB_SRC += spi_master.c
139 else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), pimoroni_trackball)
140 OPT_DEFS += -DSTM32_SPI -DHAL_USE_I2C=TRUE
141 QUANTUM_LIB_SRC += i2c_master.c
142 else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), pmw3360)
143 OPT_DEFS += -DSTM32_SPI -DHAL_USE_SPI=TRUE
144 QUANTUM_LIB_SRC += spi_master.c
145 endif
146 endif
114endif 147endif
115 148
116VALID_EEPROM_DRIVER_TYPES := vendor custom transient i2c spi 149VALID_EEPROM_DRIVER_TYPES := vendor custom transient i2c spi
diff --git a/docs/feature_pointing_device.md b/docs/feature_pointing_device.md
index badeadc12..031ee52c1 100644
--- a/docs/feature_pointing_device.md
+++ b/docs/feature_pointing_device.md
@@ -1,6 +1,6 @@
1# Pointing Device :id=pointing-device 1# Pointing Device :id=pointing-device
2 2
3Pointing Device is a generic name for a feature intended to be generic: moving the system pointer around. There are certainly other options for it - like mousekeys - but this aims to be easily modifiable and lightweight. You can implement custom keys to control functionality, or you can gather information from other peripherals and insert it directly here - let QMK handle the processing for you. 3Pointing Device is a generic name for a feature intended to be generic: moving the system pointer around. There are certainly other options for it - like mousekeys - but this aims to be easily modifiable and hardware driven. You can implement custom keys to control functionality, or you can gather information from other peripherals and insert it directly here - let QMK handle the processing for you.
4 4
5To enable Pointing Device, uncomment the following line in your rules.mk: 5To enable Pointing Device, uncomment the following line in your rules.mk:
6 6
@@ -8,12 +8,198 @@ To enable Pointing Device, uncomment the following line in your rules.mk:
8POINTING_DEVICE_ENABLE = yes 8POINTING_DEVICE_ENABLE = yes
9``` 9```
10 10
11To manipulate the mouse report, you can use the following functions: 11## Sensor Drivers
12
13There are a number of sensors that are supported by default. Note that only one sensor can be enabled by `POINTING_DEVICE_DRIVER` at a time. If you need to enable more than one sensor, then you need to implement it manually.
14
15### ADNS 5050 Sensor
16
17To use the ADNS 5050 sensor, add this to your `rules.mk`
18
19```make
20POINTING_DEVICE_DRIVER = adns5050
21```
22
23The ADNS 5050 sensor uses a serial type protocol for communication, and requires an additional light source.
24
25| Setting | Description |
26|--------------------|---------------------------------------------------------------------|
27|`ADNS5050_SCLK_PIN` | (Required) The pin connected to the clock pin of the sensor. |
28|`ADNS5050_SDIO_PIN` | (Required) The pin connected to the data pin of the sensor. |
29|`ADNS5050_CS_PIN` | (Required) The pin connected to the cable select pin of the sensor. |
30
31The CPI range is 125-1375, in increments of 125. Defaults to 500 CPI.
32
33### ADSN 9800 Sensor
34
35To use the ADNS 9800 sensor, add this to your `rules.mk`
36
37```make
38POINTING_DEVICE_DRIVER = adns9800
39```
40
41The ADNS 9800 is an SPI driven optical sensor, that uses laser output for surface tracking.
42
43| Setting | Description | Default |
44|------------------------|------------------------------------------------------------------------|---------------|
45|`ADNS9800_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `2000000` |
46|`ADNS9800_SPI_LSBFIRST` | (Optional) Sets the Least/Most Significant Byte First setting for SPI. | `false` |
47|`ADNS9800_SPI_MODE` | (Optional) Sets the SPI Mode for the sensor. | `3` |
48|`ADNS9800_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ |
49|`ADNS9800_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ |
50
51
52The CPI range is 800-8200, in increments of 200. Defaults to 1800 CPI.
53
54### Analog Joystick
55
56To use an analog joystick to control the pointer, add this to your `rules.mk`
57
58```make
59POINTING_DEVICE_DRIVER = analog_joystick
60```
61
62The Analog Joystick is an analog (ADC) driven sensor. There are a variety of joysticks that you can use for this.
63
64| Setting | Description | Default |
65|----------------------------------|----------------------------------------------------------------------------|---------------|
66|`ANALOG_JOYSTICK_X_AXIS_PIN` | (Required) The pin used for the vertical/X axis. | _not defined_ |
67|`ANALOG_JOYSTICK_Y_AXIS_PIN` | (Required) The pin used for the horizontal/Y axis. | _not defined_ |
68|`ANALOG_JOYSTICK_AXIS_MIN` | (Optional) Sets the lower range to be considered movement. | `0` |
69|`ANALOG_JOYSTICK_AXIS_MAX` | (Optional) Sets the upper range to be considered movement. | `1023` |
70|`ANALOG_JOYSTICK_SPEED_REGULATOR` | (Optional) The divisor used to slow down movement. (lower makes it faster) | `20` |
71|`ANALOG_JOYSTICK_READ_INTERVAL` | (Optional) The interval in milliseconds between reads. | `10` |
72|`ANALOG_JOYSTICK_SPEED_MAX` | (Optional) The maxiumum value used for motion. | `2` |
73|`ANALOG_JOYSTICK_CLICK_PIN` | (Optional) The pin wired up to the press switch of the analog stick. | _not defined_ |
74
75
76### Cirque Trackpad
77
78To use the Cirque Trackpad sensor, add this to your `rules.mk`:
79
80```make
81POINTING_DEVICE_DRIVER = cirque_pinnacle_i2c
82```
83
84or
85
86```make
87POINTING_DEVICE_DRIVER = cirque_pinnacle_spi
88```
12 89
13* `pointing_device_get_report()` - Returns the current report_mouse_t that represents the information sent to the host computer
14* `pointing_device_set_report(report_mouse_t newMouseReport)` - Overrides and saves the report_mouse_t to be sent to the host computer
15 90
16Keep in mind that a report_mouse_t (here "mouseReport") has the following properties: 91This supports the Cirque Pinnacle 1CA027 Touch Controller, which is used in the TM040040, TM035035 and the TM023023 trackpads. These are I2C or SPI compatible, and both configurations are supported.
92
93| Setting | Description | Default |
94|---------------------------------|---------------------------------------------------------------------------------|-----------------------|
95|`CIRQUE_PINNACLE_X_LOWER` | (Optional) The minimum reachable X value on the sensor. | `127` |
96|`CIRQUE_PINNACLE_X_UPPER` | (Optional) The maximum reachable X value on the sensor. | `1919` |
97|`CIRQUE_PINNACLE_Y_LOWER` | (Optional) The minimum reachable Y value on the sensor. | `63` |
98|`CIRQUE_PINNACLE_Y_UPPER` | (Optional) The maximum reachable Y value on the sensor. | `1471` |
99|`CIRQUE_PINNACLE_TAPPING_TERM` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` |
100|`CIRQUE_PINNACLE_TOUCH_DEBOUNCE` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` |
101
102| I2C Setting | Description | Default |
103|--------------------------|---------------------------------------------------------------------------------|---------|
104|`CIRQUE_PINNACLE_ADDR` | (Required) Sets the I2C Address for the Cirque Trackpad | `0x2A` |
105|`CIRQUE_PINNACLE_TIMEOUT` | (Optional) The timeout for i2c communication with the trackpad in milliseconds. | `20` |
106
107| SPI Setting | Description | Default |
108|-------------------------------|------------------------------------------------------------------------|---------------|
109|`CIRQUE_PINNACLE_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `1000000` |
110|`CIRQUE_PINNACLE_SPI_LSBFIRST` | (Optional) Sets the Least/Most Significant Byte First setting for SPI. | `false` |
111|`CIRQUE_PINNACLE_SPI_MODE` | (Optional) Sets the SPI Mode for the sensor. | `1` |
112|`CIRQUE_PINNACLE_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ |
113|`CIRQUE_PINNACLE_SPI_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ |
114
115Default Scaling/CPI is 1024.
116
117### Pimoroni Trackball
118
119To use the Pimoroni Trackball module, add this to your `rules.mk`:
120
121```make
122POINTING_DEVICE_DRIVER = pimoroni_trackball
123```
124
125The Pimoroni Trackball module is a I2C based breakout board with an RGB enable trackball.
126
127| Setting | Description | Default |
128|-------------------------------------|------------------------------------------------------------------------------------|---------|
129|`PIMORONI_TRACKBALL_ADDRESS` | (Required) Sets the I2C Address for the Pimoroni Trackball. | `0x0A` |
130|`PIMORONI_TRACKBALL_TIMEOUT` | (Optional) The timeout for i2c communication with the trackpad in milliseconds. | `100` |
131|`PIMORONI_TRACKBALL_INTERVAL_MS` | (Optional) The update/read interval for the sensor in milliseconds. | `8` |
132|`PIMORONI_TRACKBALL_SCALE` | (Optional) The multiplier used to generate reports from the sensor. | `5` |
133|`PIMORONI_TRACKBALL_DEBOUNCE_CYCLES` | (Optional) The number of scan cycles used for debouncing on the ball press. | `20` |
134|`PIMORONI_TRACKBALL_ERROR_COUNT` | (Optional) Specifies the number of read/write errors until the sensor is disabled. | `10` |
135
136### PMW 3360 Sensor
137
138To use the PMW 3360 sensor, add this to your `rules.mk`
139
140```make
141POINTING_DEVICE_DRIVER = pmw3360
142```
143
144The PMW 3360 is an SPI driven optical sensor, that uses a built in IR LED for surface tracking.
145
146| Setting | Description | Default |
147|-----------------------------|--------------------------------------------------------------------------------------------|---------------|
148|`PMW3360_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ |
149|`PMW3360_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `2000000` |
150|`PMW3360_SPI_LSBFIRST` | (Optional) Sets the Least/Most Significant Byte First setting for SPI. | `false` |
151|`PMW3360_SPI_MODE` | (Optional) Sets the SPI Mode for the sensor. | `3` |
152|`PMW3360_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ |
153|`ROTATIONAL_TRANSFORM_ANGLE` | (Optional) Allows for the sensor data to be rotated +/- 30 degrees directly in the sensor. | `0` |
154
155The CPI range is 100-12000, in increments of 100. Defaults to 1600 CPI.
156
157
158### Custom Driver
159
160If you have a sensor type that isn't supported here, you can manually implement it, by adding these functions (with the correct implementation for your device):
161
162```c
163void pointing_device_driver_init(void) {}
164report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report) { return mouse_report; }
165uint16_t pointing_device_driver_get_cpi(void) { return 0; }
166void pointing_device_driver_set_cpi(uint16_t cpi) {}
167```
168
169!> Ideally, new sensor hardware should be added to `drivers/sensors/` and `quantum/pointing_device_drivers.c`, but there may be cases where it's very specific to the hardware. So these functions are provided, just in case.
170
171## Common Configuration
172
173| Setting | Description | Default |
174|-------------------------------|-----------------------------------------------------------------------|---------------|
175|`POINTING_DEVICE_ROTATION_90` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ |
176|`POINTING_DEVICE_ROTATION_180` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ |
177|`POINTING_DEVICE_ROTATION_270` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ |
178|`POINTING_DEVICE_INVERT_X` | (Optional) Inverts the X axis report. | _not defined_ |
179|`POINTING_DEVICE_INVERT_Y` | (Optional) Inverts the Y axis report. | _not defined_ |
180|`POINTING_DEVICE_MOTION_PIN` | (Optional) If supported, will only read from sensor if pin is active. | _not defined_ |
181
182
183## Callbacks and Functions
184
185| Function | Description |
186|-----------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|
187| `pointing_device_init_kb(void)` | Callback to allow for keyboard level initialization. Useful for additional hardware sensors. |
188| `pointing_device_init_user(void)` | Callback to allow for user level initialization. Useful for additional hardware sensors. |
189| `pointing_device_task_kb(mouse_report)` | Callback that sends sensor data, so keyboard code can intercept and modify the data. Returns a mouse report. |
190| `pointing_device_task_user(mouse_report)` | Callback that sends sensor data, so user coe can intercept and modify the data. Returns a mouse report. |
191| `pointing_device_handle_buttons(buttons, pressed, button)` | Callback to handle hardware button presses. Returns a `uint8_t`. |
192| `pointing_device_get_cpi(void)` | Gets the current CPI/DPI setting from the sensor, if supported. |
193| `pointing_device_set_cpi(uint16_t)` | Sets the CPI/DPI, if supported. |
194| `pointing_device_get_report(void)` | Returns the current mouse report (as a `mouse_report_t` data structure). |
195| `pointing_device_set_report(mouse_report)` | Sets the mouse report to the assigned `mouse_report_t` data structured passed to the function. |
196| `pointing_device_send(void)` | Sends the current mouse report to the host system. Function can be replaced. |
197| `has_mouse_report_changed(old, new)` | Compares the old and new `mouse_report_t` data and returns true only if it has changed. |
198
199
200# Manipulating Mouse Reports
201
202The report_mouse_t (here "mouseReport") has the following properties:
17 203
18* `mouseReport.x` - this is a signed int from -127 to 127 (not 128, this is defined in USB HID spec) representing movement (+ to the right, - to the left) on the x axis. 204* `mouseReport.x` - this is a signed int from -127 to 127 (not 128, this is defined in USB HID spec) representing movement (+ to the right, - to the left) on the x axis.
19* `mouseReport.y` - this is a signed int from -127 to 127 (not 128, this is defined in USB HID spec) representing movement (+ upward, - downward) on the y axis. 205* `mouseReport.y` - this is a signed int from -127 to 127 (not 128, this is defined in USB HID spec) representing movement (+ upward, - downward) on the y axis.
@@ -21,8 +207,10 @@ Keep in mind that a report_mouse_t (here "mouseReport") has the following proper
21* `mouseReport.h` - this is a signed int from -127 to 127 (not 128, this is defined in USB HID spec) representing horizontal scrolling (+ right, - left). 207* `mouseReport.h` - this is a signed int from -127 to 127 (not 128, this is defined in USB HID spec) representing horizontal scrolling (+ right, - left).
22* `mouseReport.buttons` - this is a uint8_t in which all 8 bits are used. These bits represent the mouse button state - bit 0 is mouse button 1, and bit 7 is mouse button 8. 208* `mouseReport.buttons` - this is a uint8_t in which all 8 bits are used. These bits represent the mouse button state - bit 0 is mouse button 1, and bit 7 is mouse button 8.
23 209
24Once you have made the necessary changes to the mouse report, you need to send it: 210To manually manipulate the mouse reports outside of the `pointing_device_task_*` functions, you can use:
25 211
212* `pointing_device_get_report()` - Returns the current report_mouse_t that represents the information sent to the host computer
213* `pointing_device_set_report(report_mouse_t newMouseReport)` - Overrides and saves the report_mouse_t to be sent to the host computer
26* `pointing_device_send()` - Sends the mouse report to the host and zeroes out the report. 214* `pointing_device_send()` - Sends the mouse report to the host and zeroes out the report.
27 215
28When the mouse report is sent, the x, y, v, and h values are set to 0 (this is done in `pointing_device_send()`, which can be overridden to avoid this behavior). This way, button states persist, but movement will only occur once. For further customization, both `pointing_device_init` and `pointing_device_task` can be overridden. 216When the mouse report is sent, the x, y, v, and h values are set to 0 (this is done in `pointing_device_send()`, which can be overridden to avoid this behavior). This way, button states persist, but movement will only occur once. For further customization, both `pointing_device_init` and `pointing_device_task` can be overridden.
@@ -31,6 +219,8 @@ Additionally, by default, `pointing_device_send()` will only send a report when
31 219
32Also, you use the `has_mouse_report_changed(new, old)` function to check to see if the report has changed. 220Also, you use the `has_mouse_report_changed(new, old)` function to check to see if the report has changed.
33 221
222## Example
223
34In the following example, a custom key is used to click the mouse and scroll 127 units vertically and horizontally, then undo all of that when released - because that's a totally useful function. Listen, this is an example: 224In the following example, a custom key is used to click the mouse and scroll 127 units vertically and horizontally, then undo all of that when released - because that's a totally useful function. Listen, this is an example:
35 225
36```c 226```c
diff --git a/drivers/sensors/adns5050.c b/drivers/sensors/adns5050.c
index 254ef2ee8..c23d24d5a 100644
--- a/drivers/sensors/adns5050.c
+++ b/drivers/sensors/adns5050.c
@@ -20,81 +20,95 @@
20#include "adns5050.h" 20#include "adns5050.h"
21#include "wait.h" 21#include "wait.h"
22#include "debug.h" 22#include "debug.h"
23#include "print.h"
24#include "gpio.h" 23#include "gpio.h"
25 24
26#ifndef OPTIC_ROTATED 25// Registers
27# define OPTIC_ROTATED false 26// clang-format off
28#endif 27#define REG_PRODUCT_ID 0x00
29 28#define REG_REVISION_ID 0x01
30// Definitions for the ADNS serial line. 29#define REG_MOTION 0x02
31#ifndef ADNS_SCLK_PIN 30#define REG_DELTA_X 0x03
32# define ADNS_SCLK_PIN B7 31#define REG_DELTA_Y 0x04
33#endif 32#define REG_SQUAL 0x05
34 33#define REG_SHUTTER_UPPER 0x06
35#ifndef ADNS_SDIO_PIN 34#define REG_SHUTTER_LOWER 0x07
36# define ADNS_SDIO_PIN C6 35#define REG_MAXIMUM_PIXEL 0x08
37#endif 36#define REG_PIXEL_SUM 0x09
38 37#define REG_MINIMUM_PIXEL 0x0a
39#ifndef ADNS_CS_PIN 38#define REG_PIXEL_GRAB 0x0b
40# define ADNS_CS_PIN B4 39#define REG_MOUSE_CONTROL 0x0d
41#endif 40#define REG_MOUSE_CONTROL2 0x19
42 41#define REG_LED_DC_MODE 0x22
43#ifdef CONSOLE_ENABLE 42#define REG_CHIP_RESET 0x3a
44void print_byte(uint8_t byte) { dprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0')); } 43#define REG_PRODUCT_ID2 0x3e
45#endif 44#define REG_INV_REV_ID 0x3f
46 45#define REG_MOTION_BURST 0x63
47// Initialize the ADNS serial pins. 46// clang-format on
48void adns_init(void) { 47
49 setPinOutput(ADNS_SCLK_PIN); 48void adns5050_init(void) {
50 setPinOutput(ADNS_SDIO_PIN); 49 // Initialize the ADNS serial pins.
51 setPinOutput(ADNS_CS_PIN); 50 setPinOutput(ADNS5050_SCLK_PIN);
51 setPinOutput(ADNS5050_SDIO_PIN);
52 setPinOutput(ADNS5050_CS_PIN);
53
54 // reboot the adns.
55 // if the adns hasn't initialized yet, this is harmless.
56 adns5050_write_reg(REG_CHIP_RESET, 0x5a);
57
58 // wait maximum time before adns is ready.
59 // this ensures that the adns is actuall ready after reset.
60 wait_ms(55);
61
62 // read a burst from the adns and then discard it.
63 // gets the adns ready for write commands
64 // (for example, setting the dpi).
65 adns5050_read_burst();
52} 66}
53 67
54// Perform a synchronization with the ADNS. 68// Perform a synchronization with the ADNS.
55// Just as with the serial protocol, this is used by the slave to send a 69// Just as with the serial protocol, this is used by the slave to send a
56// synchronization signal to the master. 70// synchronization signal to the master.
57void adns_sync(void) { 71void adns5050_sync(void) {
58 writePinLow(ADNS_CS_PIN); 72 writePinLow(ADNS5050_CS_PIN);
59 wait_us(1); 73 wait_us(1);
60 writePinHigh(ADNS_CS_PIN); 74 writePinHigh(ADNS5050_CS_PIN);
61} 75}
62 76
63void adns_cs_select(void) { writePinLow(ADNS_CS_PIN); } 77void adns5050_cs_select(void) { writePinLow(ADNS5050_CS_PIN); }
64 78
65void adns_cs_deselect(void) { writePinHigh(ADNS_CS_PIN); } 79void adns5050_cs_deselect(void) { writePinHigh(ADNS5050_CS_PIN); }
66 80
67uint8_t adns_serial_read(void) { 81uint8_t adns5050_serial_read(void) {
68 setPinInput(ADNS_SDIO_PIN); 82 setPinInput(ADNS5050_SDIO_PIN);
69 uint8_t byte = 0; 83 uint8_t byte = 0;
70 84
71 for (uint8_t i = 0; i < 8; ++i) { 85 for (uint8_t i = 0; i < 8; ++i) {
72 writePinLow(ADNS_SCLK_PIN); 86 writePinLow(ADNS5050_SCLK_PIN);
73 wait_us(1); 87 wait_us(1);
74 88
75 byte = (byte << 1) | readPin(ADNS_SDIO_PIN); 89 byte = (byte << 1) | readPin(ADNS5050_SDIO_PIN);
76 90
77 writePinHigh(ADNS_SCLK_PIN); 91 writePinHigh(ADNS5050_SCLK_PIN);
78 wait_us(1); 92 wait_us(1);
79 } 93 }
80 94
81 return byte; 95 return byte;
82} 96}
83 97
84void adns_serial_write(uint8_t data) { 98void adns5050_serial_write(uint8_t data) {
85 setPinOutput(ADNS_SDIO_PIN); 99 setPinOutput(ADNS5050_SDIO_PIN);
86 100
87 for (int8_t b = 7; b >= 0; b--) { 101 for (int8_t b = 7; b >= 0; b--) {
88 writePinLow(ADNS_SCLK_PIN); 102 writePinLow(ADNS5050_SCLK_PIN);
89 103
90 if (data & (1 << b)) 104 if (data & (1 << b))
91 writePinHigh(ADNS_SDIO_PIN); 105 writePinHigh(ADNS5050_SDIO_PIN);
92 else 106 else
93 writePinLow(ADNS_SDIO_PIN); 107 writePinLow(ADNS5050_SDIO_PIN);
94 108
95 wait_us(2); 109 wait_us(2);
96 110
97 writePinHigh(ADNS_SCLK_PIN); 111 writePinHigh(ADNS5050_SCLK_PIN);
98 } 112 }
99 113
100 // tSWR. See page 15 of the ADNS spec sheet. 114 // tSWR. See page 15 of the ADNS spec sheet.
@@ -108,17 +122,17 @@ void adns_serial_write(uint8_t data) {
108 122
109// Read a byte of data from a register on the ADNS. 123// Read a byte of data from a register on the ADNS.
110// Don't forget to use the register map (as defined in the header file). 124// Don't forget to use the register map (as defined in the header file).
111uint8_t adns_read_reg(uint8_t reg_addr) { 125uint8_t adns5050_read_reg(uint8_t reg_addr) {
112 adns_cs_select(); 126 adns5050_cs_select();
113 127
114 adns_serial_write(reg_addr); 128 adns5050_serial_write(reg_addr);
115 129
116 // We don't need a minimum tSRAD here. That's because a 4ms wait time is 130 // We don't need a minimum tSRAD here. That's because a 4ms wait time is
117 // already included in adns_serial_write(), so we're good. 131 // already included in adns5050_serial_write(), so we're good.
118 // See page 10 and 15 of the ADNS spec sheet. 132 // See page 10 and 15 of the ADNS spec sheet.
119 // wait_us(4); 133 // wait_us(4);
120 134
121 uint8_t byte = adns_serial_read(); 135 uint8_t byte = adns5050_serial_read();
122 136
123 // tSRW & tSRR. See page 15 of the ADNS spec sheet. 137 // tSRW & tSRR. See page 15 of the ADNS spec sheet.
124 // Technically, this is only necessary if the next operation is an SDIO 138 // Technically, this is only necessary if the next operation is an SDIO
@@ -126,38 +140,38 @@ uint8_t adns_read_reg(uint8_t reg_addr) {
126 // Honestly, this wait could probably be removed. 140 // Honestly, this wait could probably be removed.
127 wait_us(1); 141 wait_us(1);
128 142
129 adns_cs_deselect(); 143 adns5050_cs_deselect();
130 144
131 return byte; 145 return byte;
132} 146}
133 147
134void adns_write_reg(uint8_t reg_addr, uint8_t data) { 148void adns5050_write_reg(uint8_t reg_addr, uint8_t data) {
135 adns_cs_select(); 149 adns5050_cs_select();
136 adns_serial_write(0b10000000 | reg_addr); 150 adns5050_serial_write(0b10000000 | reg_addr);
137 adns_serial_write(data); 151 adns5050_serial_write(data);
138 adns_cs_deselect(); 152 adns5050_cs_deselect();
139} 153}
140 154
141report_adns_t adns_read_burst(void) { 155report_adns5050_t adns5050_read_burst(void) {
142 adns_cs_select(); 156 adns5050_cs_select();
143 157
144 report_adns_t data; 158 report_adns5050_t data;
145 data.dx = 0; 159 data.dx = 0;
146 data.dy = 0; 160 data.dy = 0;
147 161
148 adns_serial_write(REG_MOTION_BURST); 162 adns5050_serial_write(REG_MOTION_BURST);
149 163
150 // We don't need a minimum tSRAD here. That's because a 4ms wait time is 164 // We don't need a minimum tSRAD here. That's because a 4ms wait time is
151 // already included in adns_serial_write(), so we're good. 165 // already included in adns5050_serial_write(), so we're good.
152 // See page 10 and 15 of the ADNS spec sheet. 166 // See page 10 and 15 of the ADNS spec sheet.
153 // wait_us(4); 167 // wait_us(4);
154 168
155 uint8_t x = adns_serial_read(); 169 uint8_t x = adns5050_serial_read();
156 uint8_t y = adns_serial_read(); 170 uint8_t y = adns5050_serial_read();
157 171
158 // Burst mode returns a bunch of other shit that we don't really need. 172 // Burst mode returns a bunch of other shit that we don't really need.
159 // Setting CS to high ends burst mode early. 173 // Setting CS to high ends burst mode early.
160 adns_cs_deselect(); 174 adns5050_cs_deselect();
161 175
162 data.dx = convert_twoscomp(x); 176 data.dx = convert_twoscomp(x);
163 data.dy = convert_twoscomp(y); 177 data.dy = convert_twoscomp(y);
@@ -175,12 +189,21 @@ int8_t convert_twoscomp(uint8_t data) {
175} 189}
176 190
177// Don't forget to use the definitions for CPI in the header file. 191// Don't forget to use the definitions for CPI in the header file.
178void adns_set_cpi(uint8_t cpi) { adns_write_reg(REG_MOUSE_CONTROL2, cpi); } 192void adns5050_set_cpi(uint16_t cpi) {
193 uint8_t cpival = constrain((cpi / 125), 0x1, 0xD); // limits to 0--119
194
195 adns5050_write_reg(REG_MOUSE_CONTROL2, 0b10000 | cpival);
196}
197
198uint16_t adns5050_get_cpi(void) {
199 uint8_t cpival = adns5050_read_reg(REG_MOUSE_CONTROL2);
200 return (uint16_t)((cpival & 0b10000) * 125);
201}
179 202
180bool adns_check_signature(void) { 203bool adns5050_check_signature(void) {
181 uint8_t pid = adns_read_reg(REG_PRODUCT_ID); 204 uint8_t pid = adns5050_read_reg(REG_PRODUCT_ID);
182 uint8_t rid = adns_read_reg(REG_REVISION_ID); 205 uint8_t rid = adns5050_read_reg(REG_REVISION_ID);
183 uint8_t pid2 = adns_read_reg(REG_PRODUCT_ID2); 206 uint8_t pid2 = adns5050_read_reg(REG_PRODUCT_ID2);
184 207
185 return (pid == 0x12 && rid == 0x01 && pid2 == 0x26); 208 return (pid == 0x12 && rid == 0x01 && pid2 == 0x26);
186} 209}
diff --git a/drivers/sensors/adns5050.h b/drivers/sensors/adns5050.h
index 5e9edc296..e45a25019 100644
--- a/drivers/sensors/adns5050.h
+++ b/drivers/sensors/adns5050.h
@@ -21,59 +21,52 @@
21 21
22#include <stdbool.h> 22#include <stdbool.h>
23 23
24// Registers
25#define REG_PRODUCT_ID 0x00
26#define REG_REVISION_ID 0x01
27#define REG_MOTION 0x02
28#define REG_DELTA_X 0x03
29#define REG_DELTA_Y 0x04
30#define REG_SQUAL 0x05
31#define REG_SHUTTER_UPPER 0x06
32#define REG_SHUTTER_LOWER 0x07
33#define REG_MAXIMUM_PIXEL 0x08
34#define REG_PIXEL_SUM 0x09
35#define REG_MINIMUM_PIXEL 0x0a
36#define REG_PIXEL_GRAB 0x0b
37#define REG_MOUSE_CONTROL 0x0d
38#define REG_MOUSE_CONTROL2 0x19
39#define REG_LED_DC_MODE 0x22
40#define REG_CHIP_RESET 0x3a
41#define REG_PRODUCT_ID2 0x3e
42#define REG_INV_REV_ID 0x3f
43#define REG_MOTION_BURST 0x63
44
45// CPI values 24// CPI values
46#define CPI125 0x11 25// clang-format off
47#define CPI250 0x12 26#define CPI125 0x11
48#define CPI375 0x13 27#define CPI250 0x12
49#define CPI500 0x14 28#define CPI375 0x13
50#define CPI625 0x15 29#define CPI500 0x14
51#define CPI750 0x16 30#define CPI625 0x15
52#define CPI875 0x17 31#define CPI750 0x16
32#define CPI875 0x17
53#define CPI1000 0x18 33#define CPI1000 0x18
54#define CPI1125 0x19 34#define CPI1125 0x19
55#define CPI1250 0x1a 35#define CPI1250 0x1a
56#define CPI1375 0x1b 36#define CPI1375 0x1b
37// clang-format on
38
39#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
40
41// Definitions for the ADNS serial line.
42#ifndef ADNS5050_SCLK_PIN
43# error "No clock pin defined -- missing ADNS5050_SCLK_PIN"
44#endif
45
46#ifndef ADNS5050_SDIO_PIN
47# error "No data pin defined -- missing ADNS5050_SDIO_PIN"
48#endif
57 49
58#ifdef CONSOLE_ENABLE 50#ifndef ADNS5050_CS_PIN
59void print_byte(uint8_t byte); 51# error "No chip select pin defined -- missing ADNS5050_CS_PIN"
60#endif 52#endif
61 53
62typedef struct { 54typedef struct {
63 int8_t dx; 55 int8_t dx;
64 int8_t dy; 56 int8_t dy;
65} report_adns_t; 57} report_adns5050_t;
66 58
67// A bunch of functions to implement the ADNS5050-specific serial protocol. 59// A bunch of functions to implement the ADNS5050-specific serial protocol.
68// Note that the "serial.h" driver is insufficient, because it does not 60// Note that the "serial.h" driver is insufficient, because it does not
69// manually manipulate a serial clock signal. 61// manually manipulate a serial clock signal.
70void adns_init(void); 62void adns5050_init(void);
71void adns_sync(void); 63void adns5050_sync(void);
72uint8_t adns_serial_read(void); 64uint8_t adns5050_serial_read(void);
73void adns_serial_write(uint8_t data); 65void adns5050_serial_write(uint8_t data);
74uint8_t adns_read_reg(uint8_t reg_addr); 66uint8_t adns5050_read_reg(uint8_t reg_addr);
75void adns_write_reg(uint8_t reg_addr, uint8_t data); 67void adns5050_write_reg(uint8_t reg_addr, uint8_t data);
76report_adns_t adns_read_burst(void); 68report_adns5050_t adns5050_read_burst(void);
77int8_t convert_twoscomp(uint8_t data); 69void adns5050_set_cpi(uint16_t cpi);
78void adns_set_cpi(uint8_t cpi); 70uint16_t adns5050_get_cpi(void);
79bool adns_check_signature(void); 71int8_t convert_twoscomp(uint8_t data);
72bool adns5050_check_signature(void);
diff --git a/drivers/sensors/adns9800.c b/drivers/sensors/adns9800.c
index b4f683452..c52f99180 100644
--- a/drivers/sensors/adns9800.c
+++ b/drivers/sensors/adns9800.c
@@ -15,83 +15,80 @@
15 */ 15 */
16 16
17#include "spi_master.h" 17#include "spi_master.h"
18#include "quantum.h"
19#include "adns9800_srom_A6.h" 18#include "adns9800_srom_A6.h"
20#include "adns9800.h" 19#include "adns9800.h"
20#include "wait.h"
21 21
22// registers 22// registers
23#define REG_Product_ID 0x00 23// clang-format off
24#define REG_Revision_ID 0x01 24#define REG_Product_ID 0x00
25#define REG_Motion 0x02 25#define REG_Revision_ID 0x01
26#define REG_Delta_X_L 0x03 26#define REG_Motion 0x02
27#define REG_Delta_X_H 0x04 27#define REG_Delta_X_L 0x03
28#define REG_Delta_Y_L 0x05 28#define REG_Delta_X_H 0x04
29#define REG_Delta_Y_H 0x06 29#define REG_Delta_Y_L 0x05
30#define REG_SQUAL 0x07 30#define REG_Delta_Y_H 0x06
31#define REG_Pixel_Sum 0x08 31#define REG_SQUAL 0x07
32#define REG_Maximum_Pixel 0x09 32#define REG_Pixel_Sum 0x08
33#define REG_Minimum_Pixel 0x0a 33#define REG_Maximum_Pixel 0x09
34#define REG_Shutter_Lower 0x0b 34#define REG_Minimum_Pixel 0x0a
35#define REG_Shutter_Upper 0x0c 35#define REG_Shutter_Lower 0x0b
36#define REG_Frame_Period_Lower 0x0d 36#define REG_Shutter_Upper 0x0c
37#define REG_Frame_Period_Upper 0x0e 37#define REG_Frame_Period_Lower 0x0d
38#define REG_Configuration_I 0x0f 38#define REG_Frame_Period_Upper 0x0e
39#define REG_Configuration_II 0x10 39#define REG_Configuration_I 0x0f
40#define REG_Frame_Capture 0x12 40#define REG_Configuration_II 0x10
41#define REG_SROM_Enable 0x13 41#define REG_Frame_Capture 0x12
42#define REG_Run_Downshift 0x14 42#define REG_SROM_Enable 0x13
43#define REG_Rest1_Rate 0x15 43#define REG_Run_Downshift 0x14
44#define REG_Rest1_Downshift 0x16 44#define REG_Rest1_Rate 0x15
45#define REG_Rest2_Rate 0x17 45#define REG_Rest1_Downshift 0x16
46#define REG_Rest2_Downshift 0x18 46#define REG_Rest2_Rate 0x17
47#define REG_Rest3_Rate 0x19 47#define REG_Rest2_Downshift 0x18
48#define REG_Rest3_Rate 0x19
48#define REG_Frame_Period_Max_Bound_Lower 0x1a 49#define REG_Frame_Period_Max_Bound_Lower 0x1a
49#define REG_Frame_Period_Max_Bound_Upper 0x1b 50#define REG_Frame_Period_Max_Bound_Upper 0x1b
50#define REG_Frame_Period_Min_Bound_Lower 0x1c 51#define REG_Frame_Period_Min_Bound_Lower 0x1c
51#define REG_Frame_Period_Min_Bound_Upper 0x1d 52#define REG_Frame_Period_Min_Bound_Upper 0x1d
52#define REG_Shutter_Max_Bound_Lower 0x1e 53#define REG_Shutter_Max_Bound_Lower 0x1e
53#define REG_Shutter_Max_Bound_Upper 0x1f 54#define REG_Shutter_Max_Bound_Upper 0x1f
54#define REG_LASER_CTRL0 0x20 55#define REG_LASER_CTRL0 0x20
55#define REG_Observation 0x24 56#define REG_Observation 0x24
56#define REG_Data_Out_Lower 0x25 57#define REG_Data_Out_Lower 0x25
57#define REG_Data_Out_Upper 0x26 58#define REG_Data_Out_Upper 0x26
58#define REG_SROM_ID 0x2a 59#define REG_SROM_ID 0x2a
59#define REG_Lift_Detection_Thr 0x2e 60#define REG_Lift_Detection_Thr 0x2e
60#define REG_Configuration_V 0x2f 61#define REG_Configuration_V 0x2f
61#define REG_Configuration_IV 0x39 62#define REG_Configuration_IV 0x39
62#define REG_Power_Up_Reset 0x3a 63#define REG_Power_Up_Reset 0x3a
63#define REG_Shutdown 0x3b 64#define REG_Shutdown 0x3b
64#define REG_Inverse_Product_ID 0x3f 65#define REG_Inverse_Product_ID 0x3f
65#define REG_Motion_Burst 0x50 66#define REG_Motion_Burst 0x50
66#define REG_SROM_Load_Burst 0x62 67#define REG_SROM_Load_Burst 0x62
67#define REG_Pixel_Burst 0x64 68#define REG_Pixel_Burst 0x64
68 69
69#define ADNS_CLOCK_SPEED 2000000 70#define MIN_CPI 200
70#define MIN_CPI 200 71#define MAX_CPI 8200
71#define MAX_CPI 8200 72#define CPI_STEP 200
72#define CPI_STEP 200 73#define CLAMP_CPI(value) value<MIN_CPI ? MIN_CPI : value> MAX_CPI ? MAX_CPI : value
73#define CLAMP_CPI(value) value<MIN_CPI ? MIN_CPI : value> MAX_CPI ? MAX_CPI : value
74#define SPI_MODE 3
75#define SPI_DIVISOR (F_CPU / ADNS_CLOCK_SPEED)
76#define US_BETWEEN_WRITES 120 74#define US_BETWEEN_WRITES 120
77#define US_BETWEEN_READS 20 75#define US_BETWEEN_READS 20
78#define US_BEFORE_MOTION 100 76#define US_BEFORE_MOTION 100
79#define MSB1 0x80 77#define MSB1 0x80
78// clang-format on
80 79
81extern const uint8_t firmware_data[]; 80void adns9800_spi_start(void) { spi_start(ADNS9800_CS_PIN, false, ADNS9800_SPI_MODE, ADNS9800_SPI_DIVISOR); }
82 81
83void adns_spi_start(void) { spi_start(SPI_SS_PIN, false, SPI_MODE, SPI_DIVISOR); } 82void adns9800_write(uint8_t reg_addr, uint8_t data) {
84 83 adns9800_spi_start();
85void adns_write(uint8_t reg_addr, uint8_t data) {
86 adns_spi_start();
87 spi_write(reg_addr | MSB1); 84 spi_write(reg_addr | MSB1);
88 spi_write(data); 85 spi_write(data);
89 spi_stop(); 86 spi_stop();
90 wait_us(US_BETWEEN_WRITES); 87 wait_us(US_BETWEEN_WRITES);
91} 88}
92 89
93uint8_t adns_read(uint8_t reg_addr) { 90uint8_t adns9800_read(uint8_t reg_addr) {
94 adns_spi_start(); 91 adns9800_spi_start();
95 spi_write(reg_addr & 0x7f); 92 spi_write(reg_addr & 0x7f);
96 uint8_t data = spi_read(); 93 uint8_t data = spi_read();
97 spi_stop(); 94 spi_stop();
@@ -100,39 +97,39 @@ uint8_t adns_read(uint8_t reg_addr) {
100 return data; 97 return data;
101} 98}
102 99
103void adns_init() { 100void adns9800_init() {
104 setPinOutput(SPI_SS_PIN); 101 setPinOutput(ADNS9800_CS_PIN);
105 102
106 spi_init(); 103 spi_init();
107 104
108 // reboot 105 // reboot
109 adns_write(REG_Power_Up_Reset, 0x5a); 106 adns9800_write(REG_Power_Up_Reset, 0x5a);
110 wait_ms(50); 107 wait_ms(50);
111 108
112 // read registers and discard 109 // read registers and discard
113 adns_read(REG_Motion); 110 adns9800_read(REG_Motion);
114 adns_read(REG_Delta_X_L); 111 adns9800_read(REG_Delta_X_L);
115 adns_read(REG_Delta_X_H); 112 adns9800_read(REG_Delta_X_H);
116 adns_read(REG_Delta_Y_L); 113 adns9800_read(REG_Delta_Y_L);
117 adns_read(REG_Delta_Y_H); 114 adns9800_read(REG_Delta_Y_H);
118 115
119 // upload firmware 116 // upload firmware
120 117
121 // 3k firmware mode 118 // 3k firmware mode
122 adns_write(REG_Configuration_IV, 0x02); 119 adns9800_write(REG_Configuration_IV, 0x02);
123 120
124 // enable initialisation 121 // enable initialisation
125 adns_write(REG_SROM_Enable, 0x1d); 122 adns9800_write(REG_SROM_Enable, 0x1d);
126 123
127 // wait a frame 124 // wait a frame
128 wait_ms(10); 125 wait_ms(10);
129 126
130 // start SROM download 127 // start SROM download
131 adns_write(REG_SROM_Enable, 0x18); 128 adns9800_write(REG_SROM_Enable, 0x18);
132 129
133 // write the SROM file 130 // write the SROM file
134 131
135 adns_spi_start(); 132 adns9800_spi_start();
136 133
137 spi_write(REG_SROM_Load_Burst | 0x80); 134 spi_write(REG_SROM_Load_Burst | 0x80);
138 wait_us(15); 135 wait_us(15);
@@ -140,7 +137,7 @@ void adns_init() {
140 // send all bytes of the firmware 137 // send all bytes of the firmware
141 unsigned char c; 138 unsigned char c;
142 for (int i = 0; i < FIRMWARE_LENGTH; i++) { 139 for (int i = 0; i < FIRMWARE_LENGTH; i++) {
143 c = (unsigned char)pgm_read_byte(firmware_data + i); 140 c = (unsigned char)pgm_read_byte(adns9800_firmware_data + i);
144 spi_write(c); 141 spi_write(c);
145 wait_us(15); 142 wait_us(15);
146 } 143 }
@@ -150,18 +147,30 @@ void adns_init() {
150 wait_ms(10); 147 wait_ms(10);
151 148
152 // enable laser 149 // enable laser
153 uint8_t laser_ctrl0 = adns_read(REG_LASER_CTRL0); 150 uint8_t laser_ctrl0 = adns9800_read(REG_LASER_CTRL0);
154 adns_write(REG_LASER_CTRL0, laser_ctrl0 & 0xf0); 151 adns9800_write(REG_LASER_CTRL0, laser_ctrl0 & 0xf0);
152
153 adns9800_set_cpi(ADNS9800_CPI);
155} 154}
156 155
157config_adns_t adns_get_config(void) { 156config_adns9800_t adns9800_get_config(void) {
158 uint8_t config_1 = adns_read(REG_Configuration_I); 157 uint8_t config_1 = adns9800_read(REG_Configuration_I);
159 return (config_adns_t){(config_1 & 0xFF) * CPI_STEP}; 158 return (config_adns9800_t){(config_1 & 0xFF) * CPI_STEP};
160} 159}
161 160
162void adns_set_config(config_adns_t config) { 161void adns9800_set_config(config_adns9800_t config) {
163 uint8_t config_1 = (CLAMP_CPI(config.cpi) / CPI_STEP) & 0xFF; 162 uint8_t config_1 = (CLAMP_CPI(config.cpi) / CPI_STEP) & 0xFF;
164 adns_write(REG_Configuration_I, config_1); 163 adns9800_write(REG_Configuration_I, config_1);
164}
165
166uint16_t adns9800_get_cpi(void) {
167 uint8_t config_1 = adns9800_read(REG_Configuration_I);
168 return (uint16_t){(config_1 & 0xFF) * CPI_STEP};
169}
170
171void adns9800_set_cpi(uint16_t cpi) {
172 uint8_t config_1 = (CLAMP_CPI(cpi) / CPI_STEP) & 0xFF;
173 adns9800_write(REG_Configuration_I, config_1);
165} 174}
166 175
167static int16_t convertDeltaToInt(uint8_t high, uint8_t low) { 176static int16_t convertDeltaToInt(uint8_t high, uint8_t low) {
@@ -174,10 +183,10 @@ static int16_t convertDeltaToInt(uint8_t high, uint8_t low) {
174 return twos_comp; 183 return twos_comp;
175} 184}
176 185
177report_adns_t adns_get_report(void) { 186report_adns9800_t adns9800_get_report(void) {
178 report_adns_t report = {0, 0}; 187 report_adns9800_t report = {0, 0};
179 188
180 adns_spi_start(); 189 adns9800_spi_start();
181 190
182 // start burst mode 191 // start burst mode
183 spi_write(REG_Motion_Burst & 0x7f); 192 spi_write(REG_Motion_Burst & 0x7f);
diff --git a/drivers/sensors/adns9800.h b/drivers/sensors/adns9800.h
index d19ded401..e75a869c0 100644
--- a/drivers/sensors/adns9800.h
+++ b/drivers/sensors/adns9800.h
@@ -18,18 +18,48 @@
18 18
19#include <stdint.h> 19#include <stdint.h>
20 20
21#ifndef ADNS9800_CPI
22# define ADNS9800_CPI 1600
23#endif
24
25#ifndef ADNS9800_CLOCK_SPEED
26# define ADNS9800_CLOCK_SPEED 2000000
27#endif
28
29#ifndef ADNS9800_SPI_LSBFIRST
30# define ADNS9800_SPI_LSBFIRST false
31#endif
32
33#ifndef ADNS9800_SPI_MODE
34# define ADNS9800_SPI_MODE 3
35#endif
36
37#ifndef ADNS9800_SPI_DIVISOR
38# ifdef __AVR__
39# define ADNS9800_SPI_DIVISOR (F_CPU / ADNS9800_CLOCK_SPEED)
40# else
41# define ADNS9800_SPI_DIVISOR 64
42# endif
43#endif
44
45#ifndef ADNS9800_CS_PIN
46# error "No chip select pin defined -- missing ADNS9800_CS_PIN"
47#endif
48
21typedef struct { 49typedef struct {
22 /* 200 - 8200 CPI supported */ 50 /* 200 - 8200 CPI supported */
23 uint16_t cpi; 51 uint16_t cpi;
24} config_adns_t; 52} config_adns9800_t;
25 53
26typedef struct { 54typedef struct {
27 int16_t x; 55 int16_t x;
28 int16_t y; 56 int16_t y;
29} report_adns_t; 57} report_adns9800_t;
30 58
31void adns_init(void); 59void adns9800_init(void);
32config_adns_t adns_get_config(void); 60config_adns9800_t adns9800_get_config(void);
33void adns_set_config(config_adns_t); 61void adns9800_set_config(config_adns9800_t);
62uint16_t adns9800_get_cpi(void);
63void adns9800_set_cpi(uint16_t cpi);
34/* Reads and clears the current delta values on the ADNS sensor */ 64/* Reads and clears the current delta values on the ADNS sensor */
35report_adns_t adns_get_report(void); 65report_adns9800_t adns9800_get_report(void);
diff --git a/drivers/sensors/adns9800_srom_A6.h b/drivers/sensors/adns9800_srom_A6.h
index e698a401b..d86ecbbd9 100644
--- a/drivers/sensors/adns9800_srom_A6.h
+++ b/drivers/sensors/adns9800_srom_A6.h
@@ -6,7 +6,7 @@
6 6
7// clang-format off 7// clang-format off
8 8
9const uint8_t firmware_data[FIRMWARE_LENGTH] PROGMEM = { 9const uint8_t adns9800_firmware_data[FIRMWARE_LENGTH] PROGMEM = {
10 0x03, 0xA6, 0x68, 0x1E, 0x7D, 0x10, 0x7E, 0x7E, 0x5F, 0x1C, 0xB8, 0xF2, 0x47, 0x0C, 0x7B, 0x74, 10 0x03, 0xA6, 0x68, 0x1E, 0x7D, 0x10, 0x7E, 0x7E, 0x5F, 0x1C, 0xB8, 0xF2, 0x47, 0x0C, 0x7B, 0x74,
11 0x4B, 0x14, 0x8B, 0x75, 0x66, 0x51, 0x0B, 0x8C, 0x76, 0x74, 0x4B, 0x14, 0xAA, 0xD6, 0x0F, 0x9C, 11 0x4B, 0x14, 0x8B, 0x75, 0x66, 0x51, 0x0B, 0x8C, 0x76, 0x74, 0x4B, 0x14, 0xAA, 0xD6, 0x0F, 0x9C,
12 0xBA, 0xF6, 0x6E, 0x3F, 0xDD, 0x38, 0xD5, 0x02, 0x80, 0x9B, 0x82, 0x6D, 0x58, 0x13, 0xA4, 0xAB, 12 0xBA, 0xF6, 0x6E, 0x3F, 0xDD, 0x38, 0xD5, 0x02, 0x80, 0x9B, 0x82, 0x6D, 0x58, 0x13, 0xA4, 0xAB,
diff --git a/drivers/sensors/analog_joystick.c b/drivers/sensors/analog_joystick.c
new file mode 100644
index 000000000..0f4d1d7a4
--- /dev/null
+++ b/drivers/sensors/analog_joystick.c
@@ -0,0 +1,94 @@
1/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
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 "analog_joystick.h"
18#include "analog.h"
19#include "gpio.h"
20#include "wait.h"
21
22// Set Parameters
23uint16_t minAxisValue = ANALOG_JOYSTICK_AXIS_MIN;
24uint16_t maxAxisValue = ANALOG_JOYSTICK_AXIS_MAX;
25
26uint8_t maxCursorSpeed = ANALOG_JOYSTICK_SPEED_MAX;
27uint8_t speedRegulator = ANALOG_JOYSTICK_SPEED_REGULATOR; // Lower Values Create Faster Movement
28
29int16_t xOrigin, yOrigin;
30
31uint16_t lastCursor = 0;
32
33int16_t axisCoordinate(uint8_t pin, uint16_t origin) {
34 int8_t direction;
35 int16_t distanceFromOrigin;
36 int16_t range;
37
38 int16_t position = analogReadPin(pin);
39
40 if (origin == position) {
41 return 0;
42 } else if (origin > position) {
43 distanceFromOrigin = origin - position;
44 range = origin - minAxisValue;
45 direction = -1;
46 } else {
47 distanceFromOrigin = position - origin;
48 range = maxAxisValue - origin;
49 direction = 1;
50 }
51
52 float percent = (float)distanceFromOrigin / range;
53 int16_t coordinate = (int16_t)(percent * 100);
54 if (coordinate < 0) {
55 return 0;
56 } else if (coordinate > 100) {
57 return 100 * direction;
58 } else {
59 return coordinate * direction;
60 }
61}
62
63int8_t axisToMouseComponent(uint8_t pin, int16_t origin, uint8_t maxSpeed) {
64 int16_t coordinate = axisCoordinate(pin, origin);
65 if (coordinate != 0) {
66 float percent = (float)coordinate / 100;
67 return percent * maxCursorSpeed * (abs(coordinate) / speedRegulator);
68 } else {
69 return 0;
70 }
71}
72
73report_analog_joystick_t analog_joystick_read(void) {
74 report_analog_joystick_t report = {0};
75
76 if (timer_elapsed(lastCursor) > ANALOG_JOYSTICK_READ_INTERVAL) {
77 lastCursor = timer_read();
78 report.x = axisToMouseComponent(ANALOG_JOYSTICK_X_AXIS_PIN, xOrigin, maxCursorSpeed);
79 report.y = axisToMouseComponent(ANALOG_JOYSTICK_Y_AXIS_PIN, yOrigin, maxCursorSpeed);
80 }
81#ifdef ANALOG_JOYSTICK_CLICK_PIN
82 report.button = !readPin(ANALOG_JOYSTICK_CLICK_PIN);
83#endif
84 return report;
85}
86
87void analog_joystick_init(void) {
88#ifdef ANALOG_JOYSTICK_CLICK_PIN
89 setPinInputHigh(ANALOG_JOYSTICK_CLICK_PIN);
90#endif
91 // Account for drift
92 xOrigin = analogReadPin(ANALOG_JOYSTICK_X_AXIS_PIN);
93 yOrigin = analogReadPin(ANALOG_JOYSTICK_Y_AXIS_PIN);
94}
diff --git a/drivers/sensors/analog_joystick.h b/drivers/sensors/analog_joystick.h
new file mode 100644
index 000000000..6892a0881
--- /dev/null
+++ b/drivers/sensors/analog_joystick.h
@@ -0,0 +1,51 @@
1/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
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 <stdbool.h>
20#include <stdint.h>
21
22#ifndef ANALOG_JOYSTICK_X_AXIS_PIN
23# error No pin specified for X Axis
24#endif
25#ifndef ANALOG_JOYSTICK_Y_AXIS_PIN
26# error No pin specified for Y Axis
27#endif
28
29#ifndef ANALOG_JOYSTICK_AXIS_MIN
30# define ANALOG_JOYSTICK_AXIS_MIN 0
31#endif
32#ifndef ANALOG_JOYSTICK_AXIS_MAX
33# define ANALOG_JOYSTICK_AXIS_MAX 1023
34#endif
35#ifndef ANALOG_JOYSTICK_SPEED_REGULATOR
36# define ANALOG_JOYSTICK_SPEED_REGULATOR 20
37#endif
38#ifndef ANALOG_JOYSTICK_READ_INTERVAL
39# define ANALOG_JOYSTICK_READ_INTERVAL 10
40#endif
41#ifndef ANALOG_JOYSTICK_SPEED_MAX
42# define ANALOG_JOYSTICK_SPEED_MAX 2
43#endif
44
45typedef struct {
46 int8_t x;
47 int8_t y;
48 bool button;
49} report_analog_joystick_t;
50report_analog_joystick_t analog_joystick_read(void);
51void analog_joystick_init(void);
diff --git a/drivers/sensors/cirque_pinnacle.c b/drivers/sensors/cirque_pinnacle.c
new file mode 100644
index 000000000..b807c4f07
--- /dev/null
+++ b/drivers/sensors/cirque_pinnacle.c
@@ -0,0 +1,232 @@
1// Copyright (c) 2018 Cirque Corp. Restrictions apply. See: www.cirque.com/sw-license
2#include "cirque_pinnacle.h"
3#include "print.h"
4#include "debug.h"
5#include "wait.h"
6
7// Registers for RAP
8// clang-format off
9#define FIRMWARE_ID 0x00
10#define FIRMWARE_VERSION_C 0x01
11#define STATUS_1 0x02
12#define SYSCONFIG_1 0x03
13#define FEEDCONFIG_1 0x04
14#define FEEDCONFIG_2 0x05
15#define CALIBRATION_CONFIG_1 0x07
16#define PS2_AU_CONTROL 0x08
17#define SAMPLE_RATE 0x09
18#define Z_IDLE_COUNT 0x0A
19#define Z_SCALER 0x0B
20#define SLEEP_INTERVAL 0x0C
21#define SLEEP_TIMER 0x0D
22#define PACKET_BYTE_0 0x12
23#define PACKET_BYTE_1 0x13
24#define PACKET_BYTE_2 0x14
25#define PACKET_BYTE_3 0x15
26#define PACKET_BYTE_4 0x16
27#define PACKET_BYTE_5 0x17
28
29#define ERA_VALUE 0x1B
30#define ERA_HIGH_BYTE 0x1C
31#define ERA_LOW_BYTE 0x1D
32#define ERA_CONTROL 0x1E
33
34// ADC-attenuation settings (held in BIT_7 and BIT_6)
35// 1X = most sensitive, 4X = least sensitive
36#define ADC_ATTENUATE_1X 0x00
37#define ADC_ATTENUATE_2X 0x40
38#define ADC_ATTENUATE_3X 0x80
39#define ADC_ATTENUATE_4X 0xC0
40
41// Register config values for this demo
42#define SYSCONFIG_1_VALUE 0x00
43#define FEEDCONFIG_1_VALUE 0x03 // 0x03 for absolute mode 0x01 for relative mode
44#define FEEDCONFIG_2_VALUE 0x1C // 0x1F for normal functionality 0x1E for intellimouse disabled
45#define Z_IDLE_COUNT_VALUE 0x05
46// clang-format on
47
48bool touchpad_init;
49uint16_t scale_data = 1024;
50
51void cirque_pinnacle_clear_flags(void);
52void cirque_pinnacle_enable_feed(bool feedEnable);
53void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count);
54void RAP_Write(uint8_t address, uint8_t data);
55
56#ifdef CONSOLE_ENABLE
57void print_byte(uint8_t byte) { xprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0')); }
58#endif
59
60/* Logical Scaling Functions */
61// Clips raw coordinates to "reachable" window of sensor
62// NOTE: values outside this window can only appear as a result of noise
63void ClipCoordinates(pinnacle_data_t* coordinates) {
64 if (coordinates->xValue < CIRQUE_PINNACLE_X_LOWER) {
65 coordinates->xValue = CIRQUE_PINNACLE_X_LOWER;
66 } else if (coordinates->xValue > CIRQUE_PINNACLE_X_UPPER) {
67 coordinates->xValue = CIRQUE_PINNACLE_X_UPPER;
68 }
69 if (coordinates->yValue < CIRQUE_PINNACLE_Y_LOWER) {
70 coordinates->yValue = CIRQUE_PINNACLE_Y_LOWER;
71 } else if (coordinates->yValue > CIRQUE_PINNACLE_Y_UPPER) {
72 coordinates->yValue = CIRQUE_PINNACLE_Y_UPPER;
73 }
74}
75
76uint16_t cirque_pinnacle_get_scale(void) { return scale_data; }
77void cirque_pinnacle_set_scale(uint16_t scale) { scale_data = scale; }
78
79// Scales data to desired X & Y resolution
80void cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResolution, uint16_t yResolution) {
81 uint32_t xTemp = 0;
82 uint32_t yTemp = 0;
83
84 ClipCoordinates(coordinates);
85
86 xTemp = coordinates->xValue;
87 yTemp = coordinates->yValue;
88
89 // translate coordinates to (0, 0) reference by subtracting edge-offset
90 xTemp -= CIRQUE_PINNACLE_X_LOWER;
91 yTemp -= CIRQUE_PINNACLE_Y_LOWER;
92
93 // scale coordinates to (xResolution, yResolution) range
94 coordinates->xValue = (uint16_t)(xTemp * xResolution / CIRQUE_PINNACLE_X_RANGE);
95 coordinates->yValue = (uint16_t)(yTemp * yResolution / CIRQUE_PINNACLE_Y_RANGE);
96}
97
98// Clears Status1 register flags (SW_CC and SW_DR)
99void cirque_pinnacle_clear_flags() {
100 RAP_Write(STATUS_1, 0x00);
101 wait_us(50);
102}
103
104// Enables/Disables the feed
105void cirque_pinnacle_enable_feed(bool feedEnable) {
106 uint8_t temp;
107
108 RAP_ReadBytes(FEEDCONFIG_1, &temp, 1); // Store contents of FeedConfig1 register
109
110 if (feedEnable) {
111 temp |= 0x01; // Set Feed Enable bit
112 RAP_Write(0x04, temp);
113 } else {
114 temp &= ~0x01; // Clear Feed Enable bit
115 RAP_Write(0x04, temp);
116 }
117}
118
119/* ERA (Extended Register Access) Functions */
120// Reads <count> bytes from an extended register at <address> (16-bit address),
121// stores values in <*data>
122void ERA_ReadBytes(uint16_t address, uint8_t* data, uint16_t count) {
123 uint8_t ERAControlValue = 0xFF;
124
125 cirque_pinnacle_enable_feed(false); // Disable feed
126
127 RAP_Write(ERA_HIGH_BYTE, (uint8_t)(address >> 8)); // Send upper byte of ERA address
128 RAP_Write(ERA_LOW_BYTE, (uint8_t)(address & 0x00FF)); // Send lower byte of ERA address
129
130 for (uint16_t i = 0; i < count; i++) {
131 RAP_Write(ERA_CONTROL, 0x05); // Signal ERA-read (auto-increment) to Pinnacle
132
133 // Wait for status register 0x1E to clear
134 do {
135 RAP_ReadBytes(ERA_CONTROL, &ERAControlValue, 1);
136 } while (ERAControlValue != 0x00);
137
138 RAP_ReadBytes(ERA_VALUE, data + i, 1);
139
140 cirque_pinnacle_clear_flags();
141 }
142}
143
144// Writes a byte, <data>, to an extended register at <address> (16-bit address)
145void ERA_WriteByte(uint16_t address, uint8_t data) {
146 uint8_t ERAControlValue = 0xFF;
147
148 cirque_pinnacle_enable_feed(false); // Disable feed
149
150 RAP_Write(ERA_VALUE, data); // Send data byte to be written
151
152 RAP_Write(ERA_HIGH_BYTE, (uint8_t)(address >> 8)); // Upper byte of ERA address
153 RAP_Write(ERA_LOW_BYTE, (uint8_t)(address & 0x00FF)); // Lower byte of ERA address
154
155 RAP_Write(ERA_CONTROL, 0x02); // Signal an ERA-write to Pinnacle
156
157 // Wait for status register 0x1E to clear
158 do {
159 RAP_ReadBytes(ERA_CONTROL, &ERAControlValue, 1);
160 } while (ERAControlValue != 0x00);
161
162 cirque_pinnacle_clear_flags();
163}
164
165void cirque_pinnacle_set_adc_attenuation(uint8_t adcGain) {
166 uint8_t temp = 0x00;
167
168 ERA_ReadBytes(0x0187, &temp, 1);
169 temp &= 0x3F; // clear top two bits
170 temp |= adcGain;
171 ERA_WriteByte(0x0187, temp);
172 ERA_ReadBytes(0x0187, &temp, 1);
173}
174
175// Changes thresholds to improve detection of fingers
176void cirque_pinnacle_tune_edge_sensitivity(void) {
177 uint8_t temp = 0x00;
178
179 ERA_ReadBytes(0x0149, &temp, 1);
180 ERA_WriteByte(0x0149, 0x04);
181 ERA_ReadBytes(0x0149, &temp, 1);
182
183 ERA_ReadBytes(0x0168, &temp, 1);
184 ERA_WriteByte(0x0168, 0x03);
185 ERA_ReadBytes(0x0168, &temp, 1);
186}
187
188/* Pinnacle-based TM040040 Functions */
189void cirque_pinnacle_init(void) {
190#if defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi)
191 spi_init();
192#elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c)
193 i2c_init();
194#endif
195
196 touchpad_init = true;
197 // Host clears SW_CC flag
198 cirque_pinnacle_clear_flags();
199
200 // Host configures bits of registers 0x03 and 0x05
201 RAP_Write(SYSCONFIG_1, SYSCONFIG_1_VALUE);
202 RAP_Write(FEEDCONFIG_2, FEEDCONFIG_2_VALUE);
203
204 // Host enables preferred output mode (absolute)
205 RAP_Write(FEEDCONFIG_1, FEEDCONFIG_1_VALUE);
206
207 // Host sets z-idle packet count to 5 (default is 30)
208 RAP_Write(Z_IDLE_COUNT, Z_IDLE_COUNT_VALUE);
209
210 cirque_pinnacle_set_adc_attenuation(0xFF);
211 cirque_pinnacle_tune_edge_sensitivity();
212 cirque_pinnacle_enable_feed(true);
213}
214
215// Reads XYZ data from Pinnacle registers 0x14 through 0x17
216// Stores result in pinnacle_data_t struct with xValue, yValue, and zValue members
217pinnacle_data_t cirque_pinnacle_read_data(void) {
218 uint8_t data[6] = {0};
219 pinnacle_data_t result = {0};
220 RAP_ReadBytes(PACKET_BYTE_0, data, 6);
221
222 cirque_pinnacle_clear_flags();
223
224 result.buttonFlags = data[0] & 0x3F;
225 result.xValue = data[2] | ((data[4] & 0x0F) << 8);
226 result.yValue = data[3] | ((data[4] & 0xF0) << 4);
227 result.zValue = data[5] & 0x3F;
228
229 result.touchDown = (result.xValue != 0 || result.yValue != 0);
230
231 return result;
232}
diff --git a/drivers/sensors/cirque_pinnacle.h b/drivers/sensors/cirque_pinnacle.h
new file mode 100644
index 000000000..db891122a
--- /dev/null
+++ b/drivers/sensors/cirque_pinnacle.h
@@ -0,0 +1,74 @@
1// Copyright (c) 2018 Cirque Corp. Restrictions apply. See: www.cirque.com/sw-license
2
3#pragma once
4
5#include <stdint.h>
6#include <stdbool.h>
7
8// Convenient way to store and access measurements
9typedef struct {
10 uint16_t xValue;
11 uint16_t yValue;
12 uint16_t zValue;
13 uint8_t buttonFlags;
14 bool touchDown;
15} pinnacle_data_t;
16
17void cirque_pinnacle_init(void);
18pinnacle_data_t cirque_pinnacle_read_data(void);
19void cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResolution, uint16_t yResolution);
20uint16_t cirque_pinnacle_get_scale(void);
21void cirque_pinnacle_set_scale(uint16_t scale);
22
23#ifndef CIRQUE_PINNACLE_TIMEOUT
24# define CIRQUE_PINNACLE_TIMEOUT 20
25#endif
26
27// Coordinate scaling values
28#ifndef CIRQUE_PINNACLE_X_LOWER
29# define CIRQUE_PINNACLE_X_LOWER 127 // min "reachable" X value
30#endif
31#ifndef CIRQUE_PINNACLE_X_UPPER
32# define CIRQUE_PINNACLE_X_UPPER 1919 // max "reachable" X value
33#endif
34#ifndef CIRQUE_PINNACLE_Y_LOWER
35# define CIRQUE_PINNACLE_Y_LOWER 63 // min "reachable" Y value
36#endif
37#ifndef CIRQUE_PINNACLE_Y_UPPER
38# define CIRQUE_PINNACLE_Y_UPPER 1471 // max "reachable" Y value
39#endif
40#ifndef CIRQUE_PINNACLE_X_RANGE
41# define CIRQUE_PINNACLE_X_RANGE (CIRQUE_PINNACLE_X_UPPER - CIRQUE_PINNACLE_X_LOWER)
42#endif
43#ifndef CIRQUE_PINNACLE_Y_RANGE
44# define CIRQUE_PINNACLE_Y_RANGE (CIRQUE_PINNACLE_Y_UPPER - CIRQUE_PINNACLE_Y_LOWER)
45#endif
46
47#if defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c)
48# include "i2c_master.h"
49// Cirque's 7-bit I2C Slave Address
50# ifndef CIRQUE_PINNACLE_ADDR
51# define CIRQUE_PINNACLE_ADDR 0x2A
52# endif
53#elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi)
54# include "spi_master.h"
55# ifndef CIRQUE_PINNACLE_CLOCK_SPEED
56# define CIRQUE_PINNACLE_CLOCK_SPEED 10000000
57# endif
58# ifndef CIRQUE_PINNACLE_SPI_LSBFIRST
59# define CIRQUE_PINNACLE_SPI_LSBFIRST false
60# endif
61# ifndef CIRQUE_PINNACLE_SPI_MODE
62# define CIRQUE_PINNACLE_SPI_MODE 1
63# endif
64# ifndef CIRQUE_PINNACLE_SPI_DIVISOR
65# ifdef __AVR__
66# define CIRQUE_PINNACLE_SPI_DIVISOR (F_CPU / CIRQUE_PINNACLE_CLOCK_SPEED)
67# else
68# define CIRQUE_PINNACLE_SPI_DIVISOR 64
69# endif
70# ifndef CIRQUE_PINNACLE_SPI_CS_PIN
71# error "No Chip Select pin has been defined -- missing CIRQUE_PINNACLE_SPI_CS_PIN define"
72# endif
73# endif
74#endif
diff --git a/drivers/sensors/cirque_pinnacle_i2c.c b/drivers/sensors/cirque_pinnacle_i2c.c
new file mode 100644
index 000000000..81dd982b0
--- /dev/null
+++ b/drivers/sensors/cirque_pinnacle_i2c.c
@@ -0,0 +1,43 @@
1// Copyright (c) 2018 Cirque Corp. Restrictions apply. See: www.cirque.com/sw-license
2#include "cirque_pinnacle.h"
3#include "i2c_master.h"
4#include "print.h"
5#include "debug.h"
6#include "stdio.h"
7
8// Masks for Cirque Register Access Protocol (RAP)
9#define WRITE_MASK 0x80
10#define READ_MASK 0xA0
11
12extern bool touchpad_init;
13
14/* RAP Functions */
15// Reads <count> Pinnacle registers starting at <address>
16void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) {
17 uint8_t cmdByte = READ_MASK | address; // Form the READ command byte
18 if (touchpad_init) {
19 i2c_writeReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, NULL, 0, CIRQUE_PINNACLE_TIMEOUT);
20 if (i2c_readReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, data, count, CIRQUE_PINNACLE_TIMEOUT) != I2C_STATUS_SUCCESS) {
21#ifdef CONSOLE_ENABLE
22 dprintf("error right touchpad\n");
23#endif
24 touchpad_init = false;
25 }
26 i2c_stop();
27 }
28}
29
30// Writes single-byte <data> to <address>
31void RAP_Write(uint8_t address, uint8_t data) {
32 uint8_t cmdByte = WRITE_MASK | address; // Form the WRITE command byte
33
34 if (touchpad_init) {
35 if (i2c_writeReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, &data, sizeof(data), CIRQUE_PINNACLE_TIMEOUT) != I2C_STATUS_SUCCESS) {
36#ifdef CONSOLE_ENABLE
37 dprintf("error right touchpad\n");
38#endif
39 touchpad_init = false;
40 }
41 i2c_stop();
42 }
43}
diff --git a/drivers/sensors/cirque_pinnacle_spi.c b/drivers/sensors/cirque_pinnacle_spi.c
new file mode 100644
index 000000000..f3eee8875
--- /dev/null
+++ b/drivers/sensors/cirque_pinnacle_spi.c
@@ -0,0 +1,52 @@
1// Copyright (c) 2018 Cirque Corp. Restrictions apply. See: www.cirque.com/sw-license
2#include "cirque_pinnacle.h"
3#include "spi_master.h"
4#include "print.h"
5#include "debug.h"
6
7// Masks for Cirque Register Access Protocol (RAP)
8#define WRITE_MASK 0x80
9#define READ_MASK 0xA0
10
11extern bool touchpad_init;
12
13/* RAP Functions */
14// Reads <count> Pinnacle registers starting at <address>
15void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) {
16 uint8_t cmdByte = READ_MASK | address; // Form the READ command byte
17 if (touchpad_init) {
18 if (spi_start(CIRQUE_PINNACLE_SPI_CS_PIN, CIRQUE_TRACKPAD_SPI_LSBFIRST, CIRQUE_PINNACLE_SPI_MODE, CIRQUE_PINNACLE_SPI_DIVISOR)) {
19 spi_write(cmdByte);
20 spi_read(); // filler
21 spi_read(); // filler
22 for (uint8_t i = 0; i < count; i++) {
23 data[i] = spi_read(); // each sepsequent read gets another register's contents
24 }
25 } else {
26#ifdef CONSOLE_ENABLE
27 dprintf("error right touchpad\n");
28#endif
29 touchpad_init = false;
30 j
31 }
32 spi_stop();
33 }
34}
35
36// Writes single-byte <data> to <address>
37void RAP_Write(uint8_t address, uint8_t data) {
38 uint8_t cmdByte = WRITE_MASK | address; // Form the WRITE command byte
39
40 if (touchpad_init) {
41 if (spi_start(CIRQUE_PINNACLE_SPI_CS_PIN, CIRQUE_TRACKPAD_SPI_LSBFIRST, CIRQUE_PINNACLE_SPI_MODE, CIRQUE_PINNACLE_SPI_DIVISOR)) {
42 spi_write(cmdByte);
43 spi_write(data);
44 } else {
45#ifdef CONSOLE_ENABLE
46 dprintf("error right touchpad\n");
47#endif
48 touchpad_init = false;
49 }
50 spi_stop();
51 }
52}
diff --git a/drivers/sensors/pimoroni_trackball.c b/drivers/sensors/pimoroni_trackball.c
index 48098ff0c..7d390056e 100644
--- a/drivers/sensors/pimoroni_trackball.c
+++ b/drivers/sensors/pimoroni_trackball.c
@@ -17,73 +17,55 @@
17#include "pimoroni_trackball.h" 17#include "pimoroni_trackball.h"
18#include "i2c_master.h" 18#include "i2c_master.h"
19#include "print.h" 19#include "print.h"
20 20#include "debug.h"
21#ifndef PIMORONI_TRACKBALL_ADDRESS 21#include "timer.h"
22# define PIMORONI_TRACKBALL_ADDRESS 0x0A 22
23#endif 23// clang-format off
24#ifndef PIMORONI_TRACKBALL_INTERVAL_MS 24#define PIMORONI_TRACKBALL_REG_LED_RED 0x00
25# define PIMORONI_TRACKBALL_INTERVAL_MS 8 25#define PIMORONI_TRACKBALL_REG_LED_GRN 0x01
26#endif 26#define PIMORONI_TRACKBALL_REG_LED_BLU 0x02
27#ifndef PIMORONI_TRACKBALL_MOUSE_SCALE 27#define PIMORONI_TRACKBALL_REG_LED_WHT 0x03
28# define PIMORONI_TRACKBALL_MOUSE_SCALE 5 28#define PIMORONI_TRACKBALL_REG_LEFT 0x04
29#endif 29#define PIMORONI_TRACKBALL_REG_RIGHT 0x05
30#ifndef PIMORONI_TRACKBALL_SCROLL_SCALE 30#define PIMORONI_TRACKBALL_REG_UP 0x06
31# define PIMORONI_TRACKBALL_SCROLL_SCALE 1 31#define PIMORONI_TRACKBALL_REG_DOWN 0x07
32#endif 32// clang-format on
33#ifndef PIMORONI_TRACKBALL_DEBOUNCE_CYCLES 33
34# define PIMORONI_TRACKBALL_DEBOUNCE_CYCLES 20 34static uint16_t precision = 128;
35#endif 35
36#ifndef PIMORONI_TRACKBALL_ERROR_COUNT 36float pimoroni_trackball_get_precision(void) { return ((float)precision / 128); }
37# define PIMORONI_TRACKBALL_ERROR_COUNT 10 37void pimoroni_trackball_set_precision(float floatprecision) { precision = (floatprecision * 128); }
38#endif 38
39 39void pimoroni_trackball_set_rgbw(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
40#define TRACKBALL_TIMEOUT 100
41#define TRACKBALL_REG_LED_RED 0x00
42#define TRACKBALL_REG_LED_GRN 0x01
43#define TRACKBALL_REG_LED_BLU 0x02
44#define TRACKBALL_REG_LED_WHT 0x03
45#define TRACKBALL_REG_LEFT 0x04
46#define TRACKBALL_REG_RIGHT 0x05
47#define TRACKBALL_REG_UP 0x06
48#define TRACKBALL_REG_DOWN 0x07
49
50static pimoroni_data current_pimoroni_data;
51static report_mouse_t mouse_report;
52static bool scrolling = false;
53static int16_t x_offset = 0;
54static int16_t y_offset = 0;
55static int16_t h_offset = 0;
56static int16_t v_offset = 0;
57static uint16_t precision = 128;
58static uint8_t error_count = 0;
59
60float trackball_get_precision(void) { return ((float)precision / 128); }
61void trackball_set_precision(float floatprecision) { precision = (floatprecision * 128); }
62bool trackball_is_scrolling(void) { return scrolling; }
63void trackball_set_scrolling(bool scroll) { scrolling = scroll; }
64
65void trackball_set_rgbw(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
66 uint8_t data[4] = {r, g, b, w}; 40 uint8_t data[4] = {r, g, b, w};
67 __attribute__((unused)) i2c_status_t status = i2c_writeReg(PIMORONI_TRACKBALL_ADDRESS << 1, TRACKBALL_REG_LED_RED, data, sizeof(data), TRACKBALL_TIMEOUT); 41 __attribute__((unused)) i2c_status_t status = i2c_writeReg(PIMORONI_TRACKBALL_ADDRESS << 1, PIMORONI_TRACKBALL_REG_LED_RED, data, sizeof(data), PIMORONI_TRACKBALL_TIMEOUT);
68#ifdef TRACKBALL_DEBUG 42
69 dprintf("Trackball RGBW i2c_status_t: %d\n", status); 43#ifdef CONSOLE_ENABLE
44 if (debug_mouse) dprintf("Trackball RGBW i2c_status_t: %d\n", status);
70#endif 45#endif
71} 46}
72 47
73i2c_status_t read_pimoroni_trackball(pimoroni_data* data) { 48i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data) {
74 i2c_status_t status = i2c_readReg(PIMORONI_TRACKBALL_ADDRESS << 1, TRACKBALL_REG_LEFT, (uint8_t*)data, sizeof(*data), TRACKBALL_TIMEOUT); 49 i2c_status_t status = i2c_readReg(PIMORONI_TRACKBALL_ADDRESS << 1, PIMORONI_TRACKBALL_REG_LEFT, (uint8_t*)data, sizeof(*data), PIMORONI_TRACKBALL_TIMEOUT);
75#ifdef TRACKBALL_DEBUG 50#ifdef CONSOLE_ENABLE
76 dprintf("Trackball READ i2c_status_t: %d\nLeft: %d\nRight: %d\nUp: %d\nDown: %d\nSwtich: %d\n", status, data->left, data->right, data->up, data->down, data->click); 51 if (debug_mouse) {
52 static uint16_t d_timer;
53 if (timer_elapsed(d_timer) > PIMORONI_TRACKBALL_DEBUG_INTERVAL) {
54 dprintf("Trackball READ i2c_status_t: %d L: %d R: %d Up: %d D: %d SW: %d\n", status, data->left, data->right, data->up, data->down, data->click);
55 d_timer = timer_read();
56 }
57 }
77#endif 58#endif
59
78 return status; 60 return status;
79} 61}
80 62
81__attribute__((weak)) void pointing_device_init(void) { 63__attribute__((weak)) void pimironi_trackball_device_init(void) {
82 i2c_init(); 64 i2c_init();
83 trackball_set_rgbw(0x00, 0x00, 0x00, 0x00); 65 pimoroni_trackball_set_rgbw(0x00, 0x00, 0x00, 0x00);
84} 66}
85 67
86int16_t trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale) { 68int16_t pimoroni_trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale) {
87 uint8_t offset = 0; 69 uint8_t offset = 0;
88 bool isnegative = false; 70 bool isnegative = false;
89 if (negative_dir > positive_dir) { 71 if (negative_dir > positive_dir) {
@@ -96,7 +78,7 @@ int16_t trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_
96 return isnegative ? -(int16_t)(magnitude) : (int16_t)(magnitude); 78 return isnegative ? -(int16_t)(magnitude) : (int16_t)(magnitude);
97} 79}
98 80
99void trackball_adapt_values(int8_t* mouse, int16_t* offset) { 81void pimoroni_trackball_adapt_values(int8_t* mouse, int16_t* offset) {
100 if (*offset > 127) { 82 if (*offset > 127) {
101 *mouse = 127; 83 *mouse = 127;
102 *offset -= 127; 84 *offset -= 127;
@@ -108,94 +90,3 @@ void trackball_adapt_values(int8_t* mouse, int16_t* offset) {
108 *offset = 0; 90 *offset = 0;
109 } 91 }
110} 92}
111
112__attribute__((weak)) void trackball_click(bool pressed, report_mouse_t* mouse) {
113#ifdef PIMORONI_TRACKBALL_CLICK
114 if (pressed) {
115 mouse->buttons |= MOUSE_BTN1;
116 } else {
117 mouse->buttons &= ~MOUSE_BTN1;
118 }
119#endif
120}
121
122__attribute__((weak)) bool pointing_device_task_user(pimoroni_data* trackball_data) { return true; };
123
124__attribute__((weak)) void pointing_device_task() {
125 static fast_timer_t throttle = 0;
126 static uint16_t debounce = 0;
127
128 if (error_count < PIMORONI_TRACKBALL_ERROR_COUNT && timer_elapsed_fast(throttle) >= PIMORONI_TRACKBALL_INTERVAL_MS) {
129 i2c_status_t status = read_pimoroni_trackball(&current_pimoroni_data);
130
131 if (status == I2C_STATUS_SUCCESS) {
132 error_count = 0;
133
134 if (pointing_device_task_user(&current_pimoroni_data)) {
135 mouse_report = pointing_device_get_report();
136
137 if (!(current_pimoroni_data.click & 128)) {
138 trackball_click(false, &mouse_report);
139 if (!debounce) {
140 if (scrolling) {
141#ifdef PIMORONI_TRACKBALL_INVERT_X
142 h_offset += trackball_get_offsets(current_pimoroni_data.right, current_pimoroni_data.left, PIMORONI_TRACKBALL_SCROLL_SCALE);
143#else
144 h_offset -= trackball_get_offsets(current_pimoroni_data.right, current_pimoroni_data.left, PIMORONI_TRACKBALL_SCROLL_SCALE);
145#endif
146#ifdef PIMORONI_TRACKBALL_INVERT_Y
147 v_offset += trackball_get_offsets(current_pimoroni_data.down, current_pimoroni_data.up, PIMORONI_TRACKBALL_SCROLL_SCALE);
148#else
149 v_offset -= trackball_get_offsets(current_pimoroni_data.down, current_pimoroni_data.up, PIMORONI_TRACKBALL_SCROLL_SCALE);
150#endif
151 } else {
152#ifdef PIMORONI_TRACKBALL_INVERT_X
153 x_offset -= trackball_get_offsets(current_pimoroni_data.right, current_pimoroni_data.left, PIMORONI_TRACKBALL_MOUSE_SCALE);
154#else
155 x_offset += trackball_get_offsets(current_pimoroni_data.right, current_pimoroni_data.left, PIMORONI_TRACKBALL_MOUSE_SCALE);
156#endif
157#ifdef PIMORONI_TRACKBALL_INVERT_Y
158 y_offset -= trackball_get_offsets(current_pimoroni_data.down, current_pimoroni_data.up, PIMORONI_TRACKBALL_MOUSE_SCALE);
159#else
160 y_offset += trackball_get_offsets(current_pimoroni_data.down, current_pimoroni_data.up, PIMORONI_TRACKBALL_MOUSE_SCALE);
161#endif
162 }
163 if (scrolling) {
164#ifndef PIMORONI_TRACKBALL_ROTATE
165 trackball_adapt_values(&mouse_report.h, &h_offset);
166 trackball_adapt_values(&mouse_report.v, &v_offset);
167#else
168 trackball_adapt_values(&mouse_report.h, &v_offset);
169 trackball_adapt_values(&mouse_report.v, &h_offset);
170#endif
171 mouse_report.x = 0;
172 mouse_report.y = 0;
173 } else {
174#ifndef PIMORONI_TRACKBALL_ROTATE
175 trackball_adapt_values(&mouse_report.x, &x_offset);
176 trackball_adapt_values(&mouse_report.y, &y_offset);
177#else
178 trackball_adapt_values(&mouse_report.x, &y_offset);
179 trackball_adapt_values(&mouse_report.y, &x_offset);
180#endif
181 mouse_report.h = 0;
182 mouse_report.v = 0;
183 }
184 } else {
185 debounce--;
186 }
187 } else {
188 trackball_click(true, &mouse_report);
189 debounce = PIMORONI_TRACKBALL_DEBOUNCE_CYCLES;
190 }
191 }
192 } else {
193 error_count++;
194 }
195
196 pointing_device_set_report(mouse_report);
197 pointing_device_send();
198
199 throttle = timer_read_fast();
200 }
201}
diff --git a/drivers/sensors/pimoroni_trackball.h b/drivers/sensors/pimoroni_trackball.h
index 6b2a41425..59ee8724b 100644
--- a/drivers/sensors/pimoroni_trackball.h
+++ b/drivers/sensors/pimoroni_trackball.h
@@ -16,22 +16,46 @@
16 */ 16 */
17#pragma once 17#pragma once
18 18
19#include "quantum.h" 19#include <stdint.h>
20#include "pointing_device.h" 20#include "report.h"
21#include "i2c_master.h"
21 22
22typedef struct pimoroni_data { 23#ifndef PIMORONI_TRACKBALL_ADDRESS
24# define PIMORONI_TRACKBALL_ADDRESS 0x0A
25#endif
26#ifndef PIMORONI_TRACKBALL_INTERVAL_MS
27# define PIMORONI_TRACKBALL_INTERVAL_MS 8
28#endif
29#ifndef PIMORONI_TRACKBALL_SCALE
30# define PIMORONI_TRACKBALL_SCALE 5
31#endif
32#ifndef PIMORONI_TRACKBALL_DEBOUNCE_CYCLES
33# define PIMORONI_TRACKBALL_DEBOUNCE_CYCLES 20
34#endif
35#ifndef PIMORONI_TRACKBALL_ERROR_COUNT
36# define PIMORONI_TRACKBALL_ERROR_COUNT 10
37#endif
38
39#ifndef PIMORONI_TRACKBALL_TIMEOUT
40# define PIMORONI_TRACKBALL_TIMEOUT 100
41#endif
42
43#ifndef PIMORONI_TRACKBALL_DEBUG_INTERVAL
44# define PIMORONI_TRACKBALL_DEBUG_INTERVAL 100
45#endif
46
47typedef struct {
23 uint8_t left; 48 uint8_t left;
24 uint8_t right; 49 uint8_t right;
25 uint8_t up; 50 uint8_t up;
26 uint8_t down; 51 uint8_t down;
27 uint8_t click; 52 uint8_t click;
28} pimoroni_data; 53} pimoroni_data_t;
29 54
30void trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white); 55void pimironi_trackball_device_init(void);
31void trackball_click(bool pressed, report_mouse_t* mouse); 56void pimoroni_trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white);
32int16_t trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale); 57int16_t pimoroni_trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale);
33void trackball_adapt_values(int8_t* mouse, int16_t* offset); 58void pimoroni_trackball_adapt_values(int8_t* mouse, int16_t* offset);
34float trackball_get_precision(void); 59float pimoroni_trackball_get_precision(void);
35void trackball_set_precision(float precision); 60void pimoroni_trackball_set_precision(float precision);
36bool trackball_is_scrolling(void); 61i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data);
37void trackball_set_scrolling(bool scroll);
diff --git a/drivers/sensors/pmw3360.c b/drivers/sensors/pmw3360.c
index 79b653e45..2b27dccbb 100644
--- a/drivers/sensors/pmw3360.c
+++ b/drivers/sensors/pmw3360.c
@@ -20,62 +20,71 @@
20#include "wait.h" 20#include "wait.h"
21#include "debug.h" 21#include "debug.h"
22#include "print.h" 22#include "print.h"
23#include "pmw3360_firmware.h" 23#include PMW3360_FIRMWARE_H
24 24
25// Registers 25// Registers
26#define REG_Product_ID 0x00 26// clang-format off
27#define REG_Revision_ID 0x01 27#define REG_Product_ID 0x00
28#define REG_Motion 0x02 28#define REG_Revision_ID 0x01
29#define REG_Delta_X_L 0x03 29#define REG_Motion 0x02
30#define REG_Delta_X_H 0x04 30#define REG_Delta_X_L 0x03
31#define REG_Delta_Y_L 0x05 31#define REG_Delta_X_H 0x04
32#define REG_Delta_Y_H 0x06 32#define REG_Delta_Y_L 0x05
33#define REG_SQUAL 0x07 33#define REG_Delta_Y_H 0x06
34#define REG_Raw_Data_Sum 0x08 34#define REG_SQUAL 0x07
35#define REG_Maximum_Raw_data 0x09 35#define REG_Raw_Data_Sum 0x08
36#define REG_Minimum_Raw_data 0x0A 36#define REG_Maximum_Raw_data 0x09
37#define REG_Shutter_Lower 0x0B 37#define REG_Minimum_Raw_data 0x0A
38#define REG_Shutter_Upper 0x0C 38#define REG_Shutter_Lower 0x0B
39#define REG_Control 0x0D 39#define REG_Shutter_Upper 0x0C
40#define REG_Config1 0x0F 40#define REG_Control 0x0D
41#define REG_Config2 0x10 41#define REG_Config1 0x0F
42#define REG_Angle_Tune 0x11 42#define REG_Config2 0x10
43#define REG_Frame_Capture 0x12 43#define REG_Angle_Tune 0x11
44#define REG_SROM_Enable 0x13 44#define REG_Frame_Capture 0x12
45#define REG_Run_Downshift 0x14 45#define REG_SROM_Enable 0x13
46#define REG_Rest1_Rate_Lower 0x15 46#define REG_Run_Downshift 0x14
47#define REG_Rest1_Rate_Upper 0x16 47#define REG_Rest1_Rate_Lower 0x15
48#define REG_Rest1_Downshift 0x17 48#define REG_Rest1_Rate_Upper 0x16
49#define REG_Rest2_Rate_Lower 0x18 49#define REG_Rest1_Downshift 0x17
50#define REG_Rest2_Rate_Upper 0x19 50#define REG_Rest2_Rate_Lower 0x18
51#define REG_Rest2_Downshift 0x1A 51#define REG_Rest2_Rate_Upper 0x19
52#define REG_Rest3_Rate_Lower 0x1B 52#define REG_Rest2_Downshift 0x1A
53#define REG_Rest3_Rate_Upper 0x1C 53#define REG_Rest3_Rate_Lower 0x1B
54#define REG_Observation 0x24 54#define REG_Rest3_Rate_Upper 0x1C
55#define REG_Data_Out_Lower 0x25 55#define REG_Observation 0x24
56#define REG_Data_Out_Upper 0x26 56#define REG_Data_Out_Lower 0x25
57#define REG_Raw_Data_Dump 0x29 57#define REG_Data_Out_Upper 0x26
58#define REG_SROM_ID 0x2A 58#define REG_Raw_Data_Dump 0x29
59#define REG_Min_SQ_Run 0x2B 59#define REG_SROM_ID 0x2A
60#define REG_Raw_Data_Threshold 0x2C 60#define REG_Min_SQ_Run 0x2B
61#define REG_Config5 0x2F 61#define REG_Raw_Data_Threshold 0x2C
62#define REG_Power_Up_Reset 0x3A 62#define REG_Config5 0x2F
63#define REG_Shutdown 0x3B 63#define REG_Power_Up_Reset 0x3A
64#define REG_Inverse_Product_ID 0x3F 64#define REG_Shutdown 0x3B
65#define REG_LiftCutoff_Tune3 0x41 65#define REG_Inverse_Product_ID 0x3F
66#define REG_Angle_Snap 0x42 66#define REG_LiftCutoff_Tune3 0x41
67#define REG_LiftCutoff_Tune1 0x4A 67#define REG_Angle_Snap 0x42
68#define REG_Motion_Burst 0x50 68#define REG_LiftCutoff_Tune1 0x4A
69#define REG_LiftCutoff_Tune_Timeout 0x58 69#define REG_Motion_Burst 0x50
70#define REG_LiftCutoff_Tune_Timeout 0x58
70#define REG_LiftCutoff_Tune_Min_Length 0x5A 71#define REG_LiftCutoff_Tune_Min_Length 0x5A
71#define REG_SROM_Load_Burst 0x62 72#define REG_SROM_Load_Burst 0x62
72#define REG_Lift_Config 0x63 73#define REG_Lift_Config 0x63
73#define REG_Raw_Data_Burst 0x64 74#define REG_Raw_Data_Burst 0x64
74#define REG_LiftCutoff_Tune2 0x65 75#define REG_LiftCutoff_Tune2 0x65
76// clang-format on
77
78#ifndef MAX_CPI
79# define MAX_CPI 0x77 // limits to 0--119, should be max cpi/100
80#endif
75 81
76bool _inBurst = false; 82bool _inBurst = false;
77 83
84#ifdef CONSOLE_ENABLE
78void print_byte(uint8_t byte) { dprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0')); } 85void print_byte(uint8_t byte) { dprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0')); }
86#endif
87#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
79 88
80bool spi_start_adv(void) { 89bool spi_start_adv(void) {
81 bool status = spi_start(PMW3360_CS_PIN, PMW3360_SPI_LSBFIRST, PMW3360_SPI_MODE, PMW3360_SPI_DIVISOR); 90 bool status = spi_start(PMW3360_CS_PIN, PMW3360_SPI_LSBFIRST, PMW3360_SPI_MODE, PMW3360_SPI_DIVISOR);
@@ -124,20 +133,20 @@ uint8_t spi_read_adv(uint8_t reg_addr) {
124 return data; 133 return data;
125} 134}
126 135
127void pmw_set_cpi(uint16_t cpi) { 136void pmw3360_set_cpi(uint16_t cpi) {
128 uint8_t cpival = constrain((cpi / 100) - 1, 0, 0x77); // limits to 0--119 137 uint8_t cpival = constrain((cpi / 100) - 1, 0, MAX_CPI);
129 138
130 spi_start_adv(); 139 spi_start_adv();
131 spi_write_adv(REG_Config1, cpival); 140 spi_write_adv(REG_Config1, cpival);
132 spi_stop(); 141 spi_stop();
133} 142}
134 143
135uint16_t pmw_get_cpi(void) { 144uint16_t pmw3360_get_cpi(void) {
136 uint8_t cpival = spi_read_adv(REG_Config1); 145 uint8_t cpival = spi_read_adv(REG_Config1);
137 return (uint16_t)(cpival & 0xFF) * 100; 146 return (uint16_t)(cpival & 0xFF) * 100;
138} 147}
139 148
140bool pmw_spi_init(void) { 149bool pmw3360_init(void) {
141 setPinOutput(PMW3360_CS_PIN); 150 setPinOutput(PMW3360_CS_PIN);
142 151
143 spi_init(); 152 spi_init();
@@ -164,12 +173,12 @@ bool pmw_spi_init(void) {
164 spi_read_adv(REG_Delta_Y_L); 173 spi_read_adv(REG_Delta_Y_L);
165 spi_read_adv(REG_Delta_Y_H); 174 spi_read_adv(REG_Delta_Y_H);
166 175
167 pmw_upload_firmware(); 176 pmw3360_upload_firmware();
168 177
169 spi_stop_adv(); 178 spi_stop_adv();
170 179
171 wait_ms(10); 180 wait_ms(10);
172 pmw_set_cpi(PMW3360_CPI); 181 pmw3360_set_cpi(PMW3360_CPI);
173 182
174 wait_ms(1); 183 wait_ms(1);
175 184
@@ -177,14 +186,14 @@ bool pmw_spi_init(void) {
177 186
178 spi_write_adv(REG_Angle_Tune, constrain(ROTATIONAL_TRANSFORM_ANGLE, -30, 30)); 187 spi_write_adv(REG_Angle_Tune, constrain(ROTATIONAL_TRANSFORM_ANGLE, -30, 30));
179 188
180 bool init_success = pmw_check_signature(); 189 bool init_success = pmw3360_check_signature();
181 190
182 writePinLow(PMW3360_CS_PIN); 191 writePinLow(PMW3360_CS_PIN);
183 192
184 return init_success; 193 return init_success;
185} 194}
186 195
187void pmw_upload_firmware(void) { 196void pmw3360_upload_firmware(void) {
188 spi_write_adv(REG_SROM_Enable, 0x1d); 197 spi_write_adv(REG_SROM_Enable, 0x1d);
189 198
190 wait_ms(10); 199 wait_ms(10);
@@ -211,16 +220,18 @@ void pmw_upload_firmware(void) {
211 wait_ms(10); 220 wait_ms(10);
212} 221}
213 222
214bool pmw_check_signature(void) { 223bool pmw3360_check_signature(void) {
215 uint8_t pid = spi_read_adv(REG_Product_ID); 224 uint8_t pid = spi_read_adv(REG_Product_ID);
216 uint8_t iv_pid = spi_read_adv(REG_Inverse_Product_ID); 225 uint8_t iv_pid = spi_read_adv(REG_Inverse_Product_ID);
217 uint8_t SROM_ver = spi_read_adv(REG_SROM_ID); 226 uint8_t SROM_ver = spi_read_adv(REG_SROM_ID);
218 return (pid == 0x42 && iv_pid == 0xBD && SROM_ver == 0x04); // signature for SROM 0x04 227 return (pid == firmware_signature[0] && iv_pid == firmware_signature[1] && SROM_ver == firmware_signature[2]); // signature for SROM 0x04
219} 228}
220 229
221report_pmw_t pmw_read_burst(void) { 230report_pmw3360_t pmw3360_read_burst(void) {
222 if (!_inBurst) { 231 if (!_inBurst) {
232#ifdef CONSOLE_ENABLE
223 dprintf("burst on"); 233 dprintf("burst on");
234#endif
224 spi_write_adv(REG_Motion_Burst, 0x00); 235 spi_write_adv(REG_Motion_Burst, 0x00);
225 _inBurst = true; 236 _inBurst = true;
226 } 237 }
@@ -229,12 +240,7 @@ report_pmw_t pmw_read_burst(void) {
229 spi_write(REG_Motion_Burst); 240 spi_write(REG_Motion_Burst);
230 wait_us(35); // waits for tSRAD 241 wait_us(35); // waits for tSRAD
231 242
232 report_pmw_t data; 243 report_pmw3360_t data = {0};
233 data.motion = 0;
234 data.dx = 0;
235 data.mdx = 0;
236 data.dy = 0;
237 data.mdx = 0;
238 244
239 data.motion = spi_read(); 245 data.motion = spi_read();
240 spi_write(0x00); // skip Observation 246 spi_write(0x00); // skip Observation
@@ -245,6 +251,7 @@ report_pmw_t pmw_read_burst(void) {
245 251
246 spi_stop(); 252 spi_stop();
247 253
254#ifdef CONSOLE_ENABLE
248 if (debug_mouse) { 255 if (debug_mouse) {
249 print_byte(data.motion); 256 print_byte(data.motion);
250 print_byte(data.dx); 257 print_byte(data.dx);
@@ -253,6 +260,7 @@ report_pmw_t pmw_read_burst(void) {
253 print_byte(data.mdy); 260 print_byte(data.mdy);
254 dprintf("\n"); 261 dprintf("\n");
255 } 262 }
263#endif
256 264
257 data.isMotion = (data.motion & 0x80) != 0; 265 data.isMotion = (data.motion & 0x80) != 0;
258 data.isOnSurface = (data.motion & 0x08) == 0; 266 data.isOnSurface = (data.motion & 0x08) == 0;
diff --git a/drivers/sensors/pmw3360.h b/drivers/sensors/pmw3360.h
index 7429a6ba0..7b2bef5b8 100644
--- a/drivers/sensors/pmw3360.h
+++ b/drivers/sensors/pmw3360.h
@@ -18,6 +18,8 @@
18 18
19#pragma once 19#pragma once
20 20
21#include <stdint.h>
22#include "report.h"
21#include "spi_master.h" 23#include "spi_master.h"
22 24
23#ifndef PMW3360_CPI 25#ifndef PMW3360_CPI
@@ -25,7 +27,7 @@
25#endif 27#endif
26 28
27#ifndef PMW3360_CLOCK_SPEED 29#ifndef PMW3360_CLOCK_SPEED
28# define PMW3360_CLOCK_SPEED 70000000 30# define PMW3360_CLOCK_SPEED 2000000
29#endif 31#endif
30 32
31#ifndef PMW3360_SPI_LSBFIRST 33#ifndef PMW3360_SPI_LSBFIRST
@@ -52,6 +54,17 @@
52# error "No chip select pin defined -- missing PMW3360_CS_PIN" 54# error "No chip select pin defined -- missing PMW3360_CS_PIN"
53#endif 55#endif
54 56
57/*
58The pmw33660 and pmw3389 use the same registers and timing and such.
59The only differences between the two is the firmware used, and the
60range for the DPI. So add a semi-secret hack to allow use of the
61pmw3389's firmware blob. Also, can set the max cpi range too.
62This should work for the 3390 and 3391 too, in theory.
63*/
64#ifndef PMW3360_FIRMWARE_H
65# define PMW3360_FIRMWARE_H "pmw3360_firmware.h"
66#endif
67
55#ifdef CONSOLE_ENABLE 68#ifdef CONSOLE_ENABLE
56void print_byte(uint8_t byte); 69void print_byte(uint8_t byte);
57#endif 70#endif
@@ -64,19 +77,18 @@ typedef struct {
64 int8_t mdx; 77 int8_t mdx;
65 int16_t dy; // displacement on y directions. 78 int16_t dy; // displacement on y directions.
66 int8_t mdy; 79 int8_t mdy;
67} report_pmw_t; 80} report_pmw3360_t;
68 81
69bool spi_start_adv(void); 82bool spi_start_adv(void);
70void spi_stop_adv(void); 83void spi_stop_adv(void);
71spi_status_t spi_write_adv(uint8_t reg_addr, uint8_t data); 84spi_status_t spi_write_adv(uint8_t reg_addr, uint8_t data);
72uint8_t spi_read_adv(uint8_t reg_addr); 85uint8_t spi_read_adv(uint8_t reg_addr);
73bool pmw_spi_init(void); 86bool pmw3360_init(void);
74void pmw_set_cpi(uint16_t cpi); 87void pmw3360_set_cpi(uint16_t cpi);
75uint16_t pmw_get_cpi(void); 88uint16_t pmw3360_get_cpi(void);
76void pmw_upload_firmware(void); 89void pmw3360_upload_firmware(void);
77bool pmw_check_signature(void); 90bool pmw3360_check_signature(void);
78report_pmw_t pmw_read_burst(void); 91report_pmw3360_t pmw3360_read_burst(void);
79 92
80#define degToRad(angleInDegrees) ((angleInDegrees)*M_PI / 180.0) 93#define degToRad(angleInDegrees) ((angleInDegrees)*M_PI / 180.0)
81#define radToDeg(angleInRadians) ((angleInRadians)*180.0 / M_PI) 94#define radToDeg(angleInRadians) ((angleInRadians)*180.0 / M_PI)
82#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
diff --git a/drivers/sensors/pmw3360_firmware.h b/drivers/sensors/pmw3360_firmware.h
index 4d5fe7a0b..ed9fda5a7 100644
--- a/drivers/sensors/pmw3360_firmware.h
+++ b/drivers/sensors/pmw3360_firmware.h
@@ -20,8 +20,13 @@
20 20
21#include "progmem.h" 21#include "progmem.h"
22 22
23// PID, Inverse PID, SROM version
24const uint8_t firmware_signature[] PROGMEM = {0x42, 0xBD, 0x04};
25
23#define FIRMWARE_LENGTH 4094 26#define FIRMWARE_LENGTH 4094
24 27
28// Firmware Blob foor PMW3360
29
25// clang-format off 30// clang-format off
26const uint8_t firmware_data[FIRMWARE_LENGTH] PROGMEM = { 31const uint8_t firmware_data[FIRMWARE_LENGTH] PROGMEM = {
27 0x01, 0x04, 0x8E, 0x96, 0x6E, 0x77, 0x3E, 0xFE, 0x7E, 0x5F, 0x1D, 0xB8, 0xF2, 0x66, 0x4E, 0xFF, 32 0x01, 0x04, 0x8E, 0x96, 0x6E, 0x77, 0x3E, 0xFE, 0x7E, 0x5F, 0x1D, 0xB8, 0xF2, 0x66, 0x4E, 0xFF,
diff --git a/drivers/sensors/pmw3389_firmware.h b/drivers/sensors/pmw3389_firmware.h
new file mode 100644
index 000000000..0564dab73
--- /dev/null
+++ b/drivers/sensors/pmw3389_firmware.h
@@ -0,0 +1,303 @@
1/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
2 * Copyright 2019 Sunjun Kim
3 * Copyright 2020 Ploopy Corporation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#pragma once
20
21// PID, Inverse PID, SROM version
22const uint8_t firmware_signature[] PROGMEM = {0x42, 0xBD, 0x04};
23
24// clang-format off
25// Firmware Blob foor PMW3389
26const uint16_t firmware_length = 4094;
27// clang-format off
28const uint8_t firmware_data[] PROGMEM = { // SROM 0x04
290x01, 0xe8, 0xba, 0x26, 0x0b, 0xb2, 0xbe, 0xfe, 0x7e, 0x5f, 0x3c, 0xdb, 0x15, 0xa8, 0xb3,
300xe4, 0x2b, 0xb5, 0xe8, 0x53, 0x07, 0x6d, 0x3b, 0xd1, 0x20, 0xc2, 0x06, 0x6f, 0x3d, 0xd9,
310x11, 0xa0, 0xc2, 0xe7, 0x2d, 0xb9, 0xd1, 0x20, 0xa3, 0xa5, 0xc8, 0xf3, 0x64, 0x4a, 0xf7,
320x4d, 0x18, 0x93, 0xa4, 0xca, 0xf7, 0x6c, 0x5a, 0x36, 0xee, 0x5e, 0x3e, 0xfe, 0x7e, 0x7e,
330x5f, 0x1d, 0x99, 0xb0, 0xc3, 0xe5, 0x29, 0xd3, 0x03, 0x65, 0x48, 0x12, 0x87, 0x6d, 0x58,
340x32, 0xe6, 0x2f, 0xdc, 0x3a, 0xf2, 0x4f, 0xfd, 0x59, 0x11, 0x81, 0x61, 0x21, 0xc0, 0x02,
350x86, 0x8e, 0x7f, 0x5d, 0x38, 0xf2, 0x47, 0x0c, 0x7b, 0x55, 0x28, 0xb3, 0xe4, 0x4a, 0x16,
360xab, 0xbf, 0xdd, 0x38, 0xf2, 0x66, 0x4e, 0xff, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xa5, 0xc8,
370x12, 0xa6, 0xaf, 0xdc, 0x3a, 0xd1, 0x41, 0x60, 0x75, 0x58, 0x24, 0x92, 0xd4, 0x72, 0x6c,
380xe0, 0x2f, 0xfd, 0x23, 0x8d, 0x1c, 0x5b, 0xb2, 0x97, 0x36, 0x3d, 0x0b, 0xa2, 0x49, 0xb1,
390x58, 0xf2, 0x1f, 0xc0, 0xcb, 0xf8, 0x41, 0x4f, 0xcd, 0x1e, 0x6b, 0x39, 0xa7, 0x2b, 0xe9,
400x30, 0x16, 0x83, 0xd2, 0x0e, 0x47, 0x8f, 0xe3, 0xb1, 0xdf, 0xa2, 0x15, 0xdb, 0x5d, 0x30,
410xc5, 0x1a, 0xab, 0x31, 0x99, 0xf3, 0xfa, 0xb2, 0x86, 0x69, 0xad, 0x7a, 0xe8, 0xa7, 0x18,
420x6a, 0xcc, 0xc8, 0x65, 0x23, 0x87, 0xa8, 0x5f, 0xf5, 0x21, 0x59, 0x75, 0x09, 0x71, 0x45,
430x55, 0x25, 0x4b, 0xda, 0xa1, 0xc3, 0xf7, 0x41, 0xab, 0x59, 0xd9, 0x74, 0x12, 0x55, 0x5f,
440xbc, 0xaf, 0xd9, 0xfd, 0xb0, 0x1e, 0xa3, 0x0f, 0xff, 0xde, 0x11, 0x16, 0x6a, 0xae, 0x0e,
450xe1, 0x5d, 0x3c, 0x10, 0x43, 0x9a, 0xa1, 0x0b, 0x24, 0x8f, 0x0d, 0x7f, 0x0b, 0x5e, 0x4c,
460x42, 0xa4, 0x84, 0x2c, 0x40, 0xd0, 0x55, 0x39, 0xe6, 0x4b, 0xf8, 0x9b, 0x2f, 0xdc, 0x28,
470xff, 0xfa, 0xb5, 0x85, 0x19, 0xe5, 0x28, 0xa1, 0x77, 0xaa, 0x73, 0xf3, 0x03, 0xc7, 0x62,
480xa6, 0x91, 0x18, 0xc9, 0xb0, 0xcd, 0x05, 0xdc, 0xca, 0x81, 0x26, 0x1a, 0x47, 0x40, 0xda,
490x36, 0x7d, 0x6a, 0x53, 0xc8, 0x5a, 0x77, 0x5d, 0x19, 0xa4, 0x1b, 0x23, 0x83, 0xd0, 0xb2,
500xaa, 0x0e, 0xbf, 0x77, 0x4e, 0x3a, 0x3b, 0x59, 0x00, 0x31, 0x0d, 0x02, 0x1b, 0x88, 0x7a,
510xd4, 0xbd, 0x9d, 0xcc, 0x58, 0x04, 0x69, 0xf6, 0x3b, 0xca, 0x42, 0xe2, 0xfd, 0xc3, 0x3d,
520x39, 0xc5, 0xd0, 0x71, 0xe4, 0xc8, 0xb7, 0x3e, 0x3f, 0xc8, 0xe9, 0xca, 0xc9, 0x3f, 0x04,
530x4e, 0x1b, 0x79, 0xca, 0xa5, 0x61, 0xc2, 0xed, 0x1d, 0xa6, 0xda, 0x5a, 0xe9, 0x7f, 0x65,
540x8c, 0xbe, 0x12, 0x6e, 0xa4, 0x5b, 0x33, 0x2f, 0x84, 0x28, 0x9c, 0x1c, 0x88, 0x2d, 0xff,
550x07, 0xbf, 0xa6, 0xd7, 0x5a, 0x88, 0x86, 0xb0, 0x3f, 0xf6, 0x31, 0x5b, 0x11, 0x6d, 0xf5,
560x58, 0xeb, 0x58, 0x02, 0x9e, 0xb5, 0x9a, 0xb1, 0xff, 0x25, 0x9d, 0x8b, 0x4f, 0xb6, 0x0a,
570xf9, 0xea, 0x3e, 0x3f, 0x21, 0x09, 0x65, 0x21, 0x22, 0xfe, 0x3d, 0x4e, 0x11, 0x5b, 0x9e,
580x5a, 0x59, 0x8b, 0xdd, 0xd8, 0xce, 0xd6, 0xd9, 0x59, 0xd2, 0x1e, 0xfd, 0xef, 0x0d, 0x1b,
590xd9, 0x61, 0x7f, 0xd7, 0x2d, 0xad, 0x62, 0x09, 0xe5, 0x22, 0x63, 0xea, 0xc7, 0x31, 0xd9,
600xa1, 0x38, 0x80, 0x5c, 0xa7, 0x32, 0x82, 0xec, 0x1b, 0xa2, 0x49, 0x5a, 0x06, 0xd2, 0x7c,
610xc9, 0x96, 0x57, 0xbb, 0x17, 0x75, 0xfc, 0x7a, 0x8f, 0x0d, 0x77, 0xb5, 0x7a, 0x8e, 0x3e,
620xf4, 0xba, 0x2f, 0x69, 0x13, 0x26, 0xd6, 0xd9, 0x21, 0x60, 0x2f, 0x21, 0x3e, 0x87, 0xee,
630xfd, 0x87, 0x16, 0x0d, 0xc8, 0x08, 0x00, 0x25, 0x71, 0xac, 0x2c, 0x03, 0x2a, 0x37, 0x2d,
640xb3, 0x34, 0x09, 0x91, 0xe3, 0x06, 0x2c, 0x38, 0x37, 0x95, 0x3b, 0x17, 0x7a, 0xaf, 0xac,
650x99, 0x55, 0xab, 0x41, 0x39, 0x5f, 0x8e, 0xa6, 0x43, 0x80, 0x03, 0x88, 0x6f, 0x7d, 0xbd,
660x5a, 0xb4, 0x2b, 0x32, 0x23, 0x5a, 0xa9, 0x31, 0x32, 0x39, 0x4c, 0x5b, 0xf4, 0x6b, 0xaf,
670x66, 0x6f, 0x3c, 0x8e, 0x2d, 0x82, 0x97, 0x9f, 0x4a, 0x01, 0xdc, 0x99, 0x98, 0x00, 0xec,
680x38, 0x7a, 0x79, 0x70, 0xa6, 0x85, 0xd6, 0x21, 0x63, 0x0d, 0x45, 0x9a, 0x2e, 0x5e, 0xa7,
690xb1, 0xea, 0x66, 0x6a, 0xbc, 0x62, 0x2d, 0x7b, 0x7d, 0x85, 0xea, 0x95, 0x2f, 0xc0, 0xe8,
700x6f, 0x35, 0xa0, 0x3a, 0x02, 0x25, 0xbc, 0xb2, 0x5f, 0x5c, 0x43, 0x96, 0xcc, 0x26, 0xd2,
710x16, 0xb4, 0x96, 0x73, 0xd7, 0x13, 0xc7, 0xae, 0x53, 0x15, 0x31, 0x89, 0x68, 0x66, 0x6d,
720x2c, 0x92, 0x1f, 0xcc, 0x5b, 0xa7, 0x8f, 0x5d, 0xbb, 0xc9, 0xdb, 0xe8, 0x3b, 0x9d, 0x61,
730x74, 0x8b, 0x05, 0xa1, 0x58, 0x52, 0x68, 0xee, 0x3d, 0x39, 0x79, 0xa0, 0x9b, 0xdd, 0xe1,
740x55, 0xc9, 0x60, 0xeb, 0xad, 0xb8, 0x5b, 0xc2, 0x5a, 0xb5, 0x2c, 0x18, 0x55, 0xa9, 0x50,
750xc3, 0xf6, 0x72, 0x5f, 0xcc, 0xe2, 0xf4, 0x55, 0xb5, 0xd6, 0xb5, 0x4a, 0x99, 0xa5, 0x28,
760x74, 0x97, 0x18, 0xe8, 0xc0, 0x84, 0x89, 0x50, 0x03, 0x86, 0x4d, 0x1a, 0xb7, 0x09, 0x90,
770xa2, 0x01, 0x04, 0xbb, 0x73, 0x62, 0xcb, 0x97, 0x22, 0x70, 0x5d, 0x52, 0x41, 0x8e, 0xd9,
780x90, 0x15, 0xaa, 0xab, 0x0a, 0x31, 0x65, 0xb4, 0xda, 0xd0, 0xee, 0x24, 0xc9, 0x41, 0x91,
790x1e, 0xbc, 0x46, 0x70, 0x40, 0x9d, 0xda, 0x0e, 0x2a, 0xe4, 0xb2, 0x4c, 0x9f, 0xf2, 0xfc,
800xf3, 0x84, 0x17, 0x44, 0x1e, 0xd7, 0xca, 0x23, 0x1f, 0x3f, 0x5a, 0x22, 0x3d, 0xaf, 0x9b,
810x2d, 0xfc, 0x41, 0xad, 0x26, 0xb4, 0x45, 0x67, 0x0b, 0x80, 0x0e, 0xf9, 0x61, 0x37, 0xec,
820x3b, 0xf4, 0x4b, 0x14, 0xdf, 0x5a, 0x0c, 0x3a, 0x50, 0x0b, 0x14, 0x0c, 0x72, 0xae, 0xc6,
830xc5, 0xec, 0x35, 0x53, 0x2d, 0x59, 0xed, 0x91, 0x74, 0xe2, 0xc4, 0xc8, 0xf2, 0x25, 0x6b,
840x97, 0x6f, 0xc9, 0x76, 0xce, 0xa9, 0xb1, 0x99, 0x8f, 0x5a, 0x92, 0x3b, 0xc4, 0x8d, 0x54,
850x50, 0x40, 0x72, 0xd6, 0x90, 0x83, 0xfc, 0xe5, 0x49, 0x8b, 0x17, 0xf5, 0xfd, 0x6b, 0x8d,
860x32, 0x02, 0xe9, 0x0a, 0xfe, 0xbf, 0x00, 0x6b, 0xa3, 0xad, 0x5f, 0x09, 0x4b, 0x97, 0x2b,
870x00, 0x58, 0x65, 0x2e, 0x07, 0x49, 0x0a, 0x3b, 0x6b, 0x2e, 0x50, 0x6c, 0x1d, 0xac, 0xb7,
880x6a, 0x26, 0xd8, 0x13, 0xa4, 0xca, 0x16, 0xae, 0xab, 0x93, 0xb9, 0x1c, 0x1c, 0xb4, 0x47,
890x6a, 0x38, 0x36, 0x17, 0x27, 0xc9, 0x7f, 0xc7, 0x64, 0xcb, 0x89, 0x58, 0xc5, 0x61, 0xc2,
900xc6, 0xea, 0x15, 0x0b, 0x34, 0x0c, 0x5d, 0x61, 0x76, 0x6e, 0x2b, 0x62, 0x40, 0x92, 0xa3,
910x6c, 0xef, 0xf4, 0xe4, 0xc3, 0xa1, 0xa8, 0xf5, 0x94, 0x79, 0x0d, 0xd1, 0x3d, 0xcb, 0x3d,
920x40, 0xb6, 0xd0, 0xf0, 0x10, 0x54, 0xd8, 0x47, 0x25, 0x51, 0xc5, 0x41, 0x79, 0x00, 0xe5,
930xa0, 0x72, 0xde, 0xbb, 0x3b, 0x62, 0x17, 0xf6, 0xbc, 0x5d, 0x00, 0x76, 0x2e, 0xa7, 0x3b,
940xb6, 0xf1, 0x98, 0x72, 0x59, 0x2a, 0x73, 0xb0, 0x21, 0xd6, 0x49, 0xe0, 0xc0, 0xd5, 0xeb,
950x02, 0x7d, 0x4b, 0x41, 0x28, 0x70, 0x2d, 0xec, 0x2b, 0x71, 0x1f, 0x0b, 0xb9, 0x71, 0x63,
960x06, 0xe6, 0xbc, 0x60, 0xbb, 0xf4, 0x9a, 0x62, 0x43, 0x09, 0x18, 0x4e, 0x93, 0x06, 0x4d,
970x76, 0xfa, 0x7f, 0xbd, 0x02, 0xe4, 0x50, 0x91, 0x12, 0xe5, 0x86, 0xff, 0x64, 0x1e, 0xaf,
980x7e, 0xb3, 0xb2, 0xde, 0x89, 0xc1, 0xa2, 0x6f, 0x40, 0x7b, 0x41, 0x51, 0x63, 0xea, 0x25,
990xd1, 0x97, 0x57, 0x92, 0xa8, 0x45, 0xa1, 0xa5, 0x45, 0x21, 0x43, 0x7f, 0x83, 0x15, 0x29,
1000xd0, 0x30, 0x53, 0x32, 0xb4, 0x5a, 0x17, 0x96, 0xbc, 0xc2, 0x68, 0xa9, 0xb7, 0xaf, 0xac,
1010xdf, 0xf1, 0xe3, 0x89, 0xba, 0x24, 0x79, 0x54, 0xc6, 0x14, 0x07, 0x1c, 0x1e, 0x0d, 0x3a,
1020x6b, 0xe5, 0x3d, 0x4e, 0x10, 0x60, 0x96, 0xec, 0x6c, 0xda, 0x47, 0xae, 0x03, 0x25, 0x39,
1030x1d, 0x74, 0xc8, 0xac, 0x6a, 0xf2, 0x6b, 0x05, 0x2a, 0x9a, 0xe7, 0xe8, 0x92, 0xd6, 0xc2,
1040x6d, 0xfa, 0xe8, 0xa7, 0x9d, 0x5f, 0x48, 0xc9, 0x75, 0xf1, 0x66, 0x6a, 0xdb, 0x5d, 0x9a,
1050xcd, 0x27, 0xdd, 0xb9, 0x24, 0x04, 0x9c, 0x18, 0xc2, 0x6d, 0x0c, 0x91, 0x34, 0x48, 0x42,
1060x6f, 0xe9, 0x59, 0x70, 0xc4, 0x7e, 0x81, 0x0e, 0x32, 0x0a, 0x93, 0x48, 0xb0, 0xc0, 0x15,
1070x9e, 0x05, 0xac, 0x36, 0x16, 0xcb, 0x59, 0x65, 0xa0, 0x83, 0xdf, 0x3e, 0xda, 0xfb, 0x1d,
1080x1a, 0xdb, 0x65, 0xec, 0x9a, 0xc6, 0xc3, 0x8e, 0x3c, 0x45, 0xfd, 0xc8, 0xf5, 0x1c, 0x6a,
1090x67, 0x0d, 0x8f, 0x99, 0x7d, 0x30, 0x21, 0x8c, 0xea, 0x22, 0x87, 0x65, 0xc9, 0xb2, 0x4c,
1100xe4, 0x1b, 0x46, 0xba, 0x54, 0xbd, 0x7c, 0xca, 0xd5, 0x8f, 0x5b, 0xa5, 0x01, 0x04, 0xd8,
1110x0a, 0x16, 0xbf, 0xb9, 0x50, 0x2e, 0x37, 0x2f, 0x64, 0xf3, 0x70, 0x11, 0x02, 0x05, 0x31,
1120x9b, 0xa0, 0xb2, 0x01, 0x5e, 0x4f, 0x19, 0xc9, 0xd4, 0xea, 0xa1, 0x79, 0x54, 0x53, 0xa7,
1130xde, 0x2f, 0x49, 0xd3, 0xd1, 0x63, 0xb5, 0x03, 0x15, 0x4e, 0xbf, 0x04, 0xb3, 0x26, 0x8b,
1140x20, 0xb2, 0x45, 0xcf, 0xcd, 0x5b, 0x82, 0x32, 0x88, 0x61, 0xa7, 0xa8, 0xb2, 0xa0, 0x72,
1150x96, 0xc0, 0xdb, 0x2b, 0xe2, 0x5f, 0xba, 0xe3, 0xf5, 0x8a, 0xde, 0xf1, 0x18, 0x01, 0x16,
1160x40, 0xd9, 0x86, 0x12, 0x09, 0x18, 0x1b, 0x05, 0x0c, 0xb1, 0xb5, 0x47, 0xe2, 0x43, 0xab,
1170xfe, 0x92, 0x63, 0x7e, 0x95, 0x2b, 0xf0, 0xaf, 0xe1, 0xf1, 0xc3, 0x4a, 0xff, 0x2b, 0x09,
1180xbb, 0x4a, 0x0e, 0x9a, 0xc4, 0xd8, 0x64, 0x7d, 0x83, 0xa0, 0x4f, 0x44, 0xdb, 0xc4, 0xa8,
1190x58, 0xef, 0xfc, 0x9e, 0x77, 0xf9, 0xa6, 0x8f, 0x58, 0x8b, 0x12, 0xf4, 0xe9, 0x81, 0x12,
1200x47, 0x51, 0x41, 0x83, 0xef, 0xf6, 0x73, 0xbc, 0x8e, 0x0f, 0x4c, 0x8f, 0x4e, 0x69, 0x90,
1210x77, 0x29, 0x5d, 0x92, 0xb0, 0x6d, 0x06, 0x67, 0x29, 0x60, 0xbd, 0x4b, 0x17, 0xc8, 0x89,
1220x69, 0x28, 0x29, 0xd6, 0x78, 0xcb, 0x11, 0x4c, 0xba, 0x8b, 0x68, 0xae, 0x7e, 0x9f, 0xef,
1230x95, 0xda, 0xe2, 0x9e, 0x7f, 0xe9, 0x55, 0xe5, 0xe1, 0xe2, 0xb7, 0xe6, 0x5f, 0xbb, 0x2c,
1240xa2, 0xe6, 0xee, 0xc7, 0x0a, 0x60, 0xa9, 0xd1, 0x80, 0xdf, 0x7f, 0xd6, 0x97, 0xab, 0x1d,
1250x22, 0x25, 0xfc, 0x79, 0x23, 0xe0, 0xae, 0xc5, 0xef, 0x16, 0xa4, 0xa1, 0x0f, 0x92, 0xa9,
1260xc7, 0xe3, 0x3a, 0x55, 0xdf, 0x62, 0x49, 0xd9, 0xf5, 0x84, 0x49, 0xc5, 0x90, 0x34, 0xd3,
1270xe1, 0xac, 0x99, 0x21, 0xb1, 0x02, 0x76, 0x4a, 0xfa, 0xd4, 0xbb, 0xa4, 0x9c, 0xa2, 0xe2,
1280xcb, 0x3d, 0x3b, 0x14, 0x75, 0x60, 0xd1, 0x02, 0xb4, 0xa3, 0xb4, 0x72, 0x06, 0xf9, 0x19,
1290x9c, 0xe2, 0xe4, 0xa7, 0x0f, 0x25, 0x88, 0xc6, 0x86, 0xd6, 0x8c, 0x74, 0x4e, 0x6e, 0xfc,
1300xa8, 0x48, 0x9e, 0xa7, 0x9d, 0x1a, 0x4b, 0x37, 0x09, 0xc8, 0xb0, 0x10, 0xbe, 0x6f, 0xfe,
1310xa3, 0xc4, 0x7a, 0xb5, 0x3d, 0xe8, 0x30, 0xf1, 0x0d, 0xa0, 0xb2, 0x44, 0xfc, 0x9b, 0x8c,
1320xf8, 0x61, 0xed, 0x81, 0xd1, 0x62, 0x11, 0xb4, 0xe1, 0xd5, 0x39, 0x52, 0x89, 0xd3, 0xa8,
1330x49, 0x31, 0xdf, 0xb6, 0xf9, 0x91, 0xf4, 0x1c, 0x9d, 0x09, 0x95, 0x40, 0x56, 0xe7, 0xe3,
1340xcd, 0x5c, 0x92, 0xc1, 0x1d, 0x6b, 0xe9, 0x78, 0x6f, 0x8e, 0x94, 0x42, 0x66, 0xa2, 0xaa,
1350xd3, 0xc8, 0x2e, 0xe3, 0xf6, 0x07, 0x72, 0x0b, 0x6b, 0x1e, 0x7b, 0xb9, 0x7c, 0xe0, 0xa0,
1360xbc, 0xd9, 0x25, 0xdf, 0x87, 0xa8, 0x5f, 0x9c, 0xcc, 0xf0, 0xdb, 0x42, 0x8e, 0x07, 0x31,
1370x13, 0x01, 0x66, 0x32, 0xd1, 0xb8, 0xd6, 0xe3, 0x5e, 0x12, 0x76, 0x61, 0xd3, 0x38, 0x89,
1380xe6, 0x17, 0x6f, 0xa5, 0xf2, 0x71, 0x0e, 0xa5, 0xe2, 0x88, 0x30, 0xbb, 0xbe, 0x8a, 0xea,
1390xc7, 0x62, 0xc4, 0xcf, 0xb8, 0xcd, 0x33, 0x8d, 0x3d, 0x3e, 0xb5, 0x60, 0x3a, 0x03, 0x92,
1400xe4, 0x6d, 0x1b, 0xe0, 0xb4, 0x84, 0x08, 0x55, 0x88, 0xa7, 0x3a, 0xb9, 0x3d, 0x43, 0xc3,
1410xc0, 0xfa, 0x07, 0x6a, 0xca, 0x94, 0xad, 0x99, 0x55, 0xf1, 0xf1, 0xc0, 0x23, 0x87, 0x1d,
1420x3d, 0x1c, 0xd1, 0x66, 0xa0, 0x57, 0x10, 0x52, 0xa2, 0x7f, 0xbe, 0xf9, 0x88, 0xb6, 0x02,
1430xbf, 0x08, 0x23, 0xa9, 0x0c, 0x63, 0x17, 0x2a, 0xae, 0xf5, 0xf7, 0xb7, 0x21, 0x83, 0x92,
1440x31, 0x23, 0x0d, 0x20, 0xc3, 0xc2, 0x05, 0x21, 0x62, 0x8e, 0x45, 0xe8, 0x14, 0xc1, 0xda,
1450x75, 0xb8, 0xf8, 0x92, 0x01, 0xd0, 0x5d, 0x18, 0x9f, 0x99, 0x11, 0x19, 0xf5, 0x35, 0xe8,
1460x7f, 0x20, 0x88, 0x8c, 0x05, 0x75, 0xf5, 0xd7, 0x40, 0x17, 0xbb, 0x1e, 0x36, 0x52, 0xd9,
1470xa4, 0x9c, 0xc2, 0x9d, 0x42, 0x81, 0xd8, 0xc7, 0x8a, 0xe7, 0x4c, 0x81, 0xe0, 0xb7, 0x57,
1480xed, 0x48, 0x8b, 0xf0, 0x97, 0x15, 0x61, 0xd9, 0x2c, 0x7c, 0x45, 0xaf, 0xc2, 0xcd, 0xfc,
1490xaa, 0x13, 0xad, 0x59, 0xcc, 0xb2, 0xb2, 0x6e, 0xdd, 0x63, 0x9c, 0x32, 0x0f, 0xec, 0x83,
1500xbe, 0x78, 0xac, 0x91, 0x44, 0x1a, 0x1f, 0xea, 0xfd, 0x5d, 0x8e, 0xb4, 0xc0, 0x84, 0xd4,
1510xac, 0xb4, 0x87, 0x5f, 0xac, 0xef, 0xdf, 0xcd, 0x12, 0x56, 0xc8, 0xcd, 0xfe, 0xc5, 0xda,
1520xd3, 0xc1, 0x69, 0xf3, 0x61, 0x05, 0xea, 0x25, 0xe2, 0x12, 0x05, 0x8f, 0x39, 0x08, 0x08,
1530x7c, 0x37, 0xb6, 0x7e, 0x5b, 0xd8, 0xb1, 0x0e, 0xf2, 0xdb, 0x4b, 0xf1, 0xad, 0x90, 0x01,
1540x57, 0xcd, 0xa0, 0xb4, 0x52, 0xe8, 0xf3, 0xd7, 0x8a, 0xbd, 0x4f, 0x9f, 0x21, 0x40, 0x72,
1550xa4, 0xfc, 0x0b, 0x01, 0x2b, 0x2f, 0xb6, 0x4c, 0x95, 0x2d, 0x35, 0x33, 0x41, 0x6b, 0xa0,
1560x93, 0xe7, 0x2c, 0xf2, 0xd3, 0x72, 0x8b, 0xf4, 0x4f, 0x15, 0x3c, 0xaf, 0xd6, 0x12, 0xde,
1570x3f, 0x83, 0x3f, 0xff, 0xf8, 0x7f, 0xf6, 0xcc, 0xa6, 0x7f, 0xc9, 0x9a, 0x6e, 0x1f, 0xc1,
1580x0c, 0xfb, 0xee, 0x9c, 0xe7, 0xaf, 0xc9, 0x26, 0x54, 0xef, 0xb0, 0x39, 0xef, 0xb2, 0xe9,
1590x23, 0xc4, 0xef, 0xd1, 0xa1, 0xa4, 0x25, 0x24, 0x6f, 0x8d, 0x6a, 0xe5, 0x8a, 0x32, 0x3a,
1600xaf, 0xfc, 0xda, 0xce, 0x18, 0x25, 0x42, 0x07, 0x4d, 0x45, 0x8b, 0xdf, 0x85, 0xcf, 0x55,
1610xb2, 0x24, 0xfe, 0x9c, 0x69, 0x74, 0xa7, 0x6e, 0xa0, 0xce, 0xc0, 0x39, 0xf4, 0x86, 0xc6,
1620x8d, 0xae, 0xb9, 0x48, 0x64, 0x13, 0x0b, 0x40, 0x81, 0xa2, 0xc9, 0xa8, 0x85, 0x51, 0xee,
1630x9f, 0xcf, 0xa2, 0x8c, 0x19, 0x52, 0x48, 0xe2, 0xc1, 0xa8, 0x58, 0xb4, 0x10, 0x24, 0x06,
1640x58, 0x51, 0xfc, 0xb9, 0x12, 0xec, 0xfd, 0x73, 0xb4, 0x6d, 0x84, 0xfa, 0x06, 0x8b, 0x05,
1650x0b, 0x2d, 0xd6, 0xd6, 0x1f, 0x29, 0x82, 0x9f, 0x19, 0x12, 0x1e, 0xb2, 0x04, 0x8f, 0x7f,
1660x4d, 0xbd, 0x30, 0x2e, 0xe3, 0xe0, 0x88, 0x29, 0xc5, 0x93, 0xd6, 0x6c, 0x1f, 0x29, 0x45,
1670x91, 0xa7, 0x58, 0xcd, 0x05, 0x17, 0xd6, 0x6d, 0xb3, 0xca, 0x66, 0xcc, 0x3c, 0x4a, 0x74,
1680xfd, 0x08, 0x10, 0xa6, 0x99, 0x92, 0x10, 0xd2, 0x85, 0xab, 0x6e, 0x1d, 0x0e, 0x8b, 0x26,
1690x46, 0xd1, 0x6c, 0x84, 0xc0, 0x26, 0x43, 0x59, 0x68, 0xf0, 0x13, 0x1d, 0xfb, 0xe3, 0xd1,
1700xd2, 0xb4, 0x71, 0x9e, 0xf2, 0x59, 0x6a, 0x33, 0x29, 0x79, 0xd2, 0xd7, 0x26, 0xf1, 0xae,
1710x78, 0x9e, 0x1f, 0x0f, 0x3f, 0xe3, 0xe8, 0xd0, 0x27, 0x78, 0x77, 0xf6, 0xac, 0x9c, 0x56,
1720x39, 0x73, 0x8a, 0x6b, 0x2f, 0x34, 0x78, 0xb1, 0x11, 0xdb, 0xa4, 0x5c, 0x80, 0x01, 0x71,
1730x6a, 0xc2, 0xd1, 0x2e, 0x5e, 0x76, 0x28, 0x70, 0x93, 0xae, 0x3e, 0x78, 0xb0, 0x1f, 0x0f,
1740xda, 0xbf, 0xfb, 0x8a, 0x67, 0x65, 0x4f, 0x91, 0xed, 0x49, 0x75, 0x78, 0x62, 0xa2, 0x93,
1750xb5, 0x70, 0x7f, 0x4d, 0x08, 0x4e, 0x79, 0x61, 0xa8, 0x5f, 0x7f, 0xb4, 0x65, 0x9f, 0x91,
1760x54, 0x3a, 0xe8, 0x50, 0x33, 0xd3, 0xd5, 0x8a, 0x7c, 0xf3, 0x9e, 0x8b, 0x77, 0x7b, 0xc6,
1770xc6, 0x0c, 0x45, 0x95, 0x1f, 0xb0, 0xd0, 0x0b, 0x27, 0x4a, 0xfd, 0xc7, 0xf7, 0x0d, 0x5a,
1780x43, 0xc9, 0x7d, 0x35, 0xb0, 0x7d, 0xc4, 0x9c, 0x57, 0x1e, 0x76, 0x0d, 0xf1, 0x95, 0x30,
1790x71, 0xcc, 0xb3, 0x66, 0x3b, 0x63, 0xa8, 0x6c, 0xa3, 0x43, 0xa0, 0x24, 0xcc, 0xb7, 0x53,
1800xfe, 0xfe, 0xbc, 0x6e, 0x60, 0x89, 0xaf, 0x16, 0x21, 0xc8, 0x91, 0x6a, 0x89, 0xce, 0x80,
1810x2c, 0xf1, 0x59, 0xce, 0xc3, 0x60, 0x61, 0x3b, 0x0b, 0x19, 0xfe, 0x99, 0xac, 0x65, 0x90,
1820x15, 0x12, 0x05, 0xac, 0x7e, 0xff, 0x98, 0x7b, 0x66, 0x64, 0x0e, 0x4b, 0x5b, 0xaa, 0x8d,
1830x3b, 0xd2, 0x56, 0xcf, 0x99, 0x39, 0xee, 0x22, 0x81, 0xd0, 0x60, 0x06, 0x66, 0x20, 0x81,
1840x48, 0x3c, 0x6f, 0x3a, 0x77, 0xba, 0xcb, 0x52, 0xac, 0x79, 0x56, 0xaf, 0xe9, 0x16, 0x17,
1850x0a, 0xa3, 0x82, 0x08, 0xd5, 0x3c, 0x97, 0xcb, 0x09, 0xff, 0x7f, 0xf9, 0x4f, 0x60, 0x05,
1860xb9, 0x53, 0x26, 0xaa, 0xb8, 0x50, 0xaa, 0x19, 0x25, 0xae, 0x5f, 0xea, 0x8a, 0xd0, 0x89,
1870x12, 0x80, 0x43, 0x50, 0x24, 0x12, 0x21, 0x14, 0xcd, 0x77, 0xeb, 0x21, 0xcc, 0x5c, 0x09,
1880x64, 0xf3, 0xc7, 0xcb, 0xc5, 0x4b, 0xc3, 0xe7, 0xed, 0xe7, 0x86, 0x2c, 0x1d, 0x8e, 0x19,
1890x52, 0x9b, 0x2a, 0x0c, 0x18, 0x72, 0x0b, 0x1e, 0x1b, 0xb0, 0x0f, 0x42, 0x99, 0x04, 0xae,
1900xd5, 0xb7, 0x89, 0x1a, 0xb9, 0x4f, 0xd6, 0xaf, 0xf3, 0xc9, 0x93, 0x6f, 0xb0, 0x60, 0x83,
1910x6e, 0x6b, 0xd1, 0x5f, 0x3f, 0x1a, 0x83, 0x1e, 0x24, 0x00, 0x87, 0xb5, 0x3e, 0xdb, 0xf9,
1920x4d, 0xa7, 0x16, 0x2e, 0x19, 0x5b, 0x8f, 0x1b, 0x0d, 0x47, 0x72, 0x42, 0xe9, 0x0a, 0x11,
1930x08, 0x2d, 0x88, 0x1c, 0xbc, 0xc7, 0xb4, 0xbe, 0x29, 0x4d, 0x03, 0x5e, 0xec, 0xdf, 0xf3,
1940x3d, 0x2f, 0xe8, 0x1d, 0x9a, 0xd2, 0xd1, 0xab, 0x41, 0x3d, 0x87, 0x11, 0x45, 0xb0, 0x0d,
1950x46, 0xf5, 0xe8, 0x95, 0x62, 0x1c, 0x68, 0xf7, 0xa6, 0x5b, 0x39, 0x4e, 0xbf, 0x47, 0xba,
1960x5d, 0x7f, 0xb7, 0x6a, 0xf4, 0xba, 0x1d, 0x69, 0xf6, 0xa4, 0xe7, 0xe4, 0x6b, 0x3b, 0x0d,
1970x23, 0x16, 0x4a, 0xb2, 0x68, 0xf0, 0xb2, 0x0d, 0x09, 0x17, 0x6a, 0x63, 0x8c, 0x83, 0xd3,
1980xbd, 0x05, 0xc9, 0xf6, 0xf0, 0xa1, 0x31, 0x0b, 0x2c, 0xac, 0x83, 0xac, 0x80, 0x34, 0x32,
1990xb4, 0xec, 0xd0, 0xbc, 0x54, 0x82, 0x9a, 0xc8, 0xf6, 0xa0, 0x7d, 0xc6, 0x79, 0x73, 0xf4,
2000x20, 0x99, 0xf3, 0xb4, 0x01, 0xde, 0x91, 0x27, 0xf2, 0xc0, 0xdc, 0x81, 0x00, 0x4e, 0x7e,
2010x07, 0x99, 0xc8, 0x3a, 0x51, 0xbc, 0x38, 0xd6, 0x8a, 0xa2, 0xde, 0x3b, 0x6a, 0x8c, 0x1a,
2020x7c, 0x81, 0x0f, 0x3a, 0x1f, 0xe4, 0x05, 0x7b, 0x20, 0x35, 0x6b, 0xa5, 0x6a, 0xa7, 0xe7,
2030xbc, 0x9c, 0x20, 0xec, 0x00, 0x15, 0xe2, 0x51, 0xaf, 0x77, 0xeb, 0x29, 0x3c, 0x7d, 0x2e,
2040x00, 0x5c, 0x81, 0x21, 0xfa, 0x35, 0x6f, 0x40, 0xef, 0xfb, 0xd1, 0x3f, 0xcc, 0x9d, 0x55,
2050x53, 0xfb, 0x5a, 0xa5, 0x56, 0x89, 0x0b, 0x52, 0xeb, 0x57, 0x73, 0x4f, 0x1b, 0x67, 0x24,
2060xcb, 0xb8, 0x6a, 0x10, 0x69, 0xd6, 0xfb, 0x52, 0x40, 0xff, 0x20, 0xa5, 0xf3, 0x72, 0xe1,
2070x3d, 0xa4, 0x8c, 0x81, 0x66, 0x16, 0x0d, 0x5d, 0xad, 0xa8, 0x50, 0x25, 0x78, 0x31, 0x77,
2080x0c, 0x57, 0xe4, 0xe9, 0x15, 0x2d, 0xdb, 0x07, 0x87, 0xc8, 0xb0, 0x43, 0xde, 0xfc, 0xfe,
2090xa9, 0xeb, 0xf5, 0xb0, 0xd3, 0x7b, 0xe9, 0x1f, 0x6e, 0xca, 0xe4, 0x03, 0x95, 0xc5, 0xd1,
2100x59, 0x72, 0x63, 0xf0, 0x86, 0x54, 0xe8, 0x16, 0x62, 0x0b, 0x35, 0x29, 0xc2, 0x68, 0xd0,
2110xd6, 0x3e, 0x90, 0x60, 0x57, 0x1d, 0xc9, 0xed, 0x3f, 0xed, 0xb0, 0x2f, 0x7e, 0x97, 0x02,
2120x51, 0xec, 0xee, 0x6f, 0x82, 0x74, 0x76, 0x7f, 0xfb, 0xd6, 0xc4, 0xc3, 0xdd, 0xe8, 0xb1,
2130x60, 0xfc, 0xc6, 0xb9, 0x0d, 0x6a, 0x33, 0x78, 0xc6, 0xc1, 0xbf, 0x86, 0x2c, 0x50, 0xcc,
2140x9a, 0x70, 0x8e, 0x7b, 0xec, 0xab, 0x95, 0xac, 0x53, 0xa0, 0x4b, 0x07, 0x88, 0xaf, 0x42,
2150xed, 0x19, 0x8d, 0xf6, 0x32, 0x17, 0x48, 0x47, 0x1d, 0x41, 0x6f, 0xfe, 0x2e, 0xa7, 0x8f,
2160x4b, 0xa0, 0x51, 0xf3, 0xbf, 0x02, 0x0a, 0x48, 0x58, 0xf7, 0xa1, 0x6d, 0xea, 0xa5, 0x13,
2170x5a, 0x5b, 0xea, 0x0c, 0x9e, 0x52, 0x4f, 0x9e, 0xb9, 0x71, 0x7f, 0x23, 0x83, 0xda, 0x1b,
2180x86, 0x9a, 0x41, 0x29, 0xda, 0x70, 0xe7, 0x64, 0xa1, 0x7b, 0xd5, 0x0a, 0x22, 0x0d, 0x5c,
2190x40, 0xc4, 0x81, 0x07, 0x25, 0x35, 0x4a, 0x1c, 0x10, 0xdb, 0x45, 0x0a, 0xff, 0x36, 0xd4,
2200xe0, 0xeb, 0x5f, 0x68, 0xd6, 0x67, 0xc6, 0xd0, 0x8b, 0x76, 0x1a, 0x7d, 0x59, 0x42, 0xa1,
2210xcb, 0x96, 0x4d, 0x84, 0x09, 0x9a, 0x3d, 0xe0, 0x52, 0x85, 0x6e, 0x48, 0x90, 0x85, 0x2a,
2220x63, 0xb2, 0x69, 0xd2, 0x00, 0x43, 0x31, 0x37, 0xb3, 0x52, 0xaf, 0x62, 0xfa, 0xc1, 0xe0,
2230x03, 0xfb, 0x62, 0xaa, 0x88, 0xc9, 0xb2, 0x2c, 0xd5, 0xa8, 0xf5, 0xa5, 0x4c, 0x12, 0x59,
2240x4e, 0x06, 0x5e, 0x9b, 0x15, 0x66, 0x11, 0xb2, 0x27, 0x92, 0xdc, 0x98, 0x59, 0xde, 0xdf,
2250xfa, 0x9a, 0x32, 0x2e, 0xc0, 0x5d, 0x3c, 0x33, 0x41, 0x6d, 0xaf, 0xb2, 0x25, 0x23, 0x14,
2260xa5, 0x7b, 0xc7, 0x9b, 0x68, 0xf3, 0xda, 0xeb, 0xe3, 0xa9, 0xe2, 0x6f, 0x0e, 0x1d, 0x1c,
2270xba, 0x55, 0xb6, 0x34, 0x6a, 0x93, 0x1f, 0x1f, 0xb8, 0x34, 0xc8, 0x84, 0x08, 0xb1, 0x6b,
2280x6a, 0x28, 0x74, 0x74, 0xe5, 0xeb, 0x75, 0xe9, 0x7c, 0xd8, 0xba, 0xd8, 0x42, 0xa5, 0xee,
2290x1f, 0x80, 0xd9, 0x96, 0xb2, 0x2e, 0xe7, 0xbf, 0xba, 0xeb, 0xd1, 0x69, 0xbb, 0x8f, 0xfd,
2300x5a, 0x63, 0x8f, 0x39, 0x7f, 0xdf, 0x1d, 0x37, 0xd2, 0x18, 0x35, 0x9d, 0xb6, 0xcc, 0xe4,
2310x27, 0x81, 0x89, 0x38, 0x38, 0x68, 0x33, 0xe7, 0x78, 0xd8, 0x76, 0xf5, 0xee, 0xd0, 0x4a,
2320x07, 0x69, 0x19, 0x7a, 0xad, 0x18, 0xb1, 0x94, 0x61, 0x45, 0x53, 0xa2, 0x48, 0xda, 0x96,
2330x4a, 0xf9, 0xee, 0x94, 0x2a, 0x1f, 0x6e, 0x18, 0x3c, 0x92, 0x46, 0xd1, 0x1a, 0x28, 0x18,
2340x32, 0x1f, 0x3a, 0x45, 0xbe, 0x04, 0x35, 0x92, 0xe5, 0xa3, 0xcb, 0xb5, 0x2e, 0x32, 0x43,
2350xac, 0x65, 0x17, 0x89, 0x99, 0x15, 0x03, 0x9e, 0xb1, 0x23, 0x2f, 0xed, 0x76, 0x4d, 0xd8,
2360xac, 0x21, 0x40, 0xc4, 0x99, 0x4e, 0x65, 0x71, 0x2c, 0xb3, 0x45, 0xab, 0xfb, 0xe7, 0x72,
2370x39, 0x56, 0x30, 0x6d, 0xfb, 0x74, 0xeb, 0x99, 0xf3, 0xcd, 0x57, 0x5c, 0x78, 0x75, 0xe9,
2380x8d, 0xc3, 0xa2, 0xfb, 0x5d, 0xe0, 0x90, 0xc5, 0x55, 0xad, 0x91, 0x53, 0x4e, 0x9e, 0xbd,
2390x8c, 0x49, 0xa4, 0xa4, 0x69, 0x10, 0x0c, 0xc5, 0x76, 0xe9, 0x25, 0x86, 0x8d, 0x66, 0x23,
2400xa8, 0xdb, 0x5c, 0xe8, 0xd9, 0x30, 0xe1, 0x15, 0x7b, 0xc0, 0x99, 0x0f, 0x03, 0xec, 0xaa,
2410x12, 0xef, 0xce, 0xd4, 0xea, 0x55, 0x5c, 0x08, 0x86, 0xf4, 0xf4, 0xb0, 0x83, 0x42, 0x95,
2420x37, 0xb6, 0x38, 0xe0, 0x2b, 0x54, 0x89, 0xbd, 0x4e, 0x20, 0x9d, 0x3f, 0xc3, 0x4b, 0xb7,
2430xec, 0xfa, 0x5a, 0x14, 0x03, 0xcb, 0x64, 0xc8, 0x34, 0x4a, 0x4b, 0x6e, 0xf8, 0x6e, 0x56,
2440xf6, 0xdd, 0x5f, 0xa1, 0x24, 0xe2, 0xd4, 0xd0, 0x82, 0x64, 0x1f, 0x8e, 0x9b, 0xfa, 0xb4,
2450xcb, 0xdb, 0x0a, 0xe8, 0x15, 0xfc, 0x15, 0xab, 0x4b, 0x18, 0xbf, 0xd4, 0x42, 0x14, 0x48,
2460x82, 0x85, 0xdd, 0xeb, 0x49, 0x1b, 0x0b, 0x0b, 0x05, 0xe9, 0xb4, 0xa1, 0x33, 0x0a, 0x5d,
2470x0e, 0x6c, 0x4b, 0xc0, 0xd6, 0x6c, 0x7c, 0xfb, 0x69, 0x0b, 0x53, 0x19, 0xe4, 0xf3, 0x35,
2480xfc, 0xbe, 0xa1, 0x34, 0x02, 0x09, 0x4f, 0x74, 0x86, 0x92, 0xcd, 0x5d, 0x1a, 0xc1, 0x27,
2490x0c, 0xf2, 0xc5, 0xcf, 0xdd, 0x23, 0x93, 0x02, 0xbd, 0x41, 0x5e, 0x42, 0xf0, 0xa0, 0x9d,
2500x0c, 0x72, 0xc8, 0xec, 0x32, 0x0a, 0x8a, 0xfd, 0x3d, 0x5a, 0x41, 0x27, 0x0c, 0x88, 0x59,
2510xad, 0x94, 0x2e, 0xef, 0x5d, 0x8f, 0xc7, 0xdf, 0x66, 0xe4, 0xdd, 0x56, 0x6c, 0x7b, 0xca,
2520x55, 0x81, 0xae, 0xae, 0x5c, 0x1b, 0x1a, 0xab, 0xae, 0x99, 0x8d, 0xcc, 0x42, 0x97, 0x59,
2530xf4, 0x14, 0x3f, 0x75, 0xc6, 0xd1, 0x88, 0xba, 0xaa, 0x84, 0x4a, 0xd0, 0x34, 0x08, 0x3b,
2540x7d, 0xdb, 0x15, 0x06, 0xb0, 0x5c, 0xbd, 0x40, 0xf5, 0xa8, 0xec, 0xae, 0x36, 0x40, 0xdd,
2550x90, 0x1c, 0x3e, 0x0d, 0x7e, 0x73, 0xc7, 0xc2, 0xc5, 0x6a, 0xff, 0x52, 0x05, 0x7f, 0xbe,
2560xd0, 0x92, 0xfd, 0xb3, 0x6f, 0xff, 0x5d, 0xb7, 0x97, 0x64, 0x73, 0x7b, 0xca, 0xd1, 0x98,
2570x24, 0x6b, 0x0b, 0x01, 0x68, 0xdd, 0x27, 0x85, 0x85, 0xb5, 0x83, 0xc1, 0xe0, 0x50, 0x64,
2580xc7, 0xaf, 0xf1, 0xc6, 0x4d, 0xb1, 0xef, 0xc9, 0xb4, 0x0a, 0x6d, 0x65, 0xf3, 0x47, 0xcc,
2590xa3, 0x02, 0x21, 0x0c, 0xbe, 0x22, 0x29, 0x05, 0xcf, 0x5f, 0xe8, 0x94, 0x6c, 0xe5, 0xdc,
2600xc4, 0xdf, 0xbe, 0x3e, 0xa8, 0xb4, 0x18, 0xb0, 0x99, 0xb8, 0x6f, 0xff, 0x5d, 0xb9, 0xfd,
2610x3b, 0x5d, 0x16, 0xbf, 0x3e, 0xd8, 0xb3, 0xd8, 0x08, 0x34, 0xf6, 0x47, 0x35, 0x5b, 0x72,
2620x1a, 0x33, 0xad, 0x52, 0x5d, 0xb8, 0xd0, 0x77, 0xc6, 0xab, 0xba, 0x55, 0x09, 0x5f, 0x02,
2630xf8, 0xd4, 0x5f, 0x53, 0x06, 0x91, 0xcd, 0x74, 0x42, 0xae, 0x54, 0x91, 0x81, 0x62, 0x13,
2640x6f, 0xd8, 0xa9, 0x77, 0xc3, 0x6c, 0xcb, 0xf1, 0x29, 0x5a, 0xcc, 0xda, 0x35, 0xbd, 0x52,
2650x23, 0xbe, 0x59, 0xeb, 0x12, 0x6d, 0xb7, 0x53, 0xee, 0xfc, 0xb4, 0x1b, 0x13, 0x5e, 0xba,
2660x16, 0x7c, 0xc5, 0xf3, 0xe3, 0x6d, 0x07, 0x78, 0xf5, 0x2b, 0x21, 0x05, 0x88, 0x4c, 0xc0,
2670xa1, 0xe3, 0x36, 0x10, 0xf8, 0x1b, 0xd8, 0x17, 0xfb, 0x6a, 0x4e, 0xd8, 0xb3, 0x47, 0x2d,
2680x99, 0xbd, 0xbb, 0x5d, 0x37, 0x7d, 0xba, 0xf1, 0xe1, 0x7c, 0xc0, 0xc5, 0x54, 0x62, 0x7f,
2690xcf, 0x5a, 0x4a, 0x93, 0xcc, 0xf1, 0x1b, 0x34, 0xc8, 0xa6, 0x05, 0x4c, 0x55, 0x8b, 0x54,
2700x84, 0xd5, 0x77, 0xeb, 0xc0, 0x6d, 0x3a, 0x29, 0xbd, 0x75, 0x61, 0x09, 0x9a, 0x2c, 0xbb,
2710xf7, 0x18, 0x79, 0x34, 0x90, 0x24, 0xa5, 0x81, 0x70, 0x87, 0xc5, 0x02, 0x7c, 0xba, 0xd4,
2720x5e, 0x14, 0x8e, 0xe4, 0xed, 0xa2, 0x61, 0x6a, 0xb9, 0x6e, 0xb5, 0x4a, 0xb9, 0x01, 0x46,
2730xf4, 0xcf, 0xbc, 0x09, 0x2f, 0x27, 0x4b, 0xbd, 0x86, 0x7a, 0x10, 0xe1, 0xd4, 0xc8, 0xd9,
2740x20, 0x8d, 0x8a, 0x63, 0x00, 0x63, 0x44, 0xeb, 0x54, 0x0b, 0x75, 0x49, 0x10, 0xa2, 0xa7,
2750xad, 0xb9, 0xd1, 0x01, 0x80, 0x63, 0x25, 0xc8, 0x12, 0xa6, 0xce, 0x1e, 0xbe, 0xfe, 0x7e,
2760x5f, 0x3c, 0xdb, 0x34, 0xea, 0x37, 0xec, 0x3b, 0xd5, 0x28, 0xd2, 0x07, 0x8c, 0x9a, 0xb6,
2770xee, 0x5e, 0x3e, 0xdf, 0x1d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x5c, 0x1b, 0xb4, 0xea, 0x56,
2780x2e, 0xde, 0x1f, 0x9d, 0xb8, 0xd3, 0x24, 0xab, 0xd4, 0x2a, 0xd6, 0x2e, 0xde, 0x1f, 0x9d,
2790xb8, 0xf2, 0x66, 0x2f, 0xbd, 0xf8, 0x72, 0x66, 0x4e, 0x1e, 0x9f, 0x9d, 0xb8, 0xf2, 0x47,
2800x0c, 0x9a, 0xb6, 0xee, 0x3f, 0xfc, 0x7a, 0x57, 0x0d, 0x79, 0x70, 0x62, 0x27, 0xad, 0xb9,
2810xd1, 0x01, 0x61, 0x40, 0x02, 0x67, 0x2d, 0xd8, 0x32, 0xe6, 0x2f, 0xdc, 0x3a, 0xd7, 0x2c,
2820xbb, 0xf4, 0x4b, 0xf5, 0x49, 0xf1, 0x60, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0xf9, 0x51, 0x01,
2830x80, 0x63, 0x25, 0xa9, 0xb1, 0xe0, 0x42, 0xe7, 0x4c, 0x1a, 0x97, 0xac, 0xbb, 0xf4, 0x6a,
2840x37, 0xcd, 0x18, 0xb2, 0xe6, 0x2f, 0xdc, 0x1b, 0x95, 0xa8, 0xd2, 0x07, 0x6d, 0x58, 0x32,
2850xe6, 0x4e, 0x1e, 0x9f, 0xbc, 0xfa, 0x57, 0x0d, 0x79, 0x51, 0x20, 0xc2, 0x06, 0x6f, 0x5c,
2860x1b, 0x95, 0xa8, 0xb3, 0xc5, 0xe9, 0x31, 0xe0, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0x18, 0x93,
2870x85, 0x69, 0x31, 0xc1, 0xe1, 0x21, 0xc0, 0xe3, 0x44, 0x0a, 0x77, 0x6c, 0x5a, 0x17, 0x8d,
2880x98, 0x93, 0xa4, 0xab, 0xd4, 0x2a, 0xb7, 0xec, 0x5a, 0x17, 0xac, 0xbb, 0xf4, 0x4b, 0x14,
2890xaa, 0xb7, 0xec, 0x3b, 0xd5, 0x28, 0xb3, 0xc5, 0xe9, 0x31, 0xc1, 0x00, 0x82, 0x67, 0x4c,
2900xfb, 0x55, 0x28, 0xd2, 0x26, 0xaf, 0xbd, 0xd9, 0x11, 0x81, 0x61, 0x21, 0xa1, 0xa1, 0xc0,
2910x02, 0x86, 0x6f, 0x5c, 0x1b, 0xb4, 0xcb, 0x14, 0x8b, 0x94, 0xaa, 0xd6, 0x2e, 0xbf, 0xdd,
2920x19, 0xb0, 0xe2, 0x46, 0x0e, 0x7f, 0x7c, 0x5b, 0x15, 0x89, 0x90, 0x83, 0x84, 0x6b, 0x54,
2930x0b, 0x75, 0x68, 0x52, 0x07, 0x6d, 0x58, 0x32, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0xed, 0x58,
2940x32, 0xe6, 0x4e, 0xff, 0x7c, 0x7a, 0x76, 0x6e, 0x3f, 0xdd, 0x38, 0xd3, 0x05, 0x88, 0x92,
2950xa6, 0xaf, 0xdc, 0x1b, 0xb4, 0xcb, 0xf5, 0x68, 0x52, 0x07, 0x8c, 0x7b, 0x55, 0x09, 0x90,
2960x83, 0x84, 0x6b, 0x54, 0x2a, 0xb7, 0xec, 0x3b, 0xd5, 0x09, 0x90, 0xa2, 0xc6, 0x0e, 0x7f,
2970x7c, 0x7a, 0x57, 0x0d, 0x98, 0xb2, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0x0c, 0x7b, 0x74, 0x4b,
2980x14, 0x8b, 0x94, 0xaa, 0xb7, 0xcd, 0x18, 0x93, 0xa4, 0xca, 0x16, 0xae, 0xbf, 0xdd, 0x19,
2990xb0, 0xe2, 0x46, 0x0e, 0x7f, 0x5d, 0x19, 0x91, 0x81, 0x80, 0x63, 0x44, 0xeb, 0x35, 0xc9,
3000x10, 0x83, 0x65, 0x48, 0x12, 0xa6, 0xce, 0x1e, 0x9f, 0xbc, 0xdb, 0x15, 0x89, 0x71, 0x60,
3010x23, 0xc4, 0xeb, 0x54, 0x2a, 0xb7, 0xec, 0x5a, 0x36, 0xcf, 0x81, 0x10, 0xac, 0x74 };
302
303// clang-format off
diff --git a/keyboards/oddball/pmw/pmw.h b/keyboards/40percentclub/nano/keymaps/drashna/config.h
index cc3c9ec5e..411ee8a81 100644
--- a/keyboards/oddball/pmw/pmw.h
+++ b/keyboards/40percentclub/nano/keymaps/drashna/config.h
@@ -1,4 +1,4 @@
1/* Copyright 2020 Alexander Tulloh 1/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
2 * 2 *
3 * This program is free software: you can redistribute it and/or modify 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 4 * it under the terms of the GNU General Public License as published by
@@ -16,20 +16,7 @@
16 16
17#pragma once 17#pragma once
18 18
19#include <stdint.h> 19#define ANALOG_JOYSTICK_X_AXIS_PIN B4
20#define ANALOG_JOYSTICK_Y_AXIS_PIN B5
20 21
21typedef struct { 22#define ANALOG_JOYSTICK_CLICK_PIN E6
22 /* 100 - 12000 CPI supported */
23 uint16_t cpi;
24} config_pmw_t;
25
26typedef struct {
27 int16_t x;
28 int16_t y;
29} report_pmw_t;
30
31void pmw_init(void);
32config_pmw_t pmw_get_config(void);
33void pmw_set_config(config_pmw_t);
34/* Reads and clears the current delta values on the PMW sensor */
35report_pmw_t pmw_get_report(void);
diff --git a/keyboards/40percentclub/nano/keymaps/drashna/keymap.c b/keyboards/40percentclub/nano/keymaps/drashna/keymap.c
index 13f89dd53..cc5991d7a 100644
--- a/keyboards/40percentclub/nano/keymaps/drashna/keymap.c
+++ b/keyboards/40percentclub/nano/keymaps/drashna/keymap.c
@@ -29,98 +29,3 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
29 29
30}; 30};
31// clang-format on 31// clang-format on
32
33// Joystick
34// Set Pins
35// uint8_t xPin = 8; // VRx / /B4
36// uint8_t yPin = 7; // VRy // B5
37uint8_t swPin = E6; // SW
38
39// Set Parameters
40uint16_t minAxisValue = 0;
41uint16_t maxAxisValue = 1023;
42
43uint8_t maxCursorSpeed = 2;
44uint8_t precisionSpeed = 1;
45uint8_t speedRegulator = 20; // Lower Values Create Faster Movement
46
47int8_t xPolarity = 1;
48int8_t yPolarity = 1;
49
50uint8_t cursorTimeout = 10;
51
52int16_t xOrigin, yOrigin;
53
54uint16_t lastCursor = 0;
55
56int16_t axisCoordinate(uint8_t pin, uint16_t origin) {
57 int8_t direction;
58 int16_t distanceFromOrigin;
59 int16_t range;
60
61 int16_t position = analogReadPin(pin);
62
63 if (origin == position) {
64 return 0;
65 } else if (origin > position) {
66 distanceFromOrigin = origin - position;
67 range = origin - minAxisValue;
68 direction = -1;
69 } else {
70 distanceFromOrigin = position - origin;
71 range = maxAxisValue - origin;
72 direction = 1;
73 }
74
75 float percent = (float)distanceFromOrigin / range;
76 int16_t coordinate = (int16_t)(percent * 100);
77 if (coordinate < 0) {
78 return 0;
79 } else if (coordinate > 100) {
80 return 100 * direction;
81 } else {
82 return coordinate * direction;
83 }
84}
85
86int8_t axisToMouseComponent(uint8_t pin, int16_t origin, uint8_t maxSpeed, int8_t polarity) {
87 int coordinate = axisCoordinate(pin, origin);
88 if (coordinate != 0) {
89 float percent = (float)coordinate / 100;
90 if (get_mods() & MOD_BIT(KC_LSFT)) {
91 return percent * precisionSpeed * polarity * (abs(coordinate) / speedRegulator);
92 } else {
93 return percent * maxCursorSpeed * polarity * (abs(coordinate) / speedRegulator);
94 }
95 } else {
96 return 0;
97 }
98}
99
100void pointing_device_task(void) {
101 report_mouse_t report = pointing_device_get_report();
102
103 // todo read as one vector
104 if (timer_elapsed(lastCursor) > cursorTimeout) {
105 lastCursor = timer_read();
106 report.x = axisToMouseComponent(B4, xOrigin, maxCursorSpeed, xPolarity);
107 report.y = axisToMouseComponent(B5, yOrigin, maxCursorSpeed, yPolarity);
108 }
109 //
110 if (!readPin(E6)) {
111 report.buttons |= MOUSE_BTN1;
112 } else {
113 report.buttons &= ~MOUSE_BTN1;
114 }
115
116 pointing_device_set_report(report);
117 pointing_device_send();
118}
119
120void matrix_init_keymap(void) {
121 // init pin? Is needed?
122 setPinInputHigh(E6);
123 // Account for drift
124 xOrigin = analogReadPin(B4);
125 yOrigin = analogReadPin(B5);
126}
diff --git a/keyboards/40percentclub/nano/keymaps/drashna/rules.mk b/keyboards/40percentclub/nano/keymaps/drashna/rules.mk
index 2b72a112b..aa7966a8b 100644
--- a/keyboards/40percentclub/nano/keymaps/drashna/rules.mk
+++ b/keyboards/40percentclub/nano/keymaps/drashna/rules.mk
@@ -1,7 +1,6 @@
1POINTING_DEVICE_ENABLE = yes 1POINTING_DEVICE_ENABLE = yes
2RGBLIGHT_ENABLE = no 2POINTING_DEVICE_DRIVER = analog_joystick
3CONSOLE_ENABLE = no 3RGBLIGHT_ENABLE = no
4CONSOLE_ENABLE = no
4 5
5BOOTLOADER = qmk-dfu 6BOOTLOADER = qmk-dfu
6
7SRC += analog.c
diff --git a/keyboards/handwired/tractyl_manuform/5x6_right/config.h b/keyboards/handwired/tractyl_manuform/5x6_right/config.h
index ce35197f7..6f702bd59 100644
--- a/keyboards/handwired/tractyl_manuform/5x6_right/config.h
+++ b/keyboards/handwired/tractyl_manuform/5x6_right/config.h
@@ -31,6 +31,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
31#define DIODE_DIRECTION COL2ROW 31#define DIODE_DIRECTION COL2ROW
32 32
33#define ROTATIONAL_TRANSFORM_ANGLE -25 33#define ROTATIONAL_TRANSFORM_ANGLE -25
34#define POINTING_DEVICE_INVERT_X
34 35
35/* Bootmagic Lite key configuration */ 36/* Bootmagic Lite key configuration */
36#define BOOTMAGIC_LITE_ROW 0 37#define BOOTMAGIC_LITE_ROW 0
diff --git a/keyboards/handwired/tractyl_manuform/5x6_right/keymaps/drashna/keymap.c b/keyboards/handwired/tractyl_manuform/5x6_right/keymaps/drashna/keymap.c
index 5bfc21fd1..127595076 100644
--- a/keyboards/handwired/tractyl_manuform/5x6_right/keymaps/drashna/keymap.c
+++ b/keyboards/handwired/tractyl_manuform/5x6_right/keymaps/drashna/keymap.c
@@ -174,7 +174,11 @@ bool tap_toggling = false;
174# define TAP_CHECK TAPPING_TERM 174# define TAP_CHECK TAPPING_TERM
175# endif 175# endif
176 176
177void process_mouse_user(report_mouse_t* mouse_report, int8_t x, int8_t y) { 177report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) {
178 int8_t x = mouse_report.x, y = mouse_report.y;
179 mouse_report.x = 0;
180 mouse_report.y = 0;
181
178 if (x != 0 && y != 0) { 182 if (x != 0 && y != 0) {
179 mouse_timer = timer_read(); 183 mouse_timer = timer_read();
180# ifdef OLED_ENABLE 184# ifdef OLED_ENABLE
@@ -185,13 +189,14 @@ void process_mouse_user(report_mouse_t* mouse_report, int8_t x, int8_t y) {
185 x = (x > 0 ? x * x / 16 + x : -x * x / 16 + x); 189 x = (x > 0 ? x * x / 16 + x : -x * x / 16 + x);
186 y = (y > 0 ? y * y / 16 + y : -y * y / 16 + y); 190 y = (y > 0 ? y * y / 16 + y : -y * y / 16 + y);
187 } 191 }
188 mouse_report->x = x; 192 mouse_report.x = x;
189 mouse_report->y = y; 193 mouse_report.y = y;
190 if (!layer_state_is(_MOUSE)) { 194 if (!layer_state_is(_MOUSE)) {
191 layer_on(_MOUSE); 195 layer_on(_MOUSE);
192 } 196 }
193 } 197 }
194 } 198 }
199 return mouse_report;
195} 200}
196 201
197void matrix_scan_keymap(void) { 202void matrix_scan_keymap(void) {
diff --git a/keyboards/handwired/tractyl_manuform/5x6_right/rules.mk b/keyboards/handwired/tractyl_manuform/5x6_right/rules.mk
index c9bc2dbb9..699e82648 100644
--- a/keyboards/handwired/tractyl_manuform/5x6_right/rules.mk
+++ b/keyboards/handwired/tractyl_manuform/5x6_right/rules.mk
@@ -16,11 +16,11 @@ AUDIO_ENABLE = no # Audio output
16SWAP_HANDS_ENABLE = yes 16SWAP_HANDS_ENABLE = yes
17 17
18POINTING_DEVICE_ENABLE = yes 18POINTING_DEVICE_ENABLE = yes
19POINTING_DEVICE_DRIVER = pmw3360
19MOUSE_SHARED_EP = no 20MOUSE_SHARED_EP = no
20 21
21SPLIT_KEYBOARD = yes 22SPLIT_KEYBOARD = yes
22 23
23SRC += drivers/sensors/pmw3360.c 24QUANTUM_LIB_SRC += tm_sync.c
24QUANTUM_LIB_SRC += spi_master.c tm_sync.c
25 25
26DEFAULT_FOLDER = handwired/tractyl_manuform/5x6_right/teensy2pp 26DEFAULT_FOLDER = handwired/tractyl_manuform/5x6_right/teensy2pp
diff --git a/keyboards/handwired/tractyl_manuform/tm_sync.c b/keyboards/handwired/tractyl_manuform/tm_sync.c
index 1cb354946..4739af1e7 100644
--- a/keyboards/handwired/tractyl_manuform/tm_sync.c
+++ b/keyboards/handwired/tractyl_manuform/tm_sync.c
@@ -17,7 +17,6 @@
17#include "tractyl_manuform.h" 17#include "tractyl_manuform.h"
18#include "transactions.h" 18#include "transactions.h"
19#include <string.h> 19#include <string.h>
20#include "drivers/sensors/pmw3360.h"
21 20
22kb_config_data_t kb_config; 21kb_config_data_t kb_config;
23kb_mouse_report_t sync_mouse_report; 22kb_mouse_report_t sync_mouse_report;
@@ -82,6 +81,6 @@ void housekeeping_task_sync(void) {
82void trackball_set_cpi(uint16_t cpi) { 81void trackball_set_cpi(uint16_t cpi) {
83 kb_config.device_cpi = cpi; 82 kb_config.device_cpi = cpi;
84 if (!is_keyboard_left()) { 83 if (!is_keyboard_left()) {
85 pmw_set_cpi(cpi); 84 pointing_device_set_cpi(cpi);
86 } 85 }
87} 86}
diff --git a/keyboards/handwired/tractyl_manuform/tractyl_manuform.c b/keyboards/handwired/tractyl_manuform/tractyl_manuform.c
index d851528ff..5f476fcc9 100644
--- a/keyboards/handwired/tractyl_manuform/tractyl_manuform.c
+++ b/keyboards/handwired/tractyl_manuform/tractyl_manuform.c
@@ -34,55 +34,7 @@ keyboard_config_t keyboard_config;
34uint16_t dpi_array[] = TRACKBALL_DPI_OPTIONS; 34uint16_t dpi_array[] = TRACKBALL_DPI_OPTIONS;
35#define DPI_OPTION_SIZE (sizeof(dpi_array) / sizeof(uint16_t)) 35#define DPI_OPTION_SIZE (sizeof(dpi_array) / sizeof(uint16_t))
36 36
37bool BurstState = false; // init burst state for Trackball module
38uint16_t MotionStart = 0; // Timer for accel, 0 is resting state
39 37
40__attribute__((weak)) void process_mouse_user(report_mouse_t* mouse_report, int8_t x, int8_t y) {
41 mouse_report->x = x;
42 mouse_report->y = y;
43}
44
45__attribute__((weak)) void process_mouse(void) {
46 report_pmw_t data = pmw_read_burst();
47 // Reset timer if stopped moving
48 if (!data.isMotion) {
49 if (MotionStart != 0) MotionStart = 0;
50 return;
51 }
52
53 if (data.isOnSurface) {
54 // Set timer if new motion
55 if (MotionStart == 0) {
56 if (debug_mouse) dprintf("Starting motion.\n");
57 MotionStart = timer_read();
58 }
59
60 if (debug_mouse) {
61 dprintf("Delt] d: %d t: %u\n", abs(data.dx) + abs(data.dy), MotionStart);
62 }
63 if (debug_mouse) {
64 dprintf("Pre ] X: %d, Y: %d\n", data.dx, data.dy);
65 }
66#if defined(PROFILE_LINEAR)
67 float scale = float(timer_elaspsed(MotionStart)) / 1000.0;
68 data.dx *= scale;
69 data.dy *= scale;
70#elif defined(PROFILE_INVERSE)
71 // TODO
72#else
73 // no post processing
74#endif
75
76 // Wrap to HID size
77 data.dx = constrain(data.dx, -127, 127);
78 data.dy = constrain(data.dy, -127, 127);
79 if (debug_mouse) dprintf("Cons] X: %d, Y: %d\n", data.dx, data.dy);
80 // dprintf("Elapsed:%u, X: %f Y: %\n", i, pgm_read_byte(firmware_data+i));
81
82 sync_mouse_report.x = -data.dx;
83 sync_mouse_report.y = data.dy;
84 }
85}
86 38
87bool process_record_kb(uint16_t keycode, keyrecord_t* record) { 39bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
88 if (!process_record_user(keycode, record)) { 40 if (!process_record_user(keycode, record)) {
@@ -109,11 +61,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
109#ifndef MOUSEKEY_ENABLE 61#ifndef MOUSEKEY_ENABLE
110 if (IS_MOUSEKEY_BUTTON(keycode)) { 62 if (IS_MOUSEKEY_BUTTON(keycode)) {
111 report_mouse_t currentReport = pointing_device_get_report(); 63 report_mouse_t currentReport = pointing_device_get_report();
112 if (record->event.pressed) { 64 currentReport.buttons = pointing_device_handle_buttons(currentReport.buttons, record->event.pressed, keycode - KC_MS_BTN1);
113 currentReport.buttons |= 1 << (keycode - KC_MS_BTN1);
114 } else {
115 currentReport.buttons &= ~(1 << (keycode - KC_MS_BTN1));
116 }
117 pointing_device_set_report(currentReport); 65 pointing_device_set_report(currentReport);
118 pointing_device_send(); 66 pointing_device_send();
119 } 67 }
@@ -145,33 +93,28 @@ void keyboard_post_init_kb(void) {
145} 93}
146 94
147#ifdef POINTING_DEVICE_ENABLE 95#ifdef POINTING_DEVICE_ENABLE
148void pointing_device_init(void) { 96void pointing_device_init_kb(void) {
149 if (!is_keyboard_left()) {
150 // initialize ball sensor
151 pmw_spi_init();
152 }
153 trackball_set_cpi(dpi_array[keyboard_config.dpi_config]); 97 trackball_set_cpi(dpi_array[keyboard_config.dpi_config]);
98 pointing_device_init_user();
154} 99}
155 100
156void pointing_device_task(void) { 101report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
157 report_mouse_t mouse_report = pointing_device_get_report();
158
159 if (is_keyboard_left()) { 102 if (is_keyboard_left()) {
160 if (is_keyboard_master()) { 103 if (is_keyboard_master()) {
161 transaction_rpc_recv(RPC_ID_POINTER_STATE_SYNC, sizeof(sync_mouse_report), &sync_mouse_report); 104 transaction_rpc_recv(RPC_ID_POINTER_STATE_SYNC, sizeof(sync_mouse_report), &sync_mouse_report);
162 process_mouse_user(&mouse_report, sync_mouse_report.x, sync_mouse_report.y); 105 mouse_report.x = sync_mouse_report.x;
106 mouse_report.y = sync_mouse_report.y;
107 pointing_device_task_user(mouse_report);
163 } 108 }
164 } else { 109 } else {
165 process_mouse();
166 if (is_keyboard_master()) { 110 if (is_keyboard_master()) {
167 process_mouse_user(&mouse_report, sync_mouse_report.x, sync_mouse_report.y); 111 pointing_device_task_user(mouse_report);
168 sync_mouse_report.x = 0; 112 } else {
169 sync_mouse_report.y = 0; 113 sync_mouse_report.x = mouse_report.x;
114 sync_mouse_report.y = mouse_report.y;
170 } 115 }
171 } 116 }
172 117 return mouse_report;
173 pointing_device_set_report(mouse_report);
174 pointing_device_send();
175} 118}
176#endif 119#endif
177 120
diff --git a/keyboards/oddball/config.h b/keyboards/oddball/config.h
index 050084d2d..4bc9c7997 100644
--- a/keyboards/oddball/config.h
+++ b/keyboards/oddball/config.h
@@ -58,3 +58,6 @@
58/* Bootmagic Lite key configuration */ 58/* Bootmagic Lite key configuration */
59// #define BOOTMAGIC_LITE_ROW 0 59// #define BOOTMAGIC_LITE_ROW 0
60// #define BOOTMAGIC_LITE_COLUMN 0 60// #define BOOTMAGIC_LITE_COLUMN 0
61
62#define ADNS9800_CS_PIN SPI_SS_PIN
63#define PMW3360_CS_PIN SPI_SS_PIN
diff --git a/keyboards/oddball/keymaps/default/config.h b/keyboards/oddball/keymaps/default/config.h
deleted file mode 100644
index 7eddc070d..000000000
--- a/keyboards/oddball/keymaps/default/config.h
+++ /dev/null
@@ -1 +0,0 @@
1#define ADNS_9800
diff --git a/keyboards/oddball/keymaps/default/rules.mk b/keyboards/oddball/keymaps/default/rules.mk
new file mode 100644
index 000000000..84de35aeb
--- /dev/null
+++ b/keyboards/oddball/keymaps/default/rules.mk
@@ -0,0 +1 @@
POINTING_DEVICE_DRIVER = adns9800
diff --git a/keyboards/oddball/keymaps/pmw3360/config.h b/keyboards/oddball/keymaps/pmw3360/config.h
deleted file mode 100644
index f9af5f391..000000000
--- a/keyboards/oddball/keymaps/pmw3360/config.h
+++ /dev/null
@@ -1 +0,0 @@
1#define PMW_3360
diff --git a/keyboards/oddball/keymaps/pmw3360/rules.mk b/keyboards/oddball/keymaps/pmw3360/rules.mk
new file mode 100644
index 000000000..fab9162dc
--- /dev/null
+++ b/keyboards/oddball/keymaps/pmw3360/rules.mk
@@ -0,0 +1 @@
POINTING_DEVICE_DRIVER = pmw3360
diff --git a/keyboards/oddball/oddball.c b/keyboards/oddball/oddball.c
index 7ac6d9901..bbc3b3f2e 100644
--- a/keyboards/oddball/oddball.c
+++ b/keyboards/oddball/oddball.c
@@ -16,21 +16,17 @@
16 16
17#include "oddball.h" 17#include "oddball.h"
18#include "pointing_device.h" 18#include "pointing_device.h"
19#include "optical_sensor/optical_sensor.h" 19extern const pointing_device_driver_t pointing_device_driver;
20
21#define CLAMP_HID(value) value < -127 ? -127 : value > 127 ? 127 : value
22 20
23static bool scroll_pressed; 21static bool scroll_pressed;
24static bool mouse_buttons_dirty; 22static bool mouse_buttons_dirty;
25static int8_t scroll_h; 23static int8_t scroll_h;
26static int8_t scroll_v; 24static int8_t scroll_v;
27 25
28void pointing_device_init(void){ 26void pointing_device_init_kb(void){
29 if(!is_keyboard_master()) 27 if(!is_keyboard_master())
30 return; 28 return;
31 29
32 optical_sensor_init();
33
34 // read config from EEPROM and update if needed 30 // read config from EEPROM and update if needed
35 31
36 config_oddball_t kb_config; 32 config_oddball_t kb_config;
@@ -41,21 +37,17 @@ void pointing_device_init(void){
41 eeconfig_update_kb(kb_config.raw); 37 eeconfig_update_kb(kb_config.raw);
42 } 38 }
43 39
44 optical_sensor_set_config((config_optical_sensor_t){ kb_config.cpi }); 40 pointing_device_set_cpi(kb_config.cpi);
45} 41}
46 42
47void pointing_device_task(void){ 43report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
48 if(!is_keyboard_master()) 44 if (!is_keyboard_master()) return mouse_report;
49 return;
50
51 report_mouse_t mouse_report = pointing_device_get_report();
52 report_optical_sensor_t sensor_report = optical_sensor_get_report();
53
54 int8_t clamped_x = CLAMP_HID(sensor_report.x);
55 int8_t clamped_y = CLAMP_HID(sensor_report.y);
56 45
57 if(scroll_pressed) { 46 int8_t clamped_x = mouse_report.x, clamped_y = mouse_report.y;
47 mouse_report.x = 0;
48 mouse_report.y = 0;
58 49
50 if (scroll_pressed) {
59 // accumulate scroll 51 // accumulate scroll
60 scroll_h += clamped_x; 52 scroll_h += clamped_x;
61 scroll_v += clamped_y; 53 scroll_v += clamped_y;
@@ -65,33 +57,21 @@ void pointing_device_task(void){
65 57
66 // clear accumulated scroll on assignment 58 // clear accumulated scroll on assignment
67 59
68 if(scaled_scroll_h != 0){ 60 if (scaled_scroll_h != 0) {
69 mouse_report.h = -scaled_scroll_h; 61 mouse_report.h = -scaled_scroll_h;
70 scroll_h = 0; 62 scroll_h = 0;
71 } 63 }
72 64
73 if(scaled_scroll_v != 0){ 65 if (scaled_scroll_v != 0) {
74 mouse_report.v = -scaled_scroll_v; 66 mouse_report.v = -scaled_scroll_v;
75 scroll_v = 0; 67 scroll_v = 0;
76 } 68 }
77 } 69 } else {
78 else {
79 mouse_report.x = -clamped_x; 70 mouse_report.x = -clamped_x;
80 mouse_report.y = clamped_y; 71 mouse_report.y = clamped_y;
81 } 72 }
82 73
83 pointing_device_set_report(mouse_report); 74 return mouse_report;
84
85 // only send report on change as even sending report with no change is treated as movement
86 if(mouse_buttons_dirty ||
87 mouse_report.x != 0 ||
88 mouse_report.y != 0 ||
89 mouse_report.h != 0 ||
90 mouse_report.v != 0){
91
92 mouse_buttons_dirty = false;
93 pointing_device_send();
94 }
95} 75}
96 76
97static void on_cpi_button(uint16_t cpi, keyrecord_t *record) { 77static void on_cpi_button(uint16_t cpi, keyrecord_t *record) {
@@ -99,7 +79,7 @@ static void on_cpi_button(uint16_t cpi, keyrecord_t *record) {
99 if(!record->event.pressed) 79 if(!record->event.pressed)
100 return; 80 return;
101 81
102 optical_sensor_set_config((config_optical_sensor_t){ cpi }); 82 pointing_device_set_cpi(cpi);
103 83
104 config_oddball_t kb_config; 84 config_oddball_t kb_config;
105 kb_config.cpi = cpi; 85 kb_config.cpi = cpi;
@@ -165,5 +145,5 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
165 145
166 default: 146 default:
167 return true; 147 return true;
168 } 148 }
169} 149}
diff --git a/keyboards/oddball/optical_sensor/optical_sensor.h b/keyboards/oddball/optical_sensor/optical_sensor.h
deleted file mode 100644
index 00955209e..000000000
--- a/keyboards/oddball/optical_sensor/optical_sensor.h
+++ /dev/null
@@ -1,53 +0,0 @@
1/* Copyright 2020 Alexander Tulloh
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/* common interface for opitcal sensors */
18
19#if defined ADNS_9800
20 #include "drivers/sensors/adns9800.h"
21 #define config_optical_sensor_t config_adns_t
22 #define report_optical_sensor_t report_adns_t
23 #define optical_sensor_init adns_init
24 #define optical_sensor_get_config adns_get_config
25 #define optical_sensor_set_config adns_set_config
26 #define optical_sensor_get_report adns_get_report
27#elif defined PMW_3360
28 #include "../pmw/pmw.h"
29 #define config_optical_sensor_t config_pmw_t
30 #define report_optical_sensor_t report_pmw_t
31 #define optical_sensor_init pmw_init
32 #define optical_sensor_get_config pmw_get_config
33 #define optical_sensor_set_config pmw_set_config
34 #define optical_sensor_get_report pmw_get_report
35#else
36 /* fallback stub */
37
38 #include <stdint.h>
39
40 typedef struct {
41 uint16_t cpi;
42 } config_optical_sensor_t;
43
44 typedef struct {
45 int16_t x;
46 int16_t y;
47 } report_optical_sensor_t;
48
49 #define optical_sensor_init(){ }
50 #define optical_sensor_get_config() (config_optical_sensor_t){ }
51 #define optical_sensor_set_config(config_optical_sensor_t){ }
52 #define optical_sensor_get_report() (report_optical_sensor_t){ }
53#endif
diff --git a/keyboards/oddball/pmw/pmw.c b/keyboards/oddball/pmw/pmw.c
deleted file mode 100644
index 51d692702..000000000
--- a/keyboards/oddball/pmw/pmw.c
+++ /dev/null
@@ -1,226 +0,0 @@
1/* Copyright 2020 Alexander Tulloh
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 "spi_master.h"
18#include "quantum.h"
19#include "pmw3360_srom_0x04.h"
20#include "pmw.h"
21
22// registers
23#define Product_ID 0x00
24#define Revision_ID 0x01
25#define Motion 0x02
26#define Delta_X_L 0x03
27#define Delta_X_H 0x04
28#define Delta_Y_L 0x05
29#define Delta_Y_H 0x06
30#define SQUAL 0x07
31#define Raw_Data_Sum 0x08
32#define Maximum_Raw_data 0x09
33#define Minimum_Raw_data 0x0A
34#define Shutter_Lower 0x0B
35#define Shutter_Upper 0x0C
36#define Control 0x0D
37#define Config1 0x0F
38#define Config2 0x10
39#define Angle_Tune 0x11
40#define Frame_Capture 0x12
41#define SROM_Enable 0x13
42#define Run_Downshift 0x14
43#define Rest1_Rate_Lower 0x15
44#define Rest1_Rate_Upper 0x16
45#define Rest1_Downshift 0x17
46#define Rest2_Rate_Lower 0x18
47#define Rest2_Rate_Upper 0x19
48#define Rest2_Downshift 0x1A
49#define Rest3_Rate_Lower 0x1B
50#define Rest3_Rate_Upper 0x1C
51#define Observation 0x24
52#define Data_Out_Lower 0x25
53#define Data_Out_Upper 0x26
54#define Raw_Data_Dump 0x29
55#define SROM_ID 0x2A
56#define Min_SQ_Run 0x2B
57#define Raw_Data_Threshold 0x2C
58#define Config5 0x2F
59#define Power_Up_Reset 0x3A
60#define Shutdown 0x3B
61#define Inverse_Product_ID 0x3F
62#define LiftCutoff_Tune3 0x41
63#define Angle_Snap 0x42
64#define LiftCutoff_Tune1 0x4A
65#define Motion_Burst 0x50
66#define LiftCutoff_Tune_Timeout 0x58
67#define LiftCutoff_Tune_Min_Length 0x5A
68#define SROM_Load_Burst 0x62
69#define Lift_Config 0x63
70#define Raw_Data_Burst 0x64
71#define LiftCutoff_Tune2 0x65
72
73#define PMW_CLOCK_SPEED 70000000
74#define MIN_CPI 100
75#define MAX_CPI 12000
76#define CPI_STEP 100
77#define CLAMP_CPI(value) value < MIN_CPI ? MIN_CPI : value > MAX_CPI ? MAX_CPI : value
78#define SPI_MODE 3
79#define SPI_DIVISOR (F_CPU / PMW_CLOCK_SPEED)
80#define US_BETWEEN_WRITES 180
81#define US_BETWEEN_READS 20
82#define US_BEFORE_MOTION 35
83
84#define MSB1 0x80
85
86extern const uint16_t pmw_firmware_length;
87extern const uint8_t pmw_firmware_data[];
88
89void pmw_spi_start(void){
90 spi_start(SPI_SS_PIN, false, SPI_MODE, SPI_DIVISOR);
91}
92
93void pmw_write(uint8_t reg_addr, uint8_t data){
94
95 pmw_spi_start();
96 spi_write(reg_addr | MSB1 );
97 spi_write(data);
98 spi_stop();
99 wait_us(US_BETWEEN_WRITES);
100}
101
102uint8_t pmw_read(uint8_t reg_addr){
103
104 pmw_spi_start();
105 spi_write(reg_addr & 0x7f );
106 uint8_t data = spi_read();
107 spi_stop();
108 wait_us(US_BETWEEN_READS);
109
110 return data;
111}
112
113void pmw_init() {
114
115 setPinOutput(SPI_SS_PIN);
116
117 spi_init();
118
119 // reboot
120 pmw_write(Power_Up_Reset, 0x5a);
121 wait_ms(50);
122
123 // read registers and discard
124 pmw_read(Motion);
125 pmw_read(Delta_X_L);
126 pmw_read(Delta_X_H);
127 pmw_read(Delta_Y_L);
128 pmw_read(Delta_Y_H);
129
130 // upload firmware
131
132 // disable rest mode
133 pmw_write(Config2, 0x20);
134
135 // enable initialisation
136 pmw_write(SROM_Enable, 0x1d);
137
138 // wait a frame
139 wait_ms(10);
140
141 // start SROM download
142 pmw_write(SROM_Enable, 0x18);
143
144 // write the SROM file
145
146 pmw_spi_start();
147
148 spi_write(SROM_Load_Burst | 0x80);
149 wait_us(15);
150
151 // send all bytes of the firmware
152 unsigned char c;
153 for(int i = 0; i < pmw_firmware_length; i++){
154 c = (unsigned char)pgm_read_byte(pmw_firmware_data + i);
155 spi_write(c);
156 wait_us(15);
157 }
158
159 spi_stop();
160 wait_us(US_BETWEEN_WRITES);
161
162 // read id
163 pmw_read(SROM_ID);
164
165 // wired mouse
166 pmw_write(Config2, 0x00);
167
168 // first motion burst; write anything
169 pmw_write(Motion_Burst, 0xFF);
170 writePinLow(SPI_SS_PIN);
171}
172
173config_pmw_t pmw_get_config(void) {
174 uint8_t config_1 = pmw_read(Config1);
175 return (config_pmw_t){ (config_1 & 0xFF) * CPI_STEP };
176}
177
178void pmw_set_config(config_pmw_t config) {
179 uint8_t config_1 = (CLAMP_CPI(config.cpi) / CPI_STEP) & 0xFF;
180 pmw_write(Config1, config_1);
181}
182
183static int16_t convertDeltaToInt(uint8_t high, uint8_t low){
184
185 // join bytes into twos compliment
186 uint16_t twos_comp = (high << 8) | low;
187
188 // convert twos comp to int
189 if (twos_comp & 0x8000)
190 return -1 * (~twos_comp + 1);
191
192 return twos_comp;
193}
194
195report_pmw_t pmw_get_report(void) {
196
197 report_pmw_t report = {0, 0};
198
199 pmw_spi_start();
200
201 // start burst mode
202 spi_write(Motion_Burst & 0x7f);
203
204 wait_us(US_BEFORE_MOTION);
205
206 uint8_t motion = spi_read();
207
208 if(motion & 0x80) {
209
210 // clear observation register
211 spi_read();
212
213 // delta registers
214 uint8_t delta_x_l = spi_read();
215 uint8_t delta_x_h = spi_read();
216 uint8_t delta_y_l = spi_read();
217 uint8_t delta_y_h = spi_read();
218
219 report.x = convertDeltaToInt(delta_x_h, delta_x_l);
220 report.y = convertDeltaToInt(delta_y_h, delta_y_l);
221 }
222
223 spi_stop();
224
225 return report;
226}
diff --git a/keyboards/oddball/pmw/pmw3360_srom_0x04.h b/keyboards/oddball/pmw/pmw3360_srom_0x04.h
deleted file mode 100644
index 0dda4f1ab..000000000
--- a/keyboards/oddball/pmw/pmw3360_srom_0x04.h
+++ /dev/null
@@ -1,280 +0,0 @@
1#pragma once
2
3#include "progmem.h"
4
5const uint16_t pmw_firmware_length = 4094;
6
7const uint8_t pmw_firmware_data[] PROGMEM = {
80x01, 0x04, 0x8e, 0x96, 0x6e, 0x77, 0x3e, 0xfe, 0x7e, 0x5f, 0x1d, 0xb8, 0xf2, 0x66, 0x4e,
90xff, 0x5d, 0x19, 0xb0, 0xc2, 0x04, 0x69, 0x54, 0x2a, 0xd6, 0x2e, 0xbf, 0xdd, 0x19, 0xb0,
100xc3, 0xe5, 0x29, 0xb1, 0xe0, 0x23, 0xa5, 0xa9, 0xb1, 0xc1, 0x00, 0x82, 0x67, 0x4c, 0x1a,
110x97, 0x8d, 0x79, 0x51, 0x20, 0xc7, 0x06, 0x8e, 0x7c, 0x7c, 0x7a, 0x76, 0x4f, 0xfd, 0x59,
120x30, 0xe2, 0x46, 0x0e, 0x9e, 0xbe, 0xdf, 0x1d, 0x99, 0x91, 0xa0, 0xa5, 0xa1, 0xa9, 0xd0,
130x22, 0xc6, 0xef, 0x5c, 0x1b, 0x95, 0x89, 0x90, 0xa2, 0xa7, 0xcc, 0xfb, 0x55, 0x28, 0xb3,
140xe4, 0x4a, 0xf7, 0x6c, 0x3b, 0xf4, 0x6a, 0x56, 0x2e, 0xde, 0x1f, 0x9d, 0xb8, 0xd3, 0x05,
150x88, 0x92, 0xa6, 0xce, 0x1e, 0xbe, 0xdf, 0x1d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x5c, 0x07,
160x11, 0x5d, 0x98, 0x0b, 0x9d, 0x94, 0x97, 0xee, 0x4e, 0x45, 0x33, 0x6b, 0x44, 0xc7, 0x29,
170x56, 0x27, 0x30, 0xc6, 0xa7, 0xd5, 0xf2, 0x56, 0xdf, 0xb4, 0x38, 0x62, 0xcb, 0xa0, 0xb6,
180xe3, 0x0f, 0x84, 0x06, 0x24, 0x05, 0x65, 0x6f, 0x76, 0x89, 0xb5, 0x77, 0x41, 0x27, 0x82,
190x66, 0x65, 0x82, 0xcc, 0xd5, 0xe6, 0x20, 0xd5, 0x27, 0x17, 0xc5, 0xf8, 0x03, 0x23, 0x7c,
200x5f, 0x64, 0xa5, 0x1d, 0xc1, 0xd6, 0x36, 0xcb, 0x4c, 0xd4, 0xdb, 0x66, 0xd7, 0x8b, 0xb1,
210x99, 0x7e, 0x6f, 0x4c, 0x36, 0x40, 0x06, 0xd6, 0xeb, 0xd7, 0xa2, 0xe4, 0xf4, 0x95, 0x51,
220x5a, 0x54, 0x96, 0xd5, 0x53, 0x44, 0xd7, 0x8c, 0xe0, 0xb9, 0x40, 0x68, 0xd2, 0x18, 0xe9,
230xdd, 0x9a, 0x23, 0x92, 0x48, 0xee, 0x7f, 0x43, 0xaf, 0xea, 0x77, 0x38, 0x84, 0x8c, 0x0a,
240x72, 0xaf, 0x69, 0xf8, 0xdd, 0xf1, 0x24, 0x83, 0xa3, 0xf8, 0x4a, 0xbf, 0xf5, 0x94, 0x13,
250xdb, 0xbb, 0xd8, 0xb4, 0xb3, 0xa0, 0xfb, 0x45, 0x50, 0x60, 0x30, 0x59, 0x12, 0x31, 0x71,
260xa2, 0xd3, 0x13, 0xe7, 0xfa, 0xe7, 0xce, 0x0f, 0x63, 0x15, 0x0b, 0x6b, 0x94, 0xbb, 0x37,
270x83, 0x26, 0x05, 0x9d, 0xfb, 0x46, 0x92, 0xfc, 0x0a, 0x15, 0xd1, 0x0d, 0x73, 0x92, 0xd6,
280x8c, 0x1b, 0x8c, 0xb8, 0x55, 0x8a, 0xce, 0xbd, 0xfe, 0x8e, 0xfc, 0xed, 0x09, 0x12, 0x83,
290x91, 0x82, 0x51, 0x31, 0x23, 0xfb, 0xb4, 0x0c, 0x76, 0xad, 0x7c, 0xd9, 0xb4, 0x4b, 0xb2,
300x67, 0x14, 0x09, 0x9c, 0x7f, 0x0c, 0x18, 0xba, 0x3b, 0xd6, 0x8e, 0x14, 0x2a, 0xe4, 0x1b,
310x52, 0x9f, 0x2b, 0x7d, 0xe1, 0xfb, 0x6a, 0x33, 0x02, 0xfa, 0xac, 0x5a, 0xf2, 0x3e, 0x88,
320x7e, 0xae, 0xd1, 0xf3, 0x78, 0xe8, 0x05, 0xd1, 0xe3, 0xdc, 0x21, 0xf6, 0xe1, 0x9a, 0xbd,
330x17, 0x0e, 0xd9, 0x46, 0x9b, 0x88, 0x03, 0xea, 0xf6, 0x66, 0xbe, 0x0e, 0x1b, 0x50, 0x49,
340x96, 0x40, 0x97, 0xf1, 0xf1, 0xe4, 0x80, 0xa6, 0x6e, 0xe8, 0x77, 0x34, 0xbf, 0x29, 0x40,
350x44, 0xc2, 0xff, 0x4e, 0x98, 0xd3, 0x9c, 0xa3, 0x32, 0x2b, 0x76, 0x51, 0x04, 0x09, 0xe7,
360xa9, 0xd1, 0xa6, 0x32, 0xb1, 0x23, 0x53, 0xe2, 0x47, 0xab, 0xd6, 0xf5, 0x69, 0x5c, 0x3e,
370x5f, 0xfa, 0xae, 0x45, 0x20, 0xe5, 0xd2, 0x44, 0xff, 0x39, 0x32, 0x6d, 0xfd, 0x27, 0x57,
380x5c, 0xfd, 0xf0, 0xde, 0xc1, 0xb5, 0x99, 0xe5, 0xf5, 0x1c, 0x77, 0x01, 0x75, 0xc5, 0x6d,
390x58, 0x92, 0xf2, 0xb2, 0x47, 0x00, 0x01, 0x26, 0x96, 0x7a, 0x30, 0xff, 0xb7, 0xf0, 0xef,
400x77, 0xc1, 0x8a, 0x5d, 0xdc, 0xc0, 0xd1, 0x29, 0x30, 0x1e, 0x77, 0x38, 0x7a, 0x94, 0xf1,
410xb8, 0x7a, 0x7e, 0xef, 0xa4, 0xd1, 0xac, 0x31, 0x4a, 0xf2, 0x5d, 0x64, 0x3d, 0xb2, 0xe2,
420xf0, 0x08, 0x99, 0xfc, 0x70, 0xee, 0x24, 0xa7, 0x7e, 0xee, 0x1e, 0x20, 0x69, 0x7d, 0x44,
430xbf, 0x87, 0x42, 0xdf, 0x88, 0x3b, 0x0c, 0xda, 0x42, 0xc9, 0x04, 0xf9, 0x45, 0x50, 0xfc,
440x83, 0x8f, 0x11, 0x6a, 0x72, 0xbc, 0x99, 0x95, 0xf0, 0xac, 0x3d, 0xa7, 0x3b, 0xcd, 0x1c,
450xe2, 0x88, 0x79, 0x37, 0x11, 0x5f, 0x39, 0x89, 0x95, 0x0a, 0x16, 0x84, 0x7a, 0xf6, 0x8a,
460xa4, 0x28, 0xe4, 0xed, 0x83, 0x80, 0x3b, 0xb1, 0x23, 0xa5, 0x03, 0x10, 0xf4, 0x66, 0xea,
470xbb, 0x0c, 0x0f, 0xc5, 0xec, 0x6c, 0x69, 0xc5, 0xd3, 0x24, 0xab, 0xd4, 0x2a, 0xb7, 0x99,
480x88, 0x76, 0x08, 0xa0, 0xa8, 0x95, 0x7c, 0xd8, 0x38, 0x6d, 0xcd, 0x59, 0x02, 0x51, 0x4b,
490xf1, 0xb5, 0x2b, 0x50, 0xe3, 0xb6, 0xbd, 0xd0, 0x72, 0xcf, 0x9e, 0xfd, 0x6e, 0xbb, 0x44,
500xc8, 0x24, 0x8a, 0x77, 0x18, 0x8a, 0x13, 0x06, 0xef, 0x97, 0x7d, 0xfa, 0x81, 0xf0, 0x31,
510xe6, 0xfa, 0x77, 0xed, 0x31, 0x06, 0x31, 0x5b, 0x54, 0x8a, 0x9f, 0x30, 0x68, 0xdb, 0xe2,
520x40, 0xf8, 0x4e, 0x73, 0xfa, 0xab, 0x74, 0x8b, 0x10, 0x58, 0x13, 0xdc, 0xd2, 0xe6, 0x78,
530xd1, 0x32, 0x2e, 0x8a, 0x9f, 0x2c, 0x58, 0x06, 0x48, 0x27, 0xc5, 0xa9, 0x5e, 0x81, 0x47,
540x89, 0x46, 0x21, 0x91, 0x03, 0x70, 0xa4, 0x3e, 0x88, 0x9c, 0xda, 0x33, 0x0a, 0xce, 0xbc,
550x8b, 0x8e, 0xcf, 0x9f, 0xd3, 0x71, 0x80, 0x43, 0xcf, 0x6b, 0xa9, 0x51, 0x83, 0x76, 0x30,
560x82, 0xc5, 0x6a, 0x85, 0x39, 0x11, 0x50, 0x1a, 0x82, 0xdc, 0x1e, 0x1c, 0xd5, 0x7d, 0xa9,
570x71, 0x99, 0x33, 0x47, 0x19, 0x97, 0xb3, 0x5a, 0xb1, 0xdf, 0xed, 0xa4, 0xf2, 0xe6, 0x26,
580x84, 0xa2, 0x28, 0x9a, 0x9e, 0xdf, 0xa6, 0x6a, 0xf4, 0xd6, 0xfc, 0x2e, 0x5b, 0x9d, 0x1a,
590x2a, 0x27, 0x68, 0xfb, 0xc1, 0x83, 0x21, 0x4b, 0x90, 0xe0, 0x36, 0xdd, 0x5b, 0x31, 0x42,
600x55, 0xa0, 0x13, 0xf7, 0xd0, 0x89, 0x53, 0x71, 0x99, 0x57, 0x09, 0x29, 0xc5, 0xf3, 0x21,
610xf8, 0x37, 0x2f, 0x40, 0xf3, 0xd4, 0xaf, 0x16, 0x08, 0x36, 0x02, 0xfc, 0x77, 0xc5, 0x8b,
620x04, 0x90, 0x56, 0xb9, 0xc9, 0x67, 0x9a, 0x99, 0xe8, 0x00, 0xd3, 0x86, 0xff, 0x97, 0x2d,
630x08, 0xe9, 0xb7, 0xb3, 0x91, 0xbc, 0xdf, 0x45, 0xc6, 0xed, 0x0f, 0x8c, 0x4c, 0x1e, 0xe6,
640x5b, 0x6e, 0x38, 0x30, 0xe4, 0xaa, 0xe3, 0x95, 0xde, 0xb9, 0xe4, 0x9a, 0xf5, 0xb2, 0x55,
650x9a, 0x87, 0x9b, 0xf6, 0x6a, 0xb2, 0xf2, 0x77, 0x9a, 0x31, 0xf4, 0x7a, 0x31, 0xd1, 0x1d,
660x04, 0xc0, 0x7c, 0x32, 0xa2, 0x9e, 0x9a, 0xf5, 0x62, 0xf8, 0x27, 0x8d, 0xbf, 0x51, 0xff,
670xd3, 0xdf, 0x64, 0x37, 0x3f, 0x2a, 0x6f, 0x76, 0x3a, 0x7d, 0x77, 0x06, 0x9e, 0x77, 0x7f,
680x5e, 0xeb, 0x32, 0x51, 0xf9, 0x16, 0x66, 0x9a, 0x09, 0xf3, 0xb0, 0x08, 0xa4, 0x70, 0x96,
690x46, 0x30, 0xff, 0xda, 0x4f, 0xe9, 0x1b, 0xed, 0x8d, 0xf8, 0x74, 0x1f, 0x31, 0x92, 0xb3,
700x73, 0x17, 0x36, 0xdb, 0x91, 0x30, 0xd6, 0x88, 0x55, 0x6b, 0x34, 0x77, 0x87, 0x7a, 0xe7,
710xee, 0x06, 0xc6, 0x1c, 0x8c, 0x19, 0x0c, 0x48, 0x46, 0x23, 0x5e, 0x9c, 0x07, 0x5c, 0xbf,
720xb4, 0x7e, 0xd6, 0x4f, 0x74, 0x9c, 0xe2, 0xc5, 0x50, 0x8b, 0xc5, 0x8b, 0x15, 0x90, 0x60,
730x62, 0x57, 0x29, 0xd0, 0x13, 0x43, 0xa1, 0x80, 0x88, 0x91, 0x00, 0x44, 0xc7, 0x4d, 0x19,
740x86, 0xcc, 0x2f, 0x2a, 0x75, 0x5a, 0xfc, 0xeb, 0x97, 0x2a, 0x70, 0xe3, 0x78, 0xd8, 0x91,
750xb0, 0x4f, 0x99, 0x07, 0xa3, 0x95, 0xea, 0x24, 0x21, 0xd5, 0xde, 0x51, 0x20, 0x93, 0x27,
760x0a, 0x30, 0x73, 0xa8, 0xff, 0x8a, 0x97, 0xe9, 0xa7, 0x6a, 0x8e, 0x0d, 0xe8, 0xf0, 0xdf,
770xec, 0xea, 0xb4, 0x6c, 0x1d, 0x39, 0x2a, 0x62, 0x2d, 0x3d, 0x5a, 0x8b, 0x65, 0xf8, 0x90,
780x05, 0x2e, 0x7e, 0x91, 0x2c, 0x78, 0xef, 0x8e, 0x7a, 0xc1, 0x2f, 0xac, 0x78, 0xee, 0xaf,
790x28, 0x45, 0x06, 0x4c, 0x26, 0xaf, 0x3b, 0xa2, 0xdb, 0xa3, 0x93, 0x06, 0xb5, 0x3c, 0xa5,
800xd8, 0xee, 0x8f, 0xaf, 0x25, 0xcc, 0x3f, 0x85, 0x68, 0x48, 0xa9, 0x62, 0xcc, 0x97, 0x8f,
810x7f, 0x2a, 0xea, 0xe0, 0x15, 0x0a, 0xad, 0x62, 0x07, 0xbd, 0x45, 0xf8, 0x41, 0xd8, 0x36,
820xcb, 0x4c, 0xdb, 0x6e, 0xe6, 0x3a, 0xe7, 0xda, 0x15, 0xe9, 0x29, 0x1e, 0x12, 0x10, 0xa0,
830x14, 0x2c, 0x0e, 0x3d, 0xf4, 0xbf, 0x39, 0x41, 0x92, 0x75, 0x0b, 0x25, 0x7b, 0xa3, 0xce,
840x39, 0x9c, 0x15, 0x64, 0xc8, 0xfa, 0x3d, 0xef, 0x73, 0x27, 0xfe, 0x26, 0x2e, 0xce, 0xda,
850x6e, 0xfd, 0x71, 0x8e, 0xdd, 0xfe, 0x76, 0xee, 0xdc, 0x12, 0x5c, 0x02, 0xc5, 0x3a, 0x4e,
860x4e, 0x4f, 0xbf, 0xca, 0x40, 0x15, 0xc7, 0x6e, 0x8d, 0x41, 0xf1, 0x10, 0xe0, 0x4f, 0x7e,
870x97, 0x7f, 0x1c, 0xae, 0x47, 0x8e, 0x6b, 0xb1, 0x25, 0x31, 0xb0, 0x73, 0xc7, 0x1b, 0x97,
880x79, 0xf9, 0x80, 0xd3, 0x66, 0x22, 0x30, 0x07, 0x74, 0x1e, 0xe4, 0xd0, 0x80, 0x21, 0xd6,
890xee, 0x6b, 0x6c, 0x4f, 0xbf, 0xf5, 0xb7, 0xd9, 0x09, 0x87, 0x2f, 0xa9, 0x14, 0xbe, 0x27,
900xd9, 0x72, 0x50, 0x01, 0xd4, 0x13, 0x73, 0xa6, 0xa7, 0x51, 0x02, 0x75, 0x25, 0xe1, 0xb3,
910x45, 0x34, 0x7d, 0xa8, 0x8e, 0xeb, 0xf3, 0x16, 0x49, 0xcb, 0x4f, 0x8c, 0xa1, 0xb9, 0x36,
920x85, 0x39, 0x75, 0x5d, 0x08, 0x00, 0xae, 0xeb, 0xf6, 0xea, 0xd7, 0x13, 0x3a, 0x21, 0x5a,
930x5f, 0x30, 0x84, 0x52, 0x26, 0x95, 0xc9, 0x14, 0xf2, 0x57, 0x55, 0x6b, 0xb1, 0x10, 0xc2,
940xe1, 0xbd, 0x3b, 0x51, 0xc0, 0xb7, 0x55, 0x4c, 0x71, 0x12, 0x26, 0xc7, 0x0d, 0xf9, 0x51,
950xa4, 0x38, 0x02, 0x05, 0x7f, 0xb8, 0xf1, 0x72, 0x4b, 0xbf, 0x71, 0x89, 0x14, 0xf3, 0x77,
960x38, 0xd9, 0x71, 0x24, 0xf3, 0x00, 0x11, 0xa1, 0xd8, 0xd4, 0x69, 0x27, 0x08, 0x37, 0x35,
970xc9, 0x11, 0x9d, 0x90, 0x1c, 0x0e, 0xe7, 0x1c, 0xff, 0x2d, 0x1e, 0xe8, 0x92, 0xe1, 0x18,
980x10, 0x95, 0x7c, 0xe0, 0x80, 0xf4, 0x96, 0x43, 0x21, 0xf9, 0x75, 0x21, 0x64, 0x38, 0xdd,
990x9f, 0x1e, 0x95, 0x16, 0xda, 0x56, 0x1d, 0x4f, 0x9a, 0x53, 0xb2, 0xe2, 0xe4, 0x18, 0xcb,
1000x6b, 0x1a, 0x65, 0xeb, 0x56, 0xc6, 0x3b, 0xe5, 0xfe, 0xd8, 0x26, 0x3f, 0x3a, 0x84, 0x59,
1010x72, 0x66, 0xa2, 0xf3, 0x75, 0xff, 0xfb, 0x60, 0xb3, 0x22, 0xad, 0x3f, 0x2d, 0x6b, 0xf9,
1020xeb, 0xea, 0x05, 0x7c, 0xd8, 0x8f, 0x6d, 0x2c, 0x98, 0x9e, 0x2b, 0x93, 0xf1, 0x5e, 0x46,
1030xf0, 0x87, 0x49, 0x29, 0x73, 0x68, 0xd7, 0x7f, 0xf9, 0xf0, 0xe5, 0x7d, 0xdb, 0x1d, 0x75,
1040x19, 0xf3, 0xc4, 0x58, 0x9b, 0x17, 0x88, 0xa8, 0x92, 0xe0, 0xbe, 0xbd, 0x8b, 0x1d, 0x8d,
1050x9f, 0x56, 0x76, 0xad, 0xaf, 0x29, 0xe2, 0xd9, 0xd5, 0x52, 0xf6, 0xb5, 0x56, 0x35, 0x57,
1060x3a, 0xc8, 0xe1, 0x56, 0x43, 0x19, 0x94, 0xd3, 0x04, 0x9b, 0x6d, 0x35, 0xd8, 0x0b, 0x5f,
1070x4d, 0x19, 0x8e, 0xec, 0xfa, 0x64, 0x91, 0x0a, 0x72, 0x20, 0x2b, 0xbc, 0x1a, 0x4a, 0xfe,
1080x8b, 0xfd, 0xbb, 0xed, 0x1b, 0x23, 0xea, 0xad, 0x72, 0x82, 0xa1, 0x29, 0x99, 0x71, 0xbd,
1090xf0, 0x95, 0xc1, 0x03, 0xdd, 0x7b, 0xc2, 0xb2, 0x3c, 0x28, 0x54, 0xd3, 0x68, 0xa4, 0x72,
1100xc8, 0x66, 0x96, 0xe0, 0xd1, 0xd8, 0x7f, 0xf8, 0xd1, 0x26, 0x2b, 0xf7, 0xad, 0xba, 0x55,
1110xca, 0x15, 0xb9, 0x32, 0xc3, 0xe5, 0x88, 0x97, 0x8e, 0x5c, 0xfb, 0x92, 0x25, 0x8b, 0xbf,
1120xa2, 0x45, 0x55, 0x7a, 0xa7, 0x6f, 0x8b, 0x57, 0x5b, 0xcf, 0x0e, 0xcb, 0x1d, 0xfb, 0x20,
1130x82, 0x77, 0xa8, 0x8c, 0xcc, 0x16, 0xce, 0x1d, 0xfa, 0xde, 0xcc, 0x0b, 0x62, 0xfe, 0xcc,
1140xe1, 0xb7, 0xf0, 0xc3, 0x81, 0x64, 0x73, 0x40, 0xa0, 0xc2, 0x4d, 0x89, 0x11, 0x75, 0x33,
1150x55, 0x33, 0x8d, 0xe8, 0x4a, 0xfd, 0xea, 0x6e, 0x30, 0x0b, 0xd7, 0x31, 0x2c, 0xde, 0x47,
1160xe3, 0xbf, 0xf8, 0x55, 0x42, 0xe2, 0x7f, 0x59, 0xe5, 0x17, 0xef, 0x99, 0x34, 0x69, 0x91,
1170xb1, 0x23, 0x8e, 0x20, 0x87, 0x2d, 0xa8, 0xfe, 0xd5, 0x8a, 0xf3, 0x84, 0x3a, 0xf0, 0x37,
1180xe4, 0x09, 0x00, 0x54, 0xee, 0x67, 0x49, 0x93, 0xe4, 0x81, 0x70, 0xe3, 0x90, 0x4d, 0xef,
1190xfe, 0x41, 0xb7, 0x99, 0x7b, 0xc1, 0x83, 0xba, 0x62, 0x12, 0x6f, 0x7d, 0xde, 0x6b, 0xaf,
1200xda, 0x16, 0xf9, 0x55, 0x51, 0xee, 0xa6, 0x0c, 0x2b, 0x02, 0xa3, 0xfd, 0x8d, 0xfb, 0x30,
1210x17, 0xe4, 0x6f, 0xdf, 0x36, 0x71, 0xc4, 0xca, 0x87, 0x25, 0x48, 0xb0, 0x47, 0xec, 0xea,
1220xb4, 0xbf, 0xa5, 0x4d, 0x9b, 0x9f, 0x02, 0x93, 0xc4, 0xe3, 0xe4, 0xe8, 0x42, 0x2d, 0x68,
1230x81, 0x15, 0x0a, 0xeb, 0x84, 0x5b, 0xd6, 0xa8, 0x74, 0xfb, 0x7d, 0x1d, 0xcb, 0x2c, 0xda,
1240x46, 0x2a, 0x76, 0x62, 0xce, 0xbc, 0x5c, 0x9e, 0x8b, 0xe7, 0xcf, 0xbe, 0x78, 0xf5, 0x7c,
1250xeb, 0xb3, 0x3a, 0x9c, 0xaa, 0x6f, 0xcc, 0x72, 0xd1, 0x59, 0xf2, 0x11, 0x23, 0xd6, 0x3f,
1260x48, 0xd1, 0xb7, 0xce, 0xb0, 0xbf, 0xcb, 0xea, 0x80, 0xde, 0x57, 0xd4, 0x5e, 0x97, 0x2f,
1270x75, 0xd1, 0x50, 0x8e, 0x80, 0x2c, 0x66, 0x79, 0xbf, 0x72, 0x4b, 0xbd, 0x8a, 0x81, 0x6c,
1280xd3, 0xe1, 0x01, 0xdc, 0xd2, 0x15, 0x26, 0xc5, 0x36, 0xda, 0x2c, 0x1a, 0xc0, 0x27, 0x94,
1290xed, 0xb7, 0x9b, 0x85, 0x0b, 0x5e, 0x80, 0x97, 0xc5, 0xec, 0x4f, 0xec, 0x88, 0x5d, 0x50,
1300x07, 0x35, 0x47, 0xdc, 0x0b, 0x3b, 0x3d, 0xdd, 0x60, 0xaf, 0xa8, 0x5d, 0x81, 0x38, 0x24,
1310x25, 0x5d, 0x5c, 0x15, 0xd1, 0xde, 0xb3, 0xab, 0xec, 0x05, 0x69, 0xef, 0x83, 0xed, 0x57,
1320x54, 0xb8, 0x64, 0x64, 0x11, 0x16, 0x32, 0x69, 0xda, 0x9f, 0x2d, 0x7f, 0x36, 0xbb, 0x44,
1330x5a, 0x34, 0xe8, 0x7f, 0xbf, 0x03, 0xeb, 0x00, 0x7f, 0x59, 0x68, 0x22, 0x79, 0xcf, 0x73,
1340x6c, 0x2c, 0x29, 0xa7, 0xa1, 0x5f, 0x38, 0xa1, 0x1d, 0xf0, 0x20, 0x53, 0xe0, 0x1a, 0x63,
1350x14, 0x58, 0x71, 0x10, 0xaa, 0x08, 0x0c, 0x3e, 0x16, 0x1a, 0x60, 0x22, 0x82, 0x7f, 0xba,
1360xa4, 0x43, 0xa0, 0xd0, 0xac, 0x1b, 0xd5, 0x6b, 0x64, 0xb5, 0x14, 0x93, 0x31, 0x9e, 0x53,
1370x50, 0xd0, 0x57, 0x66, 0xee, 0x5a, 0x4f, 0xfb, 0x03, 0x2a, 0x69, 0x58, 0x76, 0xf1, 0x83,
1380xf7, 0x4e, 0xba, 0x8c, 0x42, 0x06, 0x60, 0x5d, 0x6d, 0xce, 0x60, 0x88, 0xae, 0xa4, 0xc3,
1390xf1, 0x03, 0xa5, 0x4b, 0x98, 0xa1, 0xff, 0x67, 0xe1, 0xac, 0xa2, 0xb8, 0x62, 0xd7, 0x6f,
1400xa0, 0x31, 0xb4, 0xd2, 0x77, 0xaf, 0x21, 0x10, 0x06, 0xc6, 0x9a, 0xff, 0x1d, 0x09, 0x17,
1410x0e, 0x5f, 0xf1, 0xaa, 0x54, 0x34, 0x4b, 0x45, 0x8a, 0x87, 0x63, 0xa6, 0xdc, 0xf9, 0x24,
1420x30, 0x67, 0xc6, 0xb2, 0xd6, 0x61, 0x33, 0x69, 0xee, 0x50, 0x61, 0x57, 0x28, 0xe7, 0x7e,
1430xee, 0xec, 0x3a, 0x5a, 0x73, 0x4e, 0xa8, 0x8d, 0xe4, 0x18, 0xea, 0xec, 0x41, 0x64, 0xc8,
1440xe2, 0xe8, 0x66, 0xb6, 0x2d, 0xb6, 0xfb, 0x6a, 0x6c, 0x16, 0xb3, 0xdd, 0x46, 0x43, 0xb9,
1450x73, 0x00, 0x6a, 0x71, 0xed, 0x4e, 0x9d, 0x25, 0x1a, 0xc3, 0x3c, 0x4a, 0x95, 0x15, 0x99,
1460x35, 0x81, 0x14, 0x02, 0xd6, 0x98, 0x9b, 0xec, 0xd8, 0x23, 0x3b, 0x84, 0x29, 0xaf, 0x0c,
1470x99, 0x83, 0xa6, 0x9a, 0x34, 0x4f, 0xfa, 0xe8, 0xd0, 0x3c, 0x4b, 0xd0, 0xfb, 0xb6, 0x68,
1480xb8, 0x9e, 0x8f, 0xcd, 0xf7, 0x60, 0x2d, 0x7a, 0x22, 0xe5, 0x7d, 0xab, 0x65, 0x1b, 0x95,
1490xa7, 0xa8, 0x7f, 0xb6, 0x77, 0x47, 0x7b, 0x5f, 0x8b, 0x12, 0x72, 0xd0, 0xd4, 0x91, 0xef,
1500xde, 0x19, 0x50, 0x3c, 0xa7, 0x8b, 0xc4, 0xa9, 0xb3, 0x23, 0xcb, 0x76, 0xe6, 0x81, 0xf0,
1510xc1, 0x04, 0x8f, 0xa3, 0xb8, 0x54, 0x5b, 0x97, 0xac, 0x19, 0xff, 0x3f, 0x55, 0x27, 0x2f,
1520xe0, 0x1d, 0x42, 0x9b, 0x57, 0xfc, 0x4b, 0x4e, 0x0f, 0xce, 0x98, 0xa9, 0x43, 0x57, 0x03,
1530xbd, 0xe7, 0xc8, 0x94, 0xdf, 0x6e, 0x36, 0x73, 0x32, 0xb4, 0xef, 0x2e, 0x85, 0x7a, 0x6e,
1540xfc, 0x6c, 0x18, 0x82, 0x75, 0x35, 0x90, 0x07, 0xf3, 0xe4, 0x9f, 0x3e, 0xdc, 0x68, 0xf3,
1550xb5, 0xf3, 0x19, 0x80, 0x92, 0x06, 0x99, 0xa2, 0xe8, 0x6f, 0xff, 0x2e, 0x7f, 0xae, 0x42,
1560xa4, 0x5f, 0xfb, 0xd4, 0x0e, 0x81, 0x2b, 0xc3, 0x04, 0xff, 0x2b, 0xb3, 0x74, 0x4e, 0x36,
1570x5b, 0x9c, 0x15, 0x00, 0xc6, 0x47, 0x2b, 0xe8, 0x8b, 0x3d, 0xf1, 0x9c, 0x03, 0x9a, 0x58,
1580x7f, 0x9b, 0x9c, 0xbf, 0x85, 0x49, 0x79, 0x35, 0x2e, 0x56, 0x7b, 0x41, 0x14, 0x39, 0x47,
1590x83, 0x26, 0xaa, 0x07, 0x89, 0x98, 0x11, 0x1b, 0x86, 0xe7, 0x73, 0x7a, 0xd8, 0x7d, 0x78,
1600x61, 0x53, 0xe9, 0x79, 0xf5, 0x36, 0x8d, 0x44, 0x92, 0x84, 0xf9, 0x13, 0x50, 0x58, 0x3b,
1610xa4, 0x6a, 0x36, 0x65, 0x49, 0x8e, 0x3c, 0x0e, 0xf1, 0x6f, 0xd2, 0x84, 0xc4, 0x7e, 0x8e,
1620x3f, 0x39, 0xae, 0x7c, 0x84, 0xf1, 0x63, 0x37, 0x8e, 0x3c, 0xcc, 0x3e, 0x44, 0x81, 0x45,
1630xf1, 0x4b, 0xb9, 0xed, 0x6b, 0x36, 0x5d, 0xbb, 0x20, 0x60, 0x1a, 0x0f, 0xa3, 0xaa, 0x55,
1640x77, 0x3a, 0xa9, 0xae, 0x37, 0x4d, 0xba, 0xb8, 0x86, 0x6b, 0xbc, 0x08, 0x50, 0xf6, 0xcc,
1650xa4, 0xbd, 0x1d, 0x40, 0x72, 0xa5, 0x86, 0xfa, 0xe2, 0x10, 0xae, 0x3d, 0x58, 0x4b, 0x97,
1660xf3, 0x43, 0x74, 0xa9, 0x9e, 0xeb, 0x21, 0xb7, 0x01, 0xa4, 0x86, 0x93, 0x97, 0xee, 0x2f,
1670x4f, 0x3b, 0x86, 0xa1, 0x41, 0x6f, 0x41, 0x26, 0x90, 0x78, 0x5c, 0x7f, 0x30, 0x38, 0x4b,
1680x3f, 0xaa, 0xec, 0xed, 0x5c, 0x6f, 0x0e, 0xad, 0x43, 0x87, 0xfd, 0x93, 0x35, 0xe6, 0x01,
1690xef, 0x41, 0x26, 0x90, 0x99, 0x9e, 0xfb, 0x19, 0x5b, 0xad, 0xd2, 0x91, 0x8a, 0xe0, 0x46,
1700xaf, 0x65, 0xfa, 0x4f, 0x84, 0xc1, 0xa1, 0x2d, 0xcf, 0x45, 0x8b, 0xd3, 0x85, 0x50, 0x55,
1710x7c, 0xf9, 0x67, 0x88, 0xd4, 0x4e, 0xe9, 0xd7, 0x6b, 0x61, 0x54, 0xa1, 0xa4, 0xa6, 0xa2,
1720xc2, 0xbf, 0x30, 0x9c, 0x40, 0x9f, 0x5f, 0xd7, 0x69, 0x2b, 0x24, 0x82, 0x5e, 0xd9, 0xd6,
1730xa7, 0x12, 0x54, 0x1a, 0xf7, 0x55, 0x9f, 0x76, 0x50, 0xa9, 0x95, 0x84, 0xe6, 0x6b, 0x6d,
1740xb5, 0x96, 0x54, 0xd6, 0xcd, 0xb3, 0xa1, 0x9b, 0x46, 0xa7, 0x94, 0x4d, 0xc4, 0x94, 0xb4,
1750x98, 0xe3, 0xe1, 0xe2, 0x34, 0xd5, 0x33, 0x16, 0x07, 0x54, 0xcd, 0xb7, 0x77, 0x53, 0xdb,
1760x4f, 0x4d, 0x46, 0x9d, 0xe9, 0xd4, 0x9c, 0x8a, 0x36, 0xb6, 0xb8, 0x38, 0x26, 0x6c, 0x0e,
1770xff, 0x9c, 0x1b, 0x43, 0x8b, 0x80, 0xcc, 0xb9, 0x3d, 0xda, 0xc7, 0xf1, 0x8a, 0xf2, 0x6d,
1780xb8, 0xd7, 0x74, 0x2f, 0x7e, 0x1e, 0xb7, 0xd3, 0x4a, 0xb4, 0xac, 0xfc, 0x79, 0x48, 0x6c,
1790xbc, 0x96, 0xb6, 0x94, 0x46, 0x57, 0x2d, 0xb0, 0xa3, 0xfc, 0x1e, 0xb9, 0x52, 0x60, 0x85,
1800x2d, 0x41, 0xd0, 0x43, 0x01, 0x1e, 0x1c, 0xd5, 0x7d, 0xfc, 0xf3, 0x96, 0x0d, 0xc7, 0xcb,
1810x2a, 0x29, 0x9a, 0x93, 0xdd, 0x88, 0x2d, 0x37, 0x5d, 0xaa, 0xfb, 0x49, 0x68, 0xa0, 0x9c,
1820x50, 0x86, 0x7f, 0x68, 0x56, 0x57, 0xf9, 0x79, 0x18, 0x39, 0xd4, 0xe0, 0x01, 0x84, 0x33,
1830x61, 0xca, 0xa5, 0xd2, 0xd6, 0xe4, 0xc9, 0x8a, 0x4a, 0x23, 0x44, 0x4e, 0xbc, 0xf0, 0xdc,
1840x24, 0xa1, 0xa0, 0xc4, 0xe2, 0x07, 0x3c, 0x10, 0xc4, 0xb5, 0x25, 0x4b, 0x65, 0x63, 0xf4,
1850x80, 0xe7, 0xcf, 0x61, 0xb1, 0x71, 0x82, 0x21, 0x87, 0x2c, 0xf5, 0x91, 0x00, 0x32, 0x0c,
1860xec, 0xa9, 0xb5, 0x9a, 0x74, 0x85, 0xe3, 0x36, 0x8f, 0x76, 0x4f, 0x9c, 0x6d, 0xce, 0xbc,
1870xad, 0x0a, 0x4b, 0xed, 0x76, 0x04, 0xcb, 0xc3, 0xb9, 0x33, 0x9e, 0x01, 0x93, 0x96, 0x69,
1880x7d, 0xc5, 0xa2, 0x45, 0x79, 0x9b, 0x04, 0x5c, 0x84, 0x09, 0xed, 0x88, 0x43, 0xc7, 0xab,
1890x93, 0x14, 0x26, 0xa1, 0x40, 0xb5, 0xce, 0x4e, 0xbf, 0x2a, 0x42, 0x85, 0x3e, 0x2c, 0x3b,
1900x54, 0xe8, 0x12, 0x1f, 0x0e, 0x97, 0x59, 0xb2, 0x27, 0x89, 0xfa, 0xf2, 0xdf, 0x8e, 0x68,
1910x59, 0xdc, 0x06, 0xbc, 0xb6, 0x85, 0x0d, 0x06, 0x22, 0xec, 0xb1, 0xcb, 0xe5, 0x04, 0xe6,
1920x3d, 0xb3, 0xb0, 0x41, 0x73, 0x08, 0x3f, 0x3c, 0x58, 0x86, 0x63, 0xeb, 0x50, 0xee, 0x1d,
1930x2c, 0x37, 0x74, 0xa9, 0xd3, 0x18, 0xa3, 0x47, 0x6e, 0x93, 0x54, 0xad, 0x0a, 0x5d, 0xb8,
1940x2a, 0x55, 0x5d, 0x78, 0xf6, 0xee, 0xbe, 0x8e, 0x3c, 0x76, 0x69, 0xb9, 0x40, 0xc2, 0x34,
1950xec, 0x2a, 0xb9, 0xed, 0x7e, 0x20, 0xe4, 0x8d, 0x00, 0x38, 0xc7, 0xe6, 0x8f, 0x44, 0xa8,
1960x86, 0xce, 0xeb, 0x2a, 0xe9, 0x90, 0xf1, 0x4c, 0xdf, 0x32, 0xfb, 0x73, 0x1b, 0x6d, 0x92,
1970x1e, 0x95, 0xfe, 0xb4, 0xdb, 0x65, 0xdf, 0x4d, 0x23, 0x54, 0x89, 0x48, 0xbf, 0x4a, 0x2e,
1980x70, 0xd6, 0xd7, 0x62, 0xb4, 0x33, 0x29, 0xb1, 0x3a, 0x33, 0x4c, 0x23, 0x6d, 0xa6, 0x76,
1990xa5, 0x21, 0x63, 0x48, 0xe6, 0x90, 0x5d, 0xed, 0x90, 0x95, 0x0b, 0x7a, 0x84, 0xbe, 0xb8,
2000x0d, 0x5e, 0x63, 0x0c, 0x62, 0x26, 0x4c, 0x14, 0x5a, 0xb3, 0xac, 0x23, 0xa4, 0x74, 0xa7,
2010x6f, 0x33, 0x30, 0x05, 0x60, 0x01, 0x42, 0xa0, 0x28, 0xb7, 0xee, 0x19, 0x38, 0xf1, 0x64,
2020x80, 0x82, 0x43, 0xe1, 0x41, 0x27, 0x1f, 0x1f, 0x90, 0x54, 0x7a, 0xd5, 0x23, 0x2e, 0xd1,
2030x3d, 0xcb, 0x28, 0xba, 0x58, 0x7f, 0xdc, 0x7c, 0x91, 0x24, 0xe9, 0x28, 0x51, 0x83, 0x6e,
2040xc5, 0x56, 0x21, 0x42, 0xed, 0xa0, 0x56, 0x22, 0xa1, 0x40, 0x80, 0x6b, 0xa8, 0xf7, 0x94,
2050xca, 0x13, 0x6b, 0x0c, 0x39, 0xd9, 0xfd, 0xe9, 0xf3, 0x6f, 0xa6, 0x9e, 0xfc, 0x70, 0x8a,
2060xb3, 0xbc, 0x59, 0x3c, 0x1e, 0x1d, 0x6c, 0xf9, 0x7c, 0xaf, 0xf9, 0x88, 0x71, 0x95, 0xeb,
2070x57, 0x00, 0xbd, 0x9f, 0x8c, 0x4f, 0xe1, 0x24, 0x83, 0xc5, 0x22, 0xea, 0xfd, 0xd3, 0x0c,
2080xe2, 0x17, 0x18, 0x7c, 0x6a, 0x4c, 0xde, 0x77, 0xb4, 0x53, 0x9b, 0x4c, 0x81, 0xcd, 0x23,
2090x60, 0xaa, 0x0e, 0x25, 0x73, 0x9c, 0x02, 0x79, 0x32, 0x30, 0xdf, 0x74, 0xdf, 0x75, 0x19,
2100xf4, 0xa5, 0x14, 0x5c, 0xf7, 0x7a, 0xa8, 0xa5, 0x91, 0x84, 0x7c, 0x60, 0x03, 0x06, 0x3b,
2110xcd, 0x50, 0xb6, 0x27, 0x9c, 0xfe, 0xb1, 0xdd, 0xcc, 0xd3, 0xb0, 0x59, 0x24, 0xb2, 0xca,
2120xe2, 0x1c, 0x81, 0x22, 0x9d, 0x07, 0x8f, 0x8e, 0xb9, 0xbe, 0x4e, 0xfa, 0xfc, 0x39, 0x65,
2130xba, 0xbf, 0x9d, 0x12, 0x37, 0x5e, 0x97, 0x7e, 0xf3, 0x89, 0xf5, 0x5d, 0xf5, 0xe3, 0x09,
2140x8c, 0x62, 0xb5, 0x20, 0x9d, 0x0c, 0x53, 0x8a, 0x68, 0x1b, 0xd2, 0x8f, 0x75, 0x17, 0x5d,
2150xd4, 0xe5, 0xda, 0x75, 0x62, 0x19, 0x14, 0x6a, 0x26, 0x2d, 0xeb, 0xf8, 0xaf, 0x37, 0xf0,
2160x6c, 0xa4, 0x55, 0xb1, 0xbc, 0xe2, 0x33, 0xc0, 0x9a, 0xca, 0xb0, 0x11, 0x49, 0x4f, 0x68,
2170x9b, 0x3b, 0x6b, 0x3c, 0xcc, 0x13, 0xf6, 0xc7, 0x85, 0x61, 0x68, 0x42, 0xae, 0xbb, 0xdd,
2180xcd, 0x45, 0x16, 0x29, 0x1d, 0xea, 0xdb, 0xc8, 0x03, 0x94, 0x3c, 0xee, 0x4f, 0x82, 0x11,
2190xc3, 0xec, 0x28, 0xbd, 0x97, 0x05, 0x99, 0xde, 0xd7, 0xbb, 0x5e, 0x22, 0x1f, 0xd4, 0xeb,
2200x64, 0xd9, 0x92, 0xd9, 0x85, 0xb7, 0x6a, 0x05, 0x6a, 0xe4, 0x24, 0x41, 0xf1, 0xcd, 0xf0,
2210xd8, 0x3f, 0xf8, 0x9e, 0x0e, 0xcd, 0x0b, 0x7a, 0x70, 0x6b, 0x5a, 0x75, 0x0a, 0x6a, 0x33,
2220x88, 0xec, 0x17, 0x75, 0x08, 0x70, 0x10, 0x2f, 0x24, 0xcf, 0xc4, 0xe9, 0x42, 0x00, 0x61,
2230x94, 0xca, 0x1f, 0x3a, 0x76, 0x06, 0xfa, 0xd2, 0x48, 0x81, 0xf0, 0x77, 0x60, 0x03, 0x45,
2240xd9, 0x61, 0xf4, 0xa4, 0x6f, 0x3d, 0xd9, 0x30, 0xc3, 0x04, 0x6b, 0x54, 0x2a, 0xb7, 0xec,
2250x3b, 0xf4, 0x4b, 0xf5, 0x68, 0x52, 0x26, 0xce, 0xff, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xa5,
2260xa9, 0xb1, 0xe0, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0xf9, 0x51, 0x20, 0xa3, 0xa5, 0xa9, 0xb1,
2270xc1, 0x00, 0x82, 0x86, 0x8e, 0x7f, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xc4, 0xeb, 0x54, 0x0b,
2280x75, 0x68, 0x52, 0x07, 0x8c, 0x9a, 0x97, 0x8d, 0x79, 0x70, 0x62, 0x46, 0xef, 0x5c, 0x1b,
2290x95, 0x89, 0x71, 0x41, 0xe1, 0x21, 0xa1, 0xa1, 0xa1, 0xc0, 0x02, 0x67, 0x4c, 0x1a, 0xb6,
2300xcf, 0xfd, 0x78, 0x53, 0x24, 0xab, 0xb5, 0xc9, 0xf1, 0x60, 0x23, 0xa5, 0xc8, 0x12, 0x87,
2310x6d, 0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x6d, 0x58, 0x32, 0xc7, 0x0c, 0x9a, 0x97, 0xac,
2320xda, 0x36, 0xee, 0x5e, 0x3e, 0xdf, 0x1d, 0xb8, 0xf2, 0x66, 0x2f, 0xbd, 0xf8, 0x72, 0x47,
2330xed, 0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x8c, 0x7b, 0x55, 0x09, 0x90, 0xa2, 0xc6, 0xef,
2340x3d, 0xf8, 0x53, 0x24, 0xab, 0xd4, 0x2a, 0xb7, 0xec, 0x5a, 0x36, 0xee, 0x5e, 0x3e, 0xdf,
2350x3c, 0xfa, 0x76, 0x4f, 0xfd, 0x59, 0x30, 0xe2, 0x46, 0xef, 0x3d, 0xf8, 0x53, 0x05, 0x69,
2360x31, 0xc1, 0x00, 0x82, 0x86, 0x8e, 0x7f, 0x5d, 0x19, 0xb0, 0xe2, 0x27, 0xcc, 0xfb, 0x74,
2370x4b, 0x14, 0x8b, 0x94, 0x8b, 0x75, 0x68, 0x33, 0xc5, 0x08, 0x92, 0x87, 0x8c, 0x9a, 0xb6,
2380xcf, 0x1c, 0xba, 0xd7, 0x0d, 0x98, 0xb2, 0xe6, 0x2f, 0xdc, 0x1b, 0x95, 0x89, 0x71, 0x60,
2390x23, 0xc4, 0x0a, 0x96, 0x8f, 0x9c, 0xba, 0xf6, 0x6e, 0x3f, 0xfc, 0x5b, 0x15, 0xa8, 0xd2,
2400x26, 0xaf, 0xbd, 0xf8, 0x72, 0x66, 0x2f, 0xdc, 0x1b, 0xb4, 0xcb, 0x14, 0x8b, 0x94, 0xaa,
2410xb7, 0xcd, 0xf9, 0x51, 0x01, 0x80, 0x82, 0x86, 0x6f, 0x3d, 0xd9, 0x30, 0xe2, 0x27, 0xcc,
2420xfb, 0x74, 0x4b, 0x14, 0xaa, 0xb7, 0xcd, 0xf9, 0x70, 0x43, 0x04, 0x6b, 0x35, 0xc9, 0xf1,
2430x60, 0x23, 0xa5, 0xc8, 0xf3, 0x45, 0x08, 0x92, 0x87, 0x6d, 0x58, 0x32, 0xe6, 0x2f, 0xbd,
2440xf8, 0x72, 0x66, 0x4e, 0x1e, 0xbe, 0xfe, 0x7e, 0x7e, 0x7e, 0x5f, 0x1d, 0x99, 0x91, 0xa0,
2450xa3, 0xc4, 0x0a, 0x77, 0x4d, 0x18, 0x93, 0xa4, 0xab, 0xd4, 0x0b, 0x75, 0x49, 0x10, 0xa2,
2460xc6, 0xef, 0x3d, 0xf8, 0x53, 0x24, 0xab, 0xb5, 0xe8, 0x33, 0xe4, 0x4a, 0x16, 0xae, 0xde,
2470x1f, 0xbc, 0xdb, 0x15, 0xa8, 0xb3, 0xc5, 0x08, 0x73, 0x45, 0xe9, 0x31, 0xc1, 0xe1, 0x21,
2480xa1, 0xa1, 0xa1, 0xc0, 0x02, 0x86, 0x6f, 0x5c, 0x3a, 0xd7, 0x0d, 0x98, 0x93, 0xa4, 0xca,
2490x16, 0xae, 0xde, 0x1f, 0x9d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x3d, 0xf8, 0x72, 0x47, 0x0c,
2500x9a, 0xb6, 0xcf, 0xfd, 0x59, 0x11, 0xa0, 0xa3, 0xa5, 0xc8, 0xf3, 0x45, 0x08, 0x92, 0x87,
2510x6d, 0x39, 0xf0, 0x43, 0x04, 0x8a, 0x96, 0xae, 0xde, 0x3e, 0xdf, 0x1d, 0x99, 0x91, 0xa0,
2520xc2, 0x06, 0x6f, 0x3d, 0xf8, 0x72, 0x47, 0x0c, 0x9a, 0x97, 0x8d, 0x98, 0x93, 0x85, 0x88,
2530x73, 0x45, 0xe9, 0x31, 0xe0, 0x23, 0xa5, 0xa9, 0xd0, 0x03, 0x84, 0x8a, 0x96, 0xae, 0xde,
2540x1f, 0xbc, 0xdb, 0x15, 0xa8, 0xd2, 0x26, 0xce, 0xff, 0x5d, 0x19, 0x91, 0x81, 0x80, 0x82,
2550x67, 0x2d, 0xd8, 0x13, 0xa4, 0xab, 0xd4, 0x0b, 0x94, 0xaa, 0xb7, 0xcd, 0xf9, 0x51, 0x20,
2560xa3, 0xa5, 0xc8, 0xf3, 0x45, 0xe9, 0x50, 0x22, 0xc6, 0xef, 0x5c, 0x3a, 0xd7, 0x0d, 0x98,
2570x93, 0x85, 0x88, 0x73, 0x64, 0x4a, 0xf7, 0x4d, 0xf9, 0x51, 0x20, 0xa3, 0xc4, 0x0a, 0x96,
2580xae, 0xde, 0x3e, 0xfe, 0x7e, 0x7e, 0x7e, 0x5f, 0x3c, 0xfa, 0x76, 0x4f, 0xfd, 0x78, 0x72,
2590x66, 0x2f, 0xbd, 0xd9, 0x30, 0xc3, 0xe5, 0x48, 0x12, 0x87, 0x8c, 0x7b, 0x55, 0x28, 0xd2,
2600x07, 0x8c, 0x9a, 0x97, 0xac, 0xda, 0x17, 0x8d, 0x79, 0x51, 0x20, 0xa3, 0xc4, 0xeb, 0x54,
2610x0b, 0x94, 0x8b, 0x94, 0xaa, 0xd6, 0x2e, 0xbf, 0xfc, 0x5b, 0x15, 0xa8, 0xd2, 0x26, 0xaf,
2620xdc, 0x1b, 0xb4, 0xea, 0x37, 0xec, 0x3b, 0xf4, 0x6a, 0x37, 0xcd, 0x18, 0x93, 0x85, 0x69,
2630x31, 0xc1, 0xe1, 0x40, 0xe3, 0x25, 0xc8, 0x12, 0x87, 0x8c, 0x9a, 0xb6, 0xcf, 0xfd, 0x59,
2640x11, 0xa0, 0xc2, 0x06, 0x8e, 0x7f, 0x5d, 0x38, 0xf2, 0x47, 0x0c, 0x7b, 0x74, 0x6a, 0x37,
2650xec, 0x5a, 0x36, 0xee, 0x3f, 0xfc, 0x7a, 0x76, 0x4f, 0x1c, 0x9b, 0x95, 0x89, 0x71, 0x41,
2660x00, 0x63, 0x44, 0xeb, 0x54, 0x2a, 0xd6, 0x0f, 0x9c, 0xba, 0xd7, 0x0d, 0x98, 0x93, 0x85,
2670x69, 0x31, 0xc1, 0x00, 0x82, 0x86, 0x8e, 0x9e, 0xbe, 0xdf, 0x3c, 0xfa, 0x57, 0x2c, 0xda,
2680x36, 0xee, 0x3f, 0xfc, 0x5b, 0x15, 0x89, 0x71, 0x41, 0x00, 0x82, 0x86, 0x8e, 0x7f, 0x5d,
2690x38, 0xf2, 0x47, 0xed, 0x58, 0x13, 0xa4, 0xca, 0xf7, 0x4d, 0xf9, 0x51, 0x01, 0x80, 0x63,
2700x44, 0xeb, 0x54, 0x2a, 0xd6, 0x2e, 0xbf, 0xdd, 0x19, 0x91, 0xa0, 0xa3, 0xa5, 0xa9, 0xb1,
2710xe0, 0x42, 0x06, 0x8e, 0x7f, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xc4, 0x0a, 0x96, 0x8f, 0x7d,
2720x78, 0x72, 0x47, 0x0c, 0x7b, 0x74, 0x6a, 0x56, 0x2e, 0xde, 0x1f, 0xbc, 0xfa, 0x57, 0x0d,
2730x79, 0x51, 0x01, 0x61, 0x21, 0xa1, 0xc0, 0xe3, 0x25, 0xa9, 0xb1, 0xc1, 0xe1, 0x40, 0x02,
2740x67, 0x4c, 0x1a, 0x97, 0x8d, 0x98, 0x93, 0xa4, 0xab, 0xd4, 0x2a, 0xd6, 0x0f, 0x9c, 0x9b,
2750xb4, 0xcb, 0x14, 0xaa, 0xb7, 0xcd, 0xf9, 0x51, 0x20, 0xa3, 0xc4, 0xeb, 0x35, 0xc9, 0xf1,
2760x60, 0x42, 0x06, 0x8e, 0x7f, 0x7c, 0x7a, 0x76, 0x6e, 0x3f, 0xfc, 0x7a, 0x76, 0x6e, 0x5e,
2770x3e, 0xfe, 0x7e, 0x5f, 0x3c, 0xdb, 0x15, 0x89, 0x71, 0x41, 0xe1, 0x21, 0xc0, 0xe3, 0x44,
2780xeb, 0x54, 0x2a, 0xb7, 0xcd, 0xf9, 0x70, 0x62, 0x27, 0xad, 0xd8, 0x32, 0xc7, 0x0c, 0x7b,
2790x74, 0x4b, 0x14, 0xaa, 0xb7, 0xec, 0x3b, 0xd5, 0x28, 0xd2, 0x07, 0x6d, 0x39, 0xd1, 0x20,
2800xc2, 0xe7, 0x4c, 0x1a, 0x97, 0x8d, 0x98, 0xb2, 0xc7, 0x0c, 0x59, 0x28, 0xf3, 0x9b };
diff --git a/keyboards/oddball/rules.mk b/keyboards/oddball/rules.mk
index f1e7d4894..d675ebcf2 100644
--- a/keyboards/oddball/rules.mk
+++ b/keyboards/oddball/rules.mk
@@ -21,7 +21,3 @@ SPLIT_KEYBOARD = yes
21POINTING_DEVICE_ENABLE = yes 21POINTING_DEVICE_ENABLE = yes
22 22
23DEFAULT_FOLDER = oddball/v1 23DEFAULT_FOLDER = oddball/v1
24
25SRC += spi_master.c
26SRC += drivers/sensors/adns9800.c
27SRC += pmw/pmw.c
diff --git a/keyboards/ploopyco/mouse/mouse.c b/keyboards/ploopyco/mouse/mouse.c
index 0bf96a20f..1b00ef3b7 100644
--- a/keyboards/ploopyco/mouse/mouse.c
+++ b/keyboards/ploopyco/mouse/mouse.c
@@ -31,7 +31,8 @@
31# define OPT_SCALE 1 // Multiplier for wheel 31# define OPT_SCALE 1 // Multiplier for wheel
32#endif 32#endif
33#ifndef PLOOPY_DPI_OPTIONS 33#ifndef PLOOPY_DPI_OPTIONS
34# define PLOOPY_DPI_OPTIONS { 1200, 1600, 2400 } 34# define PLOOPY_DPI_OPTIONS \
35 { 1200, 1600, 2400 }
35# ifndef PLOOPY_DPI_DEFAULT 36# ifndef PLOOPY_DPI_DEFAULT
36# define PLOOPY_DPI_DEFAULT 1 37# define PLOOPY_DPI_DEFAULT 1
37# endif 38# endif
@@ -40,10 +41,10 @@
40# define PLOOPY_DPI_DEFAULT 0 41# define PLOOPY_DPI_DEFAULT 0
41#endif 42#endif
42#ifndef PLOOPY_DRAGSCROLL_DPI 43#ifndef PLOOPY_DRAGSCROLL_DPI
43# define PLOOPY_DRAGSCROLL_DPI 100 // Fixed-DPI Drag Scroll 44# define PLOOPY_DRAGSCROLL_DPI 100 // Fixed-DPI Drag Scroll
44#endif 45#endif
45#ifndef PLOOPY_DRAGSCROLL_MULTIPLIER 46#ifndef PLOOPY_DRAGSCROLL_MULTIPLIER
46# define PLOOPY_DRAGSCROLL_MULTIPLIER 0.75 // Variable-DPI Drag Scroll 47# define PLOOPY_DRAGSCROLL_MULTIPLIER 0.75 // Variable-DPI Drag Scroll
47#endif 48#endif
48 49
49keyboard_config_t keyboard_config; 50keyboard_config_t keyboard_config;
@@ -65,13 +66,7 @@ uint8_t OptLowPin = OPT_ENC1;
65bool debug_encoder = false; 66bool debug_encoder = false;
66bool is_drag_scroll = false; 67bool is_drag_scroll = false;
67 68
68__attribute__((weak)) void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v) { 69void process_wheel(report_mouse_t* mouse_report) {
69 mouse_report->h = h;
70 mouse_report->v = v;
71}
72
73__attribute__((weak)) void process_wheel(report_mouse_t* mouse_report) {
74 // TODO: Replace this with interrupt driven code, polling is S L O W
75 // Lovingly ripped from the Ploopy Source 70 // Lovingly ripped from the Ploopy Source
76 71
77 // If the mouse wheel was just released, do not scroll. 72 // If the mouse wheel was just released, do not scroll.
@@ -99,56 +94,25 @@ __attribute__((weak)) void process_wheel(report_mouse_t* mouse_report) {
99 int dir = opt_encoder_handler(p1, p2); 94 int dir = opt_encoder_handler(p1, p2);
100 95
101 if (dir == 0) return; 96 if (dir == 0) return;
102 process_wheel_user(mouse_report, mouse_report->h, (int)(mouse_report->v + (dir * OPT_SCALE))); 97 mouse_report->v = (int8_t)(dir * OPT_SCALE);
103}
104
105__attribute__((weak)) void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y) {
106 mouse_report->x = x;
107 mouse_report->y = y;
108} 98}
109 99
110__attribute__((weak)) void process_mouse(report_mouse_t* mouse_report) { 100__attribute__((weak)) report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
111 report_pmw_t data = pmw_read_burst(); 101 process_wheel(&mouse_report);
112 if (data.isOnSurface && data.isMotion) {
113 // Reset timer if stopped moving
114 if (!data.isMotion) {
115 if (MotionStart != 0) MotionStart = 0;
116 return;
117 }
118
119 // Set timer if new motion
120 if ((MotionStart == 0) && data.isMotion) {
121 if (debug_mouse) dprintf("Starting motion.\n");
122 MotionStart = timer_read();
123 }
124 102
125 if (debug_mouse) { 103 if (is_drag_scroll) {
126 dprintf("Delt] d: %d t: %u\n", abs(data.dx) + abs(data.dy), MotionStart); 104 mouse_report.h = mouse_report.x;
127 } 105#ifdef PLOOPY_DRAGSCROLL_INVERT
128 if (debug_mouse) { 106 // Invert vertical scroll direction
129 dprintf("Pre ] X: %d, Y: %d\n", data.dx, data.dy); 107 mouse_report.v = -mouse_report.y;
130 }
131#if defined(PROFILE_LINEAR)
132 float scale = float(timer_elaspsed(MotionStart)) / 1000.0;
133 data.dx *= scale;
134 data.dy *= scale;
135#elif defined(PROFILE_INVERSE)
136 // TODO
137#else 108#else
138 // no post processing 109 mouse_report.v = mouse_report.y;
139#endif 110#endif
140 // apply multiplier 111 mouse_report.x = 0;
141 // data.dx *= mouse_multiplier; 112 mouse_report.y = 0;
142 // data.dy *= mouse_multiplier;
143
144 // Wrap to HID size
145 data.dx = constrain(data.dx, -127, 127);
146 data.dy = constrain(data.dy, -127, 127);
147 if (debug_mouse) dprintf("Cons] X: %d, Y: %d\n", data.dx, data.dy);
148 // dprintf("Elapsed:%u, X: %f Y: %\n", i, pgm_read_byte(firmware_data+i));
149
150 process_mouse_user(mouse_report, data.dx, data.dy);
151 } 113 }
114
115 return pointing_device_task_user(mouse_report);
152} 116}
153 117
154bool process_record_kb(uint16_t keycode, keyrecord_t* record) { 118bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
@@ -169,7 +133,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
169 if (keycode == DPI_CONFIG && record->event.pressed) { 133 if (keycode == DPI_CONFIG && record->event.pressed) {
170 keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE; 134 keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE;
171 eeconfig_update_kb(keyboard_config.raw); 135 eeconfig_update_kb(keyboard_config.raw);
172 pmw_set_cpi(dpi_array[keyboard_config.dpi_config]); 136 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
173 } 137 }
174 138
175 if (keycode == DRAG_SCROLL) { 139 if (keycode == DRAG_SCROLL) {
@@ -180,9 +144,9 @@ bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
180 is_drag_scroll ^= 1; 144 is_drag_scroll ^= 1;
181 } 145 }
182#ifdef PLOOPY_DRAGSCROLL_FIXED 146#ifdef PLOOPY_DRAGSCROLL_FIXED
183 pmw_set_cpi(is_drag_scroll ? PLOOPY_DRAGSCROLL_DPI : dpi_array[keyboard_config.dpi_config]); 147 pointing_device_set_cpi(is_drag_scroll ? PLOOPY_DRAGSCROLL_DPI : dpi_array[keyboard_config.dpi_config]);
184#else 148#else
185 pmw_set_cpi(is_drag_scroll ? (dpi_array[keyboard_config.dpi_config] * PLOOPY_DRAGSCROLL_MULTIPLIER) : dpi_array[keyboard_config.dpi_config]); 149 pointing_device_set_cpi(is_drag_scroll ? (dpi_array[keyboard_config.dpi_config] * PLOOPY_DRAGSCROLL_MULTIPLIER) : dpi_array[keyboard_config.dpi_config]);
186#endif 150#endif
187 } 151 }
188 152
@@ -194,11 +158,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
194#ifndef MOUSEKEY_ENABLE 158#ifndef MOUSEKEY_ENABLE
195 if (IS_MOUSEKEY_BUTTON(keycode)) { 159 if (IS_MOUSEKEY_BUTTON(keycode)) {
196 report_mouse_t currentReport = pointing_device_get_report(); 160 report_mouse_t currentReport = pointing_device_get_report();
197 if (record->event.pressed) { 161 currentReport.buttons = pointing_device_handle_buttons(currentReport.buttons, record->event.pressed, keycode - KC_MS_BTN1);
198 currentReport.buttons |= 1 << (keycode - KC_MS_BTN1);
199 } else {
200 currentReport.buttons &= ~(1 << (keycode - KC_MS_BTN1));
201 }
202 pointing_device_set_report(currentReport); 162 pointing_device_set_report(currentReport);
203 pointing_device_send(); 163 pointing_device_send();
204 } 164 }
@@ -240,35 +200,12 @@ void keyboard_pre_init_kb(void) {
240 keyboard_pre_init_user(); 200 keyboard_pre_init_user();
241} 201}
242 202
243void pointing_device_init(void) { 203void pointing_device_init_kb(void) {
244 // initialize ball sensor 204 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
245 pmw_spi_init();
246 // initialize the scroll wheel's optical encoder 205 // initialize the scroll wheel's optical encoder
247 opt_encoder_init(); 206 opt_encoder_init();
248} 207}
249 208
250
251void pointing_device_task(void) {
252 report_mouse_t mouse_report = pointing_device_get_report();
253 process_wheel(&mouse_report);
254 process_mouse(&mouse_report);
255
256 if (is_drag_scroll) {
257 mouse_report.h = mouse_report.x;
258#ifdef PLOOPY_DRAGSCROLL_INVERT
259 // Invert vertical scroll direction
260 mouse_report.v = -mouse_report.y;
261#else
262 mouse_report.v = mouse_report.y;
263#endif
264 mouse_report.x = 0;
265 mouse_report.y = 0;
266 }
267
268 pointing_device_set_report(mouse_report);
269 pointing_device_send();
270}
271
272void eeconfig_init_kb(void) { 209void eeconfig_init_kb(void) {
273 keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT; 210 keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT;
274 eeconfig_update_kb(keyboard_config.raw); 211 eeconfig_update_kb(keyboard_config.raw);
@@ -284,9 +221,3 @@ void matrix_init_kb(void) {
284 } 221 }
285 matrix_init_user(); 222 matrix_init_user();
286} 223}
287
288void keyboard_post_init_kb(void) {
289 pmw_set_cpi(dpi_array[keyboard_config.dpi_config]);
290
291 keyboard_post_init_user();
292}
diff --git a/keyboards/ploopyco/mouse/mouse.h b/keyboards/ploopyco/mouse/mouse.h
index d11aa5e9a..ee5982713 100644
--- a/keyboards/ploopyco/mouse/mouse.h
+++ b/keyboards/ploopyco/mouse/mouse.h
@@ -19,11 +19,8 @@
19#pragma once 19#pragma once
20 20
21#include "quantum.h" 21#include "quantum.h"
22#include "spi_master.h"
23#include "drivers/sensors/pmw3360.h"
24#include "analog.h" 22#include "analog.h"
25#include "opt_encoder.h" 23#include "opt_encoder.h"
26#include "pointing_device.h"
27 24
28// Sensor defs 25// Sensor defs
29#define OPT_ENC1 F0 26#define OPT_ENC1 F0
@@ -31,10 +28,7 @@
31#define OPT_ENC1_MUX 0 28#define OPT_ENC1_MUX 0
32#define OPT_ENC2_MUX 4 29#define OPT_ENC2_MUX 4
33 30
34void process_mouse(report_mouse_t* mouse_report);
35void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y);
36void process_wheel(report_mouse_t* mouse_report); 31void process_wheel(report_mouse_t* mouse_report);
37void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v);
38 32
39#define LAYOUT(BLL, BL, BM, BR, BRR, BF, BB, BDPI) \ 33#define LAYOUT(BLL, BL, BM, BR, BRR, BF, BB, BDPI) \
40 { {BL, BM, BR, BF, BB, BRR, BLL, BDPI}, } 34 { {BL, BM, BR, BF, BB, BRR, BLL, BDPI}, }
diff --git a/keyboards/ploopyco/mouse/rules.mk b/keyboards/ploopyco/mouse/rules.mk
index c02afa00c..45cb38901 100644
--- a/keyboards/ploopyco/mouse/rules.mk
+++ b/keyboards/ploopyco/mouse/rules.mk
@@ -22,7 +22,8 @@ BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
22RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow 22RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
23AUDIO_ENABLE = no # Audio output 23AUDIO_ENABLE = no # Audio output
24POINTING_DEVICE_ENABLE = yes 24POINTING_DEVICE_ENABLE = yes
25POINTING_DEVICE_DRIVER = pmw3360
25MOUSEKEY_ENABLE = yes # Mouse keys 26MOUSEKEY_ENABLE = yes # Mouse keys
26 27
27QUANTUM_LIB_SRC += analog.c spi_master.c 28QUANTUM_LIB_SRC += analog.c
28SRC += drivers/sensors/pmw3360.c opt_encoder.c 29SRC += opt_encoder.c
diff --git a/keyboards/ploopyco/trackball/rules.mk b/keyboards/ploopyco/trackball/rules.mk
index af9bc7d4c..d11858152 100644
--- a/keyboards/ploopyco/trackball/rules.mk
+++ b/keyboards/ploopyco/trackball/rules.mk
@@ -19,9 +19,10 @@ BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
19RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow 19RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
20AUDIO_ENABLE = no # Audio output 20AUDIO_ENABLE = no # Audio output
21POINTING_DEVICE_ENABLE = yes 21POINTING_DEVICE_ENABLE = yes
22POINTING_DEVICE_DRIVER = pmw3360
22MOUSEKEY_ENABLE = yes # Mouse keys 23MOUSEKEY_ENABLE = yes # Mouse keys
23 24
24QUANTUM_LIB_SRC += analog.c spi_master.c 25QUANTUM_LIB_SRC += analog.c
25SRC += drivers/sensors/pmw3360.c opt_encoder.c 26SRC += opt_encoder.c
26 27
27DEFAULT_FOLDER = ploopyco/trackball/rev1_005 28DEFAULT_FOLDER = ploopyco/trackball/rev1_005
diff --git a/keyboards/ploopyco/trackball/trackball.c b/keyboards/ploopyco/trackball/trackball.c
index 719020997..e2a6e4ed5 100644
--- a/keyboards/ploopyco/trackball/trackball.c
+++ b/keyboards/ploopyco/trackball/trackball.c
@@ -65,12 +65,7 @@ uint8_t OptLowPin = OPT_ENC1;
65bool debug_encoder = false; 65bool debug_encoder = false;
66bool is_drag_scroll = false; 66bool is_drag_scroll = false;
67 67
68__attribute__((weak)) void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v) { 68void process_wheel(report_mouse_t* mouse_report) {
69 mouse_report->h = h;
70 mouse_report->v = v;
71}
72
73__attribute__((weak)) void process_wheel(report_mouse_t* mouse_report) {
74 // TODO: Replace this with interrupt driven code, polling is S L O W 69 // TODO: Replace this with interrupt driven code, polling is S L O W
75 // Lovingly ripped from the Ploopy Source 70 // Lovingly ripped from the Ploopy Source
76 71
@@ -99,56 +94,25 @@ __attribute__((weak)) void process_wheel(report_mouse_t* mouse_report) {
99 int dir = opt_encoder_handler(p1, p2); 94 int dir = opt_encoder_handler(p1, p2);
100 95
101 if (dir == 0) return; 96 if (dir == 0) return;
102 process_wheel_user(mouse_report, mouse_report->h, (int)(mouse_report->v + (dir * OPT_SCALE))); 97 mouse_report->v = (int8_t)(dir * OPT_SCALE);
103} 98}
104 99
105__attribute__((weak)) void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y) { 100report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
106 mouse_report->x = x; 101 process_wheel(&mouse_report);
107 mouse_report->y = y;
108}
109
110__attribute__((weak)) void process_mouse(report_mouse_t* mouse_report) {
111 report_pmw_t data = pmw_read_burst();
112 if (data.isOnSurface && data.isMotion) {
113 // Reset timer if stopped moving
114 if (!data.isMotion) {
115 if (MotionStart != 0) MotionStart = 0;
116 return;
117 }
118
119 // Set timer if new motion
120 if ((MotionStart == 0) && data.isMotion) {
121 if (debug_mouse) dprintf("Starting motion.\n");
122 MotionStart = timer_read();
123 }
124 102
125 if (debug_mouse) { 103 if (is_drag_scroll) {
126 dprintf("Delt] d: %d t: %u\n", abs(data.dx) + abs(data.dy), MotionStart); 104 mouse_report.h = mouse_report.x;
127 } 105#ifdef PLOOPY_DRAGSCROLL_INVERT
128 if (debug_mouse) { 106 // Invert vertical scroll direction
129 dprintf("Pre ] X: %d, Y: %d\n", data.dx, data.dy); 107 mouse_report.v = -mouse_report.y;
130 }
131#if defined(PROFILE_LINEAR)
132 float scale = float(timer_elaspsed(MotionStart)) / 1000.0;
133 data.dx *= scale;
134 data.dy *= scale;
135#elif defined(PROFILE_INVERSE)
136 // TODO
137#else 108#else
138 // no post processing 109 mouse_report.v = mouse_report.y;
139#endif 110#endif
140 // apply multiplier 111 mouse_report.x = 0;
141 // data.dx *= mouse_multiplier; 112 mouse_report.y = 0;
142 // data.dy *= mouse_multiplier;
143
144 // Wrap to HID size
145 data.dx = constrain(data.dx, -127, 127);
146 data.dy = constrain(data.dy, -127, 127);
147 if (debug_mouse) dprintf("Cons] X: %d, Y: %d\n", data.dx, data.dy);
148 // dprintf("Elapsed:%u, X: %f Y: %\n", i, pgm_read_byte(firmware_data+i));
149
150 process_mouse_user(mouse_report, data.dx, -data.dy);
151 } 113 }
114
115 return pointing_device_task_user(mouse_report);
152} 116}
153 117
154bool process_record_kb(uint16_t keycode, keyrecord_t* record) { 118bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
@@ -169,7 +133,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
169 if (keycode == DPI_CONFIG && record->event.pressed) { 133 if (keycode == DPI_CONFIG && record->event.pressed) {
170 keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE; 134 keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE;
171 eeconfig_update_kb(keyboard_config.raw); 135 eeconfig_update_kb(keyboard_config.raw);
172 pmw_set_cpi(dpi_array[keyboard_config.dpi_config]); 136 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
173 } 137 }
174 138
175 if (keycode == DRAG_SCROLL) { 139 if (keycode == DRAG_SCROLL) {
@@ -180,9 +144,9 @@ bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
180 is_drag_scroll ^= 1; 144 is_drag_scroll ^= 1;
181 } 145 }
182#ifdef PLOOPY_DRAGSCROLL_FIXED 146#ifdef PLOOPY_DRAGSCROLL_FIXED
183 pmw_set_cpi(is_drag_scroll ? PLOOPY_DRAGSCROLL_DPI : dpi_array[keyboard_config.dpi_config]); 147 pointing_device_set_cpi(is_drag_scroll ? PLOOPY_DRAGSCROLL_DPI : dpi_array[keyboard_config.dpi_config]);
184#else 148#else
185 pmw_set_cpi(is_drag_scroll ? (dpi_array[keyboard_config.dpi_config] * PLOOPY_DRAGSCROLL_MULTIPLIER) : dpi_array[keyboard_config.dpi_config]); 149 pointing_device_set_cpi(is_drag_scroll ? (dpi_array[keyboard_config.dpi_config] * PLOOPY_DRAGSCROLL_MULTIPLIER) : dpi_array[keyboard_config.dpi_config]);
186#endif 150#endif
187 } 151 }
188 152
@@ -194,11 +158,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
194#ifndef MOUSEKEY_ENABLE 158#ifndef MOUSEKEY_ENABLE
195 if (IS_MOUSEKEY_BUTTON(keycode)) { 159 if (IS_MOUSEKEY_BUTTON(keycode)) {
196 report_mouse_t currentReport = pointing_device_get_report(); 160 report_mouse_t currentReport = pointing_device_get_report();
197 if (record->event.pressed) { 161 currentReport.buttons = pointing_device_handle_buttons(record->event.pressed, keycode - KC_MS_BTN1);
198 currentReport.buttons |= 1 << (keycode - KC_MS_BTN1);
199 } else {
200 currentReport.buttons &= ~(1 << (keycode - KC_MS_BTN1));
201 }
202 pointing_device_set_report(currentReport); 162 pointing_device_set_report(currentReport);
203 pointing_device_send(); 163 pointing_device_send();
204 } 164 }
@@ -239,35 +199,12 @@ void keyboard_pre_init_kb(void) {
239 keyboard_pre_init_user(); 199 keyboard_pre_init_user();
240} 200}
241 201
242void pointing_device_init(void) { 202void pointing_device_init_kb(void) {
243 // initialize ball sensor 203 pmw3360_set_cpi(dpi_array[keyboard_config.dpi_config]);
244 pmw_spi_init();
245 // initialize the scroll wheel's optical encoder 204 // initialize the scroll wheel's optical encoder
246 opt_encoder_init(); 205 opt_encoder_init();
247} 206}
248 207
249
250void pointing_device_task(void) {
251 report_mouse_t mouse_report = pointing_device_get_report();
252 process_wheel(&mouse_report);
253 process_mouse(&mouse_report);
254
255 if (is_drag_scroll) {
256 mouse_report.h = mouse_report.x;
257#ifdef PLOOPY_DRAGSCROLL_INVERT
258 // Invert vertical scroll direction
259 mouse_report.v = -mouse_report.y;
260#else
261 mouse_report.v = mouse_report.y;
262#endif
263 mouse_report.x = 0;
264 mouse_report.y = 0;
265 }
266
267 pointing_device_set_report(mouse_report);
268 pointing_device_send();
269}
270
271void eeconfig_init_kb(void) { 208void eeconfig_init_kb(void) {
272 keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT; 209 keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT;
273 eeconfig_update_kb(keyboard_config.raw); 210 eeconfig_update_kb(keyboard_config.raw);
@@ -285,7 +222,7 @@ void matrix_init_kb(void) {
285} 222}
286 223
287void keyboard_post_init_kb(void) { 224void keyboard_post_init_kb(void) {
288 pmw_set_cpi(dpi_array[keyboard_config.dpi_config]); 225 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
289 226
290 keyboard_post_init_user(); 227 keyboard_post_init_user();
291} 228}
diff --git a/keyboards/ploopyco/trackball/trackball.h b/keyboards/ploopyco/trackball/trackball.h
index 70f5d83b1..52d955325 100644
--- a/keyboards/ploopyco/trackball/trackball.h
+++ b/keyboards/ploopyco/trackball/trackball.h
@@ -19,11 +19,8 @@
19#pragma once 19#pragma once
20 20
21#include "quantum.h" 21#include "quantum.h"
22#include "spi_master.h"
23#include "drivers/sensors/pmw3360.h"
24#include "analog.h" 22#include "analog.h"
25#include "opt_encoder.h" 23#include "opt_encoder.h"
26#include "pointing_device.h"
27#if defined(KEYBOARD_ploopyco_trackball_rev1) 24#if defined(KEYBOARD_ploopyco_trackball_rev1)
28# include "rev1.h" 25# include "rev1.h"
29#elif defined(KEYBOARD_ploopyco_trackball_rev1_005) 26#elif defined(KEYBOARD_ploopyco_trackball_rev1_005)
@@ -36,10 +33,7 @@
36#define OPT_ENC1_MUX 0 33#define OPT_ENC1_MUX 0
37#define OPT_ENC2_MUX 4 34#define OPT_ENC2_MUX 4
38 35
39void process_mouse(report_mouse_t* mouse_report);
40void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y);
41void process_wheel(report_mouse_t* mouse_report); 36void process_wheel(report_mouse_t* mouse_report);
42void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v);
43 37
44#define LAYOUT(BL, BM, BR, BF, BB) \ 38#define LAYOUT(BL, BM, BR, BF, BB) \
45 { {BL, BM, BR, BF, BB}, } 39 { {BL, BM, BR, BF, BB}, }
diff --git a/keyboards/ploopyco/trackball_mini/config.h b/keyboards/ploopyco/trackball_mini/config.h
index f76a6eb2c..52d7390ca 100644
--- a/keyboards/ploopyco/trackball_mini/config.h
+++ b/keyboards/ploopyco/trackball_mini/config.h
@@ -56,3 +56,9 @@
56 56
57// If board has a debug LED, you can enable it by defining this 57// If board has a debug LED, you can enable it by defining this
58// #define DEBUG_LED_PIN F7 58// #define DEBUG_LED_PIN F7
59
60#define ADNS5050_SCLK_PIN B7
61#define ADNS5050_SDIO_PIN C6
62#define ADNS5050_CS_PIN B4
63
64#define POINTING_DEVICE_ROTATION_90
diff --git a/keyboards/ploopyco/trackball_mini/keymaps/drag_scroll/keymap.c b/keyboards/ploopyco/trackball_mini/keymaps/drag_scroll/keymap.c
index 7784bc855..7eb973216 100644
--- a/keyboards/ploopyco/trackball_mini/keymaps/drag_scroll/keymap.c
+++ b/keyboards/ploopyco/trackball_mini/keymaps/drag_scroll/keymap.c
@@ -44,7 +44,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
44// to only scroll in one direction, if you wanted, as well. In fact, 44// to only scroll in one direction, if you wanted, as well. In fact,
45// there is no reason that you need to send this to the mouse report. 45// there is no reason that you need to send this to the mouse report.
46// You could have it register a key, instead. 46// You could have it register a key, instead.
47void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y) { 47void process_mouse_user(report_mouse_t* mouse_report, int8_t x, int8_t y) {
48 if (is_drag_scroll) { 48 if (is_drag_scroll) {
49 mouse_report->h = x; 49 mouse_report->h = x;
50 mouse_report->v = y; 50 mouse_report->v = y;
diff --git a/keyboards/ploopyco/trackball_mini/rules.mk b/keyboards/ploopyco/trackball_mini/rules.mk
index 07a6889cb..8d76c9b3d 100644
--- a/keyboards/ploopyco/trackball_mini/rules.mk
+++ b/keyboards/ploopyco/trackball_mini/rules.mk
@@ -1,9 +1,6 @@
1# MCU name 1# MCU name
2MCU = atmega32u4 2MCU = atmega32u4
3 3
4# Processor frequency
5F_CPU = 16000000
6
7# Bootloader selection 4# Bootloader selection
8BOOTLOADER = atmel-dfu 5BOOTLOADER = atmel-dfu
9 6
@@ -22,9 +19,10 @@ BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
22RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow 19RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
23AUDIO_ENABLE = no # Audio output 20AUDIO_ENABLE = no # Audio output
24POINTING_DEVICE_ENABLE = yes 21POINTING_DEVICE_ENABLE = yes
22POINTING_DEVICE_DRIVER = adns5050
25MOUSEKEY_ENABLE = no # Mouse keys 23MOUSEKEY_ENABLE = no # Mouse keys
26 24
27QUANTUM_LIB_SRC += analog.c 25QUANTUM_LIB_SRC += analog.c
28SRC += drivers/sensors/adns5050.c opt_encoder.c 26SRC += opt_encoder.c
29 27
30DEFAULT_FOLDER = ploopyco/trackball_mini/rev1_001 28DEFAULT_FOLDER = ploopyco/trackball_mini/rev1_001
diff --git a/keyboards/ploopyco/trackball_mini/trackball_mini.c b/keyboards/ploopyco/trackball_mini/trackball_mini.c
index b50850b54..2158a8f48 100644
--- a/keyboards/ploopyco/trackball_mini/trackball_mini.c
+++ b/keyboards/ploopyco/trackball_mini/trackball_mini.c
@@ -37,20 +37,17 @@
37# define OPT_SCALE 1 // Multiplier for wheel 37# define OPT_SCALE 1 // Multiplier for wheel
38#endif 38#endif
39 39
40#define PLOOPY_DPI_OPTIONS { CPI375, CPI750, CPI1375 } 40#define PLOOPY_DPI_OPTIONS \
41 { 375, 750, 1375 }
41#define PLOOPY_DPI_DEFAULT 2 42#define PLOOPY_DPI_DEFAULT 2
42 43
43#ifndef PLOOPY_DRAGSCROLL_DPI 44#ifndef PLOOPY_DRAGSCROLL_DPI
44# define PLOOPY_DRAGSCROLL_DPI CPI375 // Fixed-DPI Drag Scroll 45# define PLOOPY_DRAGSCROLL_DPI 375 // Fixed-DPI Drag Scroll
45#endif 46#endif
46#ifndef PLOOPY_DRAGSCROLL_MULTIPLIER 47#ifndef PLOOPY_DRAGSCROLL_MULTIPLIER
47# define PLOOPY_DRAGSCROLL_MULTIPLIER 0.75 // Variable-DPI Drag Scroll 48# define PLOOPY_DRAGSCROLL_MULTIPLIER 0.75 // Variable-DPI Drag Scroll
48#endif 49#endif
49 50
50// Transformation constants for delta-X and delta-Y
51const static float ADNS_X_TRANSFORM = -1.0;
52const static float ADNS_Y_TRANSFORM = 1.0;
53
54keyboard_config_t keyboard_config; 51keyboard_config_t keyboard_config;
55uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS; 52uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS;
56#define DPI_OPTION_SIZE (sizeof(dpi_array) / sizeof(uint16_t)) 53#define DPI_OPTION_SIZE (sizeof(dpi_array) / sizeof(uint16_t))
@@ -70,12 +67,7 @@ uint8_t OptLowPin = OPT_ENC1;
70bool debug_encoder = false; 67bool debug_encoder = false;
71bool is_drag_scroll = false; 68bool is_drag_scroll = false;
72 69
73__attribute__((weak)) void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v) { 70void process_wheel(report_mouse_t* mouse_report) {
74 mouse_report->h = h;
75 mouse_report->v = v;
76}
77
78__attribute__((weak)) void process_wheel(report_mouse_t* mouse_report) {
79 // If the mouse wheel was just released, do not scroll. 71 // If the mouse wheel was just released, do not scroll.
80 if (timer_elapsed(lastMidClick) < SCROLL_BUTT_DEBOUNCE) 72 if (timer_elapsed(lastMidClick) < SCROLL_BUTT_DEBOUNCE)
81 return; 73 return;
@@ -103,33 +95,31 @@ __attribute__((weak)) void process_wheel(report_mouse_t* mouse_report) {
103 if (dir == 0) 95 if (dir == 0)
104 return; 96 return;
105 97
106 process_wheel_user(mouse_report, mouse_report->h, (int)(mouse_report->v + (dir * OPT_SCALE))); 98 mouse_report->v = (int8_t)(dir * OPT_SCALE);
107} 99}
108 100
109__attribute__((weak)) void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y) { 101void pointing_device_init_kb(void) {
110 mouse_report->x = x; 102 opt_encoder_init();
111 mouse_report->y = y;
112}
113
114__attribute__((weak)) void process_mouse(report_mouse_t* mouse_report) {
115 report_adns_t data = adns_read_burst();
116
117 if (data.dx != 0 || data.dy != 0) {
118 if (debug_mouse)
119 dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy);
120 103
121 // Apply delta-X and delta-Y transformations. 104 // set the DPI.
122 // x and y are swapped 105 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
123 // the sensor is rotated 106}
124 // by 90 degrees
125 float xt = (float) data.dy * ADNS_X_TRANSFORM;
126 float yt = (float) data.dx * ADNS_Y_TRANSFORM;
127 107
128 int16_t xti = (int16_t)xt; 108report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
129 int16_t yti = (int16_t)yt;
130 109
131 process_mouse_user(mouse_report, xti, yti); 110 if (is_drag_scroll) {
111 mouse_report.h = mouse_report.x;
112#ifdef PLOOPY_DRAGSCROLL_INVERT
113 // Invert vertical scroll direction
114 mouse_report.v = -mouse_report.y;
115#else
116 mouse_report.v = mouse_report.y;
117#endif
118 mouse_report.x = 0;
119 mouse_report.y = 0;
132 } 120 }
121
122 return pointing_device_task_user(mouse_report);
133} 123}
134 124
135bool process_record_kb(uint16_t keycode, keyrecord_t* record) { 125bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
@@ -147,7 +137,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
147 if (keycode == DPI_CONFIG && record->event.pressed) { 137 if (keycode == DPI_CONFIG && record->event.pressed) {
148 keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE; 138 keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE;
149 eeconfig_update_kb(keyboard_config.raw); 139 eeconfig_update_kb(keyboard_config.raw);
150 adns_set_cpi(dpi_array[keyboard_config.dpi_config]); 140 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
151 } 141 }
152 142
153 if (keycode == DRAG_SCROLL) { 143 if (keycode == DRAG_SCROLL) {
@@ -157,7 +147,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
157 { 147 {
158 is_drag_scroll ^= 1; 148 is_drag_scroll ^= 1;
159 } 149 }
160 adns_set_cpi(is_drag_scroll ? PLOOPY_DRAGSCROLL_DPI : dpi_array[keyboard_config.dpi_config]); 150 pointing_device_set_cpi(is_drag_scroll ? PLOOPY_DRAGSCROLL_DPI : dpi_array[keyboard_config.dpi_config]);
161 } 151 }
162 152
163/* If Mousekeys is disabled, then use handle the mouse button 153/* If Mousekeys is disabled, then use handle the mouse button
@@ -168,11 +158,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
168#ifndef MOUSEKEY_ENABLE 158#ifndef MOUSEKEY_ENABLE
169 if (IS_MOUSEKEY_BUTTON(keycode)) { 159 if (IS_MOUSEKEY_BUTTON(keycode)) {
170 report_mouse_t currentReport = pointing_device_get_report(); 160 report_mouse_t currentReport = pointing_device_get_report();
171 if (record->event.pressed) { 161 currentReport.buttons = pointing_device_handle_buttons(currentReport.buttons, record->event.pressed, keycode - KC_MS_BTN1);
172 currentReport.buttons |= 1 << (keycode - KC_MS_BTN1);
173 } else {
174 currentReport.buttons &= ~(1 << (keycode - KC_MS_BTN1));
175 }
176 pointing_device_set_report(currentReport); 162 pointing_device_set_report(currentReport);
177 pointing_device_send(); 163 pointing_device_send();
178 } 164 }
@@ -207,48 +193,6 @@ void keyboard_pre_init_kb(void) {
207 keyboard_pre_init_user(); 193 keyboard_pre_init_user();
208} 194}
209 195
210void pointing_device_init(void) {
211 adns_init();
212 opt_encoder_init();
213
214 // reboot the adns.
215 // if the adns hasn't initialized yet, this is harmless.
216 adns_write_reg(REG_CHIP_RESET, 0x5a);
217
218 // wait maximum time before adns is ready.
219 // this ensures that the adns is actuall ready after reset.
220 wait_ms(55);
221
222 // read a burst from the adns and then discard it.
223 // gets the adns ready for write commands
224 // (for example, setting the dpi).
225 adns_read_burst();
226
227 // set the DPI.
228 adns_set_cpi(dpi_array[keyboard_config.dpi_config]);
229}
230
231void pointing_device_task(void) {
232 report_mouse_t mouse_report = pointing_device_get_report();
233 process_wheel(&mouse_report);
234 process_mouse(&mouse_report);
235
236 if (is_drag_scroll) {
237 mouse_report.h = mouse_report.x;
238#ifdef PLOOPY_DRAGSCROLL_INVERT
239 // Invert vertical scroll direction
240 mouse_report.v = -mouse_report.y;
241#else
242 mouse_report.v = mouse_report.y;
243#endif
244 mouse_report.x = 0;
245 mouse_report.y = 0;
246 }
247
248 pointing_device_set_report(mouse_report);
249 pointing_device_send();
250}
251
252void eeconfig_init_kb(void) { 196void eeconfig_init_kb(void) {
253 keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT; 197 keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT;
254 eeconfig_update_kb(keyboard_config.raw); 198 eeconfig_update_kb(keyboard_config.raw);
diff --git a/keyboards/ploopyco/trackball_mini/trackball_mini.h b/keyboards/ploopyco/trackball_mini/trackball_mini.h
index 7bcb02a94..fc86fe776 100644
--- a/keyboards/ploopyco/trackball_mini/trackball_mini.h
+++ b/keyboards/ploopyco/trackball_mini/trackball_mini.h
@@ -20,10 +20,8 @@
20#pragma once 20#pragma once
21 21
22#include "quantum.h" 22#include "quantum.h"
23#include "drivers/sensors/adns5050.h"
24#include "analog.h" 23#include "analog.h"
25#include "opt_encoder.h" 24#include "opt_encoder.h"
26#include "pointing_device.h"
27 25
28// Sensor defs 26// Sensor defs
29#define OPT_ENC1 F0 27#define OPT_ENC1 F0
@@ -31,10 +29,7 @@
31#define OPT_ENC1_MUX 0 29#define OPT_ENC1_MUX 0
32#define OPT_ENC2_MUX 4 30#define OPT_ENC2_MUX 4
33 31
34void process_mouse(report_mouse_t* mouse_report);
35void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y);
36void process_wheel(report_mouse_t* mouse_report); 32void process_wheel(report_mouse_t* mouse_report);
37void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v);
38 33
39#define LAYOUT(BL, BM, BR, BF, BB) \ 34#define LAYOUT(BL, BM, BR, BF, BB) \
40 { {BL, BM, BR, BF, BB}, } 35 { {BL, BM, BR, BF, BB}, }
diff --git a/keyboards/ploopyco/trackball_nano/config.h b/keyboards/ploopyco/trackball_nano/config.h
index 7450f5574..7d109db99 100644
--- a/keyboards/ploopyco/trackball_nano/config.h
+++ b/keyboards/ploopyco/trackball_nano/config.h
@@ -45,3 +45,9 @@
45 a polling rate as possible. */ 45 a polling rate as possible. */
46#define USB_POLLING_INTERVAL_MS 1 46#define USB_POLLING_INTERVAL_MS 1
47#define USB_MAX_POWER_CONSUMPTION 100 47#define USB_MAX_POWER_CONSUMPTION 100
48
49#define ADNS5050_SCLK_PIN B7
50#define ADNS5050_SDIO_PIN C6
51#define ADNS5050_CS_PIN B4
52
53#define POINTING_DEVICE_ROTATION_90
diff --git a/keyboards/ploopyco/trackball_nano/keymaps/maddie/keymap.c b/keyboards/ploopyco/trackball_nano/keymaps/maddie/keymap.c
index 6f568ecf5..9e33db378 100644
--- a/keyboards/ploopyco/trackball_nano/keymaps/maddie/keymap.c
+++ b/keyboards/ploopyco/trackball_nano/keymaps/maddie/keymap.c
@@ -21,14 +21,14 @@
21// safe range starts at `PLOOPY_SAFE_RANGE` instead. 21// safe range starts at `PLOOPY_SAFE_RANGE` instead.
22uint8_t scroll_enabled = 0; 22uint8_t scroll_enabled = 0;
23uint8_t lock_state = 0; 23uint8_t lock_state = 0;
24int16_t delta_x = 0; 24int8_t delta_x = 0;
25int16_t delta_y = 0; 25int8_t delta_y = 0;
26 26
27void process_mouse_user(report_mouse_t *mouse_report, int16_t x, int16_t y) { 27void process_mouse_user(report_mouse_t *mouse_report, int8_t x, int8_t y) {
28 if (scroll_enabled) { 28 if (scroll_enabled) {
29 delta_x += x; 29 delta_x += x;
30 delta_y += y; 30 delta_y += y;
31 31
32 if (delta_x > 60) { 32 if (delta_x > 60) {
33 mouse_report->h = 1; 33 mouse_report->h = 1;
34 delta_x = 0; 34 delta_x = 0;
@@ -44,10 +44,10 @@ void process_mouse_user(report_mouse_t *mouse_report, int16_t x, int16_t y) {
44 mouse_report->v = 1; 44 mouse_report->v = 1;
45 delta_y = 0; 45 delta_y = 0;
46 } 46 }
47 } else { 47 } else {
48 mouse_report->x = x; 48 mouse_report->x = x;
49 mouse_report->y = y; 49 mouse_report->y = y;
50 } 50 }
51} 51}
52 52
53void keyboard_post_init_user(void) { 53void keyboard_post_init_user(void) {
@@ -62,7 +62,7 @@ bool led_update_user(led_t led_state) {
62 scroll_timer = timer_read(); 62 scroll_timer = timer_read();
63 lock_count = 0; 63 lock_count = 0;
64 } 64 }
65 65
66 if (led_state.num_lock != lock_state) { 66 if (led_state.num_lock != lock_state) {
67 lock_count++; 67 lock_count++;
68 68
@@ -73,7 +73,7 @@ bool led_update_user(led_t led_state) {
73 delta_y = 0; 73 delta_y = 0;
74 } 74 }
75 } 75 }
76 76
77 lock_state = led_state.num_lock; 77 lock_state = led_state.num_lock;
78 return true; 78 return true;
79} 79}
diff --git a/keyboards/ploopyco/trackball_nano/rules.mk b/keyboards/ploopyco/trackball_nano/rules.mk
index a26ad93c8..1a29a561e 100644
--- a/keyboards/ploopyco/trackball_nano/rules.mk
+++ b/keyboards/ploopyco/trackball_nano/rules.mk
@@ -1,9 +1,6 @@
1# MCU name 1# MCU name
2MCU = atmega32u4 2MCU = atmega32u4
3 3
4# Processor frequency
5F_CPU = 16000000
6
7# Bootloader selection 4# Bootloader selection
8BOOTLOADER = atmel-dfu 5BOOTLOADER = atmel-dfu
9 6
@@ -22,9 +19,7 @@ BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
22RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow 19RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
23AUDIO_ENABLE = no # Audio output 20AUDIO_ENABLE = no # Audio output
24POINTING_DEVICE_ENABLE = yes 21POINTING_DEVICE_ENABLE = yes
22POINTING_DEVICE_DRIVER = adns5050
25MOUSEKEY_ENABLE = no # Mouse keys 23MOUSEKEY_ENABLE = no # Mouse keys
26 24
27QUANTUM_LIB_SRC += analog.c
28SRC += drivers/sensors/adns5050.c opt_encoder.c
29
30DEFAULT_FOLDER = ploopyco/trackball_nano/rev1_001 25DEFAULT_FOLDER = ploopyco/trackball_nano/rev1_001
diff --git a/keyboards/ploopyco/trackball_nano/trackball_nano.c b/keyboards/ploopyco/trackball_nano/trackball_nano.c
index 9bcfa59ef..2702f6055 100644
--- a/keyboards/ploopyco/trackball_nano/trackball_nano.c
+++ b/keyboards/ploopyco/trackball_nano/trackball_nano.c
@@ -37,7 +37,8 @@
37#endif 37#endif
38 38
39#ifndef PLOOPY_DPI_OPTIONS 39#ifndef PLOOPY_DPI_OPTIONS
40# define PLOOPY_DPI_OPTIONS { CPI375, CPI750, CPI1375 } 40# define PLOOPY_DPI_OPTIONS \
41 { 375, 750, 1375 }
41# ifndef PLOOPY_DPI_DEFAULT 42# ifndef PLOOPY_DPI_DEFAULT
42# define PLOOPY_DPI_DEFAULT 2 43# define PLOOPY_DPI_DEFAULT 2
43# endif 44# endif
@@ -49,12 +50,8 @@
49 50
50const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { }; 51const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { };
51 52
52// Transformation constants for delta-X and delta-Y
53const static float ADNS_X_TRANSFORM = -1.0;
54const static float ADNS_Y_TRANSFORM = 1.0;
55
56keyboard_config_t keyboard_config; 53keyboard_config_t keyboard_config;
57uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS; 54uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS;
58#define DPI_OPTION_SIZE (sizeof(dpi_array) / sizeof(uint16_t)) 55#define DPI_OPTION_SIZE (sizeof(dpi_array) / sizeof(uint16_t))
59 56
60// TODO: Implement libinput profiles 57// TODO: Implement libinput profiles
@@ -63,77 +60,13 @@ uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS;
63// Valid options are ACC_NONE, ACC_LINEAR, ACC_CUSTOM, ACC_QUADRATIC 60// Valid options are ACC_NONE, ACC_LINEAR, ACC_CUSTOM, ACC_QUADRATIC
64 61
65// Trackball State 62// Trackball State
66bool is_scroll_clicked = false; 63bool is_scroll_clicked = false;
67bool BurstState = false; // init burst state for Trackball module 64bool BurstState = false; // init burst state for Trackball module
68uint16_t MotionStart = 0; // Timer for accel, 0 is resting state 65uint16_t MotionStart = 0; // Timer for accel, 0 is resting state
69uint16_t lastScroll = 0; // Previous confirmed wheel event
70uint16_t lastMidClick = 0; // Stops scrollwheel from being read if it was pressed
71uint8_t OptLowPin = OPT_ENC1;
72bool debug_encoder = false;
73
74__attribute__((weak)) void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y) {
75 mouse_report->x = x;
76 mouse_report->y = y;
77}
78
79__attribute__((weak)) void process_mouse(report_mouse_t* mouse_report) {
80 report_adns_t data = adns_read_burst();
81
82 if (data.dx != 0 || data.dy != 0) {
83 if (debug_mouse)
84 dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy);
85
86 // Apply delta-X and delta-Y transformations.
87 // x and y are swapped
88 // the sensor is rotated
89 // by 90 degrees
90 float xt = (float) data.dy * ADNS_X_TRANSFORM;
91 float yt = (float) data.dx * ADNS_Y_TRANSFORM;
92
93 int16_t xti = (int16_t)xt;
94 int16_t yti = (int16_t)yt;
95
96 process_mouse_user(mouse_report, xti, yti);
97 }
98}
99
100bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
101 xprintf("KL: kc: %u, col: %u, row: %u, pressed: %u\n", keycode, record->event.key.col, record->event.key.row, record->event.pressed);
102
103 // Update Timer to prevent accidental scrolls
104 if ((record->event.key.col == 1) && (record->event.key.row == 0)) {
105 lastMidClick = timer_read();
106 is_scroll_clicked = record->event.pressed;
107 }
108
109 if (!process_record_user(keycode, record))
110 return false;
111
112 if (keycode == DPI_CONFIG && record->event.pressed) {
113 keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE;
114 eeconfig_update_kb(keyboard_config.raw);
115 adns_set_cpi(dpi_array[keyboard_config.dpi_config]);
116 }
117 66
118/* If Mousekeys is disabled, then use handle the mouse button 67void pointing_device_init_kb(void) {
119 * keycodes. This makes things simpler, and allows usage of 68 // set the DPI.
120 * the keycodes in a consistent manner. But only do this if 69 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
121 * Mousekeys is not enable, so it's not handled twice.
122 */
123#ifndef MOUSEKEY_ENABLE
124 if (IS_MOUSEKEY_BUTTON(keycode)) {
125 report_mouse_t currentReport = pointing_device_get_report();
126 if (record->event.pressed) {
127 currentReport.buttons |= 1 << (keycode - KC_MS_BTN1);
128 } else {
129 currentReport.buttons &= ~(1 << (keycode - KC_MS_BTN1));
130 }
131 pointing_device_set_report(currentReport);
132 pointing_device_send();
133 }
134#endif
135
136 return true;
137} 70}
138 71
139// Hardware Setup 72// Hardware Setup
@@ -143,9 +76,6 @@ void keyboard_pre_init_kb(void) {
143 // debug_mouse = true; 76 // debug_mouse = true;
144 // debug_encoder = true; 77 // debug_encoder = true;
145 78
146 setPinInput(OPT_ENC1);
147 setPinInput(OPT_ENC2);
148
149 /* Ground all output pins connected to ground. This provides additional 79 /* Ground all output pins connected to ground. This provides additional
150 * pathways to ground. If you're messing with this, know this: driving ANY 80 * pathways to ground. If you're messing with this, know this: driving ANY
151 * of these pins high will cause a short. On the MCU. Ka-blooey. 81 * of these pins high will cause a short. On the MCU. Ka-blooey.
@@ -162,34 +92,6 @@ void keyboard_pre_init_kb(void) {
162 keyboard_pre_init_user(); 92 keyboard_pre_init_user();
163} 93}
164 94
165void pointing_device_init(void) {
166 adns_init();
167 opt_encoder_init();
168
169 // reboot the adns.
170 // if the adns hasn't initialized yet, this is harmless.
171 adns_write_reg(REG_CHIP_RESET, 0x5a);
172
173 // wait maximum time before adns is ready.
174 // this ensures that the adns is actuall ready after reset.
175 wait_ms(55);
176
177 // read a burst from the adns and then discard it.
178 // gets the adns ready for write commands
179 // (for example, setting the dpi).
180 adns_read_burst();
181
182 // set the DPI.
183 adns_set_cpi(dpi_array[keyboard_config.dpi_config]);
184}
185
186void pointing_device_task(void) {
187 report_mouse_t mouse_report = pointing_device_get_report();
188 process_mouse(&mouse_report);
189 pointing_device_set_report(mouse_report);
190 pointing_device_send();
191}
192
193void eeconfig_init_kb(void) { 95void eeconfig_init_kb(void) {
194 keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT; 96 keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT;
195 eeconfig_update_kb(keyboard_config.raw); 97 eeconfig_update_kb(keyboard_config.raw);
diff --git a/keyboards/ploopyco/trackball_nano/trackball_nano.h b/keyboards/ploopyco/trackball_nano/trackball_nano.h
index 6c8ecace7..88725eab6 100644
--- a/keyboards/ploopyco/trackball_nano/trackball_nano.h
+++ b/keyboards/ploopyco/trackball_nano/trackball_nano.h
@@ -20,19 +20,6 @@
20#pragma once 20#pragma once
21 21
22#include "quantum.h" 22#include "quantum.h"
23#include "drivers/sensors/adns5050.h"
24#include "analog.h"
25#include "opt_encoder.h"
26#include "pointing_device.h"
27
28// Sensor defs
29#define OPT_ENC1 F0
30#define OPT_ENC2 F4
31#define OPT_ENC1_MUX 0
32#define OPT_ENC2_MUX 4
33
34void process_mouse(report_mouse_t* mouse_report);
35void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y);
36 23
37#define LAYOUT(k00) {{ KC_NO }} 24#define LAYOUT(k00) {{ KC_NO }}
38 25
diff --git a/keyboards/tkw/grandiceps/rev2/rules.mk b/keyboards/tkw/grandiceps/rev2/rules.mk
index c8f3f05bd..3e82c4507 100644
--- a/keyboards/tkw/grandiceps/rev2/rules.mk
+++ b/keyboards/tkw/grandiceps/rev2/rules.mk
@@ -1,5 +1,4 @@
1EEPROM_DRIVER = i2c 1EEPROM_DRIVER = i2c
2 2
3POINTING_DEVICE_ENABLE = yes 3POINTING_DEVICE_ENABLE = yes
4SRC += drivers/sensors/pimoroni_trackball.c 4POINTING_DEVICE_DRIVER = pimoroni_trackball
5QUANTUM_LIB_SRC += i2c_master.c
diff --git a/layouts/community/ergodox/drashna/keymap.c b/layouts/community/ergodox/drashna/keymap.c
index dd47899d7..3c9bcfeaa 100644
--- a/layouts/community/ergodox/drashna/keymap.c
+++ b/layouts/community/ergodox/drashna/keymap.c
@@ -186,20 +186,20 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
186 186
187#ifdef PIMORONI_TRACKBALL_ENABLE 187#ifdef PIMORONI_TRACKBALL_ENABLE
188void run_trackball_cleanup(void) { 188void run_trackball_cleanup(void) {
189 if (trackball_is_scrolling()) { 189 // if (trackball_is_scrolling()) {
190 trackball_set_rgbw(RGB_CYAN, 0x00); 190 // trackball_set_rgbw(RGB_CYAN, 0x00);
191 } else if (trackball_get_precision() != 1.0) { 191 // } else if (trackball_get_precision() != 1.0) {
192 trackball_set_rgbw(RGB_GREEN, 0x00); 192 // trackball_set_rgbw(RGB_GREEN, 0x00);
193 } else { 193 // } else {
194 trackball_set_rgbw(RGB_MAGENTA, 0x00); 194 // trackball_set_rgbw(RGB_MAGENTA, 0x00);
195 } 195 // }
196} 196}
197 197
198void keyboard_post_init_keymap(void) { 198void keyboard_post_init_keymap(void) {
199 // trackball_set_precision(1.5); 199 // trackball_set_precision(1.5);
200 trackball_set_rgbw(RGB_MAGENTA, 0x00); 200 // trackball_set_rgbw(RGB_MAGENTA, 0x00);
201} 201}
202void shutdown_keymap(void) { trackball_set_rgbw(RGB_RED, 0x00); } 202// void shutdown_keymap(void) { trackball_set_rgbw(RGB_RED, 0x00); }
203 203
204static bool mouse_button_one, trackball_button_one; 204static bool mouse_button_one, trackball_button_one;
205 205
@@ -244,16 +244,16 @@ bool process_record_keymap(uint16_t keycode, keyrecord_t *record) {
244 break; 244 break;
245#ifdef PIMORONI_TRACKBALL_ENABLE 245#ifdef PIMORONI_TRACKBALL_ENABLE
246 case PM_SCROLL: 246 case PM_SCROLL:
247 trackball_set_scrolling(record->event.pressed); 247 // trackball_set_scrolling(record->event.pressed);
248 run_trackball_cleanup(); 248 run_trackball_cleanup();
249 break; 249 break;
250 case PM_PRECISION: 250 case PM_PRECISION:
251 if (record->event.pressed) { 251 // if (record->event.pressed) {
252 trackball_set_precision(1.5); 252 // trackball_set_precision(1.5);
253 } else { 253 // } else {
254 trackball_set_precision(1); 254 // trackball_set_precision(1);
255 } 255 // }
256 run_trackball_cleanup(); 256 // run_trackball_cleanup();
257 break; 257 break;
258# if !defined(MOUSEKEY_ENABLE) 258# if !defined(MOUSEKEY_ENABLE)
259 case KC_MS_BTN1: 259 case KC_MS_BTN1:
diff --git a/quantum/pointing_device.c b/quantum/pointing_device.c
index 09d889f69..feeb2b316 100644
--- a/quantum/pointing_device.c
+++ b/quantum/pointing_device.c
@@ -1,34 +1,56 @@
1/* 1/* Copyright 2017 Joshua Broekhuijsen <snipeye+qmk@gmail.com>
2Copyright 2017 Joshua Broekhuijsen <snipeye+qmk@gmail.com> 2 * Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
3 3 * Copyright 2021 Dasky (@daskygit)
4This program is free software: you can redistribute it and/or modify 4 *
5it under the terms of the GNU General Public License as published by 5 * This program is free software: you can redistribute it and/or modify
6the Free Software Foundation, either version 2 of the License, or 6 * it under the terms of the GNU General Public License as published by
7(at your option) any later version. 7 * the Free Software Foundation, either version 2 of the License, or
8 8 * (at your option) any later version.
9This program is distributed in the hope that it will be useful, 9 *
10but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * This program is distributed in the hope that it will be useful,
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12GNU General Public License for more details. 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 13 * GNU General Public License for more details.
14You should have received a copy of the GNU General Public License 14 *
15along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * You should have received a copy of the GNU General Public License
16*/ 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17 */
18#include <stdint.h> 18
19#include "report.h"
20#include "host.h"
21#include "timer.h"
22#include "print.h"
23#include "debug.h"
24#include "pointing_device.h" 19#include "pointing_device.h"
20#ifdef MOUSEKEY_ENABLE
21# include "mousekey.h"
22#endif
23#if (defined(POINTING_DEVICE_ROTATION_90) + defined(POINTING_DEVICE_ROTATION_180) + defined(POINTING_DEVICE_ROTATION_270)) > 1
24# error More than one rotation selected. This is not supported.
25#endif
25 26
26static report_mouse_t mouseReport = {}; 27static report_mouse_t mouseReport = {};
27 28
28__attribute__((weak)) bool has_mouse_report_changed(report_mouse_t new, report_mouse_t old) { return (new.buttons != old.buttons) || (new.x&& new.x != old.x) || (new.y&& new.y != old.y) || (new.h&& new.h != old.h) || (new.v&& new.v != old.v); } 29extern const pointing_device_driver_t pointing_device_driver;
30
31__attribute__((weak)) bool has_mouse_report_changed(report_mouse_t new, report_mouse_t old) { return memcmp(&new, &old, sizeof(new)); }
32
33__attribute__((weak)) void pointing_device_init_kb(void) {}
34__attribute__((weak)) void pointing_device_init_user(void) {}
35__attribute__((weak)) report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { return pointing_device_task_user(mouse_report); }
36__attribute__((weak)) report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) { return mouse_report; }
37
38__attribute__((weak)) uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button) {
39 if (pressed) {
40 buttons |= 1 << (button);
41 } else {
42 buttons &= ~(1 << (button));
43 }
44 return buttons;
45}
29 46
30__attribute__((weak)) void pointing_device_init(void) { 47__attribute__((weak)) void pointing_device_init(void) {
31 // initialize device, if that needs to be done. 48 pointing_device_driver.init();
49#ifdef POINTING_DEVICE_MOTION_PIN
50 setPinInputHigh(POINTING_DEVICE_MOTION_PIN);
51#endif
52 pointing_device_init_kb();
53 pointing_device_init_user();
32} 54}
33 55
34__attribute__((weak)) void pointing_device_send(void) { 56__attribute__((weak)) void pointing_device_send(void) {
@@ -43,20 +65,55 @@ __attribute__((weak)) void pointing_device_send(void) {
43 mouseReport.y = 0; 65 mouseReport.y = 0;
44 mouseReport.v = 0; 66 mouseReport.v = 0;
45 mouseReport.h = 0; 67 mouseReport.h = 0;
46 old_report = mouseReport; 68
69 memcpy(&old_report, &mouseReport, sizeof(mouseReport));
47} 70}
48 71
49__attribute__((weak)) void pointing_device_task(void) { 72__attribute__((weak)) void pointing_device_task(void) {
50 // gather info and put it in: 73 // Gather report info
51 // mouseReport.x = 127 max -127 min 74#ifdef POINTING_DEVICE_MOTION_PIN
52 // mouseReport.y = 127 max -127 min 75 if (!readPin(POINTING_DEVICE_MOTION_PIN))
53 // mouseReport.v = 127 max -127 min (scroll vertical) 76#endif
54 // mouseReport.h = 127 max -127 min (scroll horizontal) 77 mouseReport = pointing_device_driver.get_report(mouseReport);
55 // mouseReport.buttons = 0x1F (decimal 31, binary 00011111) max (bitmask for mouse buttons 1-5, 1 is rightmost, 5 is leftmost) 0x00 min 78
56 // send the report 79 // Support rotation of the sensor data
80#if defined(POINTING_DEVICE_ROTATION_90) || defined(POINTING_DEVICE_ROTATION_180) || defined(POINTING_DEVICE_ROTATION_270)
81 int8_t x = mouseReport.x, y = mouseReport.y;
82# if defined(POINTING_DEVICE_ROTATION_90)
83 mouseReport.x = y;
84 mouseReport.y = -x;
85# elif defined(POINTING_DEVICE_ROTATION_180)
86 mouseReport.x = -x;
87 mouseReport.y = -y;
88# elif defined(POINTING_DEVICE_ROTATION_270)
89 mouseReport.x = -y;
90 mouseReport.y = x;
91# else
92# error "How the heck did you get here?!"
93# endif
94#endif
95 // Support Inverting the X and Y Axises
96#if defined(POINTING_DEVICE_INVERT_X)
97 mouseReport.x = -mouseReport.x;
98#endif
99#if defined(POINTING_DEVICE_INVERT_Y)
100 mouseReport.y = -mouseReport.y;
101#endif
102
103 // allow kb to intercept and modify report
104 mouseReport = pointing_device_task_kb(mouseReport);
105 // combine with mouse report to ensure that the combined is sent correctly
106#ifdef MOUSEKEY_ENABLE
107 report_mouse_t mousekey_report = mousekey_get_report();
108 mouseReport.buttons = mouseReport.buttons | mousekey_report.buttons;
109#endif
57 pointing_device_send(); 110 pointing_device_send();
58} 111}
59 112
60report_mouse_t pointing_device_get_report(void) { return mouseReport; } 113report_mouse_t pointing_device_get_report(void) { return mouseReport; }
61 114
62void pointing_device_set_report(report_mouse_t newMouseReport) { mouseReport = newMouseReport; } 115void pointing_device_set_report(report_mouse_t newMouseReport) { mouseReport = newMouseReport; }
116
117uint16_t pointing_device_get_cpi(void) { return pointing_device_driver.get_cpi(); }
118
119void pointing_device_set_cpi(uint16_t cpi) { pointing_device_driver.set_cpi(cpi); }
diff --git a/quantum/pointing_device.h b/quantum/pointing_device.h
index 56a542d54..5106c2666 100644
--- a/quantum/pointing_device.h
+++ b/quantum/pointing_device.h
@@ -21,9 +21,68 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
21#include "host.h" 21#include "host.h"
22#include "report.h" 22#include "report.h"
23 23
24#if defined(POINTING_DEVICE_DRIVER_adns5050)
25# include "drivers/sensors/adns5050.h"
26#elif defined(POINTING_DEVICE_DRIVER_adns9800)
27# include "spi_master.h"
28# include "drivers/sensors/adns9800.h"
29#elif defined(POINTING_DEVICE_DRIVER_analog_joystick)
30# include "analog.h"
31# include "drivers/sensors/analog_joystick.h"
32#elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c) || defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi)
33# include "drivers/sensors/cirque_pinnacle.h"
34#elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball)
35# include "i2c_master.h"
36# include "drivers/sensors/pimoroni_trackball.h"
37// support for legacy pimoroni defines
38# ifdef PIMORONI_TRACKBALL_INVERT_X
39# define POINTING_DEVICE_INVERT_X
40# endif
41# ifdef PIMORONI_TRACKBALL_INVERT_Y
42# define POINTING_DEVICE_INVERT_Y
43# endif
44# ifdef PIMORONI_TRACKBALL_ROTATE
45# define POINTING_DEVICE_ROTATION_90
46# endif
47#elif defined(POINTING_DEVICE_DRIVER_pmw3360)
48# include "spi_master.h"
49# include "drivers/sensors/pmw3360.h"
50#else
51void pointing_device_driver_init(void);
52report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report);
53uint16_t pointing_device_driver_get_cpi(void);
54void pointing_device_driver_set_cpi(uint16_t cpi);
55#endif
56
57typedef struct {
58 void (*init)(void);
59 report_mouse_t (*get_report)(report_mouse_t mouse_report);
60 void (*set_cpi)(uint16_t);
61 uint16_t (*get_cpi)(void);
62} pointing_device_driver_t;
63
64typedef enum {
65 POINTING_DEVICE_BUTTON1,
66 POINTING_DEVICE_BUTTON2,
67 POINTING_DEVICE_BUTTON3,
68 POINTING_DEVICE_BUTTON4,
69 POINTING_DEVICE_BUTTON5,
70 POINTING_DEVICE_BUTTON6,
71 POINTING_DEVICE_BUTTON7,
72 POINTING_DEVICE_BUTTON8,
73} pointing_device_buttons_t;
74
24void pointing_device_init(void); 75void pointing_device_init(void);
25void pointing_device_task(void); 76void pointing_device_task(void);
26void pointing_device_send(void); 77void pointing_device_send(void);
27report_mouse_t pointing_device_get_report(void); 78report_mouse_t pointing_device_get_report(void);
28void pointing_device_set_report(report_mouse_t newMouseReport); 79void pointing_device_set_report(report_mouse_t newMouseReport);
29bool has_mouse_report_changed(report_mouse_t new, report_mouse_t old); 80bool has_mouse_report_changed(report_mouse_t new, report_mouse_t old);
81uint16_t pointing_device_get_cpi(void);
82void pointing_device_set_cpi(uint16_t cpi);
83
84void pointing_device_init_kb(void);
85void pointing_device_init_user(void);
86report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report);
87report_mouse_t pointing_device_task_user(report_mouse_t mouse_report);
88uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button);
diff --git a/quantum/pointing_device_drivers.c b/quantum/pointing_device_drivers.c
new file mode 100644
index 000000000..9ad5e76ba
--- /dev/null
+++ b/quantum/pointing_device_drivers.c
@@ -0,0 +1,262 @@
1/* Copyright 2017 Joshua Broekhuijsen <snipeye+qmk@gmail.com>
2 * Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
3 * Copyright 2021 Dasky (@daskygit)
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "pointing_device.h"
20#include "debug.h"
21#include "wait.h"
22#include "timer.h"
23#include <stddef.h>
24
25// hid mouse reports cannot exceed -127 to 127, so constrain to that value
26#define constrain_hid(amt) ((amt) < -127 ? -127 : ((amt) > 127 ? 127 : (amt)))
27
28// get_report functions should probably be moved to their respective drivers.
29#if defined(POINTING_DEVICE_DRIVER_adns5050)
30report_mouse_t adns5050_get_report(report_mouse_t mouse_report) {
31 report_adns5050_t data = adns5050_read_burst();
32
33 if (data.dx != 0 || data.dy != 0) {
34# ifdef CONSOLE_ENABLE
35 if (debug_mouse) dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy);
36# endif
37
38 mouse_report.x = data.dx;
39 mouse_report.y = data.dy;
40 }
41
42 return mouse_report;
43}
44
45// clang-format off
46const pointing_device_driver_t pointing_device_driver = {
47 .init = adns5050_init,
48 .get_report = adns5050_get_report,
49 .set_cpi = adns5050_set_cpi,
50 .get_cpi = adns5050_get_cpi,
51};
52// clang-format on
53#elif defined(POINTING_DEVICE_DRIVER_adns9800)
54
55report_mouse_t adns9800_get_report_driver(report_mouse_t mouse_report) {
56 report_adns9800_t sensor_report = adns9800_get_report();
57
58 int8_t clamped_x = constrain_hid(sensor_report.x);
59 int8_t clamped_y = constrain_hid(sensor_report.y);
60
61 mouse_report.x = clamped_x;
62 mouse_report.y = clamped_y;
63
64 return mouse_report;
65}
66
67// clang-format off
68const pointing_device_driver_t pointing_device_driver = {
69 .init = adns9800_init,
70 .get_report = adns9800_get_report_driver,
71 .set_cpi = adns9800_set_cpi,
72 .get_cpi = adns9800_get_cpi
73};
74// clang-format on
75#elif defined(POINTING_DEVICE_DRIVER_analog_joystick)
76report_mouse_t analog_joystick_get_report(report_mouse_t mouse_report) {
77 report_analog_joystick_t data = analog_joystick_read();
78
79# ifdef CONSOLE_ENABLE
80 if (debug_mouse) dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y);
81# endif
82
83 mouse_report.x = data.x;
84 mouse_report.y = data.y;
85
86 mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, data.button, POINTING_DEVICE_BUTTON1);
87
88 return mouse_report;
89}
90
91// clang-format off
92const pointing_device_driver_t pointing_device_driver = {
93 .init = analog_joystick_init,
94 .get_report = analog_joystick_get_report,
95 .set_cpi = NULL,
96 .get_cpi = NULL
97};
98// clang-format on
99#elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c) || defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi)
100# ifndef CIRQUE_PINNACLE_TAPPING_TERM
101# ifdef TAPPING_TERM_PER_KEY
102# include "action.h"
103# include "action_tapping.h"
104# define CIRQUE_PINNACLE_TAPPING_TERM get_tapping_term(KC_BTN1, NULL)
105# else
106# ifdef TAPPING_TERM
107# define CIRQUE_PINNACLE_TAPPING_TERM TAPPING_TERM
108# else
109# define CIRQUE_PINNACLE_TAPPING_TERM 200
110# endif
111# endif
112# endif
113# ifndef CIRQUE_PINNACLE_TOUCH_DEBOUNCE
114# define CIRQUE_PINNACLE_TOUCH_DEBOUNCE (CIRQUE_PINNACLE_TAPPING_TERM * 8)
115# endif
116
117report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) {
118 pinnacle_data_t touchData = cirque_pinnacle_read_data();
119 static uint16_t x = 0, y = 0, mouse_timer = 0;
120 int8_t report_x = 0, report_y = 0;
121 static bool is_z_down = false;
122
123 cirque_pinnacle_scale_data(&touchData, cirque_pinnacle_get_scale(), cirque_pinnacle_get_scale()); // Scale coordinates to arbitrary X, Y resolution
124
125 if (x && y && touchData.xValue && touchData.yValue) {
126 report_x = (int8_t)(touchData.xValue - x);
127 report_y = (int8_t)(touchData.yValue - y);
128 }
129 x = touchData.xValue;
130 y = touchData.yValue;
131
132 if ((bool)touchData.zValue != is_z_down) {
133 is_z_down = (bool)touchData.zValue;
134 if (!touchData.zValue) {
135 if (timer_elapsed(mouse_timer) < CIRQUE_PINNACLE_TAPPING_TERM && mouse_timer != 0) {
136 mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON1);
137 pointing_device_set_report(mouse_report);
138 pointing_device_send();
139# if TAP_CODE_DELAY > 0
140 wait_ms(TAP_CODE_DELAY);
141# endif
142 mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, false, POINTING_DEVICE_BUTTON1);
143 pointing_device_set_report(mouse_report);
144 pointing_device_send();
145 }
146 }
147 mouse_timer = timer_read();
148 }
149 if (timer_elapsed(mouse_timer) > (CIRQUE_PINNACLE_TOUCH_DEBOUNCE)) {
150 mouse_timer = 0;
151 }
152 mouse_report.x = report_x;
153 mouse_report.y = report_y;
154
155 return mouse_report;
156}
157
158// clang-format off
159const pointing_device_driver_t pointing_device_driver = {
160 .init = cirque_pinnacle_init,
161 .get_report = cirque_pinnacle_get_report,
162 .set_cpi = cirque_pinnacle_set_scale,
163 .get_cpi = cirque_pinnacle_get_scale
164};
165// clang-format on
166
167#elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball)
168report_mouse_t pimorono_trackball_get_report(report_mouse_t mouse_report) {
169 static fast_timer_t throttle = 0;
170 static uint16_t debounce = 0;
171 static uint8_t error_count = 0;
172 pimoroni_data_t pimoroni_data = {0};
173 static int16_t x_offset = 0, y_offset = 0;
174
175 if (error_count < PIMORONI_TRACKBALL_ERROR_COUNT && timer_elapsed_fast(throttle) >= PIMORONI_TRACKBALL_INTERVAL_MS) {
176 i2c_status_t status = read_pimoroni_trackball(&pimoroni_data);
177
178 if (status == I2C_STATUS_SUCCESS) {
179 error_count = 0;
180
181 if (!(pimoroni_data.click & 128)) {
182 mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, false, POINTING_DEVICE_BUTTON1);
183 if (!debounce) {
184 x_offset += pimoroni_trackball_get_offsets(pimoroni_data.right, pimoroni_data.left, PIMORONI_TRACKBALL_SCALE);
185 y_offset += pimoroni_trackball_get_offsets(pimoroni_data.down, pimoroni_data.up, PIMORONI_TRACKBALL_SCALE);
186 pimoroni_trackball_adapt_values(&mouse_report.x, &x_offset);
187 pimoroni_trackball_adapt_values(&mouse_report.y, &y_offset);
188 } else {
189 debounce--;
190 }
191 } else {
192 mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON1);
193 debounce = PIMORONI_TRACKBALL_DEBOUNCE_CYCLES;
194 }
195 } else {
196 error_count++;
197 }
198 throttle = timer_read_fast();
199 }
200 return mouse_report;
201}
202
203// clang-format off
204const pointing_device_driver_t pointing_device_driver = {
205 .init = pimironi_trackball_device_init,
206 .get_report = pimorono_trackball_get_report,
207 .set_cpi = NULL,
208 .get_cpi = NULL
209};
210// clang-format on
211#elif defined(POINTING_DEVICE_DRIVER_pmw3360)
212
213static void init(void) { pmw3360_init(); }
214
215report_mouse_t pmw3360_get_report(report_mouse_t mouse_report) {
216 report_pmw3360_t data = pmw3360_read_burst();
217 static uint16_t MotionStart = 0; // Timer for accel, 0 is resting state
218
219 if (data.isOnSurface && data.isMotion) {
220 // Reset timer if stopped moving
221 if (!data.isMotion) {
222 if (MotionStart != 0) MotionStart = 0;
223 return mouse_report;
224 }
225
226 // Set timer if new motion
227 if ((MotionStart == 0) && data.isMotion) {
228# ifdef CONSOLE_ENABLE
229 if (debug_mouse) dprintf("Starting motion.\n");
230# endif
231 MotionStart = timer_read();
232 }
233 mouse_report.x = constrain_hid(data.dx);
234 mouse_report.y = constrain_hid(data.dy);
235 }
236
237 return mouse_report;
238}
239
240// clang-format off
241const pointing_device_driver_t pointing_device_driver = {
242 .init = init,
243 .get_report = pmw3360_get_report,
244 .set_cpi = pmw3360_set_cpi,
245 .get_cpi = pmw3360_get_cpi
246};
247// clang-format on
248#else
249__attribute__((weak)) void pointing_device_driver_init(void) {}
250__attribute__((weak)) report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report) { return mouse_report; }
251__attribute__((weak)) uint16_t pointing_device_driver_get_cpi(void) { return 0; }
252__attribute__((weak)) void pointing_device_driver_set_cpi(uint16_t cpi) {}
253
254// clang-format off
255const pointing_device_driver_t pointing_device_driver = {
256 .init = pointing_device_driver_init,
257 .get_report = pointing_device_driver_get_report,
258 .get_cpi = pointing_device_driver_get_cpi,
259 .set_cpi = pointing_device_driver_set_cpi
260};
261// clang-format on
262#endif
diff --git a/quantum/quantum.c b/quantum/quantum.c
index 0eca329f0..c7a3bb197 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -531,6 +531,10 @@ void suspend_power_down_quantum(void) {
531# ifdef ST7565_ENABLE 531# ifdef ST7565_ENABLE
532 st7565_off(); 532 st7565_off();
533# endif 533# endif
534# if defined(POINTING_DEVICE_ENABLE)
535 // run to ensure scanning occurs while suspended
536 pointing_device_task();
537# endif
534#endif 538#endif
535} 539}
536 540
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 9250f5acc..e6015adbe 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -204,6 +204,10 @@ extern layer_state_t layer_state;
204# include "encoder.h" 204# include "encoder.h"
205#endif 205#endif
206 206
207#ifdef POINTING_DEVICE_ENABLE
208# include "pointing_device.h"
209#endif
210
207// For tri-layer 211// For tri-layer
208void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3); 212void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3);
209layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3); 213layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3);