2014-01-09 08:10:35 +01:00
/****************************************************************************
*
* Copyright ( c ) 2012 - 2014 PX4 Development Team . All rights reserved .
*
* 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 .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @ file mavlink_main . cpp
* MAVLink 1.0 protocol implementation .
*
* @ author Lorenz Meier < lm @ inf . ethz . ch >
2014-02-11 14:38:18 +01:00
* @ author Julian Oes < joes @ student . ethz . ch >
2014-03-01 00:16:51 +04:00
* @ author Anton Babushkin < anton . babushkin @ me . com >
2014-01-09 08:10:35 +01:00
*/
# include <nuttx/config.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2014-02-11 14:38:18 +01:00
# include <stdbool.h>
2014-01-09 08:10:35 +01:00
# include <unistd.h>
# include <fcntl.h>
# include <errno.h>
2014-02-11 14:38:18 +01:00
# include <assert.h>
2014-01-09 08:10:35 +01:00
# include <math.h>
# include <poll.h>
2014-01-26 18:40:02 +01:00
# include <termios.h>
2014-01-09 08:10:35 +01:00
# include <time.h>
2014-02-16 13:24:02 +01:00
# include <math.h> /* isinf / isnan checks */
2014-01-09 08:10:35 +01:00
# include <sys/ioctl.h>
2014-02-16 13:24:02 +01:00
# include <sys/types.h>
# include <sys/stat.h>
2014-01-09 08:10:35 +01:00
# include <drivers/device/device.h>
# include <drivers/drv_hrt.h>
# include <arch/board/board.h>
2014-02-16 13:24:02 +01:00
2014-01-09 08:10:35 +01:00
# include <systemlib/param/param.h>
# include <systemlib/err.h>
# include <systemlib/perf_counter.h>
# include <systemlib/systemlib.h>
# include <geo/geo.h>
2014-02-11 14:38:18 +01:00
# include <dataman/dataman.h>
2014-01-09 08:10:35 +01:00
# include <mathlib/mathlib.h>
# include <mavlink/mavlink_log.h>
2014-02-16 13:24:02 +01:00
2014-02-26 22:47:19 +04:00
# include <uORB/topics/parameter_update.h>
# include <uORB/topics/mission.h>
# include <uORB/topics/mission_result.h>
2014-01-09 08:10:35 +01:00
# include "mavlink_bridge_header.h"
2014-01-26 18:40:02 +01:00
# include "mavlink_main.h"
2014-02-26 00:24:14 +04:00
# include "mavlink_messages.h"
2014-01-26 18:40:02 +01:00
# include "mavlink_receiver.h"
2014-02-27 13:54:55 +04:00
# include "mavlink_rate_limiter.h"
2014-04-08 23:28:52 +04:00
# include "mavlink_commands.h"
2014-01-09 08:10:35 +01:00
/* oddly, ERROR is not defined for c++ */
# ifdef ERROR
# undef ERROR
# endif
static const int ERROR = - 1 ;
2014-02-28 00:45:59 +04:00
# define DEFAULT_DEVICE_NAME " / dev / ttyS1"
2014-02-27 18:31:41 +04:00
# define MAX_DATA_RATE 10000 // max data rate in bytes/s
2014-03-01 19:27:53 +04:00
# define MAIN_LOOP_DELAY 10000 // 100 Hz @ 1000 bytes/s data rate
2014-02-26 00:24:14 +04:00
2014-03-01 18:30:30 +04:00
static Mavlink * _mavlink_instances = nullptr ;
2014-01-28 21:05:00 +01:00
2014-02-12 12:38:35 +01:00
/* TODO: if this is a class member it crashes */
static struct file_operations fops ;
2014-01-09 08:10:35 +01:00
/**
* mavlink app start / stop handling function
*
* @ ingroup apps
*/
extern " C " __EXPORT int mavlink_main ( int argc , char * argv [ ] ) ;
2014-05-31 13:15:10 +02:00
static uint64_t last_write_success_times [ 6 ] = { 0 } ;
static uint64_t last_write_try_times [ 6 ] = { 0 } ;
2014-03-12 09:04:30 +01:00
2014-01-26 18:40:02 +01:00
/*
* Internal function to send the bytes through the right serial port
*/
void
mavlink_send_uart_bytes ( mavlink_channel_t channel , const uint8_t * ch , int length )
{
2014-03-12 17:53:25 +01:00
Mavlink * instance ;
2014-01-26 18:40:02 +01:00
switch ( channel ) {
2014-03-01 00:16:51 +04:00
case MAVLINK_COMM_0 :
2014-03-12 17:53:25 +01:00
instance = Mavlink : : get_instance ( 0 ) ;
2014-01-26 18:40:02 +01:00
break ;
2014-03-01 00:16:51 +04:00
case MAVLINK_COMM_1 :
2014-03-12 17:53:25 +01:00
instance = Mavlink : : get_instance ( 1 ) ;
2014-01-26 18:40:02 +01:00
break ;
2014-03-01 00:16:51 +04:00
case MAVLINK_COMM_2 :
2014-03-12 17:53:25 +01:00
instance = Mavlink : : get_instance ( 2 ) ;
2014-01-26 18:40:02 +01:00
break ;
2014-03-01 00:16:51 +04:00
case MAVLINK_COMM_3 :
2014-03-12 17:53:25 +01:00
instance = Mavlink : : get_instance ( 3 ) ;
2014-01-26 18:40:02 +01:00
break ;
2014-03-01 00:16:51 +04:00
# ifdef MAVLINK_COMM_4
case MAVLINK_COMM_4 :
2014-03-12 17:53:25 +01:00
instance = Mavlink : : get_instance ( 4 ) ;
2014-01-26 18:40:02 +01:00
break ;
2014-03-01 00:16:51 +04:00
# endif
# ifdef MAVLINK_COMM_5
case MAVLINK_COMM_5 :
2014-03-12 17:53:25 +01:00
instance = Mavlink : : get_instance ( 5 ) ;
2014-01-26 18:40:02 +01:00
break ;
2014-03-01 00:16:51 +04:00
# endif
# ifdef MAVLINK_COMM_6
case MAVLINK_COMM_6 :
2014-03-12 17:53:25 +01:00
instance = Mavlink : : get_instance ( 6 ) ;
2014-01-26 18:40:02 +01:00
break ;
2014-03-01 00:16:51 +04:00
# endif
2014-05-21 14:21:47 +02:00
default :
2014-03-12 17:53:25 +01:00
return ;
2014-03-21 20:06:34 +04:00
}
2014-03-12 17:53:25 +01:00
int uart = instance - > get_uart_fd ( ) ;
2014-02-11 14:38:18 +01:00
ssize_t desired = ( sizeof ( uint8_t ) * length ) ;
2014-03-12 09:04:30 +01:00
/*
* Check if the OS buffer is full and disable HW
* flow control if it continues to be full
*/
int buf_free = 0 ;
2014-03-12 17:53:25 +01:00
if ( instance - > get_flow_control_enabled ( )
2014-04-10 10:26:15 +02:00
& & ioctl ( uart , FIONWRITE , ( unsigned long ) & buf_free ) = = 0 ) {
2014-03-12 09:36:12 +01:00
2014-05-31 13:15:10 +02:00
/* Disable hardware flow control:
* if no successful write since a defined time
* and if the last try was not the last successful write
*/
if ( last_write_try_times [ ( unsigned ) channel ] ! = 0 & &
hrt_elapsed_time ( & last_write_success_times [ ( unsigned ) channel ] ) > 500 * 1000UL & &
last_write_success_times [ ( unsigned ) channel ] ! =
last_write_try_times [ ( unsigned ) channel ] )
{
warnx ( " DISABLING HARDWARE FLOW CONTROL " ) ;
instance - > enable_flow_control ( false ) ;
2014-03-12 09:36:12 +01:00
}
2014-05-31 13:15:10 +02:00
2014-03-12 09:04:30 +01:00
}
2014-04-10 10:26:15 +02:00
/* If the wait until transmit flag is on, only transmit after we've received messages.
Otherwise , transmit all the time . */
if ( instance - > should_transmit ( ) ) {
2014-05-31 13:15:10 +02:00
last_write_try_times [ ( unsigned ) channel ] = hrt_absolute_time ( ) ;
2014-04-20 21:04:05 +02:00
/* check if there is space in the buffer, let it overflow else */
if ( ! ioctl ( uart , FIONWRITE , ( unsigned long ) & buf_free ) ) {
2014-05-29 18:28:37 +02:00
if ( buf_free < desired ) {
/* we don't want to send anything just in half, so return */
return ;
2014-04-20 21:04:05 +02:00
}
}
ssize_t ret = write ( uart , ch , desired ) ;
2014-04-10 10:26:15 +02:00
if ( ret ! = desired ) {
2014-04-20 21:04:05 +02:00
warnx ( " TX FAIL " ) ;
2014-05-31 13:15:10 +02:00
} else {
last_write_success_times [ ( unsigned ) channel ] = last_write_try_times [ ( unsigned ) channel ] ;
2014-04-10 10:26:15 +02:00
}
2014-03-01 00:16:51 +04:00
}
2014-01-09 08:10:35 +01:00
2014-04-10 10:26:15 +02:00
2014-01-26 18:40:02 +01:00
}
static void usage ( void ) ;
2014-01-09 08:10:35 +01:00
2014-03-11 15:34:27 +04:00
Mavlink : : Mavlink ( ) :
2014-03-01 18:30:30 +04:00
_device_name ( DEFAULT_DEVICE_NAME ) ,
_task_should_exit ( false ) ,
2014-05-21 14:21:47 +02:00
next ( nullptr ) ,
2014-02-16 13:24:02 +01:00
_mavlink_fd ( - 1 ) ,
2014-03-01 18:30:30 +04:00
_task_running ( false ) ,
2014-03-11 23:03:49 +04:00
_hil_enabled ( false ) ,
2014-04-04 12:57:44 +02:00
_use_hil_gps ( false ) ,
2014-03-16 19:43:09 +01:00
_is_usb_uart ( false ) ,
2014-04-10 10:26:15 +02:00
_wait_to_transmit ( false ) ,
_received_messages ( false ) ,
2014-03-01 19:27:53 +04:00
_main_loop_delay ( 1000 ) ,
2014-02-26 00:24:14 +04:00
_subscriptions ( nullptr ) ,
_streams ( nullptr ) ,
2014-03-01 18:30:30 +04:00
_mission_pub ( - 1 ) ,
2014-05-29 18:28:37 +02:00
_mode ( MAVLINK_MODE_NORMAL ) ,
_total_counter ( 0 ) ,
2014-04-03 21:15:47 +02:00
_verbose ( false ) ,
_forwarding_on ( false ) ,
_passing_on ( false ) ,
_uart_fd ( - 1 ) ,
2014-03-01 18:30:30 +04:00
_mavlink_param_queue_index ( 0 ) ,
2014-03-01 16:43:04 +04:00
_subscribe_to_stream ( nullptr ) ,
_subscribe_to_stream_rate ( 0.0f ) ,
2014-03-12 17:53:25 +01:00
_flow_control_enabled ( true ) ,
2014-04-03 21:15:47 +02:00
_message_buffer ( { } ) ,
2014-02-26 21:28:35 +04:00
/* performance counters */
_loop_perf ( perf_alloc ( PC_ELAPSED , " mavlink " ) )
2014-01-09 08:10:35 +01:00
{
2014-03-01 18:30:30 +04:00
_wpm = & _wpm_s ;
2014-03-11 22:26:12 +01:00
mission . count = 0 ;
2014-03-01 00:16:51 +04:00
fops . ioctl = ( int ( * ) ( file * , int , long unsigned int ) ) & mavlink_dev_ioctl ;
2014-03-11 11:12:39 +04:00
2014-03-11 15:34:27 +04:00
_instance_id = Mavlink : : instance_count ( ) ;
2014-03-11 11:12:39 +04:00
/* set channel according to instance id */
switch ( _instance_id ) {
case 0 :
_channel = MAVLINK_COMM_0 ;
break ;
2014-03-21 20:06:34 +04:00
2014-03-11 11:12:39 +04:00
case 1 :
_channel = MAVLINK_COMM_1 ;
break ;
2014-03-21 20:06:34 +04:00
2014-03-11 11:12:39 +04:00
case 2 :
_channel = MAVLINK_COMM_2 ;
break ;
2014-03-21 20:06:34 +04:00
2014-03-11 11:12:39 +04:00
case 3 :
_channel = MAVLINK_COMM_3 ;
break ;
# ifdef MAVLINK_COMM_4
2014-03-21 20:06:34 +04:00
2014-03-11 11:12:39 +04:00
case 4 :
_channel = MAVLINK_COMM_4 ;
break ;
# endif
# ifdef MAVLINK_COMM_5
2014-03-21 20:06:34 +04:00
case 5 :
2014-03-11 11:12:39 +04:00
_channel = MAVLINK_COMM_5 ;
break ;
# endif
# ifdef MAVLINK_COMM_6
2014-03-21 20:06:34 +04:00
2014-03-11 11:12:39 +04:00
case 6 :
_channel = MAVLINK_COMM_6 ;
break ;
# endif
2014-03-21 20:06:34 +04:00
2014-03-11 11:12:39 +04:00
default :
errx ( 1 , " instance ID is out of range " ) ;
break ;
}
2014-01-09 08:10:35 +01:00
}
Mavlink : : ~ Mavlink ( )
{
2014-03-11 19:28:48 +04:00
perf_free ( _loop_perf ) ;
2014-03-01 18:30:30 +04:00
if ( _task_running ) {
/* task wakes up every 10ms or so at the longest */
2014-01-09 08:10:35 +01:00
_task_should_exit = true ;
/* wait for a second for the task to quit at our request */
unsigned i = 0 ;
do {
/* wait 20ms */
usleep ( 20000 ) ;
/* if we have given up, kill it */
if ( + + i > 50 ) {
2014-03-01 18:30:30 +04:00
//TODO store main task handle in Mavlink instance to allow killing task
//task_delete(_mavlink_task);
2014-01-09 08:10:35 +01:00
break ;
}
2014-03-01 18:30:30 +04:00
} while ( _task_running ) ;
2014-01-09 08:10:35 +01:00
}
2014-03-21 20:06:34 +04:00
2014-03-11 15:34:27 +04:00
LL_DELETE ( _mavlink_instances , this ) ;
2014-01-09 08:10:35 +01:00
}
2014-02-26 21:28:35 +04:00
void
Mavlink : : set_mode ( enum MAVLINK_MODE mode )
2014-01-28 19:30:23 +01:00
{
_mode = mode ;
}
2014-02-26 21:28:35 +04:00
int
Mavlink : : instance_count ( )
2014-01-09 08:10:35 +01:00
{
unsigned inst_index = 0 ;
2014-03-01 18:30:30 +04:00
Mavlink * inst ;
2014-03-01 00:16:51 +04:00
2014-03-01 18:30:30 +04:00
LL_FOREACH ( : : _mavlink_instances , inst ) {
2014-01-09 08:10:35 +01:00
inst_index + + ;
}
2014-02-02 11:06:53 +01:00
return inst_index ;
2014-01-09 08:10:35 +01:00
}
2014-02-26 21:28:35 +04:00
Mavlink *
Mavlink : : get_instance ( unsigned instance )
2014-01-09 08:10:35 +01:00
{
2014-03-01 18:30:30 +04:00
Mavlink * inst ;
2014-01-09 08:10:35 +01:00
unsigned inst_index = 0 ;
2014-03-01 18:30:30 +04:00
LL_FOREACH ( : : _mavlink_instances , inst ) {
if ( instance = = inst_index ) {
return inst ;
}
2014-03-01 00:16:51 +04:00
2014-01-09 08:10:35 +01:00
inst_index + + ;
}
2014-03-01 18:30:30 +04:00
return nullptr ;
2014-01-09 08:10:35 +01:00
}
2014-02-28 00:45:59 +04:00
Mavlink *
Mavlink : : get_instance_for_device ( const char * device_name )
{
Mavlink * inst ;
2014-03-01 18:30:30 +04:00
LL_FOREACH ( : : _mavlink_instances , inst ) {
if ( strcmp ( inst - > _device_name , device_name ) = = 0 ) {
2014-02-28 00:45:59 +04:00
return inst ;
}
}
return nullptr ;
}
2014-02-26 21:28:35 +04:00
int
Mavlink : : destroy_all_instances ( )
2014-02-13 19:13:10 +01:00
{
/* start deleting from the end */
Mavlink * inst_to_del = nullptr ;
2014-03-01 18:30:30 +04:00
Mavlink * next_inst = : : _mavlink_instances ;
2014-02-13 19:13:10 +01:00
unsigned iterations = 0 ;
warnx ( " waiting for instances to stop " ) ;
2014-03-01 00:16:51 +04:00
2014-02-13 19:13:10 +01:00
while ( next_inst ! = nullptr ) {
inst_to_del = next_inst ;
2014-02-28 00:45:59 +04:00
next_inst = inst_to_del - > next ;
2014-02-13 19:13:10 +01:00
/* set flag to stop thread and wait for all threads to finish */
inst_to_del - > _task_should_exit = true ;
2014-03-01 00:16:51 +04:00
2014-03-01 18:30:30 +04:00
while ( inst_to_del - > _task_running ) {
2014-02-13 19:13:10 +01:00
printf ( " . " ) ;
2014-03-01 16:43:04 +04:00
fflush ( stdout ) ;
2014-02-13 19:13:10 +01:00
usleep ( 10000 ) ;
iterations + + ;
2014-03-01 17:12:46 +04:00
if ( iterations > 1000 ) {
2014-02-13 19:13:10 +01:00
warnx ( " ERROR: Couldn't stop all mavlink instances. " ) ;
return ERROR ;
}
}
}
printf ( " \n " ) ;
warnx ( " all instances stopped " ) ;
return OK ;
}
2014-02-26 21:28:35 +04:00
bool
Mavlink : : instance_exists ( const char * device_name , Mavlink * self )
2014-02-12 19:13:57 +01:00
{
2014-03-01 18:30:30 +04:00
Mavlink * inst = : : _mavlink_instances ;
2014-03-01 00:16:51 +04:00
2014-02-12 19:13:57 +01:00
while ( inst ! = nullptr ) {
/* don't compare with itself */
2014-03-01 18:30:30 +04:00
if ( inst ! = self & & ! strcmp ( device_name , inst - > _device_name ) ) {
2014-02-12 19:13:57 +01:00
return true ;
2014-03-01 00:16:51 +04:00
}
2014-02-28 00:45:59 +04:00
inst = inst - > next ;
2014-02-12 19:13:57 +01:00
}
2014-03-01 00:16:51 +04:00
2014-02-12 19:13:57 +01:00
return false ;
}
2014-04-03 21:15:47 +02:00
void
Mavlink : : forward_message ( mavlink_message_t * msg , Mavlink * self )
{
2014-06-03 16:01:28 +02:00
2014-04-07 21:42:48 +02:00
Mavlink * inst ;
LL_FOREACH ( _mavlink_instances , inst ) {
2014-04-03 21:15:47 +02:00
if ( inst ! = self ) {
inst - > pass_message ( msg ) ;
}
}
}
2014-02-26 21:28:35 +04:00
int
Mavlink : : get_uart_fd ( unsigned index )
2014-01-26 18:40:02 +01:00
{
2014-03-01 00:16:51 +04:00
Mavlink * inst = get_instance ( index ) ;
if ( inst ) {
2014-02-11 16:16:57 +01:00
return inst - > get_uart_fd ( ) ;
2014-03-01 00:16:51 +04:00
}
2014-01-26 18:40:02 +01:00
return - 1 ;
}
2014-02-26 21:28:35 +04:00
int
Mavlink : : get_uart_fd ( )
2014-02-14 13:36:59 +01:00
{
2014-03-01 18:30:30 +04:00
return _uart_fd ;
2014-02-14 13:36:59 +01:00
}
2014-03-11 11:12:39 +04:00
int
Mavlink : : get_instance_id ( )
{
return _instance_id ;
}
2014-02-26 21:28:35 +04:00
mavlink_channel_t
Mavlink : : get_channel ( )
2014-02-14 13:36:59 +01:00
{
2014-02-27 13:54:55 +04:00
return _channel ;
2014-02-14 13:36:59 +01:00
}
2014-01-09 08:10:35 +01:00
/****************************************************************************
* MAVLink text message logger
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-01-26 18:40:02 +01:00
int
Mavlink : : mavlink_dev_ioctl ( struct file * filep , int cmd , unsigned long arg )
2014-01-09 08:10:35 +01:00
{
switch ( cmd ) {
case ( int ) MAVLINK_IOC_SEND_TEXT_INFO :
case ( int ) MAVLINK_IOC_SEND_TEXT_CRITICAL :
case ( int ) MAVLINK_IOC_SEND_TEXT_EMERGENCY : {
2014-02-12 12:38:35 +01:00
2014-03-01 00:16:51 +04:00
const char * txt = ( const char * ) arg ;
2014-02-12 12:38:35 +01:00
// printf("logmsg: %s\n", txt);
2014-03-01 00:16:51 +04:00
struct mavlink_logmessage msg ;
strncpy ( msg . text , txt , sizeof ( msg . text ) ) ;
2014-03-11 19:28:48 +04:00
Mavlink * inst ;
LL_FOREACH ( _mavlink_instances , inst ) {
if ( ! inst - > _task_should_exit ) {
mavlink_logbuffer_write ( & inst - > _logbuffer , & msg ) ;
inst - > _total_counter + + ;
}
2014-03-01 00:16:51 +04:00
}
return OK ;
2014-02-12 18:35:45 +01:00
}
2014-01-09 08:10:35 +01:00
default :
return ENOTTY ;
}
}
2014-01-26 18:40:02 +01:00
void Mavlink : : mavlink_update_system ( void )
2014-01-09 08:10:35 +01:00
{
static bool initialized = false ;
static param_t param_system_id ;
static param_t param_component_id ;
static param_t param_system_type ;
2014-04-04 12:57:44 +02:00
static param_t param_use_hil_gps ;
2014-01-09 08:10:35 +01:00
if ( ! initialized ) {
param_system_id = param_find ( " MAV_SYS_ID " ) ;
param_component_id = param_find ( " MAV_COMP_ID " ) ;
param_system_type = param_find ( " MAV_TYPE " ) ;
2014-04-04 12:57:44 +02:00
param_use_hil_gps = param_find ( " MAV_USEHILGPS " ) ;
2014-01-09 08:10:35 +01:00
initialized = true ;
}
/* update system and component id */
int32_t system_id ;
param_get ( param_system_id , & system_id ) ;
if ( system_id > 0 & & system_id < 255 ) {
mavlink_system . sysid = system_id ;
}
int32_t component_id ;
param_get ( param_component_id , & component_id ) ;
if ( component_id > 0 & & component_id < 255 ) {
mavlink_system . compid = component_id ;
}
int32_t system_type ;
param_get ( param_system_type , & system_type ) ;
if ( system_type > = 0 & & system_type < MAV_TYPE_ENUM_END ) {
mavlink_system . type = system_type ;
}
2014-04-04 12:57:44 +02:00
int32_t use_hil_gps ;
param_get ( param_use_hil_gps , & use_hil_gps ) ;
_use_hil_gps = ( bool ) use_hil_gps ;
2014-01-09 08:10:35 +01:00
}
2014-01-26 18:40:02 +01:00
int Mavlink : : mavlink_open_uart ( int baud , const char * uart_name , struct termios * uart_config_original , bool * is_usb )
2014-01-09 08:10:35 +01:00
{
/* process baud rate */
int speed ;
switch ( baud ) {
case 0 : speed = B0 ; break ;
case 50 : speed = B50 ; break ;
case 75 : speed = B75 ; break ;
case 110 : speed = B110 ; break ;
case 134 : speed = B134 ; break ;
case 150 : speed = B150 ; break ;
case 200 : speed = B200 ; break ;
case 300 : speed = B300 ; break ;
case 600 : speed = B600 ; break ;
case 1200 : speed = B1200 ; break ;
case 1800 : speed = B1800 ; break ;
case 2400 : speed = B2400 ; break ;
case 4800 : speed = B4800 ; break ;
case 9600 : speed = B9600 ; break ;
case 19200 : speed = B19200 ; break ;
case 38400 : speed = B38400 ; break ;
case 57600 : speed = B57600 ; break ;
case 115200 : speed = B115200 ; break ;
case 230400 : speed = B230400 ; break ;
case 460800 : speed = B460800 ; break ;
case 921600 : speed = B921600 ; break ;
default :
2014-02-02 11:06:53 +01:00
warnx ( " ERROR: Unsupported baudrate: %d \n \t supported examples: \n \t 9600, 19200, 38400, 57600 \t \n 115200 \n 230400 \n 460800 \n 921600 \n " , baud ) ;
2014-01-09 08:10:35 +01:00
return - EINVAL ;
}
/* open uart */
2014-03-01 18:30:30 +04:00
_uart_fd = open ( uart_name , O_RDWR | O_NOCTTY ) ;
2014-01-09 08:10:35 +01:00
2014-04-22 01:23:55 +02:00
if ( _uart_fd < 0 ) {
return _uart_fd ;
}
2014-01-09 08:10:35 +01:00
/* Try to set baud rate */
struct termios uart_config ;
int termios_state ;
* is_usb = false ;
/* Back up the original uart configuration to restore it after exit */
2014-03-01 18:30:30 +04:00
if ( ( termios_state = tcgetattr ( _uart_fd , uart_config_original ) ) < 0 ) {
2014-03-12 10:29:39 +01:00
warnx ( " ERR GET CONF %s: %d \n " , uart_name , termios_state ) ;
2014-03-01 18:30:30 +04:00
close ( _uart_fd ) ;
2014-01-09 08:10:35 +01:00
return - 1 ;
}
/* Fill the struct for the new configuration */
2014-03-01 18:30:30 +04:00
tcgetattr ( _uart_fd , & uart_config ) ;
2014-01-09 08:10:35 +01:00
/* Clear ONLCR flag (which appends a CR for every LF) */
uart_config . c_oflag & = ~ ONLCR ;
/* USB serial is indicated by /dev/ttyACM0*/
if ( strcmp ( uart_name , " /dev/ttyACM0 " ) ! = OK & & strcmp ( uart_name , " /dev/ttyACM1 " ) ! = OK ) {
/* Set baud rate */
if ( cfsetispeed ( & uart_config , speed ) < 0 | | cfsetospeed ( & uart_config , speed ) < 0 ) {
2014-03-12 10:29:39 +01:00
warnx ( " ERR SET BAUD %s: %d \n " , uart_name , termios_state ) ;
2014-03-01 18:30:30 +04:00
close ( _uart_fd ) ;
2014-01-09 08:10:35 +01:00
return - 1 ;
}
}
2014-03-01 18:30:30 +04:00
if ( ( termios_state = tcsetattr ( _uart_fd , TCSANOW , & uart_config ) ) < 0 ) {
2014-03-12 10:29:39 +01:00
warnx ( " ERR SET CONF %s \n " , uart_name ) ;
2014-03-01 18:30:30 +04:00
close ( _uart_fd ) ;
2014-01-09 08:10:35 +01:00
return - 1 ;
}
2014-03-16 19:43:09 +01:00
if ( ! _is_usb_uart ) {
/*
* Setup hardware flow control . If the port has no RTS pin this call will fail ,
* which is not an issue , but requires a separate call so we can fail silently .
*/
( void ) tcgetattr ( _uart_fd , & uart_config ) ;
uart_config . c_cflag | = CRTS_IFLOW ;
( void ) tcsetattr ( _uart_fd , TCSANOW , & uart_config ) ;
/* setup output flow control */
if ( enable_flow_control ( true ) ) {
2014-03-21 10:44:31 +01:00
warnx ( " hardware flow control not supported " ) ;
2014-03-16 19:43:09 +01:00
}
2014-03-12 10:29:39 +01:00
}
2014-03-12 09:04:30 +01:00
2014-03-01 18:30:30 +04:00
return _uart_fd ;
2014-01-09 08:10:35 +01:00
}
2014-03-12 09:04:30 +01:00
int
Mavlink : : enable_flow_control ( bool enabled )
{
2014-03-16 19:43:09 +01:00
// We can't do this on USB - skip
if ( _is_usb_uart ) {
return OK ;
}
2014-03-12 09:04:30 +01:00
struct termios uart_config ;
2014-03-21 20:06:34 +04:00
2014-03-12 09:04:30 +01:00
int ret = tcgetattr ( _uart_fd , & uart_config ) ;
2014-03-21 20:06:34 +04:00
2014-03-12 09:04:30 +01:00
if ( enabled ) {
uart_config . c_cflag | = CRTSCTS ;
2014-03-21 20:06:34 +04:00
2014-03-12 09:04:30 +01:00
} else {
uart_config . c_cflag & = ~ CRTSCTS ;
}
2014-03-21 20:06:34 +04:00
2014-03-12 09:04:30 +01:00
ret = tcsetattr ( _uart_fd , TCSANOW , & uart_config ) ;
2014-03-12 17:53:25 +01:00
if ( ! ret ) {
_flow_control_enabled = enabled ;
}
2014-03-12 09:04:30 +01:00
return ret ;
}
2014-01-09 08:10:35 +01:00
int
2014-02-11 14:38:18 +01:00
Mavlink : : set_hil_enabled ( bool hil_enabled )
2014-01-09 08:10:35 +01:00
{
int ret = OK ;
2014-03-11 23:03:49 +04:00
/* enable HIL */
if ( hil_enabled & & ! _hil_enabled ) {
_hil_enabled = true ;
float rate_mult = _datarate / 1000.0f ;
configure_stream ( " HIL_CONTROLS " , 15.0f * rate_mult ) ;
2014-01-09 08:10:35 +01:00
}
2014-03-11 23:03:49 +04:00
/* disable HIL */
if ( ! hil_enabled & & _hil_enabled ) {
_hil_enabled = false ;
configure_stream ( " HIL_CONTROLS " , 0.0f ) ;
2014-01-09 08:10:35 +01:00
} else {
ret = ERROR ;
}
return ret ;
}
extern mavlink_system_t mavlink_system ;
2014-01-26 18:40:02 +01:00
int Mavlink : : mavlink_pm_queued_send ( )
2014-01-09 08:10:35 +01:00
{
2014-03-01 18:30:30 +04:00
if ( _mavlink_param_queue_index < param_count ( ) ) {
mavlink_pm_send_param ( param_for_index ( _mavlink_param_queue_index ) ) ;
_mavlink_param_queue_index + + ;
2014-01-09 08:10:35 +01:00
return 0 ;
} else {
return 1 ;
}
}
2014-01-26 18:40:02 +01:00
void Mavlink : : mavlink_pm_start_queued_send ( )
2014-01-09 08:10:35 +01:00
{
2014-03-01 18:30:30 +04:00
_mavlink_param_queue_index = 0 ;
2014-01-09 08:10:35 +01:00
}
2014-01-26 18:40:02 +01:00
int Mavlink : : mavlink_pm_send_param_for_index ( uint16_t index )
2014-01-09 08:10:35 +01:00
{
return mavlink_pm_send_param ( param_for_index ( index ) ) ;
}
2014-01-26 18:40:02 +01:00
int Mavlink : : mavlink_pm_send_param_for_name ( const char * name )
2014-01-09 08:10:35 +01:00
{
return mavlink_pm_send_param ( param_find ( name ) ) ;
}
2014-01-26 18:40:02 +01:00
int Mavlink : : mavlink_pm_send_param ( param_t param )
2014-01-09 08:10:35 +01:00
{
2014-03-01 00:16:51 +04:00
if ( param = = PARAM_INVALID ) { return 1 ; }
2014-01-09 08:10:35 +01:00
/* buffers for param transmission */
2014-05-12 22:10:52 +02:00
char name_buf [ MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN ] ;
2014-01-09 08:10:35 +01:00
float val_buf ;
2014-05-12 22:10:52 +02:00
mavlink_message_t tx_msg ;
2014-01-09 08:10:35 +01:00
/* query parameter type */
param_type_t type = param_type ( param ) ;
/* copy parameter name */
strncpy ( ( char * ) name_buf , param_name ( param ) , MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN ) ;
/*
* Map onboard parameter type to MAVLink type ,
* endianess matches ( both little endian )
*/
uint8_t mavlink_type ;
if ( type = = PARAM_TYPE_INT32 ) {
mavlink_type = MAVLINK_TYPE_INT32_T ;
} else if ( type = = PARAM_TYPE_FLOAT ) {
mavlink_type = MAVLINK_TYPE_FLOAT ;
} else {
mavlink_type = MAVLINK_TYPE_FLOAT ;
}
/*
* get param value , since MAVLink encodes float and int params in the same
* space during transmission , copy param onto float val_buf
*/
int ret ;
if ( ( ret = param_get ( param , & val_buf ) ) ! = OK ) {
return ret ;
}
mavlink_msg_param_value_pack_chan ( mavlink_system . sysid ,
mavlink_system . compid ,
2014-03-12 09:46:02 +01:00
_channel ,
2014-01-09 08:10:35 +01:00
& tx_msg ,
name_buf ,
val_buf ,
mavlink_type ,
param_count ( ) ,
param_get_index ( param ) ) ;
2014-01-26 18:40:02 +01:00
mavlink_missionlib_send_message ( & tx_msg ) ;
return OK ;
2014-01-09 08:10:35 +01:00
}
2014-01-26 18:40:02 +01:00
void Mavlink : : mavlink_pm_message_handler ( const mavlink_channel_t chan , const mavlink_message_t * msg )
2014-01-09 08:10:35 +01:00
{
switch ( msg - > msgid ) {
case MAVLINK_MSG_ID_PARAM_REQUEST_LIST : {
2014-06-06 00:42:02 +02:00
mavlink_param_request_list_t req ;
mavlink_msg_param_request_list_decode ( msg , & req ) ;
if ( req . target_system = = mavlink_system . sysid & &
( req . target_component = = mavlink_system . compid | | req . target_component = = MAV_COMP_ID_ALL ) ) {
/* Start sending parameters */
mavlink_pm_start_queued_send ( ) ;
mavlink_missionlib_send_gcs_string ( " [mavlink pm] sending list " ) ;
}
2014-01-09 08:10:35 +01:00
} break ;
case MAVLINK_MSG_ID_PARAM_SET : {
/* Handle parameter setting */
if ( msg - > msgid = = MAVLINK_MSG_ID_PARAM_SET ) {
mavlink_param_set_t mavlink_param_set ;
mavlink_msg_param_set_decode ( msg , & mavlink_param_set ) ;
if ( mavlink_param_set . target_system = = mavlink_system . sysid & & ( ( mavlink_param_set . target_component = = mavlink_system . compid ) | | ( mavlink_param_set . target_component = = MAV_COMP_ID_ALL ) ) ) {
/* local name buffer to enforce null-terminated string */
char name [ MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN + 1 ] ;
strncpy ( name , mavlink_param_set . param_id , MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN ) ;
/* enforce null termination */
name [ MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN ] = ' \0 ' ;
/* attempt to find parameter, set and send it */
param_t param = param_find ( name ) ;
if ( param = = PARAM_INVALID ) {
char buf [ MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN ] ;
sprintf ( buf , " [mavlink pm] unknown: %s " , name ) ;
mavlink_missionlib_send_gcs_string ( buf ) ;
} else {
/* set and send parameter */
param_set ( param , & ( mavlink_param_set . param_value ) ) ;
mavlink_pm_send_param ( param ) ;
}
}
}
} break ;
case MAVLINK_MSG_ID_PARAM_REQUEST_READ : {
mavlink_param_request_read_t mavlink_param_request_read ;
mavlink_msg_param_request_read_decode ( msg , & mavlink_param_request_read ) ;
if ( mavlink_param_request_read . target_system = = mavlink_system . sysid & & ( ( mavlink_param_request_read . target_component = = mavlink_system . compid ) | | ( mavlink_param_request_read . target_component = = MAV_COMP_ID_ALL ) ) ) {
/* when no index is given, loop through string ids and compare them */
if ( mavlink_param_request_read . param_index = = - 1 ) {
/* local name buffer to enforce null-terminated string */
char name [ MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN + 1 ] ;
strncpy ( name , mavlink_param_request_read . param_id , MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN ) ;
/* enforce null termination */
name [ MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN ] = ' \0 ' ;
/* attempt to find parameter and send it */
mavlink_pm_send_param_for_name ( name ) ;
} else {
/* when index is >= 0, send this parameter again */
mavlink_pm_send_param_for_index ( mavlink_param_request_read . param_index ) ;
}
}
} break ;
}
}
2014-01-26 18:40:02 +01:00
void Mavlink : : publish_mission ( )
2014-01-09 08:10:35 +01:00
{
/* Initialize mission publication if necessary */
2014-03-01 18:30:30 +04:00
if ( _mission_pub < 0 ) {
2014-04-18 11:15:40 +02:00
_mission_pub = orb_advertise ( ORB_ID ( offboard_mission ) , & mission ) ;
2014-01-09 08:10:35 +01:00
} else {
2014-04-18 11:15:40 +02:00
orb_publish ( ORB_ID ( offboard_mission ) , _mission_pub , & mission ) ;
2014-01-09 08:10:35 +01:00
}
}
2014-01-26 18:40:02 +01:00
int Mavlink : : map_mavlink_mission_item_to_mission_item ( const mavlink_mission_item_t * mavlink_mission_item , struct mission_item_s * mission_item )
2014-01-09 08:10:35 +01:00
{
/* only support global waypoints for now */
switch ( mavlink_mission_item - > frame ) {
2014-03-01 00:16:51 +04:00
case MAV_FRAME_GLOBAL :
mission_item - > lat = ( double ) mavlink_mission_item - > x ;
mission_item - > lon = ( double ) mavlink_mission_item - > y ;
mission_item - > altitude = mavlink_mission_item - > z ;
mission_item - > altitude_is_relative = false ;
break ;
2014-01-09 08:10:35 +01:00
2014-03-01 00:16:51 +04:00
case MAV_FRAME_GLOBAL_RELATIVE_ALT :
mission_item - > lat = ( double ) mavlink_mission_item - > x ;
mission_item - > lon = ( double ) mavlink_mission_item - > y ;
mission_item - > altitude = mavlink_mission_item - > z ;
mission_item - > altitude_is_relative = true ;
break ;
2014-01-09 08:10:35 +01:00
2014-03-01 00:16:51 +04:00
case MAV_FRAME_LOCAL_NED :
case MAV_FRAME_LOCAL_ENU :
return MAV_MISSION_UNSUPPORTED_FRAME ;
case MAV_FRAME_MISSION :
default :
return MAV_MISSION_ERROR ;
2014-01-09 08:10:35 +01:00
}
switch ( mavlink_mission_item - > command ) {
2014-03-01 00:16:51 +04:00
case MAV_CMD_NAV_TAKEOFF :
2014-05-28 00:12:59 +02:00
mission_item - > pitch_min = mavlink_mission_item - > param1 ;
2014-03-01 00:16:51 +04:00
break ;
2014-04-09 18:39:23 +02:00
case MAV_CMD_DO_JUMP :
mission_item - > do_jump_mission_index = mavlink_mission_item - > param1 ;
2014-06-15 11:59:45 +02:00
mission_item - > do_jump_current_count = 0 ;
2014-04-21 17:36:59 +02:00
mission_item - > do_jump_repeat_count = mavlink_mission_item - > param2 ;
2014-04-09 18:39:23 +02:00
break ;
2014-03-01 00:16:51 +04:00
default :
mission_item - > acceptance_radius = mavlink_mission_item - > param2 ;
2014-06-01 14:04:16 +02:00
mission_item - > time_inside = mavlink_mission_item - > param1 ;
2014-03-01 00:16:51 +04:00
break ;
2014-01-09 08:10:35 +01:00
}
2014-03-01 00:16:51 +04:00
mission_item - > yaw = _wrap_pi ( mavlink_mission_item - > param4 * M_DEG_TO_RAD_F ) ;
2014-01-09 08:10:35 +01:00
mission_item - > loiter_radius = fabsf ( mavlink_mission_item - > param3 ) ;
mission_item - > loiter_direction = ( mavlink_mission_item - > param3 > 0 ) ? 1 : - 1 ; /* 1 if positive CW, -1 if negative CCW */
2014-01-26 18:40:02 +01:00
mission_item - > nav_cmd = ( NAV_CMD ) mavlink_mission_item - > command ;
2014-01-09 08:10:35 +01:00
mission_item - > autocontinue = mavlink_mission_item - > autocontinue ;
// mission_item->index = mavlink_mission_item->seq;
mission_item - > origin = ORIGIN_MAVLINK ;
2014-04-21 17:36:59 +02:00
/* reset DO_JUMP count */
mission_item - > do_jump_current_count = 0 ;
2014-01-09 08:10:35 +01:00
return OK ;
}
2014-01-26 18:40:02 +01:00
int Mavlink : : map_mission_item_to_mavlink_mission_item ( const struct mission_item_s * mission_item , mavlink_mission_item_t * mavlink_mission_item )
2014-01-09 08:10:35 +01:00
{
if ( mission_item - > altitude_is_relative ) {
mavlink_mission_item - > frame = MAV_FRAME_GLOBAL ;
2014-03-01 00:16:51 +04:00
2014-01-09 08:10:35 +01:00
} else {
mavlink_mission_item - > frame = MAV_FRAME_GLOBAL_RELATIVE_ALT ;
}
2014-03-01 00:16:51 +04:00
2014-01-09 08:10:35 +01:00
switch ( mission_item - > nav_cmd ) {
2014-03-01 00:16:51 +04:00
case NAV_CMD_TAKEOFF :
2014-06-01 14:04:16 +02:00
mavlink_mission_item - > param1 = mission_item - > pitch_min ;
2014-03-01 00:16:51 +04:00
break ;
2014-04-09 18:39:23 +02:00
case NAV_CMD_DO_JUMP :
mavlink_mission_item - > param1 = mission_item - > do_jump_mission_index ;
2014-04-21 17:36:59 +02:00
mavlink_mission_item - > param2 = mission_item - > do_jump_repeat_count ;
2014-04-09 18:39:23 +02:00
break ;
2014-03-01 00:16:51 +04:00
default :
mavlink_mission_item - > param2 = mission_item - > acceptance_radius ;
2014-06-01 14:04:16 +02:00
mavlink_mission_item - > param1 = mission_item - > time_inside ;
2014-03-01 00:16:51 +04:00
break ;
2014-01-09 08:10:35 +01:00
}
mavlink_mission_item - > x = ( float ) mission_item - > lat ;
mavlink_mission_item - > y = ( float ) mission_item - > lon ;
mavlink_mission_item - > z = mission_item - > altitude ;
2014-03-01 00:16:51 +04:00
mavlink_mission_item - > param4 = mission_item - > yaw * M_RAD_TO_DEG_F ;
mavlink_mission_item - > param3 = mission_item - > loiter_radius * ( float ) mission_item - > loiter_direction ;
2014-01-09 08:10:35 +01:00
mavlink_mission_item - > command = mission_item - > nav_cmd ;
mavlink_mission_item - > autocontinue = mission_item - > autocontinue ;
// mavlink_mission_item->seq = mission_item->index;
return OK ;
}
2014-01-26 18:40:02 +01:00
void Mavlink : : mavlink_wpm_init ( mavlink_wpm_storage * state )
2014-01-09 08:10:35 +01:00
{
state - > size = 0 ;
state - > max_size = MAVLINK_WPM_MAX_WP_COUNT ;
state - > current_state = MAVLINK_WPM_STATE_IDLE ;
state - > current_partner_sysid = 0 ;
state - > current_partner_compid = 0 ;
state - > timestamp_lastaction = 0 ;
state - > timestamp_last_send_setpoint = 0 ;
2014-06-06 00:42:02 +02:00
state - > timestamp_last_send_request = 0 ;
2014-01-09 08:10:35 +01:00
state - > timeout = MAVLINK_WPM_PROTOCOL_TIMEOUT_DEFAULT ;
state - > current_dataman_id = 0 ;
}
/*
* @ brief Sends an waypoint ack message
*/
2014-01-26 18:40:02 +01:00
void Mavlink : : mavlink_wpm_send_waypoint_ack ( uint8_t sysid , uint8_t compid , uint8_t type )
2014-01-09 08:10:35 +01:00
{
mavlink_message_t msg ;
mavlink_mission_ack_t wpa ;
wpa . target_system = sysid ;
wpa . target_component = compid ;
wpa . type = type ;
2014-03-12 09:56:26 +01:00
mavlink_msg_mission_ack_encode_chan ( mavlink_system . sysid , _mavlink_wpm_comp_id , _channel , & msg , & wpa ) ;
2014-01-09 08:10:35 +01:00
mavlink_missionlib_send_message ( & msg ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " Sent waypoint ack (%u) to ID %u " , wpa . type , wpa . target_system ) ; }
2014-01-09 08:10:35 +01:00
}
/*
* @ brief Broadcasts the new target waypoint and directs the MAV to fly there
*
* This function broadcasts its new active waypoint sequence number and
* sends a message to the controller , advising it to fly to the coordinates
* of the waypoint with a given orientation
*
* @ param seq The waypoint sequence number the MAV should fly to .
*/
2014-01-26 18:40:02 +01:00
void Mavlink : : mavlink_wpm_send_waypoint_current ( uint16_t seq )
2014-01-09 08:10:35 +01:00
{
2014-03-01 18:30:30 +04:00
if ( seq < _wpm - > size ) {
2014-01-09 08:10:35 +01:00
mavlink_message_t msg ;
mavlink_mission_current_t wpc ;
wpc . seq = seq ;
2014-03-12 09:56:26 +01:00
mavlink_msg_mission_current_encode_chan ( mavlink_system . sysid , _mavlink_wpm_comp_id , _channel , & msg , & wpc ) ;
2014-01-09 08:10:35 +01:00
mavlink_missionlib_send_message ( & msg ) ;
2014-03-01 18:30:30 +04:00
} else if ( seq = = 0 & & _wpm - > size = = 0 ) {
2014-02-23 13:42:15 +01:00
/* don't broadcast if no WPs */
2014-01-09 08:10:35 +01:00
} else {
mavlink_missionlib_send_gcs_string ( " ERROR: wp index out of bounds " ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " ERROR: index out of bounds " ) ; }
2014-01-09 08:10:35 +01:00
}
}
2014-01-26 18:40:02 +01:00
void Mavlink : : mavlink_wpm_send_waypoint_count ( uint8_t sysid , uint8_t compid , uint16_t count )
2014-01-09 08:10:35 +01:00
{
mavlink_message_t msg ;
mavlink_mission_count_t wpc ;
wpc . target_system = sysid ;
wpc . target_component = compid ;
wpc . count = mission . count ;
2014-03-12 09:56:26 +01:00
mavlink_msg_mission_count_encode_chan ( mavlink_system . sysid , _mavlink_wpm_comp_id , _channel , & msg , & wpc ) ;
2014-01-09 08:10:35 +01:00
mavlink_missionlib_send_message ( & msg ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " Sent waypoint count (%u) to ID %u " , wpc . count , wpc . target_system ) ; }
2014-01-09 08:10:35 +01:00
}
2014-01-26 18:40:02 +01:00
void Mavlink : : mavlink_wpm_send_waypoint ( uint8_t sysid , uint8_t compid , uint16_t seq )
2014-01-09 08:10:35 +01:00
{
struct mission_item_s mission_item ;
ssize_t len = sizeof ( struct mission_item_s ) ;
2014-03-01 00:16:51 +04:00
2014-01-09 08:10:35 +01:00
dm_item_t dm_current ;
2014-03-01 18:30:30 +04:00
if ( _wpm - > current_dataman_id = = 0 ) {
2014-01-09 08:10:35 +01:00
dm_current = DM_KEY_WAYPOINTS_OFFBOARD_0 ;
2014-03-01 00:16:51 +04:00
2014-01-09 08:10:35 +01:00
} else {
dm_current = DM_KEY_WAYPOINTS_OFFBOARD_1 ;
}
if ( dm_read ( dm_current , seq , & mission_item , len ) = = len ) {
/* create mission_item_s from mavlink_mission_item_t */
mavlink_mission_item_t wp ;
map_mission_item_to_mavlink_mission_item ( & mission_item , & wp ) ;
mavlink_message_t msg ;
wp . target_system = sysid ;
wp . target_component = compid ;
wp . seq = seq ;
2014-03-12 09:56:26 +01:00
mavlink_msg_mission_item_encode_chan ( mavlink_system . sysid , _mavlink_wpm_comp_id , _channel , & msg , & wp ) ;
2014-01-09 08:10:35 +01:00
mavlink_missionlib_send_message ( & msg ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " Sent waypoint %u to ID %u " , wp . seq , wp . target_system ) ; }
2014-01-09 08:10:35 +01:00
} else {
2014-03-01 18:30:30 +04:00
mavlink_wpm_send_waypoint_ack ( _wpm - > current_partner_sysid , _wpm - > current_partner_compid , MAV_MISSION_ERROR ) ;
2014-06-03 16:43:15 +02:00
mavlink_missionlib_send_gcs_string ( " #audio: Unable to read from micro SD " ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " ERROR: could not read WP%u " , seq ) ; }
2014-01-09 08:10:35 +01:00
}
}
2014-01-26 18:40:02 +01:00
void Mavlink : : mavlink_wpm_send_waypoint_request ( uint8_t sysid , uint8_t compid , uint16_t seq )
2014-01-09 08:10:35 +01:00
{
2014-03-01 18:30:30 +04:00
if ( seq < _wpm - > max_size ) {
2014-01-09 08:10:35 +01:00
mavlink_message_t msg ;
mavlink_mission_request_t wpr ;
wpr . target_system = sysid ;
wpr . target_component = compid ;
wpr . seq = seq ;
2014-03-12 09:56:26 +01:00
mavlink_msg_mission_request_encode_chan ( mavlink_system . sysid , _mavlink_wpm_comp_id , _channel , & msg , & wpr ) ;
2014-01-09 08:10:35 +01:00
mavlink_missionlib_send_message ( & msg ) ;
2014-06-06 00:42:02 +02:00
_wpm - > timestamp_last_send_request = hrt_absolute_time ( ) ;
2014-01-09 08:10:35 +01:00
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " Sent waypoint request %u to ID %u " , wpr . seq , wpr . target_system ) ; }
2014-01-09 08:10:35 +01:00
} else {
mavlink_missionlib_send_gcs_string ( " ERROR: Waypoint index exceeds list capacity " ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " ERROR: Waypoint index exceeds list capacity " ) ; }
2014-01-09 08:10:35 +01:00
}
}
/*
* @ brief emits a message that a waypoint reached
*
* This function broadcasts a message that a waypoint is reached .
*
* @ param seq The waypoint sequence number the MAV has reached .
*/
2014-01-26 18:40:02 +01:00
void Mavlink : : mavlink_wpm_send_waypoint_reached ( uint16_t seq )
2014-01-09 08:10:35 +01:00
{
mavlink_message_t msg ;
mavlink_mission_item_reached_t wp_reached ;
wp_reached . seq = seq ;
2014-03-12 09:56:26 +01:00
mavlink_msg_mission_item_reached_encode_chan ( mavlink_system . sysid , _mavlink_wpm_comp_id , _channel , & msg , & wp_reached ) ;
2014-01-09 08:10:35 +01:00
mavlink_missionlib_send_message ( & msg ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " Sent waypoint %u reached message " , wp_reached . seq ) ; }
2014-01-09 08:10:35 +01:00
}
2014-01-26 18:40:02 +01:00
void Mavlink : : mavlink_waypoint_eventloop ( uint64_t now )
2014-01-09 08:10:35 +01:00
{
/* check for timed-out operations */
2014-03-01 18:30:30 +04:00
if ( now - _wpm - > timestamp_lastaction > _wpm - > timeout & & _wpm - > current_state ! = MAVLINK_WPM_STATE_IDLE ) {
2014-01-09 08:10:35 +01:00
mavlink_missionlib_send_gcs_string ( " Operation timeout " ) ;
2014-03-01 18:30:30 +04:00
if ( _verbose ) { warnx ( " Last operation (state=%u) timed out, changing state to MAVLINK_WPM_STATE_IDLE " , _wpm - > current_state ) ; }
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
_wpm - > current_state = MAVLINK_WPM_STATE_IDLE ;
_wpm - > current_partner_sysid = 0 ;
_wpm - > current_partner_compid = 0 ;
2014-06-06 00:42:02 +02:00
} else if ( now - _wpm - > timestamp_last_send_request > 500000 & & _wpm - > current_state = = MAVLINK_WPM_STATE_GETLIST_GETWPS ) {
/* try to get WP again after short timeout */
mavlink_wpm_send_waypoint_request ( _wpm - > current_partner_sysid , _wpm - > current_partner_compid , _wpm - > current_wp_id ) ;
2014-01-09 08:10:35 +01:00
}
}
2014-01-26 18:40:02 +01:00
void Mavlink : : mavlink_wpm_message_handler ( const mavlink_message_t * msg )
2014-01-09 08:10:35 +01:00
{
uint64_t now = hrt_absolute_time ( ) ;
switch ( msg - > msgid ) {
2014-03-01 00:16:51 +04:00
case MAVLINK_MSG_ID_MISSION_ACK : {
2014-01-09 08:10:35 +01:00
mavlink_mission_ack_t wpa ;
mavlink_msg_mission_ack_decode ( msg , & wpa ) ;
2014-03-01 18:30:30 +04:00
if ( ( msg - > sysid = = _wpm - > current_partner_sysid & & msg - > compid = = _wpm - > current_partner_compid ) & & ( wpa . target_system = = mavlink_system . sysid /*&& wpa.target_component == mavlink_wpm_comp_id*/ ) ) {
_wpm - > timestamp_lastaction = now ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
if ( _wpm - > current_state = = MAVLINK_WPM_STATE_SENDLIST | | _wpm - > current_state = = MAVLINK_WPM_STATE_SENDLIST_SENDWPS ) {
if ( _wpm - > current_wp_id = = _wpm - > size - 1 ) {
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
_wpm - > current_state = MAVLINK_WPM_STATE_IDLE ;
_wpm - > current_wp_id = 0 ;
2014-01-09 08:10:35 +01:00
}
}
} else {
mavlink_missionlib_send_gcs_string ( " REJ. WP CMD: curr partner id mismatch " ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " REJ. WP CMD: curr partner id mismatch " ) ; }
2014-01-09 08:10:35 +01:00
}
break ;
}
2014-03-01 00:16:51 +04:00
case MAVLINK_MSG_ID_MISSION_SET_CURRENT : {
2014-01-09 08:10:35 +01:00
mavlink_mission_set_current_t wpc ;
mavlink_msg_mission_set_current_decode ( msg , & wpc ) ;
if ( wpc . target_system = = mavlink_system . sysid /*&& wpc.target_component == mavlink_wpm_comp_id*/ ) {
2014-03-01 18:30:30 +04:00
_wpm - > timestamp_lastaction = now ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
if ( _wpm - > current_state = = MAVLINK_WPM_STATE_IDLE ) {
if ( wpc . seq < _wpm - > size ) {
2014-01-09 08:10:35 +01:00
mission . current_index = wpc . seq ;
publish_mission ( ) ;
2014-03-01 00:16:51 +04:00
2014-02-24 15:17:13 +01:00
/* don't answer yet, wait for the navigator to respond, then publish the mission_result */
// mavlink_wpm_send_waypoint_current(wpc.seq);
2014-01-09 08:10:35 +01:00
} else {
mavlink_missionlib_send_gcs_string ( " IGN WP CURR CMD: Not in list " ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " IGN WP CURR CMD: Not in list " ) ; }
2014-01-09 08:10:35 +01:00
}
} else {
mavlink_missionlib_send_gcs_string ( " IGN WP CURR CMD: Busy " ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " IGN WP CURR CMD: Busy " ) ; }
2014-01-09 08:10:35 +01:00
}
}
break ;
}
2014-03-01 00:16:51 +04:00
case MAVLINK_MSG_ID_MISSION_REQUEST_LIST : {
2014-01-09 08:10:35 +01:00
mavlink_mission_request_list_t wprl ;
mavlink_msg_mission_request_list_decode ( msg , & wprl ) ;
if ( wprl . target_system = = mavlink_system . sysid /*&& wprl.target_component == mavlink_wpm_comp_id*/ ) {
2014-03-01 18:30:30 +04:00
_wpm - > timestamp_lastaction = now ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
if ( _wpm - > current_state = = MAVLINK_WPM_STATE_IDLE | | _wpm - > current_state = = MAVLINK_WPM_STATE_SENDLIST ) {
if ( _wpm - > size > 0 ) {
2014-03-01 00:16:51 +04:00
2014-03-01 18:30:30 +04:00
_wpm - > current_state = MAVLINK_WPM_STATE_SENDLIST ;
_wpm - > current_wp_id = 0 ;
_wpm - > current_partner_sysid = msg - > sysid ;
_wpm - > current_partner_compid = msg - > compid ;
2014-01-09 08:10:35 +01:00
} else {
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " No waypoints send " ) ; }
2014-01-09 08:10:35 +01:00
}
2014-03-01 18:30:30 +04:00
_wpm - > current_count = _wpm - > size ;
mavlink_wpm_send_waypoint_count ( msg - > sysid , msg - > compid , _wpm - > current_count ) ;
2014-01-09 08:10:35 +01:00
} else {
mavlink_missionlib_send_gcs_string ( " IGN REQUEST LIST: Busy " ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " IGN REQUEST LIST: Busy " ) ; }
2014-01-09 08:10:35 +01:00
}
}
break ;
}
2014-03-01 00:16:51 +04:00
case MAVLINK_MSG_ID_MISSION_REQUEST : {
2014-01-09 08:10:35 +01:00
mavlink_mission_request_t wpr ;
mavlink_msg_mission_request_decode ( msg , & wpr ) ;
2014-03-01 18:30:30 +04:00
if ( msg - > sysid = = _wpm - > current_partner_sysid & & msg - > compid = = _wpm - > current_partner_compid & & wpr . target_system = = mavlink_system . sysid /*&& wpr.target_component == mavlink_wpm_comp_id*/ ) {
_wpm - > timestamp_lastaction = now ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
if ( wpr . seq > = _wpm - > size ) {
2014-01-09 08:10:35 +01:00
mavlink_missionlib_send_gcs_string ( " REJ. WP CMD: Req. WP not in list " ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " Ignored MAVLINK_MSG_ID_MISSION_ITEM_REQUEST because the requested waypoint ID (%u) was out of bounds. " , wpr . seq ) ; }
2014-01-09 08:10:35 +01:00
break ;
}
2014-03-01 00:16:51 +04:00
/*
* Ensure that we are in the correct state and that the first request has id 0
2014-01-09 08:10:35 +01:00
* and the following requests have either the last id ( re - send last waypoint ) or last_id + 1 ( next waypoint )
*/
2014-03-01 18:30:30 +04:00
if ( _wpm - > current_state = = MAVLINK_WPM_STATE_SENDLIST ) {
2014-01-09 08:10:35 +01:00
if ( wpr . seq = = 0 ) {
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " Got MAVLINK_MSG_ID_MISSION_ITEM_REQUEST of waypoint %u from %u changing state to MAVLINK_WPM_STATE_SENDLIST_SENDWPS " , wpr . seq , msg - > sysid ) ; }
2014-03-01 18:30:30 +04:00
_wpm - > current_state = MAVLINK_WPM_STATE_SENDLIST_SENDWPS ;
2014-03-01 00:16:51 +04:00
2014-01-09 08:10:35 +01:00
} else {
mavlink_missionlib_send_gcs_string ( " REJ. WP CMD: First id != 0 " ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " REJ. WP CMD: First id != 0 " ) ; }
2014-01-09 08:10:35 +01:00
break ;
}
2014-03-01 18:30:30 +04:00
} else if ( _wpm - > current_state = = MAVLINK_WPM_STATE_SENDLIST_SENDWPS ) {
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
if ( wpr . seq = = _wpm - > current_wp_id ) {
2014-01-09 08:10:35 +01:00
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " Got MAVLINK_MSG_ID_MISSION_ITEM_REQUEST of waypoint %u (again) from %u staying in state MAVLINK_WPM_STATE_SENDLIST_SENDWPS " , wpr . seq , msg - > sysid ) ; }
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
} else if ( wpr . seq = = _wpm - > current_wp_id + 1 ) {
2014-01-09 08:10:35 +01:00
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " Got MAVLINK_MSG_ID_MISSION_ITEM_REQUEST of waypoint %u from %u staying in state MAVLINK_WPM_STATE_SENDLIST_SENDWPS " , wpr . seq , msg - > sysid ) ; }
2014-01-09 08:10:35 +01:00
} else {
mavlink_missionlib_send_gcs_string ( " REJ. WP CMD: Req. WP was unexpected " ) ;
2014-03-01 00:16:51 +04:00
2014-03-01 18:30:30 +04:00
if ( _verbose ) { warnx ( " Ignored MAVLINK_MSG_ID_MISSION_ITEM_REQUEST because the requested waypoint ID (%u) was not the expected (%u or %u). " , wpr . seq , _wpm - > current_wp_id , _wpm - > current_wp_id + 1 ) ; }
2014-03-01 00:16:51 +04:00
2014-01-09 08:10:35 +01:00
break ;
}
} else {
mavlink_missionlib_send_gcs_string ( " REJ. WP CMD: Busy " ) ;
2014-03-01 00:16:51 +04:00
2014-03-01 18:30:30 +04:00
if ( _verbose ) { warnx ( " Ignored MAVLINK_MSG_ID_MISSION_ITEM_REQUEST because i'm doing something else already (state=%i). " , _wpm - > current_state ) ; }
2014-03-01 00:16:51 +04:00
2014-01-09 08:10:35 +01:00
break ;
}
2014-03-01 18:30:30 +04:00
_wpm - > current_wp_id = wpr . seq ;
_wpm - > current_state = MAVLINK_WPM_STATE_SENDLIST_SENDWPS ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
if ( wpr . seq < _wpm - > size ) {
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
mavlink_wpm_send_waypoint ( _wpm - > current_partner_sysid , _wpm - > current_partner_compid , _wpm - > current_wp_id ) ;
2014-01-09 08:10:35 +01:00
} else {
2014-03-01 18:30:30 +04:00
mavlink_wpm_send_waypoint_ack ( _wpm - > current_partner_sysid , _wpm - > current_partner_compid , MAV_MISSION_ERROR ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " ERROR: Waypoint %u out of bounds " , wpr . seq ) ; }
2014-01-09 08:10:35 +01:00
}
} else {
//we we're target but already communicating with someone else
2014-03-01 18:30:30 +04:00
if ( ( wpr . target_system = = mavlink_system . sysid /*&& wpr.target_component == mavlink_wpm_comp_id*/ ) & & ! ( msg - > sysid = = _wpm - > current_partner_sysid & & msg - > compid = = _wpm - > current_partner_compid ) ) {
2014-01-09 08:10:35 +01:00
mavlink_missionlib_send_gcs_string ( " REJ. WP CMD: Busy " ) ;
2014-03-01 00:16:51 +04:00
2014-03-01 18:30:30 +04:00
if ( _verbose ) { warnx ( " Ignored MAVLINK_MSG_ID_MISSION_ITEM_REQUEST from ID %u because i'm already talking to ID %u. " , msg - > sysid , _wpm - > current_partner_sysid ) ; }
2014-01-09 08:10:35 +01:00
}
}
2014-03-01 00:16:51 +04:00
2014-01-09 08:10:35 +01:00
break ;
}
2014-03-01 00:16:51 +04:00
case MAVLINK_MSG_ID_MISSION_COUNT : {
2014-01-09 08:10:35 +01:00
mavlink_mission_count_t wpc ;
mavlink_msg_mission_count_decode ( msg , & wpc ) ;
if ( wpc . target_system = = mavlink_system . sysid /* && wpc.target_component == mavlink_wpm_comp_id*/ ) {
2014-03-01 18:30:30 +04:00
_wpm - > timestamp_lastaction = now ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
if ( _wpm - > current_state = = MAVLINK_WPM_STATE_IDLE ) {
2014-01-09 08:10:35 +01:00
if ( wpc . count > NUM_MISSIONS_SUPPORTED ) {
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " Too many waypoints: %d, supported: %d " , wpc . count , NUM_MISSIONS_SUPPORTED ) ; }
2014-03-01 18:30:30 +04:00
mavlink_wpm_send_waypoint_ack ( _wpm - > current_partner_sysid , _wpm - > current_partner_compid , MAV_MISSION_NO_SPACE ) ;
2014-01-09 08:10:35 +01:00
break ;
}
if ( wpc . count = = 0 ) {
mavlink_missionlib_send_gcs_string ( " COUNT 0 " ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " got waypoint count of 0, clearing waypoint list and staying in state MAVLINK_WPM_STATE_IDLE " ) ; }
2014-01-09 08:10:35 +01:00
break ;
}
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " Got MAVLINK_MSG_ID_MISSION_ITEM_COUNT (%u) from %u changing state to MAVLINK_WPM_STATE_GETLIST " , wpc . count , msg - > sysid ) ; }
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
_wpm - > current_state = MAVLINK_WPM_STATE_GETLIST ;
_wpm - > current_wp_id = 0 ;
_wpm - > current_partner_sysid = msg - > sysid ;
_wpm - > current_partner_compid = msg - > compid ;
_wpm - > current_count = wpc . count ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
mavlink_wpm_send_waypoint_request ( _wpm - > current_partner_sysid , _wpm - > current_partner_compid , _wpm - > current_wp_id ) ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
} else if ( _wpm - > current_state = = MAVLINK_WPM_STATE_GETLIST ) {
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
if ( _wpm - > current_wp_id = = 0 ) {
2014-01-09 08:10:35 +01:00
mavlink_missionlib_send_gcs_string ( " WP CMD OK AGAIN " ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " Got MAVLINK_MSG_ID_MISSION_ITEM_COUNT (%u) again from %u " , wpc . count , msg - > sysid ) ; }
2014-01-09 08:10:35 +01:00
} else {
mavlink_missionlib_send_gcs_string ( " REJ. WP CMD: Busy " ) ;
2014-03-01 00:16:51 +04:00
2014-03-01 18:30:30 +04:00
if ( _verbose ) { warnx ( " Ignored MAVLINK_MSG_ID_MISSION_ITEM_COUNT because i'm already receiving waypoint %u. " , _wpm - > current_wp_id ) ; }
2014-01-09 08:10:35 +01:00
}
2014-03-01 00:16:51 +04:00
2014-01-09 08:10:35 +01:00
} else {
2014-03-01 00:16:51 +04:00
mavlink_missionlib_send_gcs_string ( " IGN MISSION_COUNT CMD: Busy " ) ;
if ( _verbose ) { warnx ( " IGN MISSION_COUNT CMD: Busy " ) ; }
2014-01-09 08:10:35 +01:00
}
}
}
break ;
2014-03-01 00:16:51 +04:00
case MAVLINK_MSG_ID_MISSION_ITEM : {
2014-01-09 08:10:35 +01:00
mavlink_mission_item_t wp ;
mavlink_msg_mission_item_decode ( msg , & wp ) ;
2014-02-14 13:36:59 +01:00
if ( wp . target_system = = mavlink_system . sysid & & wp . target_component = = _mavlink_wpm_comp_id ) {
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
_wpm - > timestamp_lastaction = now ;
2014-01-09 08:10:35 +01:00
/*
* ensure that we are in the correct state and that the first waypoint has id 0
* and the following waypoints have the correct ids
*/
2014-03-01 18:30:30 +04:00
if ( _wpm - > current_state = = MAVLINK_WPM_STATE_GETLIST ) {
2014-01-09 08:10:35 +01:00
2014-03-01 00:16:51 +04:00
if ( wp . seq ! = 0 ) {
mavlink_missionlib_send_gcs_string ( " Ignored MISSION_ITEM WP not 0 " ) ;
warnx ( " Ignored MAVLINK_MSG_ID_MISSION_ITEM because the first waypoint ID (%u) was not 0. " , wp . seq ) ;
break ;
}
2014-03-01 18:30:30 +04:00
} else if ( _wpm - > current_state = = MAVLINK_WPM_STATE_GETLIST_GETWPS ) {
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
if ( wp . seq > = _wpm - > current_count ) {
2014-01-09 08:10:35 +01:00
mavlink_missionlib_send_gcs_string ( " Ignored MISSION_ITEM WP out of bounds " ) ;
warnx ( " Ignored MAVLINK_MSG_ID_MISSION_ITEM because the waypoint ID (%u) was out of bounds. " , wp . seq ) ;
break ;
}
2014-03-01 18:30:30 +04:00
if ( wp . seq ! = _wpm - > current_wp_id ) {
warnx ( " Ignored MAVLINK_MSG_ID_MISSION_ITEM because the waypoint ID (%u) was not the expected %u. " , wp . seq , _wpm - > current_wp_id ) ;
mavlink_wpm_send_waypoint_request ( _wpm - > current_partner_sysid , _wpm - > current_partner_compid , _wpm - > current_wp_id ) ;
2014-01-09 08:10:35 +01:00
break ;
}
}
2014-03-01 18:30:30 +04:00
_wpm - > current_state = MAVLINK_WPM_STATE_GETLIST_GETWPS ;
2014-01-09 08:10:35 +01:00
struct mission_item_s mission_item ;
int ret = map_mavlink_mission_item_to_mission_item ( & wp , & mission_item ) ;
if ( ret ! = OK ) {
2014-03-01 18:30:30 +04:00
mavlink_wpm_send_waypoint_ack ( _wpm - > current_partner_sysid , _wpm - > current_partner_compid , ret ) ;
_wpm - > current_state = MAVLINK_WPM_STATE_IDLE ;
2014-01-09 08:10:35 +01:00
break ;
}
ssize_t len = sizeof ( struct mission_item_s ) ;
dm_item_t dm_next ;
2014-03-01 18:30:30 +04:00
if ( _wpm - > current_dataman_id = = 0 ) {
2014-01-09 08:10:35 +01:00
dm_next = DM_KEY_WAYPOINTS_OFFBOARD_1 ;
mission . dataman_id = 1 ;
2014-03-01 00:16:51 +04:00
2014-01-09 08:10:35 +01:00
} else {
dm_next = DM_KEY_WAYPOINTS_OFFBOARD_0 ;
mission . dataman_id = 0 ;
}
if ( dm_write ( dm_next , wp . seq , DM_PERSIST_IN_FLIGHT_RESET , & mission_item , len ) ! = len ) {
2014-03-01 18:30:30 +04:00
mavlink_wpm_send_waypoint_ack ( _wpm - > current_partner_sysid , _wpm - > current_partner_compid , MAV_MISSION_ERROR ) ;
2014-06-03 16:43:15 +02:00
mavlink_missionlib_send_gcs_string ( " #audio: Unable to write on micro SD " ) ;
2014-03-01 18:30:30 +04:00
_wpm - > current_state = MAVLINK_WPM_STATE_IDLE ;
2014-01-09 08:10:35 +01:00
break ;
}
2014-02-15 11:29:36 +01:00
// if (wp.current) {
// warnx("current is: %d", wp.seq);
// mission.current_index = wp.seq;
// }
// XXX ignore current set
mission . current_index = - 1 ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
_wpm - > current_wp_id = wp . seq + 1 ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
if ( _wpm - > current_wp_id = = _wpm - > current_count & & _wpm - > current_state = = MAVLINK_WPM_STATE_GETLIST_GETWPS ) {
2014-03-01 00:16:51 +04:00
2014-03-01 18:30:30 +04:00
if ( _verbose ) { warnx ( " Got all %u waypoints, changing state to MAVLINK_WPM_STATE_IDLE " , _wpm - > current_count ) ; }
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
mavlink_wpm_send_waypoint_ack ( _wpm - > current_partner_sysid , _wpm - > current_partner_compid , MAV_MISSION_ACCEPTED ) ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
mission . count = _wpm - > current_count ;
2014-03-01 00:16:51 +04:00
2014-01-09 08:10:35 +01:00
publish_mission ( ) ;
2014-03-01 18:30:30 +04:00
_wpm - > current_dataman_id = mission . dataman_id ;
_wpm - > size = _wpm - > current_count ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
_wpm - > current_state = MAVLINK_WPM_STATE_IDLE ;
2014-01-09 08:10:35 +01:00
} else {
2014-03-01 18:30:30 +04:00
mavlink_wpm_send_waypoint_request ( _wpm - > current_partner_sysid , _wpm - > current_partner_compid , _wpm - > current_wp_id ) ;
2014-01-09 08:10:35 +01:00
}
}
break ;
}
2014-03-01 00:16:51 +04:00
case MAVLINK_MSG_ID_MISSION_CLEAR_ALL : {
2014-01-09 08:10:35 +01:00
mavlink_mission_clear_all_t wpca ;
mavlink_msg_mission_clear_all_decode ( msg , & wpca ) ;
if ( wpca . target_system = = mavlink_system . sysid /*&& wpca.target_component == mavlink_wpm_comp_id */ ) {
2014-03-01 18:30:30 +04:00
if ( _wpm - > current_state = = MAVLINK_WPM_STATE_IDLE ) {
_wpm - > timestamp_lastaction = now ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
_wpm - > size = 0 ;
2014-01-09 08:10:35 +01:00
/* prepare mission topic */
mission . dataman_id = - 1 ;
mission . count = 0 ;
mission . current_index = - 1 ;
publish_mission ( ) ;
if ( dm_clear ( DM_KEY_WAYPOINTS_OFFBOARD_0 ) = = OK & & dm_clear ( DM_KEY_WAYPOINTS_OFFBOARD_1 ) = = OK ) {
2014-03-01 18:30:30 +04:00
mavlink_wpm_send_waypoint_ack ( _wpm - > current_partner_sysid , _wpm - > current_partner_compid , MAV_MISSION_ACCEPTED ) ;
2014-03-01 00:16:51 +04:00
2014-01-09 08:10:35 +01:00
} else {
2014-03-01 18:30:30 +04:00
mavlink_wpm_send_waypoint_ack ( _wpm - > current_partner_sysid , _wpm - > current_partner_compid , MAV_MISSION_ERROR ) ;
2014-01-09 08:10:35 +01:00
}
2014-03-01 00:16:51 +04:00
2014-01-09 08:10:35 +01:00
} else {
mavlink_missionlib_send_gcs_string ( " IGN WP CLEAR CMD: Busy " ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " IGN WP CLEAR CMD: Busy " ) ; }
2014-01-09 08:10:35 +01:00
}
}
break ;
}
default : {
/* other messages might should get caught by mavlink and others */
break ;
}
}
}
void
2014-01-26 18:40:02 +01:00
Mavlink : : mavlink_missionlib_send_message ( mavlink_message_t * msg )
2014-01-09 08:10:35 +01:00
{
2014-05-15 07:25:23 +02:00
uint8_t missionlib_msg_buf [ MAVLINK_MAX_PACKET_LEN ] ;
2014-01-09 08:10:35 +01:00
uint16_t len = mavlink_msg_to_send_buffer ( missionlib_msg_buf , msg ) ;
2014-02-27 13:54:55 +04:00
mavlink_send_uart_bytes ( _channel , missionlib_msg_buf , len ) ;
2014-01-09 08:10:35 +01:00
}
int
2014-01-26 18:40:02 +01:00
Mavlink : : mavlink_missionlib_send_gcs_string ( const char * string )
2014-01-09 08:10:35 +01:00
{
const int len = MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN ;
mavlink_statustext_t statustext ;
2014-05-07 14:12:48 +02:00
statustext . severity = MAV_SEVERITY_INFO ;
2014-01-09 08:10:35 +01:00
int i = 0 ;
while ( i < len - 1 ) {
statustext . text [ i ] = string [ i ] ;
2014-03-01 00:16:51 +04:00
if ( string [ i ] = = ' \0 ' ) {
2014-01-09 08:10:35 +01:00
break ;
2014-03-01 00:16:51 +04:00
}
2014-01-09 08:10:35 +01:00
i + + ;
}
if ( i > 1 ) {
/* Enforce null termination */
statustext . text [ i ] = ' \0 ' ;
2014-03-11 23:03:49 +04:00
mavlink_msg_statustext_send ( _channel , statustext . severity , statustext . text ) ;
2014-01-09 08:10:35 +01:00
return OK ;
} else {
return 1 ;
}
}
2014-03-01 16:43:04 +04:00
MavlinkOrbSubscription * Mavlink : : add_orb_subscription ( const orb_id_t topic )
2014-02-26 00:24:14 +04:00
{
/* check if already subscribed to this topic */
MavlinkOrbSubscription * sub ;
LL_FOREACH ( _subscriptions , sub ) {
2014-02-26 21:28:35 +04:00
if ( sub - > get_topic ( ) = = topic ) {
2014-02-26 00:24:14 +04:00
/* already subscribed */
return sub ;
}
}
/* add new subscription */
2014-03-01 16:43:04 +04:00
MavlinkOrbSubscription * sub_new = new MavlinkOrbSubscription ( topic ) ;
2014-02-26 00:24:14 +04:00
LL_APPEND ( _subscriptions , sub_new ) ;
return sub_new ;
}
int
2014-02-28 00:45:59 +04:00
Mavlink : : configure_stream ( const char * stream_name , const float rate )
2014-02-26 00:24:14 +04:00
{
2014-03-01 19:42:29 +04:00
/* calculate interval in us, 0 means disabled stream */
unsigned int interval = ( rate > 0.0f ) ? ( 1000000.0f / rate ) : 0 ;
2014-02-28 00:45:59 +04:00
/* search if stream exists */
MavlinkStream * stream ;
LL_FOREACH ( _streams , stream ) {
if ( strcmp ( stream_name , stream - > get_name ( ) ) = = 0 ) {
if ( interval > 0 ) {
/* set new interval */
stream - > set_interval ( interval ) ;
} else {
/* delete stream */
LL_DELETE ( _streams , stream ) ;
delete stream ;
}
2014-03-01 00:16:51 +04:00
2014-02-26 00:24:14 +04:00
return OK ;
}
}
2014-02-28 00:45:59 +04:00
if ( interval > 0 ) {
/* search for stream with specified name in supported streams list */
for ( unsigned int i = 0 ; streams_list [ i ] ! = nullptr ; i + + ) {
if ( strcmp ( stream_name , streams_list [ i ] - > get_name ( ) ) = = 0 ) {
/* create new instance */
stream = streams_list [ i ] - > new_instance ( ) ;
stream - > set_channel ( get_channel ( ) ) ;
stream - > set_interval ( interval ) ;
stream - > subscribe ( this ) ;
LL_APPEND ( _streams , stream ) ;
return OK ;
}
}
} else {
/* stream not found, nothing to disable */
return OK ;
}
2014-02-26 00:24:14 +04:00
return ERROR ;
}
2014-03-01 16:43:04 +04:00
void
Mavlink : : configure_stream_threadsafe ( const char * stream_name , const float rate )
{
/* orb subscription must be done from the main thread,
* set _subscribe_to_stream and _subscribe_to_stream_rate fields
* which polled in mavlink main loop */
if ( ! _task_should_exit ) {
/* wait for previous subscription completion */
while ( _subscribe_to_stream ! = nullptr ) {
usleep ( MAIN_LOOP_DELAY / 2 ) ;
}
/* copy stream name */
unsigned n = strlen ( stream_name ) + 1 ;
char * s = new char [ n ] ;
2014-03-14 14:40:54 +01:00
strcpy ( s , stream_name ) ;
2014-03-01 16:43:04 +04:00
/* set subscription task */
_subscribe_to_stream_rate = rate ;
_subscribe_to_stream = s ;
/* wait for subscription */
do {
usleep ( MAIN_LOOP_DELAY / 2 ) ;
} while ( _subscribe_to_stream ! = nullptr ) ;
}
}
2014-04-03 21:15:47 +02:00
int
Mavlink : : message_buffer_init ( int size )
{
_message_buffer . size = size ;
_message_buffer . write_ptr = 0 ;
_message_buffer . read_ptr = 0 ;
_message_buffer . data = ( char * ) malloc ( _message_buffer . size ) ;
return ( _message_buffer . data = = 0 ) ? ERROR : OK ;
}
void
Mavlink : : message_buffer_destroy ( )
{
_message_buffer . size = 0 ;
_message_buffer . write_ptr = 0 ;
_message_buffer . read_ptr = 0 ;
free ( _message_buffer . data ) ;
}
int
Mavlink : : message_buffer_count ( )
{
int n = _message_buffer . write_ptr - _message_buffer . read_ptr ;
if ( n < 0 ) {
n + = _message_buffer . size ;
}
return n ;
}
int
Mavlink : : message_buffer_is_empty ( )
{
return _message_buffer . read_ptr = = _message_buffer . write_ptr ;
}
bool
Mavlink : : message_buffer_write ( void * ptr , int size )
{
// bytes available to write
int available = _message_buffer . read_ptr - _message_buffer . write_ptr - 1 ;
if ( available < 0 ) {
available + = _message_buffer . size ;
}
if ( size > available ) {
// buffer overflow
return false ;
}
char * c = ( char * ) ptr ;
int n = _message_buffer . size - _message_buffer . write_ptr ; // bytes to end of the buffer
if ( n < size ) {
// message goes over end of the buffer
memcpy ( & ( _message_buffer . data [ _message_buffer . write_ptr ] ) , c , n ) ;
_message_buffer . write_ptr = 0 ;
} else {
n = 0 ;
}
// now: n = bytes already written
int p = size - n ; // number of bytes to write
memcpy ( & ( _message_buffer . data [ _message_buffer . write_ptr ] ) , & ( c [ n ] ) , p ) ;
_message_buffer . write_ptr = ( _message_buffer . write_ptr + p ) % _message_buffer . size ;
return true ;
}
int
Mavlink : : message_buffer_get_ptr ( void * * ptr , bool * is_part )
{
// bytes available to read
int available = _message_buffer . write_ptr - _message_buffer . read_ptr ;
if ( available = = 0 ) {
return 0 ; // buffer is empty
}
int n = 0 ;
if ( available > 0 ) {
// read pointer is before write pointer, all available bytes can be read
n = available ;
* is_part = false ;
} else {
// read pointer is after write pointer, read bytes from read_ptr to end of the buffer
n = _message_buffer . size - _message_buffer . read_ptr ;
* is_part = _message_buffer . write_ptr > 0 ;
}
* ptr = & ( _message_buffer . data [ _message_buffer . read_ptr ] ) ;
return n ;
}
void
Mavlink : : message_buffer_mark_read ( int n )
{
_message_buffer . read_ptr = ( _message_buffer . read_ptr + n ) % _message_buffer . size ;
}
void
Mavlink : : pass_message ( mavlink_message_t * msg )
{
if ( _passing_on ) {
/* size is 8 bytes plus variable payload */
int size = MAVLINK_NUM_NON_PAYLOAD_BYTES + msg - > len ;
pthread_mutex_lock ( & _message_buffer_mutex ) ;
message_buffer_write ( msg , size ) ;
pthread_mutex_unlock ( & _message_buffer_mutex ) ;
}
}
2014-01-26 18:40:02 +01:00
int
Mavlink : : task_main ( int argc , char * argv [ ] )
2014-01-09 08:10:35 +01:00
{
int ch ;
2014-02-02 11:06:53 +01:00
_baudrate = 57600 ;
2014-02-27 18:31:41 +04:00
_datarate = 0 ;
2014-03-11 23:03:49 +04:00
_mode = MAVLINK_MODE_NORMAL ;
2014-02-11 22:36:36 +01:00
2014-02-02 11:06:53 +01:00
/* work around some stupidity in task_create's argv handling */
argc - = 2 ;
argv + = 2 ;
2014-01-09 08:10:35 +01:00
2014-02-28 00:45:59 +04:00
/* don't exit from getopt loop to leave getopt global variables in consistent state,
* set error flag instead */
bool err_flag = false ;
2014-04-10 10:26:15 +02:00
while ( ( ch = getopt ( argc , argv , " b:r:d:m:fpvw " ) ) ! = EOF ) {
2014-02-02 11:06:53 +01:00
switch ( ch ) {
case ' b ' :
_baudrate = strtoul ( optarg , NULL , 10 ) ;
2014-03-01 00:16:51 +04:00
2014-02-28 00:45:59 +04:00
if ( _baudrate < 9600 | | _baudrate > 921600 ) {
warnx ( " invalid baud rate '%s' " , optarg ) ;
err_flag = true ;
}
2014-03-01 00:16:51 +04:00
2014-02-02 11:06:53 +01:00
break ;
2014-01-09 08:10:35 +01:00
2014-02-27 18:31:41 +04:00
case ' r ' :
_datarate = strtoul ( optarg , NULL , 10 ) ;
2014-03-01 00:16:51 +04:00
2014-02-28 00:45:59 +04:00
if ( _datarate < 10 | | _datarate > MAX_DATA_RATE ) {
warnx ( " invalid data rate '%s' " , optarg ) ;
err_flag = true ;
}
2014-03-01 00:16:51 +04:00
2014-02-27 18:31:41 +04:00
break ;
2014-02-02 11:06:53 +01:00
case ' d ' :
2014-03-01 18:30:30 +04:00
_device_name = optarg ;
2014-02-02 11:06:53 +01:00
break ;
2014-01-09 08:10:35 +01:00
2014-02-13 19:13:10 +01:00
// case 'e':
// mavlink_link_termination_allowed = true;
// break;
2014-01-09 08:10:35 +01:00
2014-02-27 18:31:41 +04:00
case ' m ' :
2014-03-11 23:03:49 +04:00
if ( strcmp ( optarg , " custom " ) = = 0 ) {
_mode = MAVLINK_MODE_CUSTOM ;
2014-03-21 20:06:34 +04:00
2014-03-17 20:12:12 +01:00
} else if ( strcmp ( optarg , " camera " ) = = 0 ) {
_mode = MAVLINK_MODE_CAMERA ;
2014-02-27 18:31:41 +04:00
}
2014-03-01 00:16:51 +04:00
2014-02-02 11:06:53 +01:00
break ;
2014-01-09 08:10:35 +01:00
2014-04-03 21:15:47 +02:00
case ' f ' :
_forwarding_on = true ;
break ;
case ' p ' :
_passing_on = true ;
break ;
2014-02-15 11:29:36 +01:00
case ' v ' :
_verbose = true ;
2014-02-23 13:42:15 +01:00
break ;
2014-02-15 11:29:36 +01:00
2014-04-10 10:26:15 +02:00
case ' w ' :
_wait_to_transmit = true ;
break ;
2014-02-02 11:06:53 +01:00
default :
2014-02-28 00:45:59 +04:00
err_flag = true ;
2014-02-02 11:06:53 +01:00
break ;
}
}
2014-01-09 08:10:35 +01:00
2014-02-28 00:45:59 +04:00
if ( err_flag ) {
usage ( ) ;
2014-03-11 15:34:27 +04:00
return ERROR ;
2014-02-28 00:45:59 +04:00
}
2014-02-27 18:31:41 +04:00
if ( _datarate = = 0 ) {
/* convert bits to bytes and use 1/2 of bandwidth by default */
_datarate = _baudrate / 20 ;
2014-02-12 19:13:57 +01:00
}
2014-02-27 18:31:41 +04:00
if ( _datarate > MAX_DATA_RATE ) {
_datarate = MAX_DATA_RATE ;
}
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
if ( Mavlink : : instance_exists ( _device_name , this ) ) {
2014-03-11 15:34:27 +04:00
warnx ( " mavlink instance for %s already running " , _device_name ) ;
return ERROR ;
2014-02-27 18:31:41 +04:00
}
2014-01-09 08:10:35 +01:00
/* inform about mode */
2014-02-11 22:36:36 +01:00
switch ( _mode ) {
2014-03-11 23:03:49 +04:00
case MAVLINK_MODE_NORMAL :
warnx ( " mode: NORMAL " ) ;
2014-03-01 00:16:51 +04:00
break ;
2014-03-11 23:03:49 +04:00
case MAVLINK_MODE_CUSTOM :
warnx ( " mode: CUSTOM " ) ;
2014-03-01 00:16:51 +04:00
break ;
2014-03-17 20:12:12 +01:00
case MAVLINK_MODE_CAMERA :
warnx ( " mode: CAMERA " ) ;
break ;
2014-03-01 00:16:51 +04:00
default :
warnx ( " ERROR: Unknown mode " ) ;
break ;
2014-02-11 22:36:36 +01:00
}
2014-01-09 08:10:35 +01:00
2014-03-11 23:03:49 +04:00
_mavlink_wpm_comp_id = MAV_COMP_ID_MISSIONPLANNER ;
2014-02-14 13:36:59 +01:00
2014-03-20 14:23:23 +01:00
warnx ( " data rate: %d Bytes/s, port: %s, baud: %d " , _datarate , _device_name , _baudrate ) ;
2014-02-27 18:31:41 +04:00
/* flush stdout in case MAVLink is about to take it over */
2014-01-09 08:10:35 +01:00
fflush ( stdout ) ;
2014-02-27 18:31:41 +04:00
struct termios uart_config_original ;
2014-01-09 08:10:35 +01:00
/* default values for arguments */
2014-03-16 19:43:09 +01:00
_uart_fd = mavlink_open_uart ( _baudrate , _device_name , & uart_config_original , & _is_usb_uart ) ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
if ( _uart_fd < 0 ) {
2014-03-11 15:34:27 +04:00
warn ( " could not open %s " , _device_name ) ;
return ERROR ;
2014-03-01 00:16:51 +04:00
}
2014-01-09 08:10:35 +01:00
2014-03-11 19:28:48 +04:00
/* initialize mavlink text message buffering */
mavlink_logbuffer_init ( & _logbuffer , 5 ) ;
2014-04-03 21:15:47 +02:00
/* if we are passing on mavlink messages, we need to prepare a buffer for this instance */
if ( _passing_on ) {
/* initialize message buffer if multiplexing is on */
if ( OK ! = message_buffer_init ( 500 ) ) {
errx ( 1 , " can't allocate message buffer, exiting " ) ;
}
/* initialize message buffer mutex */
pthread_mutex_init ( & _message_buffer_mutex , NULL ) ;
}
2014-01-09 08:10:35 +01:00
/* create the device node that's used for sending text log messages, etc. */
2014-03-01 18:30:30 +04:00
register_driver ( MAVLINK_LOG_DEVICE , & fops , 0666 , NULL ) ;
2014-02-12 12:38:35 +01:00
/* initialize logging device */
_mavlink_fd = open ( MAVLINK_LOG_DEVICE , 0 ) ;
2014-01-09 08:10:35 +01:00
/* Initialize system properties */
mavlink_update_system ( ) ;
/* start the MAVLink receiver */
2014-03-01 18:30:30 +04:00
_receive_thread = MavlinkReceiver : : receive_start ( this ) ;
2014-01-09 08:10:35 +01:00
/* initialize waypoint manager */
2014-03-01 18:30:30 +04:00
mavlink_wpm_init ( _wpm ) ;
2014-01-09 08:10:35 +01:00
int mission_result_sub = orb_subscribe ( ORB_ID ( mission_result ) ) ;
struct mission_result_s mission_result ;
memset ( & mission_result , 0 , sizeof ( mission_result ) ) ;
2014-03-01 18:30:30 +04:00
_task_running = true ;
2014-01-09 08:10:35 +01:00
2014-03-01 16:43:04 +04:00
MavlinkOrbSubscription * param_sub = add_orb_subscription ( ORB_ID ( parameter_update ) ) ;
MavlinkOrbSubscription * status_sub = add_orb_subscription ( ORB_ID ( vehicle_status ) ) ;
2014-02-02 11:06:53 +01:00
2014-02-26 21:28:35 +04:00
struct vehicle_status_s * status = ( struct vehicle_status_s * ) status_sub - > get_data ( ) ;
2014-02-11 16:16:57 +01:00
2014-04-08 23:28:52 +04:00
MavlinkCommandsStream commands_stream ( this , _channel ) ;
2014-02-27 18:31:41 +04:00
/* add default streams depending on mode and intervals depending on datarate */
float rate_mult = _datarate / 1000.0f ;
2014-02-26 00:38:21 +04:00
2014-02-28 00:45:59 +04:00
configure_stream ( " HEARTBEAT " , 1.0f ) ;
2014-02-27 13:54:55 +04:00
2014-03-01 00:16:51 +04:00
switch ( _mode ) {
2014-03-11 23:03:49 +04:00
case MAVLINK_MODE_NORMAL :
2014-02-28 00:45:59 +04:00
configure_stream ( " SYS_STATUS " , 1.0f ) ;
2014-03-01 19:27:53 +04:00
configure_stream ( " GPS_GLOBAL_ORIGIN " , 0.5f ) ;
2014-02-28 00:45:59 +04:00
configure_stream ( " HIGHRES_IMU " , 1.0f * rate_mult ) ;
configure_stream ( " ATTITUDE " , 10.0f * rate_mult ) ;
2014-03-01 20:09:02 +04:00
configure_stream ( " VFR_HUD " , 10.0f * rate_mult ) ;
2014-02-28 00:45:59 +04:00
configure_stream ( " GPS_RAW_INT " , 1.0f * rate_mult ) ;
2014-03-01 20:09:02 +04:00
configure_stream ( " GLOBAL_POSITION_INT " , 3.0f * rate_mult ) ;
configure_stream ( " LOCAL_POSITION_NED " , 3.0f * rate_mult ) ;
2014-03-08 11:37:49 +04:00
configure_stream ( " RC_CHANNELS_RAW " , 1.0f * rate_mult ) ;
2014-03-21 10:44:31 +01:00
configure_stream ( " NAMED_VALUE_FLOAT " , 1.0f * rate_mult ) ;
2014-04-07 14:38:16 +02:00
configure_stream ( " GLOBAL_POSITION_SETPOINT_INT " , 3.0f * rate_mult ) ;
configure_stream ( " ROLL_PITCH_YAW_THRUST_SETPOINT " , 3.0f * rate_mult ) ;
2014-04-13 23:30:09 +02:00
configure_stream ( " DISTANCE_SENSOR " , 0.5f ) ;
2014-02-27 13:54:55 +04:00
break ;
2014-03-17 20:12:12 +01:00
case MAVLINK_MODE_CAMERA :
configure_stream ( " SYS_STATUS " , 1.0f ) ;
2014-03-20 14:26:45 +01:00
configure_stream ( " ATTITUDE " , 15.0f * rate_mult ) ;
configure_stream ( " GLOBAL_POSITION_INT " , 15.0f * rate_mult ) ;
2014-03-17 20:12:12 +01:00
configure_stream ( " CAMERA_CAPTURE " , 1.0f ) ;
break ;
2014-02-27 13:54:55 +04:00
default :
break ;
}
2014-03-01 16:43:04 +04:00
/* don't send parameters on startup without request */
2014-03-01 18:30:30 +04:00
_mavlink_param_queue_index = param_count ( ) ;
2014-03-01 16:43:04 +04:00
2014-03-01 19:42:29 +04:00
MavlinkRateLimiter slow_rate_limiter ( 2000000.0f / rate_mult ) ;
2014-03-21 18:12:02 +01:00
MavlinkRateLimiter fast_rate_limiter ( 30000.0f / rate_mult ) ;
2014-02-02 11:06:53 +01:00
2014-03-01 19:27:53 +04:00
/* set main loop delay depending on data rate to minimize CPU overhead */
_main_loop_delay = MAIN_LOOP_DELAY / rate_mult ;
2014-03-21 08:32:54 +01:00
/* now the instance is fully initialized and we can bump the instance count */
LL_APPEND ( _mavlink_instances , this ) ;
2014-02-02 11:06:53 +01:00
while ( ! _task_should_exit ) {
2014-02-26 00:24:14 +04:00
/* main loop */
2014-03-01 19:27:53 +04:00
usleep ( _main_loop_delay ) ;
2014-02-02 11:06:53 +01:00
perf_begin ( _loop_perf ) ;
2014-02-26 00:24:14 +04:00
hrt_abstime t = hrt_absolute_time ( ) ;
2014-01-09 08:10:35 +01:00
2014-02-26 00:24:14 +04:00
if ( param_sub - > update ( t ) ) {
/* parameters updated */
2014-01-09 08:10:35 +01:00
mavlink_update_system ( ) ;
2014-02-26 00:24:14 +04:00
}
2014-01-09 08:10:35 +01:00
2014-02-26 00:24:14 +04:00
if ( status_sub - > update ( t ) ) {
2014-01-09 08:10:35 +01:00
/* switch HIL mode if required */
2014-03-11 23:03:49 +04:00
set_hil_enabled ( status - > hil_state = = HIL_STATE_ON ) ;
2014-02-26 00:24:14 +04:00
}
2014-01-09 08:10:35 +01:00
2014-04-08 23:28:52 +04:00
/* update commands stream */
commands_stream . update ( t ) ;
2014-03-01 16:43:04 +04:00
/* check for requested subscriptions */
if ( _subscribe_to_stream ! = nullptr ) {
if ( OK = = configure_stream ( _subscribe_to_stream , _subscribe_to_stream_rate ) ) {
if ( _subscribe_to_stream_rate > 0.0f ) {
2014-05-21 14:21:47 +02:00
warnx ( " stream %s on device %s enabled with rate %.1f Hz " , _subscribe_to_stream , _device_name , ( double ) _subscribe_to_stream_rate ) ;
2014-03-01 16:43:04 +04:00
} else {
2014-03-01 18:30:30 +04:00
warnx ( " stream %s on device %s disabled " , _subscribe_to_stream , _device_name ) ;
2014-03-01 16:43:04 +04:00
}
} else {
2014-05-21 14:21:47 +02:00
warnx ( " stream %s on device %s not found " , _subscribe_to_stream , _device_name ) ;
2014-03-01 16:43:04 +04:00
}
2014-03-01 18:30:30 +04:00
2014-03-01 16:43:04 +04:00
delete _subscribe_to_stream ;
_subscribe_to_stream = nullptr ;
}
/* update streams */
2014-02-26 00:24:14 +04:00
MavlinkStream * stream ;
LL_FOREACH ( _streams , stream ) {
stream - > update ( t ) ;
2014-02-24 15:17:13 +01:00
}
2014-01-09 08:10:35 +01:00
bool updated ;
orb_check ( mission_result_sub , & updated ) ;
if ( updated ) {
orb_copy ( ORB_ID ( mission_result ) , mission_result_sub , & mission_result ) ;
2014-03-01 00:16:51 +04:00
if ( _verbose ) { warnx ( " Got mission result: new current: %d " , mission_result . index_current_mission ) ; }
2014-02-15 11:29:36 +01:00
2014-02-23 13:42:15 +01:00
if ( mission_result . mission_reached ) {
2014-02-15 11:29:36 +01:00
mavlink_wpm_send_waypoint_reached ( ( uint16_t ) mission_result . mission_index_reached ) ;
2014-02-23 13:42:15 +01:00
}
2014-02-15 11:29:36 +01:00
mavlink_wpm_send_waypoint_current ( ( uint16_t ) mission_result . index_current_mission ) ;
2014-03-01 00:16:51 +04:00
2014-02-27 13:54:55 +04:00
} else {
if ( slow_rate_limiter . check ( t ) ) {
mavlink_wpm_send_waypoint_current ( ( uint16_t ) mission_result . index_current_mission ) ;
}
2014-01-09 08:10:35 +01:00
}
2014-02-27 13:54:55 +04:00
if ( fast_rate_limiter . check ( t ) ) {
2014-02-26 00:24:14 +04:00
mavlink_pm_queued_send ( ) ;
mavlink_waypoint_eventloop ( hrt_absolute_time ( ) ) ;
2014-01-09 08:10:35 +01:00
2014-03-01 18:30:30 +04:00
if ( ! mavlink_logbuffer_is_empty ( & _logbuffer ) ) {
2014-02-26 00:24:14 +04:00
struct mavlink_logmessage msg ;
2014-03-01 18:30:30 +04:00
int lb_ret = mavlink_logbuffer_read ( & _logbuffer , & msg ) ;
2014-01-09 08:10:35 +01:00
2014-02-26 00:24:14 +04:00
if ( lb_ret = = OK ) {
mavlink_missionlib_send_gcs_string ( msg . text ) ;
}
2014-02-26 21:28:35 +04:00
}
2014-02-26 00:24:14 +04:00
}
2014-01-09 08:10:35 +01:00
2014-04-03 21:15:47 +02:00
/* pass messages from other UARTs */
if ( _passing_on ) {
bool is_part ;
void * read_ptr ;
/* guard get ptr by mutex */
pthread_mutex_lock ( & _message_buffer_mutex ) ;
int available = message_buffer_get_ptr ( & read_ptr , & is_part ) ;
pthread_mutex_unlock ( & _message_buffer_mutex ) ;
if ( available > 0 ) {
/* write first part of buffer */
_mavlink_resend_uart ( _channel , ( const mavlink_message_t * ) read_ptr ) ;
message_buffer_mark_read ( available ) ;
/* write second part of buffer if there is some */
if ( is_part ) {
/* guard get ptr by mutex */
pthread_mutex_lock ( & _message_buffer_mutex ) ;
available = message_buffer_get_ptr ( & read_ptr , & is_part ) ;
pthread_mutex_unlock ( & _message_buffer_mutex ) ;
_mavlink_resend_uart ( _channel , ( const mavlink_message_t * ) read_ptr ) ;
message_buffer_mark_read ( available ) ;
}
}
}
2014-02-02 11:06:53 +01:00
perf_end ( _loop_perf ) ;
2014-01-09 08:10:35 +01:00
}
2014-03-01 16:43:04 +04:00
delete _subscribe_to_stream ;
_subscribe_to_stream = nullptr ;
2014-03-11 19:28:48 +04:00
/* delete streams */
MavlinkStream * stream_to_del = nullptr ;
MavlinkStream * stream_next = _streams ;
while ( stream_next ! = nullptr ) {
stream_to_del = stream_next ;
stream_next = stream_to_del - > next ;
delete stream_to_del ;
}
_streams = nullptr ;
/* delete subscriptions */
MavlinkOrbSubscription * sub_to_del = nullptr ;
MavlinkOrbSubscription * sub_next = _subscriptions ;
while ( sub_next ! = nullptr ) {
sub_to_del = sub_next ;
sub_next = sub_to_del - > next ;
delete sub_to_del ;
}
_subscriptions = nullptr ;
2014-03-01 18:30:30 +04:00
warnx ( " waiting for UART receive thread " ) ;
2014-03-01 17:12:46 +04:00
2014-01-09 08:10:35 +01:00
/* wait for threads to complete */
2014-03-01 18:30:30 +04:00
pthread_join ( _receive_thread , NULL ) ;
2014-01-09 08:10:35 +01:00
2014-03-01 17:12:46 +04:00
/* reset the UART flags to original state */
2014-03-01 18:30:30 +04:00
tcsetattr ( _uart_fd , TCSANOW , & uart_config_original ) ;
2014-01-09 08:10:35 +01:00
2014-03-01 17:12:46 +04:00
/* close UART */
2014-03-01 18:30:30 +04:00
close ( _uart_fd ) ;
2014-03-01 17:12:46 +04:00
2014-03-11 19:28:48 +04:00
/* close mavlink logging device */
close ( _mavlink_fd ) ;
2014-04-03 21:15:47 +02:00
if ( _passing_on ) {
message_buffer_destroy ( ) ;
pthread_mutex_destroy ( & _message_buffer_mutex ) ;
}
2014-01-09 08:10:35 +01:00
/* destroy log buffer */
2014-03-01 18:30:30 +04:00
mavlink_logbuffer_destroy ( & _logbuffer ) ;
2014-01-09 08:10:35 +01:00
2014-03-01 17:12:46 +04:00
warnx ( " exiting " ) ;
2014-03-01 18:30:30 +04:00
_task_running = false ;
2014-03-11 15:34:27 +04:00
return OK ;
2014-01-09 08:10:35 +01:00
}
2014-01-28 21:05:00 +01:00
int Mavlink : : start_helper ( int argc , char * argv [ ] )
{
2014-02-26 21:28:35 +04:00
/* create the instance in task context */
2014-03-11 15:34:27 +04:00
Mavlink * instance = new Mavlink ( ) ;
2014-03-01 18:30:30 +04:00
2014-02-26 21:28:35 +04:00
/* this will actually only return once MAVLink exits */
2014-03-11 15:34:27 +04:00
int res = instance - > task_main ( argc , argv ) ;
/* delete instance on main thread end */
delete instance ;
return res ;
2014-01-28 21:05:00 +01:00
}
2014-01-09 08:10:35 +01:00
int
2014-02-26 21:28:35 +04:00
Mavlink : : start ( int argc , char * argv [ ] )
2014-01-09 08:10:35 +01:00
{
2014-03-21 08:32:54 +01:00
// Wait for the instance count to go up one
// before returning to the shell
int ic = Mavlink : : instance_count ( ) ;
2014-02-26 21:28:35 +04:00
// Instantiate thread
2014-03-11 11:12:39 +04:00
char buf [ 24 ] ;
2014-03-21 08:32:54 +01:00
sprintf ( buf , " mavlink_if%d " , ic ) ;
2014-02-26 21:28:35 +04:00
2014-03-21 08:32:54 +01:00
// This is where the control flow splits
// between the starting task and the spawned
// task - start_helper() only returns
// when the started task exits.
2014-03-01 18:30:30 +04:00
task_spawn_cmd ( buf ,
2014-04-10 10:35:30 +02:00
SCHED_DEFAULT ,
SCHED_PRIORITY_DEFAULT ,
2014-05-16 10:47:18 +02:00
1950 ,
2014-04-10 10:35:30 +02:00
( main_t ) & Mavlink : : start_helper ,
( const char * * ) argv ) ;
2014-01-09 08:10:35 +01:00
2014-03-21 08:32:54 +01:00
// Ensure that this shell command
// does not return before the instance
// is fully initialized. As this is also
// the only path to create a new instance,
// this is effectively a lock on concurrent
// instance starting. XXX do a real lock.
2014-03-21 10:44:31 +01:00
// Sleep 500 us between each attempt
const unsigned sleeptime = 500 ;
// Wait 100 ms max for the startup.
const unsigned limit = 100 * 1000 / sleeptime ;
unsigned count = 0 ;
2014-03-21 20:06:34 +04:00
2014-03-21 10:44:31 +01:00
while ( ic = = Mavlink : : instance_count ( ) & & count < limit ) {
: : usleep ( sleeptime ) ;
count + + ;
2014-03-21 08:32:54 +01:00
}
2014-01-09 08:10:35 +01:00
return OK ;
}
void
2014-03-01 00:16:51 +04:00
Mavlink : : status ( )
2014-01-09 08:10:35 +01:00
{
2014-02-28 00:45:59 +04:00
warnx ( " running " ) ;
}
int
Mavlink : : stream ( int argc , char * argv [ ] )
{
const char * device_name = DEFAULT_DEVICE_NAME ;
float rate = - 1.0f ;
const char * stream_name = nullptr ;
2014-03-14 14:40:54 +01:00
argc - = 2 ;
argv + = 2 ;
2014-02-28 00:45:59 +04:00
/* don't exit from getopt loop to leave getopt global variables in consistent state,
* set error flag instead */
bool err_flag = false ;
2014-03-14 14:40:54 +01:00
int i = 0 ;
2014-03-21 20:06:34 +04:00
2014-03-14 14:40:54 +01:00
while ( i < argc ) {
2014-03-01 00:16:51 +04:00
2014-03-21 20:06:34 +04:00
if ( 0 = = strcmp ( argv [ i ] , " -r " ) & & i < argc - 1 ) {
rate = strtod ( argv [ i + 1 ] , nullptr ) ;
2014-02-28 00:45:59 +04:00
if ( rate < 0.0f ) {
err_flag = true ;
}
2014-03-21 20:06:34 +04:00
2014-03-14 14:40:54 +01:00
i + + ;
2014-03-21 20:06:34 +04:00
} else if ( 0 = = strcmp ( argv [ i ] , " -d " ) & & i < argc - 1 ) {
device_name = argv [ i + 1 ] ;
2014-03-14 14:40:54 +01:00
i + + ;
2014-03-21 20:06:34 +04:00
} else if ( 0 = = strcmp ( argv [ i ] , " -s " ) & & i < argc - 1 ) {
stream_name = argv [ i + 1 ] ;
2014-03-14 14:40:54 +01:00
i + + ;
2014-03-21 20:06:34 +04:00
2014-03-14 14:40:54 +01:00
} else {
2014-02-28 00:45:59 +04:00
err_flag = true ;
}
2014-03-14 14:40:54 +01:00
i + + ;
2014-02-28 00:45:59 +04:00
}
2014-05-21 14:21:47 +02:00
if ( ! err_flag & & rate > = 0.0f & & stream_name ! = nullptr ) {
2014-02-28 00:45:59 +04:00
Mavlink * inst = get_instance_for_device ( device_name ) ;
2014-03-01 00:16:51 +04:00
2014-02-28 00:45:59 +04:00
if ( inst ! = nullptr ) {
2014-03-01 16:43:04 +04:00
inst - > configure_stream_threadsafe ( stream_name , rate ) ;
2014-02-28 00:45:59 +04:00
} else {
2014-03-21 10:44:31 +01:00
// If the link is not running we should complain, but not fall over
// because this is so easy to get wrong and not fatal. Warning is sufficient.
errx ( 0 , " mavlink for device %s is not running " , device_name ) ;
2014-02-28 00:45:59 +04:00
}
} else {
errx ( 1 , " usage: mavlink stream [-d device] -s stream -r rate " ) ;
}
return OK ;
2014-01-09 08:10:35 +01:00
}
static void usage ( )
{
2014-04-10 10:26:15 +02:00
warnx ( " usage: mavlink {start|stop-all|stream} [-d device] [-b baudrate] [-r rate] [-m mode] [-s stream] [-f] [-p] [-v] [-w] " ) ;
2014-01-09 08:10:35 +01:00
}
int mavlink_main ( int argc , char * argv [ ] )
{
if ( argc < 2 ) {
usage ( ) ;
2014-03-11 15:34:27 +04:00
exit ( 1 ) ;
2014-01-09 08:10:35 +01:00
}
if ( ! strcmp ( argv [ 1 ] , " start " ) ) {
2014-02-26 21:28:35 +04:00
return Mavlink : : start ( argc , argv ) ;
2014-01-09 08:10:35 +01:00
2014-02-13 19:13:10 +01:00
} else if ( ! strcmp ( argv [ 1 ] , " stop " ) ) {
2014-02-14 14:24:26 +01:00
warnx ( " mavlink stop is deprecated, use stop-all instead " ) ;
usage ( ) ;
2014-03-11 15:34:27 +04:00
exit ( 1 ) ;
2014-02-14 14:24:26 +01:00
} else if ( ! strcmp ( argv [ 1 ] , " stop-all " ) ) {
2014-02-13 19:13:10 +01:00
return Mavlink : : destroy_all_instances ( ) ;
2014-01-09 08:10:35 +01:00
2014-03-01 00:16:51 +04:00
// } else if (!strcmp(argv[1], "status")) {
// mavlink::g_mavlink->status();
2014-01-09 08:10:35 +01:00
2014-02-28 00:45:59 +04:00
} else if ( ! strcmp ( argv [ 1 ] , " stream " ) ) {
return Mavlink : : stream ( argc , argv ) ;
2014-03-01 00:16:51 +04:00
} else {
usage ( ) ;
2014-03-11 15:34:27 +04:00
exit ( 1 ) ;
2014-03-01 00:16:51 +04:00
}
2014-01-09 08:10:35 +01:00
return 0 ;
}