From 06cdeb7b61dc83f9cf245e9851686013655bbc58 Mon Sep 17 00:00:00 2001 From: Stacey Sheldon Date: Sat, 30 Jul 2011 15:04:24 -0400 Subject: [PATCH] rcvr: support multiple simultaneous receivers Now also supports multiple instances of the Spektrum driver. These are configured as Spektrum1 and Spektrum2. --- flight/CopterControl/System/pios_board.c | 124 +++---- flight/Modules/ManualControl/manualcontrol.c | 63 ++-- flight/OpenPilot/System/pios_board.c | 219 ++++++------- flight/OpenPilot/UAVObjects.inc | 1 + flight/PiOS/Boards/STM32103CB_CC_Rev1.h | 3 +- flight/PiOS/Boards/STM3210E_OP.h | 1 + flight/PiOS/STM32F10x/pios_spektrum.c | 303 +++++++++++------- flight/PiOS/inc/pios_rcvr.h | 7 - shared/uavobjectdefinition/hwsettings.xml | 10 +- .../manualcontrolsettings.xml | 24 +- 10 files changed, 413 insertions(+), 342 deletions(-) diff --git a/flight/CopterControl/System/pios_board.c b/flight/CopterControl/System/pios_board.c index 50677de27..59b66ea3a 100644 --- a/flight/CopterControl/System/pios_board.c +++ b/flight/CopterControl/System/pios_board.c @@ -863,8 +863,12 @@ void PIOS_I2C_main_adapter_er_irq_handler(void) #if defined(PIOS_INCLUDE_RCVR) #include "pios_rcvr_priv.h" -struct pios_rcvr_channel_map pios_rcvr_channel_to_id_map[PIOS_RCVR_MAX_CHANNELS]; -uint32_t pios_rcvr_max_channel; +/* One slot per selectable receiver group. + * eg. PWM, PPM, GCS, SPEKTRUM1, SPEKTRUM2, SBUS + * NOTE: No slot in this map for NONE. + */ +uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; + #endif /* PIOS_INCLUDE_RCVR */ #if defined(PIOS_INCLUDE_USB_HID) @@ -984,7 +988,8 @@ void PIOS_Board_Init(void) { } #endif /* PIOS_INCLUDE_GPS */ break; - case HWSETTINGS_CC_MAINPORT_SPEKTRUM: + case HWSETTINGS_CC_MAINPORT_SPEKTRUM1: + case HWSETTINGS_CC_MAINPORT_SPEKTRUM2: #if defined(PIOS_INCLUDE_SPEKTRUM) { uint32_t pios_usart_spektrum_id; @@ -996,6 +1001,16 @@ void PIOS_Board_Init(void) { if (PIOS_SPEKTRUM_Init(&pios_spektrum_id, &pios_spektrum_main_cfg, &pios_usart_com_driver, pios_usart_spektrum_id, false)) { PIOS_Assert(0); } + + uint32_t pios_spektrum_rcvr_id; + if (PIOS_RCVR_Init(&pios_spektrum_rcvr_id, &pios_spektrum_rcvr_driver, pios_spektrum_id)) { + PIOS_Assert(0); + } + if (hwsettings_cc_mainport == HWSETTINGS_CC_MAINPORT_SPEKTRUM1) { + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM1] = pios_spektrum_rcvr_id; + } else { + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM2] = pios_spektrum_rcvr_id; + } } #endif /* PIOS_INCLUDE_SPEKTRUM */ break; @@ -1046,7 +1061,8 @@ void PIOS_Board_Init(void) { } #endif /* PIOS_INCLUDE_GPS */ break; - case HWSETTINGS_CC_FLEXIPORT_SPEKTRUM: + case HWSETTINGS_CC_FLEXIPORT_SPEKTRUM1: + case HWSETTINGS_CC_FLEXIPORT_SPEKTRUM2: #if defined(PIOS_INCLUDE_SPEKTRUM) { uint32_t pios_usart_spektrum_id; @@ -1058,6 +1074,16 @@ void PIOS_Board_Init(void) { if (PIOS_SPEKTRUM_Init(&pios_spektrum_id, &pios_spektrum_flexi_cfg, &pios_usart_com_driver, pios_usart_spektrum_id, false)) { PIOS_Assert(0); } + + uint32_t pios_spektrum_rcvr_id; + if (PIOS_RCVR_Init(&pios_spektrum_rcvr_id, &pios_spektrum_rcvr_driver, pios_spektrum_id)) { + PIOS_Assert(0); + } + if (hwsettings_cc_flexiport == HWSETTINGS_CC_FLEXIPORT_SPEKTRUM1) { + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM1] = pios_spektrum_rcvr_id; + } else { + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM2] = pios_spektrum_rcvr_id; + } } #endif /* PIOS_INCLUDE_SPEKTRUM */ break; @@ -1074,96 +1100,44 @@ void PIOS_Board_Init(void) { break; } - /* Configure the selected receiver */ - uint8_t manualcontrolsettings_inputmode; - ManualControlSettingsInputModeGet(&manualcontrolsettings_inputmode); + /* Configure the rcvr port */ + uint8_t hwsettings_rcvrport; + HwSettingsRcvrPortGet(&hwsettings_rcvrport); - switch (manualcontrolsettings_inputmode) { - case MANUALCONTROLSETTINGS_INPUTMODE_PWM: + switch (hwsettings_rcvrport) { + case HWSETTINGS_RCVRPORT_DISABLED: + break; + case HWSETTINGS_RCVRPORT_PWM: #if defined(PIOS_INCLUDE_PWM) PIOS_PWM_Init(); uint32_t pios_pwm_rcvr_id; if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, 0)) { PIOS_Assert(0); } - for (uint8_t i = 0; - i < PIOS_PWM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); - i++) { - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_pwm_rcvr_id; - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; - pios_rcvr_max_channel++; - } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PWM] = pios_pwm_rcvr_id; #endif /* PIOS_INCLUDE_PWM */ break; - case MANUALCONTROLSETTINGS_INPUTMODE_PPM: + case HWSETTINGS_RCVRPORT_PPM: #if defined(PIOS_INCLUDE_PPM) PIOS_PPM_Init(); uint32_t pios_ppm_rcvr_id; if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, 0)) { PIOS_Assert(0); } - for (uint8_t i = 0; - i < PIOS_PPM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); - i++) { - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_ppm_rcvr_id; - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; - pios_rcvr_max_channel++; - } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM] = pios_ppm_rcvr_id; #endif /* PIOS_INCLUDE_PPM */ break; - case MANUALCONTROLSETTINGS_INPUTMODE_SPEKTRUM: -#if defined(PIOS_INCLUDE_SPEKTRUM) - if (hwsettings_cc_mainport == HWSETTINGS_CC_MAINPORT_SPEKTRUM || - hwsettings_cc_flexiport == HWSETTINGS_CC_FLEXIPORT_SPEKTRUM) { - uint32_t pios_spektrum_rcvr_id; - if (PIOS_RCVR_Init(&pios_spektrum_rcvr_id, &pios_spektrum_rcvr_driver, 0)) { - PIOS_Assert(0); - } - for (uint8_t i = 0; - i < PIOS_SPEKTRUM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); - i++) { - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_spektrum_rcvr_id; - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; - pios_rcvr_max_channel++; - } - } -#endif /* PIOS_INCLUDE_SPEKTRUM */ - break; - case MANUALCONTROLSETTINGS_INPUTMODE_SBUS: -#if defined(PIOS_INCLUDE_SBUS) - if (hwsettings_cc_mainport == HWSETTINGS_CC_MAINPORT_SBUS) { - uint32_t pios_sbus_rcvr_id; - if (PIOS_RCVR_Init(&pios_sbus_rcvr_id, &pios_sbus_rcvr_driver, 0)) { - PIOS_Assert(0); - } - for (uint8_t i = 0; - i < SBUS_NUMBER_OF_CHANNELS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); - i++) { - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_sbus_rcvr_id; - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; - pios_rcvr_max_channel++; - } - } -#endif /* PIOS_INCLUDE_SBUS */ - break; - case MANUALCONTROLSETTINGS_INPUTMODE_GCS: -#if defined(PIOS_INCLUDE_GCSRCVR) - PIOS_GCSRCVR_Init(); - uint32_t pios_gcsrcvr_rcvr_id; - if (PIOS_RCVR_Init(&pios_gcsrcvr_rcvr_id, &pios_gcsrcvr_rcvr_driver, 0)) { - PIOS_Assert(0); - } - for (uint8_t i = 0; - i < GCSRECEIVER_CHANNEL_NUMELEM && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); - i++) { - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_gcsrcvr_rcvr_id; - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; - pios_rcvr_max_channel++; - } -#endif /* PIOS_INCLUDE_GCSRCVR */ - break; } +#if defined(PIOS_INCLUDE_GCSRCVR) + PIOS_GCSRCVR_Init(); + uint32_t pios_gcsrcvr_rcvr_id; + if (PIOS_RCVR_Init(&pios_gcsrcvr_rcvr_id, &pios_gcsrcvr_rcvr_driver, 0)) { + PIOS_Assert(0); + } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_GCS] = pios_gcsrcvr_rcvr_id; +#endif /* PIOS_INCLUDE_GCSRCVR */ + /* Remap AFIO pin */ GPIO_PinRemapConfig( GPIO_Remap_SWJ_NoJTRST, ENABLE); PIOS_Servo_Init(); diff --git a/flight/Modules/ManualControl/manualcontrol.c b/flight/Modules/ManualControl/manualcontrol.c index 19b6bc293..7c16ac172 100644 --- a/flight/Modules/ManualControl/manualcontrol.c +++ b/flight/Modules/ManualControl/manualcontrol.c @@ -141,7 +141,7 @@ static void manualControlTask(void *parameters) // Main task loop lastSysTime = xTaskGetTickCount(); while (1) { - float scaledChannel[MANUALCONTROLCOMMAND_CHANNEL_NUMELEM]; + float scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_NUMELEM]; // Wait until next update vTaskDelayUntil(&lastSysTime, UPDATE_PERIOD_MS / portTICK_RATE_MS); @@ -165,22 +165,28 @@ static void manualControlTask(void *parameters) if (!ManualControlCommandReadOnly(&cmd)) { // Read channel values in us - for (int n = 0; n < MANUALCONTROLCOMMAND_CHANNEL_NUMELEM; ++n) { - if (pios_rcvr_channel_to_id_map[n].id) { - cmd.Channel[n] = PIOS_RCVR_Read(pios_rcvr_channel_to_id_map[n].id, - pios_rcvr_channel_to_id_map[n].channel); - } else { + for (uint8_t n = 0; + n < MANUALCONTROLSETTINGS_CHANNELGROUPS_NUMELEM && n < MANUALCONTROLCOMMAND_CHANNEL_NUMELEM; + ++n) { + extern uint32_t pios_rcvr_group_map[]; + + if (settings.ChannelGroups[n] >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) { cmd.Channel[n] = -1; + } else if (!pios_rcvr_group_map[settings.ChannelGroups[n]]) { + cmd.Channel[n] = -2; + } else { + cmd.Channel[n] = PIOS_RCVR_Read(pios_rcvr_group_map[settings.ChannelGroups[n]], + settings.ChannelNumber[n]); } scaledChannel[n] = scaleChannel(cmd.Channel[n], settings.ChannelMax[n], settings.ChannelMin[n], settings.ChannelNeutral[n]); } // Check settings, if error raise alarm - if (settings.Roll >= MANUALCONTROLSETTINGS_ROLL_NONE || - settings.Pitch >= MANUALCONTROLSETTINGS_PITCH_NONE || - settings.Yaw >= MANUALCONTROLSETTINGS_YAW_NONE || - settings.Throttle >= MANUALCONTROLSETTINGS_THROTTLE_NONE || - settings.FlightMode >= MANUALCONTROLSETTINGS_FLIGHTMODE_NONE) { + if (settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_ROLL] >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE || + settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_PITCH] >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE || + settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_YAW] >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE || + settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_THROTTLE] >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE || + settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_FLIGHTMODE] >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) { AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_CRITICAL); cmd.Connected = MANUALCONTROLCOMMAND_CONNECTED_FALSE; ManualControlCommandSet(&cmd); @@ -188,10 +194,10 @@ static void manualControlTask(void *parameters) } // decide if we have valid manual input or not - bool valid_input_detected = validInputRange(settings.ChannelMin[settings.Throttle], settings.ChannelMax[settings.Throttle], cmd.Channel[settings.Throttle]) && - validInputRange(settings.ChannelMin[settings.Roll], settings.ChannelMax[settings.Roll], cmd.Channel[settings.Roll]) && - validInputRange(settings.ChannelMin[settings.Yaw], settings.ChannelMax[settings.Yaw], cmd.Channel[settings.Yaw]) && - validInputRange(settings.ChannelMin[settings.Pitch], settings.ChannelMax[settings.Pitch], cmd.Channel[settings.Pitch]); + bool valid_input_detected = validInputRange(settings.ChannelMin[MANUALCONTROLSETTINGS_CHANNELGROUPS_THROTTLE], settings.ChannelMax[MANUALCONTROLSETTINGS_CHANNELGROUPS_THROTTLE], cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_THROTTLE]) && + validInputRange(settings.ChannelMin[MANUALCONTROLSETTINGS_CHANNELGROUPS_ROLL], settings.ChannelMax[MANUALCONTROLSETTINGS_CHANNELGROUPS_ROLL], cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_ROLL]) && + validInputRange(settings.ChannelMin[MANUALCONTROLSETTINGS_CHANNELGROUPS_YAW], settings.ChannelMax[MANUALCONTROLSETTINGS_CHANNELGROUPS_YAW], cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_YAW]) && + validInputRange(settings.ChannelMin[MANUALCONTROLSETTINGS_CHANNELGROUPS_PITCH], settings.ChannelMax[MANUALCONTROLSETTINGS_CHANNELGROUPS_PITCH], cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_PITCH]); // Implement hysteresis loop on connection status if (valid_input_detected && (++connected_count > 10)) { @@ -218,28 +224,31 @@ static void manualControlTask(void *parameters) AlarmsClear(SYSTEMALARMS_ALARM_MANUALCONTROL); // Scale channels to -1 -> +1 range - cmd.Roll = scaledChannel[settings.Roll]; - cmd.Pitch = scaledChannel[settings.Pitch]; - cmd.Yaw = scaledChannel[settings.Yaw]; - cmd.Throttle = scaledChannel[settings.Throttle]; - flightMode = scaledChannel[settings.FlightMode]; + cmd.Roll = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_ROLL]; + cmd.Pitch = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_PITCH]; + cmd.Yaw = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_YAW]; + cmd.Throttle = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_THROTTLE]; + flightMode = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_FLIGHTMODE]; AccessoryDesiredData accessory; // Set Accessory 0 - if(settings.Accessory0 != MANUALCONTROLSETTINGS_ACCESSORY0_NONE) { - accessory.AccessoryVal = scaledChannel[settings.Accessory0]; + if (settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY0] != + MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) { + accessory.AccessoryVal = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_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 (settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY1] != + MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) { + accessory.AccessoryVal = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_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]; + // Set Accessory 2 + if (settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY2] != + MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) { + accessory.AccessoryVal = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY2]; if(AccessoryDesiredInstSet(2, &accessory) != 0) AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING); } diff --git a/flight/OpenPilot/System/pios_board.c b/flight/OpenPilot/System/pios_board.c index 822b7a8ae..9a9397acb 100644 --- a/flight/OpenPilot/System/pios_board.c +++ b/flight/OpenPilot/System/pios_board.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "manualcontrolsettings.h" //#define I2C_DEBUG_PIN 0 @@ -496,7 +497,6 @@ static const struct pios_usart_cfg pios_usart_spektrum_cfg = { }, }; -#include static const struct pios_spektrum_cfg pios_spektrum_cfg = { .bind = { .gpio = GPIOA, @@ -964,8 +964,12 @@ static const struct stm32_gpio pios_debug_pins[] = { #if defined(PIOS_INCLUDE_RCVR) #include "pios_rcvr_priv.h" -struct pios_rcvr_channel_map pios_rcvr_channel_to_id_map[PIOS_RCVR_MAX_CHANNELS]; -uint32_t pios_rcvr_max_channel; +/* One slot per selectable receiver group. + * eg. PWM, PPM, GCS, SPEKTRUM1, SPEKTRUM2, SBUS + * NOTE: No slot in this map for NONE. + */ +uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; + #endif /* PIOS_INCLUDE_RCVR */ #if defined(PIOS_INCLUDE_USB_HID) @@ -1047,126 +1051,125 @@ void PIOS_Board_Init(void) { /* Bind the AHRS comms layer to the AHRS SPI link */ AhrsConnect(pios_spi_ahrs_id); - /* Initialize the PiOS library */ -#if defined(PIOS_INCLUDE_COM) + /* Configure the main IO port */ + uint8_t hwsettings_op_mainport; + HwSettingsOP_MainPortGet(&hwsettings_op_mainport); + + switch (hwsettings_op_mainport) { + case HWSETTINGS_OP_MAINPORT_DISABLED: + break; + case HWSETTINGS_OP_MAINPORT_TELEMETRY: #if defined(PIOS_INCLUDE_TELEMETRY_RF) - { - uint32_t pios_usart_telem_rf_id; - if (PIOS_USART_Init(&pios_usart_telem_rf_id, &pios_usart_telem_cfg)) { - PIOS_Assert(0); - } + { + uint32_t pios_usart_telem_rf_id; + if (PIOS_USART_Init(&pios_usart_telem_rf_id, &pios_usart_telem_cfg)) { + PIOS_Assert(0); + } - uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_RX_BUF_LEN); - uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_rf_id, &pios_usart_com_driver, pios_usart_telem_rf_id, - rx_buffer, PIOS_COM_TELEM_RF_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_RF_TX_BUF_LEN)) { - PIOS_Assert(0); + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_RX_BUF_LEN); + uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_TX_BUF_LEN); + PIOS_Assert(rx_buffer); + PIOS_Assert(tx_buffer); + if (PIOS_COM_Init(&pios_com_telem_rf_id, &pios_usart_com_driver, pios_usart_telem_rf_id, + rx_buffer, PIOS_COM_TELEM_RF_RX_BUF_LEN, + tx_buffer, PIOS_COM_TELEM_RF_TX_BUF_LEN)) { + PIOS_Assert(0); + } } - } #endif /* PIOS_INCLUDE_TELEMETRY_RF */ - -#if defined(PIOS_INCLUDE_GPS) - { - uint32_t pios_usart_gps_id; - if (PIOS_USART_Init(&pios_usart_gps_id, &pios_usart_gps_cfg)) { - PIOS_Assert(0); - } - uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_GPS_RX_BUF_LEN); - PIOS_Assert(rx_buffer); - if (PIOS_COM_Init(&pios_com_gps_id, &pios_usart_com_driver, pios_usart_gps_id, - rx_buffer, PIOS_COM_GPS_RX_BUF_LEN, - NULL, 0)) { - PIOS_Assert(0); - } + break; } + + /* Configure the flexi port */ + uint8_t hwsettings_op_flexiport; + HwSettingsOP_FlexiPortGet(&hwsettings_op_flexiport); + + switch (hwsettings_op_flexiport) { + case HWSETTINGS_OP_FLEXIPORT_DISABLED: + break; + case HWSETTINGS_OP_FLEXIPORT_GPS: +#if defined(PIOS_INCLUDE_GPS) + { + uint32_t pios_usart_gps_id; + if (PIOS_USART_Init(&pios_usart_gps_id, &pios_usart_gps_cfg)) { + PIOS_Assert(0); + } + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_GPS_RX_BUF_LEN); + PIOS_Assert(rx_buffer); + if (PIOS_COM_Init(&pios_com_gps_id, &pios_usart_com_driver, pios_usart_gps_id, + rx_buffer, PIOS_COM_GPS_RX_BUF_LEN, + NULL, 0)) { + PIOS_Assert(0); + } + } #endif /* PIOS_INCLUDE_GPS */ -#endif + break; + } PIOS_Servo_Init(); PIOS_ADC_Init(); PIOS_GPIO_Init(); - /* Configure the selected receiver */ - uint8_t manualcontrolsettings_inputmode; - ManualControlSettingsInputModeGet(&manualcontrolsettings_inputmode); + /* Configure the aux port */ + uint8_t hwsettings_op_auxport; + HwSettingsOP_AuxPortGet(&hwsettings_op_auxport); - switch (manualcontrolsettings_inputmode) { - case MANUALCONTROLSETTINGS_INPUTMODE_PWM: -#if defined(PIOS_INCLUDE_PWM) -#if (PIOS_PWM_NUM_INPUTS > PIOS_RCVR_MAX_CHANNELS) -#error More receiver inputs than available devices -#endif - PIOS_PWM_Init(); - uint32_t pios_pwm_rcvr_id; - if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, 0)) { - PIOS_Assert(0); - } - for (uint8_t i = 0; - i < PIOS_PWM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); - i++) { - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_pwm_rcvr_id; - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; - pios_rcvr_max_channel++; - } -#endif /* PIOS_INCLUDE_PWM */ - break; - case MANUALCONTROLSETTINGS_INPUTMODE_PPM: -#if defined(PIOS_INCLUDE_PPM) -#if (PIOS_PPM_NUM_INPUTS > PIOS_RCVR_MAX_CHANNELS) -#error More receiver inputs than available devices -#endif - PIOS_PPM_Init(); - uint32_t pios_ppm_rcvr_id; - if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, 0)) { - PIOS_Assert(0); - } - for (uint8_t i = 0; - i < PIOS_PPM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); - i++) { - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_ppm_rcvr_id; - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; - pios_rcvr_max_channel++; - } -#endif /* PIOS_INCLUDE_PPM */ - break; - case MANUALCONTROLSETTINGS_INPUTMODE_SPEKTRUM: + switch (hwsettings_op_auxport) { + case HWSETTINGS_OP_AUXPORT_DISABLED: + break; + case HWSETTINGS_OP_AUXPORT_DEBUG: + /* Not supported yet */ + break; + case HWSETTINGS_OP_AUXPORT_SPEKTRUM1: #if defined(PIOS_INCLUDE_SPEKTRUM) -#if (PIOS_SPEKTRUM_NUM_INPUTS > PIOS_RCVR_MAX_CHANNELS) -#error More receiver inputs than available devices -#endif - { - uint32_t pios_usart_spektrum_id; - if (PIOS_USART_Init(&pios_usart_spektrum_id, &pios_usart_spektrum_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_spektrum_id; - if (PIOS_SPEKTRUM_Init(&pios_spektrum_id, &pios_spektrum_cfg, &pios_usart_com_driver, pios_usart_spektrum_id, false)) { - PIOS_Assert(0); - } - - uint32_t pios_spektrum_rcvr_id; - if (PIOS_RCVR_Init(&pios_spektrum_rcvr_id, &pios_spektrum_rcvr_driver, 0)) { - PIOS_Assert(0); - } - for (uint8_t i = 0; - i < PIOS_SPEKTRUM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); - i++) { - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_spektrum_rcvr_id; - pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; - pios_rcvr_max_channel++; - } + { + uint32_t pios_usart_spektrum_id; + if (PIOS_USART_Init(&pios_usart_spektrum_id, &pios_usart_spektrum_cfg)) { + PIOS_Assert(0); } + + uint32_t pios_spektrum_id; + if (PIOS_SPEKTRUM_Init(&pios_spektrum_id, &pios_spektrum_cfg, &pios_usart_com_driver, pios_usart_spektrum_id, false)) { + PIOS_Assert(0); + } + + uint32_t pios_spektrum_rcvr_id; + if (PIOS_RCVR_Init(&pios_spektrum_rcvr_id, &pios_spektrum_rcvr_driver, pios_spektrum_id)) { + PIOS_Assert(0); + } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM1] = pios_spektrum_rcvr_id; + } #endif - break; - case MANUALCONTROLSETTINGS_INPUTMODE_SBUS: -#if defined(PIOS_INCLUDE_SBUS) -#error SBUS NOT ON OP YET -#endif /* PIOS_INCLUDE_SBUS */ - break; + break; + } + + /* Configure the rcvr port */ + uint8_t hwsettings_rcvrport; + HwSettingsRcvrPortGet(&hwsettings_rcvrport); + + switch (hwsettings_rcvrport) { + case HWSETTINGS_RCVRPORT_DISABLED: + break; + case HWSETTINGS_RCVRPORT_PWM: +#if defined(PIOS_INCLUDE_PWM) + PIOS_PWM_Init(); + uint32_t pios_pwm_rcvr_id; + if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, 0)) { + PIOS_Assert(0); + } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PWM] = pios_pwm_rcvr_id; +#endif /* PIOS_INCLUDE_PWM */ + break; + case HWSETTINGS_RCVRPORT_PPM: +#if defined(PIOS_INCLUDE_PPM) + PIOS_PPM_Init(); + uint32_t pios_ppm_rcvr_id; + if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, 0)) { + PIOS_Assert(0); + } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM] = pios_ppm_rcvr_id; +#endif /* PIOS_INCLUDE_PPM */ + break; } #if defined(PIOS_INCLUDE_USB_HID) diff --git a/flight/OpenPilot/UAVObjects.inc b/flight/OpenPilot/UAVObjects.inc index 3eb2fa571..a30dcf540 100644 --- a/flight/OpenPilot/UAVObjects.inc +++ b/flight/OpenPilot/UAVObjects.inc @@ -69,6 +69,7 @@ UAVOBJSRCFILENAMES += velocityactual UAVOBJSRCFILENAMES += velocitydesired UAVOBJSRCFILENAMES += watchdogstatus UAVOBJSRCFILENAMES += flightstatus +UAVOBJSRCFILENAMES += hwsettings UAVOBJSRC = $(foreach UAVOBJSRCFILE,$(UAVOBJSRCFILENAMES),$(UAVOBJSYNTHDIR)/$(UAVOBJSRCFILE).c ) UAVOBJDEFINE = $(foreach UAVOBJSRCFILE,$(UAVOBJSRCFILENAMES),-DUAVOBJ_INIT_$(UAVOBJSRCFILE) ) diff --git a/flight/PiOS/Boards/STM32103CB_CC_Rev1.h b/flight/PiOS/Boards/STM32103CB_CC_Rev1.h index 18e0da624..8c1467b0d 100644 --- a/flight/PiOS/Boards/STM32103CB_CC_Rev1.h +++ b/flight/PiOS/Boards/STM32103CB_CC_Rev1.h @@ -206,7 +206,7 @@ extern uint32_t pios_com_telem_usb_id; // PIOS_RCVR // See also pios_board.c //------------------------ -#define PIOS_RCVR_MAX_DEVS 1 +#define PIOS_RCVR_MAX_DEVS 3 #define PIOS_RCVR_MAX_CHANNELS 12 //------------------------- @@ -222,6 +222,7 @@ extern uint32_t pios_com_telem_usb_id; //------------------------- // Receiver SPEKTRUM input //------------------------- +#define PIOS_SPEKTRUM_MAX_DEVS 2 #define PIOS_SPEKTRUM_NUM_INPUTS 12 //------------------------- diff --git a/flight/PiOS/Boards/STM3210E_OP.h b/flight/PiOS/Boards/STM3210E_OP.h index 3098ee259..159ebbd88 100644 --- a/flight/PiOS/Boards/STM3210E_OP.h +++ b/flight/PiOS/Boards/STM3210E_OP.h @@ -195,6 +195,7 @@ extern uint32_t pios_com_aux_id; //------------------------- // Receiver SPEKTRUM input //------------------------- +#define PIOS_SPEKTRUM_MAX_DEVS 1 #define PIOS_SPEKTRUM_NUM_INPUTS 12 //------------------------- diff --git a/flight/PiOS/STM32F10x/pios_spektrum.c b/flight/PiOS/STM32F10x/pios_spektrum.c index 8b0f38c6b..e062e6314 100644 --- a/flight/PiOS/STM32F10x/pios_spektrum.c +++ b/flight/PiOS/STM32F10x/pios_spektrum.c @@ -31,10 +31,11 @@ /* Project Includes */ #include "pios.h" -#include "pios_spektrum_priv.h" #if defined(PIOS_INCLUDE_SPEKTRUM) +#include "pios_spektrum_priv.h" + /** * @Note Framesyncing: * The code resets the watchdog timer whenever a single byte is received, so what watchdog code @@ -52,22 +53,80 @@ const struct pios_rcvr_driver pios_spektrum_rcvr_driver = { .read = PIOS_SPEKTRUM_Get, }; -/* Local Variables */ -static uint16_t CaptureValue[PIOS_SPEKTRUM_NUM_INPUTS],CaptureValueTemp[PIOS_SPEKTRUM_NUM_INPUTS]; -static uint8_t prev_byte = 0xFF, sync = 0, bytecount = 0, datalength=0, frame_error=0, byte_array[20] = { 0 }; -uint8_t sync_of = 0; -uint16_t supv_timer=0; +enum pios_spektrum_dev_magic { + PIOS_SPEKTRUM_DEV_MAGIC = 0xa9b9c9d9, +}; + +struct pios_spektrum_fsm { + uint16_t channel; + uint16_t CaptureValue[PIOS_SPEKTRUM_NUM_INPUTS]; + uint16_t CaptureValueTemp[PIOS_SPEKTRUM_NUM_INPUTS]; + uint8_t prev_byte; + uint8_t sync; + uint8_t bytecount; + uint8_t datalength; + uint8_t frame_error; + uint8_t sync_of; +}; + +struct pios_spektrum_dev { + enum pios_spektrum_dev_magic magic; + const struct pios_spektrum_cfg * cfg; + + struct pios_spektrum_fsm fsm; + + uint16_t supv_timer; +}; + +static bool PIOS_SPEKTRUM_validate(struct pios_spektrum_dev * spektrum_dev) +{ + return (spektrum_dev->magic == PIOS_SPEKTRUM_DEV_MAGIC); +} + +#if defined(PIOS_INCLUDE_FREERTOS) && 0 +static struct pios_spektrum_dev * PIOS_SPEKTRUM_alloc(void) +{ + struct pios_spektrum_dev * spektrum_dev; + + spektrum_dev = (struct pios_spektrum_dev *)malloc(sizeof(*spektrum_dev)); + if (!spektrum_dev) return(NULL); + + spektrum_dev->magic = PIOS_SPEKTRUM_DEV_MAGIC; + return(spektrum_dev); +} +#else +static struct pios_spektrum_dev pios_spektrum_devs[PIOS_SPEKTRUM_MAX_DEVS]; +static uint8_t pios_spektrum_num_devs; +static struct pios_spektrum_dev * PIOS_SPEKTRUM_alloc(void) +{ + struct pios_spektrum_dev * spektrum_dev; + + if (pios_spektrum_num_devs >= PIOS_SPEKTRUM_MAX_DEVS) { + return (NULL); + } + + spektrum_dev = &pios_spektrum_devs[pios_spektrum_num_devs++]; + spektrum_dev->magic = PIOS_SPEKTRUM_DEV_MAGIC; + + return (spektrum_dev); +} +#endif static void PIOS_SPEKTRUM_Supervisor(uint32_t spektrum_id); static bool PIOS_SPEKTRUM_Bind(const struct pios_spektrum_cfg * cfg); -static int32_t PIOS_SPEKTRUM_Decode(uint8_t b); +static int32_t PIOS_SPEKTRUM_UpdateFSM(struct pios_spektrum_fsm * fsm, uint8_t b); static uint16_t PIOS_SPEKTRUM_RxInCallback(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * need_yield) { + struct pios_spektrum_dev * spektrum_dev = (struct pios_spektrum_dev *)context; + + bool valid = PIOS_SPEKTRUM_validate(spektrum_dev); + PIOS_Assert(valid); + /* process byte(s) and clear receive timer */ for (uint8_t i = 0; i < buf_len; i++) { - PIOS_SPEKTRUM_Decode(buf[i]); - supv_timer = 0; + PIOS_SPEKTRUM_UpdateFSM(&(spektrum_dev->fsm), buf[i]); + spektrum_dev->supv_timer = 0; } /* Always signal that we can accept another byte */ @@ -82,23 +141,118 @@ static uint16_t PIOS_SPEKTRUM_RxInCallback(uint32_t context, uint8_t * buf, uint return (buf_len); } +static void PIOS_SPEKTRUM_ResetFSM(struct pios_spektrum_fsm * fsm) +{ + fsm->channel = 0; + fsm->prev_byte = 0xFF; + fsm->sync = 0; + fsm->bytecount = 0; + fsm->datalength = 0; + fsm->frame_error = 0; + fsm->sync_of = 0; +} + +/** +* Decodes a byte +* \param[in] b byte which should be spektrum decoded +* \return 0 if no error +* \return -1 if USART not available +* \return -2 if buffer full (retry) +*/ +static int32_t PIOS_SPEKTRUM_UpdateFSM(struct pios_spektrum_fsm * fsm, uint8_t b) +{ + fsm->bytecount++; + if (fsm->sync == 0) { + /* Known sync bytes, 0x01, 0x02, 0x12 */ + if (fsm->bytecount == 2) { + if (b == 0x01) { + fsm->datalength=0; // 10bit + fsm->sync = 1; + fsm->bytecount = 2; + } + else if(b == 0x02) { + fsm->datalength=0; // 10bit + fsm->sync = 1; + fsm->bytecount = 2; + } + else if(b == 0x12) { + fsm->datalength=1; // 11bit + fsm->sync = 1; + fsm->bytecount = 2; + } + else + { + fsm->bytecount = 0; + } + } + } else { + if ((fsm->bytecount % 2) == 0) { + uint16_t data; + uint8_t channeln; + + fsm->channel = (fsm->prev_byte << 8) + b; + channeln = (fsm->channel >> (10+fsm->datalength)) & 0x0F; + data = fsm->channel & (0x03FF+(0x0400*fsm->datalength)); + if(channeln==0 && data<10) // discard frame if throttle misbehaves + { + fsm->frame_error=1; + } + if (channeln < PIOS_SPEKTRUM_NUM_INPUTS && !fsm->frame_error) + fsm->CaptureValueTemp[channeln] = data; + } + } + if (fsm->bytecount == 16) { + fsm->bytecount = 0; + fsm->sync = 0; + fsm->sync_of = 0; + if (!fsm->frame_error) + { + for(int i=0;iCaptureValue[i] = fsm->CaptureValueTemp[i]; + } + } + fsm->frame_error=0; + } + fsm->prev_byte = b; + return 0; +} + /** * Bind and Initialise Spektrum satellite receiver */ int32_t PIOS_SPEKTRUM_Init(uint32_t * spektrum_id, const struct pios_spektrum_cfg *cfg, const struct pios_com_driver * driver, uint32_t lower_id, bool bind) { - // TODO: need setting flag for bind on next powerup + PIOS_DEBUG_Assert(spektrum_id); + PIOS_DEBUG_Assert(cfg); + PIOS_DEBUG_Assert(driver); + + struct pios_spektrum_dev * spektrum_dev; + + spektrum_dev = (struct pios_spektrum_dev *) PIOS_SPEKTRUM_alloc(); + if (!spektrum_dev) goto out_fail; + + /* Bind the configuration to the device instance */ + spektrum_dev->cfg = cfg; + if (bind) { PIOS_SPEKTRUM_Bind(cfg); } - (driver->bind_rx_cb)(lower_id, PIOS_SPEKTRUM_RxInCallback, 0); + PIOS_SPEKTRUM_ResetFSM(&(spektrum_dev->fsm)); - if (!PIOS_RTC_RegisterTickCallback(PIOS_SPEKTRUM_Supervisor, 0)) { + *spektrum_id = (uint32_t)spektrum_dev; + + (driver->bind_rx_cb)(lower_id, PIOS_SPEKTRUM_RxInCallback, *spektrum_id); + + if (!PIOS_RTC_RegisterTickCallback(PIOS_SPEKTRUM_Supervisor, *spektrum_id)) { PIOS_DEBUG_Assert(0); } return (0); + +out_fail: + return(-1); } /** @@ -109,11 +263,16 @@ int32_t PIOS_SPEKTRUM_Init(uint32_t * spektrum_id, const struct pios_spektrum_cf */ static int32_t PIOS_SPEKTRUM_Get(uint32_t rcvr_id, uint8_t channel) { + struct pios_spektrum_dev * spektrum_dev = (struct pios_spektrum_dev *)rcvr_id; + + bool valid = PIOS_SPEKTRUM_validate(spektrum_dev); + PIOS_Assert(valid); + /* Return error if channel not available */ if (channel >= PIOS_SPEKTRUM_NUM_INPUTS) { return -1; } - return CaptureValue[channel]; + return spektrum_dev->fsm.CaptureValue[channel]; } /** @@ -145,114 +304,38 @@ static bool PIOS_SPEKTRUM_Bind(const struct pios_spektrum_cfg * cfg) return true; } -/** -* Decodes a byte -* \param[in] b byte which should be spektrum decoded -* \return 0 if no error -* \return -1 if USART not available -* \return -2 if buffer full (retry) -* \note Applications shouldn't call these functions directly -*/ -static int32_t PIOS_SPEKTRUM_Decode(uint8_t b) -{ - static uint16_t channel = 0; /*, sync_word = 0;*/ - uint8_t channeln = 0, frame = 0; - uint16_t data = 0; - byte_array[bytecount] = b; - bytecount++; - if (sync == 0) { - //sync_word = (prev_byte << 8) + b; -#if 0 - /* maybe create object to show this data */ - if(bytecount==1) - { - /* record losscounter into channel8 */ - CaptureValueTemp[7]=b; - /* instant write */ - CaptureValue[7]=b; - } -#endif - /* Known sync bytes, 0x01, 0x02, 0x12 */ - if (bytecount == 2) { - if (b == 0x01) { - datalength=0; // 10bit - //frames=1; - sync = 1; - bytecount = 2; - } - else if(b == 0x02) { - datalength=0; // 10bit - //frames=2; - sync = 1; - bytecount = 2; - } - else if(b == 0x12) { - datalength=1; // 11bit - //frames=2; - sync = 1; - bytecount = 2; - } - else - { - bytecount = 0; - } - } - } else { - if ((bytecount % 2) == 0) { - channel = (prev_byte << 8) + b; - frame = channel >> 15; - channeln = (channel >> (10+datalength)) & 0x0F; - data = channel & (0x03FF+(0x0400*datalength)); - if(channeln==0 && data<10) // discard frame if throttle misbehaves - { - frame_error=1; - } - if (channeln < PIOS_SPEKTRUM_NUM_INPUTS && !frame_error) - CaptureValueTemp[channeln] = data; - } - } - if (bytecount == 16) { - //PIOS_COM_SendBufferNonBlocking(PIOS_COM_TELEM_RF,byte_array,16); //00 2c 58 84 b0 dc ff - bytecount = 0; - sync = 0; - sync_of = 0; - if (!frame_error) - { - for(int i=0;i 5) { + spektrum_dev->supv_timer++; + if(spektrum_dev->supv_timer > 5) { /* sync between frames */ - sync = 0; - bytecount = 0; - prev_byte = 0xFF; - frame_error = 0; - sync_of++; + struct pios_spektrum_fsm * fsm = &(spektrum_dev->fsm); + + fsm->sync = 0; + fsm->bytecount = 0; + fsm->prev_byte = 0xFF; + fsm->frame_error = 0; + fsm->sync_of++; /* watchdog activated after 100ms silence */ - if (sync_of > 12) { + if (fsm->sync_of > 12) { /* signal lost */ - sync_of = 0; + fsm->sync_of = 0; for (int i = 0; i < PIOS_SPEKTRUM_NUM_INPUTS; i++) { - CaptureValue[i] = 0; - CaptureValueTemp[i] = 0; + fsm->CaptureValue[i] = 0; + fsm->CaptureValueTemp[i] = 0; } } - supv_timer = 0; + spektrum_dev->supv_timer = 0; } } diff --git a/flight/PiOS/inc/pios_rcvr.h b/flight/PiOS/inc/pios_rcvr.h index dfec004f5..0f4e6a973 100644 --- a/flight/PiOS/inc/pios_rcvr.h +++ b/flight/PiOS/inc/pios_rcvr.h @@ -31,13 +31,6 @@ #ifndef PIOS_RCVR_H #define PIOS_RCVR_H -struct pios_rcvr_channel_map { - uint32_t id; - uint8_t channel; -}; - -extern struct pios_rcvr_channel_map pios_rcvr_channel_to_id_map[]; - struct pios_rcvr_driver { void (*init)(uint32_t id); int32_t (*read)(uint32_t id, uint8_t channel); diff --git a/shared/uavobjectdefinition/hwsettings.xml b/shared/uavobjectdefinition/hwsettings.xml index a3494f820..7b4ed7ec4 100644 --- a/shared/uavobjectdefinition/hwsettings.xml +++ b/shared/uavobjectdefinition/hwsettings.xml @@ -1,8 +1,14 @@ Selection of optional hardware configurations. - - + + + + + + + + diff --git a/shared/uavobjectdefinition/manualcontrolsettings.xml b/shared/uavobjectdefinition/manualcontrolsettings.xml index 3b76d70f8..d6d7b90a3 100644 --- a/shared/uavobjectdefinition/manualcontrolsettings.xml +++ b/shared/uavobjectdefinition/manualcontrolsettings.xml @@ -1,15 +1,18 @@ Settings to indicate how to decode receiver input by @ref ManualControlModule. - - - - - - - - - + + + + + + @@ -20,9 +23,6 @@ - - -