fix power button shutdown: use an orb topic instead of a work queue call

px4_shutdown_request() was called from the power button IRQ callback, which
invoked a work queue callback. But on NuttX, the work queue uses a
semaphore, and thus it cannot be called from IRQ context.
This patch switches to publishing an uORB msg instead, which is handled in
the commander main thread.

To increase failure resistance, we could subscribe to the same topic in
another module for redundancy, in case commander runs wild.
This commit is contained in:
Beat Küng 2017-07-24 13:05:52 +02:00 committed by Lorenz Meier
parent 61b0a81bf9
commit 2815c62acf
4 changed files with 53 additions and 6 deletions

View File

@ -81,6 +81,7 @@ set(msg_file_names
parameter_update.msg
position_setpoint.msg
position_setpoint_triplet.msg
power_button_state.msg
pwm_input.msg
qshell_req.msg
rc_channels.msg

View File

@ -0,0 +1,8 @@
# power button state notification message
uint8 PWR_BUTTON_STATE_IDEL = 0 # Button went up without meeting shutdown button down time (delete event)
uint8 PWR_BUTTON_STATE_DOWN = 1 # Button went Down
uint8 PWR_BUTTON_STATE_UP = 2 # Button went Up
uint8 PWR_BUTTON_STATE_REQUEST_SHUTDOWN = 3 # Button went Up after meeting shutdown button down time
uint8 event # one of PWR_BUTTON_STATE_*

View File

@ -104,6 +104,7 @@
#include <uORB/topics/mission_result.h>
#include <uORB/topics/offboard_control_mode.h>
#include <uORB/topics/position_setpoint_triplet.h>
#include <uORB/topics/power_button_state.h>
#include <uORB/topics/vehicle_roi.h>
#include <uORB/topics/parameter_update.h>
#include <uORB/topics/safety.h>
@ -174,6 +175,8 @@ static int64_t lvel_probation_time_us = POSVEL_PROBATION_TAKEOFF;
/* Mavlink log uORB handle */
static orb_advert_t mavlink_log_pub = nullptr;
static orb_advert_t power_button_state_pub = nullptr;
/* System autostart ID */
static int autostart_id;
@ -334,11 +337,34 @@ static void publish_status_flags(orb_advert_t &vehicle_status_flags_pub);
static int power_button_state_notification_cb(board_power_button_state_notification_e request)
{
// Note: this can be called from IRQ handlers
if (request == PWR_BUTTON_REQUEST_SHUT_DOWN) {
px4_shutdown_request(false, false);
// Note: this can be called from IRQ handlers, so we publish a message that will be handled
// on the main thread of commander.
power_button_state_s button_state;
button_state.timestamp = hrt_absolute_time();
int ret = PWR_BUTTON_RESPONSE_SHUT_DOWN_PENDING;
switch(request) {
case PWR_BUTTON_IDEL:
button_state.event = power_button_state_s::PWR_BUTTON_STATE_IDEL;
break;
case PWR_BUTTON_DOWN:
button_state.event = power_button_state_s::PWR_BUTTON_STATE_DOWN;
break;
case PWR_BUTTON_UP:
button_state.event = power_button_state_s::PWR_BUTTON_STATE_UP;
break;
case PWR_BUTTON_REQUEST_SHUT_DOWN:
button_state.event = power_button_state_s::PWR_BUTTON_STATE_REQUEST_SHUTDOWN;
break;
default:
PX4_ERR("unhandled power button state: %i", (int)request);
return ret;
}
return PWR_BUTTON_RESPONSE_SHUT_DOWN_PENDING;
int instance;
orb_publish_auto(ORB_ID(power_button_state), &power_button_state_pub, &button_state, &instance, ORB_PRIO_DEFAULT);
return ret;
}
int commander_main(int argc, char *argv[])
@ -1641,6 +1667,8 @@ int commander_thread_main(int argc, char *argv[])
struct system_power_s system_power;
memset(&system_power, 0, sizeof(system_power));
int power_button_state_sub = orb_subscribe(ORB_ID(power_button_state));
/* Subscribe to actuator controls (outputs) */
int actuator_controls_sub = orb_subscribe(ORB_ID_VEHICLE_ATTITUDE_CONTROLS);
struct actuator_controls_s actuator_controls;
@ -1878,6 +1906,17 @@ int commander_thread_main(int argc, char *argv[])
param_init_forced = false;
}
/* handle power button state */
orb_check(power_button_state_sub, &updated);
if (updated) {
power_button_state_s button_state;
orb_copy(ORB_ID(power_button_state), power_button_state_sub, &button_state);
if (button_state.event == power_button_state_s::PWR_BUTTON_STATE_REQUEST_SHUTDOWN) {
px4_shutdown_request(false, false);
}
}
orb_check(sp_man_sub, &updated);
if (updated) {

View File

@ -69,8 +69,7 @@ __EXPORT int px4_unregister_shutdown_hook(shutdown_hook_t hook);
/**
* Request the system to shut down. It's save to call this from an IRQ context,
* but the work queues need to be initialized already.
* Request the system to shut down or reboot.
* Note the following:
* - The system might not support to shutdown (or reboot). In that case -EINVAL will
* be returned.