xref: /aosp_15_r20/external/libwebsockets/lib/drivers/button/README.md (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker# LWS GPIO Button class drivers
2*1c60b9acSAndroid Build Coastguard Worker
3*1c60b9acSAndroid Build Coastguard WorkerLws provides an GPIO button controller class, this centralizes handling a set of
4*1c60b9acSAndroid Build Coastguard Workerup to 31 buttons for resource efficiency.  Each controller has two OS timers,
5*1c60b9acSAndroid Build Coastguard Workerone for interrupt to bottom-half event triggering and another that runs at 5ms
6*1c60b9acSAndroid Build Coastguard Workerintervals only when one or more button is down.
7*1c60b9acSAndroid Build Coastguard Worker
8*1c60b9acSAndroid Build Coastguard WorkerEach button has its own active level control and sophisticated state tracking;
9*1c60b9acSAndroid Build Coastguard Workereach button can apply its own classification regime, to allow for different
10*1c60b9acSAndroid Build Coastguard Workerphysical button characteristics, if not overridden a default one is provided.
11*1c60b9acSAndroid Build Coastguard Worker
12*1c60b9acSAndroid Build Coastguard WorkerBoth the controller and individual buttons specify names that are used in the
13*1c60b9acSAndroid Build Coastguard WorkerJSON events produced when the buttons perform actions.
14*1c60b9acSAndroid Build Coastguard Worker
15*1c60b9acSAndroid Build Coastguard Worker## Button electronic to logical event processing
16*1c60b9acSAndroid Build Coastguard Worker
17*1c60b9acSAndroid Build Coastguard WorkerButtons are monitored using GPIO interrupts since this is very cheap in the
18*1c60b9acSAndroid Build Coastguard Workerusual case no interaction is ongoing.  There is assumed to be one interrupt
19*1c60b9acSAndroid Build Coastguard Workerper GPIO, but they are pointed at the same ISR, with an opaque pointer to an
20*1c60b9acSAndroid Build Coastguard Workerinternal struct passed per-interrupt to differentiate them and bind them to a
21*1c60b9acSAndroid Build Coastguard Workerparticular button.
22*1c60b9acSAndroid Build Coastguard Worker
23*1c60b9acSAndroid Build Coastguard WorkerThe interrupt is set for notification of the active-going edge, usually if
24*1c60b9acSAndroid Build Coastguard Workerthe button is pulled-up, that's the downgoing edge only.  This avoids any
25*1c60b9acSAndroid Build Coastguard Workerambiguity about the interrupt meaning, although oscillation is common around
26*1c60b9acSAndroid Build Coastguard Workerthe transition region when the signal is becoming inactive too.
27*1c60b9acSAndroid Build Coastguard Worker
28*1c60b9acSAndroid Build Coastguard WorkerAn OS timer is used to schedule a bottom-half handler outside of interrupt
29*1c60b9acSAndroid Build Coastguard Workercontext.
30*1c60b9acSAndroid Build Coastguard Worker
31*1c60b9acSAndroid Build Coastguard WorkerTo combat commonly-seen partial charging of the actual and parasitic network
32*1c60b9acSAndroid Build Coastguard Workeraround the button causing drift and oscillation, the bottom-half briefly drives
33*1c60b9acSAndroid Build Coastguard Workerthe button signal to the active level, forcing a more deterministic charge level
34*1c60b9acSAndroid Build Coastguard Workerif it reached the point the interrupt was triggered.  This removes much of the
35*1c60b9acSAndroid Build Coastguard Workerunpredictable behaviour in the us range.  It would be better done in the ISR
36*1c60b9acSAndroid Build Coastguard Workerbut many OS apis cannot perform GPIO operations in interrupt context.
37*1c60b9acSAndroid Build Coastguard Worker
38*1c60b9acSAndroid Build Coastguard WorkerThe bottom-half makes sure a monitoring timer is enabled, by refcount.  This
39*1c60b9acSAndroid Build Coastguard Workeris the engine of the rest of the classification while any button is down.  The
40*1c60b9acSAndroid Build Coastguard Workermonitoring timer happens per OS tick or 5ms, whichever is longer.
41*1c60b9acSAndroid Build Coastguard Worker
42*1c60b9acSAndroid Build Coastguard Worker## Declaring button controllers
43*1c60b9acSAndroid Build Coastguard Worker
44*1c60b9acSAndroid Build Coastguard WorkerAn array of button map elements if provided first mapping at least GPIOs to
45*1c60b9acSAndroid Build Coastguard Workerbutton names, and also optionally the classification regime for that button.
46*1c60b9acSAndroid Build Coastguard Worker
47*1c60b9acSAndroid Build Coastguard WorkerThen the button controller definition which points back to the button map.
48*1c60b9acSAndroid Build Coastguard Worker
49*1c60b9acSAndroid Build Coastguard Worker```
50*1c60b9acSAndroid Build Coastguard Workerstatic const lws_button_map_t bcm[] = {
51*1c60b9acSAndroid Build Coastguard Worker	{
52*1c60b9acSAndroid Build Coastguard Worker		.gpio			= GPIO_NUM_0,
53*1c60b9acSAndroid Build Coastguard Worker		.smd_interaction_name	= "user"
54*1c60b9acSAndroid Build Coastguard Worker	},
55*1c60b9acSAndroid Build Coastguard Worker};
56*1c60b9acSAndroid Build Coastguard Worker
57*1c60b9acSAndroid Build Coastguard Workerstatic const lws_button_controller_t bc = {
58*1c60b9acSAndroid Build Coastguard Worker	.smd_bc_name			= "bc",
59*1c60b9acSAndroid Build Coastguard Worker	.gpio_ops			= &lws_gpio_plat,
60*1c60b9acSAndroid Build Coastguard Worker	.button_map			= &bcm[0],
61*1c60b9acSAndroid Build Coastguard Worker	.active_state_bitmap		= 0,
62*1c60b9acSAndroid Build Coastguard Worker	.count_buttons			= LWS_ARRAY_SIZE(bcm),
63*1c60b9acSAndroid Build Coastguard Worker};
64*1c60b9acSAndroid Build Coastguard Worker
65*1c60b9acSAndroid Build Coastguard Worker	struct lws_button_state *bcs;
66*1c60b9acSAndroid Build Coastguard Worker
67*1c60b9acSAndroid Build Coastguard Worker	bcs = lws_button_controller_create(context, &bc);
68*1c60b9acSAndroid Build Coastguard Worker	if (!bcs) {
69*1c60b9acSAndroid Build Coastguard Worker		lwsl_err("%s: could not create buttons\n", __func__);
70*1c60b9acSAndroid Build Coastguard Worker		goto spin;
71*1c60b9acSAndroid Build Coastguard Worker	}
72*1c60b9acSAndroid Build Coastguard Worker```
73*1c60b9acSAndroid Build Coastguard Worker
74*1c60b9acSAndroid Build Coastguard WorkerThat is all that is needed for init, button events will be issued on lws_smd
75*1c60b9acSAndroid Build Coastguard Workerwhen buttons are pressed.
76*1c60b9acSAndroid Build Coastguard Worker
77*1c60b9acSAndroid Build Coastguard Worker### Regime settings
78*1c60b9acSAndroid Build Coastguard Worker
79*1c60b9acSAndroid Build Coastguard WorkerThe classification regime is designed to reflect both the user interaction
80*1c60b9acSAndroid Build Coastguard Workerstyle and the characteristics of a particular type of button.
81*1c60b9acSAndroid Build Coastguard Worker
82*1c60b9acSAndroid Build Coastguard WorkerMember|Default|Meaning
83*1c60b9acSAndroid Build Coastguard Worker---|---|---
84*1c60b9acSAndroid Build Coastguard Workerms_min_down|20ms|Down events shorter than this are ignored
85*1c60b9acSAndroid Build Coastguard Workerms_min_down_longpress|300ms|Down events longer than this are reported as a long-click
86*1c60b9acSAndroid Build Coastguard Workerms_up_settle|20ms|After the first indication a button is no longer down, the button is ignored for this interval
87*1c60b9acSAndroid Build Coastguard Workerms_doubleclick_grace|120ms|The time allowed after a click to see if a second, double-click, is forthcoming
88*1c60b9acSAndroid Build Coastguard Workerms_repeat_down|0 / disabled|If held down, interval at which to issue `stilldown` events
89*1c60b9acSAndroid Build Coastguard Workerflags|LWSBTNRGMFLAG_CLASSIFY_DOUBLECLICK|Control which classifications can apply
90*1c60b9acSAndroid Build Coastguard Worker
91*1c60b9acSAndroid Build Coastguard Worker### lws_smd System Message Distribution Events
92*1c60b9acSAndroid Build Coastguard Worker
93*1c60b9acSAndroid Build Coastguard WorkerThe button controller emits system messages of class `LWSSMDCL_INTERACTION`,
94*1c60b9acSAndroid Build Coastguard Workerusing a JSON formatted payload
95*1c60b9acSAndroid Build Coastguard Worker
96*1c60b9acSAndroid Build Coastguard Worker```
97*1c60b9acSAndroid Build Coastguard Worker{
98*1c60b9acSAndroid Build Coastguard Worker	"type":  "button",
99*1c60b9acSAndroid Build Coastguard Worker	"src":   "controller-name/button-name",
100*1c60b9acSAndroid Build Coastguard Worker	"event": "event-name"
101*1c60b9acSAndroid Build Coastguard Worker}
102*1c60b9acSAndroid Build Coastguard Worker```
103*1c60b9acSAndroid Build Coastguard Worker
104*1c60b9acSAndroid Build Coastguard WorkerFor example, `{"type":"button","src":"bc/user","event":"doubleclick"}`
105*1c60b9acSAndroid Build Coastguard Worker
106*1c60b9acSAndroid Build Coastguard WorkerJSON is used because it is maintainable, extensible, self-documenting and does
107*1c60b9acSAndroid Build Coastguard Workernot require a central, fragile-against-versioning specification of mappings.
108*1c60b9acSAndroid Build Coastguard WorkerUsing button names allows the same code to adapt to different hardware or
109*1c60b9acSAndroid Build Coastguard Workerbutton mappings.  Button events may be synthesized for test or other purposes
110*1c60b9acSAndroid Build Coastguard Workercleanly and clearly.
111*1c60b9acSAndroid Build Coastguard Worker
112*1c60b9acSAndroid Build Coastguard WorkerAll the events are somewhat filtered, too short glitches from EMI or whatever
113*1c60b9acSAndroid Build Coastguard Workerare not reported.  "up" and "down" events are reported for the buttons in case
114*1c60b9acSAndroid Build Coastguard Workerthe intention is the duration of the press is meaningful to the user code, but
115*1c60b9acSAndroid Build Coastguard Workermore typically the user code wants to consume a higher-level classification of
116*1c60b9acSAndroid Build Coastguard Workerthe interaction, eg, that it can be understood as a single "double-click" event.
117*1c60b9acSAndroid Build Coastguard Worker
118*1c60b9acSAndroid Build Coastguard WorkerEvent name|Meaning
119*1c60b9acSAndroid Build Coastguard Worker---|---
120*1c60b9acSAndroid Build Coastguard Workerdown|The button passes a filter for being down, useful for duration-based response
121*1c60b9acSAndroid Build Coastguard Workerstilldown|The regime can be configured to issue "repeat" notifications at intervals
122*1c60b9acSAndroid Build Coastguard Workerup|The button has come up, useful for duration-based response
123*1c60b9acSAndroid Build Coastguard Workerclick|The button activity resulted in a classification as a single-click
124*1c60b9acSAndroid Build Coastguard Workerlongclick|The button activity resulted in a classification as a long-click
125*1c60b9acSAndroid Build Coastguard Workerdoubleclick|The button activity resulted in a classification as a double-click
126*1c60b9acSAndroid Build Coastguard Worker
127*1c60b9acSAndroid Build Coastguard WorkerSince double-click detection requires delaying click reporting until it becomes
128*1c60b9acSAndroid Build Coastguard Workerclear a second click isn't coming, it is enabled as a possible classification in
129*1c60b9acSAndroid Build Coastguard Workerthe regime structure and the regime structure chosen per-button.
130*1c60b9acSAndroid Build Coastguard Worker
131*1c60b9acSAndroid Build Coastguard WorkerTypically user code is interested in, eg, a high level classification of what
132*1c60b9acSAndroid Build Coastguard Workerthe button is doing, eg, a "click" event on a specific button.  Rather than
133*1c60b9acSAndroid Build Coastguard Workerperform a JSON parse, these events can be processed as strings cheaply using
134*1c60b9acSAndroid Build Coastguard Worker`lws_json_simple_strcmp()`, it's dumb enough to be cheap but smart enough to
135*1c60b9acSAndroid Build Coastguard Workerunderstand enough JSON semantics to be accurate, while retaining the ability to
136*1c60b9acSAndroid Build Coastguard Workerchange and extend the JSON, eg
137*1c60b9acSAndroid Build Coastguard Worker
138*1c60b9acSAndroid Build Coastguard Worker```
139*1c60b9acSAndroid Build Coastguard Worker	if (!lws_json_simple_strcmp(buf, len, "\"src\":", "bc/user")) {
140*1c60b9acSAndroid Build Coastguard Worker		if (!lws_json_simple_strcmp(buf, len, "\"event\":", "click")) {
141*1c60b9acSAndroid Build Coastguard Worker			...
142*1c60b9acSAndroid Build Coastguard Worker		}
143*1c60b9acSAndroid Build Coastguard Worker		...
144*1c60b9acSAndroid Build Coastguard Worker	}
145*1c60b9acSAndroid Build Coastguard Worker```
146*1c60b9acSAndroid Build Coastguard Worker
147*1c60b9acSAndroid Build Coastguard Worker### Relationship between up / down and classification
148*1c60b9acSAndroid Build Coastguard Worker
149*1c60b9acSAndroid Build Coastguard WorkerClassification|Sequencing
150*1c60b9acSAndroid Build Coastguard Worker---|---
151*1c60b9acSAndroid Build Coastguard Workerclick|down-up-click (it's classified when it went up and cannot be a longclick)
152*1c60b9acSAndroid Build Coastguard Workerlongclick|down-longclick-up (it's classified while still down)
153*1c60b9acSAndroid Build Coastguard Workerdoubleclick|down-up-down-doubleclick-up (classified as soon as second click down long enough)
154*1c60b9acSAndroid Build Coastguard Worker
155*1c60b9acSAndroid Build Coastguard WorkerIf the regime is configured for it, any "down" may be followed by one or more
156*1c60b9acSAndroid Build Coastguard Worker"stilldown" at intervals if the button is down long enough
157