10
10
#include <zephyr/drivers/gpio.h>
11
11
#include <zephyr/sys/util.h>
12
12
#include <zephyr/kernel.h>
13
- #include <zephyr/drivers/sensor.h>
14
- #include <zephyr/sys/__assert.h>
15
13
#include <zephyr/logging/log.h>
16
14
17
15
#include "ec11.h"
20
18
21
19
LOG_MODULE_REGISTER (EC11 , CONFIG_SENSOR_LOG_LEVEL );
22
20
23
- static int ec11_get_ab_state (const struct device * dev ) {
24
- const struct ec11_config * drv_cfg = dev -> config ;
25
-
26
- return (gpio_pin_get_dt (& drv_cfg -> a ) << 1 ) | gpio_pin_get_dt (& drv_cfg -> b );
27
- }
28
-
29
- static int ec11_sample_fetch (const struct device * dev , enum sensor_channel chan ) {
30
- struct ec11_data * drv_data = dev -> data ;
31
- const struct ec11_config * drv_cfg = dev -> config ;
32
- uint8_t val ;
33
- int8_t delta ;
34
-
35
- __ASSERT_NO_MSG (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_ROTATION );
36
-
37
- val = ec11_get_ab_state (dev );
38
-
39
- LOG_DBG ("prev: %d, new: %d" , drv_data -> ab_state , val );
40
-
41
- switch (val | (drv_data -> ab_state << 2 )) {
42
- case 0b0010 :
43
- case 0b0100 :
44
- case 0b1101 :
45
- case 0b1011 :
46
- delta = -1 ;
47
- break ;
48
- case 0b0001 :
49
- case 0b0111 :
50
- case 0b1110 :
51
- case 0b1000 :
52
- delta = 1 ;
53
- break ;
54
- default :
55
- delta = 0 ;
56
- break ;
21
+ static void ec11_apply_reading (struct ec11_data * drv_data , uint8_t a , uint8_t b ) {
22
+ if (a == drv_data -> prev_a && b == drv_data -> prev_b ) {
23
+ LOG_DBG ("no state change" );
24
+ return ;
57
25
}
58
26
59
- LOG_DBG ("Delta: %d" , delta );
27
+ bool bwd1 = (drv_data -> prev_b != a );
28
+ bool bwd2 = (drv_data -> prev_a == b );
29
+ int8_t delta = (bwd1 == bwd2 ) ? (bwd1 ? -1 : +1 ) : 0 ; // delta == 0 implies missing states
30
+ LOG_DBG ("state %u%u -> %u%u delta:%d" , drv_data -> prev_a , drv_data -> prev_b , a , b , delta );
60
31
61
32
drv_data -> pulses += delta ;
62
- drv_data -> ab_state = val ;
33
+ drv_data -> prev_a = a ;
34
+ drv_data -> prev_b = b ;
63
35
64
36
// TODO: Temporary code for backwards compatibility to support
65
37
// the sensor channel rotation reporting *ticks* instead of delta of degrees.
66
38
// REMOVE ME
39
+ const struct ec11_config * drv_cfg = drv_data -> dev -> config ;
67
40
if (drv_cfg -> steps == 0 ) {
68
41
drv_data -> ticks = drv_data -> pulses / drv_cfg -> resolution ;
69
42
drv_data -> delta = delta ;
70
43
drv_data -> pulses %= drv_cfg -> resolution ;
71
44
}
72
45
73
- return 0 ;
46
+ #ifdef CONFIG_EC11_TRIGGER
47
+ // TODO: CONFIG_EC11_TRIGGER_OWN_THREAD, CONFIG_EC11_TRIGGER_GLOBAL_THREAD
48
+ // XXX: zmk_sensors_trigger_handler() already uses a work queue?
49
+ if (delta != 0 && drv_data -> handler ) {
50
+ drv_data -> handler (drv_data -> dev , drv_data -> trigger );
51
+ }
52
+ #endif
53
+ }
54
+
55
+ static int ec11_sample_fetch (const struct device * dev , enum sensor_channel chan ) {
56
+ return 0 ; // nothing to do; driven by interrupts & timer
74
57
}
75
58
76
59
static int ec11_channel_get (const struct device * dev , enum sensor_channel chan ,
@@ -100,6 +83,16 @@ static int ec11_channel_get(const struct device *dev, enum sensor_channel chan,
100
83
return 0 ;
101
84
}
102
85
86
+ #ifdef CONFIG_EC11_TRIGGER
87
+ static int ec11_trigger_set (const struct device * dev , const struct sensor_trigger * trig ,
88
+ sensor_trigger_handler_t handler ) {
89
+ struct ec11_data * drv_data = dev -> data ;
90
+ drv_data -> trigger = trig ;
91
+ drv_data -> handler = handler ;
92
+ return 0 ;
93
+ }
94
+ #endif
95
+
103
96
static const struct sensor_driver_api ec11_driver_api = {
104
97
#ifdef CONFIG_EC11_TRIGGER
105
98
.trigger_set = ec11_trigger_set ,
@@ -108,42 +101,113 @@ static const struct sensor_driver_api ec11_driver_api = {
108
101
.channel_get = ec11_channel_get ,
109
102
};
110
103
104
+ static void ec11_period (struct k_timer * timer_id ) {
105
+ struct ec11_data * drv_data = CONTAINER_OF (timer_id , struct ec11_data , debouncer );
106
+ const struct ec11_config * drv_cfg = drv_data -> dev -> config ;
107
+
108
+ uint32_t samples_needed = drv_cfg -> debounce_ms / drv_cfg -> debounce_scan_period_ms ;
109
+ samples_needed += !!(drv_cfg -> debounce_ms % drv_cfg -> debounce_scan_period_ms ); // round up
110
+
111
+ // add a single reading to the moving window
112
+ drv_data -> hist_a = (drv_data -> hist_a << 1 ) | gpio_pin_get_dt (& drv_cfg -> a );
113
+ drv_data -> hist_b = (drv_data -> hist_b << 1 ) | gpio_pin_get_dt (& drv_cfg -> b );
114
+ if (drv_data -> samples < samples_needed ) {
115
+ drv_data -> samples ++ ;
116
+ }
117
+
118
+ // histogram from the window
119
+ uint32_t as = drv_data -> hist_a ;
120
+ uint32_t bs = drv_data -> hist_b ;
121
+ uint8_t cnts [4 ] = {0 , 0 , 0 , 0 };
122
+ for (uint8_t i = 0 ; i < drv_data -> samples ; i ++ ) {
123
+ cnts [((as & 1 ) << 1 ) | (bs & 1 )]++ ;
124
+ as >>= 1 ;
125
+ bs >>= 1 ;
126
+ }
127
+ LOG_DBG ("histogram 00:%u 01:%u 10:%u 11:%u" , cnts [0 ], cnts [1 ], cnts [2 ], cnts [3 ]);
128
+
129
+ // check if any state has reached the threshold
130
+ for (uint8_t ab = 0 ; ab < 4 ; ab ++ ) {
131
+ if (cnts [ab ] >= samples_needed / 2 + 1 ) { // more than half
132
+ ec11_apply_reading (drv_data , ab >> 1 , ab & 1 );
133
+ if (cnts [ab ] == samples_needed ) { // stable for a full window
134
+ LOG_DBG ("timer stop" );
135
+ drv_data -> samples = 0 ;
136
+ drv_data -> running = false;
137
+ k_timer_stop (& drv_data -> debouncer );
138
+ }
139
+ break ;
140
+ }
141
+ }
142
+ }
143
+
144
+ static void ec11_interrupt_cb_comon (struct ec11_data * drv_data ) {
145
+ if (!drv_data -> running ) {
146
+ LOG_DBG ("timer start" );
147
+ drv_data -> running = true;
148
+ const struct ec11_config * drv_cfg = drv_data -> dev -> config ;
149
+ int32_t ms = drv_cfg -> debounce_scan_period_ms ;
150
+ k_timer_start (& drv_data -> debouncer , K_MSEC (ms ), K_MSEC (ms ));
151
+ }
152
+ }
153
+
154
+ static void ec11_cb_a (const struct device * port , struct gpio_callback * cb , uint32_t pins ) {
155
+ ec11_interrupt_cb_comon (CONTAINER_OF (cb , struct ec11_data , a_gpio_cb ));
156
+ }
157
+
158
+ static void ec11_cb_b (const struct device * port , struct gpio_callback * cb , uint32_t pins ) {
159
+ ec11_interrupt_cb_comon (CONTAINER_OF (cb , struct ec11_data , b_gpio_cb ));
160
+ }
161
+
111
162
int ec11_init (const struct device * dev ) {
112
- struct ec11_data * drv_data = dev -> data ;
113
163
const struct ec11_config * drv_cfg = dev -> config ;
114
-
115
164
LOG_DBG ("A: %s %d B: %s %d resolution %d" , drv_cfg -> a .port -> name , drv_cfg -> a .pin ,
116
165
drv_cfg -> b .port -> name , drv_cfg -> b .pin , drv_cfg -> resolution );
117
166
118
167
if (!device_is_ready (drv_cfg -> a .port )) {
119
168
LOG_ERR ("A GPIO device is not ready" );
120
169
return - EINVAL ;
121
170
}
122
-
123
171
if (!device_is_ready (drv_cfg -> b .port )) {
124
172
LOG_ERR ("B GPIO device is not ready" );
125
173
return - EINVAL ;
126
174
}
127
175
128
176
if (gpio_pin_configure_dt (& drv_cfg -> a , GPIO_INPUT )) {
129
- LOG_DBG ("Failed to configure A pin" );
177
+ LOG_ERR ("Failed to configure A pin" );
130
178
return - EIO ;
131
179
}
132
-
133
180
if (gpio_pin_configure_dt (& drv_cfg -> b , GPIO_INPUT )) {
134
- LOG_DBG ("Failed to configure B pin" );
181
+ LOG_ERR ("Failed to configure B pin" );
135
182
return - EIO ;
136
183
}
137
184
138
- #ifdef CONFIG_EC11_TRIGGER
139
- if (ec11_init_interrupt (dev ) < 0 ) {
140
- LOG_DBG ("Failed to initialize interrupt!" );
185
+ struct ec11_data * drv_data = dev -> data ; // already zero-initialized
186
+ drv_data -> dev = dev ;
187
+ drv_data -> prev_a = gpio_pin_get_dt (& drv_cfg -> a );
188
+ drv_data -> prev_b = gpio_pin_get_dt (& drv_cfg -> b );
189
+
190
+ // enable interrupts
191
+ gpio_init_callback (& drv_data -> a_gpio_cb , ec11_cb_a , BIT (drv_cfg -> a .pin ));
192
+ if (gpio_add_callback (drv_cfg -> a .port , & drv_data -> a_gpio_cb ) < 0 ) {
193
+ LOG_ERR ("Failed to set A callback!" );
194
+ return - EIO ;
195
+ }
196
+ gpio_init_callback (& drv_data -> b_gpio_cb , ec11_cb_b , BIT (drv_cfg -> b .pin ));
197
+ if (gpio_add_callback (drv_cfg -> b .port , & drv_data -> b_gpio_cb ) < 0 ) {
198
+ LOG_ERR ("Failed to set B callback!" );
199
+ return - EIO ;
200
+ }
201
+ if (gpio_pin_interrupt_configure_dt (& drv_cfg -> a , GPIO_INT_EDGE_BOTH )) {
202
+ LOG_ERR ("Unable to set A pin GPIO interrupt" );
203
+ return - EIO ;
204
+ }
205
+ if (gpio_pin_interrupt_configure_dt (& drv_cfg -> b , GPIO_INT_EDGE_BOTH )) {
206
+ LOG_ERR ("Unable to set B pin GPIO interrupt" );
141
207
return - EIO ;
142
208
}
143
- #endif
144
-
145
- drv_data -> ab_state = ec11_get_ab_state (dev );
146
209
210
+ k_timer_init (& drv_data -> debouncer , ec11_period , NULL );
147
211
return 0 ;
148
212
}
149
213
@@ -154,6 +218,8 @@ int ec11_init(const struct device *dev) {
154
218
.b = GPIO_DT_SPEC_INST_GET(n, b_gpios), \
155
219
.resolution = DT_INST_PROP_OR(n, resolution, 1), \
156
220
.steps = DT_INST_PROP_OR(n, steps, 0), \
221
+ .debounce_ms = DT_INST_PROP_OR(n, debounce_ms, 5), \
222
+ .debounce_scan_period_ms = DT_INST_PROP_OR(n, debounce_scan_period_ms, 1), \
157
223
}; \
158
224
DEVICE_DT_INST_DEFINE(n, ec11_init, NULL, &ec11_data_##n, &ec11_cfg_##n, POST_KERNEL, \
159
225
CONFIG_SENSOR_INIT_PRIORITY, &ec11_driver_api);
0 commit comments