Browse Source

fix debounce. add handling of different buttons. implement combined middle mouse and scroll lock button.

Thomas Buck 1 year ago
parent
commit
93c3178d27

+ 4
- 0
firmware/include/config.h View File

@@ -16,6 +16,10 @@
16 16
 #define INVERT_MOUSE_Y_AXIS true
17 17
 #define DEFAULT_MOUSE_SENSITIVITY PMW_CPI_TO_SENSE(500)
18 18
 
19
+#define INVERT_SCROLL_X_AXIS false
20
+#define INVERT_SCROLL_Y_AXIS false
21
+#define MIN_SCROLL_SUPPRESS_CLICK 10
22
+
19 23
 #define DEBOUNCE_DELAY_MS 5
20 24
 
21 25
 #endif // __CONFIG_H__

+ 21
- 2
firmware/include/controls.h View File

@@ -5,8 +5,27 @@
5 5
 #ifndef __CONTROLS_H__
6 6
 #define __CONTROLS_H__
7 7
 
8
-void controls_new(int id, bool state);
9
-bool controls_button_read(void);
8
+enum mouse_buttons {
9
+    MOUSE_LEFT = 0,
10
+    MOUSE_MIDDLE,
11
+    MOUSE_RIGHT,
12
+    MOUSE_BACK,
13
+    MOUSE_FORWARD,
14
+    MOUSE_BUTTONS_COUNT
15
+};
16
+
17
+struct mouse_state {
18
+    bool changed;
19
+    bool button[MOUSE_BUTTONS_COUNT];
20
+    int16_t delta_x, delta_y;
21
+    int16_t scroll_x, scroll_y;
22
+    bool scroll_lock, fake_middle;
23
+};
24
+
25
+void controls_init(void);
26
+
27
+void controls_mouse_new(int id, bool state);
28
+struct mouse_state controls_mouse_read(void);
10 29
 
11 30
 #endif // __CONTROLS_H__
12 31
 

+ 3
- 0
firmware/include/log.h View File

@@ -18,8 +18,11 @@
18 18
 #define println(fmt, ...) debug_log(false, fmt "\r\n", ##__VA_ARGS__)
19 19
 
20 20
 void debug_log(bool log, const char *format, ...) __attribute__((format(printf, 2, 3)));
21
+void debug_wait_input(const char *format, ...) __attribute__((format(printf, 1, 2)));
21 22
 
22 23
 void log_dump_to_usb(void);
23 24
 void log_dump_to_disk(void);
24 25
 
26
+void debug_handle_input(char *buff, uint32_t len);
27
+
25 28
 #endif // __LOG_H__

+ 1
- 0
firmware/include/usb_cdc.h View File

@@ -6,5 +6,6 @@
6 6
 #define __USB_CDC_H__
7 7
 
8 8
 void usb_cdc_write(const char *buf, uint32_t count);
9
+void usb_cdc_set_reroute(bool reroute);
9 10
 
10 11
 #endif // __USB_CDC_H__

+ 12
- 5
firmware/src/buttons.c View File

@@ -13,7 +13,7 @@ uint gpio_num[BUTTONS_COUNT] = { 21, 22, 26, 27 };
13 13
 
14 14
 struct button_state {
15 15
     uint32_t last_time;
16
-    bool last_state;
16
+    bool current_state, last_state;
17 17
 };
18 18
 
19 19
 struct button_state buttons[BUTTONS_COUNT];
@@ -21,13 +21,18 @@ struct button_state buttons[BUTTONS_COUNT];
21 21
 void buttons_init(void) {
22 22
     for (int i = 0; i < BUTTONS_COUNT; i++) {
23 23
         gpio_init(gpio_num[i]);
24
+        gpio_set_dir(gpio_num[i], GPIO_IN);
24 25
         gpio_pull_up(gpio_num[i]);
26
+
27
+        buttons[i].last_time = 0;
28
+        buttons[i].current_state = false;
29
+        buttons[i].last_state = false;
25 30
     }
26 31
 }
27 32
 
