1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-29 14:52:12 +01:00

OP-423: merge master into that branch, resolve conflicts and test with CC and bl_CC

heap reamining is low (about 500) but stacks can be ajusted (specially the 200 bytes from system) to give the level close to 1Ko if needed.

Merge branch 'master' into OP-423_Mathieu_Change_Init_To_Reduce_Memory_Footprint

Conflicts:
	flight/CopterControl/System/inc/FreeRTOSConfig.h
	flight/CopterControl/System/inc/pios_config.h
This commit is contained in:
Mathieu Rondonneau 2011-06-17 19:04:09 -07:00
commit b67a38661e
19 changed files with 179 additions and 58 deletions

View File

@ -137,6 +137,7 @@ endif
## UAVOBJECTS
ifndef TESTAPP
SRC += $(OPUAVSYNTHDIR)/accessorydesired.c
SRC += $(OPUAVSYNTHDIR)/objectpersistence.c
SRC += $(OPUAVSYNTHDIR)/gcstelemetrystats.c
SRC += $(OPUAVSYNTHDIR)/flighttelemetrystats.c

View File

@ -75,6 +75,19 @@ NVIC value of 255. */
#define CHECK_IRQ_STACK
#endif
/* Enable run time stats collection */
//#if defined(DEBUG)
#define configGENERATE_RUN_TIME_STATS 1
#define INCLUDE_uxTaskGetRunTime 1
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()\
do {\
(*(unsigned long *)0xe000edfc) |= (1<<24);/* DEMCR |= DEMCR_TRCENA */\
(*(unsigned long *)0xe0001000) |= 1; /* DWT_CTRL |= DWT_CYCCNT_ENA */\
} while(0)
#define portGET_RUN_TIME_COUNTER_VALUE() (*(unsigned long *)0xe0001004)/* DWT_CYCCNT */
//#endif
/**
* @}
*/

View File

@ -84,11 +84,11 @@
#define AUXUART_ENABLED 0
#define AUXUART_BAUDRATE 19200
/* Alarm Thresholds */
#define HEAP_LIMIT_WARNING 350
#define HEAP_LIMIT_CRITICAL 250
/* Alarm Thresholds */
#define HEAP_LIMIT_WARNING 220
#define HEAP_LIMIT_CRITICAL 150
#define IRQSTACK_LIMIT_WARNING 150
#define IRQSTACK_LIMIT_CRITICAL 80
#define IRQSTACK_LIMIT_CRITICAL 80
#define CPULOAD_LIMIT_WARNING 80
#define CPULOAD_LIMIT_CRITICAL 95

View File

@ -35,21 +35,23 @@
// Private variables
static xSemaphoreHandle lock;
static xTaskHandle handles[TASKINFO_RUNNING_NUMELEM];
static uint32_t lastMonitorTime;
// Private functions
/**
* Initialize library
* Initialize library
*/
int32_t TaskMonitorInitialize(void)
{
lock = xSemaphoreCreateRecursiveMutex();
memset(handles, 0, sizeof(xTaskHandle)*TASKINFO_RUNNING_NUMELEM);
lastMonitorTime = portGET_RUN_TIME_COUNTER_VALUE();
return 0;
}
/**
* Register a task handle with the library
* Register a task handle with the library
*/
int32_t TaskMonitorAdd(TaskInfoRunningElem task, xTaskHandle handle)
{
@ -67,16 +69,30 @@ int32_t TaskMonitorAdd(TaskInfoRunningElem task, xTaskHandle handle)
}
/**
* Update the status of all tasks
* Update the status of all tasks
*/
void TaskMonitorUpdateAll(void)
{
TaskInfoData data;
int n;
// Lock
xSemaphoreTakeRecursive(lock, portMAX_DELAY);
#if ( configGENERATE_RUN_TIME_STATS == 1 )
uint32_t currentTime;
uint32_t deltaTime;
/*
* Calculate the amount of elapsed run time between the last time we
* measured and now. Scale so that we can convert task run times
* directly to percentages.
*/
currentTime = portGET_RUN_TIME_COUNTER_VALUE();
deltaTime = ((currentTime - lastMonitorTime) / 100) ? : 1; /* avoid divide-by-zero if the interval is too small */
lastMonitorTime = currentTime;
#endif
// Update all task information
for (n = 0; n < TASKINFO_RUNNING_NUMELEM; ++n)
{
@ -87,18 +103,24 @@ void TaskMonitorUpdateAll(void)
data.StackRemaining[n] = 10000;
#else
data.StackRemaining[n] = uxTaskGetStackHighWaterMark(handles[n]) * 4;
#if ( configGENERATE_RUN_TIME_STATS == 1 )
/* Generate run time stats */
data.RunningTime[n] = uxTaskGetRunTime(handles[n]) / deltaTime;
#endif
#endif
}
else
{
data.Running[n] = TASKINFO_RUNNING_FALSE;
data.StackRemaining[n] = 0;
data.RunningTime[n] = 0;
}
}
// Update object
TaskInfoSet(&data);
// Done
xSemaphoreGiveRecursive(lock);
}

