led-seq.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. * Generic GPIO led
  3. *
  4. * Copyright (C) 2019 - 2020 Andy Green <[email protected]>
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to
  8. * deal in the Software without restriction, including without limitation the
  9. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  10. * sell copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  22. * IN THE SOFTWARE.
  23. */
  24. #include "private-lib-core.h"
  25. #include "drivers/led/private-lib-drivers-led.h"
  26. /*
  27. * 64 entry interpolated CIE correction
  28. * https://en.wikipedia.org/wiki/Lightness
  29. */
  30. uint16_t cie[] = {
  31. 0, 113, 227, 340, 454, 568, 688, 824, 976, 1146,
  32. 1335, 1543, 1772, 2023, 2296, 2592, 2914, 3260, 3633, 4034,
  33. 4463, 4921, 5409, 5929, 6482, 7067, 7687, 8341, 9032, 9761,
  34. 10527, 11332, 12178, 13064, 13993, 14964, 15980, 17040, 18146, 19299,
  35. 20500, 21750, 23049, 24400, 25802, 27256, 28765, 30328, 31946, 33622,
  36. 35354, 37146, 38996, 40908, 42881, 44916, 47014, 49177, 51406, 53700,
  37. 56062, 58492, 60992, 63561,
  38. 65535 /* for interpolation */
  39. };
  40. /*
  41. * This is the default intensity correction function, it can be overridden
  42. * per-led to eg, normalize intensity of different leds
  43. */
  44. static lws_led_intensity_t
  45. cie_antilog(lws_led_intensity_t lin)
  46. {
  47. return (cie[lin >> 10] * (0x3ff - (lin & 0x3ff)) +
  48. cie[(lin >> 10) + 1] * (lin & 0x3ff)) / 0x3ff;
  49. }
  50. static void
  51. lws_seq_advance(lws_led_state_t *lcs, lws_led_state_ch_t *ch)
  52. {
  53. if (!ch->seq)
  54. return;
  55. if (ch->phase_budget != LWS_SEQ_LEDPHASE_TOTAL_ENDLESS &&
  56. (ch->phase_budget < ch->step || !ch->phase_budget)) {
  57. /* we are done */
  58. ch->seq = NULL;
  59. if (!(--lcs->timer_refcount)) {
  60. #if defined(LWS_PLAT_TIMER_STOP)
  61. LWS_PLAT_TIMER_STOP(lcs->timer);
  62. #endif
  63. }
  64. return;
  65. }
  66. ch->ph += ch->step;
  67. if (ch->phase_budget != LWS_SEQ_LEDPHASE_TOTAL_ENDLESS)
  68. ch->phase_budget -= ch->step;
  69. }
  70. static lws_led_intensity_t
  71. lws_seq_sample(const lws_led_gpio_map_t *map, lws_led_state_chs_t *chs)
  72. {
  73. unsigned int i;
  74. if (chs->seqs[LLSI_CURR].seq)
  75. chs->seqs[LLSI_CURR].last = chs->seqs[LLSI_CURR].seq->
  76. func(chs->seqs[LLSI_CURR].ph);
  77. if (chs->seqs[LLSI_TRANS].seq) {
  78. /*
  79. * If a transition is ongoing, we need to use the transition
  80. * intensity as the mixing factor between the still-live current
  81. * and newly-live next sequences
  82. */
  83. chs->seqs[LLSI_TRANS].last = chs->seqs[LLSI_TRANS].seq->
  84. func(chs->seqs[LLSI_TRANS].ph);
  85. if (chs->seqs[LLSI_NEXT].seq)
  86. chs->seqs[LLSI_NEXT].last = chs->seqs[LLSI_NEXT].seq->
  87. func(chs->seqs[LLSI_NEXT].ph);
  88. i = (lws_led_intensity_t)(((
  89. (unsigned int)chs->seqs[LLSI_CURR].last *
  90. (65535 - chs->seqs[LLSI_TRANS].last) >> 16) +
  91. (((unsigned int)chs->seqs[LLSI_NEXT].last *
  92. (unsigned int)chs->seqs[LLSI_TRANS].last) >> 16)));
  93. } else
  94. i = chs->seqs[LLSI_CURR].last;
  95. return map->intensity_correction ? map->intensity_correction(i) :
  96. cie_antilog((lws_led_intensity_t)i);
  97. }
  98. void
  99. lws_seq_timer_handle(lws_led_state_t *lcs)
  100. {
  101. lws_led_gpio_controller_t *lgc = lcs->controller;
  102. lws_led_state_chs_t *chs = (lws_led_state_chs_t *)&lcs[1];
  103. const lws_led_gpio_map_t *map = &lgc->led_map[0];
  104. unsigned int n;
  105. for (n = 0; n < lgc->count_leds; n++) {
  106. lgc->led_ops.intensity(&lgc->led_ops, map->name,
  107. lws_seq_sample(map, chs));
  108. lws_seq_advance(lcs, &chs->seqs[LLSI_CURR]);
  109. if (chs->seqs[LLSI_TRANS].seq) {
  110. lws_seq_advance(lcs, &chs->seqs[LLSI_NEXT]);
  111. lws_seq_advance(lcs, &chs->seqs[LLSI_TRANS]);
  112. /*
  113. * When we finished the transition, we can make the
  114. * "next" sequence the current sequence and no need for
  115. * a "next" or a transition any more.
  116. */
  117. if (!chs->seqs[LLSI_TRANS].seq) {
  118. chs->seqs[LLSI_CURR] = chs->seqs[LLSI_NEXT];
  119. chs->seqs[LLSI_NEXT].seq = NULL;
  120. }
  121. }
  122. map++;
  123. chs++;
  124. }
  125. }
  126. static int
  127. lws_led_set_chs_seq(struct lws_led_state *lcs, lws_led_state_ch_t *dest,
  128. const lws_led_sequence_def_t *def)
  129. {
  130. int steps;
  131. dest->seq = def;
  132. dest->ph = def->ledphase_offset;
  133. dest->phase_budget = def->ledphase_total;
  134. /*
  135. * We need to compute the incremental phase angle step to cover the
  136. * total number of phases in the indicated ms, incrementing at the
  137. * timer rate of LWS_LED_SEQUENCER_UPDATE_RATE_HZ. Eg,
  138. *
  139. * 65536 phase steps (one cycle) in 2000ms at 30Hz timer rate means we
  140. * will update 2000ms / 33ms = 60 times, so we must step at at
  141. * 65536 / 60 = 1092 phase angle resolution
  142. */
  143. steps = def->ms / LWS_LED_SEQUENCER_UPDATE_INTERVAL_MS;
  144. dest->step = (def->ledphase_total != LWS_SEQ_LEDPHASE_TOTAL_ENDLESS ?
  145. def->ledphase_total : LWS_LED_FUNC_PHASE) / (steps ? steps : 1);
  146. if (!lcs->timer_refcount++) {
  147. #if defined(LWS_PLAT_TIMER_START)
  148. LWS_PLAT_TIMER_START(lcs->timer);
  149. #endif
  150. }
  151. return steps;
  152. }
  153. int
  154. lws_led_transition(struct lws_led_state *lcs, const char *name,
  155. const lws_led_sequence_def_t *next,
  156. const lws_led_sequence_def_t *trans)
  157. {
  158. lws_led_state_chs_t *chs = (lws_led_state_chs_t *)&lcs[1];
  159. int index = lws_led_gpio_lookup(&lcs->controller->led_ops, name);
  160. if (index < 0)
  161. return 1;
  162. lws_led_set_chs_seq(lcs, &chs[index].seqs[LLSI_TRANS], trans);
  163. lws_led_set_chs_seq(lcs, &chs[index].seqs[LLSI_NEXT], next);
  164. return 0;
  165. }