blob: 00082e27f88db974bef2d43add1bae9fd781de64 [file] [log] [blame]
Harald Welteabba8a82017-03-06 16:58:00 +01001#include <stdint.h>
2#include <string.h>
3#include <assert.h>
4
5#include <osmocom/core/timer.h>
6
7#include "board.h"
8#include "utils.h"
9#include "led.h"
10
11#ifdef PINS_LEDS
12static const Pin pinsLeds[] = { PINS_LEDS } ;
13
14static void led_set(enum led led, int on)
15{
16 ASSERT(led < PIO_LISTSIZE(pinsLeds));
17
18 if (on)
Harald Welteabba8a82017-03-06 16:58:00 +010019 PIO_Clear(&pinsLeds[led]);
King Kévin4cbdc7c2018-07-04 16:36:17 +020020 else
21 PIO_Set(&pinsLeds[led]);
Harald Welteabba8a82017-03-06 16:58:00 +010022}
23
24/* LED blinking code */
25
26/* a single state in a sequence of blinking */
27struct blink_state {
28 /* duration of the state in ms */
29 uint16_t duration;
Kévin Redon11914d92018-06-27 16:33:01 +020030 /* brightness of LED during the state */
Harald Welteabba8a82017-03-06 16:58:00 +010031 uint8_t on;
32} __attribute__((packed));
33
34static const struct blink_state bs_off[] = {
35 { 0, 0 }
36};
37
38static const struct blink_state bs_on[] = {
39 { 0, 1 }
40};
41
42static const struct blink_state bs_3on_5off[] = {
43 { 300, 1 }, { 500, 0 }
44};
45
46static const struct blink_state bs_3on_30off[] = {
47 { 300, 1 }, { 3000, 0 }
48};
49
50static const struct blink_state bs_3on_1off_3on_30off[] = {
51 { 300, 1 }, { 100, 0 }, { 300, 1 }, { 3000, 0 }
52};
53
54static const struct blink_state bs_3on_1off_3on_1off_3on_30off[] = {
55 { 300, 1 }, { 100, 0 }, { 300, 1 }, { 100, 0 }, { 300, 1 }, { 3000, 0 }
56};
Kévin Redon11914d92018-06-27 16:33:01 +020057static const struct blink_state bs_2on_off[] = {
58 { 200, 1 }, { 0, 0 },
59};
Harald Welteabba8a82017-03-06 16:58:00 +010060static const struct blink_state bs_200on_off[] = {
61 { 20000, 1 }, { 0, 0 },
62};
63static const struct blink_state bs_600on_off[] = {
64 { 60000, 1 }, { 0, 0 },
65};
66
67
68/* a blink pattern is an array of blink_states */
69struct blink_pattern {
70 const struct blink_state *states;
71 uint16_t size;
72};
73
74/* compiled-in default blinking patterns */
75static const struct blink_pattern patterns[] = {
76 [BLINK_ALWAYS_OFF] = {
77 .states = bs_off,
78 .size = ARRAY_SIZE(bs_off),
79 },
80 [BLINK_ALWAYS_ON] = {
81 .states = bs_on,
82 .size = ARRAY_SIZE(bs_on),
83 },
84 [BLINK_3O_5F] = {
85 .states = bs_3on_5off,
86 .size = ARRAY_SIZE(bs_3on_5off),
87 },
88 [BLINK_3O_30F] = {
89 .states = bs_3on_30off,
90 .size = ARRAY_SIZE(bs_3on_30off),
91 },
92 [BLINK_3O_1F_3O_30F] = {
93 .states = bs_3on_1off_3on_30off,
94 .size = ARRAY_SIZE(bs_3on_1off_3on_30off),
95 },
96 [BLINK_3O_1F_3O_1F_3O_30F] = {
97 .states = bs_3on_1off_3on_1off_3on_30off,
98 .size = ARRAY_SIZE(bs_3on_1off_3on_1off_3on_30off),
99 },
Kévin Redon11914d92018-06-27 16:33:01 +0200100 [BLINK_2O_F] = {
101 .states = bs_2on_off,
102 .size = ARRAY_SIZE(bs_2on_off),
103 },
Harald Welteabba8a82017-03-06 16:58:00 +0100104 [BLINK_200O_F] = {
105 .states = bs_200on_off,
106 .size = ARRAY_SIZE(bs_200on_off),
107 },
108 [BLINK_600O_F] = {
109 .states = bs_600on_off,
110 .size = ARRAY_SIZE(bs_600on_off),
111 },
112};
113
114struct led_state {
115 /* which led are we handling */
116 enum led led;
117
118 /* timer */
119 struct osmo_timer_list timer;
120
121 /* pointer and size of blink array */
122 const struct blink_pattern *pattern;
123
124 unsigned int cur_state;
125 unsigned int illuminated;
126
127 /* static allocated space for custom blinking pattern */
128 struct blink_pattern pattern_cust;
129 struct blink_state blink_cust[10];
130};
131
132static unsigned int cur_state_inc(struct led_state *ls)
133{
134 ls->cur_state = (ls->cur_state + 1) % ls->pattern->size;
135 return ls->cur_state;
136}
137
138static const struct blink_state *
139next_blink_state(struct led_state *ls)
140{
141 return &ls->pattern->states[cur_state_inc(ls)];
142}
143
144/* apply the next state to the LED */
145static void apply_blinkstate(struct led_state *ls,
146 const struct blink_state *bs)
147{
148 led_set(ls->led, bs->on);
149 ls->illuminated = bs->on;
150
151 /* re-schedule the timer */
152 if (bs->duration) {
153 uint32_t us = bs->duration * 1000;
154 osmo_timer_schedule(&ls->timer, us / 1000000, us % 1000000);
155 }
156}
157
158static void blink_tmr_cb(void *data)
159{
160 struct led_state *ls = data;
161 const struct blink_state *next_bs = next_blink_state(ls);
162
163 /* apply the next state to the LED */
164 apply_blinkstate(ls, next_bs);
165}
166
167static struct led_state led_state[] = {
Harald Welteabba8a82017-03-06 16:58:00 +0100168 [LED_RED] = {
169 .led = LED_RED,
170 .timer.cb = blink_tmr_cb,
171 .timer.data = &led_state[LED_RED],
172 },
Kévin Redon11914d92018-06-27 16:33:01 +0200173 [LED_GREEN] = {
174 .led = LED_GREEN,
175 .timer.cb = blink_tmr_cb,
176 .timer.data = &led_state[LED_GREEN],
177 },
Harald Welteabba8a82017-03-06 16:58:00 +0100178};
179#endif /* PINS_LEDS */
180
181void led_blink(enum led led, enum led_pattern blink)
182{
183#ifdef PINS_LEDS
184 struct led_state *ls;
185
186 if (led >= ARRAY_SIZE(led_state))
187 return;
188 ls = &led_state[led];
189
190 /* stop previous blinking, if any */
191 osmo_timer_del(&ls->timer);
192 led_set(led, 0);
193 ls->illuminated = 0;
194 ls->pattern = NULL;
195 ls->cur_state = 0;
196
197 switch (blink) {
198 case BLINK_CUSTOM:
199 ls->pattern = &ls->pattern_cust;
200 break;
201 default:
202 if (blink >= ARRAY_SIZE(patterns))
203 return;
204 ls->pattern = &patterns[blink];
205 break;
206 }
207
208 if (ls->pattern && ls->pattern->size > 0)
209 apply_blinkstate(ls, &ls->pattern->states[0]);
210#endif
211}
212
213enum led_pattern led_get(enum led led)
214{
215#ifdef PINS_LEDS
216 struct led_state *ls;
217 unsigned int i;
218
219 if (led >= ARRAY_SIZE(led_state))
220 return -1;
221 ls = &led_state[led];
222
223 if (ls->pattern == &ls->pattern_cust)
224 return BLINK_CUSTOM;
225
226 for (i = 0; i < ARRAY_SIZE(patterns); i++) {
227 if (ls->pattern == &patterns[i])
228 return i;
229 }
230#endif
231 /* default case, shouldn't be reached */
232 return -1;
233}
234
235void led_start(void)
236{
237 led_set(LED_GREEN, led_state[LED_GREEN].illuminated);
238 led_set(LED_RED, led_state[LED_RED].illuminated);
239}
240
241void led_stop(void)
242{
243 led_set(LED_GREEN, 0);
244 led_set(LED_RED, 0);
245}
246
247void led_init(void)
248{
249#ifdef PINS_LEDS
250 PIO_Configure(pinsLeds, PIO_LISTSIZE(pinsLeds));
251 led_set(LED_GREEN, 0);
252 led_set(LED_RED, 0);
253#endif
254}
255
256void led_fini(void)
257{
258#ifdef PINS_LEDS
259 /* we don't actually need to do this, but just in case... */
260 osmo_timer_del(&led_state[LED_RED].timer);
261 osmo_timer_del(&led_state[LED_GREEN].timer);
262 led_set(LED_GREEN, 0);
263 led_set(LED_RED, 0);
264#endif
265}