Skip to content

Commit 71c70ea

Browse files
committed
Create hid_mouse_log_filter.ino
This filter seems to compensate for Essential Tremors better than the other. YMMV, but I think this is a good starting point
1 parent 761cfd3 commit 71c70ea

File tree

1 file changed

+214
-0
lines changed

1 file changed

+214
-0
lines changed
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/*********************************************************************
2+
Adafruit invests time and resources providing this open source code,
3+
please support Adafruit and open-source hardware by purchasing
4+
products from Adafruit!
5+
6+
MIT license, check LICENSE for more information
7+
Copyright (c) 2023 Bill Binko for Adafruit Industries
8+
Based on tremor_filter example by Thach Ha
9+
All text above, and the splash screen below must be included in
10+
any redistribution
11+
*********************************************************************/
12+
13+
14+
/* This example demonstrates use of both device and host, where
15+
* - Device run on native usb controller (controller0)
16+
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
17+
*
18+
* Example sketch receive keyboard report from host interface (from e.g consumer keyboard)
19+
* and remap it to another key and send it via device interface (to PC). For simplicity,
20+
* this example only toggle shift key to the report, effectively remap:
21+
* - all character key <-> upper case
22+
* - number <-> its symbol (with shift)
23+
*
24+
* Requirements:
25+
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
26+
* - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
27+
* - Provide VBus (5v) and GND for peripheral
28+
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
29+
*/
30+
31+
// pio-usb is required for rp2040 host
32+
#include "pio_usb.h"
33+
#include "Adafruit_TinyUSB.h"
34+
#include <math.h>
35+
36+
// Pin D+ for host, D- = D+ + 1
37+
#ifndef PIN_USB_HOST_DP
38+
#define PIN_USB_HOST_DP 16
39+
#endif
40+
41+
// Pin for enabling Host VBUS. comment out if not used
42+
#ifndef PIN_5V_EN
43+
#define PIN_5V_EN 18
44+
#endif
45+
46+
#ifndef PIN_5V_EN_STATE
47+
#define PIN_5V_EN_STATE 1
48+
#endif
49+
50+
// Language ID: English
51+
#define LANGUAGE_ID 0x0409
52+
53+
// USB Host object
54+
Adafruit_USBH_Host USBHost;
55+
56+
// HID report descriptor using TinyUSB's template
57+
// Single Report (no ID) descriptor
58+
uint8_t const desc_hid_report[] =
59+
{
60+
TUD_HID_REPORT_DESC_MOUSE()
61+
};
62+
63+
// USB HID object. For ESP32 these values cannot be changed after this declaration
64+
// desc report, desc len, protocol, interval, use out endpoint
65+
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_MOUSE, 2, false);
66+
67+
/* Adjustable parameters for the log_filter() method. Adjust for each user (would be ideal to have this
68+
* adjustable w/o recompiling
69+
*/
70+
#define PRESCALE 8.0 // Must be > 0, Higher numbers increase rate of attenuation
71+
#define POSTSCALE 1.5 // Must be > 0, Higher numbers compensate for PRESCALE attenuation
72+
#define DEADZONE 1.0 // Must be > 1, Movements < this magnitude will not be filtered
73+
74+
75+
//--------------------------------------------------------------------+
76+
// Setup and Loop on Core0
77+
//--------------------------------------------------------------------+
78+
79+
void setup()
80+
{
81+
Serial.begin(115200);
82+
usb_hid.begin();
83+
84+
//while ( !Serial ) delay(10); // wait for native usb
85+
Serial.println("ATMakers Logarithm Tremor Filter Example");
86+
}
87+
88+
void loop()
89+
{
90+
Serial.flush();
91+
}
92+
93+
//--------------------------------------------------------------------+
94+
// Setup and Loop on Core1
95+
//--------------------------------------------------------------------+
96+
97+
void setup1() {
98+
//while ( !Serial ) delay(10); // wait for native usb
99+
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
100+
101+
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
102+
uint32_t cpu_hz = clock_get_hz(clk_sys);
103+
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
104+
while ( !Serial ) delay(10); // wait for native usb
105+
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
106+
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
107+
while(1) delay(1);
108+
}
109+
110+
#ifdef PIN_5V_EN
111+
pinMode(PIN_5V_EN, OUTPUT);
112+
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
113+
#endif
114+
115+
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
116+
pio_cfg.pin_dp = PIN_USB_HOST_DP;
117+
USBHost.configure_pio_usb(1, &pio_cfg);
118+
119+
// run host stack on controller (rhport) 1
120+
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
121+
// host bit-banging processing works done in core1 to free up core0 for other works
122+
USBHost.begin(1);
123+
}
124+
125+
void loop1()
126+
{
127+
USBHost.task();
128+
}
129+
130+
131+
extern "C"
132+
{
133+
134+
// Invoked when device with hid interface is mounted
135+
// Report descriptor is also available for use.
136+
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
137+
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
138+
// it will be skipped therefore report_desc = NULL, desc_len = 0
139+
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
140+
(void) desc_report;
141+
(void) desc_len;
142+
uint16_t vid, pid;
143+
tuh_vid_pid_get(dev_addr, &vid, &pid);
144+
145+
Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
146+
Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid);
147+
148+
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
149+
if (itf_protocol == HID_ITF_PROTOCOL_MOUSE) {
150+
Serial.printf("HID Mouse\r\n");
151+
if (!tuh_hid_receive_report(dev_addr, instance)) {
152+
Serial.printf("Error: cannot request to receive report\r\n");
153+
}
154+
}
155+
}
156+
157+
// Invoked when device with hid interface is un-mounted
158+
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
159+
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
160+
}
161+
162+
163+
// Invoked when received report from device via interrupt endpoint
164+
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
165+
filter_report((hid_mouse_report_t const *) report);
166+
167+
// continue to request to receive report
168+
if (!tuh_hid_receive_report(dev_addr, instance)) {
169+
Serial.printf("Error: cannot request to receive report\r\n");
170+
}
171+
}
172+
173+
} // extern C
174+
175+
//--------------------------------------------------------------------+
176+
// Low pass filter Functions
177+
//--------------------------------------------------------------------+
178+
179+
/*
180+
* log_filter: Reduce large motions due to tremors by applying the natural log function
181+
* Handles negative values and a dead zone where small values will not be adjusted
182+
*/
183+
int8_t log_filter(int8_t val)
184+
{
185+
if (val < -1*DEADZONE)
186+
{
187+
return (int8_t) (-1.0 * POSTSCALE * logf(-1.0 * PRESCALE * (float)val));
188+
}
189+
else if (val > DEADZONE)
190+
{
191+
return (int8_t) (POSTSCALE * logf(PRESCALE * (float)val));
192+
}
193+
else
194+
{
195+
return val;
196+
}
197+
}
198+
199+
/*
200+
* Adjust HID report by applying log_filter
201+
*/
202+
void filter_report(hid_mouse_report_t const* report) {
203+
204+
int8_t old_x = report->x;
205+
int8_t old_y = report->y;
206+
207+
hid_mouse_report_t filtered_report = *report;
208+
filtered_report.x = log_filter(old_x);
209+
filtered_report.y = log_filter(old_y);
210+
211+
//Serial.printf("%d,%d,%d,%d\n", old_x, filtered_report.x, old_y, filtered_report.y);
212+
usb_hid.sendReport(0, &filtered_report, sizeof(filtered_report));
213+
214+
}

0 commit comments

Comments
 (0)