xref: /aosp_15_r20/external/libwebsockets/lib/drivers/led/README.md (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker# lws_led gpio and pwm class drivers
2*1c60b9acSAndroid Build Coastguard Worker
3*1c60b9acSAndroid Build Coastguard WorkerLws provides an abstract led controller class that can bind an array of LEDs
4*1c60b9acSAndroid Build Coastguard Workerto gpio and pwm controllers, and automatically handled pwm sequencers.
5*1c60b9acSAndroid Build Coastguard Worker
6*1c60b9acSAndroid Build Coastguard WorkerLumience intensity is corrected for IEC curves to match perceptual intensity,
7*1c60b9acSAndroid Build Coastguard Workerand the correction can be overridden per led for curve adaptation matching.
8*1c60b9acSAndroid Build Coastguard Worker
9*1c60b9acSAndroid Build Coastguard WorkerIntensity is normalized to a 16-bit scale, when controlled by a GPIO b15 is
10*1c60b9acSAndroid Build Coastguard Workersignificant and the rest ignored.  When controlled by PWM, as many bits from
11*1c60b9acSAndroid Build Coastguard Workerb15 down are significant as the PWM arrangements can represent.
12*1c60b9acSAndroid Build Coastguard Worker
13*1c60b9acSAndroid Build Coastguard WorkerThe PWM sequencers use arbitrary function generation callbacks on a normalized
14*1c60b9acSAndroid Build Coastguard Worker16-bit phase space, they can choose how much to interpolate and how much to put
15*1c60b9acSAndroid Build Coastguard Workerin a table, a 64-sample, 16-bit sine function is provided along with 16-bit
16*1c60b9acSAndroid Build Coastguard Workerlinear sawtooth.
17*1c60b9acSAndroid Build Coastguard Worker
18*1c60b9acSAndroid Build Coastguard WorkerChanging the sequencer is subject to a third transition function sequencer, this
19*1c60b9acSAndroid Build Coastguard Workercan for example mix the transition linearly over, eg, 500ms so the leds look
20*1c60b9acSAndroid Build Coastguard Workervery smooth.
21*1c60b9acSAndroid Build Coastguard Worker
22*1c60b9acSAndroid Build Coastguard Worker## Defining an led controller
23*1c60b9acSAndroid Build Coastguard Worker
24*1c60b9acSAndroid Build Coastguard WorkerAn array of inidividual LED information is provided first, and referenced by
25*1c60b9acSAndroid Build Coastguard Workerthe LED controller definintion.  Leds are named so code does not introduce
26*1c60b9acSAndroid Build Coastguard Workerdependencies on specific implementations.
27*1c60b9acSAndroid Build Coastguard Worker
28*1c60b9acSAndroid Build Coastguard Worker```
29*1c60b9acSAndroid Build Coastguard Workerstatic const lws_led_gpio_map_t lgm[] = {
30*1c60b9acSAndroid Build Coastguard Worker	{
31*1c60b9acSAndroid Build Coastguard Worker		.name			= "alert",
32*1c60b9acSAndroid Build Coastguard Worker		.gpio			= GPIO_NUM_25,
33*1c60b9acSAndroid Build Coastguard Worker		.pwm_ops		= &pwm_ops,
34*1c60b9acSAndroid Build Coastguard Worker		.active_level		= 1,
35*1c60b9acSAndroid Build Coastguard Worker	},
36*1c60b9acSAndroid Build Coastguard Worker};
37*1c60b9acSAndroid Build Coastguard Worker
38*1c60b9acSAndroid Build Coastguard Workerstatic const lws_led_gpio_controller_t lgc = {
39*1c60b9acSAndroid Build Coastguard Worker	.led_ops			= lws_led_gpio_ops,
40*1c60b9acSAndroid Build Coastguard Worker	.gpio_ops			= &lws_gpio_plat,
41*1c60b9acSAndroid Build Coastguard Worker	.led_map			= &lgm[0],
42*1c60b9acSAndroid Build Coastguard Worker	.count_leds			= LWS_ARRAY_SIZE(lgm)
43*1c60b9acSAndroid Build Coastguard Worker};
44*1c60b9acSAndroid Build Coastguard Worker
45*1c60b9acSAndroid Build Coastguard Worker	struct lws_led_state *lls;
46*1c60b9acSAndroid Build Coastguard Worker
47*1c60b9acSAndroid Build Coastguard Worker	lls = lgc.led_ops.create(&lgc.led_ops);
48*1c60b9acSAndroid Build Coastguard Worker	if (!lls) {
49*1c60b9acSAndroid Build Coastguard Worker		lwsl_err("%s: could not create led\n", __func__);
50*1c60b9acSAndroid Build Coastguard Worker		goto spin;
51*1c60b9acSAndroid Build Coastguard Worker	}
52*1c60b9acSAndroid Build Coastguard Worker
53*1c60b9acSAndroid Build Coastguard Worker```
54*1c60b9acSAndroid Build Coastguard Worker
55*1c60b9acSAndroid Build Coastguard WorkerFor GPIO control, the active level of the GPIO to light the LED may be set.
56*1c60b9acSAndroid Build Coastguard Worker
57*1c60b9acSAndroid Build Coastguard WorkerEach LED may bind to a pwm controller, in which case setting the intensity
58*1c60b9acSAndroid Build Coastguard Workerprograms the pwm controller corresponding to the GPIO.
59*1c60b9acSAndroid Build Coastguard Worker
60*1c60b9acSAndroid Build Coastguard Worker## Setting the intensity directly
61*1c60b9acSAndroid Build Coastguard Worker
62*1c60b9acSAndroid Build Coastguard Worker```
63*1c60b9acSAndroid Build Coastguard Worker	lgc.led_ops.intensity(&lgc.led_ops, "alert", 0);
64*1c60b9acSAndroid Build Coastguard Worker```
65*1c60b9acSAndroid Build Coastguard Worker
66*1c60b9acSAndroid Build Coastguard Worker## Defining Sequencer
67*1c60b9acSAndroid Build Coastguard Worker
68*1c60b9acSAndroid Build Coastguard WorkerSome common sequencers are provided out of the box, you can also define your
69*1c60b9acSAndroid Build Coastguard Workerown arbitrary ones.
70*1c60b9acSAndroid Build Coastguard Worker
71*1c60b9acSAndroid Build Coastguard WorkerThe main point is sequencers have a function that returns an intensity for each
72*1c60b9acSAndroid Build Coastguard Workerof 65536 phase steps in its cycle.  For example, this is the linear function
73*1c60b9acSAndroid Build Coastguard Workerthat is included
74*1c60b9acSAndroid Build Coastguard Worker
75*1c60b9acSAndroid Build Coastguard Worker```
76*1c60b9acSAndroid Build Coastguard Workerlws_led_intensity_t
77*1c60b9acSAndroid Build Coastguard Workerlws_led_func_linear(lws_led_seq_phase_t n)
78*1c60b9acSAndroid Build Coastguard Worker{
79*1c60b9acSAndroid Build Coastguard Worker	return (lws_led_intensity_t)n;
80*1c60b9acSAndroid Build Coastguard Worker}
81*1c60b9acSAndroid Build Coastguard Worker```
82*1c60b9acSAndroid Build Coastguard Worker
83*1c60b9acSAndroid Build Coastguard WorkerIt simply returns an intensity between 0 - 65535 matching the phase angle of
84*1c60b9acSAndroid Build Coastguard Worker0 - 65535 that it was given, so it's a sawtooth ramp.
85*1c60b9acSAndroid Build Coastguard Worker
86*1c60b9acSAndroid Build Coastguard WorkerAn interpolated sine function is also provided that returns an intensity
87*1c60b9acSAndroid Build Coastguard Workerbetween 0 - 65535 reflecting one cycle of sine wave for the phase angle of 0 -
88*1c60b9acSAndroid Build Coastguard Worker65535.
89*1c60b9acSAndroid Build Coastguard Worker
90*1c60b9acSAndroid Build Coastguard WorkerThese functions are packaged into sequencer structures like this
91*1c60b9acSAndroid Build Coastguard Worker
92*1c60b9acSAndroid Build Coastguard Worker```
93*1c60b9acSAndroid Build Coastguard Workerconst lws_led_sequence_def_t lws_pwmseq_sine_endless_fast = {
94*1c60b9acSAndroid Build Coastguard Worker	.func			= lws_led_func_sine,
95*1c60b9acSAndroid Build Coastguard Worker	.ledphase_offset	= 0, /* already at 0 amp at 0 phase */
96*1c60b9acSAndroid Build Coastguard Worker	.ledphase_total		= LWS_SEQ_LEDPHASE_TOTAL_ENDLESS,
97*1c60b9acSAndroid Build Coastguard Worker	.ms			= 750
98*1c60b9acSAndroid Build Coastguard Worker};
99*1c60b9acSAndroid Build Coastguard Worker```
100*1c60b9acSAndroid Build Coastguard Worker
101*1c60b9acSAndroid Build Coastguard WorkerThis "endless" sequencer cycles through the sine function at 750ms per cycle.
102*1c60b9acSAndroid Build Coastguard WorkerNon-endless sequencers have a specific start and end in the phase space, eg
103*1c60b9acSAndroid Build Coastguard Worker
104*1c60b9acSAndroid Build Coastguard Worker```
105*1c60b9acSAndroid Build Coastguard Workerconst lws_led_sequence_def_t lws_pwmseq_sine_up = {
106*1c60b9acSAndroid Build Coastguard Worker	.func			= lws_led_func_sine,
107*1c60b9acSAndroid Build Coastguard Worker	.ledphase_offset	= 0, /* already at 0 amp at 0 phase */
108*1c60b9acSAndroid Build Coastguard Worker	.ledphase_total		= LWS_LED_FUNC_PHASE / 2, /* 180 degree ./^ */
109*1c60b9acSAndroid Build Coastguard Worker	.ms			= 300
110*1c60b9acSAndroid Build Coastguard Worker};
111*1c60b9acSAndroid Build Coastguard Worker```
112*1c60b9acSAndroid Build Coastguard Worker
113*1c60b9acSAndroid Build Coastguard Worker... this one traverses 180 degrees of the sine wave starting from 0 and ending
114*1c60b9acSAndroid Build Coastguard Workerat full intensity, over 300ms.
115*1c60b9acSAndroid Build Coastguard Worker
116*1c60b9acSAndroid Build Coastguard WorkerA commonly-used, provided one is like this, as used in the next section
117*1c60b9acSAndroid Build Coastguard Worker
118*1c60b9acSAndroid Build Coastguard Worker```
119*1c60b9acSAndroid Build Coastguard Workerconst lws_led_sequence_def_t lws_pwmseq_linear_wipe = {
120*1c60b9acSAndroid Build Coastguard Worker	.func			= lws_led_func_linear,
121*1c60b9acSAndroid Build Coastguard Worker	.ledphase_offset	= 0,
122*1c60b9acSAndroid Build Coastguard Worker	.ledphase_total		= LWS_LED_FUNC_PHASE - 1,
123*1c60b9acSAndroid Build Coastguard Worker	.ms			= 300
124*1c60b9acSAndroid Build Coastguard Worker};
125*1c60b9acSAndroid Build Coastguard Worker```
126*1c60b9acSAndroid Build Coastguard Worker
127*1c60b9acSAndroid Build Coastguard Worker## Setting the intensity using sequencer transitions
128*1c60b9acSAndroid Build Coastguard Worker
129*1c60b9acSAndroid Build Coastguard WorkerThe main api for high level sequenced control is
130*1c60b9acSAndroid Build Coastguard Worker
131*1c60b9acSAndroid Build Coastguard Worker```
132*1c60b9acSAndroid Build Coastguard Workerint
133*1c60b9acSAndroid Build Coastguard Workerlws_led_transition(struct lws_led_state *lcs, const char *name,
134*1c60b9acSAndroid Build Coastguard Worker		   const lws_led_sequence_def_t *next,
135*1c60b9acSAndroid Build Coastguard Worker		   const lws_led_sequence_def_t *trans);
136*1c60b9acSAndroid Build Coastguard Worker```
137*1c60b9acSAndroid Build Coastguard Worker
138*1c60b9acSAndroid Build Coastguard WorkerThis fades from the current sequence to a new sequence, using `trans` sequencer
139*1c60b9acSAndroid Build Coastguard Workerintensity as the mix factor.  `trans` is typically `lws_pwmseq_linear_wipe`,
140*1c60b9acSAndroid Build Coastguard Workerfading between the current and new linearly over 300ms.  At the end of the
141*1c60b9acSAndroid Build Coastguard Worker`trans` sequence, the new sequence simply replaces the current one and the
142*1c60b9acSAndroid Build Coastguard Workertransition is completed.
143*1c60b9acSAndroid Build Coastguard Worker
144*1c60b9acSAndroid Build Coastguard WorkerSequencers use a single 30Hz OS timer while any sequence is active.
145*1c60b9acSAndroid Build Coastguard Worker
146*1c60b9acSAndroid Build Coastguard Workerexported sequencer symbol|description
147*1c60b9acSAndroid Build Coastguard Worker---|---
148*1c60b9acSAndroid Build Coastguard Workerlws_pwmseq_sine_endless_slow|continuous 100% sine, 1.5s cycle
149*1c60b9acSAndroid Build Coastguard Workerlws_pwmseq_sine_endless_fast|continuous 100% sine, 0.75s cycle
150*1c60b9acSAndroid Build Coastguard Workerlws_pwmseq_linear_wipe|single 0 - 100% ramp over 0.3s
151*1c60b9acSAndroid Build Coastguard Workerlws_pwmseq_sine_up|single 0 - 100% using sine curve over 0.3s
152*1c60b9acSAndroid Build Coastguard Workerlws_pwmseq_sine_down|single 100% - 0 using sine curve over 0.3s
153*1c60b9acSAndroid Build Coastguard Workerlws_pwmseq_static_on|100% static
154*1c60b9acSAndroid Build Coastguard Workerlws_pwmseq_static_half|50% static
155*1c60b9acSAndroid Build Coastguard Workerlws_pwmseq_static_off|0% static
156