mirror of
https://libwebsockets.org/repo/libwebsockets
synced 2024-11-22 09:02:33 +00:00
63c1e8ba00
Add lws_display and minimal example support for esp32-wrover to match wsp32-heltec-wb32 Since no usable buttons that don't affect something else on wrover kit, assumes a button to 0V on GPIO14.
156 lines
4.7 KiB
Markdown
156 lines
4.7 KiB
Markdown
# lws_led gpio and pwm class drivers
|
|
|
|
Lws provides an abstract led controller class that can bind an array of LEDs
|
|
to gpio and pwm controllers, and automatically handled pwm sequencers.
|
|
|
|
Lumience intensity is corrected for IEC curves to match perceptual intensity,
|
|
and the correction can be overridden per led for curve adaptation matching.
|
|
|
|
Intensity is normalized to a 16-bit scale, when controlled by a GPIO b15 is
|
|
significant and the rest ignored. When controlled by PWM, as many bits from
|
|
b15 down are significant as the PWM arrangements can represent.
|
|
|
|
The PWM sequencers use arbitrary function generation callbacks on a normalized
|
|
16-bit phase space, they can choose how much to interpolate and how much to put
|
|
in a table, a 64-sample, 16-bit sine function is provided along with 16-bit
|
|
linear sawtooth.
|
|
|
|
Changing the sequencer is subject to a third transition function sequencer, this
|
|
can for example mix the transition linearly over, eg, 500ms so the leds look
|
|
very smooth.
|
|
|
|
## Defining an led controller
|
|
|
|
An array of inidividual LED information is provided first, and referenced by
|
|
the LED controller definintion. Leds are named so code does not introduce
|
|
dependencies on specific implementations.
|
|
|
|
```
|
|
static const lws_led_gpio_map_t lgm[] = {
|
|
{
|
|
.name = "alert",
|
|
.gpio = GPIO_NUM_25,
|
|
.pwm_ops = &pwm_ops,
|
|
.active_level = 1,
|
|
},
|
|
};
|
|
|
|
static const lws_led_gpio_controller_t lgc = {
|
|
.led_ops = lws_led_gpio_ops,
|
|
.gpio_ops = &lws_gpio_plat,
|
|
.led_map = &lgm[0],
|
|
.count_leds = LWS_ARRAY_SIZE(lgm)
|
|
};
|
|
|
|
struct lws_led_state *lls;
|
|
|
|
lls = lgc.led_ops.create(&lgc.led_ops);
|
|
if (!lls) {
|
|
lwsl_err("%s: could not create led\n", __func__);
|
|
goto spin;
|
|
}
|
|
|
|
```
|
|
|
|
For GPIO control, the active level of the GPIO to light the LED may be set.
|
|
|
|
Each LED may bind to a pwm controller, in which case setting the intensity
|
|
programs the pwm controller corresponding to the GPIO.
|
|
|
|
## Setting the intensity directly
|
|
|
|
```
|
|
lgc.led_ops.intensity(&lgc.led_ops, "alert", 0);
|
|
```
|
|
|
|
## Defining Sequencer
|
|
|
|
Some common sequencers are provided out of the box, you can also define your
|
|
own arbitrary ones.
|
|
|
|
The main point is sequencers have a function that returns an intensity for each
|
|
of 65536 phase steps in its cycle. For example, this is the linear function
|
|
that is included
|
|
|
|
```
|
|
lws_led_intensity_t
|
|
lws_led_func_linear(lws_led_seq_phase_t n)
|
|
{
|
|
return (lws_led_intensity_t)n;
|
|
}
|
|
```
|
|
|
|
It simply returns an intensity between 0 - 65535 matching the phase angle of
|
|
0 - 65535 that it was given, so it's a sawtooth ramp.
|
|
|
|
An interpolated sine function is also provided that returns an intensity
|
|
between 0 - 65535 reflecting one cycle of sine wave for the phase angle of 0 -
|
|
65535.
|
|
|
|
These functions are packaged into sequencer structures like this
|
|
|
|
```
|
|
const lws_led_sequence_def_t lws_pwmseq_sine_endless_fast = {
|
|
.func = lws_led_func_sine,
|
|
.ledphase_offset = 0, /* already at 0 amp at 0 phase */
|
|
.ledphase_total = LWS_SEQ_LEDPHASE_TOTAL_ENDLESS,
|
|
.ms = 750
|
|
};
|
|
```
|
|
|
|
This "endless" sequencer cycles through the sine function at 750ms per cycle.
|
|
Non-endless sequencers have a specific start and end in the phase space, eg
|
|
|
|
```
|
|
const lws_led_sequence_def_t lws_pwmseq_sine_up = {
|
|
.func = lws_led_func_sine,
|
|
.ledphase_offset = 0, /* already at 0 amp at 0 phase */
|
|
.ledphase_total = LWS_LED_FUNC_PHASE / 2, /* 180 degree ./^ */
|
|
.ms = 300
|
|
};
|
|
```
|
|
|
|
... this one traverses 180 degrees of the sine wave starting from 0 and ending
|
|
at full intensity, over 300ms.
|
|
|
|
A commonly-used, provided one is like this, as used in the next section
|
|
|
|
```
|
|
const lws_led_sequence_def_t lws_pwmseq_linear_wipe = {
|
|
.func = lws_led_func_linear,
|
|
.ledphase_offset = 0,
|
|
.ledphase_total = LWS_LED_FUNC_PHASE - 1,
|
|
.ms = 300
|
|
};
|
|
```
|
|
|
|
## Setting the intensity using sequencer transitions
|
|
|
|
The main api for high level sequenced control is
|
|
|
|
```
|
|
int
|
|
lws_led_transition(struct lws_led_state *lcs, const char *name,
|
|
const lws_led_sequence_def_t *next,
|
|
const lws_led_sequence_def_t *trans);
|
|
```
|
|
|
|
This fades from the current sequence to a new sequence, using `trans` sequencer
|
|
intensity as the mix factor. `trans` is typically `lws_pwmseq_linear_wipe`,
|
|
fading between the current and new linearly over 300ms. At the end of the
|
|
`trans` sequence, the new sequence simply replaces the current one and the
|
|
transition is completed.
|
|
|
|
Sequencers use a single 30Hz OS timer while any sequence is active.
|
|
|
|
exported sequencer symbol|description
|
|
---|---
|
|
lws_pwmseq_sine_endless_slow|continuous 100% sine, 1.5s cycle
|
|
lws_pwmseq_sine_endless_fast|continuous 100% sine, 0.75s cycle
|
|
lws_pwmseq_linear_wipe|single 0 - 100% ramp over 0.3s
|
|
lws_pwmseq_sine_up|single 0 - 100% using sine curve over 0.3s
|
|
lws_pwmseq_sine_down|single 100% - 0 using sine curve over 0.3s
|
|
lws_pwmseq_static_on|100% static
|
|
lws_pwmseq_static_half|50% static
|
|
lws_pwmseq_static_off|0% static
|