PX4 Firmware
PX4 Autopilot Software http://px4.io
led.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2017 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file led.cpp
36  */
37 
38 
39 #include "led.h"
40 
42 {
44  // handle new state
46 
47  if (_led_control_sub.copy(&led_control)) {
48 
49  // don't apply the new state just yet to avoid interrupting an ongoing blinking state
50  for (int i = 0; i < BOARD_MAX_LEDS; ++i) {
51  if (led_control.led_mask & (1 << i)) {
52  // if next state has already a higher priority state than
53  // led_control, set lower prio state directly, so that this
54  // information is not lost
55  if (_states[i].next_state.is_valid() && led_control.priority < _states[i].next_state.priority) {
56  _states[i].set(led_control);
57 
58  } else {
59  // if a lower prio event is already in next state and a
60  // higher prio event is coming in
61  if (_states[i].next_state.is_valid() && led_control.priority > _states[i].next_state.priority) {
63  }
64 
65  _states[i].next_state.set(led_control);
66  }
67  }
68  }
69  }
70 
71  _force_update = false;
72  }
73 
74  bool had_changes = false; // did one of the outputs change?
75 
76  // handle state updates
78 
79  if (_last_update_call == 0) {
80  _last_update_call = now;
81  return 0;
82  }
83 
84  uint16_t blink_delta_t = (uint16_t)((now - _last_update_call) / 100); // Note: this is in 0.1ms
85  constexpr uint16_t breathe_duration = BREATHE_INTERVAL * BREATHE_STEPS / 100;
86 
87  int num_blinking_leds = 0;
88  int num_blinking_do_not_change_state = 0;
89  int current_priorities[BOARD_MAX_LEDS];
90 
91  for (int i = 0; i < BOARD_MAX_LEDS; ++i) {
92  int priority = led_control_s::MAX_PRIORITY;
93 
94  for (; priority >= 0; --priority) {
95 
96  PerPriorityData &cur_data = _states[i].priority[priority];
97 
98  if (cur_data.mode == led_control_s::MODE_DISABLED) {
99  continue; // handle next priority
100  }
101 
102  // handle state updates
103  uint16_t current_blink_duration = 0;
104 
105  switch (cur_data.mode) {
106  case led_control_s::MODE_FLASH:
107  case led_control_s::MODE_BLINK_FAST:
108  current_blink_duration = BLINK_FAST_DURATION / 100;
109  break;
110 
111  case led_control_s::MODE_BLINK_NORMAL:
112  current_blink_duration = BLINK_NORMAL_DURATION / 100;
113  break;
114 
115  case led_control_s::MODE_BLINK_SLOW:
116  current_blink_duration = BLINK_SLOW_DURATION / 100;
117  break;
118 
119  case led_control_s::MODE_BREATHE:
120  _states[i].current_blinking_time += blink_delta_t;
121 
122  while (_states[i].current_blinking_time > breathe_duration) {
123  _states[i].current_blinking_time -= breathe_duration;
124  }
125 
126  had_changes = true;
127  break;
128  }
129 
130  if (current_blink_duration > 0) {
131  ++num_blinking_leds;
132 
133  if ((_states[i].current_blinking_time += blink_delta_t) > current_blink_duration) {
134  _states[i].current_blinking_time -= current_blink_duration;
135 
136  if (cur_data.blink_times_left == 246) {
137  // handle toggling for infinite case: decrease between 255 and 246
138  // In order to handle the flash mode infinite case it needs a
139  // total of 10 steps.
140  cur_data.blink_times_left = 255;
141  ++num_blinking_do_not_change_state;
142 
143  } else if (--cur_data.blink_times_left == 0) {
144  cur_data.mode = led_control_s::MODE_DISABLED;
146 
147  } else if (cur_data.blink_times_left % 2 == 1) {
148  ++num_blinking_do_not_change_state;
149  }
150 
151  had_changes = true;
152 
153  } else {
154  ++num_blinking_do_not_change_state;
155  }
156  }
157 
158  break; // handle next led
159  }
160 
161  current_priorities[i] = priority;
162 
163  }
164 
165  // handle next state:
166  // only allow a state change if no led blinks or at least one of the blinking leds signals that it's ok to switch.
167  // This makes sure all leds are kept in sync, but does not allow interrupting at arbitrary points.
168  if (num_blinking_leds == 0 || num_blinking_leds > num_blinking_do_not_change_state) {
169  for (int i = 0; i < BOARD_MAX_LEDS; ++i) {
170  if (_states[i].next_state.is_valid()) {
171  int next_priority = (int)_states[i].next_state.priority;
172 
173  if (next_priority >= current_priorities[i]) {
175  had_changes = true;
176  }
177 
179  _states[i].next_state.reset();
180  }
181 
182  }
183  }
184 
185  _last_update_call = now;
186 
187  if (!had_changes) {
188  return 0;
189  }
190 
191  // create output
192  get_control_data(control_data);
193 
194  return 1;
195 }
196 
198 {
199  _breathe_enabled = false;
200 
201  for (int i = 0; i < BOARD_MAX_LEDS; ++i) {
202  control_data.leds[i].color = led_control_s::COLOR_OFF; // set output to a defined state
203  control_data.leds[i].brightness = 255;
204 
205  for (int priority = led_control_s::MAX_PRIORITY; priority >= 0; --priority) {
206  bool flash_output_active = true;
207  const PerPriorityData &cur_data = _states[i].priority[priority];
208 
209  if (cur_data.mode == led_control_s::MODE_DISABLED) {
210  continue; // handle next priority
211  }
212 
213  switch (cur_data.mode) {
214  case led_control_s::MODE_ON:
215  control_data.leds[i].color = cur_data.color;
216  break;
217 
218  case led_control_s::MODE_BREATHE: {
219  // fade on and off
221  int n = counter >= (BREATHE_STEPS / 2) ? BREATHE_STEPS - counter : counter;
222  control_data.leds[i].brightness = (n * n) * 255 / (BREATHE_STEPS * BREATHE_STEPS / 4); // (n/(steps/2))^2
223  control_data.leds[i].color = cur_data.color;
224  _breathe_enabled = true;
225  break;
226  }
227 
228  case led_control_s::MODE_FLASH:
229  if (cur_data.blink_times_left % 10 < 6) { // 2 blinks, then turn off for the rest of the cycle
230  flash_output_active = false;
231  }
232 
233  /* FALLTHROUGH */
234  case led_control_s::MODE_BLINK_FAST:
235  case led_control_s::MODE_BLINK_NORMAL:
236  case led_control_s::MODE_BLINK_SLOW:
237  if (cur_data.blink_times_left % 2 == 0 && flash_output_active) {
238  control_data.leds[i].color = cur_data.color;
239  }
240 
241  break;
242  // MODE_OFF does not need to be handled, it's already set above
243  }
244 
245  break; // handle next led
246  }
247  }
248 }
PerLedData _states[BOARD_MAX_LEDS]
keep current LED states
Definition: led.h:175
void get_control_data(LedControlData &control_data)
set control_data based on current Led states
Definition: led.cpp:197
static constexpr int BREATHE_INTERVAL
single step when in breathe mode
Definition: led.h:85
uint8_t priority
Definition: led_control.h:77
uint8_t color
one of led_control_s::COLOR_*
Definition: led.h:101
static led_control_s led_control
LedControlDataSingle leds[BOARD_MAX_LEDS]
Definition: led.h:55
static constexpr int BLINK_FAST_DURATION
duration of half a blinking cycle (on-to-off and off-to-on) in us
Definition: led.h:88
static constexpr int BREATHE_STEPS
number of steps in breathe mode for a full on-off cycle
Definition: led.h:86
hrt_abstime _last_update_call
Definition: led.h:178
uint8_t led_mask
Definition: led_control.h:73
bool _breathe_enabled
true if at least one of the led&#39;s is currently in breathe mode
Definition: led.h:180
uint8_t brightness
brightness in [0, 255]
Definition: led.h:52
PerPriorityData priority[led_control_s::MAX_PRIORITY+1]
Definition: led.h:129
uint8_t color
one of led_control_s::COLOR_*
Definition: led.h:51
void set(const led_control_s &led_control)
Definition: led.h:133
static constexpr int BLINK_SLOW_DURATION
duration of half a blinking cycle (on-to-off and off-to-on) in us
Definition: led.h:92
uint16_t current_blinking_time
how long the Led was in current state (in 0.1 ms, wraps if > 6.5s)
Definition: led.h:130
void apply_next_state()
Definition: led.h:155
static constexpr int BLINK_NORMAL_DURATION
duration of half a blinking cycle (on-to-off and off-to-on) in us
Definition: led.h:90
static unsigned counter
Definition: safety.c:56
bool updated()
Check if there is a new update.
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
Definition: drv_hrt.h:58
void set(const led_control_s &led_control)
Definition: led.h:113
#define BOARD_MAX_LEDS
Definition: drv_led.h:49
int update(LedControlData &control_data)
Update and retrieve the Led state.
Definition: led.cpp:41
Led controller helper class, used by Led drivers.
uORB::Subscription _led_control_sub
uorb subscription
Definition: led.h:177
uint8_t blink_times_left
how many times left to blink (MSB bit is used for infinite case).
Definition: led.h:103
uint8_t mode
one of led_control_s::MODE_*
Definition: led.h:102
NextState next_state
Definition: led.h:131
bool copy(void *dst)
Copy the struct.
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
bool _force_update
force an orb_copy in the beginning
Definition: led.h:179