aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrashna Jaelre <drashna@live.com>2020-09-27 15:11:41 -0700
committerGitHub <noreply@github.com>2020-09-27 15:11:41 -0700
commitfbdc65e2e956e9d51c94fecdbce1f0abc2817950 (patch)
treef7e31480856b1ce14a70941bc0641cb6647b688f
parent34b9c51d9cb9694e2e1d0667758f33054a2aad81 (diff)
downloadqmk_firmware-fbdc65e2e956e9d51c94fecdbce1f0abc2817950.tar.gz
qmk_firmware-fbdc65e2e956e9d51c94fecdbce1f0abc2817950.zip
[Keyboard] Add PloopyCo devices (#7935)
* Initial Commit for Ploopyco Trackball This is a WIP at this point. Most of it compiles, but the SPI commands are non-functioning as they come from Arduino, so don't exist in LUFA * Convert SPI commands from arduino to LUFA But I have no idea if this is actually correct or not * Update keyboard readme * Clean up ploopyco trackball * Update readme * Update mouse key stuff * last minutue cleanup * Add caveat about scroll wheel * Fixup to code * Additional fixup * Add movement multiplier * Rename folders * mid changes * temp * Got it working!!!!! * Additional cleanup of code * Make unused pin calls more compact * Rotation info * Add debouncing checks * Make everything replaceable * Add info.json * Include ISP flashing info * Better handling for user customization * Reconfigure CPI stuff * fix issues with debug printing * Fix tiny scroll issue * Add and update scroll code from ploopy mouse * Update licensing * Add PloopyCo Mouse * Cleanup and layout stuff * Move common files to main folder for reuse * Increase polling rate * Update image for mouse * Apply changes from code review * Add VIA support
-rw-r--r--keyboards/ploopyco/mouse/config.h73
-rw-r--r--keyboards/ploopyco/mouse/info.json21
-rw-r--r--keyboards/ploopyco/mouse/keymaps/default/keymap.c23
-rw-r--r--keyboards/ploopyco/mouse/keymaps/default/readme.md1
-rw-r--r--keyboards/ploopyco/mouse/keymaps/via/keymap.c26
-rw-r--r--keyboards/ploopyco/mouse/keymaps/via/rules.mk1
-rw-r--r--keyboards/ploopyco/mouse/mouse.c237
-rw-r--r--keyboards/ploopyco/mouse/mouse.h40
-rw-r--r--keyboards/ploopyco/mouse/readme.md68
-rw-r--r--keyboards/ploopyco/mouse/rules.mk30
-rw-r--r--keyboards/ploopyco/opt_encoder.c211
-rw-r--r--keyboards/ploopyco/opt_encoder.h66
-rw-r--r--keyboards/ploopyco/pmw3600.c222
-rw-r--r--keyboards/ploopyco/pmw3600.h103
-rw-r--r--keyboards/ploopyco/pmw3600_firmware.h300
-rw-r--r--keyboards/ploopyco/trackball/config.h69
-rw-r--r--keyboards/ploopyco/trackball/info.json18
-rw-r--r--keyboards/ploopyco/trackball/keymaps/default/keymap.c26
-rw-r--r--keyboards/ploopyco/trackball/keymaps/default/readme.md1
-rw-r--r--keyboards/ploopyco/trackball/keymaps/via/keymap.c26
-rw-r--r--keyboards/ploopyco/trackball/keymaps/via/rules.mk1
-rw-r--r--keyboards/ploopyco/trackball/readme.md68
-rw-r--r--keyboards/ploopyco/trackball/rules.mk30
-rw-r--r--keyboards/ploopyco/trackball/trackball.c237
-rw-r--r--keyboards/ploopyco/trackball/trackball.h40
25 files changed, 1938 insertions, 0 deletions
diff --git a/keyboards/ploopyco/mouse/config.h b/keyboards/ploopyco/mouse/config.h
new file mode 100644
index 000000000..787eb9a85
--- /dev/null
+++ b/keyboards/ploopyco/mouse/config.h
@@ -0,0 +1,73 @@
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#include "config_common.h"
22
23/* USB Device descriptor parameter */
24#define VENDOR_ID 0x5043
25#define PRODUCT_ID 0x4D6F
26#define DEVICE_VER 0x0001
27#define MANUFACTURER Ploopyco
28#define PRODUCT Mouse
29
30/* key matrix size */
31#define MATRIX_ROWS 1
32#define MATRIX_COLS 8
33
34/*
35 * Keyboard Matrix Assignments
36 *
37 * Change this to how you wired your keyboard
38 * COLS: AVR pins used for columns, left to right
39 * ROWS: AVR pins used for rows, top to bottom
40 * DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode)
41 * ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode)
42 *
43 */
44#define DIRECT_PINS \
45 { \
46 { D4, D2, E6, B6, D7, C6, C7, B7 } \
47 }
48
49// These pins are not broken out, and cannot be used normally.
50// They are set as output and pulled high, by default
51#define UNUSED_PINS \
52 { B4, D6, F1, F5, F6, F7 }
53
54/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
55#define DEBOUNCE 5
56
57/* Much more so than a keyboard, speed matters for a mouse. So we'll go for as high
58 a polling rate as possible. */
59#define USB_POLLING_INTERVAL_MS 1
60
61/* define if matrix has ghost (lacks anti-ghosting diodes) */
62//#define MATRIX_HAS_GHOST
63
64/* disable action features */
65//#define NO_ACTION_LAYER
66//#define NO_ACTION_TAPPING
67//#define NO_ACTION_ONESHOT
68#define NO_ACTION_MACRO
69#define NO_ACTION_FUNCTION
70
71/* Bootmagic Lite key configuration */
72#define BOOTMAGIC_LITE_ROW 0
73#define BOOTMAGIC_LITE_COLUMN 3
diff --git a/keyboards/ploopyco/mouse/info.json b/keyboards/ploopyco/mouse/info.json
new file mode 100644
index 000000000..6763838dc
--- /dev/null
+++ b/keyboards/ploopyco/mouse/info.json
@@ -0,0 +1,21 @@
1{
2 "keyboard_name": "PloopyCo Mouse",
3 "url": "",
4 "maintainer": "drashna",
5 "width": 8,
6 "height": 3,
7 "layouts": {
8 "LAYOUT": {
9 "layout": [
10 {"x":1, "y":0, "h":2},
11 {"x":2, "y":0, "h":2},
12 {"x":3, "y":0.25, "h":1.25},
13 {"x":4, "y":0, "h":2},
14 {"x":5, "y":0, "h":2},
15 {"x":0, "y":0},
16 {"x":0, "y":1},
17 {"x":3, "y":1.5}
18 ]
19 }
20 }
21}
diff --git a/keyboards/ploopyco/mouse/keymaps/default/keymap.c b/keyboards/ploopyco/mouse/keymaps/default/keymap.c
new file mode 100644
index 000000000..c02d23d2a
--- /dev/null
+++ b/keyboards/ploopyco/mouse/keymaps/default/keymap.c
@@ -0,0 +1,23 @@
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#include QMK_KEYBOARD_H
19
20const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
21 [0] = LAYOUT(/* Base */
22 C(KC_C), KC_BTN1, KC_BTN3, KC_BTN2, C(KC_C), KC_BTN4, KC_BTN5, C(KC_Z)),
23};
diff --git a/keyboards/ploopyco/mouse/keymaps/default/readme.md b/keyboards/ploopyco/mouse/keymaps/default/readme.md
new file mode 100644
index 000000000..f965ef3c3
--- /dev/null
+++ b/keyboards/ploopyco/mouse/keymaps/default/readme.md
@@ -0,0 +1 @@
# The default keymap for Ploopyco Trackball
diff --git a/keyboards/ploopyco/mouse/keymaps/via/keymap.c b/keyboards/ploopyco/mouse/keymaps/via/keymap.c
new file mode 100644
index 000000000..27a038438
--- /dev/null
+++ b/keyboards/ploopyco/mouse/keymaps/via/keymap.c
@@ -0,0 +1,26 @@
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#include QMK_KEYBOARD_H
19
20const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
21 [0] = LAYOUT(/* Base */
22 C(KC_C), KC_BTN1, KC_BTN3, KC_BTN2, C(KC_C), KC_BTN4, KC_BTN5, C(KC_Z)),
23 [1] = LAYOUT(_______, _______, _______, _______, _______, _______, _______, _______),
24 [2] = LAYOUT(_______, _______, _______, _______, _______, _______, _______, _______),
25 [3] = LAYOUT(_______, _______, _______, _______, _______, _______, _______, _______),
26};
diff --git a/keyboards/ploopyco/mouse/keymaps/via/rules.mk b/keyboards/ploopyco/mouse/keymaps/via/rules.mk
new file mode 100644
index 000000000..1e5b99807
--- /dev/null
+++ b/keyboards/ploopyco/mouse/keymaps/via/rules.mk
@@ -0,0 +1 @@
VIA_ENABLE = yes
diff --git a/keyboards/ploopyco/mouse/mouse.c b/keyboards/ploopyco/mouse/mouse.c
new file mode 100644
index 000000000..6a9bffbff
--- /dev/null
+++ b/keyboards/ploopyco/mouse/mouse.c
@@ -0,0 +1,237 @@
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#include QMK_KEYBOARD_H
20
21#ifndef OPT_DEBOUNCE
22# define OPT_DEBOUNCE 5 // (ms) Time between scroll events
23#endif
24#ifndef SCROLL_BUTT_DEBOUNCE
25# define SCROLL_BUTT_DEBOUNCE 100 // (ms) Time between scroll events
26#endif
27#ifndef OPT_THRES
28# define OPT_THRES 150 // (0-1024) Threshold for actication
29#endif
30#ifndef OPT_SCALE
31# define OPT_SCALE 1 // Multiplier for wheel
32#endif
33
34// TODO: Implement libinput profiles
35// https://wayland.freedesktop.org/libinput/doc/latest/pointer-acceleration.html
36// Compile time accel selection
37// Valid options are ACC_NONE, ACC_LINEAR, ACC_CUSTOM, ACC_QUADRATIC
38
39// Trackball State
40bool is_scroll_clicked = false;
41bool BurstState = false; // init burst state for Trackball module
42uint16_t MotionStart = 0; // Timer for accel, 0 is resting state
43uint16_t lastScroll = 0; // Previous confirmed wheel event
44uint16_t lastMidClick = 0; // Stops scrollwheel from being read if it was pressed
45uint8_t OptLowPin = OPT_ENC1;
46bool debug_encoder = false;
47
48__attribute__((weak)) void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v) {
49 mouse_report->h = h;
50 mouse_report->v = v;
51}
52
53__attribute__((weak)) void process_wheel(report_mouse_t* mouse_report) {
54 // TODO: Replace this with interrupt driven code, polling is S L O W
55 // Lovingly ripped from the Ploopy Source
56
57 // If the mouse wheel was just released, do not scroll.
58 if (timer_elapsed(lastMidClick) < SCROLL_BUTT_DEBOUNCE) {
59 return;
60 }
61
62 // Limit the number of scrolls per unit time.
63 if (timer_elapsed(lastScroll) < OPT_DEBOUNCE) {
64 return;
65 }
66
67 // Don't scroll if the middle button is depressed.
68 if (is_scroll_clicked) {
69#ifndef IGNORE_SCROLL_CLICK
70 return;
71#endif
72 }
73
74 lastScroll = timer_read();
75 uint16_t p1 = adc_read(OPT_ENC1_MUX);
76 uint16_t p2 = adc_read(OPT_ENC2_MUX);
77 if (debug_encoder) dprintf("OPT1: %d, OPT2: %d\n", p1, p2);
78
79 uint8_t dir = opt_encoder_handler(p1, p2);
80
81 if (dir == 0) return;
82 process_wheel_user(mouse_report, mouse_report->h, (int)(mouse_report->v + (dir * OPT_SCALE)));
83}
84
85__attribute__((weak)) void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y) {
86 mouse_report->x = x;
87 mouse_report->y = y;
88}
89
90__attribute__((weak)) void process_mouse(report_mouse_t* mouse_report) {
91 report_pmw_t data = pmw_read_burst();
92 if (data.isOnSurface && data.isMotion) {
93 // Reset timer if stopped moving
94 if (!data.isMotion) {
95 if (MotionStart != 0) MotionStart = 0;
96 return;
97 }
98
99 // Set timer if new motion
100 if ((MotionStart == 0) && data.isMotion) {
101 if (debug_mouse) dprintf("Starting motion.\n");
102 MotionStart = timer_read();
103 }
104
105 if (debug_mouse) {
106 dprintf("Delt] d: %d t: %u\n", abs(data.dx) + abs(data.dy), MotionStart);
107 }
108 if (debug_mouse) {
109 dprintf("Pre ] X: %d, Y: %d\n", data.dx, data.dy);
110 }
111#if defined(PROFILE_LINEAR)
112 float scale = float(timer_elaspsed(MotionStart)) / 1000.0;
113 data.dx *= scale;
114 data.dy *= scale;
115#elif defined(PROFILE_INVERSE)
116 // TODO
117#else
118 // no post processing
119#endif
120 // apply multiplier
121 // data.dx *= mouse_multiplier;
122 // data.dy *= mouse_multiplier;
123
124 // Wrap to HID size
125 data.dx = constrain(data.dx, -127, 127);
126 data.dy = constrain(data.dy, -127, 127);
127 if (debug_mouse) dprintf("Cons] X: %d, Y: %d\n", data.dx, data.dy);
128 // dprintf("Elapsed:%u, X: %f Y: %\n", i, pgm_read_byte(firmware_data+i));
129
130 process_mouse_user(mouse_report, data.dx, data.dy);
131 }
132}
133
134bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
135 if (debug_mouse) {
136 dprintf("KL: kc: %u, col: %u, row: %u, pressed: %u\n", keycode, record->event.key.col, record->event.key.row, record->event.pressed);
137 }
138
139 // Update Timer to prevent accidental scrolls
140 if ((record->event.key.col == 2) && (record->event.key.row == 0)) {
141 lastMidClick = timer_read();
142 is_scroll_clicked = record->event.pressed;
143 }
144
145/* If Mousekeys is disabled, then use handle the mouse button
146 * keycodes. This makes things simpler, and allows usage of
147 * the keycodes in a consistent manner. But only do this if
148 * Mousekeys is not enable, so it's not handled twice.
149 */
150#ifndef MOUSEKEY_ENABLE
151 if (IS_MOUSEKEY_BUTTON(keycode)) {
152 report_mouse_t currentReport = pointing_device_get_report();
153 if (record->event.pressed) {
154 if (keycode == KC_MS_BTN1)
155 currentReport.buttons |= MOUSE_BTN1;
156 else if (keycode == KC_MS_BTN2)
157 currentReport.buttons |= MOUSE_BTN2;
158 else if (keycode == KC_MS_BTN3)
159 currentReport.buttons |= MOUSE_BTN3;
160 else if (keycode == KC_MS_BTN4)
161 currentReport.buttons |= MOUSE_BTN4;
162 else if (keycode == KC_MS_BTN5)
163 currentReport.buttons |= MOUSE_BTN5;
164 } else {
165 if (keycode == KC_MS_BTN1)
166 currentReport.buttons &= ~MOUSE_BTN1;
167 else if (keycode == KC_MS_BTN2)
168 currentReport.buttons &= ~MOUSE_BTN2;
169 else if (keycode == KC_MS_BTN3)
170 currentReport.buttons &= ~MOUSE_BTN3;
171 else if (keycode == KC_MS_BTN4)
172 currentReport.buttons &= ~MOUSE_BTN4;
173 else if (keycode == KC_MS_BTN5)
174 currentReport.buttons &= ~MOUSE_BTN5;
175 }
176 pointing_device_set_report(currentReport);
177 }
178#endif
179
180 return process_record_user(keycode, record);
181}
182
183// Hardware Setup
184void keyboard_pre_init_kb(void) {
185 // debug_enable = true;
186 // debug_matrix = true;
187 // debug_mouse = true;
188 // debug_encoder = true;
189
190 setPinInput(OPT_ENC1);
191 setPinInput(OPT_ENC2);
192
193 // This is the debug LED.
194 setPinOutput(F7);
195 writePin(F7, debug_enable);
196
197 /* Ground all output pins connected to ground. This provides additional
198 * pathways to ground. If you're messing with this, know this: driving ANY
199 * of these pins high will cause a short. On the MCU. Ka-blooey.
200 */
201#ifdef UNUSED_PINS
202 const pin_t unused_pins[] = UNUSED_PINS;
203
204 for (uint8_t i = 0; i < (sizeof(unused_pins) / sizeof(pin_t)); i++) {
205 setPinOutput(unused_pins[i]);
206 writePinLow(unused_pins[i]);
207 }
208#endif
209 keyboard_pre_init_user();
210}
211
212void pointing_device_init(void) {
213 // initialize ball sensor
214 pmw_spi_init();
215 // initialize the scroll wheel's optical encoder
216 opt_encoder_init();
217}
218
219bool has_report_changed (report_mouse_t first, report_mouse_t second) {
220 return !(
221 (!first.buttons && first.buttons == second.buttons) &&
222 (!first.x && first.x == second.x) &&
223 (!first.y && first.y == second.y) &&
224 (!first.h && first.h == second.h) &&
225 (!first.v && first.v == second.v) );
226}
227
228void pointing_device_task(void) {
229 report_mouse_t mouse_report = pointing_device_get_report();
230 process_wheel(&mouse_report);
231 process_mouse(&mouse_report);
232
233 pointing_device_set_report(mouse_report);
234 if (has_report_changed(mouse_report, pointing_device_get_report())) {
235 pointing_device_send();
236 }
237}
diff --git a/keyboards/ploopyco/mouse/mouse.h b/keyboards/ploopyco/mouse/mouse.h
new file mode 100644
index 000000000..3c89d64d8
--- /dev/null
+++ b/keyboards/ploopyco/mouse/mouse.h
@@ -0,0 +1,40 @@
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#include "quantum.h"
22#include "spi_master.h"
23#include "pmw3600.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);
36void process_wheel(report_mouse_t* mouse_report);
37void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v);
38
39#define LAYOUT(BLL, BL, BM, BR, BRR, BF, BB, BDPI) \
40 { {BL, BM, BR, BF, BB, BRR, BLL, BDPI}, }
diff --git a/keyboards/ploopyco/mouse/readme.md b/keyboards/ploopyco/mouse/readme.md
new file mode 100644
index 000000000..abfa643a4
--- /dev/null
+++ b/keyboards/ploopyco/mouse/readme.md
@@ -0,0 +1,68 @@
1# Ploopyco Mouse
2
3![Ploopyco Mouse](https://i.redd.it/bf7bkzqzeti51.jpg)
4
5It's a DIY, QMK Powered Trackball!!!!
6
7Everything works. However the scroll wheel has some issues and acts very odd.
8
9* Keyboard Maintainer: [PloopyCo](https://github.com/ploopyco), [Drashna Jael're](https://github.com/drashna/), [Germ](https://github.com/germ/)
10* Hardware Supported: ATMega32u4 8MHz(3.3v)
11* Hardware Availability: [Store](https://ploopy.co), [GitHub](https://github.com/ploopyco)
12
13Make example for this keyboard (after setting up your build environment):
14
15 make ploopyco/mouse:default:flash
16
17To jump to the bootloader, hold down "Button 4" (immediate right of the Mouse)
18
19See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
20
21# Customzing your PloopyCo Trackball
22
23While the defaults are designed so that it can be plugged in and used right away, there are a number of things that you may want to change. Such as adding DPI control, or to use the ball to scroll while holding a button. To allow for this sort of control, there is a callback for both the scroll wheel and the mouse censor.
24
25The default behavior for this is:
26
27```c
28void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v) {
29 mouse_report->h = h;
30 mouse_report->v = v;
31}
32
33void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y) {
34 mouse_report->x = x;
35 mouse_report->y = y;
36}
37```
38
39This should allow you to more heavily customize the behavior.
40
41Alternatively, the `process_wheel` and `process_mouse` functions can both be replaced too, to allow for even more functionality.
42
43Additionally, you can change the DPI/CPI or speed of the Mouse by calling `pmw_set_cpi` at any time. And tThe default can be changed by adding a define to the keymap's `config.h` file:
44
45 #define PMW_CPI 1600
46
47# Programming QMK-DFU onto the PloopyCo Mouse
48
49If you would rather have DFU on this board, you can use the QMK-DFU bootloader on the device. To do so, you want to run:
50
51 make ploopyco/trackball:default:production
52
53Once you have that, you'll need to [ISP Flash](https://docs.qmk.fm/#/isp_flashing_guide) the chip with the new bootloader hex file created (or the production hex), and set the fuses:
54
55
56| Fuse | Setting |
57|----------|------------------|
58| Low | `0xDF` |
59| High | `0xD8` or `0x98` |
60| Extended | `0xCB` |
61
62Original (Caterina) settings:
63
64| Fuse | Setting |
65|----------|------------------|
66| Low | `0xFF` |
67| High | `0xD8` |
68| Extended | `0xFE` |
diff --git a/keyboards/ploopyco/mouse/rules.mk b/keyboards/ploopyco/mouse/rules.mk
new file mode 100644
index 000000000..d77431b67
--- /dev/null
+++ b/keyboards/ploopyco/mouse/rules.mk
@@ -0,0 +1,30 @@
1# MCU name
2MCU = atmega32u4
3
4# Processor frequency
5F_CPU = 8000000
6
7# Bootloader selection
8BOOTLOADER = caterina
9
10# Build Options
11# change yes to no to disable
12#
13BOOTMAGIC_ENABLE = lite # Virtual DIP switch configuration
14EXTRAKEY_ENABLE = yes # Audio control and System control
15CONSOLE_ENABLE = yes # Console for debug
16COMMAND_ENABLE = no # Commands for debug and configuration
17# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
18SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
19# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
20NKRO_ENABLE = no # USB Nkey Rollover
21BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
22RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
23UNICODE_ENABLE = no # Unicode
24BLUETOOTH_ENABLE = no # Enable Bluetooth
25AUDIO_ENABLE = no # Audio output
26POINTING_DEVICE_ENABLE = yes
27MOUSEKEY_ENABLE = no # Mouse keys
28
29QUANTUM_LIB_SRC += analog.c spi_master.c
30SRC += pmw3600.c opt_encoder.c
diff --git a/keyboards/ploopyco/opt_encoder.c b/keyboards/ploopyco/opt_encoder.c
new file mode 100644
index 000000000..44bcd5eb8
--- /dev/null
+++ b/keyboards/ploopyco/opt_encoder.c
@@ -0,0 +1,211 @@
1/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
2 * Copyright 2020 Ploopy Corporation
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#include "opt_encoder.h"
18
19/* Setup function for the scroll wheel. Initializes
20 the relevant variables. */
21void opt_encoder_init(void) {
22 state = HIHI;
23 lohif = false;
24 hilof = false;
25 lowA = 1023;
26 highA = 0;
27 cLowA = false;
28 cHighA = false;
29 lowIndexA = 0;
30 highIndexA = 0;
31 lowOverflowA = false;
32 highOverflowA = false;
33 lowB = 1023;
34 highB = 0;
35 cLowB = false;
36 cHighB = false;
37 lowIndexB = 0;
38 highIndexB = 0;
39 lowOverflowB = false;
40 highOverflowB = false;
41 scrollThresholdA = 0;
42 scrollThresholdB = 0;
43}
44
45int opt_encoder_handler(int curA, int curB) {
46 if (lowOverflowA == false || highOverflowA == false) calculateThresholdA(curA);
47 if (lowOverflowB == false || highOverflowB == false) calculateThresholdB(curB);
48
49 bool LO = false;
50 bool HI = true;
51 bool sA, sB;
52 int ret = 0;
53
54 if (curA < scrollThresholdA)
55 sA = LO;
56 else
57 sA = HI;
58
59 if (curB < scrollThresholdB)
60 sB = LO;
61 else
62 sB = HI;
63
64 if (state == HIHI) {
65 if (sA == LO && sB == HI) {
66 state = LOHI;
67 if (hilof) {
68 ret = 1;
69 hilof = false;
70 }
71 } else if (sA == HI && sB == LO) {
72 state = HILO;
73 if (lohif) {
74 ret = -1;
75 lohif = false;
76 }
77 }
78 }
79
80 else if (state == HILO) {
81 if (sA == HI && sB == HI) {
82 state = HIHI;
83 hilof = true;
84 lohif = false;
85 } else if (sA == LO && sB == LO) {
86 state = LOLO;
87 hilof = true;
88 lohif = false;
89 }
90 }
91
92 else if (state == LOLO) {
93 if (sA == HI && sB == LO) {
94 state = HILO;
95 if (lohif) {
96 ret = 1;
97 lohif = false;
98 }
99 } else if (sA == LO && sB == HI) {
100 state = LOHI;
101 if (hilof) {
102 ret = -1;
103 hilof = false;
104 }
105 }
106 }
107
108 else { // state must be LOHI
109 if (sA == HI && sB == HI) {
110 state = HIHI;
111 lohif = true;
112 hilof = false;
113 } else if (sA == LO && sB == LO) {
114 state = LOLO;
115 lohif = true;
116 hilof = false;
117 }
118 }
119
120 return ret;
121}
122
123void calculateThresholdA(int curA) { scrollThresholdA = calculateThreshold(curA, &lowA, &highA, &cLowA, &cHighA, arLowA, arHighA, &lowIndexA, &highIndexA, &lowOverflowA, &highOverflowA); }
124
125void calculateThresholdB(int curB) { scrollThresholdB = calculateThreshold(curB, &lowB, &highB, &cLowB, &cHighB, arLowB, arHighB, &lowIndexB, &highIndexB, &lowOverflowB, &highOverflowB); }
126
127int calculateThreshold(int cur, int* low, int* high, bool* cLow, bool* cHigh, int arLow[], int arHigh[], int* lowIndex, int* highIndex, bool* lowOverflow, bool* highOverflow) {
128 if (cur < *low) *low = cur;
129 if (cur > *high) *high = cur;
130
131 int curThresh = thresholdEquation(*low, *high);
132 int range = *high - *low;
133
134 // The range is enforced to be over a certain limit because noise
135 // can cause erroneous readings, making these calculations unstable.
136 if (range >= SCROLL_THRESH_RANGE_LIM) {
137 if (cur < curThresh) {
138 if (*cHigh == true) {
139 // We were just high, and now we crossed to low.
140 // high reflects a sample of a high reading.
141 arHigh[*highIndex] = *high;
142 incrementIndex(highIndex, highOverflow);
143 int midpoint = ((*high - *low) / 2) + *low;
144 *low = midpoint;
145 *high = midpoint;
146 *cLow = false;
147 *cHigh = false;
148 } else {
149 *cLow = true;
150 }
151 }
152 if (cur > curThresh) {
153 if (*cLow == true) {
154 // We were just low, and now we crossed to high.
155 // low reflects a sample of a low reading.
156 arLow[*lowIndex] = *low;
157 incrementIndex(lowIndex, lowOverflow);
158 int midpoint = ((*high - *low) / 2) + *low;
159 *low = midpoint;
160 *high = midpoint;
161 *cLow = false;
162 *cHigh = false;
163 } else {
164 *cHigh = true;
165 }
166 }
167 }
168
169 int calcHigh = 0;
170 if (*highOverflow == true) {
171 for (int i = 0; i < SCROLLER_AR_SIZE; i++) {
172 calcHigh += arHigh[i];
173 }
174 calcHigh = calcHigh / SCROLLER_AR_SIZE;
175 } else if (*highIndex != 0) {
176 for (int i = 0; i < *highIndex; i++) {
177 calcHigh += arHigh[i];
178 }
179 calcHigh = calcHigh / *highIndex;
180 } else {
181 calcHigh = *high;
182 }
183
184 int calcLow = 0;
185 if (*lowOverflow == true) {
186 for (int i = 0; i < SCROLLER_AR_SIZE; i++) {
187 calcLow += arLow[i];
188 }
189 calcLow = calcLow / SCROLLER_AR_SIZE;
190 } else if (*lowIndex != 0) {
191 for (int i = 0; i < *lowIndex; i++) {
192 calcLow += arLow[i];
193 }
194 calcLow = calcLow / *lowIndex;
195 } else {
196 calcLow = *low;
197 }
198
199 return thresholdEquation(calcLow, calcHigh);
200}
201
202int thresholdEquation(int lo, int hi) { return ((hi - lo) / 3) + lo; }
203
204void incrementIndex(int* index, bool* ovflw) {
205 if (*index < SCROLLER_AR_SIZE - 1)
206 (*index)++;
207 else {
208 *index = 0;
209 *ovflw = true;
210 }
211}
diff --git a/keyboards/ploopyco/opt_encoder.h b/keyboards/ploopyco/opt_encoder.h
new file mode 100644
index 000000000..23a170d59
--- /dev/null
+++ b/keyboards/ploopyco/opt_encoder.h
@@ -0,0 +1,66 @@
1/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
2 * Copyright 2020 Ploopy Corporation
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#pragma once
18
19#include <stdbool.h>
20
21#ifndef SCROLLER_AR_SIZE
22# define SCROLLER_AR_SIZE 31
23#endif
24
25#ifndef SCROLL_THRESH_RANGE_LIM
26# define SCROLL_THRESH_RANGE_LIM 10
27#endif
28
29enum State { HIHI, HILO, LOLO, LOHI };
30
31enum State state;
32
33/* Variables used for scroll wheel functionality. */
34bool lohif;
35bool hilof;
36int lowA;
37int highA;
38bool cLowA;
39bool cHighA;
40int lowIndexA;
41int highIndexA;
42bool lowOverflowA;
43bool highOverflowA;
44int lowB;
45int highB;
46bool cLowB;
47bool cHighB;
48int lowIndexB;
49int highIndexB;
50bool lowOverflowB;
51bool highOverflowB;
52int scrollThresholdA;
53int scrollThresholdB;
54int arLowA[SCROLLER_AR_SIZE];
55int arHighA[SCROLLER_AR_SIZE];
56int arLowB[SCROLLER_AR_SIZE];
57int arHighB[SCROLLER_AR_SIZE];
58
59void calculateThresholdA(int curA);
60void calculateThresholdB(int curB);
61int calculateThreshold(int cur, int* low, int* high, bool* cLow, bool* cHigh, int arLow[], int arHigh[], int* lowIndex, int* highIndex, bool* lowOverflow, bool* highOverflow);
62int thresholdEquation(int lo, int hi);
63void incrementIndex(int* index, bool* ovflw);
64
65void opt_encoder_init(void);
66int opt_encoder_handler(int curA, int curB);
diff --git a/keyboards/ploopyco/pmw3600.c b/keyboards/ploopyco/pmw3600.c
new file mode 100644
index 000000000..93b47078a
--- /dev/null
+++ b/keyboards/ploopyco/pmw3600.c
@@ -0,0 +1,222 @@
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
20#include "pmw3600.h"
21#include "pmw3600_firmware.h"
22#ifdef CONSOLE_ENABLE
23# include "print.h"
24#endif
25bool _inBurst = false;
26
27#ifndef PMW_CPI
28# define PMW_CPI 1600
29#endif
30#ifndef SPI_DIVISOR
31# define SPI_DIVISOR 2
32#endif
33
34static const int8_t ROTATIONAL_TRANSFORM_ANGLE = 20;
35
36#ifdef CONSOLE_ENABLE
37void 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')); }
38#endif
39
40
41bool spi_start_adv(void) {
42 bool status = spi_start(SPI_SS_PIN, false, 3, SPI_DIVISOR);
43 wait_us(1);
44 return status;
45}
46
47void spi_stop_adv(void) {
48 wait_us(1);
49 spi_stop();
50}
51
52spi_status_t spi_write_adv(uint8_t reg_addr, uint8_t data) {
53 if (reg_addr != REG_Motion_Burst) {
54 _inBurst = false;
55 }
56
57 spi_start_adv();
58 // send address of the register, with MSBit = 1 to indicate it's a write
59 spi_status_t status = spi_write(reg_addr | 0x80);
60 status = spi_write(data);
61
62 // tSCLK-NCS for write operation
63 wait_us(20);
64
65 // tSWW/tSWR (=120us) minus tSCLK-NCS. Could be shortened, but is looks like a safe lower bound
66 wait_us(100);
67 spi_stop();
68 return status;
69}
70
71uint8_t spi_read_adv(uint8_t reg_addr) {
72 spi_start_adv();
73 // send adress of the register, with MSBit = 0 to indicate it's a read
74 spi_write(reg_addr & 0x7f);
75
76 uint8_t data = spi_read();
77
78 // tSCLK-NCS for read operation is 120ns
79 wait_us(1);
80
81 // tSRW/tSRR (=20us) minus tSCLK-NCS
82 wait_us(19);
83
84 spi_stop();
85 return data;
86}
87
88void pmw_set_cpi(uint16_t cpi) {
89 int cpival = constrain((cpi / 100) - 1, 0, 0x77); // limits to 0--119
90
91 spi_start_adv();
92 spi_write_adv(REG_Config1, cpival);
93 spi_stop();
94}
95
96bool pmw_spi_init(void) {
97 spi_init();
98 _inBurst = false;
99
100 spi_stop();
101 spi_start_adv();
102 spi_stop();
103
104 spi_write_adv(REG_Shutdown, 0xb6); // Shutdown first
105 wait_ms(300);
106
107 spi_start_adv();
108 wait_us(40);
109 spi_stop_adv();
110 wait_us(40);
111
112 spi_write_adv(REG_Power_Up_Reset, 0x5a);
113 wait_ms(50);
114
115 spi_read_adv(REG_Motion);
116 spi_read_adv(REG_Delta_X_L);
117 spi_read_adv(REG_Delta_X_H);
118 spi_read_adv(REG_Delta_Y_L);
119 spi_read_adv(REG_Delta_Y_H);
120
121 pmw_upload_firmware();
122
123 spi_write_adv(REG_Angle_Tune, constrain(ROTATIONAL_TRANSFORM_ANGLE, -30, 30));
124 spi_stop_adv();
125
126 wait_ms(10);
127 pmw_set_cpi(PMW_CPI);
128
129 wait_ms(1);
130
131 return pmw_check_signature();
132}
133
134void pmw_upload_firmware(void) {
135 spi_write_adv(REG_Config2, 0x00);
136
137 spi_write_adv(REG_SROM_Enable, 0x1d);
138
139 wait_ms(10);
140
141 spi_write_adv(REG_SROM_Enable, 0x18);
142
143 spi_start_adv();
144 spi_write(REG_SROM_Load_Burst | 0x80);
145 wait_us(15);
146
147 unsigned char c;
148 for (int i = 0; i < firmware_length; i++) {
149 c = (unsigned char)pgm_read_byte(firmware_data + i);
150 spi_write(c);
151 wait_us(15);
152 }
153 wait_us(200);
154
155 spi_read_adv(REG_SROM_ID);
156
157 spi_write_adv(REG_Config2, 0x00);
158
159 spi_stop();
160 wait_ms(10);
161}
162
163bool pmw_check_signature(void) {
164 uint8_t pid = spi_read_adv(REG_Product_ID);
165 uint8_t iv_pid = spi_read_adv(REG_Inverse_Product_ID);
166 uint8_t SROM_ver = spi_read_adv(REG_SROM_ID);
167 return (pid == 0x42 && iv_pid == 0xBD && SROM_ver == 0x04); // signature for SROM 0x04
168}
169
170report_pmw_t pmw_read_burst(void) {
171 if (!_inBurst) {
172#ifdef CONSOLE_ENABLE
173 dprintf("burst on");
174#endif
175 spi_write_adv(REG_Motion_Burst, 0x00);
176 _inBurst = true;
177 }
178
179 spi_start_adv();
180 spi_write(REG_Motion_Burst);
181 wait_us(35); // waits for tSRAD
182
183 report_pmw_t data;
184 data.motion = 0;
185 data.dx = 0;
186 data.mdx = 0;
187 data.dy = 0;
188 data.mdx = 0;
189
190 data.motion = spi_read();
191 spi_write(0x00); // skip Observation
192 data.dx = spi_read();
193 data.mdx = spi_read();
194 data.dy = spi_read();
195 data.mdy = spi_read();
196
197 spi_stop();
198
199#ifdef CONSOLE_ENABLE
200 print_byte(data.motion);
201 print_byte(data.dx);
202 print_byte(data.mdx);
203 print_byte(data.dy);
204 print_byte(data.mdy);
205 dprintf("\n");
206#endif
207
208 data.isMotion = (data.motion & 0x80) != 0;
209 data.isOnSurface = (data.motion & 0x08) == 0;
210 data.dx |= (data.mdx << 8);
211 data.dx = data.dx * -1;
212 data.dy |= (data.mdy << 8);
213 // data.dy = data.dy * -1;
214
215 spi_stop();
216
217 if (data.motion & 0b111) { // panic recovery, sometimes burst mode works weird.
218 _inBurst = false;
219 }
220
221 return data;
222}
diff --git a/keyboards/ploopyco/pmw3600.h b/keyboards/ploopyco/pmw3600.h
new file mode 100644
index 000000000..c1d5e3bad
--- /dev/null
+++ b/keyboards/ploopyco/pmw3600.h
@@ -0,0 +1,103 @@
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#include "spi_master.h"
22
23// Registers
24#define REG_Product_ID 0x00
25#define REG_Revision_ID 0x01
26#define REG_Motion 0x02
27#define REG_Delta_X_L 0x03
28#define REG_Delta_X_H 0x04
29#define REG_Delta_Y_L 0x05
30#define REG_Delta_Y_H 0x06
31#define REG_SQUAL 0x07
32#define REG_Raw_Data_Sum 0x08
33#define REG_Maximum_Raw_data 0x09
34#define REG_Minimum_Raw_data 0x0A
35#define REG_Shutter_Lower 0x0B
36#define REG_Shutter_Upper 0x0C
37#define REG_Control 0x0D
38#define REG_Config1 0x0F
39#define REG_Config2 0x10
40#define REG_Angle_Tune 0x11
41#define REG_Frame_Capture 0x12
42#define REG_SROM_Enable 0x13
43#define REG_Run_Downshift 0x14
44#define REG_Rest1_Rate_Lower 0x15
45#define REG_Rest1_Rate_Upper 0x16
46#define REG_Rest1_Downshift 0x17
47#define REG_Rest2_Rate_Lower 0x18
48#define REG_Rest2_Rate_Upper 0x19
49#define REG_Rest2_Downshift 0x1A
50#define REG_Rest3_Rate_Lower 0x1B
51#define REG_Rest3_Rate_Upper 0x1C
52#define REG_Observation 0x24
53#define REG_Data_Out_Lower 0x25
54#define REG_Data_Out_Upper 0x26
55#define REG_Raw_Data_Dump 0x29
56#define REG_SROM_ID 0x2A
57#define REG_Min_SQ_Run 0x2B
58#define REG_Raw_Data_Threshold 0x2C
59#define REG_Config5 0x2F
60#define REG_Power_Up_Reset 0x3A
61#define REG_Shutdown 0x3B
62#define REG_Inverse_Product_ID 0x3F
63#define REG_LiftCutoff_Tune3 0x41
64#define REG_Angle_Snap 0x42
65#define REG_LiftCutoff_Tune1 0x4A
66#define REG_Motion_Burst 0x50
67#define REG_LiftCutoff_Tune_Timeout 0x58
68#define REG_LiftCutoff_Tune_Min_Length 0x5A
69#define REG_SROM_Load_Burst 0x62
70#define REG_Lift_Config 0x63
71#define REG_Raw_Data_Burst 0x64
72#define REG_LiftCutoff_Tune2 0x65
73
74#ifdef CONSOLE_ENABLE
75void print_byte(uint8_t byte);
76#endif
77
78typedef struct {
79 int8_t motion;
80 bool isMotion; // True if a motion is detected.
81 bool isOnSurface; // True when a chip is on a surface
82 int16_t dx; // displacement on x directions. Unit: Count. (CPI * Count = Inch value)
83 int8_t mdx;
84 int16_t dy; // displacement on y directions.
85 int8_t mdy;
86} report_pmw_t;
87
88
89
90bool spi_start_adv(void);
91void spi_stop_adv(void);
92spi_status_t spi_write_adv(uint8_t reg_addr, uint8_t data);
93uint8_t spi_read_adv(uint8_t reg_addr);
94bool pmw_spi_init(void);
95void pmw_set_cpi(uint16_t cpi);
96void pmw_upload_firmware(void);
97bool pmw_check_signature(void);
98report_pmw_t pmw_read_burst(void);
99
100
101#define degToRad(angleInDegrees) ((angleInDegrees)*M_PI / 180.0)
102#define radToDeg(angleInRadians) ((angleInRadians)*180.0 / M_PI)
103#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
diff --git a/keyboards/ploopyco/pmw3600_firmware.h b/keyboards/ploopyco/pmw3600_firmware.h
new file mode 100644
index 000000000..cca5a6a4d
--- /dev/null
+++ b/keyboards/ploopyco/pmw3600_firmware.h
@@ -0,0 +1,300 @@
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// clang-format off
22// Firmware Blob foor PMW3360
23const uint16_t firmware_length = 4094;
24// clang-format off
25const uint8_t firmware_data[] PROGMEM = { // SROM 0x04
260x01, 0x04, 0x8e, 0x96, 0x6e, 0x77, 0x3e, 0xfe, 0x7e, 0x5f, 0x1d, 0xb8, 0xf2, 0x66, 0x4e,
270xff, 0x5d, 0x19, 0xb0, 0xc2, 0x04, 0x69, 0x54, 0x2a, 0xd6, 0x2e, 0xbf, 0xdd, 0x19, 0xb0,
280xc3, 0xe5, 0x29, 0xb1, 0xe0, 0x23, 0xa5, 0xa9, 0xb1, 0xc1, 0x00, 0x82, 0x67, 0x4c, 0x1a,
290x97, 0x8d, 0x79, 0x51, 0x20, 0xc7, 0x06, 0x8e, 0x7c, 0x7c, 0x7a, 0x76, 0x4f, 0xfd, 0x59,
300x30, 0xe2, 0x46, 0x0e, 0x9e, 0xbe, 0xdf, 0x1d, 0x99, 0x91, 0xa0, 0xa5, 0xa1, 0xa9, 0xd0,
310x22, 0xc6, 0xef, 0x5c, 0x1b, 0x95, 0x89, 0x90, 0xa2, 0xa7, 0xcc, 0xfb, 0x55, 0x28, 0xb3,
320xe4, 0x4a, 0xf7, 0x6c, 0x3b, 0xf4, 0x6a, 0x56, 0x2e, 0xde, 0x1f, 0x9d, 0xb8, 0xd3, 0x05,
330x88, 0x92, 0xa6, 0xce, 0x1e, 0xbe, 0xdf, 0x1d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x5c, 0x07,
340x11, 0x5d, 0x98, 0x0b, 0x9d, 0x94, 0x97, 0xee, 0x4e, 0x45, 0x33, 0x6b, 0x44, 0xc7, 0x29,
350x56, 0x27, 0x30, 0xc6, 0xa7, 0xd5, 0xf2, 0x56, 0xdf, 0xb4, 0x38, 0x62, 0xcb, 0xa0, 0xb6,
360xe3, 0x0f, 0x84, 0x06, 0x24, 0x05, 0x65, 0x6f, 0x76, 0x89, 0xb5, 0x77, 0x41, 0x27, 0x82,
370x66, 0x65, 0x82, 0xcc, 0xd5, 0xe6, 0x20, 0xd5, 0x27, 0x17, 0xc5, 0xf8, 0x03, 0x23, 0x7c,
380x5f, 0x64, 0xa5, 0x1d, 0xc1, 0xd6, 0x36, 0xcb, 0x4c, 0xd4, 0xdb, 0x66, 0xd7, 0x8b, 0xb1,
390x99, 0x7e, 0x6f, 0x4c, 0x36, 0x40, 0x06, 0xd6, 0xeb, 0xd7, 0xa2, 0xe4, 0xf4, 0x95, 0x51,
400x5a, 0x54, 0x96, 0xd5, 0x53, 0x44, 0xd7, 0x8c, 0xe0, 0xb9, 0x40, 0x68, 0xd2, 0x18, 0xe9,
410xdd, 0x9a, 0x23, 0x92, 0x48, 0xee, 0x7f, 0x43, 0xaf, 0xea, 0x77, 0x38, 0x84, 0x8c, 0x0a,
420x72, 0xaf, 0x69, 0xf8, 0xdd, 0xf1, 0x24, 0x83, 0xa3, 0xf8, 0x4a, 0xbf, 0xf5, 0x94, 0x13,
430xdb, 0xbb, 0xd8, 0xb4, 0xb3, 0xa0, 0xfb, 0x45, 0x50, 0x60, 0x30, 0x59, 0x12, 0x31, 0x71,
440xa2, 0xd3, 0x13, 0xe7, 0xfa, 0xe7, 0xce, 0x0f, 0x63, 0x15, 0x0b, 0x6b, 0x94, 0xbb, 0x37,
450x83, 0x26, 0x05, 0x9d, 0xfb, 0x46, 0x92, 0xfc, 0x0a, 0x15, 0xd1, 0x0d, 0x73, 0x92, 0xd6,
460x8c, 0x1b, 0x8c, 0xb8, 0x55, 0x8a, 0xce, 0xbd, 0xfe, 0x8e, 0xfc, 0xed, 0x09, 0x12, 0x83,
470x91, 0x82, 0x51, 0x31, 0x23, 0xfb, 0xb4, 0x0c, 0x76, 0xad, 0x7c, 0xd9, 0xb4, 0x4b, 0xb2,
480x67, 0x14, 0x09, 0x9c, 0x7f, 0x0c, 0x18, 0xba, 0x3b, 0xd6, 0x8e, 0x14, 0x2a, 0xe4, 0x1b,
490x52, 0x9f, 0x2b, 0x7d, 0xe1, 0xfb, 0x6a, 0x33, 0x02, 0xfa, 0xac, 0x5a, 0xf2, 0x3e, 0x88,
500x7e, 0xae, 0xd1, 0xf3, 0x78, 0xe8, 0x05, 0xd1, 0xe3, 0xdc, 0x21, 0xf6, 0xe1, 0x9a, 0xbd,
510x17, 0x0e, 0xd9, 0x46, 0x9b, 0x88, 0x03, 0xea, 0xf6, 0x66, 0xbe, 0x0e, 0x1b, 0x50, 0x49,
520x96, 0x40, 0x97, 0xf1, 0xf1, 0xe4, 0x80, 0xa6, 0x6e, 0xe8, 0x77, 0x34, 0xbf, 0x29, 0x40,
530x44, 0xc2, 0xff, 0x4e, 0x98, 0xd3, 0x9c, 0xa3, 0x32, 0x2b, 0x76, 0x51, 0x04, 0x09, 0xe7,
540xa9, 0xd1, 0xa6, 0x32, 0xb1, 0x23, 0x53, 0xe2, 0x47, 0xab, 0xd6, 0xf5, 0x69, 0x5c, 0x3e,
550x5f, 0xfa, 0xae, 0x45, 0x20, 0xe5, 0xd2, 0x44, 0xff, 0x39, 0x32, 0x6d, 0xfd, 0x27, 0x57,
560x5c, 0xfd, 0xf0, 0xde, 0xc1, 0xb5, 0x99, 0xe5, 0xf5, 0x1c, 0x77, 0x01, 0x75, 0xc5, 0x6d,
570x58, 0x92, 0xf2, 0xb2, 0x47, 0x00, 0x01, 0x26, 0x96, 0x7a, 0x30, 0xff, 0xb7, 0xf0, 0xef,
580x77, 0xc1, 0x8a, 0x5d, 0xdc, 0xc0, 0xd1, 0x29, 0x30, 0x1e, 0x77, 0x38, 0x7a, 0x94, 0xf1,
590xb8, 0x7a, 0x7e, 0xef, 0xa4, 0xd1, 0xac, 0x31, 0x4a, 0xf2, 0x5d, 0x64, 0x3d, 0xb2, 0xe2,
600xf0, 0x08, 0x99, 0xfc, 0x70, 0xee, 0x24, 0xa7, 0x7e, 0xee, 0x1e, 0x20, 0x69, 0x7d, 0x44,
610xbf, 0x87, 0x42, 0xdf, 0x88, 0x3b, 0x0c, 0xda, 0x42, 0xc9, 0x04, 0xf9, 0x45, 0x50, 0xfc,
620x83, 0x8f, 0x11, 0x6a, 0x72, 0xbc, 0x99, 0x95, 0xf0, 0xac, 0x3d, 0xa7, 0x3b, 0xcd, 0x1c,
630xe2, 0x88, 0x79, 0x37, 0x11, 0x5f, 0x39, 0x89, 0x95, 0x0a, 0x16, 0x84, 0x7a, 0xf6, 0x8a,
640xa4, 0x28, 0xe4, 0xed, 0x83, 0x80, 0x3b, 0xb1, 0x23, 0xa5, 0x03, 0x10, 0xf4, 0x66, 0xea,
650xbb, 0x0c, 0x0f, 0xc5, 0xec, 0x6c, 0x69, 0xc5, 0xd3, 0x24, 0xab, 0xd4, 0x2a, 0xb7, 0x99,
660x88, 0x76, 0x08, 0xa0, 0xa8, 0x95, 0x7c, 0xd8, 0x38, 0x6d, 0xcd, 0x59, 0x02, 0x51, 0x4b,
670xf1, 0xb5, 0x2b, 0x50, 0xe3, 0xb6, 0xbd, 0xd0, 0x72, 0xcf, 0x9e, 0xfd, 0x6e, 0xbb, 0x44,
680xc8, 0x24, 0x8a, 0x77, 0x18, 0x8a, 0x13, 0x06, 0xef, 0x97, 0x7d, 0xfa, 0x81, 0xf0, 0x31,
690xe6, 0xfa, 0x77, 0xed, 0x31, 0x06, 0x31, 0x5b, 0x54, 0x8a, 0x9f, 0x30, 0x68, 0xdb, 0xe2,
700x40, 0xf8, 0x4e, 0x73, 0xfa, 0xab, 0x74, 0x8b, 0x10, 0x58, 0x13, 0xdc, 0xd2, 0xe6, 0x78,
710xd1, 0x32, 0x2e, 0x8a, 0x9f, 0x2c, 0x58, 0x06, 0x48, 0x27, 0xc5, 0xa9, 0x5e, 0x81, 0x47,
720x89, 0x46, 0x21, 0x91, 0x03, 0x70, 0xa4, 0x3e, 0x88, 0x9c, 0xda, 0x33, 0x0a, 0xce, 0xbc,
730x8b, 0x8e, 0xcf, 0x9f, 0xd3, 0x71, 0x80, 0x43, 0xcf, 0x6b, 0xa9, 0x51, 0x83, 0x76, 0x30,
740x82, 0xc5, 0x6a, 0x85, 0x39, 0x11, 0x50, 0x1a, 0x82, 0xdc, 0x1e, 0x1c, 0xd5, 0x7d, 0xa9,
750x71, 0x99, 0x33, 0x47, 0x19, 0x97, 0xb3, 0x5a, 0xb1, 0xdf, 0xed, 0xa4, 0xf2, 0xe6, 0x26,
760x84, 0xa2, 0x28, 0x9a, 0x9e, 0xdf, 0xa6, 0x6a, 0xf4, 0xd6, 0xfc, 0x2e, 0x5b, 0x9d, 0x1a,
770x2a, 0x27, 0x68, 0xfb, 0xc1, 0x83, 0x21, 0x4b, 0x90, 0xe0, 0x36, 0xdd, 0x5b, 0x31, 0x42,
780x55, 0xa0, 0x13, 0xf7, 0xd0, 0x89, 0x53, 0x71, 0x99, 0x57, 0x09, 0x29, 0xc5, 0xf3, 0x21,
790xf8, 0x37, 0x2f, 0x40, 0xf3, 0xd4, 0xaf, 0x16, 0x08, 0x36, 0x02, 0xfc, 0x77, 0xc5, 0x8b,
800x04, 0x90, 0x56, 0xb9, 0xc9, 0x67, 0x9a, 0x99, 0xe8, 0x00, 0xd3, 0x86, 0xff, 0x97, 0x2d,
810x08, 0xe9, 0xb7, 0xb3, 0x91, 0xbc, 0xdf, 0x45, 0xc6, 0xed, 0x0f, 0x8c, 0x4c, 0x1e, 0xe6,
820x5b, 0x6e, 0x38, 0x30, 0xe4, 0xaa, 0xe3, 0x95, 0xde, 0xb9, 0xe4, 0x9a, 0xf5, 0xb2, 0x55,
830x9a, 0x87, 0x9b, 0xf6, 0x6a, 0xb2, 0xf2, 0x77, 0x9a, 0x31, 0xf4, 0x7a, 0x31, 0xd1, 0x1d,
840x04, 0xc0, 0x7c, 0x32, 0xa2, 0x9e, 0x9a, 0xf5, 0x62, 0xf8, 0x27, 0x8d, 0xbf, 0x51, 0xff,
850xd3, 0xdf, 0x64, 0x37, 0x3f, 0x2a, 0x6f, 0x76, 0x3a, 0x7d, 0x77, 0x06, 0x9e, 0x77, 0x7f,
860x5e, 0xeb, 0x32, 0x51, 0xf9, 0x16, 0x66, 0x9a, 0x09, 0xf3, 0xb0, 0x08, 0xa4, 0x70, 0x96,
870x46, 0x30, 0xff, 0xda, 0x4f, 0xe9, 0x1b, 0xed, 0x8d, 0xf8, 0x74, 0x1f, 0x31, 0x92, 0xb3,
880x73, 0x17, 0x36, 0xdb, 0x91, 0x30, 0xd6, 0x88, 0x55, 0x6b, 0x34, 0x77, 0x87, 0x7a, 0xe7,
890xee, 0x06, 0xc6, 0x1c, 0x8c, 0x19, 0x0c, 0x48, 0x46, 0x23, 0x5e, 0x9c, 0x07, 0x5c, 0xbf,
900xb4, 0x7e, 0xd6, 0x4f, 0x74, 0x9c, 0xe2, 0xc5, 0x50, 0x8b, 0xc5, 0x8b, 0x15, 0x90, 0x60,
910x62, 0x57, 0x29, 0xd0, 0x13, 0x43, 0xa1, 0x80, 0x88, 0x91, 0x00, 0x44, 0xc7, 0x4d, 0x19,
920x86, 0xcc, 0x2f, 0x2a, 0x75, 0x5a, 0xfc, 0xeb, 0x97, 0x2a, 0x70, 0xe3, 0x78, 0xd8, 0x91,
930xb0, 0x4f, 0x99, 0x07, 0xa3, 0x95, 0xea, 0x24, 0x21, 0xd5, 0xde, 0x51, 0x20, 0x93, 0x27,
940x0a, 0x30, 0x73, 0xa8, 0xff, 0x8a, 0x97, 0xe9, 0xa7, 0x6a, 0x8e, 0x0d, 0xe8, 0xf0, 0xdf,
950xec, 0xea, 0xb4, 0x6c, 0x1d, 0x39, 0x2a, 0x62, 0x2d, 0x3d, 0x5a, 0x8b, 0x65, 0xf8, 0x90,
960x05, 0x2e, 0x7e, 0x91, 0x2c, 0x78, 0xef, 0x8e, 0x7a, 0xc1, 0x2f, 0xac, 0x78, 0xee, 0xaf,
970x28, 0x45, 0x06, 0x4c, 0x26, 0xaf, 0x3b, 0xa2, 0xdb, 0xa3, 0x93, 0x06, 0xb5, 0x3c, 0xa5,
980xd8, 0xee, 0x8f, 0xaf, 0x25, 0xcc, 0x3f, 0x85, 0x68, 0x48, 0xa9, 0x62, 0xcc, 0x97, 0x8f,
990x7f, 0x2a, 0xea, 0xe0, 0x15, 0x0a, 0xad, 0x62, 0x07, 0xbd, 0x45, 0xf8, 0x41, 0xd8, 0x36,
1000xcb, 0x4c, 0xdb, 0x6e, 0xe6, 0x3a, 0xe7, 0xda, 0x15, 0xe9, 0x29, 0x1e, 0x12, 0x10, 0xa0,
1010x14, 0x2c, 0x0e, 0x3d, 0xf4, 0xbf, 0x39, 0x41, 0x92, 0x75, 0x0b, 0x25, 0x7b, 0xa3, 0xce,
1020x39, 0x9c, 0x15, 0x64, 0xc8, 0xfa, 0x3d, 0xef, 0x73, 0x27, 0xfe, 0x26, 0x2e, 0xce, 0xda,
1030x6e, 0xfd, 0x71, 0x8e, 0xdd, 0xfe, 0x76, 0xee, 0xdc, 0x12, 0x5c, 0x02, 0xc5, 0x3a, 0x4e,
1040x4e, 0x4f, 0xbf, 0xca, 0x40, 0x15, 0xc7, 0x6e, 0x8d, 0x41, 0xf1, 0x10, 0xe0, 0x4f, 0x7e,
1050x97, 0x7f, 0x1c, 0xae, 0x47, 0x8e, 0x6b, 0xb1, 0x25, 0x31, 0xb0, 0x73, 0xc7, 0x1b, 0x97,
1060x79, 0xf9, 0x80, 0xd3, 0x66, 0x22, 0x30, 0x07, 0x74, 0x1e, 0xe4, 0xd0, 0x80, 0x21, 0xd6,
1070xee, 0x6b, 0x6c, 0x4f, 0xbf, 0xf5, 0xb7, 0xd9, 0x09, 0x87, 0x2f, 0xa9, 0x14, 0xbe, 0x27,
1080xd9, 0x72, 0x50, 0x01, 0xd4, 0x13, 0x73, 0xa6, 0xa7, 0x51, 0x02, 0x75, 0x25, 0xe1, 0xb3,
1090x45, 0x34, 0x7d, 0xa8, 0x8e, 0xeb, 0xf3, 0x16, 0x49, 0xcb, 0x4f, 0x8c, 0xa1, 0xb9, 0x36,
1100x85, 0x39, 0x75, 0x5d, 0x08, 0x00, 0xae, 0xeb, 0xf6, 0xea, 0xd7, 0x13, 0x3a, 0x21, 0x5a,
1110x5f, 0x30, 0x84, 0x52, 0x26, 0x95, 0xc9, 0x14, 0xf2, 0x57, 0x55, 0x6b, 0xb1, 0x10, 0xc2,
1120xe1, 0xbd, 0x3b, 0x51, 0xc0, 0xb7, 0x55, 0x4c, 0x71, 0x12, 0x26, 0xc7, 0x0d, 0xf9, 0x51,
1130xa4, 0x38, 0x02, 0x05, 0x7f, 0xb8, 0xf1, 0x72, 0x4b, 0xbf, 0x71, 0x89, 0x14, 0xf3, 0x77,
1140x38, 0xd9, 0x71, 0x24, 0xf3, 0x00, 0x11, 0xa1, 0xd8, 0xd4, 0x69, 0x27, 0x08, 0x37, 0x35,
1150xc9, 0x11, 0x9d, 0x90, 0x1c, 0x0e, 0xe7, 0x1c, 0xff, 0x2d, 0x1e, 0xe8, 0x92, 0xe1, 0x18,
1160x10, 0x95, 0x7c, 0xe0, 0x80, 0xf4, 0x96, 0x43, 0x21, 0xf9, 0x75, 0x21, 0x64, 0x38, 0xdd,
1170x9f, 0x1e, 0x95, 0x16, 0xda, 0x56, 0x1d, 0x4f, 0x9a, 0x53, 0xb2, 0xe2, 0xe4, 0x18, 0xcb,
1180x6b, 0x1a, 0x65, 0xeb, 0x56, 0xc6, 0x3b, 0xe5, 0xfe, 0xd8, 0x26, 0x3f, 0x3a, 0x84, 0x59,
1190x72, 0x66, 0xa2, 0xf3, 0x75, 0xff, 0xfb, 0x60, 0xb3, 0x22, 0xad, 0x3f, 0x2d, 0x6b, 0xf9,
1200xeb, 0xea, 0x05, 0x7c, 0xd8, 0x8f, 0x6d, 0x2c, 0x98, 0x9e, 0x2b, 0x93, 0xf1, 0x5e, 0x46,
1210xf0, 0x87, 0x49, 0x29, 0x73, 0x68, 0xd7, 0x7f, 0xf9, 0xf0, 0xe5, 0x7d, 0xdb, 0x1d, 0x75,
1220x19, 0xf3, 0xc4, 0x58, 0x9b, 0x17, 0x88, 0xa8, 0x92, 0xe0, 0xbe, 0xbd, 0x8b, 0x1d, 0x8d,
1230x9f, 0x56, 0x76, 0xad, 0xaf, 0x29, 0xe2, 0xd9, 0xd5, 0x52, 0xf6, 0xb5, 0x56, 0x35, 0x57,
1240x3a, 0xc8, 0xe1, 0x56, 0x43, 0x19, 0x94, 0xd3, 0x04, 0x9b, 0x6d, 0x35, 0xd8, 0x0b, 0x5f,
1250x4d, 0x19, 0x8e, 0xec, 0xfa, 0x64, 0x91, 0x0a, 0x72, 0x20, 0x2b, 0xbc, 0x1a, 0x4a, 0xfe,
1260x8b, 0xfd, 0xbb, 0xed, 0x1b, 0x23, 0xea, 0xad, 0x72, 0x82, 0xa1, 0x29, 0x99, 0x71, 0xbd,
1270xf0, 0x95, 0xc1, 0x03, 0xdd, 0x7b, 0xc2, 0xb2, 0x3c, 0x28, 0x54, 0xd3, 0x68, 0xa4, 0x72,
1280xc8, 0x66, 0x96, 0xe0, 0xd1, 0xd8, 0x7f, 0xf8, 0xd1, 0x26, 0x2b, 0xf7, 0xad, 0xba, 0x55,
1290xca, 0x15, 0xb9, 0x32, 0xc3, 0xe5, 0x88, 0x97, 0x8e, 0x5c, 0xfb, 0x92, 0x25, 0x8b, 0xbf,
1300xa2, 0x45, 0x55, 0x7a, 0xa7, 0x6f, 0x8b, 0x57, 0x5b, 0xcf, 0x0e, 0xcb, 0x1d, 0xfb, 0x20,
1310x82, 0x77, 0xa8, 0x8c, 0xcc, 0x16, 0xce, 0x1d, 0xfa, 0xde, 0xcc, 0x0b, 0x62, 0xfe, 0xcc,
1320xe1, 0xb7, 0xf0, 0xc3, 0x81, 0x64, 0x73, 0x40, 0xa0, 0xc2, 0x4d, 0x89, 0x11, 0x75, 0x33,
1330x55, 0x33, 0x8d, 0xe8, 0x4a, 0xfd, 0xea, 0x6e, 0x30, 0x0b, 0xd7, 0x31, 0x2c, 0xde, 0x47,
1340xe3, 0xbf, 0xf8, 0x55, 0x42, 0xe2, 0x7f, 0x59, 0xe5, 0x17, 0xef, 0x99, 0x34, 0x69, 0x91,
1350xb1, 0x23, 0x8e, 0x20, 0x87, 0x2d, 0xa8, 0xfe, 0xd5, 0x8a, 0xf3, 0x84, 0x3a, 0xf0, 0x37,
1360xe4, 0x09, 0x00, 0x54, 0xee, 0x67, 0x49, 0x93, 0xe4, 0x81, 0x70, 0xe3, 0x90, 0x4d, 0xef,
1370xfe, 0x41, 0xb7, 0x99, 0x7b, 0xc1, 0x83, 0xba, 0x62, 0x12, 0x6f, 0x7d, 0xde, 0x6b, 0xaf,
1380xda, 0x16, 0xf9, 0x55, 0x51, 0xee, 0xa6, 0x0c, 0x2b, 0x02, 0xa3, 0xfd, 0x8d, 0xfb, 0x30,
1390x17, 0xe4, 0x6f, 0xdf, 0x36, 0x71, 0xc4, 0xca, 0x87, 0x25, 0x48, 0xb0, 0x47, 0xec, 0xea,
1400xb4, 0xbf, 0xa5, 0x4d, 0x9b, 0x9f, 0x02, 0x93, 0xc4, 0xe3, 0xe4, 0xe8, 0x42, 0x2d, 0x68,
1410x81, 0x15, 0x0a, 0xeb, 0x84, 0x5b, 0xd6, 0xa8, 0x74, 0xfb, 0x7d, 0x1d, 0xcb, 0x2c, 0xda,
1420x46, 0x2a, 0x76, 0x62, 0xce, 0xbc, 0x5c, 0x9e, 0x8b, 0xe7, 0xcf, 0xbe, 0x78, 0xf5, 0x7c,
1430xeb, 0xb3, 0x3a, 0x9c, 0xaa, 0x6f, 0xcc, 0x72, 0xd1, 0x59, 0xf2, 0x11, 0x23, 0xd6, 0x3f,
1440x48, 0xd1, 0xb7, 0xce, 0xb0, 0xbf, 0xcb, 0xea, 0x80, 0xde, 0x57, 0xd4, 0x5e, 0x97, 0x2f,
1450x75, 0xd1, 0x50, 0x8e, 0x80, 0x2c, 0x66, 0x79, 0xbf, 0x72, 0x4b, 0xbd, 0x8a, 0x81, 0x6c,
1460xd3, 0xe1, 0x01, 0xdc, 0xd2, 0x15, 0x26, 0xc5, 0x36, 0xda, 0x2c, 0x1a, 0xc0, 0x27, 0x94,
1470xed, 0xb7, 0x9b, 0x85, 0x0b, 0x5e, 0x80, 0x97, 0xc5, 0xec, 0x4f, 0xec, 0x88, 0x5d, 0x50,
1480x07, 0x35, 0x47, 0xdc, 0x0b, 0x3b, 0x3d, 0xdd, 0x60, 0xaf, 0xa8, 0x5d, 0x81, 0x38, 0x24,
1490x25, 0x5d, 0x5c, 0x15, 0xd1, 0xde, 0xb3, 0xab, 0xec, 0x05, 0x69, 0xef, 0x83, 0xed, 0x57,
1500x54, 0xb8, 0x64, 0x64, 0x11, 0x16, 0x32, 0x69, 0xda, 0x9f, 0x2d, 0x7f, 0x36, 0xbb, 0x44,
1510x5a, 0x34, 0xe8, 0x7f, 0xbf, 0x03, 0xeb, 0x00, 0x7f, 0x59, 0x68, 0x22, 0x79, 0xcf, 0x73,
1520x6c, 0x2c, 0x29, 0xa7, 0xa1, 0x5f, 0x38, 0xa1, 0x1d, 0xf0, 0x20, 0x53, 0xe0, 0x1a, 0x63,
1530x14, 0x58, 0x71, 0x10, 0xaa, 0x08, 0x0c, 0x3e, 0x16, 0x1a, 0x60, 0x22, 0x82, 0x7f, 0xba,
1540xa4, 0x43, 0xa0, 0xd0, 0xac, 0x1b, 0xd5, 0x6b, 0x64, 0xb5, 0x14, 0x93, 0x31, 0x9e, 0x53,
1550x50, 0xd0, 0x57, 0x66, 0xee, 0x5a, 0x4f, 0xfb, 0x03, 0x2a, 0x69, 0x58, 0x76, 0xf1, 0x83,
1560xf7, 0x4e, 0xba, 0x8c, 0x42, 0x06, 0x60, 0x5d, 0x6d, 0xce, 0x60, 0x88, 0xae, 0xa4, 0xc3,
1570xf1, 0x03, 0xa5, 0x4b, 0x98, 0xa1, 0xff, 0x67, 0xe1, 0xac, 0xa2, 0xb8, 0x62, 0xd7, 0x6f,
1580xa0, 0x31, 0xb4, 0xd2, 0x77, 0xaf, 0x21, 0x10, 0x06, 0xc6, 0x9a, 0xff, 0x1d, 0x09, 0x17,
1590x0e, 0x5f, 0xf1, 0xaa, 0x54, 0x34, 0x4b, 0x45, 0x8a, 0x87, 0x63, 0xa6, 0xdc, 0xf9, 0x24,
1600x30, 0x67, 0xc6, 0xb2, 0xd6, 0x61, 0x33, 0x69, 0xee, 0x50, 0x61, 0x57, 0x28, 0xe7, 0x7e,
1610xee, 0xec, 0x3a, 0x5a, 0x73, 0x4e, 0xa8, 0x8d, 0xe4, 0x18, 0xea, 0xec, 0x41, 0x64, 0xc8,
1620xe2, 0xe8, 0x66, 0xb6, 0x2d, 0xb6, 0xfb, 0x6a, 0x6c, 0x16, 0xb3, 0xdd, 0x46, 0x43, 0xb9,
1630x73, 0x00, 0x6a, 0x71, 0xed, 0x4e, 0x9d, 0x25, 0x1a, 0xc3, 0x3c, 0x4a, 0x95, 0x15, 0x99,
1640x35, 0x81, 0x14, 0x02, 0xd6, 0x98, 0x9b, 0xec, 0xd8, 0x23, 0x3b, 0x84, 0x29, 0xaf, 0x0c,
1650x99, 0x83, 0xa6, 0x9a, 0x34, 0x4f, 0xfa, 0xe8, 0xd0, 0x3c, 0x4b, 0xd0, 0xfb, 0xb6, 0x68,
1660xb8, 0x9e, 0x8f, 0xcd, 0xf7, 0x60, 0x2d, 0x7a, 0x22, 0xe5, 0x7d, 0xab, 0x65, 0x1b, 0x95,
1670xa7, 0xa8, 0x7f, 0xb6, 0x77, 0x47, 0x7b, 0x5f, 0x8b, 0x12, 0x72, 0xd0, 0xd4, 0x91, 0xef,
1680xde, 0x19, 0x50, 0x3c, 0xa7, 0x8b, 0xc4, 0xa9, 0xb3, 0x23, 0xcb, 0x76, 0xe6, 0x81, 0xf0,
1690xc1, 0x04, 0x8f, 0xa3, 0xb8, 0x54, 0x5b, 0x97, 0xac, 0x19, 0xff, 0x3f, 0x55, 0x27, 0x2f,
1700xe0, 0x1d, 0x42, 0x9b, 0x57, 0xfc, 0x4b, 0x4e, 0x0f, 0xce, 0x98, 0xa9, 0x43, 0x57, 0x03,
1710xbd, 0xe7, 0xc8, 0x94, 0xdf, 0x6e, 0x36, 0x73, 0x32, 0xb4, 0xef, 0x2e, 0x85, 0x7a, 0x6e,
1720xfc, 0x6c, 0x18, 0x82, 0x75, 0x35, 0x90, 0x07, 0xf3, 0xe4, 0x9f, 0x3e, 0xdc, 0x68, 0xf3,
1730xb5, 0xf3, 0x19, 0x80, 0x92, 0x06, 0x99, 0xa2, 0xe8, 0x6f, 0xff, 0x2e, 0x7f, 0xae, 0x42,
1740xa4, 0x5f, 0xfb, 0xd4, 0x0e, 0x81, 0x2b, 0xc3, 0x04, 0xff, 0x2b, 0xb3, 0x74, 0x4e, 0x36,
1750x5b, 0x9c, 0x15, 0x00, 0xc6, 0x47, 0x2b, 0xe8, 0x8b, 0x3d, 0xf1, 0x9c, 0x03, 0x9a, 0x58,
1760x7f, 0x9b, 0x9c, 0xbf, 0x85, 0x49, 0x79, 0x35, 0x2e, 0x56, 0x7b, 0x41, 0x14, 0x39, 0x47,
1770x83, 0x26, 0xaa, 0x07, 0x89, 0x98, 0x11, 0x1b, 0x86, 0xe7, 0x73, 0x7a, 0xd8, 0x7d, 0x78,
1780x61, 0x53, 0xe9, 0x79, 0xf5, 0x36, 0x8d, 0x44, 0x92, 0x84, 0xf9, 0x13, 0x50, 0x58, 0x3b,
1790xa4, 0x6a, 0x36, 0x65, 0x49, 0x8e, 0x3c, 0x0e, 0xf1, 0x6f, 0xd2, 0x84, 0xc4, 0x7e, 0x8e,
1800x3f, 0x39, 0xae, 0x7c, 0x84, 0xf1, 0x63, 0x37, 0x8e, 0x3c, 0xcc, 0x3e, 0x44, 0x81, 0x45,
1810xf1, 0x4b, 0xb9, 0xed, 0x6b, 0x36, 0x5d, 0xbb, 0x20, 0x60, 0x1a, 0x0f, 0xa3, 0xaa, 0x55,
1820x77, 0x3a, 0xa9, 0xae, 0x37, 0x4d, 0xba, 0xb8, 0x86, 0x6b, 0xbc, 0x08, 0x50, 0xf6, 0xcc,
1830xa4, 0xbd, 0x1d, 0x40, 0x72, 0xa5, 0x86, 0xfa, 0xe2, 0x10, 0xae, 0x3d, 0x58, 0x4b, 0x97,
1840xf3, 0x43, 0x74, 0xa9, 0x9e, 0xeb, 0x21, 0xb7, 0x01, 0xa4, 0x86, 0x93, 0x97, 0xee, 0x2f,
1850x4f, 0x3b, 0x86, 0xa1, 0x41, 0x6f, 0x41, 0x26, 0x90, 0x78, 0x5c, 0x7f, 0x30, 0x38, 0x4b,
1860x3f, 0xaa, 0xec, 0xed, 0x5c, 0x6f, 0x0e, 0xad, 0x43, 0x87, 0xfd, 0x93, 0x35, 0xe6, 0x01,
1870xef, 0x41, 0x26, 0x90, 0x99, 0x9e, 0xfb, 0x19, 0x5b, 0xad, 0xd2, 0x91, 0x8a, 0xe0, 0x46,
1880xaf, 0x65, 0xfa, 0x4f, 0x84, 0xc1, 0xa1, 0x2d, 0xcf, 0x45, 0x8b, 0xd3, 0x85, 0x50, 0x55,
1890x7c, 0xf9, 0x67, 0x88, 0xd4, 0x4e, 0xe9, 0xd7, 0x6b, 0x61, 0x54, 0xa1, 0xa4, 0xa6, 0xa2,
1900xc2, 0xbf, 0x30, 0x9c, 0x40, 0x9f, 0x5f, 0xd7, 0x69, 0x2b, 0x24, 0x82, 0x5e, 0xd9, 0xd6,
1910xa7, 0x12, 0x54, 0x1a, 0xf7, 0x55, 0x9f, 0x76, 0x50, 0xa9, 0x95, 0x84, 0xe6, 0x6b, 0x6d,
1920xb5, 0x96, 0x54, 0xd6, 0xcd, 0xb3, 0xa1, 0x9b, 0x46, 0xa7, 0x94, 0x4d, 0xc4, 0x94, 0xb4,
1930x98, 0xe3, 0xe1, 0xe2, 0x34, 0xd5, 0x33, 0x16, 0x07, 0x54, 0xcd, 0xb7, 0x77, 0x53, 0xdb,
1940x4f, 0x4d, 0x46, 0x9d, 0xe9, 0xd4, 0x9c, 0x8a, 0x36, 0xb6, 0xb8, 0x38, 0x26, 0x6c, 0x0e,
1950xff, 0x9c, 0x1b, 0x43, 0x8b, 0x80, 0xcc, 0xb9, 0x3d, 0xda, 0xc7, 0xf1, 0x8a, 0xf2, 0x6d,
1960xb8, 0xd7, 0x74, 0x2f, 0x7e, 0x1e, 0xb7, 0xd3, 0x4a, 0xb4, 0xac, 0xfc, 0x79, 0x48, 0x6c,
1970xbc, 0x96, 0xb6, 0x94, 0x46, 0x57, 0x2d, 0xb0, 0xa3, 0xfc, 0x1e, 0xb9, 0x52, 0x60, 0x85,
1980x2d, 0x41, 0xd0, 0x43, 0x01, 0x1e, 0x1c, 0xd5, 0x7d, 0xfc, 0xf3, 0x96, 0x0d, 0xc7, 0xcb,
1990x2a, 0x29, 0x9a, 0x93, 0xdd, 0x88, 0x2d, 0x37, 0x5d, 0xaa, 0xfb, 0x49, 0x68, 0xa0, 0x9c,
2000x50, 0x86, 0x7f, 0x68, 0x56, 0x57, 0xf9, 0x79, 0x18, 0x39, 0xd4, 0xe0, 0x01, 0x84, 0x33,
2010x61, 0xca, 0xa5, 0xd2, 0xd6, 0xe4, 0xc9, 0x8a, 0x4a, 0x23, 0x44, 0x4e, 0xbc, 0xf0, 0xdc,
2020x24, 0xa1, 0xa0, 0xc4, 0xe2, 0x07, 0x3c, 0x10, 0xc4, 0xb5, 0x25, 0x4b, 0x65, 0x63, 0xf4,
2030x80, 0xe7, 0xcf, 0x61, 0xb1, 0x71, 0x82, 0x21, 0x87, 0x2c, 0xf5, 0x91, 0x00, 0x32, 0x0c,
2040xec, 0xa9, 0xb5, 0x9a, 0x74, 0x85, 0xe3, 0x36, 0x8f, 0x76, 0x4f, 0x9c, 0x6d, 0xce, 0xbc,
2050xad, 0x0a, 0x4b, 0xed, 0x76, 0x04, 0xcb, 0xc3, 0xb9, 0x33, 0x9e, 0x01, 0x93, 0x96, 0x69,
2060x7d, 0xc5, 0xa2, 0x45, 0x79, 0x9b, 0x04, 0x5c, 0x84, 0x09, 0xed, 0x88, 0x43, 0xc7, 0xab,
2070x93, 0x14, 0x26, 0xa1, 0x40, 0xb5, 0xce, 0x4e, 0xbf, 0x2a, 0x42, 0x85, 0x3e, 0x2c, 0x3b,
2080x54, 0xe8, 0x12, 0x1f, 0x0e, 0x97, 0x59, 0xb2, 0x27, 0x89, 0xfa, 0xf2, 0xdf, 0x8e, 0x68,
2090x59, 0xdc, 0x06, 0xbc, 0xb6, 0x85, 0x0d, 0x06, 0x22, 0xec, 0xb1, 0xcb, 0xe5, 0x04, 0xe6,
2100x3d, 0xb3, 0xb0, 0x41, 0x73, 0x08, 0x3f, 0x3c, 0x58, 0x86, 0x63, 0xeb, 0x50, 0xee, 0x1d,
2110x2c, 0x37, 0x74, 0xa9, 0xd3, 0x18, 0xa3, 0x47, 0x6e, 0x93, 0x54, 0xad, 0x0a, 0x5d, 0xb8,
2120x2a, 0x55, 0x5d, 0x78, 0xf6, 0xee, 0xbe, 0x8e, 0x3c, 0x76, 0x69, 0xb9, 0x40, 0xc2, 0x34,
2130xec, 0x2a, 0xb9, 0xed, 0x7e, 0x20, 0xe4, 0x8d, 0x00, 0x38, 0xc7, 0xe6, 0x8f, 0x44, 0xa8,
2140x86, 0xce, 0xeb, 0x2a, 0xe9, 0x90, 0xf1, 0x4c, 0xdf, 0x32, 0xfb, 0x73, 0x1b, 0x6d, 0x92,
2150x1e, 0x95, 0xfe, 0xb4, 0xdb, 0x65, 0xdf, 0x4d, 0x23, 0x54, 0x89, 0x48, 0xbf, 0x4a, 0x2e,
2160x70, 0xd6, 0xd7, 0x62, 0xb4, 0x33, 0x29, 0xb1, 0x3a, 0x33, 0x4c, 0x23, 0x6d, 0xa6, 0x76,
2170xa5, 0x21, 0x63, 0x48, 0xe6, 0x90, 0x5d, 0xed, 0x90, 0x95, 0x0b, 0x7a, 0x84, 0xbe, 0xb8,
2180x0d, 0x5e, 0x63, 0x0c, 0x62, 0x26, 0x4c, 0x14, 0x5a, 0xb3, 0xac, 0x23, 0xa4, 0x74, 0xa7,
2190x6f, 0x33, 0x30, 0x05, 0x60, 0x01, 0x42, 0xa0, 0x28, 0xb7, 0xee, 0x19, 0x38, 0xf1, 0x64,
2200x80, 0x82, 0x43, 0xe1, 0x41, 0x27, 0x1f, 0x1f, 0x90, 0x54, 0x7a, 0xd5, 0x23, 0x2e, 0xd1,
2210x3d, 0xcb, 0x28, 0xba, 0x58, 0x7f, 0xdc, 0x7c, 0x91, 0x24, 0xe9, 0x28, 0x51, 0x83, 0x6e,
2220xc5, 0x56, 0x21, 0x42, 0xed, 0xa0, 0x56, 0x22, 0xa1, 0x40, 0x80, 0x6b, 0xa8, 0xf7, 0x94,
2230xca, 0x13, 0x6b, 0x0c, 0x39, 0xd9, 0xfd, 0xe9, 0xf3, 0x6f, 0xa6, 0x9e, 0xfc, 0x70, 0x8a,
2240xb3, 0xbc, 0x59, 0x3c, 0x1e, 0x1d, 0x6c, 0xf9, 0x7c, 0xaf, 0xf9, 0x88, 0x71, 0x95, 0xeb,
2250x57, 0x00, 0xbd, 0x9f, 0x8c, 0x4f, 0xe1, 0x24, 0x83, 0xc5, 0x22, 0xea, 0xfd, 0xd3, 0x0c,
2260xe2, 0x17, 0x18, 0x7c, 0x6a, 0x4c, 0xde, 0x77, 0xb4, 0x53, 0x9b, 0x4c, 0x81, 0xcd, 0x23,
2270x60, 0xaa, 0x0e, 0x25, 0x73, 0x9c, 0x02, 0x79, 0x32, 0x30, 0xdf, 0x74, 0xdf, 0x75, 0x19,
2280xf4, 0xa5, 0x14, 0x5c, 0xf7, 0x7a, 0xa8, 0xa5, 0x91, 0x84, 0x7c, 0x60, 0x03, 0x06, 0x3b,
2290xcd, 0x50, 0xb6, 0x27, 0x9c, 0xfe, 0xb1, 0xdd, 0xcc, 0xd3, 0xb0, 0x59, 0x24, 0xb2, 0xca,
2300xe2, 0x1c, 0x81, 0x22, 0x9d, 0x07, 0x8f, 0x8e, 0xb9, 0xbe, 0x4e, 0xfa, 0xfc, 0x39, 0x65,
2310xba, 0xbf, 0x9d, 0x12, 0x37, 0x5e, 0x97, 0x7e, 0xf3, 0x89, 0xf5, 0x5d, 0xf5, 0xe3, 0x09,
2320x8c, 0x62, 0xb5, 0x20, 0x9d, 0x0c, 0x53, 0x8a, 0x68, 0x1b, 0xd2, 0x8f, 0x75, 0x17, 0x5d,
2330xd4, 0xe5, 0xda, 0x75, 0x62, 0x19, 0x14, 0x6a, 0x26, 0x2d, 0xeb, 0xf8, 0xaf, 0x37, 0xf0,
2340x6c, 0xa4, 0x55, 0xb1, 0xbc, 0xe2, 0x33, 0xc0, 0x9a, 0xca, 0xb0, 0x11, 0x49, 0x4f, 0x68,
2350x9b, 0x3b, 0x6b, 0x3c, 0xcc, 0x13, 0xf6, 0xc7, 0x85, 0x61, 0x68, 0x42, 0xae, 0xbb, 0xdd,
2360xcd, 0x45, 0x16, 0x29, 0x1d, 0xea, 0xdb, 0xc8, 0x03, 0x94, 0x3c, 0xee, 0x4f, 0x82, 0x11,
2370xc3, 0xec, 0x28, 0xbd, 0x97, 0x05, 0x99, 0xde, 0xd7, 0xbb, 0x5e, 0x22, 0x1f, 0xd4, 0xeb,
2380x64, 0xd9, 0x92, 0xd9, 0x85, 0xb7, 0x6a, 0x05, 0x6a, 0xe4, 0x24, 0x41, 0xf1, 0xcd, 0xf0,
2390xd8, 0x3f, 0xf8, 0x9e, 0x0e, 0xcd, 0x0b, 0x7a, 0x70, 0x6b, 0x5a, 0x75, 0x0a, 0x6a, 0x33,
2400x88, 0xec, 0x17, 0x75, 0x08, 0x70, 0x10, 0x2f, 0x24, 0xcf, 0xc4, 0xe9, 0x42, 0x00, 0x61,
2410x94, 0xca, 0x1f, 0x3a, 0x76, 0x06, 0xfa, 0xd2, 0x48, 0x81, 0xf0, 0x77, 0x60, 0x03, 0x45,
2420xd9, 0x61, 0xf4, 0xa4, 0x6f, 0x3d, 0xd9, 0x30, 0xc3, 0x04, 0x6b, 0x54, 0x2a, 0xb7, 0xec,
2430x3b, 0xf4, 0x4b, 0xf5, 0x68, 0x52, 0x26, 0xce, 0xff, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xa5,
2440xa9, 0xb1, 0xe0, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0xf9, 0x51, 0x20, 0xa3, 0xa5, 0xa9, 0xb1,
2450xc1, 0x00, 0x82, 0x86, 0x8e, 0x7f, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xc4, 0xeb, 0x54, 0x0b,
2460x75, 0x68, 0x52, 0x07, 0x8c, 0x9a, 0x97, 0x8d, 0x79, 0x70, 0x62, 0x46, 0xef, 0x5c, 0x1b,
2470x95, 0x89, 0x71, 0x41, 0xe1, 0x21, 0xa1, 0xa1, 0xa1, 0xc0, 0x02, 0x67, 0x4c, 0x1a, 0xb6,
2480xcf, 0xfd, 0x78, 0x53, 0x24, 0xab, 0xb5, 0xc9, 0xf1, 0x60, 0x23, 0xa5, 0xc8, 0x12, 0x87,
2490x6d, 0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x6d, 0x58, 0x32, 0xc7, 0x0c, 0x9a, 0x97, 0xac,
2500xda, 0x36, 0xee, 0x5e, 0x3e, 0xdf, 0x1d, 0xb8, 0xf2, 0x66, 0x2f, 0xbd, 0xf8, 0x72, 0x47,
2510xed, 0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x8c, 0x7b, 0x55, 0x09, 0x90, 0xa2, 0xc6, 0xef,
2520x3d, 0xf8, 0x53, 0x24, 0xab, 0xd4, 0x2a, 0xb7, 0xec, 0x5a, 0x36, 0xee, 0x5e, 0x3e, 0xdf,
2530x3c, 0xfa, 0x76, 0x4f, 0xfd, 0x59, 0x30, 0xe2, 0x46, 0xef, 0x3d, 0xf8, 0x53, 0x05, 0x69,
2540x31, 0xc1, 0x00, 0x82, 0x86, 0x8e, 0x7f, 0x5d, 0x19, 0xb0, 0xe2, 0x27, 0xcc, 0xfb, 0x74,
2550x4b, 0x14, 0x8b, 0x94, 0x8b, 0x75, 0x68, 0x33, 0xc5, 0x08, 0x92, 0x87, 0x8c, 0x9a, 0xb6,
2560xcf, 0x1c, 0xba, 0xd7, 0x0d, 0x98, 0xb2, 0xe6, 0x2f, 0xdc, 0x1b, 0x95, 0x89, 0x71, 0x60,
2570x23, 0xc4, 0x0a, 0x96, 0x8f, 0x9c, 0xba, 0xf6, 0x6e, 0x3f, 0xfc, 0x5b, 0x15, 0xa8, 0xd2,
2580x26, 0xaf, 0xbd, 0xf8, 0x72, 0x66, 0x2f, 0xdc, 0x1b, 0xb4, 0xcb, 0x14, 0x8b, 0x94, 0xaa,
2590xb7, 0xcd, 0xf9, 0x51, 0x01, 0x80, 0x82, 0x86, 0x6f, 0x3d, 0xd9, 0x30, 0xe2, 0x27, 0xcc,
2600xfb, 0x74, 0x4b, 0x14, 0xaa, 0xb7, 0xcd, 0xf9, 0x70, 0x43, 0x04, 0x6b, 0x35, 0xc9, 0xf1,
2610x60, 0x23, 0xa5, 0xc8, 0xf3, 0x45, 0x08, 0x92, 0x87, 0x6d, 0x58, 0x32, 0xe6, 0x2f, 0xbd,
2620xf8, 0x72, 0x66, 0x4e, 0x1e, 0xbe, 0xfe, 0x7e, 0x7e, 0x7e, 0x5f, 0x1d, 0x99, 0x91, 0xa0,
2630xa3, 0xc4, 0x0a, 0x77, 0x4d, 0x18, 0x93, 0xa4, 0xab, 0xd4, 0x0b, 0x75, 0x49, 0x10, 0xa2,
2640xc6, 0xef, 0x3d, 0xf8, 0x53, 0x24, 0xab, 0xb5, 0xe8, 0x33, 0xe4, 0x4a, 0x16, 0xae, 0xde,
2650x1f, 0xbc, 0xdb, 0x15, 0xa8, 0xb3, 0xc5, 0x08, 0x73, 0x45, 0xe9, 0x31, 0xc1, 0xe1, 0x21,
2660xa1, 0xa1, 0xa1, 0xc0, 0x02, 0x86, 0x6f, 0x5c, 0x3a, 0xd7, 0x0d, 0x98, 0x93, 0xa4, 0xca,
2670x16, 0xae, 0xde, 0x1f, 0x9d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x3d, 0xf8, 0x72, 0x47, 0x0c,
2680x9a, 0xb6, 0xcf, 0xfd, 0x59, 0x11, 0xa0, 0xa3, 0xa5, 0xc8, 0xf3, 0x45, 0x08, 0x92, 0x87,
2690x6d, 0x39, 0xf0, 0x43, 0x04, 0x8a, 0x96, 0xae, 0xde, 0x3e, 0xdf, 0x1d, 0x99, 0x91, 0xa0,
2700xc2, 0x06, 0x6f, 0x3d, 0xf8, 0x72, 0x47, 0x0c, 0x9a, 0x97, 0x8d, 0x98, 0x93, 0x85, 0x88,
2710x73, 0x45, 0xe9, 0x31, 0xe0, 0x23, 0xa5, 0xa9, 0xd0, 0x03, 0x84, 0x8a, 0x96, 0xae, 0xde,
2720x1f, 0xbc, 0xdb, 0x15, 0xa8, 0xd2, 0x26, 0xce, 0xff, 0x5d, 0x19, 0x91, 0x81, 0x80, 0x82,
2730x67, 0x2d, 0xd8, 0x13, 0xa4, 0xab, 0xd4, 0x0b, 0x94, 0xaa, 0xb7, 0xcd, 0xf9, 0x51, 0x20,
2740xa3, 0xa5, 0xc8, 0xf3, 0x45, 0xe9, 0x50, 0x22, 0xc6, 0xef, 0x5c, 0x3a, 0xd7, 0x0d, 0x98,
2750x93, 0x85, 0x88, 0x73, 0x64, 0x4a, 0xf7, 0x4d, 0xf9, 0x51, 0x20, 0xa3, 0xc4, 0x0a, 0x96,
2760xae, 0xde, 0x3e, 0xfe, 0x7e, 0x7e, 0x7e, 0x5f, 0x3c, 0xfa, 0x76, 0x4f, 0xfd, 0x78, 0x72,
2770x66, 0x2f, 0xbd, 0xd9, 0x30, 0xc3, 0xe5, 0x48, 0x12, 0x87, 0x8c, 0x7b, 0x55, 0x28, 0xd2,
2780x07, 0x8c, 0x9a, 0x97, 0xac, 0xda, 0x17, 0x8d, 0x79, 0x51, 0x20, 0xa3, 0xc4, 0xeb, 0x54,
2790x0b, 0x94, 0x8b, 0x94, 0xaa, 0xd6, 0x2e, 0xbf, 0xfc, 0x5b, 0x15, 0xa8, 0xd2, 0x26, 0xaf,
2800xdc, 0x1b, 0xb4, 0xea, 0x37, 0xec, 0x3b, 0xf4, 0x6a, 0x37, 0xcd, 0x18, 0x93, 0x85, 0x69,
2810x31, 0xc1, 0xe1, 0x40, 0xe3, 0x25, 0xc8, 0x12, 0x87, 0x8c, 0x9a, 0xb6, 0xcf, 0xfd, 0x59,
2820x11, 0xa0, 0xc2, 0x06, 0x8e, 0x7f, 0x5d, 0x38, 0xf2, 0x47, 0x0c, 0x7b, 0x74, 0x6a, 0x37,
2830xec, 0x5a, 0x36, 0xee, 0x3f, 0xfc, 0x7a, 0x76, 0x4f, 0x1c, 0x9b, 0x95, 0x89, 0x71, 0x41,
2840x00, 0x63, 0x44, 0xeb, 0x54, 0x2a, 0xd6, 0x0f, 0x9c, 0xba, 0xd7, 0x0d, 0x98, 0x93, 0x85,
2850x69, 0x31, 0xc1, 0x00, 0x82, 0x86, 0x8e, 0x9e, 0xbe, 0xdf, 0x3c, 0xfa, 0x57, 0x2c, 0xda,
2860x36, 0xee, 0x3f, 0xfc, 0x5b, 0x15, 0x89, 0x71, 0x41, 0x00, 0x82, 0x86, 0x8e, 0x7f, 0x5d,
2870x38, 0xf2, 0x47, 0xed, 0x58, 0x13, 0xa4, 0xca, 0xf7, 0x4d, 0xf9, 0x51, 0x01, 0x80, 0x63,
2880x44, 0xeb, 0x54, 0x2a, 0xd6, 0x2e, 0xbf, 0xdd, 0x19, 0x91, 0xa0, 0xa3, 0xa5, 0xa9, 0xb1,
2890xe0, 0x42, 0x06, 0x8e, 0x7f, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xc4, 0x0a, 0x96, 0x8f, 0x7d,
2900x78, 0x72, 0x47, 0x0c, 0x7b, 0x74, 0x6a, 0x56, 0x2e, 0xde, 0x1f, 0xbc, 0xfa, 0x57, 0x0d,
2910x79, 0x51, 0x01, 0x61, 0x21, 0xa1, 0xc0, 0xe3, 0x25, 0xa9, 0xb1, 0xc1, 0xe1, 0x40, 0x02,
2920x67, 0x4c, 0x1a, 0x97, 0x8d, 0x98, 0x93, 0xa4, 0xab, 0xd4, 0x2a, 0xd6, 0x0f, 0x9c, 0x9b,
2930xb4, 0xcb, 0x14, 0xaa, 0xb7, 0xcd, 0xf9, 0x51, 0x20, 0xa3, 0xc4, 0xeb, 0x35, 0xc9, 0xf1,
2940x60, 0x42, 0x06, 0x8e, 0x7f, 0x7c, 0x7a, 0x76, 0x6e, 0x3f, 0xfc, 0x7a, 0x76, 0x6e, 0x5e,
2950x3e, 0xfe, 0x7e, 0x5f, 0x3c, 0xdb, 0x15, 0x89, 0x71, 0x41, 0xe1, 0x21, 0xc0, 0xe3, 0x44,
2960xeb, 0x54, 0x2a, 0xb7, 0xcd, 0xf9, 0x70, 0x62, 0x27, 0xad, 0xd8, 0x32, 0xc7, 0x0c, 0x7b,
2970x74, 0x4b, 0x14, 0xaa, 0xb7, 0xec, 0x3b, 0xd5, 0x28, 0xd2, 0x07, 0x6d, 0x39, 0xd1, 0x20,
2980xc2, 0xe7, 0x4c, 0x1a, 0x97, 0x8d, 0x98, 0xb2, 0xc7, 0x0c, 0x59, 0x28, 0xf3, 0x9b };
299
300// clang-format off
diff --git a/keyboards/ploopyco/trackball/config.h b/keyboards/ploopyco/trackball/config.h
new file mode 100644
index 000000000..57113d965
--- /dev/null
+++ b/keyboards/ploopyco/trackball/config.h
@@ -0,0 +1,69 @@
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#include "config_common.h"
22
23/* USB Device descriptor parameter */
24#define VENDOR_ID 0x5043
25#define PRODUCT_ID 0x5442
26#define DEVICE_VER 0x0001
27#define MANUFACTURER Ploopyco
28#define PRODUCT Trackball
29
30/* key matrix size */
31#define MATRIX_ROWS 1
32#define MATRIX_COLS 5
33
34/*
35 * Keyboard Matrix Assignments
36 *
37 * Change this to how you wired your keyboard
38 * COLS: AVR pins used for columns, left to right
39 * ROWS: AVR pins used for rows, top to bottom
40 * DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode)
41 * ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode)
42 *
43 */
44#define DIRECT_PINS { { D4, D2, E6, B5, D7 } }
45
46// These pins are not broken out, and cannot be used normally.
47// They are set as output and pulled high, by default
48#define UNUSED_PINS { D1, D3, B4, B6, B7, D6, C7, F6, F5, F3 }
49
50/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
51#define DEBOUNCE 5
52
53/* define if matrix has ghost (lacks anti-ghosting diodes) */
54//#define MATRIX_HAS_GHOST
55
56/* disable action features */
57//#define NO_ACTION_LAYER
58//#define NO_ACTION_TAPPING
59//#define NO_ACTION_ONESHOT
60#define NO_ACTION_MACRO
61#define NO_ACTION_FUNCTION
62
63/* Much more so than a keyboard, speed matters for a mouse. So we'll go for as high
64 a polling rate as possible. */
65#define USB_POLLING_INTERVAL_MS 1
66
67/* Bootmagic Lite key configuration */
68#define BOOTMAGIC_LITE_ROW 0
69#define BOOTMAGIC_LITE_COLUMN 3
diff --git a/keyboards/ploopyco/trackball/info.json b/keyboards/ploopyco/trackball/info.json
new file mode 100644
index 000000000..84d512d8d
--- /dev/null
+++ b/keyboards/ploopyco/trackball/info.json
@@ -0,0 +1,18 @@
1{
2 "keyboard_name": "PloopyCo Trackball",
3 "url": "",
4 "maintainer": "drashna",
5 "width": 8,
6 "height": 3,
7 "layouts": {
8 "LAYOUT": {
9 "layout": [
10 {"x":0, "y":0, "h":2},
11 {"x":1, "y":0.25, "h":1.5},
12 {"x":2, "y":0, "h":2},
13 {"x":3.5, "y":0, "h":2},
14 {"x":4.5, "y":0, "h":2}
15 ]
16 }
17 }
18}
diff --git a/keyboards/ploopyco/trackball/keymaps/default/keymap.c b/keyboards/ploopyco/trackball/keymaps/default/keymap.c
new file mode 100644
index 000000000..dc1ad1439
--- /dev/null
+++ b/keyboards/ploopyco/trackball/keymaps/default/keymap.c
@@ -0,0 +1,26 @@
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#include QMK_KEYBOARD_H
19
20
21const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
22 [0] = LAYOUT( /* Base */
23 KC_BTN1, KC_BTN3, KC_BTN2,
24 KC_BTN4, KC_BTN5
25 ),
26};
diff --git a/keyboards/ploopyco/trackball/keymaps/default/readme.md b/keyboards/ploopyco/trackball/keymaps/default/readme.md
new file mode 100644
index 000000000..f965ef3c3
--- /dev/null
+++ b/keyboards/ploopyco/trackball/keymaps/default/readme.md
@@ -0,0 +1 @@
# The default keymap for Ploopyco Trackball
diff --git a/keyboards/ploopyco/trackball/keymaps/via/keymap.c b/keyboards/ploopyco/trackball/keymaps/via/keymap.c
new file mode 100644
index 000000000..dc1ad1439
--- /dev/null
+++ b/keyboards/ploopyco/trackball/keymaps/via/keymap.c
@@ -0,0 +1,26 @@
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#include QMK_KEYBOARD_H
19
20
21const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
22 [0] = LAYOUT( /* Base */
23 KC_BTN1, KC_BTN3, KC_BTN2,
24 KC_BTN4, KC_BTN5
25 ),
26};
diff --git a/keyboards/ploopyco/trackball/keymaps/via/rules.mk b/keyboards/ploopyco/trackball/keymaps/via/rules.mk
new file mode 100644
index 000000000..1e5b99807
--- /dev/null
+++ b/keyboards/ploopyco/trackball/keymaps/via/rules.mk
@@ -0,0 +1 @@
VIA_ENABLE = yes
diff --git a/keyboards/ploopyco/trackball/readme.md b/keyboards/ploopyco/trackball/readme.md
new file mode 100644
index 000000000..76b9d6a76
--- /dev/null
+++ b/keyboards/ploopyco/trackball/readme.md
@@ -0,0 +1,68 @@
1# Ploopyco Trackball
2
3![Ploopyco Trackball](https://i.redd.it/j7z0y83txps31.jpg)
4
5It's a DIY, QMK Powered Trackball!!!!
6
7Everything works. However the scroll wheel has some issues and acts very odd.
8
9* Keyboard Maintainer: [PloopyCo](https://github.com/ploopyco), [Drashna Jael're](https://github.com/drashna/), [Germ](https://github.com/germ/)
10* Hardware Supported: ATMega32u4 8MHz(3.3v)
11* Hardware Availability: [Store](https://ploopy.co), [GitHub](https://github.com/ploopyco)
12
13Make example for this keyboard (after setting up your build environment):
14
15 make ploopyco/trackball:default:flash
16
17To jump to the bootloader, hold down "Button 4" (immediate right of the trackball)
18
19See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
20
21# Customzing your PloopyCo Trackball
22
23While the defaults are designed so that it can be plugged in and used right away, there are a number of things that you may want to change. Such as adding DPI control, or to use the ball to scroll while holding a button. To allow for this sort of control, there is a callback for both the scroll wheel and the mouse censor.
24
25The default behavior for this is:
26
27```c
28void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v) {
29 mouse_report->h = h;
30 mouse_report->v = v;
31}
32
33void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y) {
34 mouse_report->x = x;
35 mouse_report->y = y;
36}
37```
38
39This should allow you to more heavily customize the behavior.
40
41Alternatively, the `process_wheel` and `process_mouse` functions can both be replaced too, to allow for even more functionality.
42
43Additionally, you can change the DPI/CPI or speed of the trackball by calling `pmw_set_cpi` at any time. And tThe default can be changed by adding a define to the keymap's `config.h` file:
44
45 #define PMW_CPI 1600
46
47# Programming QMK-DFU onto the PloopyCo Trackball
48
49If you would rather have DFU on this board, you can use the QMK-DFU bootloader on the device. To do so, you want to run:
50
51 make ploopyco/trackball:default:production
52
53Once you have that, you'll need to [ISP Flash](https://docs.qmk.fm/#/isp_flashing_guide) the chip with the new bootloader hex file created (or the production hex), and set the fuses:
54
55
56| Fuse | Setting |
57|----------|------------------|
58| Low | `0xDF` |
59| High | `0xD8` or `0x98` |
60| Extended | `0xCB` |
61
62Original (Caterina) settings:
63
64| Fuse | Setting |
65|----------|------------------|
66| Low | `0xFF` |
67| High | `0xD8` |
68| Extended | `0xFE` |
diff --git a/keyboards/ploopyco/trackball/rules.mk b/keyboards/ploopyco/trackball/rules.mk
new file mode 100644
index 000000000..d77431b67
--- /dev/null
+++ b/keyboards/ploopyco/trackball/rules.mk
@@ -0,0 +1,30 @@
1# MCU name
2MCU = atmega32u4
3
4# Processor frequency
5F_CPU = 8000000
6
7# Bootloader selection
8BOOTLOADER = caterina
9
10# Build Options
11# change yes to no to disable
12#
13BOOTMAGIC_ENABLE = lite # Virtual DIP switch configuration
14EXTRAKEY_ENABLE = yes # Audio control and System control
15CONSOLE_ENABLE = yes # Console for debug
16COMMAND_ENABLE = no # Commands for debug and configuration
17# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
18SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
19# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
20NKRO_ENABLE = no # USB Nkey Rollover
21BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
22RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
23UNICODE_ENABLE = no # Unicode
24BLUETOOTH_ENABLE = no # Enable Bluetooth
25AUDIO_ENABLE = no # Audio output
26POINTING_DEVICE_ENABLE = yes
27MOUSEKEY_ENABLE = no # Mouse keys
28
29QUANTUM_LIB_SRC += analog.c spi_master.c
30SRC += pmw3600.c opt_encoder.c
diff --git a/keyboards/ploopyco/trackball/trackball.c b/keyboards/ploopyco/trackball/trackball.c
new file mode 100644
index 000000000..6a9bffbff
--- /dev/null
+++ b/keyboards/ploopyco/trackball/trackball.c
@@ -0,0 +1,237 @@
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#include QMK_KEYBOARD_H
20
21#ifndef OPT_DEBOUNCE
22# define OPT_DEBOUNCE 5 // (ms) Time between scroll events
23#endif
24#ifndef SCROLL_BUTT_DEBOUNCE
25# define SCROLL_BUTT_DEBOUNCE 100 // (ms) Time between scroll events
26#endif
27#ifndef OPT_THRES
28# define OPT_THRES 150 // (0-1024) Threshold for actication
29#endif
30#ifndef OPT_SCALE
31# define OPT_SCALE 1 // Multiplier for wheel
32#endif
33
34// TODO: Implement libinput profiles
35// https://wayland.freedesktop.org/libinput/doc/latest/pointer-acceleration.html
36// Compile time accel selection
37// Valid options are ACC_NONE, ACC_LINEAR, ACC_CUSTOM, ACC_QUADRATIC
38
39// Trackball State
40bool is_scroll_clicked = false;
41bool BurstState = false; // init burst state for Trackball module
42uint16_t MotionStart = 0; // Timer for accel, 0 is resting state
43uint16_t lastScroll = 0; // Previous confirmed wheel event
44uint16_t lastMidClick = 0; // Stops scrollwheel from being read if it was pressed
45uint8_t OptLowPin = OPT_ENC1;
46bool debug_encoder = false;
47
48__attribute__((weak)) void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v) {
49 mouse_report->h = h;
50 mouse_report->v = v;
51}
52
53__attribute__((weak)) void process_wheel(report_mouse_t* mouse_report) {
54 // TODO: Replace this with interrupt driven code, polling is S L O W
55 // Lovingly ripped from the Ploopy Source
56
57 // If the mouse wheel was just released, do not scroll.
58 if (timer_elapsed(lastMidClick) < SCROLL_BUTT_DEBOUNCE) {
59 return;
60 }
61
62 // Limit the number of scrolls per unit time.
63 if (timer_elapsed(lastScroll) < OPT_DEBOUNCE) {
64 return;
65 }
66
67 // Don't scroll if the middle button is depressed.
68 if (is_scroll_clicked) {
69#ifndef IGNORE_SCROLL_CLICK
70 return;
71#endif
72 }
73
74 lastScroll = timer_read();
75 uint16_t p1 = adc_read(OPT_ENC1_MUX);
76 uint16_t p2 = adc_read(OPT_ENC2_MUX);
77 if (debug_encoder) dprintf("OPT1: %d, OPT2: %d\n", p1, p2);
78
79 uint8_t dir = opt_encoder_handler(p1, p2);
80
81 if (dir == 0) return;
82 process_wheel_user(mouse_report, mouse_report->h, (int)(mouse_report->v + (dir * OPT_SCALE)));
83}
84
85__attribute__((weak)) void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y) {
86 mouse_report->x = x;
87 mouse_report->y = y;
88}
89
90__attribute__((weak)) void process_mouse(report_mouse_t* mouse_report) {
91 report_pmw_t data = pmw_read_burst();
92 if (data.isOnSurface && data.isMotion) {
93 // Reset timer if stopped moving
94 if (!data.isMotion) {
95 if (MotionStart != 0) MotionStart = 0;
96 return;
97 }
98
99 // Set timer if new motion
100 if ((MotionStart == 0) && data.isMotion) {
101 if (debug_mouse) dprintf("Starting motion.\n");
102 MotionStart = timer_read();
103 }
104
105 if (debug_mouse) {
106 dprintf("Delt] d: %d t: %u\n", abs(data.dx) + abs(data.dy), MotionStart);
107 }
108 if (debug_mouse) {
109 dprintf("Pre ] X: %d, Y: %d\n", data.dx, data.dy);
110 }
111#if defined(PROFILE_LINEAR)
112 float scale = float(timer_elaspsed(MotionStart)) / 1000.0;
113 data.dx *= scale;
114 data.dy *= scale;
115#elif defined(PROFILE_INVERSE)
116 // TODO
117#else
118 // no post processing
119#endif
120 // apply multiplier
121 // data.dx *= mouse_multiplier;
122 // data.dy *= mouse_multiplier;
123
124 // Wrap to HID size
125 data.dx = constrain(data.dx, -127, 127);
126 data.dy = constrain(data.dy, -127, 127);
127 if (debug_mouse) dprintf("Cons] X: %d, Y: %d\n", data.dx, data.dy);
128 // dprintf("Elapsed:%u, X: %f Y: %\n", i, pgm_read_byte(firmware_data+i));
129
130 process_mouse_user(mouse_report, data.dx, data.dy);
131 }
132}
133
134bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
135 if (debug_mouse) {
136 dprintf("KL: kc: %u, col: %u, row: %u, pressed: %u\n", keycode, record->event.key.col, record->event.key.row, record->event.pressed);
137 }
138
139 // Update Timer to prevent accidental scrolls
140 if ((record->event.key.col == 2) && (record->event.key.row == 0)) {
141 lastMidClick = timer_read();
142 is_scroll_clicked = record->event.pressed;
143 }
144
145/* If Mousekeys is disabled, then use handle the mouse button
146 * keycodes. This makes things simpler, and allows usage of
147 * the keycodes in a consistent manner. But only do this if
148 * Mousekeys is not enable, so it's not handled twice.
149 */
150#ifndef MOUSEKEY_ENABLE
151 if (IS_MOUSEKEY_BUTTON(keycode)) {
152 report_mouse_t currentReport = pointing_device_get_report();
153 if (record->event.pressed) {
154 if (keycode == KC_MS_BTN1)
155 currentReport.buttons |= MOUSE_BTN1;
156 else if (keycode == KC_MS_BTN2)
157 currentReport.buttons |= MOUSE_BTN2;
158 else if (keycode == KC_MS_BTN3)
159 currentReport.buttons |= MOUSE_BTN3;
160 else if (keycode == KC_MS_BTN4)
161 currentReport.buttons |= MOUSE_BTN4;
162 else if (keycode == KC_MS_BTN5)
163 currentReport.buttons |= MOUSE_BTN5;
164 } else {
165 if (keycode == KC_MS_BTN1)
166 currentReport.buttons &= ~MOUSE_BTN1;
167 else if (keycode == KC_MS_BTN2)
168 currentReport.buttons &= ~MOUSE_BTN2;
169 else if (keycode == KC_MS_BTN3)
170 currentReport.buttons &= ~MOUSE_BTN3;
171 else if (keycode == KC_MS_BTN4)
172 currentReport.buttons &= ~MOUSE_BTN4;
173 else if (keycode == KC_MS_BTN5)
174 currentReport.buttons &= ~MOUSE_BTN5;
175 }
176 pointing_device_set_report(currentReport);
177 }
178#endif
179
180 return process_record_user(keycode, record);
181}
182
183// Hardware Setup
184void keyboard_pre_init_kb(void) {
185 // debug_enable = true;
186 // debug_matrix = true;
187 // debug_mouse = true;
188 // debug_encoder = true;
189
190 setPinInput(OPT_ENC1);
191 setPinInput(OPT_ENC2);
192
193 // This is the debug LED.
194 setPinOutput(F7);
195 writePin(F7, debug_enable);
196
197 /* Ground all output pins connected to ground. This provides additional
198 * pathways to ground. If you're messing with this, know this: driving ANY
199 * of these pins high will cause a short. On the MCU. Ka-blooey.
200 */
201#ifdef UNUSED_PINS
202 const pin_t unused_pins[] = UNUSED_PINS;
203
204 for (uint8_t i = 0; i < (sizeof(unused_pins) / sizeof(pin_t)); i++) {
205 setPinOutput(unused_pins[i]);
206 writePinLow(unused_pins[i]);
207 }
208#endif
209 keyboard_pre_init_user();
210}
211
212void pointing_device_init(void) {
213 // initialize ball sensor
214 pmw_spi_init();
215 // initialize the scroll wheel's optical encoder
216 opt_encoder_init();
217}
218
219bool has_report_changed (report_mouse_t first, report_mouse_t second) {
220 return !(
221 (!first.buttons && first.buttons == second.buttons) &&
222 (!first.x && first.x == second.x) &&
223 (!first.y && first.y == second.y) &&
224 (!first.h && first.h == second.h) &&
225 (!first.v && first.v == second.v) );
226}
227
228void pointing_device_task(void) {
229 report_mouse_t mouse_report = pointing_device_get_report();
230 process_wheel(&mouse_report);
231 process_mouse(&mouse_report);
232
233 pointing_device_set_report(mouse_report);
234 if (has_report_changed(mouse_report, pointing_device_get_report())) {
235 pointing_device_send();
236 }
237}
diff --git a/keyboards/ploopyco/trackball/trackball.h b/keyboards/ploopyco/trackball/trackball.h
new file mode 100644
index 000000000..959305a07
--- /dev/null
+++ b/keyboards/ploopyco/trackball/trackball.h
@@ -0,0 +1,40 @@
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#include "quantum.h"
22#include "spi_master.h"
23#include "pmw3600.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);
36void process_wheel(report_mouse_t* mouse_report);
37void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v);
38
39#define LAYOUT(BL, BM, BR, BF, BB) \
40 { {BL, BM, BR, BF, BB}, }