Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_led.c
1 #include <bc_led.h>
2 
3 #define BC_LED_DEFAULT_SLOT_INTERVAL 100
4 
5 static void _bc_led_task(void *param);
6 
7 static void _bc_led_gpio_init(bc_led_t *self);
8 
9 static void _bc_led_gpio_on(bc_led_t *self);
10 
11 static void _bc_led_gpio_off(bc_led_t *self);
12 
13 static const bc_led_driver_t _bc_led_driver_gpio =
14 {
15  .init = _bc_led_gpio_init,
16  .on = _bc_led_gpio_on,
17  .off = _bc_led_gpio_off,
18 };
19 
20 void bc_led_init(bc_led_t *self, bc_gpio_channel_t gpio_channel, bool open_drain_output, int idle_state)
21 {
22  memset(self, 0, sizeof(*self));
23 
24  self->_channel.gpio = gpio_channel;
25 
26  self->_open_drain_output = open_drain_output;
27 
28  self->_idle_state = idle_state;
29 
30  self->_driver = &_bc_led_driver_gpio;
31 
32  self->_driver->init(self);
33 
34  self->_driver->off(self);
35 
36  if (self->_open_drain_output)
37  {
38  bc_gpio_set_mode(self->_channel.gpio, BC_GPIO_MODE_OUTPUT_OD);
39  }
40  else
41  {
42  bc_gpio_set_mode(self->_channel.gpio, BC_GPIO_MODE_OUTPUT);
43  }
44 
45  self->_slot_interval = BC_LED_DEFAULT_SLOT_INTERVAL;
46 
47  self->_task_id = bc_scheduler_register(_bc_led_task, self, BC_TICK_INFINITY);
48 }
49 
50 void bc_led_init_virtual(bc_led_t *self, int channel, const bc_led_driver_t *driver, int idle_state)
51 {
52  memset(self, 0, sizeof(*self));
53 
54  self->_channel.virtual = channel;
55 
56  self->_idle_state = idle_state;
57 
58  self->_driver = driver;
59 
60  self->_driver->init(self);
61 
62  self->_driver->off(self);
63 
64  self->_slot_interval = BC_LED_DEFAULT_SLOT_INTERVAL;
65 
66  self->_task_id = bc_scheduler_register(_bc_led_task, self, BC_TICK_INFINITY);
67 }
68 
70 {
71  self->_slot_interval = interval;
72 }
73 
75 {
76  uint32_t pattern = self->_pattern;
77 
78  switch (mode)
79  {
80  case BC_LED_MODE_TOGGLE:
81  {
82  if (pattern == 0x00000000)
83  {
84  self->_pattern = 0xffffffff;
85 
86  self->_driver->on(self);
87  }
88  else if (pattern == 0xffffffff)
89  {
90  self->_pattern = 0x00000000;
91 
92  if (!self->_pulse_active)
93  {
94  self->_driver->off(self);
95  }
96  }
97 
98  return;
99  }
100  case BC_LED_MODE_OFF:
101  {
102  self->_pattern = 0x00000000;
103 
104  if (!self->_pulse_active)
105  {
106  self->_driver->off(self);
107  }
108 
109  return;
110  }
111  case BC_LED_MODE_ON:
112  {
113  self->_pattern = 0xffffffff;
114 
115  if (!self->_pulse_active)
116  {
117  self->_driver->on(self);
118  }
119 
120  return;
121  }
122  case BC_LED_MODE_BLINK:
123  {
124  pattern = 0xf0f0f0f0;
125 
126  break;
127  }
129  {
130  pattern = 0xffff0000;
131 
132  break;
133  }
135  {
136  pattern = 0xaaaaaaaa;
137 
138  break;
139  }
140  case BC_LED_MODE_FLASH:
141  {
142  pattern = 0x80000000;
143 
144  break;
145  }
146  default:
147  {
148  break;
149  }
150  }
151 
152  if (self->_pattern != pattern)
153  {
154  self->_pattern = pattern;
155 
156  self->_selector = 0;
157  }
158 
159  self->_count = -1;
160 
161  bc_scheduler_plan_now(self->_task_id);
162 }
163 
164 void bc_led_set_pattern(bc_led_t *self, uint32_t pattern)
165 {
166  self->_pattern = pattern;
167 
168  self->_selector = 0;
169 
170  bc_scheduler_plan_now(self->_task_id);
171 }
172 
173 void bc_led_set_count(bc_led_t *self, int count)
174 {
175  self->_count = count;
176 }
177 
178 void bc_led_blink(bc_led_t *self, int count)
179 {
180  self->_pattern = 0xf0f0f0f0;
181 
182  self->_selector = 0;
183 
184  self->_count = count * 8;
185 
186  bc_scheduler_plan_now(self->_task_id);
187 }
188 
189 void bc_led_pulse(bc_led_t *self, bc_tick_t duration)
190 {
191  if (!self->_pulse_active)
192  {
193  self->_driver->on(self);
194 
195  self->_pulse_active = true;
196  }
197 
198  bc_scheduler_plan_from_now(self->_task_id, duration);
199 }
200 
202 {
203  return self->_pulse_active;
204 }
205 
206 static void _bc_led_task(void *param)
207 {
208  bc_led_t *self = param;
209 
210  if (self->_pulse_active)
211  {
212  self->_driver->off(self);
213 
214  self->_pulse_active = false;
215 
216  self->_selector = 0;
217 
218  bc_scheduler_plan_current_relative(self->_slot_interval);
219 
220  return;
221  }
222 
223  if ((self->_pattern == 0x00000000) || self->_pattern == 0xffffffff)
224  {
225  return;
226  }
227 
228  if (self->_selector == 0)
229  {
230  self->_selector = 0x80000000;
231  }
232 
233  if (self->_count > -1)
234  {
235  if (--self->_count < 0)
236  {
237  self->_driver->off(self);
238 
239  return;
240  }
241  }
242 
243  if ((self->_pattern & self->_selector) != 0)
244  {
245  self->_driver->on(self);
246  }
247  else
248  {
249  self->_driver->off(self);
250  }
251 
252  self->_selector >>= 1;
253 
254  bc_scheduler_plan_current_relative(self->_slot_interval);
255 }
256 
257 static void _bc_led_gpio_init(bc_led_t *self)
258 {
259  bc_gpio_init(self->_channel.gpio);
260 }
261 
262 static void _bc_led_gpio_on(bc_led_t *self)
263 {
264  bc_gpio_set_output(self->_channel.gpio, self->_idle_state ? 0 : 1);
265 }
266 
267 static void _bc_led_gpio_off(bc_led_t *self)
268 {
269  bc_gpio_set_output(self->_channel.gpio, self->_idle_state ? 1 : 0);
270 }
bool bc_led_is_pulse(bc_led_t *self)
Check if there is ongoing LED pulse.
Definition: bc_led.c:201
uint64_t bc_tick_t
Timestamp data type.
Definition: bc_tick.h:16
LED toggles between on/off state (this has no effect while processing alternating patterns) ...
Definition: bc_led.h:28
LED driver interface.
Definition: bc_led.h:56
bc_led_mode_t
LED modes.
Definition: bc_led.h:25
void bc_led_set_slot_interval(bc_led_t *self, bc_tick_t interval)
Set slot interval for pattern processing.
Definition: bc_led.c:69
void bc_led_set_count(bc_led_t *self, int count)
Set count for blinking pattern executed.
Definition: bc_led.c:173
LED has steady off state.
Definition: bc_led.h:31
void bc_led_blink(bc_led_t *self, int count)
LED blink.
Definition: bc_led.c:178
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
void bc_scheduler_plan_now(bc_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
Definition: bc_scheduler.c:119
void bc_gpio_set_output(bc_gpio_channel_t channel, int state)
Set output state for GPIO channel.
Definition: bc_gpio.c:442
LED flashes repeatedly.
Definition: bc_led.h:46
struct bc_led_t bc_led_t
LED instance.
Definition: bc_led.h:52
void bc_gpio_set_mode(bc_gpio_channel_t channel, bc_gpio_mode_t mode)
Set mode of operation for GPIO channel.
Definition: bc_gpio.c:340
LED blinks slowly.
Definition: bc_led.h:40
LED blinks quickly.
Definition: bc_led.h:43
void bc_scheduler_plan_current_relative(bc_tick_t tick)
Schedule current task to tick relative from current spin.
Definition: bc_scheduler.c:149
void bc_led_set_mode(bc_led_t *self, bc_led_mode_t mode)
Set LED mode.
Definition: bc_led.c:74
LED blinks.
Definition: bc_led.h:37
void(* init)(bc_led_t *self)
Callback for initialization.
Definition: bc_led.h:59
void bc_led_init(bc_led_t *self, bc_gpio_channel_t gpio_channel, bool open_drain_output, int idle_state)
Initialize LED.
Definition: bc_led.c:20
void bc_led_set_pattern(bc_led_t *self, uint32_t pattern)
Set custom blinking pattern.
Definition: bc_led.c:164
void bc_scheduler_plan_from_now(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to tick relative from now.
Definition: bc_scheduler.c:134
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
bc_gpio_channel_t
GPIO channels.
Definition: bc_gpio.h:12
LED has steady on state.
Definition: bc_led.h:34
GPIO channel operates as open-drain output.
Definition: bc_gpio.h:111
void bc_led_init_virtual(bc_led_t *self, int channel, const bc_led_driver_t *driver, int idle_state)
Initialize virtual LED.
Definition: bc_led.c:50
void bc_led_pulse(bc_led_t *self, bc_tick_t duration)
Turn on LED for the specified duration of time.
Definition: bc_led.c:189
void bc_gpio_init(bc_gpio_channel_t channel)
Initialize GPIO channel.
Definition: bc_gpio.c:301
GPIO channel operates as output.
Definition: bc_gpio.h:102