View File

@ -32,6 +32,7 @@
#include "openpilot.h"
#include "accessorydesired.h"
#include "actuator.h"
#include "actuatorsettings.h"
#include "systemsettings.h"
@ -74,7 +75,6 @@ static int16_t scaleChannel(float value, int16_t max, int16_t min, int16_t neutr
static void setFailsafe();
static float MixerCurve(const float throttle, const float* curve);
static bool set_channel(uint8_t mixer_channel, uint16_t value);
float ProcessMixer(const int index, const float curve1, const float curve2,
MixerSettingsData* mixerSettings, ActuatorDesiredData* desired,
const float period);
@ -201,7 +201,35 @@ static void actuatorTask(void* parameters)
bool spinWhileArmed = MotorsSpinWhileArmed == ACTUATORSETTINGS_MOTORSSPINWHILEARMED_TRUE;
float curve1 = MixerCurve(desired.Throttle,mixerSettings.ThrottleCurve1);
float curve2 = MixerCurve(desired.Throttle,mixerSettings.ThrottleCurve2);
//The source for the secondary curve is selectable
float curve2 = 0;
AccessoryDesiredData accessory;
switch(mixerSettings.Curve2Source) {
case MIXERSETTINGS_CURVE2SOURCE_THROTTLE:
curve2 = MixerCurve(desired.Throttle,mixerSettings.ThrottleCurve2);
break;
case MIXERSETTINGS_CURVE2SOURCE_ROLL:
curve2 = MixerCurve(desired.Roll,mixerSettings.ThrottleCurve2);
break;
case MIXERSETTINGS_CURVE2SOURCE_PITCH:
curve2 = MixerCurve(desired.Pitch,mixerSettings.ThrottleCurve2);
break;
case MIXERSETTINGS_CURVE2SOURCE_YAW:
curve2 = MixerCurve(desired.Yaw,mixerSettings.ThrottleCurve2);
break;
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY0:
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY1:
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY2:
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY3:
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY4:
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY5:
if(AccessoryDesiredInstGet(mixerSettings.Curve2Source - MIXERSETTINGS_CURVE2SOURCE_ACCESSORY0,&accessory) == 0)
curve2 = MixerCurve(accessory.AccessoryVal,mixerSettings.ThrottleCurve2);
else
curve2 = 0;
break;
}
for(int ct=0; ct < MAX_MIX_ACTUATORS; ct++)
{
if(mixers[ct].type == MIXERSETTINGS_MIXER1TYPE_DISABLED) {
@ -229,7 +257,22 @@ static void actuatorTask(void* parameters)
(status[ct] < 0) )
status[ct] = 0;
}
// If an accessory channel is selected for direct bypass mode
// In this configuration the accessory channel is scaled and mapped
// directly to output. Note: THERE IS NO SAFETY CHECK HERE FOR ARMING
// these also will not be updated in failsafe mode. I'm not sure what
// the correct behavior is since it seems domain specific. I don't love
// this code
if( (mixers[ct].type >= MIXERSETTINGS_MIXER1TYPE_ACCESSORY0) &&
(mixers[ct].type <= MIXERSETTINGS_MIXER1TYPE_ACCESSORY2))
{
if(AccessoryDesiredInstGet(mixers[ct].type - MIXERSETTINGS_MIXER1TYPE_ACCESSORY0,&accessory) == 0)
status[ct] = accessory.AccessoryVal;
else
status[ct] = -1;
}
command.Channel[ct] = scaleChannel(status[ct],
ChannelMax[ct],
ChannelMin[ct],
@ -453,8 +496,6 @@ static void actuator_update_rate(UAVObjEvent * ev)
}
}
#if defined(ARCH_POSIX) || defined(ARCH_WIN32)
static bool set_channel(uint8_t mixer_channel, uint16_t value) {
return true;

View File

@ -42,6 +42,7 @@
#include "stabilizationdesired.h"
#include "flighttelemetrystats.h"
#include "flightstatus.h"
#include "accessorydesired.h"
// Private constants
#if defined(PIOS_MANUAL_STACK_SIZE)
@ -171,6 +172,11 @@ static void manualControlTask(void *parameters)
uint8_t disconnected_count = 0;
uint8_t connected_count = 0;
// For now manual instantiate extra instances of Accessory Desired. In future should be done dynamically
// this includes not even registering it if not used
AccessoryDesiredCreateInstance();
AccessoryDesiredCreateInstance();
// Make sure unarmed on power up
ManualControlCommandGet(&cmd);
FlightStatusGet(&flightStatus);
@ -267,10 +273,26 @@ static void manualControlTask(void *parameters)
cmd.Throttle = scaledChannel[settings.Throttle];
flightMode = scaledChannel[settings.FlightMode];
// Set accessory channels
cmd.Accessory1 = (settings.Accessory1 != MANUALCONTROLSETTINGS_ACCESSORY1_NONE) ? scaledChannel[settings.Accessory1] : 0;
cmd.Accessory2 = (settings.Accessory2 != MANUALCONTROLSETTINGS_ACCESSORY2_NONE) ? scaledChannel[settings.Accessory2] : 0;
cmd.Accessory3 = (settings.Accessory3 != MANUALCONTROLSETTINGS_ACCESSORY3_NONE) ? scaledChannel[settings.Accessory3] : 0;
AccessoryDesiredData accessory;
// Set Accessory 0
if(settings.Accessory0 != MANUALCONTROLSETTINGS_ACCESSORY0_NONE) {
accessory.AccessoryVal = scaledChannel[settings.Accessory0];
if(AccessoryDesiredInstSet(0, &accessory) != 0)
AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING);
}
// Set Accessory 1
if(settings.Accessory1 != MANUALCONTROLSETTINGS_ACCESSORY1_NONE) {
accessory.AccessoryVal = scaledChannel[settings.Accessory1];
if(AccessoryDesiredInstSet(1, &accessory) != 0)
AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING);
}
// Set Accsesory 2
if(settings.Accessory2 != MANUALCONTROLSETTINGS_ACCESSORY2_NONE) {
accessory.AccessoryVal = scaledChannel[settings.Accessory2];
if(AccessoryDesiredInstSet(2, &accessory) != 0)
AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING);
}
processFlightMode(&settings, flightMode);
processArm(&cmd, &settings);