28 33
 void buttons_run(void) {
29 34
     for (int i = 0; i < BUTTONS_COUNT; i++) {
30
-        bool state = gpio_get(gpio_num[i]);
35
+        bool state = !gpio_get(gpio_num[i]);
31 36
         uint32_t now = to_ms_since_boot(get_absolute_time());
32 37
 
33 38
         if (state != buttons[i].last_state) {
@@ -35,11 +40,13 @@ void buttons_run(void) {
35 40
         }
36 41
 
37 42
         if ((now - buttons[i].last_time) > DEBOUNCE_DELAY_MS) {
38
-            if (state != buttons[i].last_state) {
39
-                buttons[i].last_state = state;
40
-                controls_new(i, state);
43
+            if (state != buttons[i].current_state) {
44
+                buttons[i].current_state = state;
45
+                controls_mouse_new(i, state);
41 46
             }
42 47
         }
48
+
49
+        buttons[i].last_state = state;
43 50
     }
44 51
 }
45 52
 

+ 103
- 6
firmware/src/controls.c View File

@@ -2,19 +2,116 @@
2 2
  * controls.c
3 3
  */
4 4
 
5
+#include <stdlib.h>
6
+
5 7
 #include "pico/stdlib.h"
6 8
 
7 9
 #include "config.h"
10
+#include "log.h"
11
+#include "pmw3360.h"
8 12
 #include "controls.h"
9 13
 
10
-static bool button_state = false;
14
+static struct mouse_state mouse, last_mouse;
15
+static uint64_t scroll_sum = 0;
16
+
17
+void controls_init(void) {
18
+    for (int i = 0; i < MOUSE_BUTTONS_COUNT; i++) {
19
+        mouse.button[i] = false;
20
+    }
21
+    mouse.changed = false;
22
+    mouse.delta_x = 0;
23
+    mouse.delta_y = 0;
24
+    mouse.scroll_x = 0;
25
+    mouse.scroll_y = 0;
26
+    mouse.scroll_lock = false;
27
+    mouse.fake_middle = false;
28
+
29
+    last_mouse = mouse;
30
+}
31
+
32
+void controls_mouse_new(int id, bool state) {
33
+    //debug("button %d %s", id, state ? "pressed" : "released");
11 34
 
12
-void controls_new(int id, bool state) {
13
-    (void)id;
14
-    button_state = state;
35
+    switch (id) {
36
+    case 0:
37
+        mouse.button[MOUSE_BACK] = state;
38
+        break;
39
+
40
+    case 1:
41
+        mouse.scroll_lock = state;
42
+        break;
43
+
44
+    case 2:
45
+        mouse.button[MOUSE_LEFT] = state;
46
+        break;
47
+
48
+    case 3:
49
+        mouse.button[MOUSE_RIGHT] = state;
50
+        break;
51
+    }
15 52
 }
16 53
 
17
-bool controls_button_read(void) {
18
-    return button_state;
54
+static bool mouse_state_changed(struct mouse_state a, struct mouse_state b) {
55
+    for (int i = 0; i < MOUSE_BUTTONS_COUNT; i++) {
56
+        if (a.button[i] != b.button[i]) {
57
+            return true;
58
+        }
59
+    }
60
+
61
+    if ((a.delta_x != b.delta_x)
62
+            || (a.delta_y != b.delta_y)
63
+            || (a.scroll_x != b.scroll_x)
64
+            || (a.scroll_y != b.scroll_y)) {
65
+        return true;
66
+    }
67
+
68
+    return false;
69
+}
70
+
71
+struct mouse_state controls_mouse_read(void) {
72
+    struct pmw_motion motion = pmw_get();
73
+
74
+    if (motion.motion) {
75
+        mouse.delta_x = motion.delta_x;
76
+        mouse.delta_y = motion.delta_y;
77
+    }
78
+
79
+    if (mouse.scroll_lock) {
80
+        mouse.scroll_x = mouse.delta_x;
81
+        mouse.scroll_y = mouse.delta_y;
82
+        mouse.delta_x = 0;
83
+        mouse.delta_y = 0;
84
+
85
+        scroll_sum += abs(mouse.scroll_x);
86
+        scroll_sum += abs(mouse.scroll_y);
87
+    } else {
88
+        mouse.scroll_x = 0;
89
+        mouse.scroll_y = 0;
90
+    }
91
+
92
+    if (mouse.fake_middle) {
93
+        mouse.button[MOUSE_MIDDLE] = false;
94
+        mouse.fake_middle = false;
95
+    }
96
+
97
+    if (!mouse.scroll_lock && last_mouse.scroll_lock) {
98
+        // middle mouse button was held and has now been released
99
+        if (scroll_sum < MIN_SCROLL_SUPPRESS_CLICK) {
100
+            // fake middle mouse click, user was not scrolling
101
+            mouse.button[MOUSE_MIDDLE] = true;
102
+            mouse.fake_middle = true;
103
+        }
104
+    }
105
+
106
+    if (mouse_state_changed(mouse, last_mouse)
107
+            || (mouse.delta_x != 0)
108
+            || (mouse.delta_y != 0)
109
+            || (mouse.scroll_x != 0)
110
+            || (mouse.scroll_y != 0)) {
111
+        mouse.changed = true;
112
+    }
113
+
114
+    last_mouse = mouse;
115
+    return mouse;
19 116
 }
20 117
 

+ 39
- 4
firmware/src/log.c View File

@@ -4,16 +4,20 @@
4 4
 
5 5
 #include <stdarg.h>
6 6
 #include <stdio.h>
7
+
7 8
 #include "pico/stdlib.h"
9
+#include "hardware/watchdog.h"
8 10
 #include "ff.h"
9 11
 
10 12
 #include "config.h"
13
+#include "usb.h"
11 14
 #include "usb_cdc.h"
12 15
 #include "log.h"
13 16
 
14
-char log_buff[4096];
15
-size_t head = 0, tail = 0;
16
-bool full = false;
17
+static char log_buff[4096];
18
+static size_t head = 0, tail = 0;
19
+static bool full = false;
20
+static bool got_input = false;
17 21
 
18 22
 static void add_to_log(const char *buff, int len) {
19 23
     for (int i = 0; i < len; i++) {
@@ -103,7 +107,7 @@ static int format_debug_log(char *buff, size_t len, const char *format, va_list
103 107
 }
104 108
 
105 109
 void debug_log(bool log, const char* format, ...) {
106
-    static char line_buff[256];
110
+    static char line_buff[512];
107 111
 
108 112
     va_list args;
109 113
     va_start(args, format);
@@ -118,3 +122,34 @@ void debug_log(bool log, const char* format, ...) {
118 122
         }
119 123
     }
120 124
 }
125
+
126
+void debug_handle_input(char *buff, uint32_t len) {
127
+    (void)buff;
128
+
129
+    if (len > 0) {
130
+        got_input = true;
131
+    }
132
+}
133
+
134
+void debug_wait_input(const char *format, ...) {
135
+    static char line_buff[512];
136
+
137
+    va_list args;
138
+    va_start(args, format);
139
+    int l = format_debug_log(line_buff, sizeof(line_buff), format, args);
140
+    va_end(args);
141
+
142
+    if ((l > 0) && (l <= (int)sizeof(line_buff))) {
143
+        usb_cdc_write(line_buff, l);
144
+    }
145
+
146
+    got_input = false;
147
+    usb_cdc_set_reroute(true);
148
+
149
+    while (!got_input) {
150
+        watchdog_update();
151
+        usb_run();
152
+    }
153
+
154
+    usb_cdc_set_reroute(false);
155
+}

+ 9
- 2
firmware/src/main.c View File

@@ -13,10 +13,12 @@
13 13
 #include "pmw3360.h"
14 14
 #include "fat_disk.h"
15 15
 #include "buttons.h"
16
+#include "controls.h"
16 17
 
17 18
 int main(void) {
18 19
     heartbeat_init();
19 20
     buttons_init();
21
+    controls_init();
20 22
 
21 23
     cnsl_init();
22 24
     usb_init();
@@ -29,13 +31,15 @@ int main(void) {
29 31
     fat_disk_init();
30 32
 
31 33
     debug("pmw_init");
34
+    bool use_pmw = true;
32 35
     if (pmw_init() != 0) {
33 36
         debug("error initializing PMW3360");
37
+        use_pmw = false;
34 38
     }
35 39
 
36 40
     // trigger after 500ms
37 41
     // (PMW3360 initialization takes ~160ms)
38
-    //watchdog_enable(500, 1);
42
+    watchdog_enable(500, 1);
39 43
 
40 44
     debug("init done");
41 45
 
@@ -46,7 +50,10 @@ int main(void) {
46 50
         buttons_run();
47 51
         usb_run();
48 52
         cnsl_run();
49
-        pmw_run();
53
+
54
+        if (use_pmw) {
55
+            pmw_run();
56
+        }
50 57
     }
51 58
 
52 59
     return 0;

+ 1
- 1
firmware/src/pmw3360.c View File

@@ -345,7 +345,7 @@ static void pmw_irq_init(void) {
345 345
         // setup MOTION pin interrupt to handle reading data
346 346
         gpio_add_raw_irq_handler(PMW_MOTION_PIN, pmw_motion_irq);
347 347
         irq_set_enabled(IO_IRQ_BANK0, true);
348
-	first_init = true;
348
+        first_init = true;
349 349
     }
350 350
 
351 351
     pmw_irq_start();

+ 8
- 0
firmware/src/usb_cdc.c View File

@@ -33,6 +33,8 @@
33 33
 #include "usb_descriptors.h"
34 34
 #include "usb_cdc.h"
35 35
 
36
+static bool reroute_cdc_debug = false;
37
+
36 38
 void usb_cdc_write(const char *buf, uint32_t count) {
37 39
 #ifndef DISABLE_CDC_DTR_CHECK
38 40
     if (!tud_cdc_connected()) {
@@ -59,6 +61,10 @@ void usb_cdc_write(const char *buf, uint32_t count) {
59 61
     }
60 62
 }
61 63
 
64
+void usb_cdc_set_reroute(bool reroute) {
65
+    reroute_cdc_debug = reroute;
66
+}
67
+
62 68
 void cdc_task(void) {
63 69
     const uint32_t cdc_buf_len = 64;
64 70
 
@@ -70,6 +76,8 @@ void cdc_task(void) {
70 76
             // ASCII 0x18 = CAN (cancel)
71 77
             debug("switching to bootloader");
72 78
             reset_to_bootloader();
79
+        } else if (reroute_cdc_debug) {
80
+            debug_handle_input(buf, count);
73 81
         } else {
74 82
             // echo back
75 83
             usb_cdc_write(buf, count);

+ 17
- 6
firmware/src/usb_hid.c View File

@@ -27,7 +27,6 @@
27 27
 #include "tusb.h"
28 28
 
29 29
 #include "config.h"
30
-#include "pmw3360.h"
31 30
 #include "controls.h"
32 31
 #include "usb_descriptors.h"
33 32
 #include "usb_hid.h"
@@ -58,16 +57,28 @@ static void send_hid_report(uint8_t report_id, uint32_t btn) {
58 57
 
59 58
         case REPORT_ID_MOUSE:
60 59
         {
61
-            struct pmw_motion mouse = pmw_get();
60
+            struct mouse_state mouse = controls_mouse_read();
61
+
62 62
             uint8_t buttons = 0x00;
63
-            if (btn) {
63
+            if (mouse.button[MOUSE_LEFT]) {
64 64
                 buttons |= MOUSE_BUTTON_LEFT;
65 65
             }
66
-            if (mouse.motion) {
66
+            if (mouse.button[MOUSE_RIGHT]) {
67
+                buttons |= MOUSE_BUTTON_RIGHT;
68
+            }
69
+            if (mouse.button[MOUSE_MIDDLE]) {
70
+                buttons |= MOUSE_BUTTON_MIDDLE;
71
+            }
72
+            if (mouse.button[MOUSE_BACK]) {
73
+                buttons |= MOUSE_BUTTON_BACKWARD;
74
+            }
75
+
76
+            if (mouse.changed) {
67 77
                 tud_hid_mouse_report(REPORT_ID_MOUSE, buttons,
68 78
                         mouse.delta_x * (INVERT_MOUSE_X_AXIS ? -1 : 1),
69 79
                         mouse.delta_y * (INVERT_MOUSE_Y_AXIS ? -1 : 1),
70
-                        0, 0);
80
+                        mouse.scroll_y * (INVERT_SCROLL_Y_AXIS ? -1 : 1),
81
+                        mouse.scroll_x * (INVERT_SCROLL_X_AXIS ? -1 : 1));
71 82
             }
72 83
         }
73 84
         break;
@@ -130,7 +141,7 @@ void hid_task(void) {
130 141
     if ( board_millis() - start_ms < interval_ms) return; // not enough time
131 142
     start_ms += interval_ms;
132 143
 
133
-    uint32_t const btn = controls_button_read();
144
+    uint32_t const btn = 0;
134 145
 
135 146
     // Remote wakeup
136 147
     if ( tud_suspended() && btn ) {

Loading…
Cancel
Save