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