PX4 Firmware
PX4 Autopilot Software http://px4.io
watchdog.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2016 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 "watchdog.h"
35 
36 #include <px4_platform_common/log.h>
37 
38 #if defined(__PX4_NUTTX) && !defined(CONFIG_SCHED_INSTRUMENTATION)
39 # error watchdog support requires CONFIG_SCHED_INSTRUMENTATION
40 #endif
41 
42 using namespace time_literals;
43 
44 namespace px4
45 {
46 namespace logger
47 {
48 
49 bool watchdog_update(watchdog_data_t &watchdog_data)
50 {
51 
52 #ifdef __PX4_NUTTX
53 
54  if (system_load.initialized && watchdog_data.logger_main_task_index >= 0
55  && watchdog_data.logger_writer_task_index >= 0) {
56  const hrt_abstime now = hrt_absolute_time();
57  const system_load_taskinfo_s &log_writer_task = system_load.tasks[watchdog_data.logger_writer_task_index];
58 
59  if (log_writer_task.valid) {
60  // Trigger the watchdog if the log writer task has been ready to run for a
61  // minimum duration and it has not been scheduled during that time.
62  // When the writer is waiting for an SD transfer, it is not in ready state, thus a long dropout
63  // will not trigger it. The longest period in ready state I measured was around 70ms,
64  // after a param change.
65  // We only check the log writer because it runs at lower priority than the main thread.
66  // No need to lock the tcb access, since we are in IRQ context
67 
68  // update the timestamp if it has been scheduled recently
69  if (log_writer_task.curr_start_time > watchdog_data.ready_to_run_timestamp) {
70  watchdog_data.ready_to_run_timestamp = log_writer_task.curr_start_time;
71  }
72 
73  // update the timestamp if not ready to run or if transitioned into ready to run
74  uint8_t current_state = log_writer_task.tcb->task_state;
75 
76  if (current_state != TSTATE_TASK_READYTORUN
77  || (watchdog_data.last_state != TSTATE_TASK_READYTORUN && current_state == TSTATE_TASK_READYTORUN)) {
78  watchdog_data.ready_to_run_timestamp = now;
79  }
80 
81  watchdog_data.last_state = current_state;
82 
83 #if 0 // for debugging
84  // test code that prints the maximum time in ready state.
85  // Note: we are in IRQ context, and thus are strictly speaking not allowed to use PX4_ERR -
86  // we do it anyway since it's only used for debugging.
87  static uint64_t max_time = 0;
88 
89  if (now - watchdog_data.ready_to_run_timestamp > max_time) {
90  max_time = now - watchdog_data.ready_to_run_timestamp;
91  }
92 
93  static int counter = 0;
94 
95  if (++counter > 300) {
96  PX4_ERR("max time in ready: %i ms", (int)max_time / 1000);
97  counter = 0;
98  max_time = 0;
99  }
100 
101 #endif
102 
103  if (now - watchdog_data.ready_to_run_timestamp > 1_s) {
104  // boost the priority to make sure the logger continues to write to the log.
105  // Note that we never restore the priority, to keep the logic simple and because it is
106  // an event that must not occur under normal circumstances (if it does, there's a bug
107  // somewhere)
108  sched_param param{};
109  param.sched_priority = SCHED_PRIORITY_MAX;
110 
111  if (system_load.tasks[watchdog_data.logger_main_task_index].valid) {
112  sched_setparam(system_load.tasks[watchdog_data.logger_main_task_index].tcb->pid, &param);
113  }
114 
115  sched_setparam(log_writer_task.tcb->pid, &param);
116 
117  // make sure we won't trigger again
118  watchdog_data.logger_main_task_index = -1;
119  return true;
120  }
121 
122  } else {
123  // should never happen
124  watchdog_data.logger_main_task_index = -1;
125  }
126  }
127 
128 #endif /* __PX4_NUTTX */
129 
130  return false;
131 
132 }
133 
134 void watchdog_initialize(const pid_t pid_logger_main, const pthread_t writer_thread, watchdog_data_t &watchdog_data)
135 {
136 #ifdef __PX4_NUTTX
137 
138  // The pthread_t ID is equal to the PID on NuttX
139  const pthread_t pid_logger_writer = writer_thread;
140 
141  sched_lock(); // need to lock the tcb access
142 
143  for (int i = 0; i < CONFIG_MAX_TASKS; i++) {
144  if (system_load.tasks[i].valid) {
145  if (system_load.tasks[i].tcb->pid == pid_logger_writer) {
146  watchdog_data.logger_writer_task_index = i;
147  }
148 
149  if (system_load.tasks[i].tcb->pid == pid_logger_main) {
150  watchdog_data.logger_main_task_index = i;
151  }
152  }
153  }
154 
155  sched_unlock();
156 
157  if (watchdog_data.logger_writer_task_index == -1 ||
158  watchdog_data.logger_main_task_index == -1) {
159  // If we land here it means the NuttX implementation changed
160  // and one of our assumptions is not valid anymore
161  PX4_ERR("watchdog init failed");
162  }
163 
164 #endif /* __PX4_NUTTX */
165 }
166 
167 
168 } // namespace logger
169 } // namespace px4
void watchdog_initialize(const pid_t pid_logger_main, const pthread_t writer_thread, watchdog_data_t &watchdog_data)
Initialize the watchdog, fill in watchdog_data.
Definition: watchdog.cpp:134
bool watchdog_update(watchdog_data_t &watchdog_data)
Update the watchdog and trigger it if necessary.
Definition: watchdog.cpp:49
#define CONFIG_MAX_TASKS
Definition: printload.h:49
static unsigned counter
Definition: safety.c:56
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
Definition: drv_hrt.h:58
Definition: bst.cpp:62
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).