PX4 Firmware
PX4 Autopilot Software http://px4.io
SafetyButton.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2012-2019 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 #include "SafetyButton.hpp"
35 
36 using namespace time_literals;
37 
38 static constexpr uint8_t CYCLE_COUNT{10}; /* safety switch must be held for 1 second to activate */
39 
40 // Define the various LED flash sequences for each system state.
41 enum class LED_PATTERN : uint16_t {
42  FMU_OK_TO_ARM = 0x0003, /**< slow blinking */
43  FMU_REFUSE_TO_ARM = 0x5555, /**< fast blinking */
44  IO_ARMED = 0x5050, /**< long off, then double blink */
45  FMU_ARMED = 0x5500, /**< long off, then quad blink */
46  IO_FMU_ARMED = 0xffff, /**< constantly on */
47 };
48 
50 {
51  ScheduleClear();
52 }
53 
54 void
56 {
57  // Debounce the safety button, change state if it has been held for long enough.
58  bool safety_button_pressed = px4_arch_gpioread(GPIO_BTN_SAFETY);
59 
60  /*
61  * Keep pressed for a while to arm.
62  *
63  * Note that the counting sequence has to be same length
64  * for arming / disarming in order to end up as proper
65  * state machine, keep ARM_COUNTER_THRESHOLD the same
66  * length in all cases of the if/else struct below.
67  */
68  if (safety_button_pressed && !_safety_btn_off) {
69  if (_button_counter < CYCLE_COUNT) {
70  _button_counter++;
71 
72  } else if (_button_counter == CYCLE_COUNT) {
73  // switch to armed state
74  _safety_btn_off = true;
75  _button_counter++;
76  }
77 
78  } else if (safety_button_pressed && _safety_btn_off) {
79 
80  if (_button_counter < CYCLE_COUNT) {
81  _button_counter++;
82 
83  } else if (_button_counter == CYCLE_COUNT) {
84  // change to disarmed state and notify
85  _safety_btn_off = false;
86  _button_counter++;
87  }
88 
89  } else {
90  _button_counter = 0;
91  }
92 }
93 
94 void
96 {
97 #if defined(GPIO_LED_SAFETY)
99 
100  if (_armed_sub.copy(&armed)) {
101  // Select the appropriate LED flash pattern depending on the current arm state
103 
104  // cycle the blink state machine at 10Hz
105  if (_safety_btn_off) {
106  if (armed.armed) {
107  pattern = LED_PATTERN::IO_FMU_ARMED;
108 
109  } else {
110  pattern = LED_PATTERN::IO_ARMED;
111  }
112 
113  } else if (armed.armed) {
114  pattern = LED_PATTERN::FMU_ARMED;
115 
116  } else {
117  pattern = LED_PATTERN::FMU_OK_TO_ARM;
118  }
119 
120  // Turn the LED on if we have a 1 at the current bit position
121  px4_arch_gpiowrite(GPIO_LED_SAFETY, !((uint16_t)pattern & (1 << _blink_counter++)));
122 
123  if (_blink_counter > 15) {
124  _blink_counter = 0;
125  }
126  }
127 
128 #endif // GPIO_LED_SAFETY
129 }
130 
131 void
133 {
134  if (should_exit()) {
135  exit_and_cleanup();
136  }
137 
138  // read safety switch input and control safety switch LED at 10Hz
139  CheckButton();
140 
141  // Make the safety button flash anyway, no matter if it's used or not.
142  FlashButton();
143 
144  safety_s safety{};
147  safety.safety_off = _safety_btn_off;
148 
149  // publish the safety status
150  _to_safety.publish(safety);
151 }
152 
153 int
154 SafetyButton::task_spawn(int argc, char *argv[])
155 {
156  if (PX4_MFT_HW_SUPPORTED(PX4_MFT_PX4IO)) {
157  PX4_ERR("not starting (use px4io for safety button)");
158 
159  return PX4_ERROR;
160 
161  } else if (circuit_breaker_enabled("CBRK_IO_SAFETY", CBRK_IO_SAFETY_KEY)) {
162  PX4_WARN("disabled by CBRK_IO_SAFETY, exiting");
163  return PX4_ERROR;
164 
165  } else {
167 
168  if (instance) {
169  _object.store(instance);
170  _task_id = task_id_is_work_queue;
171 
172  if (instance->Start() == PX4_OK) {
173  return PX4_OK;
174  }
175 
176  } else {
177  PX4_ERR("alloc failed");
178  }
179 
180  delete instance;
181  _object.store(nullptr);
182  _task_id = -1;
183  }
184 
185  return PX4_ERROR;
186 }
187 
188 int
190 {
191  ScheduleOnInterval(100_ms); // run at 10 Hz
192 
193  return PX4_OK;
194 }
195 
196 int
197 SafetyButton::custom_command(int argc, char *argv[])
198 {
199  return print_usage("unknown command");
200 }
201 
202 int
204 {
205  PX4_INFO("Safety State (from button): %s", _safety_btn_off ? "off" : "on");
206 
207  return 0;
208 }
209 
210 int
211 SafetyButton::print_usage(const char *reason)
212 {
213  if (reason) {
214  PX4_WARN("%s\n", reason);
215  }
216 
217  PRINT_MODULE_DESCRIPTION(
218  R"DESCR_STR(
219 ### Description
220 This module is responsible for the safety button.
221 
222 )DESCR_STR");
223 
224  PRINT_MODULE_USAGE_NAME("safety_button", "driver");
225  PRINT_MODULE_USAGE_COMMAND_DESCR("start", "Start the safety button driver");
226 
227  return 0;
228 }
229 
230 extern "C" __EXPORT int safety_button_main(int argc, char *argv[])
231 {
232  return SafetyButton::main(argc, argv);
233 }
void FlashButton()
LED_PATTERN
#define CBRK_IO_SAFETY_KEY
bool circuit_breaker_enabled(const char *breaker, int32_t magic)
int main(int argc, char **argv)
Definition: main.cpp:3
Definition: I2C.hpp:51
static int custom_command(int argc, char *argv[])
static void print_usage()
bool safety_switch_available
Definition: safety.h:54
LidarLite * instance
Definition: ll40ls.cpp:65
void CheckButton()
static struct safety_s safety
Definition: Commander.cpp:140
static struct actuator_armed_s armed
Definition: Commander.cpp:139
static int print_usage(const char *reason=nullptr)
int print_status() override
void Run() override
uint64_t timestamp
Definition: safety.h:53
long off, then quad blink
static int task_spawn(int argc, char *argv[])
virtual ~SafetyButton()
static bool safety_button_pressed
Definition: safety.c:78
long off, then double blink
bool safety_off
Definition: safety.h:55
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
__EXPORT int safety_button_main(int argc, char *argv[])
static constexpr uint8_t CYCLE_COUNT