2016-04-08 14:04:33 +02:00
/**
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2016-04-24 01:46:13 +02:00
* @ addtogroup OpenPilotModules OpenPilot Modules
2016-04-08 14:04:33 +02:00
* @ {
* @ addtogroup UAVOMSPBridge UAVO to MSP Bridge Module
* @ {
*
* @ file uavomspbridge . c
2016-04-22 03:19:51 +02:00
* @ author The LibrePilot Project , http : //www.librepilot.org Copyright (C) 2016.
2016-04-22 22:53:16 +02:00
* Tau Labs , http : //taulabs.org, Copyright (C) 2015
* dRonin , http : //dronin.org Copyright (C) 2015-2016
2016-04-08 14:04:33 +02:00
* @ brief Bridges selected UAVObjects to MSP for MWOSD and the like .
*
* @ see The GNU Public License ( GPL ) Version 3
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
* Additional note on redistribution : The copyright and license notices above
* must be maintained in each individual source file that is a derivative work
* of this source file ; otherwise redistribution is prohibited .
*/
# include "openpilot.h"
# include "receiverstatus.h"
# include "hwsettings.h"
2016-04-22 03:29:38 +02:00
# include "flightmodesettings.h"
2016-04-08 14:04:33 +02:00
# include "flightbatterysettings.h"
# include "flightbatterystate.h"
# include "gpspositionsensor.h"
# include "manualcontrolcommand.h"
2016-04-24 01:50:41 +02:00
# include "manualcontrolsettings.h"
# include "oplinkstatus.h"
2016-04-08 14:04:33 +02:00
# include "accessorydesired.h"
# include "attitudestate.h"
# include "airspeedstate.h"
# include "actuatorsettings.h"
# include "actuatordesired.h"
# include "flightstatus.h"
# include "systemstats.h"
# include "systemalarms.h"
2016-04-24 01:49:09 +02:00
# include "takeofflocation.h"
2016-04-08 14:04:33 +02:00
# include "homelocation.h"
2016-04-24 01:46:13 +02:00
# include "positionstate.h"
# include "velocitystate.h"
2016-04-08 14:04:33 +02:00
# include "stabilizationdesired.h"
2016-04-19 23:23:06 +02:00
# include "taskinfo.h"
2016-04-22 03:29:38 +02:00
# include "stabilizationsettings.h"
# include "stabilizationbank.h"
# include "stabilizationsettingsbank1.h"
# include "stabilizationsettingsbank2.h"
# include "stabilizationsettingsbank3.h"
# include "magstate.h"
2016-04-08 14:04:33 +02:00
# include "pios_sensors.h"
# define PIOS_INCLUDE_MSP_BRIDGE
# if defined(PIOS_INCLUDE_MSP_BRIDGE)
2016-04-25 14:58:46 +02:00
// oplink rssi - absolute low : -127 dBm noise floor (set by software when link is completely lost)
// in reality : around -110 dBm
// max: various articles found on web quote -10 dBm as maximum received signal power.
2016-04-25 13:28:10 +02:00
# define OPLINK_LOW_RSSI -110
# define OPLINK_HIGH_RSSI -10
2016-04-22 03:19:51 +02:00
# define MSP_SENSOR_ACC (1 << 0)
# define MSP_SENSOR_BARO (1 << 1)
# define MSP_SENSOR_MAG (1 << 2)
# define MSP_SENSOR_GPS (1 << 3)
2016-04-08 14:04:33 +02:00
# define MSP_SENSOR_SONAR (1 << 4)
// Magic numbers copied from mwosd
2016-04-22 03:19:51 +02:00
# define MSP_IDENT 100 // multitype + multiwii version + protocol version + capability variable
# define MSP_STATUS 101 // cycletime & errors_count & sensor present & box activation & current setting number
# define MSP_RAW_IMU 102 // 9 DOF
# define MSP_SERVO 103 // 8 servos
# define MSP_MOTOR 104 // 8 motors
# define MSP_RC 105 // 8 rc chan and more
# define MSP_RAW_GPS 106 // fix, numsat, lat, lon, alt, speed, ground course
# define MSP_COMP_GPS 107 // distance home, direction home
# define MSP_ATTITUDE 108 // 2 angles 1 heading
# define MSP_ALTITUDE 109 // altitude, variometer
# define MSP_ANALOG 110 // vbat, powermetersum, rssi if available on RX
# define MSP_RC_TUNING 111 // rc rate, rc expo, rollpitch rate, yaw rate, dyn throttle PID
# define MSP_PID 112 // P I D coeff (10 are used currently)
# define MSP_BOX 113 // BOX setup (number is dependant of your setup)
# define MSP_MISC 114 // powermeter trig
# define MSP_MOTOR_PINS 115 // which pins are in use for motors & servos, for GUI
# define MSP_BOXNAMES 116 // the aux switch names
# define MSP_PIDNAMES 117 // the PID names
# define MSP_BOXIDS 119 // get the permanent IDs associated to BOXes
# define MSP_NAV_STATUS 121 // Returns navigation status
# define MSP_CELLS 130 // FrSky SPort Telemtry
# define MSP_ALARMS 242 // Alarm request
# define MSP_SET_PID 202 // set P I D coeff
2016-04-22 03:29:38 +02:00
2016-04-08 14:04:33 +02:00
typedef enum {
2016-04-22 03:19:51 +02:00
MSP_BOX_ID_ARM ,
MSP_BOX_ID_ANGLE , // mode.stable (attitude??) - [sensor icon] [ fligth mode icon ]
MSP_BOX_ID_HORIZON , // [sensor icon] [ flight mode icon ]
MSP_BOX_ID_BARO , // [sensor icon]
MSP_BOX_ID_VARIO ,
MSP_BOX_ID_MAG , // [sensor icon]
MSP_BOX_ID_HEADFREE ,
MSP_BOX_ID_HEADADJ ,
MSP_BOX_ID_CAMSTAB , // [gimbal icon]
MSP_BOX_ID_CAMTRIG ,
MSP_BOX_ID_GPSHOME , // [ flight mode icon ]
MSP_BOX_ID_GPSHOLD , // [ flight mode icon ]
MSP_BOX_ID_PASSTHRU , // [ flight mode icon ]
MSP_BOX_ID_BEEPER ,
MSP_BOX_ID_LEDMAX ,
MSP_BOX_ID_LEDLOW ,
MSP_BOX_ID_LLIGHTS , // landing lights
MSP_BOX_ID_CALIB ,
MSP_BOX_ID_GOVERNOR ,
MSP_BOX_ID_OSD_SWITCH , // OSD on or off, maybe.
MSP_BOX_ID_GPSMISSION , // [ flight mode icon ]
MSP_BOX_ID_GPSLAND , // [ flight mode icon ]
MSP_BOX_ID_AIR = 28 , // this box will add AIRMODE icon to flight mode.
MSP_BOX_ID_ACROPLUS = 29 , // this will add PLUS icon to ACRO. ACRO = !ANGLE && !HORIZON
2016-04-22 03:29:38 +02:00
} msp_boxid_t ;
2016-04-22 03:19:51 +02:00
enum {
MSP_STATUS_ARMED ,
MSP_STATUS_FLIGHTMODE_STABILIZED ,
MSP_STATUS_FLIGHTMODE_HORIZON ,
MSP_STATUS_SENSOR_BARO ,
MSP_STATUS_SENSOR_MAG ,
MSP_STATUS_MISC_GIMBAL ,
MSP_STATUS_FLIGHTMODE_GPSHOME ,
MSP_STATUS_FLIGHTMODE_GPSHOLD ,
MSP_STATUS_FLIGHTMODE_GPSMISSION ,
MSP_STATUS_FLIGHTMODE_GPSLAND ,
MSP_STATUS_FLIGHTMODE_PASSTHRU ,
MSP_STATUS_OSD_SWITCH ,
MSP_STATUS_ICON_AIRMODE ,
MSP_STATUS_ICON_ACROPLUS ,
2016-04-22 03:29:38 +02:00
} ;
2016-04-22 03:19:51 +02:00
static const uint8_t msp_boxes [ ] = {
[ MSP_STATUS_ARMED ] = MSP_BOX_ID_ARM ,
[ MSP_STATUS_FLIGHTMODE_STABILIZED ] = MSP_BOX_ID_ANGLE , // flight mode
[ MSP_STATUS_FLIGHTMODE_HORIZON ] = MSP_BOX_ID_HORIZON , // flight mode
[ MSP_STATUS_SENSOR_BARO ] = MSP_BOX_ID_BARO , // sensor icon only
[ MSP_STATUS_SENSOR_MAG ] = MSP_BOX_ID_MAG , // sensor icon only
[ MSP_STATUS_MISC_GIMBAL ] = MSP_BOX_ID_CAMSTAB , // gimbal icon only
[ MSP_STATUS_FLIGHTMODE_GPSHOME ] = MSP_BOX_ID_GPSHOME , // flight mode
[ MSP_STATUS_FLIGHTMODE_GPSHOLD ] = MSP_BOX_ID_GPSHOLD , // flight mode
[ MSP_STATUS_FLIGHTMODE_GPSMISSION ] = MSP_BOX_ID_GPSMISSION , // flight mode
[ MSP_STATUS_FLIGHTMODE_GPSLAND ] = MSP_BOX_ID_GPSLAND , // flight mode
[ MSP_STATUS_FLIGHTMODE_PASSTHRU ] = MSP_BOX_ID_PASSTHRU , // flight mode
[ MSP_STATUS_OSD_SWITCH ] = MSP_BOX_ID_OSD_SWITCH , // switch OSD mode
[ MSP_STATUS_ICON_AIRMODE ] = MSP_BOX_ID_AIR ,
[ MSP_STATUS_ICON_ACROPLUS ] = MSP_BOX_ID_ACROPLUS ,
2016-04-08 14:04:33 +02:00
} ;
typedef enum {
2016-04-22 03:19:51 +02:00
MSP_IDLE ,
MSP_HEADER_START ,
MSP_HEADER_M ,
MSP_HEADER_SIZE ,
MSP_HEADER_CMD ,
MSP_FILLBUF ,
MSP_CHECKSUM ,
MSP_DISCARD ,
MSP_MAYBE_UAVTALK2 ,
MSP_MAYBE_UAVTALK3 ,
MSP_MAYBE_UAVTALK4 ,
MSP_MAYBE_UAVTALK_SLOW2 ,
MSP_MAYBE_UAVTALK_SLOW3 ,
MSP_MAYBE_UAVTALK_SLOW4 ,
MSP_MAYBE_UAVTALK_SLOW5 ,
MSP_MAYBE_UAVTALK_SLOW6
2016-04-08 14:04:33 +02:00
} msp_state ;
2016-05-11 13:35:40 +02:00
2016-04-22 03:19:51 +02:00
typedef struct __attribute__ ( ( packed ) ) {
2016-05-11 13:35:40 +02:00
uint8_t values [ 3 ] ;
2016-04-22 03:19:51 +02:00
}
msp_pid_t ;
2016-04-22 03:29:38 +02:00
typedef enum {
PIDROLL ,
PIDPITCH ,
PIDYAW ,
2016-05-11 13:35:40 +02:00
PIDAROLL , // (PIDALT) use this for Attitude ROLL
2016-05-11 14:53:36 +02:00
PIDAPITCH , // (PIDPOS) use this for Attitude PITCH
2016-05-11 13:35:40 +02:00
PIDPOSR , // skipped by MWOSD
2016-05-11 14:53:36 +02:00
PIDNAVR , // skipped by MWOSD
PIDAYAW , // (PIDLEVEL) use this for Attitude YAW
PIDMAG , // unused for now
2016-05-11 13:35:40 +02:00
PIDVEL , // skipped by MWOSD
2016-04-22 03:29:38 +02:00
PID_ITEM_COUNT
} pidIndex_e ;
2016-05-11 13:35:40 +02:00
static const char msp_pidnames [ ] = " ROLL; "
" PITCH; "
" YAW; "
" A.ROLL; "
" A.PITCH; "
2016-05-11 14:53:36 +02:00
" PosR; "
" NavR; "
2016-05-11 13:35:40 +02:00
" A.YAW; "
2016-05-11 14:53:36 +02:00
" MAG; "
2016-05-11 13:35:40 +02:00
" VEL; " ;
2016-04-22 03:19:51 +02:00
2016-04-08 14:04:33 +02:00
# define MSP_ANALOG_VOLTAGE (1 << 0)
# define MSP_ANALOG_CURRENT (1 << 1)
struct msp_bridge {
2016-04-22 03:19:51 +02:00
uintptr_t com ;
uint8_t sensors ;
uint8_t analog ;
2016-05-11 13:35:40 +02:00
UAVObjHandle current_pid_bank ;
2016-04-22 03:19:51 +02:00
msp_state state ;
uint8_t cmd_size ;
uint8_t cmd_id ;
uint8_t cmd_i ;
uint8_t checksum ;
union {
uint8_t data [ 0 ] ;
// Specific packed data structures go here.
msp_pid_t piditems [ PID_ITEM_COUNT ] ;
} cmd_data ;
2016-04-08 14:04:33 +02:00
} ;
# if defined(PIOS_MSP_STACK_SIZE)
2016-04-22 03:19:51 +02:00
# define STACK_SIZE_BYTES PIOS_MSP_STACK_SIZE
2016-04-08 14:04:33 +02:00
# else
2016-04-22 03:19:51 +02:00
# define STACK_SIZE_BYTES 768
2016-04-08 14:04:33 +02:00
# endif
2016-04-22 03:19:51 +02:00
# define TASK_PRIORITY (tskIDLE_PRIORITY)
2016-04-08 14:04:33 +02:00
2016-04-22 03:19:51 +02:00
# define MAX_ALARM_LEN 30
2016-04-08 14:04:33 +02:00
2016-04-22 03:19:51 +02:00
# define BOOT_DISPLAY_TIME_MS (10 * 1000)
2016-04-08 14:04:33 +02:00
static bool module_enabled = false ;
static struct msp_bridge * msp ;
static int32_t uavoMSPBridgeInitialize ( void ) ;
static void uavoMSPBridgeTask ( void * parameters ) ;
static void msp_send ( struct msp_bridge * m , uint8_t cmd , const uint8_t * data , size_t len )
{
2016-04-22 03:19:51 +02:00
uint8_t buf [ 5 ] ;
uint8_t cs = ( uint8_t ) ( len ) ^ cmd ;
buf [ 0 ] = ' $ ' ;
buf [ 1 ] = ' M ' ;
buf [ 2 ] = ' > ' ;
buf [ 3 ] = ( uint8_t ) ( len ) ;
buf [ 4 ] = cmd ;
PIOS_COM_SendBuffer ( m - > com , buf , sizeof ( buf ) ) ;
if ( len > 0 ) {
PIOS_COM_SendBuffer ( m - > com , data , len ) ;
for ( unsigned i = 0 ; i < len ; i + + ) {
cs ^ = data [ i ] ;
2016-04-20 18:29:44 +02:00
}
2016-04-22 03:19:51 +02:00
}
2016-04-08 14:04:33 +02:00
2016-04-22 03:19:51 +02:00
cs ^ = 0 ;
2016-04-08 14:04:33 +02:00
2016-04-22 03:19:51 +02:00
buf [ 0 ] = cs ;
PIOS_COM_SendBuffer ( m - > com , buf , 1 ) ;
2016-04-08 14:04:33 +02:00
}
static msp_state msp_state_size ( struct msp_bridge * m , uint8_t b )
{
2016-04-22 03:19:51 +02:00
m - > cmd_size = b ;
m - > checksum = b ;
return MSP_HEADER_CMD ;
2016-04-08 14:04:33 +02:00
}
static msp_state msp_state_cmd ( struct msp_bridge * m , uint8_t b )
{
2016-04-22 03:19:51 +02:00
m - > cmd_i = 0 ;
m - > cmd_id = b ;
m - > checksum ^ = m - > cmd_id ;
2016-04-08 14:04:33 +02:00
2016-04-22 03:19:51 +02:00
if ( m - > cmd_size > sizeof ( m - > cmd_data ) ) {
// Too large a body. Let's ignore it.
return MSP_DISCARD ;
}
2016-04-08 14:04:33 +02:00
2016-04-22 03:19:51 +02:00
return m - > cmd_size = = 0 ? MSP_CHECKSUM : MSP_FILLBUF ;
2016-04-08 14:04:33 +02:00
}
static msp_state msp_state_fill_buf ( struct msp_bridge * m , uint8_t b )
{
2016-04-22 03:19:51 +02:00
m - > cmd_data . data [ m - > cmd_i + + ] = b ;
m - > checksum ^ = b ;
return m - > cmd_i = = m - > cmd_size ? MSP_CHECKSUM : MSP_FILLBUF ;
2016-04-08 14:04:33 +02:00
}
static void msp_send_attitude ( struct msp_bridge * m )
{
2016-04-22 03:19:51 +02:00
union {
uint8_t buf [ 0 ] ;
struct {
int16_t x ;
int16_t y ;
int16_t h ;
} att ;
} data ;
AttitudeStateData attState ;
AttitudeStateGet ( & attState ) ;
// Roll and Pitch are in 10ths of a degree.
data . att . x = attState . Roll * 10 ;
data . att . y = attState . Pitch * - 10 ;
// Yaw is just -180 -> 180
data . att . h = attState . Yaw ;
msp_send ( m , MSP_ATTITUDE , data . buf , sizeof ( data ) ) ;
2016-04-08 14:04:33 +02:00
}
2016-04-22 03:19:51 +02:00
# define IS_STAB_MODE(d, m) (((d).Roll == (m)) && ((d).Pitch == (m)))
2016-04-22 03:29:38 +02:00
2016-04-08 14:04:33 +02:00
static void msp_send_status ( struct msp_bridge * m )
{
2016-04-22 03:19:51 +02:00
union {
uint8_t buf [ 0 ] ;
struct {
uint16_t cycleTime ;
uint16_t i2cErrors ;
uint16_t sensors ;
uint32_t flags ;
uint8_t setting ;
} __attribute__ ( ( packed ) ) status ;
} data ;
// TODO: https://github.com/TauLabs/TauLabs/blob/next/shared/uavobjectdefinition/actuatordesired.xml#L8
data . status . cycleTime = 0 ;
data . status . i2cErrors = 0 ;
data . status . sensors = m - > sensors ;
if ( GPSPositionSensorHandle ( ) ! = NULL ) {
GPSPositionSensorStatusOptions gpsStatus ;
GPSPositionSensorStatusGet ( & gpsStatus ) ;
if ( gpsStatus ! = GPSPOSITIONSENSOR_STATUS_NOGPS ) {
data . status . sensors | = MSP_SENSOR_GPS ;
}
}
data . status . flags = 0 ;
data . status . setting = 0 ;
FlightStatusData flightStatus ;
FlightStatusGet ( & flightStatus ) ;
StabilizationDesiredStabilizationModeData stabModeData ;
StabilizationDesiredStabilizationModeGet ( & stabModeData ) ;
if ( flightStatus . Armed = = FLIGHTSTATUS_ARMED_ARMED ) {
data . status . flags | = ( 1 < < MSP_STATUS_ARMED ) ;
}
// flightmode
if ( flightStatus . FlightMode = = FLIGHTSTATUS_FLIGHTMODE_POSITIONHOLD ) {
data . status . flags | = ( 1 < < MSP_STATUS_FLIGHTMODE_GPSHOLD ) ;
} else if ( flightStatus . FlightMode = = FLIGHTSTATUS_FLIGHTMODE_RETURNTOBASE ) {
data . status . flags | = ( 1 < < MSP_STATUS_FLIGHTMODE_GPSHOME ) ;
} else if ( flightStatus . FlightMode = = FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER ) {
data . status . flags | = ( 1 < < MSP_STATUS_FLIGHTMODE_GPSMISSION ) ;
} else if ( flightStatus . FlightMode = = FLIGHTSTATUS_FLIGHTMODE_LAND ) {
data . status . flags | = ( 1 < < MSP_STATUS_FLIGHTMODE_GPSLAND ) ;
} else if ( flightStatus . FlightMode = = FLIGHTSTATUS_FLIGHTMODE_MANUAL ) {
data . status . flags | = ( 1 < < MSP_STATUS_FLIGHTMODE_PASSTHRU ) ;
} else { //
// if Roll(Rate) && Pitch(Rate) => Acro
// if Roll(Acro+) && Pitch(Acro+) => Acro+
// if Roll(Rattitude) && Pitch(Rattitude) => Horizon
// else => Stabilized
if ( IS_STAB_MODE ( stabModeData , STABILIZATIONDESIRED_STABILIZATIONMODE_RATE )
| | IS_STAB_MODE ( stabModeData , STABILIZATIONDESIRED_STABILIZATIONMODE_RATETRAINER ) ) {
// data.status.flags should not set any mode flags
} else if ( IS_STAB_MODE ( stabModeData , STABILIZATIONDESIRED_STABILIZATIONMODE_ACRO ) ) { // this is Acro+ mode
data . status . flags | = ( 1 < < MSP_STATUS_ICON_ACROPLUS ) ;
} else if ( IS_STAB_MODE ( stabModeData , STABILIZATIONDESIRED_STABILIZATIONMODE_RATTITUDE ) ) {
data . status . flags | = ( 1 < < MSP_STATUS_FLIGHTMODE_HORIZON ) ;
} else { // looks like stabilized mode, whichever it is..
data . status . flags | = ( 1 < < MSP_STATUS_FLIGHTMODE_STABILIZED ) ;
}
}
// sensors in use?
// flight mode HORIZON or STABILIZED will turn on Accelerometer icon.
// Barometer?
if ( ( stabModeData . Thrust = = STABILIZATIONDESIRED_STABILIZATIONMODE_ALTITUDEHOLD )
| | ( stabModeData . Thrust = = STABILIZATIONDESIRED_STABILIZATIONMODE_ALTITUDEVARIO ) ) {
data . status . flags | = ( 1 < < MSP_STATUS_SENSOR_BARO ) ;
}
# ifndef PIOS_EXCLUDE_ADVANCED_FEATURES
if ( MagStateHandle ( ) ! = NULL ) {
MagStateSourceOptions magSource ;
MagStateSourceGet ( & magSource ) ;
if ( magSource ! = MAGSTATE_SOURCE_INVALID ) {
data . status . flags | = ( 1 < < MSP_STATUS_SENSOR_MAG ) ;
}
}
# endif /* PIOS_EXCLUDE_ADVANCED_FEATURES */
if ( flightStatus . AlwaysStabilizeWhenArmed = = FLIGHTSTATUS_ALWAYSSTABILIZEWHENARMED_TRUE ) {
data . status . flags | = ( 1 < < MSP_STATUS_ICON_AIRMODE ) ;
}
msp_send ( m , MSP_STATUS , data . buf , sizeof ( data ) ) ;
2016-04-08 14:04:33 +02:00
}
static void msp_send_analog ( struct msp_bridge * m )
{
2016-04-22 03:19:51 +02:00
union {
uint8_t buf [ 0 ] ;
struct {
uint8_t vbat ;
uint16_t powerMeterSum ;
uint16_t rssi ;
uint16_t current ;
} __attribute__ ( ( packed ) ) status ;
} data ;
memset ( & data , 0 , sizeof ( data ) ) ;
# ifndef PIOS_EXCLUDE_ADVANCED_FEATURES
if ( FlightBatteryStateHandle ( ) ! = NULL ) {
FlightBatteryStateData batState ;
FlightBatteryStateGet ( & batState ) ;
if ( m - > analog & MSP_ANALOG_VOLTAGE ) {
data . status . vbat = ( uint8_t ) lroundf ( batState . Voltage * 10 ) ;
}
if ( m - > analog & MSP_ANALOG_CURRENT ) {
data . status . current = lroundf ( batState . Current * 100 ) ;
data . status . powerMeterSum = lroundf ( batState . ConsumedEnergy ) ;
}
}
# endif
2016-04-24 01:38:30 +02:00
// OPLink supports RSSI reported in dBm, but updates different value in ReceiverStatus.Quality (link_quality - function of lost, repaired and good packet count).
// We use same method as in Receiver module to decide if oplink is used for control:
// Check for Throttle channel group, if this belongs to oplink, we will use oplink rssi instead of ReceiverStatus.Quality.
ManualControlSettingsChannelGroupsData channelGroups ;
ManualControlSettingsChannelGroupsGet ( & channelGroups ) ;
2016-04-24 01:50:41 +02:00
2016-04-25 15:15:03 +02:00
# ifdef PIOS_INCLUDE_OPLINKRCVR
2016-04-24 01:50:41 +02:00
if ( channelGroups . Throttle = = MANUALCONTROLSETTINGS_CHANNELGROUPS_OPLINK ) {
2016-04-24 01:38:30 +02:00
int8_t rssi ;
OPLinkStatusRSSIGet ( & rssi ) ;
2016-04-24 01:50:41 +02:00
2016-04-25 13:28:10 +02:00
// MSP values have no units, and OSD rssi display requires calibration anyway, so we will translate OPLINK_LOW_RSSI to OPLINK_HIGH_RSSI -> 0-1023
if ( rssi < OPLINK_LOW_RSSI ) {
rssi = OPLINK_LOW_RSSI ;
} else if ( rssi > OPLINK_HIGH_RSSI ) {
rssi = OPLINK_HIGH_RSSI ;
}
2016-04-24 01:50:41 +02:00
2016-04-25 13:28:10 +02:00
data . status . rssi = ( ( rssi - OPLINK_LOW_RSSI ) * 1023 ) / ( OPLINK_HIGH_RSSI - OPLINK_LOW_RSSI ) ;
2016-04-24 01:50:41 +02:00
} else {
2016-04-25 15:15:03 +02:00
# endif /* PIOS_INCLUDE_OPLINKRCVR */
2016-04-24 01:38:30 +02:00
uint8_t quality ;
ReceiverStatusQualityGet ( & quality ) ;
2016-04-08 14:04:33 +02:00
2016-04-24 01:38:30 +02:00
// MSP RSSI's range is 0-1023
data . status . rssi = ( quality * 1023 ) / 100 ;
2016-04-25 15:15:03 +02:00
# ifdef PIOS_INCLUDE_OPLINKRCVR
2016-04-24 01:38:30 +02:00
}
2016-04-25 15:15:03 +02:00
# endif /* PIOS_INCLUDE_OPLINKRCVR */
2016-04-08 14:04:33 +02:00
2016-04-22 03:19:51 +02:00
if ( data . status . rssi > 1023 ) {
data . status . rssi = 1023 ;
}
msp_send ( m , MSP_ANALOG , data . buf , sizeof ( data ) ) ;
2016-04-08 14:04:33 +02:00
}
static void msp_send_raw_gps ( struct msp_bridge * m )
{
2016-04-22 03:19:51 +02:00
union {
uint8_t buf [ 0 ] ;
struct {
uint8_t fix ; // 0 or 1
uint8_t num_sat ;
int32_t lat ; // 1 / 10 000 000 deg
int32_t lon ; // 1 / 10 000 000 deg
uint16_t alt ; // meter
uint16_t speed ; // cm/s
int16_t ground_course ; // degree * 10
} __attribute__ ( ( packed ) ) raw_gps ;
} data ;
GPSPositionSensorData gps_data ;
if ( GPSPositionSensorHandle ( ) ! = NULL ) {
GPSPositionSensorGet ( & gps_data ) ;
data . raw_gps . fix = ( gps_data . Status > = GPSPOSITIONSENSOR_STATUS_FIX2D ? 1 : 0 ) ; // Data will display on OSD if 2D fix or better
data . raw_gps . num_sat = gps_data . Satellites ;
data . raw_gps . lat = gps_data . Latitude ;
data . raw_gps . lon = gps_data . Longitude ;
data . raw_gps . alt = ( uint16_t ) gps_data . Altitude ;
data . raw_gps . speed = ( uint16_t ) gps_data . Groundspeed ;
data . raw_gps . ground_course = ( int16_t ) ( gps_data . Heading * 10.0f ) ;
msp_send ( m , MSP_RAW_GPS , data . buf , sizeof ( data ) ) ;
}
2016-04-08 14:04:33 +02:00
}
2016-04-22 03:19:51 +02:00
# ifndef PIOS_EXCLUDE_ADVANCED_FEATURES
2016-04-24 01:49:09 +02:00
static inline float Sq ( float x )
{
return x * x ;
}
2016-04-08 14:04:33 +02:00
static void msp_send_comp_gps ( struct msp_bridge * m )
{
2016-04-22 03:19:51 +02:00
union {
uint8_t buf [ 0 ] ;
struct {
uint16_t distance_to_home ; // meter
int16_t direction_to_home ; // degree [-180:180]
uint8_t home_position_valid ; // 0 = Invalid, Dronin MSP specific
} __attribute__ ( ( packed ) ) comp_gps ;
} data ;
2016-04-24 01:50:41 +02:00
2016-04-24 01:49:09 +02:00
data . comp_gps . distance_to_home = 0 ;
2016-04-24 01:38:30 +02:00
data . comp_gps . direction_to_home = 0 ;
2016-04-24 01:49:09 +02:00
data . comp_gps . home_position_valid = 0 ; // Home distance and direction will not display on OSD
2016-04-24 01:50:41 +02:00
if ( PositionStateHandle ( ) & & TakeOffLocationHandle ( ) ) {
2016-04-24 01:49:09 +02:00
TakeOffLocationData takeOffLocation ;
TakeOffLocationGet ( & takeOffLocation ) ;
2016-04-24 01:50:41 +02:00
if ( takeOffLocation . Status = = TAKEOFFLOCATION_STATUS_VALID ) {
PositionStateData positionState ;
2016-04-24 01:49:09 +02:00
PositionStateGet ( & positionState ) ;
2016-04-24 01:50:41 +02:00
data . comp_gps . distance_to_home = ( uint16_t ) sqrtf ( Sq ( takeOffLocation . East - positionState . East ) + Sq ( takeOffLocation . North - positionState . North ) ) ;
data . comp_gps . direction_to_home = RAD2DEG ( atan2f ( takeOffLocation . East - positionState . East , takeOffLocation . North - positionState . North ) ) ;
2016-04-24 01:49:09 +02:00
data . comp_gps . home_position_valid = 1 ;
2016-04-22 03:19:51 +02:00
}
2016-04-24 01:49:09 +02:00
}
// here, CC3D implementation could use raw gps data (GPSPositionSensorData) and locally cached GPSPositionSensorData at arming time as TakeOffLocation.
2016-04-24 01:50:41 +02:00
2016-04-24 01:38:30 +02:00
msp_send ( m , MSP_COMP_GPS , data . buf , sizeof ( data ) ) ;
}
2016-04-08 14:04:33 +02:00
static void msp_send_altitude ( struct msp_bridge * m )
{
2016-04-22 03:19:51 +02:00
union {
uint8_t buf [ 0 ] ;
struct {
2016-04-24 01:50:41 +02:00
int32_t estimatedAltitude ; // cm
int16_t vario ; // cm/s
2016-04-24 01:46:13 +02:00
} __attribute__ ( ( packed ) ) altitude ;
2016-04-22 03:19:51 +02:00
} data ;
2016-04-08 14:04:33 +02:00
2016-04-24 01:46:13 +02:00
if ( PositionStateHandle ( ) ! = NULL ) {
PositionStateData positionState ;
PositionStateGet ( & positionState ) ;
2016-04-08 14:04:33 +02:00
2016-04-24 01:46:13 +02:00
data . altitude . estimatedAltitude = ( int32_t ) roundf ( positionState . Down * - 100.0f ) ;
} else {
data . altitude . estimatedAltitude = 0 ;
}
2016-04-24 01:50:41 +02:00
if ( VelocityStateHandle ( ) ! = NULL ) {
2016-04-24 01:46:13 +02:00
VelocityStateData velocityState ;
VelocityStateGet ( & velocityState ) ;
2016-04-24 01:50:41 +02:00
2016-04-24 01:46:13 +02:00
data . altitude . vario = ( int16_t ) roundf ( velocityState . Down * - 100.0f ) ;
} else {
data . altitude . vario = 0 ;
}
2016-04-08 14:04:33 +02:00
2016-04-24 01:38:30 +02:00
msp_send ( m , MSP_ALTITUDE , data . buf , sizeof ( data ) ) ;
}
2016-04-22 03:19:51 +02:00
# endif /* PIOS_EXCLUDE_ADVANCED_FEATURES */
2016-04-08 14:04:33 +02:00
// Scale stick values whose input range is -1 to 1 to MSP's expected
// PWM range of 1000-2000.
2016-04-22 03:19:51 +02:00
static uint16_t msp_scale_rc ( float percent )
{
return percent * 500 + 1500 ;
2016-04-08 14:04:33 +02:00
}
// Throttle maps to 1100-1900 and a bit differently as -1 == 1000 and
// then jumps immediately to 0 -> 1 for the rest of the range. MWOSD
// can learn ranges as wide as they are sent, but defaults to
// 1100-1900 so the throttle indicator will vary for the same stick
// position unless we send it what it wants right away.
2016-04-22 03:19:51 +02:00
static uint16_t msp_scale_rc_thr ( float percent )
{
2016-04-22 22:53:16 +02:00
return percent < = 0 ? 1100 : percent * 800 + 1100 ;
2016-04-08 14:04:33 +02:00
}
// MSP RC order is Roll/Pitch/Yaw/Throttle/AUX1/AUX2/AUX3/AUX4
static void msp_send_channels ( struct msp_bridge * m )
{
2016-04-24 01:41:42 +02:00
AccessoryDesiredData acc0 , acc1 , acc2 , acc3 ;
2016-04-22 03:19:51 +02:00
ManualControlCommandData manualState ;
ManualControlCommandGet ( & manualState ) ;
AccessoryDesiredInstGet ( 0 , & acc0 ) ;
AccessoryDesiredInstGet ( 1 , & acc1 ) ;
AccessoryDesiredInstGet ( 2 , & acc2 ) ;
2016-04-25 12:55:23 +02:00
AccessoryDesiredInstGet ( 3 , & acc3 ) ;
2016-04-22 03:19:51 +02:00
union {
uint8_t buf [ 0 ] ;
uint16_t channels [ 8 ] ;
} data = {
. channels = {
msp_scale_rc ( manualState . Roll ) ,
msp_scale_rc ( manualState . Pitch * - 1 ) , // TL pitch is backwards
msp_scale_rc ( manualState . Yaw ) ,
msp_scale_rc_thr ( manualState . Throttle ) ,
msp_scale_rc ( acc0 . AccessoryVal ) ,
msp_scale_rc ( acc1 . AccessoryVal ) ,
msp_scale_rc ( acc2 . AccessoryVal ) ,
2016-04-24 01:41:42 +02:00
msp_scale_rc ( acc3 . AccessoryVal ) ,
2016-04-22 03:19:51 +02:00
}
} ;
msp_send ( m , MSP_RC , data . buf , sizeof ( data ) ) ;
2016-04-08 14:04:33 +02:00
}
2016-04-22 03:19:51 +02:00
static void msp_send_boxids ( struct msp_bridge * m ) // This is actually sending a map of MSP_STATUS.flag bits to BOX ids.
{
msp_send ( m , MSP_BOXIDS , msp_boxes , sizeof ( msp_boxes ) ) ;
2016-04-22 03:29:38 +02:00
}
2016-04-08 14:04:33 +02:00
2016-05-11 13:35:40 +02:00
static void msp_send_pidnames ( struct msp_bridge * m )
2016-04-22 03:29:38 +02:00
{
2016-05-11 13:35:40 +02:00
msp_send ( m , MSP_PIDNAMES , ( const uint8_t * ) msp_pidnames , sizeof ( msp_pidnames ) - 1 ) ; // without terminating 0
2016-04-20 18:29:44 +02:00
}
2016-05-11 13:35:40 +02:00
static void pid_native2msp ( const float * native , msp_pid_t * piditem , float scale , unsigned numelem )
2016-04-20 18:29:44 +02:00
{
2016-05-11 13:35:40 +02:00
for ( unsigned i = 0 ; i < numelem ; + + i ) {
piditem - > values [ i ] = lroundf ( native [ i ] * scale ) ;
2016-04-22 03:19:51 +02:00
}
2016-04-20 18:29:44 +02:00
}
2016-05-11 13:35:40 +02:00
static void pid_msp2native ( const msp_pid_t * piditem , float * native , float scale , unsigned numelem )
2016-04-20 18:29:44 +02:00
{
2016-05-11 13:35:40 +02:00
for ( unsigned i = 0 ; i < numelem ; + + i ) {
native [ i ] = ( float ) piditem - > values [ i ] / scale ;
2016-04-22 03:19:51 +02:00
}
2016-04-20 18:29:44 +02:00
}
2016-05-11 13:35:40 +02:00
static UAVObjHandle get_current_pid_bank_handle ( )
2016-04-20 18:29:44 +02:00
{
2016-05-11 13:35:40 +02:00
uint8_t fm ;
2016-04-20 18:29:44 +02:00
2016-05-11 13:35:40 +02:00
ManualControlCommandFlightModeSwitchPositionGet ( & fm ) ;
if ( fm > = FLIGHTMODESETTINGS_FLIGHTMODEPOSITION_NUMELEM ) {
return STABILIZATIONSETTINGS_FLIGHTMODEMAP_BANK1 ;
}
StabilizationSettingsFlightModeMapOptions flightModeMap [ STABILIZATIONSETTINGS_FLIGHTMODEMAP_NUMELEM ] ;
StabilizationSettingsFlightModeMapGet ( flightModeMap ) ;
switch ( flightModeMap [ fm ] )
{
case STABILIZATIONSETTINGS_FLIGHTMODEMAP_BANK1 :
return StabilizationSettingsBank1Handle ( ) ;
case STABILIZATIONSETTINGS_FLIGHTMODEMAP_BANK2 :
return StabilizationSettingsBank2Handle ( ) ;
case STABILIZATIONSETTINGS_FLIGHTMODEMAP_BANK3 :
return StabilizationSettingsBank3Handle ( ) ;
}
return 0 ;
2016-04-20 18:29:44 +02:00
}
static void msp_send_pid ( struct msp_bridge * m )
{
2016-05-11 13:35:40 +02:00
m - > current_pid_bank = get_current_pid_bank_handle ( ) ;
2016-04-22 03:19:51 +02:00
StabilizationBankData bankData ;
2016-05-11 13:35:40 +02:00
UAVObjGetData ( m - > current_pid_bank , & bankData ) ;
2016-04-22 03:19:51 +02:00
msp_pid_t piditems [ PID_ITEM_COUNT ] ;
memset ( piditems , 0 , sizeof ( piditems ) ) ;
2016-05-11 13:35:40 +02:00
pid_native2msp ( ( float * ) & bankData . RollRatePID , & piditems [ PIDROLL ] , 10000 , 3 ) ;
pid_native2msp ( ( float * ) & bankData . PitchRatePID , & piditems [ PIDPITCH ] , 10000 , 3 ) ;
pid_native2msp ( ( float * ) & bankData . YawRatePID , & piditems [ PIDYAW ] , 10000 , 3 ) ;
pid_native2msp ( ( float * ) & bankData . RollPI , & piditems [ PIDAROLL ] , 10 , 2 ) ;
pid_native2msp ( ( float * ) & bankData . PitchPI , & piditems [ PIDAPITCH ] , 10 , 2 ) ;
pid_native2msp ( ( float * ) & bankData . YawPI , & piditems [ PIDAYAW ] , 10 , 2 ) ;
2016-04-22 03:19:51 +02:00
msp_send ( m , MSP_PID , ( const uint8_t * ) piditems , sizeof ( piditems ) ) ;
2016-04-08 14:04:33 +02:00
}
2016-04-20 18:29:44 +02:00
static void msp_set_pid ( struct msp_bridge * m )
{
2016-05-11 13:35:40 +02:00
if ( m - > current_pid_bank = = 0 ) {
return ;
}
2016-04-22 03:19:51 +02:00
2016-05-11 13:35:40 +02:00
StabilizationBankData bankData ;
UAVObjGetData ( m - > current_pid_bank , & bankData ) ;
2016-04-22 03:19:51 +02:00
2016-05-11 13:35:40 +02:00
pid_msp2native ( & m - > cmd_data . piditems [ PIDROLL ] , ( float * ) & bankData . RollRatePID , 10000 , 3 ) ;
pid_msp2native ( & m - > cmd_data . piditems [ PIDPITCH ] , ( float * ) & bankData . PitchRatePID , 10000 , 3 ) ;
pid_msp2native ( & m - > cmd_data . piditems [ PIDYAW ] , ( float * ) & bankData . YawRatePID , 10000 , 3 ) ;
2016-04-22 03:19:51 +02:00
2016-05-11 13:35:40 +02:00
pid_msp2native ( & m - > cmd_data . piditems [ PIDAROLL ] , ( float * ) & bankData . RollPI , 10 , 2 ) ;
pid_msp2native ( & m - > cmd_data . piditems [ PIDAPITCH ] , ( float * ) & bankData . PitchPI , 10 , 2 ) ;
pid_msp2native ( & m - > cmd_data . piditems [ PIDAYAW ] , ( float * ) & bankData . YawPI , 10 , 2 ) ;
2016-04-22 03:19:51 +02:00
2016-05-11 13:35:40 +02:00
UAVObjSetData ( m - > current_pid_bank , & bankData ) ;
bool needSave = true ;
if ( needSave ) {
FlightStatusArmedOptions armed ;
FlightStatusArmedGet ( & armed ) ;
if ( armed = = FLIGHTSTATUS_ARMED_DISARMED ) {
UAVObjSave ( m - > current_pid_bank , 0 ) ;
}
}
2016-04-22 03:19:51 +02:00
msp_send ( m , MSP_SET_PID , 0 , 0 ) ; // send ack.
2016-04-20 18:29:44 +02:00
}
2016-04-22 03:19:51 +02:00
# define ALARM_OK 0
# define ALARM_WARN 1
2016-04-08 14:04:33 +02:00
# define ALARM_ERROR 2
2016-04-22 03:19:51 +02:00
# define ALARM_CRIT 3
2016-04-08 14:04:33 +02:00
# define MS2TICKS(m) ((m) / (portTICK_RATE_MS))
2016-04-22 03:19:51 +02:00
static void msp_send_alarms ( __attribute__ ( ( unused ) ) struct msp_bridge * m )
{
union {
uint8_t buf [ 0 ] ;
struct {
uint8_t state ;
char msg [ MAX_ALARM_LEN ] ;
} __attribute__ ( ( packed ) ) alarm ;
} data ;
2016-04-08 14:04:33 +02:00
2016-04-22 03:19:51 +02:00
SystemAlarmsData alarm ;
SystemAlarmsGet ( & alarm ) ;
2016-04-08 14:04:33 +02:00
2016-04-22 03:19:51 +02:00
// Special case early boot times -- just report boot reason
2016-04-08 14:04:33 +02:00
2016-04-22 00:22:07 +02:00
#if 0
2016-04-22 03:19:51 +02:00
if ( xTaskGetTickCount ( ) < MS2TICKS ( 10 * 1000 ) ) {
data . alarm . state = ALARM_CRIT ;
const char * boot_reason = AlarmBootReason ( alarm . RebootCause ) ;
strncpy ( ( char * ) data . alarm . msg , boot_reason , MAX_ALARM_LEN ) ;
data . alarm . msg [ MAX_ALARM_LEN - 1 ] = ' \0 ' ;
msp_send ( m , MSP_ALARMS , data . buf , strlen ( ( char * ) data . alarm . msg ) + 1 ) ;
return ;
}
2016-04-22 00:22:07 +02:00
# endif
2016-04-08 14:04:33 +02:00
2016-04-22 03:19:51 +02:00
uint8_t state ;
data . alarm . state = ALARM_OK ;
int32_t len = AlarmString ( & alarm , data . alarm . msg ,
sizeof ( data . alarm . msg ) , SYSTEMALARMS_ALARM_CRITICAL , & state ) ; // Include only CRITICAL and ERROR
2016-04-26 11:54:47 +02:00
// NOTE: LP alarm severity levels and MSP levels do not match. ERROR and CRITICAL are swapped.
// So far, MW-OSD code (MSP consumer) does not make difference between ALARM_ERROR and ALARM_CRITICAL.
// ALARM_WARN should be blinking if thats the highest severity level at the moment.
// There might be other types of MSP consumers.
2016-04-22 03:19:51 +02:00
switch ( state ) {
case SYSTEMALARMS_ALARM_WARNING :
data . alarm . state = ALARM_WARN ;
break ;
case SYSTEMALARMS_ALARM_ERROR :
2016-04-26 11:54:47 +02:00
data . alarm . state = ALARM_CRIT ;
2016-04-22 03:19:51 +02:00
break ;
case SYSTEMALARMS_ALARM_CRITICAL :
2016-04-26 11:54:47 +02:00
data . alarm . state = ALARM_ERROR ;
2016-04-26 11:56:58 +02:00
break ;
2016-04-22 03:19:51 +02:00
}
msp_send ( m , MSP_ALARMS , data . buf , len + 1 ) ;
2016-04-08 14:04:33 +02:00
}
static msp_state msp_state_checksum ( struct msp_bridge * m , uint8_t b )
{
2016-04-22 03:19:51 +02:00
if ( ( m - > checksum ^ b ) ! = 0 ) {
return MSP_IDLE ;
}
// Respond to interesting things.
switch ( m - > cmd_id ) {
case MSP_RAW_GPS :
msp_send_raw_gps ( m ) ;
break ;
# ifndef PIOS_EXCLUDE_ADVANCED_FEATURES
case MSP_COMP_GPS :
msp_send_comp_gps ( m ) ;
break ;
case MSP_ALTITUDE :
msp_send_altitude ( m ) ;
break ;
# endif /* PIOS_EXCLUDE_ADVANCED_FEATURES */
case MSP_ATTITUDE :
msp_send_attitude ( m ) ;
break ;
case MSP_STATUS :
msp_send_status ( m ) ;
break ;
case MSP_ANALOG :
msp_send_analog ( m ) ;
break ;
case MSP_RC :
msp_send_channels ( m ) ;
break ;
case MSP_BOXIDS :
msp_send_boxids ( m ) ;
break ;
case MSP_ALARMS :
msp_send_alarms ( m ) ;
break ;
case MSP_PID :
msp_send_pid ( m ) ;
break ;
case MSP_SET_PID :
msp_set_pid ( m ) ;
break ;
2016-05-11 13:35:40 +02:00
case MSP_PIDNAMES :
msp_send_pidnames ( m ) ;
break ;
2016-04-22 03:19:51 +02:00
}
return MSP_IDLE ;
2016-04-08 14:04:33 +02:00
}
static msp_state msp_state_discard ( struct msp_bridge * m , __attribute__ ( ( unused ) ) uint8_t b )
{
2016-04-22 03:19:51 +02:00
return m - > cmd_i + + = = m - > cmd_size ? MSP_IDLE : MSP_DISCARD ;
2016-04-08 14:04:33 +02:00
}
/**
* Process incoming bytes from an MSP query thing .
* @ param [ in ] b received byte
* @ return true if we should continue processing bytes
*/
static bool msp_receive_byte ( struct msp_bridge * m , uint8_t b )
{
2016-04-22 03:19:51 +02:00
switch ( m - > state ) {
case MSP_IDLE :
switch ( b ) {
case 0xe0 : // uavtalk matching first part of 0x3c @ 57600 baud
m - > state = MSP_MAYBE_UAVTALK_SLOW2 ;
break ;
case ' < ' : // uavtalk matching with 0x3c 0x2x 0xxx 0x0x
m - > state = MSP_MAYBE_UAVTALK2 ;
break ;
case ' $ ' :
m - > state = MSP_HEADER_START ;
break ;
default :
m - > state = MSP_IDLE ;
}
break ;
case MSP_HEADER_START :
m - > state = b = = ' M ' ? MSP_HEADER_M : MSP_IDLE ;
break ;
case MSP_HEADER_M :
m - > state = b = = ' < ' ? MSP_HEADER_SIZE : MSP_IDLE ;
break ;
case MSP_HEADER_SIZE :
m - > state = msp_state_size ( m , b ) ;
break ;
case MSP_HEADER_CMD :
m - > state = msp_state_cmd ( m , b ) ;
break ;
case MSP_FILLBUF :
m - > state = msp_state_fill_buf ( m , b ) ;
break ;
case MSP_CHECKSUM :
m - > state = msp_state_checksum ( m , b ) ;
break ;
case MSP_DISCARD :
m - > state = msp_state_discard ( m , b ) ;
break ;
case MSP_MAYBE_UAVTALK2 :
// e.g. 3c 20 1d 00
// second possible uavtalk byte
m - > state = ( b & 0xf0 ) = = 0x20 ? MSP_MAYBE_UAVTALK3 : MSP_IDLE ;
break ;
case MSP_MAYBE_UAVTALK3 :
// third possible uavtalk byte can be anything
m - > state = MSP_MAYBE_UAVTALK4 ;
break ;
case MSP_MAYBE_UAVTALK4 :
m - > state = MSP_IDLE ;
// If this looks like the fourth possible uavtalk byte, we're done
if ( ( b & 0xf0 ) = = 0 ) {
PIOS_COM_TELEM_RF = m - > com ;
return false ;
}
break ;
case MSP_MAYBE_UAVTALK_SLOW2 :
m - > state = b = = 0x18 ? MSP_MAYBE_UAVTALK_SLOW3 : MSP_IDLE ;
break ;
case MSP_MAYBE_UAVTALK_SLOW3 :
m - > state = b = = 0x98 ? MSP_MAYBE_UAVTALK_SLOW4 : MSP_IDLE ;
break ;
case MSP_MAYBE_UAVTALK_SLOW4 :
m - > state = b = = 0x7e ? MSP_MAYBE_UAVTALK_SLOW5 : MSP_IDLE ;
break ;
case MSP_MAYBE_UAVTALK_SLOW5 :
m - > state = b = = 0x00 ? MSP_MAYBE_UAVTALK_SLOW6 : MSP_IDLE ;
break ;
case MSP_MAYBE_UAVTALK_SLOW6 :
m - > state = MSP_IDLE ;
// If this looks like the sixth possible 57600 baud uavtalk byte, we're done
if ( b = = 0x60 ) {
PIOS_COM_ChangeBaud ( m - > com , 57600 ) ;
PIOS_COM_TELEM_RF = m - > com ;
return false ;
}
break ;
}
return true ;
2016-04-08 14:04:33 +02:00
}
/**
* Module start routine automatically called after initialization routine
* @ return 0 when was successful
*/
static int32_t uavoMSPBridgeStart ( void )
{
2016-04-22 03:19:51 +02:00
if ( ! module_enabled ) {
// give port to telemetry if it doesn't have one
// stops board getting stuck in condition where it can't be connected to gcs
if ( ! PIOS_COM_TELEM_RF ) {
PIOS_COM_TELEM_RF = pios_com_msp_id ;
}
2016-04-08 14:04:33 +02:00
2016-04-22 03:19:51 +02:00
return - 1 ;
}
2016-04-08 14:04:33 +02:00
2016-04-22 03:19:51 +02:00
xTaskHandle taskHandle ;
2016-04-08 14:04:33 +02:00
2016-04-22 03:19:51 +02:00
xTaskCreate ( uavoMSPBridgeTask , " uavoMSPBridge " , STACK_SIZE_BYTES / 4 , NULL , TASK_PRIORITY , & taskHandle ) ;
PIOS_TASK_MONITOR_RegisterTask ( TASKINFO_RUNNING_UAVOMSPBRIDGE , taskHandle ) ;
return 0 ;
2016-04-08 14:04:33 +02:00
}
static uint32_t hwsettings_mspspeed_enum_to_baud ( uint8_t baud )
{
switch ( baud ) {
case HWSETTINGS_MSPSPEED_2400 :
return 2400 ;
case HWSETTINGS_MSPSPEED_4800 :
return 4800 ;
case HWSETTINGS_MSPSPEED_9600 :
return 9600 ;
case HWSETTINGS_MSPSPEED_19200 :
return 19200 ;
case HWSETTINGS_MSPSPEED_38400 :
return 38400 ;
case HWSETTINGS_MSPSPEED_57600 :
return 57600 ;
2016-04-08 14:20:20 +02:00
default :
2016-04-08 14:04:33 +02:00
case HWSETTINGS_MSPSPEED_115200 :
return 115200 ;
}
}
/**
* Module initialization routine
* @ return 0 when initialization was successful
*/
static int32_t uavoMSPBridgeInitialize ( void )
{
2016-04-22 03:19:51 +02:00
if ( pios_com_msp_id ) {
msp = pios_malloc ( sizeof ( * msp ) ) ;
if ( msp ! = NULL ) {
memset ( msp , 0x00 , sizeof ( * msp ) ) ;
msp - > com = pios_com_msp_id ;
// now figure out enabled features: registered sensors, ADC routing, GPS
# ifdef PIOS_EXCLUDE_ADVANCED_FEATURES
msp - > sensors | = MSP_SENSOR_ACC ;
# else
if ( PIOS_SENSORS_GetInstanceByType ( 0 , PIOS_SENSORS_TYPE_3AXIS_ACCEL ) ) {
msp - > sensors | = MSP_SENSOR_ACC ;
}
if ( PIOS_SENSORS_GetInstanceByType ( 0 , PIOS_SENSORS_TYPE_1AXIS_BARO ) ) {
msp - > sensors | = MSP_SENSOR_BARO ;
}
if ( PIOS_SENSORS_GetInstanceByType ( 0 , PIOS_SENSORS_TYPE_3AXIS_MAG | PIOS_SENSORS_TYPE_3AXIS_AUXMAG ) ) {
msp - > sensors | = MSP_SENSOR_MAG ;
}
2016-04-08 14:04:33 +02:00
# ifdef PIOS_SENSORS_TYPE_1AXIS_SONAR
2016-04-22 03:19:51 +02:00
if ( PIOS_SENSORS_GetInstanceByType ( 0 , PIOS_SENSORS_TYPE_1AXIS_SONAR ) ) {
msp - > sensors | = MSP_SENSOR_SONAR ;
}
# endif /* PIOS_SENSORS_TYPE_1AXIS_SONAR */
# endif /* PIOS_EXCLUDE_ADVANCED_FEATURES */
// MAP_SENSOR_GPS is hot-pluggable type
HwSettingsADCRoutingDataArray adcRoutingDataArray ;
HwSettingsADCRoutingArrayGet ( adcRoutingDataArray . array ) ;
for ( unsigned i = 0 ; i < sizeof ( adcRoutingDataArray . array ) / sizeof ( adcRoutingDataArray . array [ 0 ] ) ; + + i ) {
switch ( adcRoutingDataArray . array [ i ] ) {
case HWSETTINGS_ADCROUTING_BATTERYVOLTAGE :
msp - > analog | = MSP_ANALOG_VOLTAGE ;
break ;
case HWSETTINGS_ADCROUTING_BATTERYCURRENT :
msp - > analog | = MSP_ANALOG_CURRENT ;
break ;
default : ;
}
}
HwSettingsMSPSpeedOptions mspSpeed ;
HwSettingsMSPSpeedGet ( & mspSpeed ) ;
PIOS_COM_ChangeBaud ( pios_com_msp_id , hwsettings_mspspeed_enum_to_baud ( mspSpeed ) ) ;
module_enabled = true ;
return 0 ;
}
}
return - 1 ;
2016-04-08 14:04:33 +02:00
}
MODULE_INITCALL ( uavoMSPBridgeInitialize , uavoMSPBridgeStart ) ;
/**
* Main task routine
* @ param [ in ] parameters parameter given by PIOS_Thread_Create ( )
*/
static void uavoMSPBridgeTask ( __attribute__ ( ( unused ) ) void * parameters )
{
2016-04-22 03:19:51 +02:00
while ( 1 ) {
uint8_t b = 0 ;
uint16_t count = PIOS_COM_ReceiveBuffer ( msp - > com , & b , 1 , ~ 0 ) ;
if ( count ) {
if ( ! msp_receive_byte ( msp , b ) ) {
// Returning is considered risky here as
// that's unusual and this is an edge case.
while ( 1 ) {
PIOS_DELAY_WaitmS ( 60 * 1000 ) ;
}
}
}
}
2016-04-08 14:04:33 +02:00
}
2016-04-22 03:19:51 +02:00
# endif // PIOS_INCLUDE_MSP_BRIDGE
2016-04-08 14:04:33 +02:00
/**
* @ }
* @ }
*/