View File

@ -75,9 +75,12 @@ NVIC value of 255. */
#if defined(DEBUG)
#define configGENERATE_RUN_TIME_STATS 1
#define INCLUDE_uxTaskGetRunTime 1
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() PIOS_RTC_Init()
// Note: Using the tick count defeats the purpose here, need some timer on the scale of 10khz
#define portGET_RUN_TIME_COUNTER_VALUE() PIOS_RTC_Counter()
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()\
do {\
(*(unsigned long *)0xe000edfc) |= (1<<24);/* DEMCR |= DEMCR_TRCENA */\
(*(unsigned long *)0xe0001000) |= 1; /* DWT_CTRL |= DWT_CYCCNT_ENA */\
} while(0)
#define portGET_RUN_TIME_COUNTER_VALUE() (*(unsigned long *)0xe0001004)/* DWT_CYCCNT */
#endif
#if !defined(ARCH_POSIX) && !defined(ARCH_WIN32)

View File

@ -35,6 +35,7 @@
// Private variables
static xSemaphoreHandle lock;
static xTaskHandle handles[TASKINFO_RUNNING_NUMELEM];
static uint32_t lastMonitorTime;
// Private functions
@ -45,6 +46,7 @@ int32_t TaskMonitorInitialize(void)
{
lock = xSemaphoreCreateRecursiveMutex();
memset(handles, 0, sizeof(xTaskHandle)*TASKINFO_RUNNING_NUMELEM);
lastMonitorTime = portGET_RUN_TIME_COUNTER_VALUE();
return 0;
}
@ -95,6 +97,20 @@ void TaskMonitorUpdateAll(void)
// Lock
xSemaphoreTakeRecursive(lock, portMAX_DELAY);
#if ( configGENERATE_RUN_TIME_STATS == 1 )
uint32_t currentTime;
uint32_t deltaTime;
/*
* Calculate the amount of elapsed run time between the last time we
* measured and now. Scale so that we can convert task run times
* directly to percentages.
*/
currentTime = portGET_RUN_TIME_COUNTER_VALUE();
deltaTime = ((currentTime - lastMonitorTime) / 100) ? : 1; /* avoid divide-by-zero if the interval is too small */
lastMonitorTime = currentTime;
#endif
// Update all task information
for (n = 0; n < TASKINFO_RUNNING_NUMELEM; ++n)
{
@ -107,7 +123,8 @@ void TaskMonitorUpdateAll(void)
data.StackRemaining[n] = uxTaskGetStackHighWaterMark(handles[n]) * 4;
#if ( configGENERATE_RUN_TIME_STATS == 1 )
/* Generate run time stats */
data.RunningTime[n] = 100 * (float) uxTaskGetRunTime(handles[n]) / portGET_RUN_TIME_COUNTER_VALUE();
data.RunningTime[n] = uxTaskGetRunTime(handles[n]) / deltaTime;
#endif
#endif

View File

@ -24,6 +24,7 @@
# (all architectures)
UAVOBJSRCFILENAMES =
UAVOBJSRCFILENAMES += accessorydesired
UAVOBJSRCFILENAMES += actuatorcommand
UAVOBJSRCFILENAMES += actuatordesired
UAVOBJSRCFILENAMES += actuatorsettings

View File

@ -105,7 +105,7 @@ int32_t PIOS_FLASHFS_Init()
*/
static int32_t PIOS_FLASHFS_CleabObjectTableHeader()
{
if(PIOS_Flash_W25X_EraseSector(OBJECT_TABLE_START) != 0)
if(PIOS_Flash_W25X_EraseSector(0) != 0)
return -1;
uint32_t object_table_magic = OBJECT_TABLE_MAGIC;

View File

@ -2315,9 +2315,13 @@ tskTCB *pxNewTCB;
#if ( INCLUDE_uxTaskGetRunTime == 1 )
unsigned portBASE_TYPE uxTaskGetRunTime( xTaskHandle xTask )
{
unsigned long runTime;
tskTCB *pxTCB;
pxTCB = prvGetTCBFromHandle( xTask );
return pxTCB->ulRunTimeCounter;
runTime = pxTCB->ulRunTimeCounter;
pxTCB->ulRunTimeCounter = 0;
return runTime;
}
#endif

View File

@ -2738,6 +2738,7 @@
65E6E09912E037C800058553 /* pios_adc_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_adc_priv.h; sourceTree = "<group>"; };
65E8C743139A6D0900E1F979 /* pios_crc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pios_crc.c; sourceTree = "<group>"; };
65E8C745139A6D1A00E1F979 /* pios_crc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_crc.h; sourceTree = "<group>"; };
65E8C788139AA2A800E1F979 /* accessorydesired.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = accessorydesired.xml; sourceTree = "<group>"; };
65E8EF1F11EEA61E00BBF654 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = ../../OpenPilot/Makefile; sourceTree = SOURCE_ROOT; };
65E8EF2011EEA61E00BBF654 /* Makefile.posix */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Makefile.posix; path = ../../OpenPilot/Makefile.posix; sourceTree = SOURCE_ROOT; };
65E8EF5C11EEA61E00BBF654 /* alarms.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = alarms.c; path = ../../OpenPilot/System/alarms.c; sourceTree = SOURCE_ROOT; };
@ -7418,6 +7419,7 @@
65C35E4F12EFB2F3004811C2 /* uavobjectdefinition */ = {
isa = PBXGroup;
children = (
65E8C788139AA2A800E1F979 /* accessorydesired.xml */,
65C35E5012EFB2F3004811C2 /* actuatorcommand.xml */,
65C35E5112EFB2F3004811C2 /* actuatordesired.xml */,
65C35E5212EFB2F3004811C2 /* actuatorsettings.xml */,

View File

@ -1,7 +1,7 @@
define connect
target remote localhost:3333
monitor cortex_m3 vector_catch all
file ./build/coptercontrol/CopterControl.elf
file ./build/fw_coptercontrol/fw_coptercontrol.elf
end
#monitor reset halt

View File

@ -23,7 +23,8 @@ SOURCES += uavobject.cpp \
OTHER_FILES += UAVObjects.pluginspec
# Add in all of the synthetic/generated uavobject files
HEADERS += $$UAVOBJECT_SYNTHETICS/ahrsstatus.h \
HEADERS += $$UAVOBJECT_SYNTHETICS/accessorydesired.h \
$$UAVOBJECT_SYNTHETICS/ahrsstatus.h \
$$UAVOBJECT_SYNTHETICS/ahrscalibration.h \
$$UAVOBJECT_SYNTHETICS/baroaltitude.h \
$$UAVOBJECT_SYNTHETICS/attitudeactual.h \
@ -69,7 +70,8 @@ HEADERS += $$UAVOBJECT_SYNTHETICS/ahrsstatus.h \
$$UAVOBJECT_SYNTHETICS/flightstatus.h \
$$UAVOBJECT_SYNTHETICS/attitudesettings.h
SOURCES += $$UAVOBJECT_SYNTHETICS/ahrsstatus.cpp \
SOURCES += $$UAVOBJECT_SYNTHETICS/accessorydesired.cpp \
$$UAVOBJECT_SYNTHETICS/ahrsstatus.cpp \
$$UAVOBJECT_SYNTHETICS/ahrscalibration.cpp \
$$UAVOBJECT_SYNTHETICS/baroaltitude.cpp \
$$UAVOBJECT_SYNTHETICS/attitudeactual.cpp \

View File

@ -295,7 +295,7 @@ bool UAVTalk::processInputByte(quint8 rxbyte)
}
// Check the lengths match
if ((rxPacketLength + rxLength) != packetSize)
if ((rxPacketLength + rxLength + (rxObj->isSingleInstance() ? 0 : 2)) != packetSize)
{ // packet error - mismatched packet size
stats.rxErrors++;
rxState = STATE_SYNC;
@ -805,17 +805,3 @@ quint8 UAVTalk::updateCRC(quint8 crc, const quint8* data, qint32 length)
crc = crc_table[crc ^ *data++];
return crc;
}

View File

@ -0,0 +1,10 @@
<xml>
<object name="AccessoryDesired" singleinstance="false" settings="false">
<description>Desired Auxillary actuator settings. Comes from @ref ManualControlModule.</description>
<field name="AccessoryVal" units="" type="float" elements="1"/>
<access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="false" updatemode="manual" period="0"/>
<telemetryflight acked="false" updatemode="periodic" period="1000"/>
<logging updatemode="never" period="0"/>
</object>
</xml>

View File

@ -6,11 +6,7 @@
<field name="Pitch" units="%" type="float" elements="1"/>
<field name="Yaw" units="%" type="float" elements="1"/>
<field name="Throttle" units="%" type="float" elements="1"/>
<field name="Accessory1" units="%" type="float" elements="1"/>
<field name="Accessory2" units="%" type="float" elements="1"/>
<field name="Accessory3" units="%" type="float" elements="1"/>
<field name="Channel" units="us" type="uint16" elements="8"/>
<field name="Channel" units="us" type="uint16" elements="8"/>
<access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="false" updatemode="manual" period="0"/>
<telemetryflight acked="false" updatemode="periodic" period="2000"/>

View File

@ -7,9 +7,9 @@
<field name="Yaw" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,None" defaultvalue="None"/>
<field name="Throttle" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,None" defaultvalue="None"/>
<field name="FlightMode" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,None" defaultvalue="None"/>
<field name="Accessory0" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,None" defaultvalue="None"/>
<field name="Accessory1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,None" defaultvalue="None"/>
<field name="Accessory2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,None" defaultvalue="None"/>
<field name="Accessory3" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,None" defaultvalue="None"/>
<field name="Arming" units="" type="enum" elements="1" options="Always Disarmed,Always Armed,Roll Left,Roll Right,Pitch Forward,Pitch Aft,Yaw Left,Yaw Right" defaultvalue="Always Disarmed"/>
<!-- Note these options should be identical to those in StabilizationDesired.StabilizationMode -->

View File

@ -6,22 +6,23 @@
<field name="AccelTime" units="ms" type="float" elements="1" defaultvalue="0"/>
<field name="DecelTime" units="ms" type="float" elements="1" defaultvalue="0"/>
<field name="ThrottleCurve1" units="percent" type="float" elements="5" elementnames="0,25,50,75,100" defaultvalue="0,0.25,0.5,0.75,1"/>
<field name="Curve2Source" units="" type="enum" elements="1" options="Throttle,Roll,Pitch,Yaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Throttle"/>
<field name="ThrottleCurve2" units="percent" type="float" elements="5" elementnames="0,25,50,75,100" defaultvalue="0,0.25,0.5,0.75,1"/>
<field name="Mixer1Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer1Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/>
<field name="Mixer1Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<field name="Mixer2Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer2Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/>
<field name="Mixer2Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<field name="Mixer3Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer3Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/>
<field name="Mixer3Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<field name="Mixer4Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer4Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/>
<field name="Mixer4Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<field name="Mixer5Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer5Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/>
<field name="Mixer5Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<field name="Mixer6Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer6Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/>
<field name="Mixer6Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<field name="Mixer7Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer7Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/>
<field name="Mixer7Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<field name="Mixer8Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer8Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/>
<field name="Mixer8Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="true" updatemode="onchange" period="0"/>