2012-08-04 15:12:36 -07:00
/****************************************************************************
*
2013-06-25 13:15:38 +02:00
* Copyright ( C ) 2013 PX4 Development Team . All rights reserved .
2012-10-23 13:15:36 +02:00
* Author : Petri Tanskanen < petri . tanskanen @ inf . ethz . ch >
* Lorenz Meier < lm @ inf . ethz . ch >
* Thomas Gubler < thomasgubler @ student . ethz . ch >
* Julian Oes < joes @ student . ethz . ch >
2013-09-19 19:58:41 +02:00
* Anton Babushkin < anton . babushkin @ me . com >
2012-08-04 15:12:36 -07:00
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in
* the documentation and / or other materials provided with the
* distribution .
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING ,
* BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS
* OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
2013-07-20 13:47:51 +02:00
* @ file commander . cpp
2012-08-04 15:12:36 -07:00
* Main system state machine implementation .
2012-10-23 13:15:36 +02:00
*
2012-08-04 15:12:36 -07:00
*/
# include <nuttx/config.h>
# include <pthread.h>
# include <stdio.h>
# include <stdlib.h>
# include <stdbool.h>
# include <string.h>
# include <unistd.h>
# include <fcntl.h>
# include <errno.h>
2013-09-05 13:24:21 +02:00
# include <systemlib/err.h>
2012-08-04 15:12:36 -07:00
# include <debug.h>
# include <sys/prctl.h>
2013-08-17 15:47:42 +02:00
# include <sys/stat.h>
2012-08-04 15:12:36 -07:00
# include <string.h>
# include <math.h>
# include <poll.h>
2013-03-11 10:39:57 -07:00
2012-08-04 15:12:36 -07:00
# include <uORB/uORB.h>
# include <uORB/topics/sensor_combined.h>
2013-01-01 13:30:24 +01:00
# include <uORB/topics/battery_status.h>
2012-09-21 12:55:41 +02:00
# include <uORB/topics/manual_control_setpoint.h>
# include <uORB/topics/offboard_control_setpoint.h>
2013-01-19 14:46:26 +01:00
# include <uORB/topics/home_position.h>
2012-12-13 10:23:02 +01:00
# include <uORB/topics/vehicle_global_position.h>
# include <uORB/topics/vehicle_local_position.h>
2013-01-19 14:46:26 +01:00
# include <uORB/topics/vehicle_gps_position.h>
2012-08-04 15:12:36 -07:00
# include <uORB/topics/vehicle_command.h>
2012-08-24 00:01:23 +02:00
# include <uORB/topics/subsystem_info.h>
2012-09-05 11:37:17 +02:00
# include <uORB/topics/actuator_controls.h>
2013-07-15 22:15:15 +02:00
# include <uORB/topics/actuator_armed.h>
2012-12-13 10:23:02 +01:00
# include <uORB/topics/parameter_update.h>
2013-02-24 21:57:38 +01:00
# include <uORB/topics/differential_pressure.h>
2013-07-15 22:15:15 +02:00
# include <uORB/topics/safety.h>
2012-09-25 10:31:19 +02:00
2013-03-11 10:39:57 -07:00
# include <drivers/drv_led.h>
# include <drivers/drv_hrt.h>
# include <drivers/drv_tone_alarm.h>
# include <mavlink/mavlink_log.h>
2012-08-20 23:52:13 +02:00
# include <systemlib/param/param.h>
2012-08-04 15:12:36 -07:00
# include <systemlib/systemlib.h>
2012-09-11 23:35:01 +02:00
# include <systemlib/err.h>
2013-03-11 10:39:57 -07:00
# include <systemlib/cpuload.h>
2013-08-25 16:33:14 +02:00
# include <systemlib/rc_check.h>
2013-03-11 10:39:57 -07:00
2013-08-14 10:59:22 +02:00
# include "px4_custom_mode.h"
2013-06-25 16:30:35 +02:00
# include "commander_helper.h"
2013-03-11 10:39:57 -07:00
# include "state_machine_helper.h"
2012-10-21 15:36:29 +02:00
# include "calibration_routines.h"
2013-04-25 23:59:46 +04:00
# include "accelerometer_calibration.h"
2013-06-25 16:30:35 +02:00
# include "gyro_calibration.h"
# include "mag_calibration.h"
# include "baro_calibration.h"
# include "rc_calibration.h"
# include "airspeed_calibration.h"
2012-09-11 23:35:01 +02:00
2013-07-20 13:47:51 +02:00
/* oddly, ERROR is not defined for c++ */
# ifdef ERROR
# undef ERROR
# endif
static const int ERROR = - 1 ;
2013-03-11 10:39:57 -07:00
2012-08-04 15:12:36 -07:00
extern struct system_load_s system_load ;
/* Decouple update interval and hysteris counters, all depends on intervals */
# define COMMANDER_MONITORING_INTERVAL 50000
# define COMMANDER_MONITORING_LOOPSPERMSEC (1 / (COMMANDER_MONITORING_INTERVAL / 1000.0f))
2013-11-05 19:56:33 +01:00
# define MAVLINK_OPEN_INTERVAL 50000
2012-09-21 12:55:41 +02:00
# define STICK_ON_OFF_LIMIT 0.75f
# define STICK_THRUST_RANGE 1.0f
2012-08-04 15:12:36 -07:00
# define STICK_ON_OFF_HYSTERESIS_TIME_MS 1000
# define STICK_ON_OFF_COUNTER_LIMIT (STICK_ON_OFF_HYSTERESIS_TIME_MS*COMMANDER_MONITORING_LOOPSPERMSEC)
2013-08-17 12:37:41 +02:00
# define POSITION_TIMEOUT 1000000 /**< consider the local or global position estimate invalid after 1s */
# define RC_TIMEOUT 100000
# define DIFFPRESS_TIMEOUT 2000000
2013-03-11 10:39:57 -07:00
2013-07-31 20:58:27 +04:00
# define PRINT_INTERVAL 5000000
# define PRINT_MODE_REJECT_INTERVAL 2000000
enum MAV_MODE_FLAG {
MAV_MODE_FLAG_CUSTOM_MODE_ENABLED = 1 , /* 0b00000001 Reserved for future use. | */
MAV_MODE_FLAG_TEST_ENABLED = 2 , /* 0b00000010 system has a test mode enabled. This flag is intended for temporary system tests and should not be used for stable implementations. | */
MAV_MODE_FLAG_AUTO_ENABLED = 4 , /* 0b00000100 autonomous mode enabled, system finds its own goal positions. Guided flag can be set or not, depends on the actual implementation. | */
MAV_MODE_FLAG_GUIDED_ENABLED = 8 , /* 0b00001000 guided mode enabled, system flies MISSIONs / mission items. | */
MAV_MODE_FLAG_STABILIZE_ENABLED = 16 , /* 0b00010000 system stabilizes electronically its attitude (and optionally position). It needs however further control inputs to move around. | */
MAV_MODE_FLAG_HIL_ENABLED = 32 , /* 0b00100000 hardware in the loop simulation. All motors / actuators are blocked, but internal software is full operational. | */
MAV_MODE_FLAG_MANUAL_INPUT_ENABLED = 64 , /* 0b01000000 remote control input is enabled. | */
MAV_MODE_FLAG_SAFETY_ARMED = 128 , /* 0b10000000 MAV safety set to armed. Motors are enabled / running / can start. Ready to fly. | */
MAV_MODE_FLAG_ENUM_END = 129 , /* | */
} ;
2013-08-07 20:21:49 +02:00
2013-07-16 09:24:21 +02:00
/* Mavlink file descriptors */
2012-08-04 15:12:36 -07:00
static int mavlink_fd ;
2013-02-16 13:40:09 -08:00
/* flags */
2012-08-04 15:12:36 -07:00
static bool commander_initialized = false ;
2013-09-08 20:05:15 +02:00
static volatile bool thread_should_exit = false ; /**< daemon exit flag */
static volatile bool thread_running = false ; /**< daemon status flag */
2013-02-16 13:40:09 -08:00
static int daemon_task ; /**< Handle of daemon task / thread */
2013-07-31 20:58:27 +04:00
static unsigned int leds_counter ;
/* To remember when last notification was sent */
static uint64_t last_print_mode_reject_time = 0 ;
2013-08-17 15:47:42 +02:00
/* if connected via USB */
static bool on_usb_power = false ;
2013-07-31 20:58:27 +04:00
2013-08-30 10:11:24 +02:00
static float takeoff_alt = 5.0f ;
2012-09-21 12:55:41 +02:00
2013-03-25 14:53:54 -07:00
/* tasks waiting for low prio thread */
2013-07-31 20:58:27 +04:00
typedef enum {
2013-03-25 14:53:54 -07:00
LOW_PRIO_TASK_NONE = 0 ,
LOW_PRIO_TASK_PARAM_SAVE ,
LOW_PRIO_TASK_PARAM_LOAD ,
LOW_PRIO_TASK_GYRO_CALIBRATION ,
LOW_PRIO_TASK_MAG_CALIBRATION ,
LOW_PRIO_TASK_ALTITUDE_CALIBRATION ,
LOW_PRIO_TASK_RC_CALIBRATION ,
LOW_PRIO_TASK_ACCEL_CALIBRATION ,
LOW_PRIO_TASK_AIRSPEED_CALIBRATION
2013-07-31 20:58:27 +04:00
} low_prio_task_t ;
2013-03-25 14:53:54 -07:00
2013-07-31 20:58:27 +04:00
static low_prio_task_t low_prio_task = LOW_PRIO_TASK_NONE ;
2012-08-04 15:12:36 -07:00
2013-07-16 09:24:21 +02:00
/**
2013-07-16 09:35:31 +02:00
* The daemon app only briefly exists to start
* the background job . The stack size assigned in the
* Makefile does only apply to this management task .
*
* The actual stack size should be set in the call
* to task_create ( ) .
2013-07-20 13:47:51 +02:00
*
* @ ingroup apps
2013-07-16 09:24:21 +02:00
*/
2013-07-20 13:47:51 +02:00
extern " C " __EXPORT int commander_main ( int argc , char * argv [ ] ) ;
2012-08-04 15:12:36 -07:00
2012-08-20 23:52:13 +02:00
/**
2013-07-16 09:35:31 +02:00
* Print the correct usage .
2012-08-20 23:52:13 +02:00
*/
2013-07-16 09:35:31 +02:00
void usage ( const char * reason ) ;
2012-08-20 23:52:13 +02:00
2013-07-16 09:24:21 +02:00
/**
* React to commands that are sent e . g . from the mavlink module .
*/
2013-12-29 22:38:22 +04:00
bool handle_command ( struct vehicle_status_s * status , struct vehicle_command_s * cmd , struct actuator_armed_s * armed ) ;
2012-08-20 23:52:13 +02:00
/**
2013-07-16 09:35:31 +02:00
* Mainloop of commander .
2012-08-20 23:52:13 +02:00
*/
2013-07-16 09:35:31 +02:00
int commander_thread_main ( int argc , char * argv [ ] ) ;
2013-11-01 09:05:28 +01:00
void control_status_leds ( vehicle_status_s * status , const actuator_armed_s * actuator_armed , bool changed ) ;
2013-08-27 23:08:00 +02:00
2013-08-17 12:37:41 +02:00
void check_valid ( hrt_abstime timestamp , hrt_abstime timeout , bool valid_in , bool * valid_out , bool * changed ) ;
2013-07-31 20:58:27 +04:00
2013-07-28 23:12:16 +04:00
void check_mode_switches ( struct manual_control_setpoint_s * sp_man , struct vehicle_status_s * current_status ) ;
transition_result_t check_main_state_machine ( struct vehicle_status_s * current_status ) ;
2013-07-31 20:58:27 +04:00
void print_reject_mode ( const char * msg ) ;
2013-08-27 23:08:00 +02:00
2013-08-16 09:23:39 +02:00
void print_reject_arm ( const char * msg ) ;
2013-07-31 20:58:27 +04:00
2013-08-17 15:47:42 +02:00
void print_status ( ) ;
2013-07-16 09:35:31 +02:00
/**
* Loop that runs at a lower rate and priority for calibration and parameter tasks .
*/
void * commander_low_prio_loop ( void * arg ) ;
2013-08-27 23:08:00 +02:00
void answer_command ( struct vehicle_command_s & cmd , enum VEHICLE_CMD_RESULT result ) ;
2013-07-16 09:35:31 +02:00
int commander_main ( int argc , char * argv [ ] )
{
if ( argc < 1 )
usage ( " missing command " ) ;
if ( ! strcmp ( argv [ 1 ] , " start " ) ) {
if ( thread_running ) {
2013-09-08 20:05:15 +02:00
warnx ( " commander already running " ) ;
2013-07-16 09:35:31 +02:00
/* this is not an error */
exit ( 0 ) ;
}
thread_should_exit = false ;
daemon_task = task_spawn_cmd ( " commander " ,
2013-07-28 23:12:16 +04:00
SCHED_DEFAULT ,
SCHED_PRIORITY_MAX - 40 ,
3000 ,
commander_thread_main ,
( argv ) ? ( const char * * ) & argv [ 2 ] : ( const char * * ) NULL ) ;
2013-09-08 20:05:15 +02:00
while ( ! thread_running ) {
usleep ( 200 ) ;
}
2013-07-16 09:35:31 +02:00
exit ( 0 ) ;
}
2012-08-04 15:12:36 -07:00
2013-07-16 09:35:31 +02:00
if ( ! strcmp ( argv [ 1 ] , " stop " ) ) {
2013-09-08 20:05:15 +02:00
if ( ! thread_running )
errx ( 0 , " commander already stopped " ) ;
2013-07-16 09:35:31 +02:00
thread_should_exit = true ;
2013-09-08 20:05:15 +02:00
while ( thread_running ) {
usleep ( 200000 ) ;
warnx ( " . " ) ;
}
warnx ( " terminated. " ) ;
2013-07-16 09:35:31 +02:00
exit ( 0 ) ;
}
2013-03-25 14:53:54 -07:00
2013-07-16 09:35:31 +02:00
if ( ! strcmp ( argv [ 1 ] , " status " ) ) {
if ( thread_running ) {
2013-09-08 20:05:15 +02:00
warnx ( " \t commander is running " ) ;
2013-08-17 15:47:42 +02:00
print_status ( ) ;
2013-07-16 09:35:31 +02:00
} else {
2013-09-08 20:05:15 +02:00
warnx ( " \t commander not started " ) ;
2013-07-16 09:35:31 +02:00
}
exit ( 0 ) ;
}
usage ( " unrecognized command " ) ;
exit ( 1 ) ;
}
void usage ( const char * reason )
{
if ( reason )
fprintf ( stderr , " %s \n " , reason ) ;
fprintf ( stderr , " usage: daemon {start|stop|status} [-p <additional params>] \n \n " ) ;
exit ( 1 ) ;
}
2013-02-24 21:57:38 +01:00
2013-08-27 23:08:00 +02:00
void print_status ( )
{
2013-08-17 15:47:42 +02:00
warnx ( " usb powered: %s " , ( on_usb_power ) ? " yes " : " no " ) ;
2013-08-18 12:42:24 +02:00
/* read all relevant states */
int state_sub = orb_subscribe ( ORB_ID ( vehicle_status ) ) ;
struct vehicle_status_s state ;
orb_copy ( ORB_ID ( vehicle_status ) , state_sub , & state ) ;
2013-08-27 23:08:00 +02:00
const char * armed_str ;
2013-08-18 12:42:24 +02:00
switch ( state . arming_state ) {
2013-08-27 23:08:00 +02:00
case ARMING_STATE_INIT :
armed_str = " INIT " ;
break ;
case ARMING_STATE_STANDBY :
armed_str = " STANDBY " ;
break ;
case ARMING_STATE_ARMED :
armed_str = " ARMED " ;
break ;
case ARMING_STATE_ARMED_ERROR :
armed_str = " ARMED_ERROR " ;
break ;
case ARMING_STATE_STANDBY_ERROR :
armed_str = " STANDBY_ERROR " ;
break ;
case ARMING_STATE_REBOOT :
armed_str = " REBOOT " ;
break ;
case ARMING_STATE_IN_AIR_RESTORE :
armed_str = " IN_AIR_RESTORE " ;
break ;
default :
armed_str = " ERR: UNKNOWN STATE " ;
break ;
2013-08-18 12:42:24 +02:00
}
2013-09-01 10:29:30 +02:00
close ( state_sub ) ;
2013-08-18 12:42:24 +02:00
warnx ( " arming: %s " , armed_str ) ;
2013-08-17 15:47:42 +02:00
}
2013-09-08 21:06:55 +02:00
static orb_advert_t status_pub ;
2013-12-29 22:38:22 +04:00
bool handle_command ( struct vehicle_status_s * status , const struct safety_s * safety , struct vehicle_command_s * cmd , struct actuator_armed_s * armed )
2012-08-04 15:12:36 -07:00
{
/* result of the command */
2013-12-29 12:16:49 +04:00
enum VEHICLE_CMD_RESULT result = VEHICLE_CMD_RESULT_UNSUPPORTED ;
2013-12-29 22:38:22 +04:00
bool ret = false ;
2012-08-04 15:12:36 -07:00
2013-08-17 18:39:46 +02:00
/* only handle high-priority commands here */
2012-08-04 15:12:36 -07:00
/* request to set different system mode */
switch ( cmd - > command ) {
2013-07-31 20:58:27 +04:00
case VEHICLE_CMD_DO_SET_MODE : {
2013-08-07 20:21:49 +02:00
uint8_t base_mode = ( uint8_t ) cmd - > param1 ;
2013-08-25 20:17:42 +02:00
uint8_t custom_main_mode = ( uint8_t ) cmd - > param2 ;
2013-10-06 14:18:28 +02:00
transition_result_t arming_res = TRANSITION_NOT_CHANGED ;
2013-08-07 20:21:49 +02:00
2013-09-08 21:06:55 +02:00
/* set HIL state */
hil_state_t new_hil_state = ( base_mode & MAV_MODE_FLAG_HIL_ENABLED ) ? HIL_STATE_ON : HIL_STATE_OFF ;
2013-12-29 12:16:49 +04:00
int hil_ret = hil_state_transition ( new_hil_state , status_pub , status , mavlink_fd ) ;
2013-10-06 14:18:28 +02:00
/* if HIL got enabled, reset battery status state */
2013-12-29 12:16:49 +04:00
if ( hil_ret = = OK & & status - > hil_state = = HIL_STATE_ON ) {
2013-10-06 14:18:28 +02:00
/* reset the arming mode to disarmed */
2013-12-29 12:16:49 +04:00
arming_res = arming_state_transition ( status , safety , ARMING_STATE_STANDBY , armed ) ;
2013-10-21 20:07:47 +02:00
2013-10-06 14:18:28 +02:00
if ( arming_res ! = TRANSITION_DENIED ) {
mavlink_log_info ( mavlink_fd , " [cmd] HIL: Reset ARMED state to standby " ) ;
2013-10-21 20:07:47 +02:00
2013-10-06 14:18:28 +02:00
} else {
mavlink_log_info ( mavlink_fd , " [cmd] HIL: FAILED resetting armed state " ) ;
}
}
2013-12-29 22:38:22 +04:00
if ( hil_ret = = OK )
ret = true ;
2013-09-08 21:06:55 +02:00
2013-07-31 20:58:27 +04:00
// TODO remove debug code
2013-10-28 14:47:37 +01:00
//mavlink_log_critical(mavlink_fd, "#audio: command setmode: %d %d", base_mode, custom_main_mode);
2013-07-31 20:58:27 +04:00
/* set arming state */
2013-10-06 14:18:28 +02:00
arming_res = TRANSITION_NOT_CHANGED ;
2013-07-31 20:58:27 +04:00
if ( base_mode & MAV_MODE_FLAG_SAFETY_ARMED ) {
2013-12-29 12:16:49 +04:00
if ( ( safety - > safety_switch_available & & ! safety - > safety_off ) & & status - > hil_state = = HIL_STATE_OFF ) {
2013-09-14 08:55:45 +02:00
print_reject_arm ( " NOT ARMING: Press safety switch first. " ) ;
arming_res = TRANSITION_DENIED ;
} else {
2013-12-29 12:16:49 +04:00
arming_res = arming_state_transition ( status , safety , ARMING_STATE_ARMED , armed ) ;
2013-09-14 08:55:45 +02:00
}
2013-08-07 20:21:49 +02:00
2013-07-31 20:58:27 +04:00
if ( arming_res = = TRANSITION_CHANGED ) {
mavlink_log_info ( mavlink_fd , " [cmd] ARMED by command " ) ;
}
2012-08-08 18:47:46 +02:00
2013-07-31 20:58:27 +04:00
} else {
if ( status - > arming_state = = ARMING_STATE_ARMED | | status - > arming_state = = ARMING_STATE_ARMED_ERROR ) {
arming_state_t new_arming_state = ( status - > arming_state = = ARMING_STATE_ARMED ? ARMING_STATE_STANDBY : ARMING_STATE_STANDBY_ERROR ) ;
2013-12-29 12:16:49 +04:00
arming_res = arming_state_transition ( status , safety , new_arming_state , armed ) ;
2013-08-07 20:21:49 +02:00
2013-07-31 20:58:27 +04:00
if ( arming_res = = TRANSITION_CHANGED ) {
mavlink_log_info ( mavlink_fd , " [cmd] DISARMED by command " ) ;
}
2013-08-07 20:21:49 +02:00
2013-07-31 20:58:27 +04:00
} else {
arming_res = TRANSITION_NOT_CHANGED ;
}
}
2013-12-29 22:38:22 +04:00
if ( arming_res = = TRANSITION_CHANGED )
ret = true ;
2012-08-13 18:53:37 +02:00
2013-07-31 20:58:27 +04:00
/* set main state */
transition_result_t main_res = TRANSITION_DENIED ;
2012-08-04 15:12:36 -07:00
2013-08-07 20:21:49 +02:00
if ( base_mode & MAV_MODE_FLAG_CUSTOM_MODE_ENABLED ) {
/* use autopilot-specific mode */
2013-08-25 20:17:42 +02:00
if ( custom_main_mode = = PX4_CUSTOM_MAIN_MODE_MANUAL ) {
2013-08-07 20:21:49 +02:00
/* MANUAL */
main_res = main_state_transition ( status , MAIN_STATE_MANUAL ) ;
2013-08-25 20:17:42 +02:00
} else if ( custom_main_mode = = PX4_CUSTOM_MAIN_MODE_SEATBELT ) {
2013-08-07 20:21:49 +02:00
/* SEATBELT */
main_res = main_state_transition ( status , MAIN_STATE_SEATBELT ) ;
2012-12-27 17:13:48 +01:00
2013-08-25 20:17:42 +02:00
} else if ( custom_main_mode = = PX4_CUSTOM_MAIN_MODE_EASY ) {
2013-07-31 20:58:27 +04:00
/* EASY */
main_res = main_state_transition ( status , MAIN_STATE_EASY ) ;
2012-12-27 17:13:48 +01:00
2013-08-25 20:17:42 +02:00
} else if ( custom_main_mode = = PX4_CUSTOM_MAIN_MODE_AUTO ) {
2013-08-07 20:21:49 +02:00
/* AUTO */
main_res = main_state_transition ( status , MAIN_STATE_AUTO ) ;
}
2013-07-28 23:12:16 +04:00
2013-08-07 20:21:49 +02:00
} else {
/* use base mode */
if ( base_mode & MAV_MODE_FLAG_AUTO_ENABLED ) {
/* AUTO */
main_res = main_state_transition ( status , MAIN_STATE_AUTO ) ;
} else if ( base_mode & MAV_MODE_FLAG_MANUAL_INPUT_ENABLED ) {
if ( base_mode & MAV_MODE_FLAG_GUIDED_ENABLED ) {
/* EASY */
main_res = main_state_transition ( status , MAIN_STATE_EASY ) ;
} else if ( base_mode & MAV_MODE_FLAG_STABILIZE_ENABLED ) {
2013-07-31 20:58:27 +04:00
/* MANUAL */
main_res = main_state_transition ( status , MAIN_STATE_MANUAL ) ;
}
2013-02-19 12:32:47 -08:00
}
2013-07-31 20:58:27 +04:00
}
2013-12-29 22:38:22 +04:00
if ( main_res = = TRANSITION_CHANGED )
ret = true ;
2013-07-31 20:58:27 +04:00
if ( arming_res ! = TRANSITION_DENIED & & main_res ! = TRANSITION_DENIED ) {
result = VEHICLE_CMD_RESULT_ACCEPTED ;
2012-08-29 14:20:55 +02:00
2013-07-28 23:12:16 +04:00
} else {
result = VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED ;
2012-08-04 15:12:36 -07:00
}
2013-07-31 20:58:27 +04:00
break ;
}
2012-11-02 15:21:37 +01:00
2013-10-21 20:07:47 +02:00
case VEHICLE_CMD_COMPONENT_ARM_DISARM : {
transition_result_t arming_res = TRANSITION_NOT_CHANGED ;
2013-09-22 14:43:12 +02:00
2013-10-21 20:07:47 +02:00
if ( ! armed - > armed & & ( ( int ) ( cmd - > param1 + 0.5f ) ) = = 1 ) {
if ( safety - > safety_switch_available & & ! safety - > safety_off ) {
print_reject_arm ( " NOT ARMING: Press safety switch first. " ) ;
arming_res = TRANSITION_DENIED ;
2013-09-22 14:43:12 +02:00
2013-10-21 20:07:47 +02:00
} else {
2013-12-29 12:16:49 +04:00
arming_res = arming_state_transition ( status , safety , ARMING_STATE_ARMED , armed ) ;
2013-10-21 20:07:47 +02:00
}
if ( arming_res = = TRANSITION_CHANGED ) {
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: ARMED by component arm cmd " ) ;
2013-10-21 20:07:47 +02:00
result = VEHICLE_CMD_RESULT_ACCEPTED ;
2013-12-29 22:38:22 +04:00
ret = true ;
2013-10-21 20:07:47 +02:00
} else {
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: REJECTING component arm cmd " ) ;
2013-10-21 20:07:47 +02:00
result = VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED ;
}
2013-09-22 14:43:12 +02:00
}
}
2013-07-31 20:58:27 +04:00
break ;
2013-01-11 07:42:09 +01:00
2013-12-29 22:38:22 +04:00
case VEHICLE_CMD_OVERRIDE_GOTO : {
// TODO listen vehicle_command topic directly from navigator (?)
unsigned int mav_goto = cmd - > param1 ;
if ( mav_goto = = 0 ) { // MAV_GOTO_DO_HOLD
status - > set_nav_state = NAV_STATE_LOITER ;
status - > set_nav_state_timestamp = hrt_absolute_time ( ) ;
mavlink_log_critical ( mavlink_fd , " #audio: pause mission cmd " ) ;
result = VEHICLE_CMD_RESULT_ACCEPTED ;
ret = true ;
} else if ( mav_goto = = 1 ) { // MAV_GOTO_DO_CONTINUE
status - > set_nav_state = NAV_STATE_MISSION ;
status - > set_nav_state_timestamp = hrt_absolute_time ( ) ;
mavlink_log_critical ( mavlink_fd , " #audio: continue mission cmd " ) ;
result = VEHICLE_CMD_RESULT_ACCEPTED ;
ret = true ;
} else {
mavlink_log_info ( mavlink_fd , " Unsupported OVERRIDE_GOTO: %f %f %f %f %f %f %f %f " , cmd - > param1 , cmd - > param2 , cmd - > param3 , cmd - > param4 , cmd - > param5 , cmd - > param6 , cmd - > param7 ) ;
}
}
break ;
2013-12-08 16:52:41 +01:00
/* Flight termination */
case VEHICLE_CMD_DO_SET_SERVO : { //xxx: needs its own mavlink command
if ( armed - > armed & & cmd - > param3 > 0.5 ) { //xxx: for safety only for now, param3 is unused by VEHICLE_CMD_DO_SET_SERVO
2013-12-29 12:16:49 +04:00
transition_result_t flighttermination_res = flighttermination_state_transition ( status , FLIGHTTERMINATION_STATE_ON ) ;
2013-12-08 16:52:41 +01:00
result = VEHICLE_CMD_RESULT_ACCEPTED ;
2013-12-29 22:38:22 +04:00
ret = true ;
2013-12-08 16:52:41 +01:00
} else {
/* reject parachute depoyment not armed */
result = VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED ;
}
}
break ;
2013-12-29 12:16:49 +04:00
case VEHICLE_CMD_PREFLIGHT_REBOOT_SHUTDOWN :
case VEHICLE_CMD_PREFLIGHT_CALIBRATION :
case VEHICLE_CMD_PREFLIGHT_SET_SENSOR_OFFSETS :
case VEHICLE_CMD_PREFLIGHT_STORAGE :
/* ignore commands that handled in low prio loop */
break ;
2013-05-17 11:24:02 +02:00
default :
2013-12-29 12:16:49 +04:00
/* warn about unsupported commands */
answer_command ( * cmd , VEHICLE_CMD_RESULT_UNSUPPORTED ) ;
2012-08-04 15:12:36 -07:00
break ;
}
2013-12-29 12:16:49 +04:00
if ( result ! = VEHICLE_CMD_RESULT_UNSUPPORTED ) {
/* already warned about unsupported commands in "default" case */
answer_command ( * cmd , result ) ;
2012-11-02 15:21:37 +01:00
}
2012-08-04 15:12:36 -07:00
/* send any requested ACKs */
2013-08-17 18:39:46 +02:00
if ( cmd - > confirmation > 0 & & result ! = VEHICLE_CMD_RESULT_UNSUPPORTED ) {
2012-08-04 15:12:36 -07:00
/* send acknowledge command */
2012-08-24 00:01:23 +02:00
// XXX TODO
2012-08-04 15:12:36 -07:00
}
}
2013-08-17 18:39:46 +02:00
static struct vehicle_status_s status ;
/* armed topic */
static struct actuator_armed_s armed ;
static struct safety_s safety ;
2012-08-20 23:52:13 +02:00
int commander_thread_main ( int argc , char * argv [ ] )
2012-08-04 15:12:36 -07:00
{
/* not yet initialized */
commander_initialized = false ;
2013-01-19 14:46:26 +01:00
bool home_position_set = false ;
2012-08-04 15:12:36 -07:00
2013-06-25 13:15:38 +02:00
bool battery_tune_played = false ;
bool arm_tune_played = false ;
2012-09-21 12:55:41 +02:00
/* set parameters */
2012-12-31 12:31:31 -08:00
param_t _param_sys_type = param_find ( " MAV_TYPE " ) ;
2013-02-17 16:06:33 +01:00
param_t _param_system_id = param_find ( " MAV_SYS_ID " ) ;
param_t _param_component_id = param_find ( " MAV_COMP_ID " ) ;
2013-08-30 10:11:24 +02:00
param_t _param_takeoff_alt = param_find ( " NAV_TAKEOFF_ALT " ) ;
2012-12-13 10:23:02 +01:00
2012-08-04 15:12:36 -07:00
/* welcome user */
2013-08-30 10:11:24 +02:00
warnx ( " starting " ) ;
2012-08-04 15:12:36 -07:00
2013-07-16 09:24:21 +02:00
/* pthread for slow low prio thread */
2013-03-25 14:53:54 -07:00
pthread_t commander_low_prio_thread ;
2012-08-04 15:12:36 -07:00
/* initialize */
if ( led_init ( ) ! = 0 ) {
2013-02-16 13:40:09 -08:00
warnx ( " ERROR: Failed to initialize leds " ) ;
2012-08-04 15:12:36 -07:00
}
2013-06-25 16:30:35 +02:00
if ( buzzer_init ( ) ! = OK ) {
2013-02-16 13:40:09 -08:00
warnx ( " ERROR: Failed to initialize buzzer " ) ;
2012-08-04 15:12:36 -07:00
}
mavlink_fd = open ( MAVLINK_LOG_DEVICE , 0 ) ;
2013-06-14 13:53:26 +02:00
/* Main state machine */
2012-08-13 18:53:37 +02:00
/* make sure we are in preflight state */
2013-07-28 23:12:16 +04:00
memset ( & status , 0 , sizeof ( status ) ) ;
2013-08-16 23:36:49 +02:00
status . condition_landed = true ; // initialize to safe value
2013-03-11 10:39:57 -07:00
2013-07-15 22:15:15 +02:00
/* armed topic */
orb_advert_t armed_pub ;
/* Initialize armed with all false */
memset ( & armed , 0 , sizeof ( armed ) ) ;
2013-06-14 13:53:26 +02:00
2013-07-28 23:12:16 +04:00
status . main_state = MAIN_STATE_MANUAL ;
2013-12-31 12:46:35 +04:00
status . set_nav_state = NAV_STATE_NONE ;
2013-12-29 12:16:49 +04:00
status . set_nav_state_timestamp = 0 ;
2013-07-28 23:12:16 +04:00
status . arming_state = ARMING_STATE_INIT ;
status . hil_state = HIL_STATE_OFF ;
2013-02-16 13:40:09 -08:00
2012-10-02 13:02:57 +02:00
/* neither manual nor offboard control commands have been received */
2013-07-28 23:12:16 +04:00
status . offboard_control_signal_found_once = false ;
status . rc_signal_found_once = false ;
2013-02-16 13:40:09 -08:00
2012-10-02 13:02:57 +02:00
/* mark all signals lost as long as they haven't been found */
2013-07-28 23:12:16 +04:00
status . rc_signal_lost = true ;
status . offboard_control_signal_lost = true ;
2013-02-16 13:40:09 -08:00
2013-01-08 21:19:23 +01:00
/* set battery warning flag */
2013-07-28 23:12:16 +04:00
status . battery_warning = VEHICLE_BATTERY_WARNING_NONE ;
2013-08-15 17:27:29 +02:00
status . condition_battery_voltage_valid = false ;
2013-07-28 23:12:16 +04:00
2013-02-17 23:07:07 -08:00
// XXX for now just set sensors as initialized
2013-07-28 23:12:16 +04:00
status . condition_system_sensors_initialized = true ;
2013-02-17 23:07:07 -08:00
2012-08-04 15:12:36 -07:00
/* advertise to ORB */
2013-07-28 23:12:16 +04:00
status_pub = orb_advertise ( ORB_ID ( vehicle_status ) , & status ) ;
2012-08-16 15:49:56 +02:00
/* publish current state machine */
2013-07-28 23:12:16 +04:00
2013-07-31 20:58:27 +04:00
/* publish initial state */
2013-07-28 23:12:16 +04:00
status . counter + + ;
status . timestamp = hrt_absolute_time ( ) ;
orb_publish ( ORB_ID ( vehicle_status ) , status_pub , & status ) ;
2013-06-25 16:30:35 +02:00
2013-07-15 22:15:15 +02:00
armed_pub = orb_advertise ( ORB_ID ( actuator_armed ) , & armed ) ;
2013-06-25 13:15:38 +02:00
2013-01-19 14:46:26 +01:00
/* home position */
orb_advert_t home_pub = - 1 ;
struct home_position_s home ;
memset ( & home , 0 , sizeof ( home ) ) ;
2013-06-14 13:53:26 +02:00
if ( status_pub < 0 ) {
2013-02-18 16:45:59 +01:00
warnx ( " ERROR: orb_advertise for topic vehicle_status failed (uorb app running?). \n " ) ;
warnx ( " exiting. " ) ;
2012-08-11 19:45:32 +02:00
exit ( ERROR ) ;
2012-08-04 15:12:36 -07:00
}
2013-07-31 20:58:27 +04:00
mavlink_log_info ( mavlink_fd , " [cmd] started " ) ;
2012-08-04 15:12:36 -07:00
2013-09-08 20:05:15 +02:00
int ret ;
2013-03-25 14:53:54 -07:00
pthread_attr_t commander_low_prio_attr ;
pthread_attr_init ( & commander_low_prio_attr ) ;
2013-08-31 11:49:36 +02:00
pthread_attr_setstacksize ( & commander_low_prio_attr , 2992 ) ;
2013-03-25 14:53:54 -07:00
struct sched_param param ;
2013-09-05 13:24:21 +02:00
( void ) pthread_attr_getschedparam ( & commander_low_prio_attr , & param ) ;
2013-09-08 20:05:15 +02:00
2013-03-25 14:53:54 -07:00
/* low priority */
param . sched_priority = SCHED_PRIORITY_DEFAULT - 50 ;
( void ) pthread_attr_setschedparam ( & commander_low_prio_attr , & param ) ;
pthread_create ( & commander_low_prio_thread , & commander_low_prio_attr , commander_low_prio_loop , NULL ) ;
2013-09-08 20:05:15 +02:00
pthread_attr_destroy ( & commander_low_prio_attr ) ;
2013-03-25 14:53:54 -07:00
2012-08-04 15:12:36 -07:00
/* Start monitoring loop */
2013-07-16 18:55:32 +02:00
unsigned counter = 0 ;
unsigned stick_off_counter = 0 ;
unsigned stick_on_counter = 0 ;
2012-08-04 15:12:36 -07:00
2013-08-15 17:27:29 +02:00
bool low_battery_voltage_actions_done = false ;
bool critical_battery_voltage_actions_done = false ;
2013-07-16 18:55:32 +02:00
2013-07-16 10:05:51 +02:00
uint64_t last_idle_time = 0 ;
uint64_t start_time = 0 ;
2013-07-31 20:58:27 +04:00
bool status_changed = true ;
2013-07-16 10:05:51 +02:00
bool param_init_forced = true ;
2013-07-31 20:58:27 +04:00
bool updated = false ;
2013-07-16 10:05:51 +02:00
2013-10-22 21:01:30 +02:00
bool rc_calibration_ok = ( OK = = rc_calibration_check ( mavlink_fd ) ) ;
2013-08-25 16:33:14 +02:00
2013-07-15 22:15:15 +02:00
/* Subscribe to safety topic */
int safety_sub = orb_subscribe ( ORB_ID ( safety ) ) ;
memset ( & safety , 0 , sizeof ( safety ) ) ;
2013-08-15 09:52:22 +02:00
safety . safety_switch_available = false ;
safety . safety_off = false ;
2013-07-15 22:15:15 +02:00
2012-09-21 12:55:41 +02:00
/* Subscribe to manual control data */
int sp_man_sub = orb_subscribe ( ORB_ID ( manual_control_setpoint ) ) ;
struct manual_control_setpoint_s sp_man ;
memset ( & sp_man , 0 , sizeof ( sp_man ) ) ;
/* Subscribe to offboard control data */
int sp_offboard_sub = orb_subscribe ( ORB_ID ( offboard_control_setpoint ) ) ;
struct offboard_control_setpoint_s sp_offboard ;
memset ( & sp_offboard , 0 , sizeof ( sp_offboard ) ) ;
2012-08-04 15:12:36 -07:00
2013-02-16 13:40:09 -08:00
/* Subscribe to global position */
2012-12-13 10:23:02 +01:00
int global_position_sub = orb_subscribe ( ORB_ID ( vehicle_global_position ) ) ;
struct vehicle_global_position_s global_position ;
memset ( & global_position , 0 , sizeof ( global_position ) ) ;
2013-02-16 13:40:09 -08:00
/* Subscribe to local position data */
2012-12-13 10:23:02 +01:00
int local_position_sub = orb_subscribe ( ORB_ID ( vehicle_local_position ) ) ;
struct vehicle_local_position_s local_position ;
memset ( & local_position , 0 , sizeof ( local_position ) ) ;
2012-08-04 15:12:36 -07:00
2013-07-28 23:12:16 +04:00
/*
2013-01-19 14:46:26 +01:00
* The home position is set based on GPS only , to prevent a dependency between
* position estimator and commander . RAW GPS is more than good enough for a
* non - flying vehicle .
*/
2013-02-16 13:40:09 -08:00
/* Subscribe to GPS topic */
2013-01-19 14:46:26 +01:00
int gps_sub = orb_subscribe ( ORB_ID ( vehicle_gps_position ) ) ;
struct vehicle_gps_position_s gps_position ;
memset ( & gps_position , 0 , sizeof ( gps_position ) ) ;
2013-02-16 13:40:09 -08:00
/* Subscribe to sensor topic */
2012-08-04 15:12:36 -07:00
int sensor_sub = orb_subscribe ( ORB_ID ( sensor_combined ) ) ;
2012-08-05 22:51:31 +02:00
struct sensor_combined_s sensors ;
memset ( & sensors , 0 , sizeof ( sensors ) ) ;
2012-08-04 15:12:36 -07:00
2013-07-16 10:05:51 +02:00
/* Subscribe to differential pressure topic */
2013-04-19 18:28:06 +02:00
int diff_pres_sub = orb_subscribe ( ORB_ID ( differential_pressure ) ) ;
struct differential_pressure_s diff_pres ;
memset ( & diff_pres , 0 , sizeof ( diff_pres ) ) ;
2013-02-25 15:48:16 +01:00
2012-10-15 08:52:41 +02:00
/* Subscribe to command topic */
int cmd_sub = orb_subscribe ( ORB_ID ( vehicle_command ) ) ;
struct vehicle_command_s cmd ;
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
2012-12-13 10:23:02 +01:00
/* Subscribe to parameters changed topic */
int param_changed_sub = orb_subscribe ( ORB_ID ( parameter_update ) ) ;
struct parameter_update_s param_changed ;
memset ( & param_changed , 0 , sizeof ( param_changed ) ) ;
2013-07-16 10:05:51 +02:00
/* Subscribe to battery topic */
2013-01-01 13:30:24 +01:00
int battery_sub = orb_subscribe ( ORB_ID ( battery_status ) ) ;
struct battery_status_s battery ;
memset ( & battery , 0 , sizeof ( battery ) ) ;
2013-07-16 09:24:21 +02:00
/* Subscribe to subsystem info topic */
int subsys_sub = orb_subscribe ( ORB_ID ( subsystem_info ) ) ;
struct subsystem_info_s info ;
memset ( & info , 0 , sizeof ( info ) ) ;
2013-09-19 19:58:41 +02:00
control_status_leds ( & status , & armed , true ) ;
2013-08-29 16:45:33 +02:00
2012-08-04 15:12:36 -07:00
/* now initialized */
commander_initialized = true ;
2013-02-18 16:45:59 +01:00
thread_running = true ;
2012-08-04 15:12:36 -07:00
2013-07-16 10:05:51 +02:00
start_time = hrt_absolute_time ( ) ;
2012-12-23 17:20:53 -08:00
2012-08-24 00:01:23 +02:00
while ( ! thread_should_exit ) {
2012-08-04 15:12:36 -07:00
2013-11-05 19:56:33 +01:00
if ( mavlink_fd < 0 & & counter % ( 1000000 / MAVLINK_OPEN_INTERVAL ) = = 0 ) {
/* try to open the mavlink log device every once in a while */
mavlink_fd = open ( MAVLINK_LOG_DEVICE , 0 ) ;
}
2013-06-09 14:09:09 +02:00
/* update parameters */
2013-07-31 20:58:27 +04:00
orb_check ( param_changed_sub , & updated ) ;
2013-06-09 14:09:09 +02:00
2013-07-31 20:58:27 +04:00
if ( updated | | param_init_forced ) {
2013-06-09 14:09:09 +02:00
param_init_forced = false ;
/* parameters changed */
orb_copy ( ORB_ID ( parameter_update ) , param_changed_sub , & param_changed ) ;
/* update parameters */
2013-07-15 22:15:15 +02:00
if ( ! armed . armed ) {
2013-07-28 23:12:16 +04:00
if ( param_get ( _param_sys_type , & ( status . system_type ) ) ! = OK ) {
2013-07-16 10:05:51 +02:00
warnx ( " failed getting new system type " ) ;
2013-06-09 14:09:09 +02:00
}
/* disable manual override for all systems that rely on electronic stabilization */
2013-07-28 23:12:16 +04:00
if ( status . system_type = = VEHICLE_TYPE_COAXIAL | |
status . system_type = = VEHICLE_TYPE_HELICOPTER | |
status . system_type = = VEHICLE_TYPE_TRICOPTER | |
status . system_type = = VEHICLE_TYPE_QUADROTOR | |
status . system_type = = VEHICLE_TYPE_HEXAROTOR | |
status . system_type = = VEHICLE_TYPE_OCTOROTOR ) {
status . is_rotary_wing = true ;
2013-06-09 14:09:09 +02:00
} else {
2013-07-28 23:12:16 +04:00
status . is_rotary_wing = false ;
2013-06-09 14:09:09 +02:00
}
/* check and update system / component ID */
2013-07-28 23:12:16 +04:00
param_get ( _param_system_id , & ( status . system_id ) ) ;
param_get ( _param_component_id , & ( status . component_id ) ) ;
2013-07-31 20:58:27 +04:00
status_changed = true ;
2013-08-25 16:33:14 +02:00
2013-08-30 10:11:24 +02:00
/* re-check RC calibration */
2013-10-22 21:01:30 +02:00
rc_calibration_ok = ( OK = = rc_calibration_check ( mavlink_fd ) ) ;
2013-08-30 10:11:24 +02:00
/* navigation parameters */
param_get ( _param_takeoff_alt , & takeoff_alt ) ;
2013-06-09 14:09:09 +02:00
}
}
2013-07-31 20:58:27 +04:00
orb_check ( sp_man_sub , & updated ) ;
2013-01-11 07:42:09 +01:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2012-09-26 21:30:03 +02:00
orb_copy ( ORB_ID ( manual_control_setpoint ) , sp_man_sub , & sp_man ) ;
}
2013-07-31 20:58:27 +04:00
orb_check ( sp_offboard_sub , & updated ) ;
2013-01-11 07:42:09 +01:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2012-09-26 21:30:03 +02:00
orb_copy ( ORB_ID ( offboard_control_setpoint ) , sp_offboard_sub , & sp_offboard ) ;
}
2012-12-19 11:34:51 +01:00
2013-07-31 20:58:27 +04:00
orb_check ( sensor_sub , & updated ) ;
2013-01-11 07:42:09 +01:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2012-12-19 11:34:51 +01:00
orb_copy ( ORB_ID ( sensor_combined ) , sensor_sub , & sensors ) ;
}
2012-08-04 15:12:36 -07:00
2013-07-31 20:58:27 +04:00
orb_check ( diff_pres_sub , & updated ) ;
2013-02-25 15:48:16 +01:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2013-04-19 18:28:06 +02:00
orb_copy ( ORB_ID ( differential_pressure ) , diff_pres_sub , & diff_pres ) ;
2013-02-25 15:48:16 +01:00
}
2013-08-17 12:37:41 +02:00
check_valid ( diff_pres . timestamp , DIFFPRESS_TIMEOUT , true , & ( status . condition_airspeed_valid ) , & status_changed ) ;
2013-08-16 23:36:49 +02:00
2013-06-25 13:15:38 +02:00
/* update safety topic */
2013-07-31 20:58:27 +04:00
orb_check ( safety_sub , & updated ) ;
2013-06-25 13:15:38 +02:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2013-07-15 22:15:15 +02:00
orb_copy ( ORB_ID ( safety ) , safety_sub , & safety ) ;
2013-11-01 09:05:28 +01:00
// XXX this would be the right approach to do it, but do we *WANT* this?
// /* disarm if safety is now on and still armed */
// if (safety.safety_switch_available && !safety.safety_off) {
2013-12-29 12:16:49 +04:00
// (void)arming_state_transition(&status, &safety, ARMING_STATE_STANDBY, &armed);
2013-11-01 09:05:28 +01:00
// }
2013-06-25 13:15:38 +02:00
}
2012-12-13 10:23:02 +01:00
/* update global position estimate */
2013-07-31 20:58:27 +04:00
orb_check ( global_position_sub , & updated ) ;
2013-01-11 07:42:09 +01:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2012-12-13 10:23:02 +01:00
/* position changed */
orb_copy ( ORB_ID ( vehicle_global_position ) , global_position_sub , & global_position ) ;
}
2013-08-17 12:37:41 +02:00
/* update condition_global_position_valid */
check_valid ( global_position . timestamp , POSITION_TIMEOUT , global_position . valid , & ( status . condition_global_position_valid ) , & status_changed ) ;
2013-08-16 23:36:49 +02:00
2012-12-13 10:23:02 +01:00
/* update local position estimate */
2013-07-31 20:58:27 +04:00
orb_check ( local_position_sub , & updated ) ;
2013-01-11 07:42:09 +01:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2012-12-13 10:23:02 +01:00
/* position changed */
orb_copy ( ORB_ID ( vehicle_local_position ) , local_position_sub , & local_position ) ;
}
2013-08-18 23:05:26 +02:00
/* update condition_local_position_valid and condition_local_altitude_valid */
check_valid ( local_position . timestamp , POSITION_TIMEOUT , local_position . xy_valid , & ( status . condition_local_position_valid ) , & status_changed ) ;
check_valid ( local_position . timestamp , POSITION_TIMEOUT , local_position . z_valid , & ( status . condition_local_altitude_valid ) , & status_changed ) ;
2013-08-27 23:08:00 +02:00
2013-11-26 13:47:37 +01:00
if ( status . is_rotary_wing & & status . condition_local_altitude_valid ) {
2013-08-20 12:17:15 +02:00
if ( status . condition_landed ! = local_position . landed ) {
status . condition_landed = local_position . landed ;
status_changed = true ;
2013-08-27 23:08:00 +02:00
2013-08-20 12:17:15 +02:00
if ( status . condition_landed ) {
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: LANDED " ) ;
2013-08-27 23:08:00 +02:00
2013-08-20 12:17:15 +02:00
} else {
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: IN AIR " ) ;
2013-08-20 12:17:15 +02:00
}
}
}
2013-03-11 10:39:57 -07:00
2013-01-12 00:38:49 +01:00
/* update battery status */
2013-07-31 20:58:27 +04:00
orb_check ( battery_sub , & updated ) ;
2013-07-28 23:12:16 +04:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2013-01-01 13:30:24 +01:00
orb_copy ( ORB_ID ( battery_status ) , battery_sub , & battery ) ;
2013-11-11 22:02:55 +04:00
/* only consider battery voltage if system has been running 2s and battery voltage is valid */
if ( hrt_absolute_time ( ) > start_time + 2000000 & & battery . voltage_filtered_v > 0.0f ) {
status . battery_voltage = battery . voltage_filtered_v ;
2013-11-08 21:30:10 +04:00
status . battery_current = battery . current_a ;
2013-08-15 17:27:29 +02:00
status . condition_battery_voltage_valid = true ;
2013-11-11 22:02:55 +04:00
status . battery_remaining = battery_remaining_estimate_voltage ( battery . voltage_filtered_v , battery . discharged_mah ) ;
2013-08-15 17:27:29 +02:00
}
2012-09-05 18:05:11 +02:00
}
2012-08-04 15:12:36 -07:00
2013-07-16 09:24:21 +02:00
/* update subsystem */
2013-07-31 20:58:27 +04:00
orb_check ( subsys_sub , & updated ) ;
2013-07-28 23:12:16 +04:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2013-07-16 09:24:21 +02:00
orb_copy ( ORB_ID ( subsystem_info ) , subsys_sub , & info ) ;
2013-07-31 20:58:27 +04:00
warnx ( " subsystem changed: %d \n " , ( int ) info . subsystem_type ) ;
2013-07-16 09:24:21 +02:00
/* mark / unmark as present */
if ( info . present ) {
2013-07-28 23:12:16 +04:00
status . onboard_control_sensors_present | = info . subsystem_type ;
2013-07-16 09:24:21 +02:00
} else {
2013-07-28 23:12:16 +04:00
status . onboard_control_sensors_present & = ~ info . subsystem_type ;
2013-07-16 09:24:21 +02:00
}
/* mark / unmark as enabled */
if ( info . enabled ) {
2013-07-28 23:12:16 +04:00
status . onboard_control_sensors_enabled | = info . subsystem_type ;
2013-07-16 09:24:21 +02:00
} else {
2013-07-28 23:12:16 +04:00
status . onboard_control_sensors_enabled & = ~ info . subsystem_type ;
2013-07-16 09:24:21 +02:00
}
/* mark / unmark as ok */
if ( info . ok ) {
2013-07-28 23:12:16 +04:00
status . onboard_control_sensors_health | = info . subsystem_type ;
2013-07-16 09:24:21 +02:00
} else {
2013-07-28 23:12:16 +04:00
status . onboard_control_sensors_health & = ~ info . subsystem_type ;
2013-07-16 09:24:21 +02:00
}
2012-08-04 15:12:36 -07:00
2013-07-31 20:58:27 +04:00
status_changed = true ;
2013-02-16 13:40:09 -08:00
}
2012-08-04 15:12:36 -07:00
2013-02-16 13:40:09 -08:00
if ( counter % ( 1000000 / COMMANDER_MONITORING_INTERVAL ) = = 0 ) {
/* compute system load */
uint64_t interval_runtime = system_load . tasks [ 0 ] . total_runtime - last_idle_time ;
2012-08-04 15:12:36 -07:00
2013-02-16 13:40:09 -08:00
if ( last_idle_time > 0 )
2013-08-16 10:17:57 +02:00
status . load = 1.0f - ( ( float ) interval_runtime / 1e6 f ) ; //system load is time spent in non-idle
2012-08-04 15:12:36 -07:00
2013-02-16 13:40:09 -08:00
last_idle_time = system_load . tasks [ 0 ] . total_runtime ;
2013-08-17 15:47:42 +02:00
/* check if board is connected via USB */
2013-10-21 20:07:47 +02:00
//struct stat statbuf;
2013-08-17 15:47:42 +02:00
//on_usb_power = (stat("/dev/ttyACM0", &statbuf) == 0);
2012-08-04 15:12:36 -07:00
}
2012-09-05 18:05:11 +02:00
/* if battery voltage is getting lower, warn using buzzer, etc. */
2013-08-16 18:05:59 +02:00
if ( status . condition_battery_voltage_valid & & status . battery_remaining < 0.25f & & ! low_battery_voltage_actions_done ) {
2013-11-11 22:02:55 +04:00
low_battery_voltage_actions_done = true ;
mavlink_log_critical ( mavlink_fd , " #audio: WARNING: LOW BATTERY " ) ;
status . battery_warning = VEHICLE_BATTERY_WARNING_LOW ;
status_changed = true ;
battery_tune_played = false ;
2012-09-05 18:05:11 +02:00
2013-07-31 20:58:27 +04:00
} else if ( status . condition_battery_voltage_valid & & status . battery_remaining < 0.1f & & ! critical_battery_voltage_actions_done & & low_battery_voltage_actions_done ) {
/* critical battery voltage, this is rather an emergency, change state machine */
2013-11-11 22:02:55 +04:00
critical_battery_voltage_actions_done = true ;
mavlink_log_critical ( mavlink_fd , " #audio: EMERGENCY: CRITICAL BATTERY " ) ;
status . battery_warning = VEHICLE_BATTERY_WARNING_CRITICAL ;
battery_tune_played = false ;
2013-08-16 09:27:05 +02:00
2013-11-11 22:02:55 +04:00
if ( armed . armed ) {
2014-01-14 15:45:49 +01:00
arming_state_transition ( & status , & safety , ARMING_STATE_ARMED_ERROR , & armed ) ;
2013-10-21 20:07:47 +02:00
2013-11-11 22:02:55 +04:00
} else {
2014-01-14 15:45:49 +01:00
arming_state_transition ( & status , & safety , ARMING_STATE_STANDBY_ERROR , & armed ) ;
2012-09-05 18:05:11 +02:00
}
2013-11-11 22:02:55 +04:00
status_changed = true ;
2012-09-05 18:05:11 +02:00
}
/* End battery voltage check */
2013-02-18 16:35:34 -08:00
/* If in INIT state, try to proceed to STANDBY state */
2013-07-31 20:58:27 +04:00
if ( status . arming_state = = ARMING_STATE_INIT & & low_prio_task = = LOW_PRIO_TASK_NONE ) {
2013-03-26 10:44:49 -07:00
// XXX check for sensors
2013-12-29 12:16:49 +04:00
arming_state_transition ( & status , & safety , ARMING_STATE_STANDBY , & armed ) ;
2013-07-28 23:12:16 +04:00
2013-02-18 16:35:34 -08:00
} else {
// XXX: Add emergency stuff if sensors are lost
}
2012-12-19 14:20:40 +01:00
/*
* Check for valid position information .
*
* If the system has a valid position source from an onboard
* position estimator , it is safe to operate it autonomously .
* The flag_vector_flight_mode_ok flag indicates that a minimum
* set of position measurements is available .
*/
2013-07-31 20:58:27 +04:00
orb_check ( gps_sub , & updated ) ;
2012-12-13 10:23:02 +01:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2013-01-19 14:46:26 +01:00
orb_copy ( ORB_ID ( vehicle_gps_position ) , gps_sub , & gps_position ) ;
2013-07-31 20:58:27 +04:00
/* check if GPS fix is ok */
2013-02-06 13:50:32 -08:00
float hdop_threshold_m = 4.0f ;
float vdop_threshold_m = 8.0f ;
2013-01-19 14:46:26 +01:00
/*
* If horizontal dilution of precision ( hdop / eph )
* and vertical diluation of precision ( vdop / epv )
* are below a certain threshold ( e . g . 4 m ) , AND
* home position is not yet set AND the last GPS
* GPS measurement is not older than two seconds AND
* the system is currently not armed , set home
* position to the current position .
*/
2013-02-06 13:50:32 -08:00
2013-08-17 12:37:41 +02:00
if ( ! home_position_set & & gps_position . fix_type > = 3 & &
2013-08-27 23:08:00 +02:00
( gps_position . eph_m < hdop_threshold_m ) & & ( gps_position . epv_m < vdop_threshold_m ) & & // XXX note that vdop is 0 for mtk
2013-12-27 11:07:45 +01:00
( hrt_absolute_time ( ) < gps_position . timestamp_position + POSITION_TIMEOUT ) & & ! armed . armed
& & global_position . valid ) {
2013-01-19 14:46:26 +01:00
/* copy position data to uORB home message, store it locally as well */
2014-01-24 00:06:10 +01:00
home . lat = global_position . lat ;
home . lon = global_position . lon ;
home . alt = global_position . alt ;
2013-01-19 14:46:26 +01:00
2014-01-24 00:06:10 +01:00
warnx ( " home: lat = %.7f, lon = %.7f, alt = %.4f " , home . lat , home . lon , ( double ) home . alt ) ;
mavlink_log_info ( mavlink_fd , " [cmd] home: %.7f, %.7f, %.4f " , home . lat , home . lon , ( double ) home . alt ) ;
2013-07-31 20:58:27 +04:00
2013-01-19 14:46:26 +01:00
/* announce new home position */
if ( home_pub > 0 ) {
orb_publish ( ORB_ID ( home_position ) , home_pub , & home ) ;
2013-07-28 23:12:16 +04:00
2013-01-19 14:46:26 +01:00
} else {
home_pub = orb_advertise ( ORB_ID ( home_position ) , & home ) ;
}
2012-08-04 15:12:36 -07:00
2013-01-19 17:03:35 +01:00
/* mark home position as set */
home_position_set = true ;
2013-03-25 14:53:54 -07:00
tune_positive ( ) ;
2013-01-19 14:46:26 +01:00
}
}
2012-08-04 15:12:36 -07:00
2012-09-21 12:55:41 +02:00
/* ignore RC signals if in offboard control mode */
2013-07-28 23:12:16 +04:00
if ( ! status . offboard_control_signal_found_once & & sp_man . timestamp ! = 0 ) {
2013-07-31 20:58:27 +04:00
/* start RC input check */
2013-08-17 12:37:41 +02:00
if ( hrt_absolute_time ( ) < sp_man . timestamp + RC_TIMEOUT ) {
2013-07-28 23:12:16 +04:00
/* handle the case where RC signal was regained */
if ( ! status . rc_signal_found_once ) {
status . rc_signal_found_once = true ;
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: detected RC signal first time " ) ;
2013-07-31 20:58:27 +04:00
status_changed = true ;
2013-02-20 10:38:06 -08:00
} else {
2013-07-28 23:12:16 +04:00
if ( status . rc_signal_lost ) {
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: RC signal regained " ) ;
2013-07-31 20:58:27 +04:00
status_changed = true ;
2013-07-28 23:12:16 +04:00
}
2013-02-20 10:38:06 -08:00
}
2012-12-27 18:27:08 +01:00
2013-07-28 23:12:16 +04:00
status . rc_signal_lost = false ;
2012-12-29 11:00:15 +01:00
2013-07-28 23:12:16 +04:00
transition_result_t res ; // store all transitions results here
2012-12-27 18:27:08 +01:00
2013-07-28 23:12:16 +04:00
/* arm/disarm by RC */
res = TRANSITION_NOT_CHANGED ;
2012-12-27 18:27:08 +01:00
2013-08-24 20:31:01 +02:00
/* check if left stick is in lower left position and we are in MANUAL or AUTO_READY mode or (ASSISTED mode and landed) -> disarm
2013-07-28 23:12:16 +04:00
* do it only for rotary wings */
if ( status . is_rotary_wing & &
( status . arming_state = = ARMING_STATE_ARMED | | status . arming_state = = ARMING_STATE_ARMED_ERROR ) & &
2013-12-29 12:16:49 +04:00
( status . main_state = = MAIN_STATE_MANUAL | | status . condition_landed ) & &
sp_man . yaw < - STICK_ON_OFF_LIMIT & & sp_man . throttle < STICK_THRUST_RANGE * 0.1f ) {
2013-08-24 20:31:01 +02:00
if ( stick_off_counter > STICK_ON_OFF_COUNTER_LIMIT ) {
/* disarm to STANDBY if ARMED or to STANDBY_ERROR if ARMED_ERROR */
arming_state_t new_arming_state = ( status . arming_state = = ARMING_STATE_ARMED ? ARMING_STATE_STANDBY : ARMING_STATE_STANDBY_ERROR ) ;
2013-12-29 12:16:49 +04:00
res = arming_state_transition ( & status , & safety , new_arming_state , & armed ) ;
2013-08-24 20:31:01 +02:00
stick_off_counter = 0 ;
2013-07-31 20:58:27 +04:00
2013-07-28 23:12:16 +04:00
} else {
2013-08-24 20:31:01 +02:00
stick_off_counter + + ;
2013-07-28 23:12:16 +04:00
}
2013-08-27 23:08:00 +02:00
2013-08-24 20:31:01 +02:00
} else {
stick_off_counter = 0 ;
2013-07-22 21:48:21 +04:00
}
2013-08-24 20:31:01 +02:00
/* check if left stick is in lower right position and we're in MANUAL mode -> arm */
2013-07-28 23:12:16 +04:00
if ( status . arming_state = = ARMING_STATE_STANDBY & &
2013-08-24 20:31:01 +02:00
sp_man . yaw > STICK_ON_OFF_LIMIT & & sp_man . throttle < STICK_THRUST_RANGE * 0.1f ) {
if ( stick_on_counter > STICK_ON_OFF_COUNTER_LIMIT ) {
2013-09-14 08:55:45 +02:00
if ( safety . safety_switch_available & & ! safety . safety_off ) {
print_reject_arm ( " NOT ARMING: Press safety switch first. " ) ;
} else if ( status . main_state ! = MAIN_STATE_MANUAL ) {
print_reject_arm ( " NOT ARMING: Switch to MANUAL mode first. " ) ;
} else {
2013-12-29 12:16:49 +04:00
res = arming_state_transition ( & status , & safety , ARMING_STATE_ARMED , & armed ) ;
2013-09-14 08:55:45 +02:00
}
2013-08-24 20:31:01 +02:00
stick_on_counter = 0 ;
2013-07-31 20:58:27 +04:00
2013-07-28 23:12:16 +04:00
} else {
2013-08-24 20:31:01 +02:00
stick_on_counter + + ;
2013-07-28 23:12:16 +04:00
}
2013-08-24 20:31:01 +02:00
} else {
stick_on_counter = 0 ;
2013-07-28 23:12:16 +04:00
}
2013-02-16 13:40:09 -08:00
2013-07-28 23:12:16 +04:00
if ( res = = TRANSITION_CHANGED ) {
if ( status . arming_state = = ARMING_STATE_ARMED ) {
mavlink_log_info ( mavlink_fd , " [cmd] ARMED by RC " ) ;
2013-02-16 13:40:09 -08:00
2013-07-28 23:12:16 +04:00
} else {
mavlink_log_info ( mavlink_fd , " [cmd] DISARMED by RC " ) ;
}
2013-08-16 23:36:49 +02:00
2013-08-16 09:23:39 +02:00
} else if ( res = = TRANSITION_DENIED ) {
2013-09-14 08:55:45 +02:00
warnx ( " ERROR: main denied: arm %d main %d mode_sw %d " , status . arming_state , status . main_state , status . mode_switch ) ;
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: ERROR: main denied: arm %d main %d mode_sw %d " , status . arming_state , status . main_state , status . mode_switch ) ;
2013-02-20 10:38:06 -08:00
}
2013-07-28 23:12:16 +04:00
/* fill current_status according to mode switches */
check_mode_switches ( & sp_man , & status ) ;
2013-02-16 13:40:09 -08:00
2013-07-28 23:12:16 +04:00
/* evaluate the main state machine */
res = check_main_state_machine ( & status ) ;
2013-07-31 20:58:27 +04:00
if ( res = = TRANSITION_CHANGED ) {
2013-08-27 23:08:00 +02:00
//mavlink_log_info(mavlink_fd, "[cmd] main state: %d", status.main_state);
2013-07-31 20:58:27 +04:00
tune_positive ( ) ;
2012-08-04 15:12:36 -07:00
2013-07-31 20:58:27 +04:00
} else if ( res = = TRANSITION_DENIED ) {
/* DENIED here indicates bug in the commander */
warnx ( " ERROR: main denied: arm %d main %d mode_sw %d " , status . arming_state , status . main_state , status . mode_switch ) ;
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: ERROR: main denied: arm %d main %d mode_sw %d " , status . arming_state , status . main_state , status . mode_switch ) ;
2013-07-28 23:12:16 +04:00
}
2012-08-08 18:47:46 +02:00
} else {
2013-08-27 23:08:00 +02:00
if ( ! status . rc_signal_lost ) {
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: CRITICAL: RC SIGNAL LOST " ) ;
2013-07-28 23:12:16 +04:00
status . rc_signal_lost = true ;
2013-07-31 20:58:27 +04:00
status_changed = true ;
2014-01-21 15:26:51 +01:00
}
if ( status . main_state ! = MAIN_STATE_AUTO & & armed . armed ) {
transition_result_t res = main_state_transition ( & status , MAIN_STATE_AUTO ) ;
if ( res = = TRANSITION_CHANGED ) {
mavlink_log_critical ( mavlink_fd , " #audio: failsafe, switching to RTL mode " ) ;
status . set_nav_state = NAV_STATE_RTL ;
status . set_nav_state_timestamp = hrt_absolute_time ( ) ;
} else if ( status . main_state ! = MAIN_STATE_SEATBELT ) {
res = main_state_transition ( & status , MAIN_STATE_SEATBELT ) ;
2014-01-18 00:15:34 +01:00
if ( res = = TRANSITION_CHANGED ) {
2014-01-21 15:26:51 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: failsafe, switching to SEATBELT mode " ) ;
2014-01-18 00:15:34 +01:00
}
}
2012-09-21 12:55:41 +02:00
}
2012-08-08 18:47:46 +02:00
}
2012-08-04 15:12:36 -07:00
}
2013-12-14 11:03:02 +01:00
/* Flight termination in manual mode if assisted switch is on easy position //xxx hack! */
if ( armed . armed & & status . main_state = = MAIN_STATE_MANUAL & & sp_man . assisted_switch > STICK_ON_OFF_LIMIT ) {
2013-12-29 12:16:49 +04:00
transition_result_t flighttermination_res = flighttermination_state_transition ( & status , FLIGHTTERMINATION_STATE_ON ) ;
2013-12-14 11:03:02 +01:00
if ( flighttermination_res = = TRANSITION_CHANGED ) {
tune_positive ( ) ;
}
} else {
2013-12-29 12:16:49 +04:00
flighttermination_state_transition ( & status , FLIGHTTERMINATION_STATE_OFF ) ;
2013-12-14 11:03:02 +01:00
}
2013-09-22 14:58:06 +02:00
/* handle commands last, as the system needs to be updated to handle them */
orb_check ( cmd_sub , & updated ) ;
if ( updated ) {
/* got command */
orb_copy ( ORB_ID ( vehicle_command ) , cmd_sub , & cmd ) ;
/* handle it */
2013-12-29 22:38:22 +04:00
if ( handle_command ( & status , & safety , & cmd , & armed ) )
status_changed = true ;
2013-07-31 20:58:27 +04:00
}
2013-06-25 13:15:38 +02:00
2013-07-31 20:58:27 +04:00
/* check which state machines for changes, clear "changed" flag */
bool arming_state_changed = check_arming_state_changed ( ) ;
bool main_state_changed = check_main_state_changed ( ) ;
2013-12-08 16:52:41 +01:00
bool flighttermination_state_changed = check_flighttermination_state_changed ( ) ;
2013-06-25 13:15:38 +02:00
2013-08-17 12:37:41 +02:00
hrt_abstime t1 = hrt_absolute_time ( ) ;
2013-12-29 12:16:49 +04:00
if ( arming_state_changed | | main_state_changed ) {
mavlink_log_info ( mavlink_fd , " [cmd] state: arm %d, main %d " , status . arming_state , status . main_state ) ;
2013-10-07 22:16:57 +02:00
status_changed = true ;
2013-07-31 20:58:27 +04:00
}
2013-03-26 10:44:49 -07:00
2013-08-18 12:42:24 +02:00
/* publish states (armed, control mode, vehicle status) at least with 5 Hz */
if ( counter % ( 200000 / COMMANDER_MONITORING_INTERVAL ) = = 0 | | status_changed ) {
2013-08-17 12:37:41 +02:00
status . timestamp = t1 ;
2013-07-28 23:12:16 +04:00
orb_publish ( ORB_ID ( vehicle_status ) , status_pub , & status ) ;
2013-08-19 09:53:00 +02:00
armed . timestamp = t1 ;
2013-08-18 12:42:24 +02:00
orb_publish ( ORB_ID ( actuator_armed ) , armed_pub , & armed ) ;
2012-08-16 15:49:56 +02:00
}
2013-07-31 20:58:27 +04:00
/* play arming and battery warning tunes */
2013-11-01 09:05:28 +01:00
if ( ! arm_tune_played & & armed . armed & & ( ! safety . safety_switch_available | | ( safety . safety_switch_available & & safety . safety_off ) ) ) {
2013-07-31 20:58:27 +04:00
/* play tune when armed */
2013-06-25 16:30:35 +02:00
if ( tune_arm ( ) = = OK )
2013-06-25 14:45:27 +02:00
arm_tune_played = true ;
2013-06-25 13:15:38 +02:00
2013-08-29 16:41:59 +02:00
} else if ( status . battery_warning = = VEHICLE_BATTERY_WARNING_LOW ) {
2013-07-31 20:58:27 +04:00
/* play tune on battery warning */
if ( tune_low_bat ( ) = = OK )
2013-06-25 14:45:27 +02:00
battery_tune_played = true ;
2013-07-28 23:12:16 +04:00
2013-08-29 16:41:59 +02:00
} else if ( status . battery_warning = = VEHICLE_BATTERY_WARNING_CRITICAL ) {
2013-07-31 20:58:27 +04:00
/* play tune on battery critical */
if ( tune_critical_bat ( ) = = OK )
2013-06-25 14:45:27 +02:00
battery_tune_played = true ;
2013-07-28 23:12:16 +04:00
} else if ( battery_tune_played ) {
2013-06-25 16:30:35 +02:00
tune_stop ( ) ;
2013-06-25 13:15:38 +02:00
battery_tune_played = false ;
}
/* reset arm_tune_played when disarmed */
2013-11-01 09:05:28 +01:00
if ( status . arming_state ! = ARMING_STATE_ARMED | | ( safety . safety_switch_available & & ! safety . safety_off ) ) {
2013-06-25 13:15:38 +02:00
arm_tune_played = false ;
}
2012-08-04 15:12:36 -07:00
fflush ( stdout ) ;
counter + + ;
2013-08-16 18:05:59 +02:00
2013-09-19 19:58:41 +02:00
int blink_state = blink_msg_state ( ) ;
2013-10-21 20:07:47 +02:00
2013-09-19 19:58:41 +02:00
if ( blink_state > 0 ) {
/* blinking LED message, don't touch LEDs */
if ( blink_state = = 2 ) {
/* blinking LED message completed, restore normal state */
control_status_leds ( & status , & armed , true ) ;
}
2013-10-21 20:07:47 +02:00
2013-09-19 19:58:41 +02:00
} else {
/* normal state */
control_status_leds ( & status , & armed , status_changed ) ;
}
status_changed = false ;
2013-08-16 18:05:59 +02:00
2012-08-04 15:12:36 -07:00
usleep ( COMMANDER_MONITORING_INTERVAL ) ;
}
/* wait for threads to complete */
2013-09-08 20:05:15 +02:00
ret = pthread_join ( commander_low_prio_thread , NULL ) ;
2013-09-14 08:55:45 +02:00
2013-09-08 20:05:15 +02:00
if ( ret ) {
2013-10-21 20:07:47 +02:00
warn ( " join failed: %d " , ret ) ;
2013-09-08 20:05:15 +02:00
}
rgbled_set_mode ( RGBLED_MODE_OFF ) ;
2012-08-04 15:12:36 -07:00
/* close fds */
led_deinit ( ) ;
buzzer_deinit ( ) ;
2012-09-21 12:55:41 +02:00
close ( sp_man_sub ) ;
close ( sp_offboard_sub ) ;
2013-07-16 10:05:51 +02:00
close ( local_position_sub ) ;
2012-12-13 10:23:02 +01:00
close ( global_position_sub ) ;
2013-07-16 10:05:51 +02:00
close ( gps_sub ) ;
2012-08-24 00:01:23 +02:00
close ( sensor_sub ) ;
2013-07-15 22:15:15 +02:00
close ( safety_sub ) ;
2012-10-15 08:52:41 +02:00
close ( cmd_sub ) ;
2013-07-16 09:24:21 +02:00
close ( subsys_sub ) ;
2013-07-16 10:05:51 +02:00
close ( diff_pres_sub ) ;
close ( param_changed_sub ) ;
close ( battery_sub ) ;
2012-08-24 00:01:23 +02:00
2012-08-20 23:52:13 +02:00
thread_running = false ;
2012-08-04 15:12:36 -07:00
return 0 ;
}
2013-03-25 14:53:54 -07:00
2013-08-19 09:53:00 +02:00
void
check_valid ( hrt_abstime timestamp , hrt_abstime timeout , bool valid_in , bool * valid_out , bool * changed )
{
hrt_abstime t = hrt_absolute_time ( ) ;
bool valid_new = ( t < timestamp + timeout & & t > timeout & & valid_in ) ;
if ( * valid_out ! = valid_new ) {
* valid_out = valid_new ;
* changed = true ;
}
}
2013-07-31 20:58:27 +04:00
void
2013-11-01 09:05:28 +01:00
control_status_leds ( vehicle_status_s * status , const actuator_armed_s * actuator_armed , bool changed )
2013-07-31 20:58:27 +04:00
{
2013-09-19 19:58:41 +02:00
/* driving rgbled */
if ( changed ) {
bool set_normal_color = false ;
2013-10-21 20:07:47 +02:00
2013-09-19 19:58:41 +02:00
/* set mode */
if ( status - > arming_state = = ARMING_STATE_ARMED ) {
rgbled_set_mode ( RGBLED_MODE_ON ) ;
set_normal_color = true ;
} else if ( status - > arming_state = = ARMING_STATE_ARMED_ERROR ) {
rgbled_set_mode ( RGBLED_MODE_BLINK_FAST ) ;
rgbled_set_color ( RGBLED_COLOR_RED ) ;
} else if ( status - > arming_state = = ARMING_STATE_STANDBY ) {
rgbled_set_mode ( RGBLED_MODE_BREATHE ) ;
set_normal_color = true ;
} else { // STANDBY_ERROR and other states
rgbled_set_mode ( RGBLED_MODE_BLINK_NORMAL ) ;
rgbled_set_color ( RGBLED_COLOR_RED ) ;
}
if ( set_normal_color ) {
/* set color */
if ( status - > battery_warning ! = VEHICLE_BATTERY_WARNING_NONE ) {
if ( status - > battery_warning = = VEHICLE_BATTERY_WARNING_LOW ) {
rgbled_set_color ( RGBLED_COLOR_AMBER ) ;
}
2013-10-21 20:07:47 +02:00
2013-09-19 19:58:41 +02:00
/* VEHICLE_BATTERY_WARNING_CRITICAL handled as ARMING_STATE_ARMED_ERROR / ARMING_STATE_STANDBY_ERROR */
} else {
if ( status - > condition_local_position_valid ) {
rgbled_set_color ( RGBLED_COLOR_GREEN ) ;
} else {
rgbled_set_color ( RGBLED_COLOR_BLUE ) ;
}
}
}
}
2013-08-16 18:05:59 +02:00
# ifdef CONFIG_ARCH_BOARD_PX4FMU_V1
2013-08-27 23:08:00 +02:00
2013-08-16 18:05:59 +02:00
/* this runs at around 20Hz, full cycle is 16 ticks = 10/16Hz */
2013-11-01 09:05:28 +01:00
if ( actuator_armed - > armed ) {
2013-08-16 18:05:59 +02:00
/* armed, solid */
led_on ( LED_BLUE ) ;
2013-11-01 09:05:28 +01:00
} else if ( actuator_armed - > ready_to_arm ) {
2013-08-16 18:05:59 +02:00
/* ready to arm, blink at 1Hz */
if ( leds_counter % 20 = = 0 )
led_toggle ( LED_BLUE ) ;
2013-08-27 23:08:00 +02:00
2013-08-16 18:05:59 +02:00
} else {
/* not ready to arm, blink at 10Hz */
if ( leds_counter % 2 = = 0 )
led_toggle ( LED_BLUE ) ;
}
2013-08-27 23:08:00 +02:00
2013-08-16 18:05:59 +02:00
# endif
/* give system warnings on error LED, XXX maybe add memory usage warning too */
if ( status - > load > 0.95f ) {
if ( leds_counter % 2 = = 0 )
led_toggle ( LED_AMBER ) ;
2013-08-27 23:08:00 +02:00
2013-08-16 18:05:59 +02:00
} else {
led_off ( LED_AMBER ) ;
2013-07-31 20:58:27 +04:00
}
leds_counter + + ;
}
2013-07-28 23:12:16 +04:00
void
check_mode_switches ( struct manual_control_setpoint_s * sp_man , struct vehicle_status_s * current_status )
{
/* main mode switch */
if ( ! isfinite ( sp_man - > mode_switch ) ) {
warnx ( " mode sw not finite " ) ;
current_status - > mode_switch = MODE_SWITCH_MANUAL ;
} else if ( sp_man - > mode_switch > STICK_ON_OFF_LIMIT ) {
current_status - > mode_switch = MODE_SWITCH_AUTO ;
2013-07-31 20:58:27 +04:00
} else if ( sp_man - > mode_switch < - STICK_ON_OFF_LIMIT ) {
2013-07-28 23:12:16 +04:00
current_status - > mode_switch = MODE_SWITCH_MANUAL ;
2013-07-31 20:58:27 +04:00
} else {
current_status - > mode_switch = MODE_SWITCH_ASSISTED ;
2013-07-28 23:12:16 +04:00
}
2013-12-30 14:04:24 +04:00
/* return switch */
2013-07-28 23:12:16 +04:00
if ( ! isfinite ( sp_man - > return_switch ) ) {
current_status - > return_switch = RETURN_SWITCH_NONE ;
} else if ( sp_man - > return_switch > STICK_ON_OFF_LIMIT ) {
current_status - > return_switch = RETURN_SWITCH_RETURN ;
} else {
2013-12-30 14:04:24 +04:00
current_status - > return_switch = RETURN_SWITCH_NORMAL ;
2013-07-28 23:12:16 +04:00
}
/* assisted switch */
if ( ! isfinite ( sp_man - > assisted_switch ) ) {
current_status - > assisted_switch = ASSISTED_SWITCH_SEATBELT ;
} else if ( sp_man - > assisted_switch > STICK_ON_OFF_LIMIT ) {
current_status - > assisted_switch = ASSISTED_SWITCH_EASY ;
} else {
current_status - > assisted_switch = ASSISTED_SWITCH_SEATBELT ;
}
/* mission switch */
if ( ! isfinite ( sp_man - > mission_switch ) ) {
2013-12-30 14:04:24 +04:00
current_status - > mission_switch = MISSION_SWITCH_NONE ;
2013-07-28 23:12:16 +04:00
} else if ( sp_man - > mission_switch > STICK_ON_OFF_LIMIT ) {
2013-12-30 14:04:24 +04:00
current_status - > mission_switch = MISSION_SWITCH_LOITER ;
2013-07-28 23:12:16 +04:00
} else {
current_status - > mission_switch = MISSION_SWITCH_MISSION ;
}
}
transition_result_t
check_main_state_machine ( struct vehicle_status_s * current_status )
{
/* evaluate the main state machine */
transition_result_t res = TRANSITION_DENIED ;
switch ( current_status - > mode_switch ) {
case MODE_SWITCH_MANUAL :
2013-07-31 20:58:27 +04:00
res = main_state_transition ( current_status , MAIN_STATE_MANUAL ) ;
2013-07-28 23:12:16 +04:00
// TRANSITION_DENIED is not possible here
break ;
case MODE_SWITCH_ASSISTED :
if ( current_status - > assisted_switch = = ASSISTED_SWITCH_EASY ) {
2013-07-31 20:58:27 +04:00
res = main_state_transition ( current_status , MAIN_STATE_EASY ) ;
2013-07-28 23:12:16 +04:00
if ( res ! = TRANSITION_DENIED )
break ; // changed successfully or already in this state
// else fallback to SEATBELT
2013-07-31 20:58:27 +04:00
print_reject_mode ( " EASY " ) ;
2013-07-28 23:12:16 +04:00
}
2013-07-31 20:58:27 +04:00
res = main_state_transition ( current_status , MAIN_STATE_SEATBELT ) ;
2013-07-28 23:12:16 +04:00
if ( res ! = TRANSITION_DENIED )
break ; // changed successfully or already in this mode
2013-07-31 20:58:27 +04:00
if ( current_status - > assisted_switch ! = ASSISTED_SWITCH_EASY ) // don't print both messages
print_reject_mode ( " SEATBELT " ) ;
2013-07-28 23:12:16 +04:00
// else fallback to MANUAL
2013-07-31 20:58:27 +04:00
res = main_state_transition ( current_status , MAIN_STATE_MANUAL ) ;
2013-07-28 23:12:16 +04:00
// TRANSITION_DENIED is not possible here
break ;
case MODE_SWITCH_AUTO :
2013-07-31 20:58:27 +04:00
res = main_state_transition ( current_status , MAIN_STATE_AUTO ) ;
2013-07-28 23:12:16 +04:00
if ( res ! = TRANSITION_DENIED )
break ; // changed successfully or already in this state
// else fallback to SEATBELT (EASY likely will not work too)
2013-07-31 20:58:27 +04:00
print_reject_mode ( " AUTO " ) ;
res = main_state_transition ( current_status , MAIN_STATE_SEATBELT ) ;
2013-07-28 23:12:16 +04:00
if ( res ! = TRANSITION_DENIED )
break ; // changed successfully or already in this state
// else fallback to MANUAL
2013-07-31 20:58:27 +04:00
res = main_state_transition ( current_status , MAIN_STATE_MANUAL ) ;
2013-07-28 23:12:16 +04:00
// TRANSITION_DENIED is not possible here
break ;
default :
break ;
}
return res ;
}
2013-07-31 20:58:27 +04:00
void
print_reject_mode ( const char * msg )
{
hrt_abstime t = hrt_absolute_time ( ) ;
if ( t - last_print_mode_reject_time > PRINT_MODE_REJECT_INTERVAL ) {
last_print_mode_reject_time = t ;
char s [ 80 ] ;
2013-10-28 14:47:37 +01:00
sprintf ( s , " #audio: warning: reject %s " , msg ) ;
2013-07-31 20:58:27 +04:00
mavlink_log_critical ( mavlink_fd , s ) ;
tune_negative ( ) ;
}
}
2013-08-16 09:23:39 +02:00
void
print_reject_arm ( const char * msg )
{
hrt_abstime t = hrt_absolute_time ( ) ;
if ( t - last_print_mode_reject_time > PRINT_MODE_REJECT_INTERVAL ) {
last_print_mode_reject_time = t ;
char s [ 80 ] ;
2013-10-28 14:47:37 +01:00
sprintf ( s , " #audio: %s " , msg ) ;
2013-08-16 09:23:39 +02:00
mavlink_log_critical ( mavlink_fd , s ) ;
tune_negative ( ) ;
}
}
2013-08-22 15:57:17 +02:00
void answer_command ( struct vehicle_command_s & cmd , enum VEHICLE_CMD_RESULT result )
{
switch ( result ) {
2013-08-27 23:08:00 +02:00
case VEHICLE_CMD_RESULT_ACCEPTED :
2013-08-22 15:57:17 +02:00
tune_positive ( ) ;
2013-08-27 23:08:00 +02:00
break ;
case VEHICLE_CMD_RESULT_DENIED :
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: command denied: %u " , cmd . command ) ;
2013-08-27 23:08:00 +02:00
tune_negative ( ) ;
break ;
case VEHICLE_CMD_RESULT_FAILED :
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: command failed: %u " , cmd . command ) ;
2013-08-27 23:08:00 +02:00
tune_negative ( ) ;
break ;
case VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED :
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: command temporarily rejected: %u " , cmd . command ) ;
2013-08-27 23:08:00 +02:00
tune_negative ( ) ;
break ;
case VEHICLE_CMD_RESULT_UNSUPPORTED :
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: command unsupported: %u " , cmd . command ) ;
2013-08-27 23:08:00 +02:00
tune_negative ( ) ;
break ;
default :
break ;
2013-08-22 15:57:17 +02:00
}
}
2013-03-26 10:44:49 -07:00
void * commander_low_prio_loop ( void * arg )
2013-03-25 14:53:54 -07:00
{
/* Set thread name */
2013-07-31 20:58:27 +04:00
prctl ( PR_SET_NAME , " commander_low_prio " , getpid ( ) ) ;
2013-03-25 14:53:54 -07:00
2013-08-17 18:39:46 +02:00
/* Subscribe to command topic */
int cmd_sub = orb_subscribe ( ORB_ID ( vehicle_command ) ) ;
struct vehicle_command_s cmd ;
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
/* wakeup source(s) */
struct pollfd fds [ 1 ] ;
/* use the gyro to pace output - XXX BROKEN if we are using the L3GD20 */
fds [ 0 ] . fd = cmd_sub ;
fds [ 0 ] . events = POLLIN ;
2013-08-15 09:52:22 +02:00
2013-03-25 14:53:54 -07:00
while ( ! thread_should_exit ) {
2013-10-21 20:07:47 +02:00
/* wait for up to 200ms for data */
2013-09-08 20:05:15 +02:00
int pret = poll ( & fds [ 0 ] , ( sizeof ( fds ) / sizeof ( fds [ 0 ] ) ) , 200 ) ;
2013-03-25 14:53:54 -07:00
2013-10-21 20:07:47 +02:00
/* timed out - periodic check for thread_should_exit, etc. */
2013-08-17 18:39:46 +02:00
if ( pret = = 0 )
continue ;
2013-03-25 14:53:54 -07:00
2013-08-17 18:39:46 +02:00
/* this is undesirable but not much we can do - might want to flag unhappy status */
if ( pret < 0 ) {
warn ( " poll error %d, %d " , pret , errno ) ;
continue ;
}
2013-08-07 20:21:49 +02:00
2013-08-17 18:39:46 +02:00
/* if we reach here, we have a valid command */
orb_copy ( ORB_ID ( vehicle_command ) , cmd_sub , & cmd ) ;
2013-03-25 14:53:54 -07:00
2013-08-17 18:39:46 +02:00
/* ignore commands the high-prio loop handles */
if ( cmd . command = = VEHICLE_CMD_DO_SET_MODE | |
2013-08-24 20:31:01 +02:00
cmd . command = = VEHICLE_CMD_COMPONENT_ARM_DISARM | |
2013-12-08 16:52:41 +01:00
cmd . command = = VEHICLE_CMD_NAV_TAKEOFF | |
cmd . command = = VEHICLE_CMD_DO_SET_SERVO )
2013-08-17 18:39:46 +02:00
continue ;
2013-03-25 14:53:54 -07:00
2013-08-17 18:39:46 +02:00
/* only handle low-priority commands here */
switch ( cmd . command ) {
2013-08-07 20:21:49 +02:00
2013-08-17 18:39:46 +02:00
case VEHICLE_CMD_PREFLIGHT_REBOOT_SHUTDOWN :
2013-08-22 15:57:17 +02:00
if ( is_safe ( & status , & safety , & armed ) ) {
if ( ( ( int ) ( cmd . param1 ) ) = = 1 ) {
answer_command ( cmd , VEHICLE_CMD_RESULT_ACCEPTED ) ;
2013-09-05 13:24:21 +02:00
usleep ( 100000 ) ;
2013-08-22 15:57:17 +02:00
/* reboot */
systemreset ( false ) ;
2013-08-27 23:08:00 +02:00
2013-08-22 15:57:17 +02:00
} else if ( ( ( int ) ( cmd . param1 ) ) = = 3 ) {
answer_command ( cmd , VEHICLE_CMD_RESULT_ACCEPTED ) ;
2013-09-05 13:24:21 +02:00
usleep ( 100000 ) ;
2013-08-22 15:57:17 +02:00
/* reboot to bootloader */
systemreset ( true ) ;
2013-08-27 23:08:00 +02:00
2013-08-17 18:39:46 +02:00
} else {
2013-08-22 15:57:17 +02:00
answer_command ( cmd , VEHICLE_CMD_RESULT_DENIED ) ;
2013-08-17 18:39:46 +02:00
}
2013-03-25 14:53:54 -07:00
2013-08-22 15:57:17 +02:00
} else {
answer_command ( cmd , VEHICLE_CMD_RESULT_DENIED ) ;
}
2013-08-27 23:08:00 +02:00
break ;
2013-03-25 14:53:54 -07:00
2013-08-22 15:57:17 +02:00
case VEHICLE_CMD_PREFLIGHT_CALIBRATION : {
2013-03-25 14:53:54 -07:00
2013-08-27 23:08:00 +02:00
int calib_ret = ERROR ;
2013-03-25 14:53:54 -07:00
2013-08-27 23:08:00 +02:00
/* try to go to INIT/PREFLIGHT arming state */
2013-03-25 14:53:54 -07:00
2013-08-27 23:08:00 +02:00
// XXX disable interrupts in arming_state_transition
2013-12-29 12:16:49 +04:00
if ( TRANSITION_DENIED = = arming_state_transition ( & status , & safety , ARMING_STATE_INIT , & armed ) ) {
2013-08-27 23:08:00 +02:00
answer_command ( cmd , VEHICLE_CMD_RESULT_DENIED ) ;
break ;
}
2013-03-25 14:53:54 -07:00
2013-08-27 23:08:00 +02:00
if ( ( int ) ( cmd . param1 ) = = 1 ) {
/* gyro calibration */
answer_command ( cmd , VEHICLE_CMD_RESULT_ACCEPTED ) ;
calib_ret = do_gyro_calibration ( mavlink_fd ) ;
2013-08-22 15:57:17 +02:00
2013-08-27 23:08:00 +02:00
} else if ( ( int ) ( cmd . param2 ) = = 1 ) {
/* magnetometer calibration */
answer_command ( cmd , VEHICLE_CMD_RESULT_ACCEPTED ) ;
calib_ret = do_mag_calibration ( mavlink_fd ) ;
2013-08-22 15:57:17 +02:00
2013-08-27 23:08:00 +02:00
} else if ( ( int ) ( cmd . param3 ) = = 1 ) {
/* zero-altitude pressure calibration */
answer_command ( cmd , VEHICLE_CMD_RESULT_DENIED ) ;
2013-08-22 15:57:17 +02:00
2013-08-27 23:08:00 +02:00
} else if ( ( int ) ( cmd . param4 ) = = 1 ) {
/* RC calibration */
2013-10-21 20:07:47 +02:00
answer_command ( cmd , VEHICLE_CMD_RESULT_ACCEPTED ) ;
2013-09-05 13:24:21 +02:00
calib_ret = do_rc_calibration ( mavlink_fd ) ;
2013-08-22 15:57:17 +02:00
2013-08-27 23:08:00 +02:00
} else if ( ( int ) ( cmd . param5 ) = = 1 ) {
/* accelerometer calibration */
answer_command ( cmd , VEHICLE_CMD_RESULT_ACCEPTED ) ;
calib_ret = do_accel_calibration ( mavlink_fd ) ;
2013-08-22 15:57:17 +02:00
2013-08-27 23:08:00 +02:00
} else if ( ( int ) ( cmd . param6 ) = = 1 ) {
/* airspeed calibration */
answer_command ( cmd , VEHICLE_CMD_RESULT_ACCEPTED ) ;
calib_ret = do_airspeed_calibration ( mavlink_fd ) ;
}
2013-03-25 14:53:54 -07:00
2013-08-27 23:08:00 +02:00
if ( calib_ret = = OK )
tune_positive ( ) ;
else
tune_negative ( ) ;
2013-03-25 14:53:54 -07:00
2013-12-29 12:16:49 +04:00
arming_state_transition ( & status , & safety , ARMING_STATE_STANDBY , & armed ) ;
2013-03-25 14:53:54 -07:00
2013-08-27 23:08:00 +02:00
break ;
}
2013-07-28 23:12:16 +04:00
2013-08-17 18:39:46 +02:00
case VEHICLE_CMD_PREFLIGHT_STORAGE : {
2013-07-28 23:12:16 +04:00
2013-08-27 23:08:00 +02:00
if ( ( ( int ) ( cmd . param1 ) ) = = 0 ) {
2013-09-05 13:24:21 +02:00
int ret = param_load_default ( ) ;
2013-09-14 08:55:45 +02:00
2013-09-05 13:24:21 +02:00
if ( ret = = OK ) {
2013-08-27 23:08:00 +02:00
mavlink_log_info ( mavlink_fd , " [cmd] parameters loaded " ) ;
answer_command ( cmd , VEHICLE_CMD_RESULT_ACCEPTED ) ;
2013-08-17 18:39:46 +02:00
2013-08-27 23:08:00 +02:00
} else {
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: parameters load ERROR " ) ;
2013-09-14 08:55:45 +02:00
2013-09-05 13:24:21 +02:00
/* convenience as many parts of NuttX use negative errno */
if ( ret < 0 )
ret = - ret ;
if ( ret < 1000 )
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: %s " , strerror ( ret ) ) ;
2013-09-14 08:55:45 +02:00
2013-08-27 23:08:00 +02:00
answer_command ( cmd , VEHICLE_CMD_RESULT_FAILED ) ;
}
2013-08-17 18:39:46 +02:00
2013-08-27 23:08:00 +02:00
} else if ( ( ( int ) ( cmd . param1 ) ) = = 1 ) {
2013-09-05 13:24:21 +02:00
int ret = param_save_default ( ) ;
2013-09-14 08:55:45 +02:00
2013-09-05 13:24:21 +02:00
if ( ret = = OK ) {
2013-08-27 23:08:00 +02:00
mavlink_log_info ( mavlink_fd , " [cmd] parameters saved " ) ;
answer_command ( cmd , VEHICLE_CMD_RESULT_ACCEPTED ) ;
2013-08-17 18:39:46 +02:00
2013-08-27 23:08:00 +02:00
} else {
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: parameters save error " ) ;
2013-09-14 08:55:45 +02:00
2013-09-05 13:24:21 +02:00
/* convenience as many parts of NuttX use negative errno */
if ( ret < 0 )
ret = - ret ;
if ( ret < 1000 )
2013-10-28 14:47:37 +01:00
mavlink_log_critical ( mavlink_fd , " #audio: %s " , strerror ( ret ) ) ;
2013-09-14 08:55:45 +02:00
2013-08-27 23:08:00 +02:00
answer_command ( cmd , VEHICLE_CMD_RESULT_FAILED ) ;
}
2013-08-17 18:39:46 +02:00
}
2013-08-27 23:08:00 +02:00
break ;
2013-08-17 18:39:46 +02:00
}
2013-03-25 14:53:54 -07:00
2013-08-22 15:57:17 +02:00
default :
2013-12-29 12:16:49 +04:00
/* don't answer on unsupported commands, it will be done in main loop */
2013-08-22 15:57:17 +02:00
break ;
2013-08-17 18:39:46 +02:00
}
/* send any requested ACKs */
if ( cmd . confirmation > 0 & & cmd . command ! = VEHICLE_CMD_DO_SET_MODE
2013-08-27 23:08:00 +02:00
& & cmd . command ! = VEHICLE_CMD_COMPONENT_ARM_DISARM ) {
2013-08-17 18:39:46 +02:00
/* send acknowledge command */
// XXX TODO
}
2013-03-25 14:53:54 -07:00
}
2013-09-01 10:29:30 +02:00
close ( cmd_sub ) ;
2013-09-08 20:05:15 +02:00
return NULL ;
2013-03-25 14:53:54 -07:00
}