blob: e4d2d578ba4698b84417864e989270f5587e2800 [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)
19 PIO_Set(&pinsLeds[led]);
20 else
21 PIO_Clear(&pinsLeds[led]);
22}
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;
30 /* bringhtness of LED during the state */
31 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};
57static const struct blink_state bs_200on_off[] = {
58 { 20000, 1 }, { 0, 0 },
59};
60static const struct blink_state bs_600on_off[] = {
61 { 60000, 1 }, { 0, 0 },
62};
63
64
65/* a blink pattern is an array of blink_states */
66struct blink_pattern {
67 const struct blink_state *states;
68 uint16_t size;
69};
70
71/* compiled-in default blinking patterns */
72static const struct blink_pattern patterns[] = {
73 [BLINK_ALWAYS_OFF] = {
74 .states = bs_off,
75 .size = ARRAY_SIZE(bs_off),
76 },
77 [BLINK_ALWAYS_ON] = {
78 .states = bs_on,
79 .size = ARRAY_SIZE(bs_on),
80 },
81 [BLINK_3O_5F] = {
82 .states = bs_3on_5off,
83 .size = ARRAY_SIZE(bs_3on_5off),
84 },
85 [BLINK_3O_30F] = {
86 .states = bs_3on_30off,
87 .size = ARRAY_SIZE(bs_3on_30off),
88 },
89 [BLINK_3O_1F_3O_30F] = {
90 .states = bs_3on_1off_3on_30off,
91 .size = ARRAY_SIZE(bs_3on_1off_3on_30off),
92 },
93 [BLINK_3O_1F_3O_1F_3O_30F] = {
94 .states = bs_3on_1off_3on_1off_3on_30off,
95 .size = ARRAY_SIZE(bs_3on_1off_3on_1off_3on_30off),
96 },
97 [BLINK_200O_F] = {
98 .states = bs_200on_off,
99 .size = ARRAY_SIZE(bs_200on_off),
100 },
101 [BLINK_600O_F] = {
102 .states = bs_600on_off,
103 .size = ARRAY_SIZE(bs_600on_off),
104 },
105};
106
107struct led_state {
108 /* which led are we handling */
109 enum led led;
110
111 /* timer */
112 struct osmo_timer_list timer;
113
114 /* pointer and size of blink array */
115 const struct blink_pattern *pattern;
116
117 unsigned int cur_state;
118 unsigned int illuminated;
119
120 /* static allocated space for custom blinking pattern */
121 struct blink_pattern pattern_cust;
122 struct blink_state blink_cust[10];
123};
124
125static unsigned int cur_state_inc(struct led_state *ls)
126{
127 ls->cur_state = (ls->cur_state + 1) % ls->pattern->size;
128 return ls->cur_state;
129}
130
131static const struct blink_state *
132next_blink_state(struct led_state *ls)
133{
134 return &ls->pattern->states[cur_state_inc(ls)];
135}
136
137/* apply the next state to the LED */
138static void apply_blinkstate(struct led_state *ls,
139 const struct blink_state *bs)
140{
141 led_set(ls->led, bs->on);
142 ls->illuminated = bs->on;
143
144 /* re-schedule the timer */
145 if (bs->duration) {
146 uint32_t us = bs->duration * 1000;
147 osmo_timer_schedule(&ls->timer, us / 1000000, us % 1000000);
148 }
149}
150
151static void blink_tmr_cb(void *data)
152{
153 struct led_state *ls = data;
154 const struct blink_state *next_bs = next_blink_state(ls);
155
156 /* apply the next state to the LED */
157 apply_blinkstate(ls, next_bs);
158}
159
160static struct led_state led_state[] = {
161 [LED_GREEN] = {
162 .led = LED_GREEN,
163 .timer.cb = blink_tmr_cb,
164 .timer.data = &led_state[LED_GREEN],
165 },
166 [LED_RED] = {
167 .led = LED_RED,
168 .timer.cb = blink_tmr_cb,
169 .timer.data = &led_state[LED_RED],
170 },
171};
172#endif /* PINS_LEDS */
173
174void led_blink(enum led led, enum led_pattern blink)
175{
176#ifdef PINS_LEDS
177 struct led_state *ls;
178
179 if (led >= ARRAY_SIZE(led_state))
180 return;
181 ls = &led_state[led];
182
183 /* stop previous blinking, if any */
184 osmo_timer_del(&ls->timer);
185 led_set(led, 0);
186 ls->illuminated = 0;
187 ls->pattern = NULL;
188 ls->cur_state = 0;
189
190 switch (blink) {
191 case BLINK_CUSTOM:
192 ls->pattern = &ls->pattern_cust;
193 break;
194 default:
195 if (blink >= ARRAY_SIZE(patterns))
196 return;
197 ls->pattern = &patterns[blink];
198 break;
199 }
200
201 if (ls->pattern && ls->pattern->size > 0)
202 apply_blinkstate(ls, &ls->pattern->states[0]);
203#endif
204}
205
206enum led_pattern led_get(enum led led)
207{
208#ifdef PINS_LEDS
209 struct led_state *ls;
210 unsigned int i;
211
212 if (led >= ARRAY_SIZE(led_state))
213 return -1;
214 ls = &led_state[led];
215
216 if (ls->pattern == &ls->pattern_cust)
217 return BLINK_CUSTOM;
218
219 for (i = 0; i < ARRAY_SIZE(patterns); i++) {
220 if (ls->pattern == &patterns[i])
221 return i;
222 }
223#endif
224 /* default case, shouldn't be reached */
225 return -1;
226}
227
228void led_start(void)
229{
230 led_set(LED_GREEN, led_state[LED_GREEN].illuminated);
231 led_set(LED_RED, led_state[LED_RED].illuminated);
232}
233
234void led_stop(void)
235{
236 led_set(LED_GREEN, 0);
237 led_set(LED_RED, 0);
238}
239
240void led_init(void)
241{
242#ifdef PINS_LEDS
243 PIO_Configure(pinsLeds, PIO_LISTSIZE(pinsLeds));
244 led_set(LED_GREEN, 0);
245 led_set(LED_RED, 0);
246#endif
247}
248
249void led_fini(void)
250{
251#ifdef PINS_LEDS
252 /* we don't actually need to do this, but just in case... */
253 osmo_timer_del(&led_state[LED_RED].timer);
254 osmo_timer_del(&led_state[LED_GREEN].timer);
255 led_set(LED_GREEN, 0);
256 led_set(LED_RED, 0);
257#endif
258}