diff --git a/HISTORY.txt b/HISTORY.txt index 0be2551ff..626a41593 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -1,5 +1,21 @@ Short summary of changes. For a complete list see the git log. +2011-11-04 +New Spektrum/JR satellite receiver driver implementation. +It now provides explicit selection of DSM2 (and DSMJ), DSMX (10bit) and +DSMX (11bit) serial protocol variations to better serve different frame +and resolution modes. The protocol name used now is DSM instead of +previously used Spektrum to make it less ambiguous when used with JR +2.4GHz radios. + +2011-10-20 +Inputs can be remapped to outputs to allow up to 10 channels of control. The +receiver inputs remap as follows: +Receiver 3 because output channel 7 +Receiver 4 because output channel 8 +Receiver 5 because output channel 9 +Receiver 6 because output channel 10 + 2011-10-11 Fix for the Mac telemetry rates and specifically how long enumeration took. diff --git a/flight/CopterControl/Makefile b/flight/CopterControl/Makefile index 106138320..5f2886f2f 100644 --- a/flight/CopterControl/Makefile +++ b/flight/CopterControl/Makefile @@ -193,7 +193,7 @@ SRC += $(PIOSSTM32F10X)/pios_i2c.c SRC += $(PIOSSTM32F10X)/pios_spi.c SRC += $(PIOSSTM32F10X)/pios_ppm.c SRC += $(PIOSSTM32F10X)/pios_pwm.c -SRC += $(PIOSSTM32F10X)/pios_spektrum.c +SRC += $(PIOSSTM32F10X)/pios_dsm.c SRC += $(PIOSSTM32F10X)/pios_sbus.c SRC += $(PIOSSTM32F10X)/pios_debug.c SRC += $(PIOSSTM32F10X)/pios_gpio.c diff --git a/flight/CopterControl/System/inc/pios_config.h b/flight/CopterControl/System/inc/pios_config.h index 6bf218de7..8e29e0b73 100644 --- a/flight/CopterControl/System/inc/pios_config.h +++ b/flight/CopterControl/System/inc/pios_config.h @@ -46,7 +46,7 @@ #define PIOS_INCLUDE_RCVR /* Supported receiver interfaces */ -#define PIOS_INCLUDE_SPEKTRUM +#define PIOS_INCLUDE_DSM #define PIOS_INCLUDE_SBUS #define PIOS_INCLUDE_PPM #define PIOS_INCLUDE_PWM diff --git a/flight/CopterControl/System/pios_board.c b/flight/CopterControl/System/pios_board.c index ee6d3af5a..f895d8e2b 100644 --- a/flight/CopterControl/System/pios_board.c +++ b/flight/CopterControl/System/pios_board.c @@ -410,6 +410,133 @@ static const struct pios_tim_channel pios_tim_servoport_all_pins[] = { }, }; + +static const struct pios_tim_channel pios_tim_servoport_rcvrport_pins[] = { + { + .timer = TIM4, + .timer_chan = TIM_Channel_4, + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_9, + .GPIO_Mode = GPIO_Mode_AF_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, + }, + { + .timer = TIM4, + .timer_chan = TIM_Channel_3, + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_8, + .GPIO_Mode = GPIO_Mode_AF_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, + }, + { + .timer = TIM4, + .timer_chan = TIM_Channel_2, + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_7, + .GPIO_Mode = GPIO_Mode_AF_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, + }, + { + .timer = TIM1, + .timer_chan = TIM_Channel_1, + .pin = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_8, + .GPIO_Mode = GPIO_Mode_AF_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, + }, + { + .timer = TIM3, + .timer_chan = TIM_Channel_1, + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_4, + .GPIO_Mode = GPIO_Mode_AF_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, + .remap = GPIO_PartialRemap_TIM3, + }, + { + .timer = TIM2, + .timer_chan = TIM_Channel_3, + .pin = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_2, + .GPIO_Mode = GPIO_Mode_AF_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, + }, + + // Receiver port pins + // S3-S6 inputs are used as outputs in this case + { + .timer = TIM3, + .timer_chan = TIM_Channel_3, + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_0, + .GPIO_Mode = GPIO_Mode_AF_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, + }, + { + .timer = TIM3, + .timer_chan = TIM_Channel_4, + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_1, + .GPIO_Mode = GPIO_Mode_AF_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, + }, + { + .timer = TIM2, + .timer_chan = TIM_Channel_1, + .pin = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_0, + .GPIO_Mode = GPIO_Mode_AF_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, + }, + { + .timer = TIM2, + .timer_chan = TIM_Channel_2, + .pin = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_1, + .GPIO_Mode = GPIO_Mode_AF_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, + }, +}; #if defined(PIOS_INCLUDE_USART) #include "pios_usart_priv.h" @@ -568,13 +695,13 @@ static const struct pios_usart_cfg pios_usart_gps_flexi_cfg = { }; #endif /* PIOS_INCLUDE_GPS */ -#if defined(PIOS_INCLUDE_SPEKTRUM) +#if defined(PIOS_INCLUDE_DSM) /* - * SPEKTRUM USART + * Spektrum/JR DSM USART */ -#include +#include -static const struct pios_usart_cfg pios_usart_spektrum_main_cfg = { +static const struct pios_usart_cfg pios_usart_dsm_main_cfg = { .regs = USART1, .init = { .USART_BaudRate = 115200, @@ -610,7 +737,7 @@ static const struct pios_usart_cfg pios_usart_spektrum_main_cfg = { }, }; -static const struct pios_spektrum_cfg pios_spektrum_main_cfg = { +static const struct pios_dsm_cfg pios_dsm_main_cfg = { .bind = { .gpio = GPIOA, .init = { @@ -619,10 +746,9 @@ static const struct pios_spektrum_cfg pios_spektrum_main_cfg = { .GPIO_Mode = GPIO_Mode_Out_PP, }, }, - .remap = 0, }; -static const struct pios_usart_cfg pios_usart_spektrum_flexi_cfg = { +static const struct pios_usart_cfg pios_usart_dsm_flexi_cfg = { .regs = USART3, .init = { .USART_BaudRate = 115200, @@ -658,7 +784,7 @@ static const struct pios_usart_cfg pios_usart_spektrum_flexi_cfg = { }, }; -static const struct pios_spektrum_cfg pios_spektrum_flexi_cfg = { +static const struct pios_dsm_cfg pios_dsm_flexi_cfg = { .bind = { .gpio = GPIOB, .init = { @@ -667,14 +793,13 @@ static const struct pios_spektrum_cfg pios_spektrum_flexi_cfg = { .GPIO_Mode = GPIO_Mode_Out_PP, }, }, - .remap = 0, }; -#endif /* PIOS_INCLUDE_SPEKTRUM */ +#endif /* PIOS_INCLUDE_DSM */ #if defined(PIOS_INCLUDE_SBUS) /* - * SBUS USART + * S.Bus USART */ #include @@ -795,6 +920,22 @@ const struct pios_servo_cfg pios_servo_cfg = { .num_channels = NELEMENTS(pios_tim_servoport_all_pins), }; +const struct pios_servo_cfg pios_servo_rcvr_cfg = { + .tim_oc_init = { + .TIM_OCMode = TIM_OCMode_PWM1, + .TIM_OutputState = TIM_OutputState_Enable, + .TIM_OutputNState = TIM_OutputNState_Disable, + .TIM_Pulse = PIOS_SERVOS_INITIAL_POSITION, + .TIM_OCPolarity = TIM_OCPolarity_High, + .TIM_OCNPolarity = TIM_OCPolarity_High, + .TIM_OCIdleState = TIM_OCIdleState_Reset, + .TIM_OCNIdleState = TIM_OCNIdleState_Reset, + }, + .channels = pios_tim_servoport_rcvrport_pins, + .num_channels = NELEMENTS(pios_tim_servoport_rcvrport_pins), +}; + + /* * PPM Inputs */ @@ -916,7 +1057,7 @@ void PIOS_I2C_main_adapter_er_irq_handler(void) #include "pios_rcvr_priv.h" /* One slot per selectable receiver group. - * eg. PWM, PPM, GCS, SPEKTRUM1, SPEKTRUM2, SBUS + * eg. PWM, PPM, GCS, DSMMAINPORT, DSMFLEXIPORT, SBUS * NOTE: No slot in this map for NONE. */ uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; @@ -1025,7 +1166,7 @@ void PIOS_Board_Init(void) { } uint32_t pios_sbus_id; - if (PIOS_SBUS_Init(&pios_sbus_id, &pios_sbus_cfg, &pios_usart_com_driver, pios_usart_sbus_id)) { + if (PIOS_SBus_Init(&pios_sbus_id, &pios_sbus_cfg, &pios_usart_com_driver, pios_usart_sbus_id)) { PIOS_Assert(0); } @@ -1056,31 +1197,48 @@ void PIOS_Board_Init(void) { } #endif /* PIOS_INCLUDE_GPS */ break; - case HWSETTINGS_CC_MAINPORT_SPEKTRUM1: - case HWSETTINGS_CC_MAINPORT_SPEKTRUM2: -#if defined(PIOS_INCLUDE_SPEKTRUM) + case HWSETTINGS_CC_MAINPORT_DSM2: + case HWSETTINGS_CC_MAINPORT_DSMX10BIT: + case HWSETTINGS_CC_MAINPORT_DSMX11BIT: +#if defined(PIOS_INCLUDE_DSM) { - uint32_t pios_usart_spektrum_id; - if (PIOS_USART_Init(&pios_usart_spektrum_id, &pios_usart_spektrum_main_cfg)) { + enum pios_dsm_proto proto; + switch (hwsettings_cc_mainport) { + case HWSETTINGS_CC_MAINPORT_DSM2: + proto = PIOS_DSM_PROTO_DSM2; + break; + case HWSETTINGS_CC_MAINPORT_DSMX10BIT: + proto = PIOS_DSM_PROTO_DSMX10BIT; + break; + case HWSETTINGS_CC_MAINPORT_DSMX11BIT: + proto = PIOS_DSM_PROTO_DSMX11BIT; + break; + default: + PIOS_Assert(0); + break; + } + + uint32_t pios_usart_dsm_id; + if (PIOS_USART_Init(&pios_usart_dsm_id, &pios_usart_dsm_main_cfg)) { PIOS_Assert(0); } - uint32_t pios_spektrum_id; - if (PIOS_SPEKTRUM_Init(&pios_spektrum_id, &pios_spektrum_main_cfg, &pios_usart_com_driver, pios_usart_spektrum_id, 0)) { + uint32_t pios_dsm_id; + if (PIOS_DSM_Init(&pios_dsm_id, + &pios_dsm_main_cfg, + &pios_usart_com_driver, + pios_usart_dsm_id, + proto, 0)) { PIOS_Assert(0); } - uint32_t pios_spektrum_rcvr_id; - if (PIOS_RCVR_Init(&pios_spektrum_rcvr_id, &pios_spektrum_rcvr_driver, pios_spektrum_id)) { + uint32_t pios_dsm_rcvr_id; + if (PIOS_RCVR_Init(&pios_dsm_rcvr_id, &pios_dsm_rcvr_driver, pios_dsm_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; - } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMMAINPORT] = pios_dsm_rcvr_id; } -#endif /* PIOS_INCLUDE_SPEKTRUM */ +#endif /* PIOS_INCLUDE_DSM */ break; case HWSETTINGS_CC_MAINPORT_COMAUX: break; @@ -1129,31 +1287,48 @@ void PIOS_Board_Init(void) { } #endif /* PIOS_INCLUDE_GPS */ break; - case HWSETTINGS_CC_FLEXIPORT_SPEKTRUM1: - case HWSETTINGS_CC_FLEXIPORT_SPEKTRUM2: -#if defined(PIOS_INCLUDE_SPEKTRUM) + case HWSETTINGS_CC_FLEXIPORT_DSM2: + case HWSETTINGS_CC_FLEXIPORT_DSMX10BIT: + case HWSETTINGS_CC_FLEXIPORT_DSMX11BIT: +#if defined(PIOS_INCLUDE_DSM) { - uint32_t pios_usart_spektrum_id; - if (PIOS_USART_Init(&pios_usart_spektrum_id, &pios_usart_spektrum_flexi_cfg)) { + enum pios_dsm_proto proto; + switch (hwsettings_cc_flexiport) { + case HWSETTINGS_CC_FLEXIPORT_DSM2: + proto = PIOS_DSM_PROTO_DSM2; + break; + case HWSETTINGS_CC_FLEXIPORT_DSMX10BIT: + proto = PIOS_DSM_PROTO_DSMX10BIT; + break; + case HWSETTINGS_CC_FLEXIPORT_DSMX11BIT: + proto = PIOS_DSM_PROTO_DSMX11BIT; + break; + default: + PIOS_Assert(0); + break; + } + + uint32_t pios_usart_dsm_id; + if (PIOS_USART_Init(&pios_usart_dsm_id, &pios_usart_dsm_flexi_cfg)) { PIOS_Assert(0); } - uint32_t pios_spektrum_id; - if (PIOS_SPEKTRUM_Init(&pios_spektrum_id, &pios_spektrum_flexi_cfg, &pios_usart_com_driver, pios_usart_spektrum_id, hwsettings_DSMxBind)) { + uint32_t pios_dsm_id; + if (PIOS_DSM_Init(&pios_dsm_id, + &pios_dsm_flexi_cfg, + &pios_usart_com_driver, + pios_usart_dsm_id, + proto, hwsettings_DSMxBind)) { PIOS_Assert(0); } - uint32_t pios_spektrum_rcvr_id; - if (PIOS_RCVR_Init(&pios_spektrum_rcvr_id, &pios_spektrum_rcvr_driver, pios_spektrum_id)) { + uint32_t pios_dsm_rcvr_id; + if (PIOS_RCVR_Init(&pios_dsm_rcvr_id, &pios_dsm_rcvr_driver, pios_dsm_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; - } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMFLEXIPORT] = pios_dsm_rcvr_id; } -#endif /* PIOS_INCLUDE_SPEKTRUM */ +#endif /* PIOS_INCLUDE_DSM */ break; case HWSETTINGS_CC_FLEXIPORT_COMAUX: break; @@ -1190,6 +1365,7 @@ void PIOS_Board_Init(void) { #endif /* PIOS_INCLUDE_PWM */ break; case HWSETTINGS_CC_RCVRPORT_PPM: + case HWSETTINGS_CC_RCVRPORT_PPMSERVO: #if defined(PIOS_INCLUDE_PPM) { uint32_t pios_ppm_id; @@ -1219,7 +1395,17 @@ void PIOS_Board_Init(void) { GPIO_PinRemapConfig( GPIO_Remap_SWJ_NoJTRST, ENABLE); #ifndef PIOS_DEBUG_ENABLE_DEBUG_PINS - PIOS_Servo_Init(&pios_servo_cfg); + switch (hwsettings_rcvrport) { + case HWSETTINGS_CC_RCVRPORT_DISABLED: + case HWSETTINGS_CC_RCVRPORT_PWM: + case HWSETTINGS_CC_RCVRPORT_PPM: + PIOS_Servo_Init(&pios_servo_cfg); + break; + case HWSETTINGS_CC_RCVRPORT_PPMSERVO: + case HWSETTINGS_CC_RCVRPORT_SERVO: + PIOS_Servo_Init(&pios_servo_rcvr_cfg); + break; + } #else PIOS_DEBUG_Init(&pios_tim_servo_all_channels, NELEMENTS(pios_tim_servo_all_channels)); #endif /* PIOS_DEBUG_ENABLE_DEBUG_PINS */ diff --git a/flight/Modules/ManualControl/manualcontrol.c b/flight/Modules/ManualControl/manualcontrol.c index 6186a6af9..db98283df 100644 --- a/flight/Modules/ManualControl/manualcontrol.c +++ b/flight/Modules/ManualControl/manualcontrol.c @@ -439,11 +439,11 @@ static bool updateRcvrActivityCompare(uint32_t rcvr_id, struct rcvr_activity_fsm case MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM: group = RECEIVERACTIVITY_ACTIVEGROUP_PPM; break; - case MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM1: - group = RECEIVERACTIVITY_ACTIVEGROUP_SPEKTRUM1; + case MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMMAINPORT: + group = RECEIVERACTIVITY_ACTIVEGROUP_DSMMAINPORT; break; - case MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM2: - group = RECEIVERACTIVITY_ACTIVEGROUP_SPEKTRUM2; + case MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMFLEXIPORT: + group = RECEIVERACTIVITY_ACTIVEGROUP_DSMFLEXIPORT; break; case MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS: group = RECEIVERACTIVITY_ACTIVEGROUP_SBUS; diff --git a/flight/Modules/System/systemmod.c b/flight/Modules/System/systemmod.c index d5a6bfb12..6740e88aa 100644 --- a/flight/Modules/System/systemmod.c +++ b/flight/Modules/System/systemmod.c @@ -390,25 +390,24 @@ static void updateSystemAlarms() EventStats evStats; SystemStatsGet(&stats); - // Check heap - if (stats.HeapRemaining < HEAP_LIMIT_CRITICAL) { - AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_CRITICAL); - } else if (stats.HeapRemaining < HEAP_LIMIT_WARNING) { - AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_WARNING); - } else { - AlarmsClear(SYSTEMALARMS_ALARM_OUTOFMEMORY); - } - + // Check heap, IRQ stack and malloc failures + if ( mallocFailed + || (stats.HeapRemaining < HEAP_LIMIT_CRITICAL) #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK) - // Check IRQ stack - if (stats.IRQStackRemaining < IRQSTACK_LIMIT_CRITICAL) { + || (stats.IRQStackRemaining < IRQSTACK_LIMIT_CRITICAL) +#endif + ) { AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_CRITICAL); - } else if (stats.IRQStackRemaining < IRQSTACK_LIMIT_WARNING) { + } else if ( + (stats.HeapRemaining < HEAP_LIMIT_WARNING) +#if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK) + || (stats.IRQStackRemaining < IRQSTACK_LIMIT_WARNING) +#endif + ) { AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_WARNING); } else { AlarmsClear(SYSTEMALARMS_ALARM_OUTOFMEMORY); } -#endif // Check CPU load if (stats.CPULoad > CPULOAD_LIMIT_CRITICAL) { @@ -426,13 +425,6 @@ static void updateSystemAlarms() AlarmsClear(SYSTEMALARMS_ALARM_STACKOVERFLOW); } - // Check for malloc failures - if (mallocFailed) { - AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_CRITICAL); - } else { - AlarmsClear(SYSTEMALARMS_ALARM_OUTOFMEMORY); - } - #if defined(PIOS_INCLUDE_SDCARD) // Check for SD card if (PIOS_SDCARD_IsMounted() == 0) { diff --git a/flight/OpenPilot/Makefile b/flight/OpenPilot/Makefile index cb989f2bc..5374221b8 100644 --- a/flight/OpenPilot/Makefile +++ b/flight/OpenPilot/Makefile @@ -169,7 +169,7 @@ SRC += $(PIOSSTM32F10X)/pios_i2c.c SRC += $(PIOSSTM32F10X)/pios_spi.c SRC += $(PIOSSTM32F10X)/pios_ppm.c SRC += $(PIOSSTM32F10X)/pios_pwm.c -SRC += $(PIOSSTM32F10X)/pios_spektrum.c +SRC += $(PIOSSTM32F10X)/pios_dsm.c SRC += $(PIOSSTM32F10X)/pios_sbus.c SRC += $(PIOSSTM32F10X)/pios_tim.c SRC += $(PIOSSTM32F10X)/pios_debug.c diff --git a/flight/OpenPilot/System/inc/pios_config.h b/flight/OpenPilot/System/inc/pios_config.h index 12dc4e161..81699215b 100644 --- a/flight/OpenPilot/System/inc/pios_config.h +++ b/flight/OpenPilot/System/inc/pios_config.h @@ -44,7 +44,7 @@ #define PIOS_INCLUDE_RCVR -#define PIOS_INCLUDE_SPEKTRUM +#define PIOS_INCLUDE_DSM //#define PIOS_INCLUDE_SBUS #define PIOS_INCLUDE_PWM #define PIOS_INCLUDE_PPM diff --git a/flight/OpenPilot/System/openpilot.c b/flight/OpenPilot/System/openpilot.c index 81a8f17b1..c90f5fd81 100644 --- a/flight/OpenPilot/System/openpilot.c +++ b/flight/OpenPilot/System/openpilot.c @@ -143,11 +143,11 @@ static void TaskTesting(void *pvParameters) PIOS_COM_SendFormattedStringNonBlocking(COM_DEBUG_USART, "%u\r", PIOS_BMP085_GetPressure()); */ -#if defined(PIOS_INCLUDE_SPEKTRUM) - PIOS_COM_SendFormattedStringNonBlocking(COM_DEBUG_USART, "%u,%u,%u,%u,%u,%u,%u,%u\r", PIOS_SPEKTRUM_Get(0), PIOS_SPEKTRUM_Get(1), PIOS_SPEKTRUM_Get(2), PIOS_SPEKTRUM_Get(3), PIOS_SPEKTRUM_Get(4), PIOS_SPEKTRUM_Get(5), PIOS_SPEKTRUM_Get(6), PIOS_SPEKTRUM_Get(7)); +#if defined(PIOS_INCLUDE_DSM) + PIOS_COM_SendFormattedStringNonBlocking(COM_DEBUG_USART, "%u,%u,%u,%u,%u,%u,%u,%u\r", PIOS_DSM_Get(0), PIOS_DSM_Get(1), PIOS_DSM_Get(2), PIOS_DSM_Get(3), PIOS_DSM_Get(4), PIOS_DSM_Get(5), PIOS_DSM_Get(6), PIOS_DSM_Get(7)); #endif #if defined(PIOS_INCLUDE_SBUS) - PIOS_COM_SendFormattedStringNonBlocking(COM_DEBUG_USART, "%u,%u,%u,%u,%u,%u,%u,%u\r", PIOS_SBUS_Get(0), PIOS_SBUS_Get(1), PIOS_SBUS_Get(2), PIOS_SBUS_Get(3), PIOS_SBUS_Get(4), PIOS_SBUS_Get(5), PIOS_SBUS_Get(6), PIOS_SBUS_Get(7)); + PIOS_COM_SendFormattedStringNonBlocking(COM_DEBUG_USART, "%u,%u,%u,%u,%u,%u,%u,%u\r", PIOS_SBus_Get(0), PIOS_SBus_Get(1), PIOS_SBus_Get(2), PIOS_SBus_Get(3), PIOS_SBus_Get(4), PIOS_SBus_Get(5), PIOS_SBus_Get(6), PIOS_SBus_Get(7)); #endif #if defined(PIOS_INCLUDE_PWM) PIOS_COM_SendFormattedStringNonBlocking(COM_DEBUG_USART, "%u,%u,%u,%u,%u,%u,%u,%u uS\r", PIOS_PWM_Get(0), PIOS_PWM_Get(1), PIOS_PWM_Get(2), PIOS_PWM_Get(3), PIOS_PWM_Get(4), PIOS_PWM_Get(5), PIOS_PWM_Get(6), PIOS_PWM_Get(7)); diff --git a/flight/OpenPilot/System/pios_board.c b/flight/OpenPilot/System/pios_board.c index 9b22ba8e0..03a75a30c 100644 --- a/flight/OpenPilot/System/pios_board.c +++ b/flight/OpenPilot/System/pios_board.c @@ -538,13 +538,13 @@ void PIOS_RTC_IRQ_Handler (void) #endif -#if defined(PIOS_INCLUDE_SPEKTRUM) +#if defined(PIOS_INCLUDE_DSM) /* - * SPEKTRUM USART + * Spektrum/JR DSM USART */ -#include +#include -static const struct pios_usart_cfg pios_usart_spektrum_cfg = { +static const struct pios_usart_cfg pios_usart_dsm_cfg = { .regs = USART1, .init = { .USART_BaudRate = 115200, @@ -580,7 +580,7 @@ static const struct pios_usart_cfg pios_usart_spektrum_cfg = { }, }; -static const struct pios_spektrum_cfg pios_spektrum_cfg = { +static const struct pios_dsm_cfg pios_dsm_cfg = { .bind = { .gpio = GPIOA, .init = { @@ -589,10 +589,9 @@ static const struct pios_spektrum_cfg pios_spektrum_cfg = { .GPIO_Mode = GPIO_Mode_Out_PP, }, }, - .remap = 0, }; -#endif /* PIOS_COM_SPEKTRUM */ +#endif /* PIOS_COM_DSM */ #if defined(PIOS_INCLUDE_SBUS) #error PIOS_INCLUDE_SBUS not implemented @@ -1035,7 +1034,7 @@ static const struct stm32_gpio pios_debug_pins[] = { #include "pios_rcvr_priv.h" /* One slot per selectable receiver group. - * eg. PWM, PPM, GCS, SPEKTRUM1, SPEKTRUM2, SBUS + * eg. PWM, PPM, GCS, DSMMAINPORT, DSMFLEXIPORT, SBUS * NOTE: No slot in this map for NONE. */ uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; @@ -1063,7 +1062,7 @@ uint32_t pios_com_telem_rf_id; uint32_t pios_com_telem_usb_id; uint32_t pios_com_gps_id; uint32_t pios_com_aux_id; -uint32_t pios_com_spektrum_id; +uint32_t pios_com_dsm_id; #include "ahrs_spi_comm.h" @@ -1204,24 +1203,46 @@ void PIOS_Board_Init(void) { case HWSETTINGS_OP_RCVRPORT_DEBUG: /* Not supported yet */ break; - case HWSETTINGS_OP_RCVRPORT_SPEKTRUM1: -#if defined(PIOS_INCLUDE_SPEKTRUM) + case HWSETTINGS_OP_RCVRPORT_DSM2: + case HWSETTINGS_OP_RCVRPORT_DSMX10BIT: + case HWSETTINGS_OP_RCVRPORT_DSMX11BIT: +#if defined(PIOS_INCLUDE_DSM) { - uint32_t pios_usart_spektrum_id; - if (PIOS_USART_Init(&pios_usart_spektrum_id, &pios_usart_spektrum_cfg)) { + enum pios_dsm_proto proto; + switch (hwsettings_rcvrport) { + case HWSETTINGS_OP_RCVRPORT_DSM2: + proto = PIOS_DSM_PROTO_DSM2; + break; + case HWSETTINGS_OP_RCVRPORT_DSMX10BIT: + proto = PIOS_DSM_PROTO_DSMX10BIT; + break; + case HWSETTINGS_OP_RCVRPORT_DSMX11BIT: + proto = PIOS_DSM_PROTO_DSMX11BIT; + break; + default: + PIOS_Assert(0); + break; + } + + uint32_t pios_usart_dsm_id; + if (PIOS_USART_Init(&pios_usart_dsm_id, &pios_usart_dsm_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)) { + uint32_t pios_dsm_id; + if (PIOS_DSM_Init(&pios_dsm_id, + &pios_dsm_cfg, + &pios_usart_com_driver, + pios_usart_dsm_id, + proto, 0)) { PIOS_Assert(0); } - uint32_t pios_spektrum_rcvr_id; - if (PIOS_RCVR_Init(&pios_spektrum_rcvr_id, &pios_spektrum_rcvr_driver, pios_spektrum_id)) { + uint32_t pios_dsm_rcvr_id; + if (PIOS_RCVR_Init(&pios_dsm_rcvr_id, &pios_dsm_rcvr_driver, pios_dsm_id)) { PIOS_Assert(0); } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM1] = pios_spektrum_rcvr_id; + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMMAINPORT] = pios_dsm_rcvr_id; } #endif break; diff --git a/flight/OpenPilot/System/pios_board_posix.c b/flight/OpenPilot/System/pios_board_posix.c index 679110ea5..bb1f7d5b2 100644 --- a/flight/OpenPilot/System/pios_board_posix.c +++ b/flight/OpenPilot/System/pios_board_posix.c @@ -40,7 +40,7 @@ #include "pios_rcvr_priv.h" /* One slot per selectable receiver group. - * eg. PWM, PPM, GCS, SPEKTRUM1, SPEKTRUM2, SBUS + * eg. PWM, PPM, GCS, DSMMAINPORT, DSMFLEXIPORT, SBUS * NOTE: No slot in this map for NONE. */ uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; diff --git a/flight/PiOS/Boards/STM32103CB_CC_Rev1.h b/flight/PiOS/Boards/STM32103CB_CC_Rev1.h index 42b3a5e4d..1a8a17c89 100644 --- a/flight/PiOS/Boards/STM32103CB_CC_Rev1.h +++ b/flight/PiOS/Boards/STM32103CB_CC_Rev1.h @@ -222,10 +222,16 @@ extern uint32_t pios_com_telem_usb_id; #define PIOS_PWM_NUM_INPUTS 6 //------------------------- -// Receiver SPEKTRUM input +// Receiver DSM input //------------------------- -#define PIOS_SPEKTRUM_MAX_DEVS 2 -#define PIOS_SPEKTRUM_NUM_INPUTS 12 +#define PIOS_DSM_MAX_DEVS 2 +#define PIOS_DSM_NUM_INPUTS 12 + +//------------------------- +// Receiver S.Bus input +//------------------------- +#define PIOS_SBUS_MAX_DEVS 1 +#define PIOS_SBUS_NUM_INPUTS (16+2) //------------------------- // Servo outputs diff --git a/flight/PiOS/Boards/STM3210E_OP.h b/flight/PiOS/Boards/STM3210E_OP.h index ea925a271..c82bb8fe8 100644 --- a/flight/PiOS/Boards/STM3210E_OP.h +++ b/flight/PiOS/Boards/STM3210E_OP.h @@ -195,10 +195,16 @@ extern uint32_t pios_com_aux_id; #define PIOS_PWM_NUM_INPUTS 8 //------------------------- -// Receiver SPEKTRUM input +// Receiver DSM input //------------------------- -#define PIOS_SPEKTRUM_MAX_DEVS 1 -#define PIOS_SPEKTRUM_NUM_INPUTS 12 +#define PIOS_DSM_MAX_DEVS 1 +#define PIOS_DSM_NUM_INPUTS 12 + +//------------------------- +// Receiver S.Bus input +//------------------------- +#define PIOS_SBUS_MAX_DEVS 0 +#define PIOS_SBUS_NUM_INPUTS (16+2) //------------------------- // Servo outputs diff --git a/flight/PiOS/Common/pios_hcsr04.c b/flight/PiOS/Common/pios_hcsr04.c index 6db1bc401..cbdb31e7e 100644 --- a/flight/PiOS/Common/pios_hcsr04.c +++ b/flight/PiOS/Common/pios_hcsr04.c @@ -32,8 +32,8 @@ #include "pios.h" #if defined(PIOS_INCLUDE_HCSR04) -#if !(defined(PIOS_INCLUDE_SPEKTRUM) || defined(PIOS_INCLUDE_SBUS)) -#error Only supported with Spektrum or S.Bus interface! +#if !(defined(PIOS_INCLUDE_DSM) || defined(PIOS_INCLUDE_SBUS)) +#error Only supported with Spektrum/JR DSM or S.Bus interface! #endif /* Local Variables */ diff --git a/flight/PiOS/STM32F10x/pios_dsm.c b/flight/PiOS/STM32F10x/pios_dsm.c new file mode 100644 index 000000000..cb838b56b --- /dev/null +++ b/flight/PiOS/STM32F10x/pios_dsm.c @@ -0,0 +1,407 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_DSM Spektrum/JR DSMx satellite receiver functions + * @brief Code to bind and read Spektrum/JR DSMx satellite receiver serial stream + * @{ + * + * @file pios_dsm.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. + * @brief Code bind and read Spektrum/JR DSMx satellite receiver serial stream + * @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 + */ + +/* Project Includes */ +#include "pios.h" +#include "pios_dsm_priv.h" + +#if defined(PIOS_INCLUDE_DSM) + +/* Forward Declarations */ +static int32_t PIOS_DSM_Get(uint32_t rcvr_id, uint8_t channel); +static uint16_t PIOS_DSM_RxInCallback(uint32_t context, + uint8_t *buf, + uint16_t buf_len, + uint16_t *headroom, + bool *need_yield); +static void PIOS_DSM_Supervisor(uint32_t dsm_id); + +/* Local Variables */ +const struct pios_rcvr_driver pios_dsm_rcvr_driver = { + .read = PIOS_DSM_Get, +}; + +enum pios_dsm_dev_magic { + PIOS_DSM_DEV_MAGIC = 0x44534d78, +}; + +struct pios_dsm_state { + uint16_t channel_data[PIOS_DSM_NUM_INPUTS]; + uint8_t received_data[DSM_FRAME_LENGTH]; + uint8_t receive_timer; + uint8_t failsafe_timer; + uint8_t frame_found; + uint8_t byte_count; +#ifdef DSM_LOST_FRAME_COUNTER + uint8_t frames_lost_last; + uint16_t frames_lost; +#endif +}; + +struct pios_dsm_dev { + enum pios_dsm_dev_magic magic; + const struct pios_dsm_cfg *cfg; + enum pios_dsm_proto proto; + struct pios_dsm_state state; +}; + +/* Allocate DSM device descriptor */ +#if defined(PIOS_INCLUDE_FREERTOS) +static struct pios_dsm_dev *PIOS_DSM_Alloc(void) +{ + struct pios_dsm_dev *dsm_dev; + + dsm_dev = (struct pios_dsm_dev *)pvPortMalloc(sizeof(*dsm_dev)); + if (!dsm_dev) + return NULL; + + dsm_dev->magic = PIOS_DSM_DEV_MAGIC; + return dsm_dev; +} +#else +static struct pios_dsm_dev pios_dsm_devs[PIOS_DSM_MAX_DEVS]; +static uint8_t pios_dsm_num_devs; +static struct pios_dsm_dev *PIOS_DSM_Alloc(void) +{ + struct pios_dsm_dev *dsm_dev; + + if (pios_dsm_num_devs >= PIOS_DSM_MAX_DEVS) + return NULL; + + dsm_dev = &pios_dsm_devs[pios_dsm_num_devs++]; + dsm_dev->magic = PIOS_DSM_DEV_MAGIC; + + return dsm_dev; +} +#endif + +/* Validate DSM device descriptor */ +static bool PIOS_DSM_Validate(struct pios_dsm_dev *dsm_dev) +{ + return (dsm_dev->magic == PIOS_DSM_DEV_MAGIC); +} + +/* Try to bind DSMx satellite using specified number of pulses */ +static void PIOS_DSM_Bind(struct pios_dsm_dev *dsm_dev, uint8_t bind) +{ + const struct pios_dsm_cfg *cfg = dsm_dev->cfg; + + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = cfg->bind.init.GPIO_Pin; + GPIO_InitStructure.GPIO_Speed = cfg->bind.init.GPIO_Speed; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; + + /* just to limit bind pulses */ + if (bind > 10) + bind = 10; + + GPIO_Init(cfg->bind.gpio, &cfg->bind.init); + + /* RX line, set high */ + GPIO_SetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); + + /* on CC works up to 140ms, guess bind window is around 20-140ms after power up */ + PIOS_DELAY_WaitmS(60); + + for (int i = 0; i < bind ; i++) { + /* RX line, drive low for 120us */ + GPIO_ResetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); + PIOS_DELAY_WaituS(120); + /* RX line, drive high for 120us */ + GPIO_SetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); + PIOS_DELAY_WaituS(120); + } + /* RX line, set input and wait for data */ + GPIO_Init(cfg->bind.gpio, &GPIO_InitStructure); +} + +/* Reset channels in case of lost signal or explicit failsafe receiver flag */ +static void PIOS_DSM_ResetChannels(struct pios_dsm_dev *dsm_dev) +{ + struct pios_dsm_state *state = &(dsm_dev->state); + for (int i = 0; i < PIOS_DSM_NUM_INPUTS; i++) { + state->channel_data[i] = PIOS_RCVR_TIMEOUT; + } +} + +/* Reset DSM receiver state */ +static void PIOS_DSM_ResetState(struct pios_dsm_dev *dsm_dev) +{ + struct pios_dsm_state *state = &(dsm_dev->state); + state->receive_timer = 0; + state->failsafe_timer = 0; + state->frame_found = 0; +#ifdef DSM_LOST_FRAME_COUNTER + state->frames_lost_last = 0; + state->frames_lost = 0; +#endif + PIOS_DSM_ResetChannels(dsm_dev); +} + +/** + * Check and unroll complete frame data. + * \output 0 frame data accepted + * \output -1 frame error found + */ +static int PIOS_DSM_UnrollChannels(struct pios_dsm_dev *dsm_dev) +{ + struct pios_dsm_state *state = &(dsm_dev->state); + uint8_t resolution; + +#ifdef DSM_LOST_FRAME_COUNTER + /* increment the lost frame counter */ + uint8_t frames_lost = state->received_data[0]; + state->frames_lost += (frames_lost - state->frames_lost_last); + state->frames_lost_last = frames_lost; +#endif + + /* check the frame type assuming master satellite stream */ + uint8_t type = state->received_data[1]; + switch (type) { + case 0x01: + case 0x02: + case 0x12: + /* DSM2, DSMJ stream */ + if (dsm_dev->proto == PIOS_DSM_PROTO_DSM2) { + /* DSM2/DSMJ resolution is known from the header */ + resolution = (type & DSM_DSM2_RES_MASK) ? 11 : 10; + } else { + /* DSMX resolution should explicitly be selected */ + goto stream_error; + } + break; + case 0xA2: + case 0xB2: + /* DSMX stream */ + if (dsm_dev->proto == PIOS_DSM_PROTO_DSMX10BIT) { + resolution = 10; + } else if (dsm_dev->proto == PIOS_DSM_PROTO_DSMX11BIT) { + resolution = 11; + } else { + /* DSMX resolution should explicitly be selected */ + goto stream_error; + } + break; + default: + /* unknown yet data stream */ + goto stream_error; + } + + /* unroll channels */ + uint8_t *s = &(state->received_data[2]); + uint16_t mask = (resolution == 10) ? 0x03ff : 0x07ff; + + for (int i = 0; i < DSM_CHANNELS_PER_FRAME; i++) { + uint16_t word = ((uint16_t)s[0] << 8) | s[1]; + s += 2; + + /* skip empty channel slot */ + if (word == 0xffff) + continue; + + /* minimal data validation */ + if ((i > 0) && (word & DSM_2ND_FRAME_MASK)) { + /* invalid frame data, ignore rest of the frame */ + goto stream_error; + } + + /* extract and save the channel value */ + uint8_t channel_num = (word >> resolution) & 0x0f; + if (channel_num < PIOS_DSM_NUM_INPUTS) + state->channel_data[channel_num] = (word & mask); + } + +#ifdef DSM_LOST_FRAME_COUNTER + /* put lost frames counter into the last channel for debugging */ + state->channel_data[PIOS_DSM_NUM_INPUTS-1] = state->frames_lost; +#endif + + /* all channels processed */ + return 0; + +stream_error: + /* either DSM2 selected with DSMX stream found, or vice-versa */ + return -1; +} + +/* Update decoder state processing input byte from the DSMx stream */ +static void PIOS_DSM_UpdateState(struct pios_dsm_dev *dsm_dev, uint8_t byte) +{ + struct pios_dsm_state *state = &(dsm_dev->state); + if (state->frame_found) { + /* receiving the data frame */ + if (state->byte_count < DSM_FRAME_LENGTH) { + /* store next byte */ + state->received_data[state->byte_count++] = byte; + if (state->byte_count == DSM_FRAME_LENGTH) { + /* full frame received - process and wait for new one */ + if (!PIOS_DSM_UnrollChannels(dsm_dev)) + /* data looking good */ + state->failsafe_timer = 0; + + /* prepare for the next frame */ + state->frame_found = 0; + } + } + } +} + +/* Initialise DSM receiver interface */ +int32_t PIOS_DSM_Init(uint32_t *dsm_id, + const struct pios_dsm_cfg *cfg, + const struct pios_com_driver *driver, + uint32_t lower_id, + enum pios_dsm_proto proto, + uint8_t bind) +{ + PIOS_DEBUG_Assert(dsm_id); + PIOS_DEBUG_Assert(cfg); + PIOS_DEBUG_Assert(driver); + + struct pios_dsm_dev *dsm_dev; + + dsm_dev = (struct pios_dsm_dev *)PIOS_DSM_Alloc(); + if (!dsm_dev) + return -1; + + /* Bind the configuration to the device instance */ + dsm_dev->cfg = cfg; + dsm_dev->proto = proto; + + /* Bind the receiver if requested */ + if (bind) + PIOS_DSM_Bind(dsm_dev, bind); + + PIOS_DSM_ResetState(dsm_dev); + + *dsm_id = (uint32_t)dsm_dev; + + /* Set comm driver callback */ + (driver->bind_rx_cb)(lower_id, PIOS_DSM_RxInCallback, *dsm_id); + + if (!PIOS_RTC_RegisterTickCallback(PIOS_DSM_Supervisor, *dsm_id)) { + PIOS_DEBUG_Assert(0); + } + + return 0; +} + +/* Comm byte received callback */ +static uint16_t PIOS_DSM_RxInCallback(uint32_t context, + uint8_t *buf, + uint16_t buf_len, + uint16_t *headroom, + bool *need_yield) +{ + struct pios_dsm_dev *dsm_dev = (struct pios_dsm_dev *)context; + + bool valid = PIOS_DSM_Validate(dsm_dev); + PIOS_Assert(valid); + + /* process byte(s) and clear receive timer */ + for (uint8_t i = 0; i < buf_len; i++) { + PIOS_DSM_UpdateState(dsm_dev, buf[i]); + dsm_dev->state.receive_timer = 0; + } + + /* Always signal that we can accept another byte */ + if (headroom) + *headroom = DSM_FRAME_LENGTH; + + /* We never need a yield */ + *need_yield = false; + + /* Always indicate that all bytes were consumed */ + return buf_len; +} + +/** + * Get the value of an input channel + * \param[in] channel Number of the channel desired (zero based) + * \output PIOS_RCVR_INVALID channel not available + * \output PIOS_RCVR_TIMEOUT failsafe condition or missing receiver + * \output >0 channel value + */ +static int32_t PIOS_DSM_Get(uint32_t rcvr_id, uint8_t channel) +{ + struct pios_dsm_dev *dsm_dev = (struct pios_dsm_dev *)rcvr_id; + + if (!PIOS_DSM_Validate(dsm_dev)) + return PIOS_RCVR_INVALID; + + /* return error if channel is not available */ + if (channel >= PIOS_DSM_NUM_INPUTS) + return PIOS_RCVR_INVALID; + + /* may also be PIOS_RCVR_TIMEOUT set by other function */ + return dsm_dev->state.channel_data[channel]; +} + +/** + * Input data supervisor is called periodically and provides + * two functions: frame syncing and failsafe triggering. + * + * DSM frames come at 11ms or 22ms rate at 115200bps. + * RTC timer is running at 625Hz (1.6ms). So with divider 5 it gives + * 8ms pause between frames which is good for both DSM frame rates. + * + * Data receive function must clear the receive_timer to confirm new + * data reception. If no new data received in 100ms, we must call the + * failsafe function which clears all channels. + */ +static void PIOS_DSM_Supervisor(uint32_t dsm_id) +{ + struct pios_dsm_dev *dsm_dev = (struct pios_dsm_dev *)dsm_id; + + bool valid = PIOS_DSM_Validate(dsm_dev); + PIOS_Assert(valid); + + struct pios_dsm_state *state = &(dsm_dev->state); + + /* waiting for new frame if no bytes were received in 8ms */ + if (++state->receive_timer > 4) { + state->frame_found = 1; + state->byte_count = 0; + state->receive_timer = 0; + } + + /* activate failsafe if no frames have arrived in 102.4ms */ + if (++state->failsafe_timer > 64) { + PIOS_DSM_ResetChannels(dsm_dev); + state->failsafe_timer = 0; + } +} + +#endif /* PIOS_INCLUDE_DSM */ + +/** + * @} + * @} + */ diff --git a/flight/PiOS/STM32F10x/pios_sbus.c b/flight/PiOS/STM32F10x/pios_sbus.c index 319142dc6..53730b16b 100644 --- a/flight/PiOS/STM32F10x/pios_sbus.c +++ b/flight/PiOS/STM32F10x/pios_sbus.c @@ -2,13 +2,13 @@ ****************************************************************************** * @addtogroup PIOS PIOS Core hardware abstraction layer * @{ - * @addtogroup PIOS_SBUS Futaba S.Bus receiver functions - * @brief Code to read Futaba S.Bus input + * @addtogroup PIOS_SBus Futaba S.Bus receiver functions + * @brief Code to read Futaba S.Bus receiver serial stream * @{ * * @file pios_sbus.c * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. - * @brief USART commands. Inits USARTs, controls USARTs & Interrupt handlers. (STM32 dependent) + * @brief Code to read Futaba S.Bus receiver serial stream * @see The GNU Public License (GPL) Version 3 * *****************************************************************************/ @@ -34,44 +34,166 @@ #if defined(PIOS_INCLUDE_SBUS) -/* Provide a RCVR driver */ -static int32_t PIOS_SBUS_Get(uint32_t rcvr_id, uint8_t channel); +/* Forward Declarations */ +static int32_t PIOS_SBus_Get(uint32_t rcvr_id, uint8_t channel); +static uint16_t PIOS_SBus_RxInCallback(uint32_t context, + uint8_t *buf, + uint16_t buf_len, + uint16_t *headroom, + bool *need_yield); +static void PIOS_SBus_Supervisor(uint32_t sbus_id); -const struct pios_rcvr_driver pios_sbus_rcvr_driver = { - .read = PIOS_SBUS_Get, -}; /* Local Variables */ -static uint16_t channel_data[SBUS_NUMBER_OF_CHANNELS]; -static uint8_t received_data[SBUS_FRAME_LENGTH - 2]; -static uint8_t receive_timer; -static uint8_t failsafe_timer; -static uint8_t frame_found; +const struct pios_rcvr_driver pios_sbus_rcvr_driver = { + .read = PIOS_SBus_Get, +}; -static void PIOS_SBUS_Supervisor(uint32_t sbus_id); +enum pios_sbus_dev_magic { + PIOS_SBUS_DEV_MAGIC = 0x53427573, +}; -/** - * reset_channels() function clears all channel data in case of - * lost signal or explicit failsafe flag from the S.Bus data stream - */ -static void reset_channels(void) +struct pios_sbus_state { + uint16_t channel_data[PIOS_SBUS_NUM_INPUTS]; + uint8_t received_data[SBUS_FRAME_LENGTH - 2]; + uint8_t receive_timer; + uint8_t failsafe_timer; + uint8_t frame_found; + uint8_t byte_count; +}; + +struct pios_sbus_dev { + enum pios_sbus_dev_magic magic; + const struct pios_sbus_cfg *cfg; + struct pios_sbus_state state; +}; + +/* Allocate S.Bus device descriptor */ +#if defined(PIOS_INCLUDE_FREERTOS) +static struct pios_sbus_dev *PIOS_SBus_Alloc(void) { - for (int i = 0; i < SBUS_NUMBER_OF_CHANNELS; i++) { - channel_data[i] = PIOS_RCVR_TIMEOUT; + struct pios_sbus_dev *sbus_dev; + + sbus_dev = (struct pios_sbus_dev *)pvPortMalloc(sizeof(*sbus_dev)); + if (!sbus_dev) return(NULL); + + sbus_dev->magic = PIOS_SBUS_DEV_MAGIC; + return(sbus_dev); +} +#else +static struct pios_sbus_dev pios_sbus_devs[PIOS_SBUS_MAX_DEVS]; +static uint8_t pios_sbus_num_devs; +static struct pios_sbus_dev *PIOS_SBus_Alloc(void) +{ + struct pios_sbus_dev *sbus_dev; + + if (pios_sbus_num_devs >= PIOS_SBUS_MAX_DEVS) { + return (NULL); + } + + sbus_dev = &pios_sbus_devs[pios_sbus_num_devs++]; + sbus_dev->magic = PIOS_SBUS_DEV_MAGIC; + + return (sbus_dev); +} +#endif + +/* Validate S.Bus device descriptor */ +static bool PIOS_SBus_Validate(struct pios_sbus_dev *sbus_dev) +{ + return (sbus_dev->magic == PIOS_SBUS_DEV_MAGIC); +} + +/* Reset channels in case of lost signal or explicit failsafe receiver flag */ +static void PIOS_SBus_ResetChannels(struct pios_sbus_state *state) +{ + for (int i = 0; i < PIOS_SBUS_NUM_INPUTS; i++) { + state->channel_data[i] = PIOS_RCVR_TIMEOUT; } } +/* Reset S.Bus receiver state */ +static void PIOS_SBus_ResetState(struct pios_sbus_state *state) +{ + state->receive_timer = 0; + state->failsafe_timer = 0; + state->frame_found = 0; + PIOS_SBus_ResetChannels(state); +} + +/* Initialise S.Bus receiver interface */ +int32_t PIOS_SBus_Init(uint32_t *sbus_id, + const struct pios_sbus_cfg *cfg, + const struct pios_com_driver *driver, + uint32_t lower_id) +{ + PIOS_DEBUG_Assert(sbus_id); + PIOS_DEBUG_Assert(cfg); + PIOS_DEBUG_Assert(driver); + + struct pios_sbus_dev *sbus_dev; + + sbus_dev = (struct pios_sbus_dev *)PIOS_SBus_Alloc(); + if (!sbus_dev) goto out_fail; + + /* Bind the configuration to the device instance */ + sbus_dev->cfg = cfg; + + PIOS_SBus_ResetState(&(sbus_dev->state)); + + *sbus_id = (uint32_t)sbus_dev; + + /* Enable inverter clock and enable the inverter */ + (*cfg->gpio_clk_func)(cfg->gpio_clk_periph, ENABLE); + GPIO_Init(cfg->inv.gpio, &cfg->inv.init); + GPIO_WriteBit(cfg->inv.gpio, cfg->inv.init.GPIO_Pin, cfg->gpio_inv_enable); + + /* Set comm driver callback */ + (driver->bind_rx_cb)(lower_id, PIOS_SBus_RxInCallback, *sbus_id); + + if (!PIOS_RTC_RegisterTickCallback(PIOS_SBus_Supervisor, *sbus_id)) { + PIOS_DEBUG_Assert(0); + } + + return 0; + +out_fail: + return -1; +} + /** - * unroll_channels() function computes channel_data[] from received_data[] + * Get the value of an input channel + * \param[in] channel Number of the channel desired (zero based) + * \output PIOS_RCVR_INVALID channel not available + * \output PIOS_RCVR_TIMEOUT failsafe condition or missing receiver + * \output >0 channel value + */ +static int32_t PIOS_SBus_Get(uint32_t rcvr_id, uint8_t channel) +{ + struct pios_sbus_dev *sbus_dev = (struct pios_sbus_dev *)rcvr_id; + + if (!PIOS_SBus_Validate(sbus_dev)) + return PIOS_RCVR_INVALID; + + /* return error if channel is not available */ + if (channel >= PIOS_SBUS_NUM_INPUTS) { + return PIOS_RCVR_INVALID; + } + + return sbus_dev->state.channel_data[channel]; +} + +/** + * Compute channel_data[] from received_data[]. * For efficiency it unrolls first 8 channels without loops and does the * same for other 8 channels. Also 2 discrete channels will be set. */ -static void unroll_channels(void) +static void PIOS_SBus_UnrollChannels(struct pios_sbus_state *state) { - uint8_t *s = received_data; - uint16_t *d = channel_data; + uint8_t *s = state->received_data; + uint16_t *d = state->channel_data; -#define F(v,s) ((v) >> s) & 0x7ff +#define F(v,s) (((v) >> (s)) & 0x7ff) /* unroll channels 1-8 */ *d++ = F(s[0] | s[1] << 8, 0); @@ -98,132 +220,119 @@ static void unroll_channels(void) *d++ = (s[22] & SBUS_FLAG_DC2) ? SBUS_VALUE_MAX : SBUS_VALUE_MIN; } -/** - * process_byte() function processes incoming byte from S.Bus stream - */ -static void process_byte(uint8_t b) +/* Update decoder state processing input byte from the S.Bus stream */ +static void PIOS_SBus_UpdateState(struct pios_sbus_state *state, uint8_t b) { - static uint8_t byte_count; + /* should not process any data until new frame is found */ + if (!state->frame_found) + return; - if (frame_found == 0) { - /* no frame found yet, waiting for start byte */ - if (b == SBUS_SOF_BYTE) { - byte_count = 0; - frame_found = 1; - } - } else { - /* do not store start and end of frame bytes */ - if (byte_count < SBUS_FRAME_LENGTH - 2) { - /* store next byte */ - received_data[byte_count++] = b; + if (state->byte_count == 0) { + if (b != SBUS_SOF_BYTE) { + /* discard the whole frame if the 1st byte is not correct */ + state->frame_found = 0; } else { - if (b == SBUS_EOF_BYTE) { - /* full frame received */ - uint8_t flags = received_data[SBUS_FRAME_LENGTH - 3]; - if (flags & SBUS_FLAG_FL) { - /* frame lost, do not update */ - } else if (flags & SBUS_FLAG_FS) { - /* failsafe flag active */ - reset_channels(); - } else { - /* data looking good */ - unroll_channels(); - failsafe_timer = 0; - } - } else { - /* discard whole frame */ - } - - /* prepare for the next frame */ - frame_found = 0; + /* do not store the SOF byte */ + state->byte_count++; } + return; + } + + /* do not store last frame byte as well */ + if (state->byte_count < SBUS_FRAME_LENGTH - 1) { + /* store next byte */ + state->received_data[state->byte_count - 1] = b; + state->byte_count++; + } else { + if (b == SBUS_EOF_BYTE) { + /* full frame received */ + uint8_t flags = state->received_data[SBUS_FRAME_LENGTH - 3]; + if (flags & SBUS_FLAG_FL) { + /* frame lost, do not update */ + } else if (flags & SBUS_FLAG_FS) { + /* failsafe flag active */ + PIOS_SBus_ResetChannels(state); + } else { + /* data looking good */ + PIOS_SBus_UnrollChannels(state); + state->failsafe_timer = 0; + } + } else { + /* discard whole frame */ + } + + /* prepare for the next frame */ + state->frame_found = 0; } } -static uint16_t PIOS_SBUS_RxInCallback(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * need_yield) +/* Comm byte received callback */ +static uint16_t PIOS_SBus_RxInCallback(uint32_t context, + uint8_t *buf, + uint16_t buf_len, + uint16_t *headroom, + bool *need_yield) { + struct pios_sbus_dev *sbus_dev = (struct pios_sbus_dev *)context; + + bool valid = PIOS_SBus_Validate(sbus_dev); + PIOS_Assert(valid); + + struct pios_sbus_state *state = &(sbus_dev->state); + /* process byte(s) and clear receive timer */ for (uint8_t i = 0; i < buf_len; i++) { - process_byte(buf[i]); - receive_timer = 0; + PIOS_SBus_UpdateState(state, buf[i]); + state->receive_timer = 0; } /* Always signal that we can accept another byte */ - if (headroom) { + if (headroom) *headroom = SBUS_FRAME_LENGTH; - } /* We never need a yield */ *need_yield = false; /* Always indicate that all bytes were consumed */ - return (buf_len); -} - -/** - * Initialise S.Bus receiver interface - */ -int32_t PIOS_SBUS_Init(uint32_t * sbus_id, const struct pios_sbus_cfg *cfg, const struct pios_com_driver * driver, uint32_t lower_id) -{ - /* Enable inverter clock and enable the inverter */ - (*cfg->gpio_clk_func)(cfg->gpio_clk_periph, ENABLE); - GPIO_Init(cfg->inv.gpio, &cfg->inv.init); - GPIO_WriteBit(cfg->inv.gpio, - cfg->inv.init.GPIO_Pin, - cfg->gpio_inv_enable); - - (driver->bind_rx_cb)(lower_id, PIOS_SBUS_RxInCallback, 0); - - if (!PIOS_RTC_RegisterTickCallback(PIOS_SBUS_Supervisor, 0)) { - PIOS_Assert(0); - } - - return (0); -} - -/** - * Get the value of an input channel - * \param[in] channel Number of the channel desired (zero based) - * \output -1 channel not available - * \output >0 channel value - */ -static int32_t PIOS_SBUS_Get(uint32_t rcvr_id, uint8_t channel) -{ - /* return error if channel is not available */ - if (channel >= SBUS_NUMBER_OF_CHANNELS) { - return PIOS_RCVR_INVALID; - } - return channel_data[channel]; + return buf_len; } /** * Input data supervisor is called periodically and provides * two functions: frame syncing and failsafe triggering. * - * S.Bus frames come at 7ms (HS) or 14ms (FS) rate at 100000bps. RTC - * timer is running at 625Hz (1.6ms). So with divider 2 it gives - * 3.2ms pause between frames which is good for both S.Bus data rates. + * S.Bus frames come at 7ms (HS) or 14ms (FS) rate at 100000bps. + * RTC timer is running at 625Hz (1.6ms). So with divider 2 it gives + * 3.2ms pause between frames which is good for both S.Bus frame rates. * * Data receive function must clear the receive_timer to confirm new * data reception. If no new data received in 100ms, we must call the * failsafe function which clears all channels. */ -static void PIOS_SBUS_Supervisor(uint32_t sbus_id) +static void PIOS_SBus_Supervisor(uint32_t sbus_id) { + struct pios_sbus_dev *sbus_dev = (struct pios_sbus_dev *)sbus_id; + + bool valid = PIOS_SBus_Validate(sbus_dev); + PIOS_Assert(valid); + + struct pios_sbus_state *state = &(sbus_dev->state); + /* waiting for new frame if no bytes were received in 3.2ms */ - if (++receive_timer > 2) { - receive_timer = 0; - frame_found = 0; + if (++state->receive_timer > 2) { + state->frame_found = 1; + state->byte_count = 0; + state->receive_timer = 0; } /* activate failsafe if no frames have arrived in 102.4ms */ - if (++failsafe_timer > 64) { - reset_channels(); - failsafe_timer = 0; + if (++state->failsafe_timer > 64) { + PIOS_SBus_ResetChannels(state); + state->failsafe_timer = 0; } } -#endif +#endif /* PIOS_INCLUDE_SBUS */ /** * @} diff --git a/flight/PiOS/STM32F10x/pios_spektrum.c b/flight/PiOS/STM32F10x/pios_spektrum.c deleted file mode 100644 index 7ab8abcf3..000000000 --- a/flight/PiOS/STM32F10x/pios_spektrum.c +++ /dev/null @@ -1,350 +0,0 @@ -/** - ****************************************************************************** - * @addtogroup PIOS PIOS Core hardware abstraction layer - * @{ - * @addtogroup PIOS_SPEKTRUM Spektrum receiver functions - * @brief Code to read Spektrum input - * @{ - * - * @file pios_spektrum.c - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @brief USART commands. Inits USARTs, controls USARTs & Interrupt handlers. (STM32 dependent) - * @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 - */ - -/* Project Includes */ -#include "pios.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 - * is never called if regularly getting bytes. - * RTC timer is running @625Hz, supervisor timer has divider 5 so frame sync comes every 1/125Hz=8ms. - * Good for both 11ms and 22ms framecycles - */ - -/* Global Variables */ - -/* Provide a RCVR driver */ -static int32_t PIOS_SPEKTRUM_Get(uint32_t rcvr_id, uint8_t channel); - -const struct pios_rcvr_driver pios_spektrum_rcvr_driver = { - .read = PIOS_SPEKTRUM_Get, -}; - -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) -static struct pios_spektrum_dev * PIOS_SPEKTRUM_alloc(void) -{ - struct pios_spektrum_dev * spektrum_dev; - - spektrum_dev = (struct pios_spektrum_dev *)pvPortMalloc(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, uint8_t bind); -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_UpdateFSM(&(spektrum_dev->fsm), buf[i]); - spektrum_dev->supv_timer = 0; - } - - /* Always signal that we can accept another byte */ - if (headroom) { - *headroom = 1; - } - - /* We never need a yield */ - *need_yield = false; - - /* Always indicate that all bytes were consumed */ - 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, 0xb2 */ - /* 0xb2 DX8 3bind pulses only */ - if (fsm->bytecount == 2) { - if ((b == 0x01) || (b == 0x02) || (b == 0xb2)) { - 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, uint8_t bind) -{ - 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,bind); - } - - PIOS_SPEKTRUM_ResetFSM(&(spektrum_dev->fsm)); - - *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); -} - -/** -* Get the value of an input channel -* \param[in] Channel Number of the channel desired -* \output -1 Channel not available -* \output >0 Channel value -*/ -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; - - if(!PIOS_SPEKTRUM_validate(spektrum_dev)) - return PIOS_RCVR_INVALID; - - /* Return error if channel not available */ - if (channel >= PIOS_SPEKTRUM_NUM_INPUTS) { - return PIOS_RCVR_INVALID; - } - return spektrum_dev->fsm.CaptureValue[channel]; -} - -/** -* Spektrum bind function -* \output true Successful bind -* \output false Bind failed -*/ -static bool PIOS_SPEKTRUM_Bind(const struct pios_spektrum_cfg * cfg, uint8_t bind) -{ - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Pin = cfg->bind.init.GPIO_Pin; - GPIO_InitStructure.GPIO_Speed = cfg->bind.init.GPIO_Speed; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; - - /* just to limit bind pulses */ - bind=(bind<=10)?bind:10; - - GPIO_Init(cfg->bind.gpio, &cfg->bind.init); - /* RX line, set high */ - GPIO_SetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); - - /* on CC works upto 140ms, I guess bind window is around 20-140ms after powerup */ - PIOS_DELAY_WaitmS(60); - - for (int i = 0; i < bind ; i++) { - /* RX line, drive low for 120us */ - GPIO_ResetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); - PIOS_DELAY_WaituS(120); - /* RX line, drive high for 120us */ - GPIO_SetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); - PIOS_DELAY_WaituS(120); - } - /* RX line, set input and wait for data, PIOS_SPEKTRUM_Init */ - GPIO_Init(cfg->bind.gpio, &GPIO_InitStructure); - - return true; -} - -/** - *@brief This function is called between frames and when a spektrum word hasnt been decoded for too long - *@brief clears the channel values - */ -static void PIOS_SPEKTRUM_Supervisor(uint32_t spektrum_id) -{ - struct pios_spektrum_dev * spektrum_dev = (struct pios_spektrum_dev *)spektrum_id; - - bool valid = PIOS_SPEKTRUM_validate(spektrum_dev); - PIOS_Assert(valid); - - /* 625hz */ - spektrum_dev->supv_timer++; - if(spektrum_dev->supv_timer > 4) { - /* sync between frames */ - 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 200ms silence */ - if (fsm->sync_of > 30) { - - /* signal lost */ - fsm->sync_of = 0; - for (int i = 0; i < PIOS_SPEKTRUM_NUM_INPUTS; i++) { - fsm->CaptureValue[i] = PIOS_RCVR_TIMEOUT; - fsm->CaptureValueTemp[i] = PIOS_RCVR_TIMEOUT; - } - } - spektrum_dev->supv_timer = 0; - } -} - -#endif - -/** - * @} - * @} - */ diff --git a/flight/PiOS/inc/pios_spektrum.h b/flight/PiOS/inc/pios_dsm.h similarity index 78% rename from flight/PiOS/inc/pios_spektrum.h rename to flight/PiOS/inc/pios_dsm.h index 765d2c8a5..4bd9ed481 100644 --- a/flight/PiOS/inc/pios_spektrum.h +++ b/flight/PiOS/inc/pios_dsm.h @@ -2,13 +2,12 @@ ****************************************************************************** * @addtogroup PIOS PIOS Core hardware abstraction layer * @{ - * @addtogroup PIOS_SPEKTRUM Spektrum receiver functions + * @addtogroup PIOS_DSM Spektrum/JR DSMx satellite receiver functions * @{ * - * @file pios_spektrum.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Thorsten Klose (tk@midibox.org) - * @brief Spektrum satellite functions header. + * @file pios_dsm.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. + * @brief Spektrum/JR DSMx satellite receiver functions header. * @see The GNU Public License (GPL) Version 3 * *****************************************************************************/ @@ -28,16 +27,16 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef PIOS_SPEKTRUM_H -#define PIOS_SPEKTRUM_H +#ifndef PIOS_DSM_H +#define PIOS_DSM_H /* Global Types */ /* Public Functions */ -#endif /* PIOS_SPEKTRUM_H */ +#endif /* PIOS_DSM_H */ /** - * @} - * @} - */ + * @} + * @} + */ diff --git a/flight/PiOS/inc/pios_dsm_priv.h b/flight/PiOS/inc/pios_dsm_priv.h new file mode 100644 index 000000000..0d1a3803d --- /dev/null +++ b/flight/PiOS/inc/pios_dsm_priv.h @@ -0,0 +1,139 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_DSM Spektrum/JR DSMx satellite receiver functions + * @brief PIOS interface to bind and read Spektrum/JR DSMx satellite receiver + * @{ + * + * @file pios_dsm_priv.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. + * @brief Spektrum/JR DSMx satellite receiver private structures. + * @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 + */ + +#ifndef PIOS_DSM_PRIV_H +#define PIOS_DSM_PRIV_H + +#include +#include +#include + +/* + * Currently known DSMx (DSM2, DSMJ, DSMX) satellite serial port settings: + * 115200bps serial stream, 8 bits, no parity, 1 stop bit + * size of each frame: 16 bytes + * data resolution: 10 or 11 bits + * number of frames: 1 or 2 + * frame period: 11ms or 22ms + * + * Currently known DSMx frame structure: + * 2 bytes - depend on protocol version: + * for DSM2/DSMJ: + * 1 byte - lost frame counter (8 bit) + * 1 byte - data format (for master receiver bound with 3 or 5 pulses), + * or unknown (for slave receiver bound with 4 or 6 pulses, + * some sources call it also the lost frame counter) + * for DSMX: + * 1 byte - unknown data (does not look like lost frame counter) + * 1 byte - unknown data, has been seen only 0xB2 so far + + * 14 bytes - up to 7 channels (16 bit word per channel) with encoded channel + * number, channel value, the "2nd frame in a sequence" flag. + * Unused channels have FF FF instead of data bytes. + * + * Data format identification: + * - for DSM2/DSMJ: [0 0 0 R 0 0 N1 N0] + * where + * R is data resolution (0 - 10 bits, 1 - 11 bits), + * N1..N0 is the number of frames required to receive all channel + * data (01 or 10 are known to the moment, which means 1 or 2 frames). + * Three values for the transmitter information byte have been seen + * thus far: 0x01, 0x02, 0x12. + * - for DSMX this byte contains just 0xB2 or 0xA2 value for any resolution. + * It is not known at the moment how to find the exact resolution from the + * DSMX data stream. The frame number (1 or 2) and 10/11 bit resolution were + * found in different data streams. So it is safer at the moment to ask user + * explicitly choose the resolution. + * Also some weird throttle channel (0) behavior was found in some streams + * from DX8 transmitter (all zeroes). Thus DSMX needs special processing. + * + * Channel data are: + * - for 10 bit: [F 0 C3 C2 C1 C0 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0] + * - for 11 bit: [F C3 C2 C1 C0 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0] + * where + * F is normally 0 but set to 1 for the first channel of the 2nd frame, + * C3 to C0 is the channel number, 4 bit, zero-based, in any order, + * Dx..D0 - channel data (10 or 11 bits) + * + * DSM2 protocol bug: in some cases in 2-frame format some bytes of the + * frame can contain invalid values from the previous frame. They usually + * are the last 5 bytes and can be equal to FF or other data from last + * frame. There is no explicit workaround currently known. + * + * Binding: the number of pulses within bind window after power up defines + * if this receiver is a master (provides receiver capabilities info to + * the transmitter to choose data format) or slave (does not respond to + * the transmitter which falls back to the old DSM mode in that case). + * Currently known are 3(4) pulses for low resolution (10 bit) mode, and + * 5(6) pulses for high resolution (11 bit) mode. Thus only 3 or 5 pulses + * should be used for stand-alone satellite receiver to be bound correctly + * as the master. 5 pulses (high resolution) mode simulates high-end + * receivers which should work in all cases except user explicitly wants + * to bind in low resolution mode. + */ + +#define DSM_CHANNELS_PER_FRAME 7 +#define DSM_FRAME_LENGTH (1+1+DSM_CHANNELS_PER_FRAME*2) +#define DSM_DSM2_RES_MASK 0x0010 +#define DSM_2ND_FRAME_MASK 0x8000 + +/* + * Include lost frame counter and provide it as a last channel value + * for debugging. Currently is not used by the receiver layer. + */ +//#define DSM_LOST_FRAME_COUNTER + +/* DSM protocol variations */ +enum pios_dsm_proto { + PIOS_DSM_PROTO_DSM2, + PIOS_DSM_PROTO_DSMX10BIT, + PIOS_DSM_PROTO_DSMX11BIT, +}; + +/* DSM receiver instance configuration */ +struct pios_dsm_cfg { + struct stm32_gpio bind; +}; + +extern const struct pios_rcvr_driver pios_dsm_rcvr_driver; + +extern int32_t PIOS_DSM_Init(uint32_t *dsm_id, + const struct pios_dsm_cfg *cfg, + const struct pios_com_driver *driver, + uint32_t lower_id, + enum pios_dsm_proto proto, + uint8_t bind); + +#endif /* PIOS_DSM_PRIV_H */ + +/** + * @} + * @} + */ diff --git a/flight/PiOS/inc/pios_sbus.h b/flight/PiOS/inc/pios_sbus.h index 868fedd70..fd8580f2e 100644 --- a/flight/PiOS/inc/pios_sbus.h +++ b/flight/PiOS/inc/pios_sbus.h @@ -2,7 +2,7 @@ ****************************************************************************** * @addtogroup PIOS PIOS Core hardware abstraction layer * @{ - * @addtogroup PIOS_SBUS Futaba S.Bus receiver functions + * @addtogroup PIOS_SBus Futaba S.Bus receiver functions * @{ * * @file pios_sbus.h diff --git a/flight/PiOS/inc/pios_sbus_priv.h b/flight/PiOS/inc/pios_sbus_priv.h index b7e441c30..127db9a46 100644 --- a/flight/PiOS/inc/pios_sbus_priv.h +++ b/flight/PiOS/inc/pios_sbus_priv.h @@ -2,7 +2,7 @@ ****************************************************************************** * @addtogroup PIOS PIOS Core hardware abstraction layer * @{ - * @addtogroup PIOS_SBUS S.Bus Functions + * @addtogroup PIOS_SBus S.Bus Functions * @brief PIOS interface to read and write from Futaba S.Bus port * @{ * @@ -63,7 +63,9 @@ * S.Bus protocol provides 16 proportional and 2 discrete channels. * Do not change unless driver code is updated accordingly. */ -#define SBUS_NUMBER_OF_CHANNELS (16 + 2) +#if (PIOS_SBUS_NUM_INPUTS != (16+2)) +#error "S.Bus protocol provides 16 proportional and 2 discrete channels" +#endif /* Discrete channels represented as bits, provide values for them */ #define SBUS_VALUE_MIN 352 @@ -81,7 +83,10 @@ struct pios_sbus_cfg { extern const struct pios_rcvr_driver pios_sbus_rcvr_driver; -extern int32_t PIOS_SBUS_Init(uint32_t * sbus_id, const struct pios_sbus_cfg *cfg, const struct pios_com_driver * driver, uint32_t lower_id); +extern int32_t PIOS_SBus_Init(uint32_t *sbus_id, + const struct pios_sbus_cfg *cfg, + const struct pios_com_driver *driver, + uint32_t lower_id); #endif /* PIOS_SBUS_PRIV_H */ diff --git a/flight/PiOS/inc/pios_spektrum_priv.h b/flight/PiOS/inc/pios_spektrum_priv.h deleted file mode 100644 index 17b330cae..000000000 --- a/flight/PiOS/inc/pios_spektrum_priv.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - ****************************************************************************** - * @addtogroup PIOS PIOS Core hardware abstraction layer - * @{ - * @addtogroup PIOS_SPEKTRUM SPEKTRUM Functions - * @brief PIOS interface to read and write from spektrum port - * @{ - * - * @file pios_spektrum_priv.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @brief Servo private structures. - * @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 - */ - -#ifndef PIOS_SPEKTRUM_PRIV_H -#define PIOS_SPEKTRUM_PRIV_H - -#include -#include -#include - -struct pios_spektrum_cfg { - struct stm32_gpio bind; - uint32_t remap; /* GPIO_Remap_* */ -}; - -extern const struct pios_rcvr_driver pios_spektrum_rcvr_driver; - -extern 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, uint8_t bind); - -#endif /* PIOS_SPEKTRUM_PRIV_H */ - -/** - * @} - * @} - */ diff --git a/flight/PiOS/pios.h b/flight/PiOS/pios.h index 4be0bfafc..58d869517 100644 --- a/flight/PiOS/pios.h +++ b/flight/PiOS/pios.h @@ -81,7 +81,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj index b860e748c..d807e49ad 100644 --- a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj +++ b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj @@ -96,11 +96,9 @@ 65643CAD1413322000A32F59 /* pios_rtc_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_rtc_priv.h; sourceTree = ""; }; 65643CAE1413322000A32F59 /* pios_sbus_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_sbus_priv.h; sourceTree = ""; }; 65643CAF1413322000A32F59 /* pios_sbus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_sbus.h; sourceTree = ""; }; - 65643CB01413322000A32F59 /* pios_spektrum_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_spektrum_priv.h; sourceTree = ""; }; + 65643CB01413322000A32F59 /* pios_dsm_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_dsm_priv.h; sourceTree = ""; }; 65643CB91413456D00A32F59 /* pios_tim.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pios_tim.c; sourceTree = ""; }; 65643CBA141350C200A32F59 /* pios_sbus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pios_sbus.c; sourceTree = ""; }; - 65643CEC141429A100A32F59 /* NMEA.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = NMEA.c; sourceTree = ""; }; - 65643CEE141429AF00A32F59 /* NMEA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NMEA.h; sourceTree = ""; }; 6572CB1613D0F2B200FC2972 /* link_STM32103CB_CC_Rev1_memory.ld */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = link_STM32103CB_CC_Rev1_memory.ld; path = ../../PiOS/STM32F10x/link_STM32103CB_CC_Rev1_memory.ld; sourceTree = SOURCE_ROOT; }; 6572CB1713D0F2B200FC2972 /* link_STM32103CB_CC_Rev1_sections.ld */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = link_STM32103CB_CC_Rev1_sections.ld; path = ../../PiOS/STM32F10x/link_STM32103CB_CC_Rev1_sections.ld; sourceTree = SOURCE_ROOT; }; 657CEEAD121DB6C8007A1FBE /* homelocation.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = homelocation.xml; sourceTree = ""; }; @@ -2658,7 +2656,6 @@ 65C35E5612EFB2F3004811C2 /* attitudeactual.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = attitudeactual.xml; sourceTree = ""; }; 65C35E5812EFB2F3004811C2 /* attituderaw.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = attituderaw.xml; sourceTree = ""; }; 65C35E5912EFB2F3004811C2 /* baroaltitude.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = baroaltitude.xml; sourceTree = ""; }; - 65C35E5A12EFB2F3004811C2 /* batterysettings.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = batterysettings.xml; sourceTree = ""; }; 65C35E5C12EFB2F3004811C2 /* flightbatterystate.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = flightbatterystate.xml; sourceTree = ""; }; 65C35E5D12EFB2F3004811C2 /* flightplancontrol.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = flightplancontrol.xml; sourceTree = ""; }; 65C35E5E12EFB2F3004811C2 /* flightplansettings.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = flightplansettings.xml; sourceTree = ""; }; @@ -2799,7 +2796,7 @@ 65E8F04911EFF25C00BBF654 /* pios_pwm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pios_pwm.h; path = ../../PiOS/inc/pios_pwm.h; sourceTree = SOURCE_ROOT; }; 65E8F04A11EFF25C00BBF654 /* pios_sdcard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pios_sdcard.h; path = ../../PiOS/inc/pios_sdcard.h; sourceTree = SOURCE_ROOT; }; 65E8F04B11EFF25C00BBF654 /* pios_servo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pios_servo.h; path = ../../PiOS/inc/pios_servo.h; sourceTree = SOURCE_ROOT; }; - 65E8F04C11EFF25C00BBF654 /* pios_spektrum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pios_spektrum.h; path = ../../PiOS/inc/pios_spektrum.h; sourceTree = SOURCE_ROOT; }; + 65E8F04C11EFF25C00BBF654 /* pios_dsm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pios_dsm.h; path = ../../PiOS/inc/pios_dsm.h; sourceTree = SOURCE_ROOT; }; 65E8F04D11EFF25C00BBF654 /* pios_spi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pios_spi.h; path = ../../PiOS/inc/pios_spi.h; sourceTree = SOURCE_ROOT; }; 65E8F04E11EFF25C00BBF654 /* pios_spi_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pios_spi_priv.h; path = ../../PiOS/inc/pios_spi_priv.h; sourceTree = SOURCE_ROOT; }; 65E8F04F11EFF25C00BBF654 /* pios_stm32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pios_stm32.h; path = ../../PiOS/inc/pios_stm32.h; sourceTree = SOURCE_ROOT; }; @@ -2928,7 +2925,7 @@ 65E8F0E411EFF25C00BBF654 /* pios_ppm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pios_ppm.c; path = ../../PiOS/STM32F10x/pios_ppm.c; sourceTree = SOURCE_ROOT; }; 65E8F0E511EFF25C00BBF654 /* pios_pwm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pios_pwm.c; path = ../../PiOS/STM32F10x/pios_pwm.c; sourceTree = SOURCE_ROOT; }; 65E8F0E611EFF25C00BBF654 /* pios_servo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pios_servo.c; path = ../../PiOS/STM32F10x/pios_servo.c; sourceTree = SOURCE_ROOT; }; - 65E8F0E711EFF25C00BBF654 /* pios_spektrum.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pios_spektrum.c; path = ../../PiOS/STM32F10x/pios_spektrum.c; sourceTree = SOURCE_ROOT; }; + 65E8F0E711EFF25C00BBF654 /* pios_dsm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pios_dsm.c; path = ../../PiOS/STM32F10x/pios_dsm.c; sourceTree = SOURCE_ROOT; }; 65E8F0E811EFF25C00BBF654 /* pios_spi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pios_spi.c; path = ../../PiOS/STM32F10x/pios_spi.c; sourceTree = SOURCE_ROOT; }; 65E8F0E911EFF25C00BBF654 /* pios_sys.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pios_sys.c; path = ../../PiOS/STM32F10x/pios_sys.c; sourceTree = SOURCE_ROOT; }; 65E8F0EA11EFF25C00BBF654 /* pios_usart.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pios_usart.c; path = ../../PiOS/STM32F10x/pios_usart.c; sourceTree = SOURCE_ROOT; }; @@ -7436,7 +7433,6 @@ 65C35E4F12EFB2F3004811C2 /* uavobjectdefinition */ = { isa = PBXGroup; children = ( - 65E6D80713E3A4D0002A557A /* hwsettings.xml */, 65E8C788139AA2A800E1F979 /* accessorydesired.xml */, 65C35E5012EFB2F3004811C2 /* actuatorcommand.xml */, 65C35E5112EFB2F3004811C2 /* actuatordesired.xml */, @@ -7448,7 +7444,6 @@ 65C35E5812EFB2F3004811C2 /* attituderaw.xml */, 65E410AE12F65AEA00725888 /* attitudesettings.xml */, 65C35E5912EFB2F3004811C2 /* baroaltitude.xml */, - 65C35E5A12EFB2F3004811C2 /* batterysettings.xml */, 655B1A8E13B2FC0900B0E48D /* camerastabsettings.xml */, 652C8568132B632A00BFCC70 /* firmwareiapobj.xml */, 65C35E5C12EFB2F3004811C2 /* flightbatterystate.xml */, @@ -7463,6 +7458,7 @@ 65C35E6412EFB2F3004811C2 /* gpstime.xml */, 65C35E6512EFB2F3004811C2 /* guidancesettings.xml */, 65C35E6612EFB2F3004811C2 /* homelocation.xml */, + 65E6D80713E3A4D0002A557A /* hwsettings.xml */, 65C35E6712EFB2F3004811C2 /* i2cstats.xml */, 65C35E6812EFB2F3004811C2 /* manualcontrolcommand.xml */, 65C35E6912EFB2F3004811C2 /* manualcontrolsettings.xml */, @@ -7743,8 +7739,8 @@ 65E8F04A11EFF25C00BBF654 /* pios_sdcard.h */, 65E8F04B11EFF25C00BBF654 /* pios_servo.h */, 65FBE14412E7C98100176B5A /* pios_servo_priv.h */, - 65E8F04C11EFF25C00BBF654 /* pios_spektrum.h */, - 65643CB01413322000A32F59 /* pios_spektrum_priv.h */, + 65E8F04C11EFF25C00BBF654 /* pios_dsm.h */, + 65643CB01413322000A32F59 /* pios_dsm_priv.h */, 65E8F04D11EFF25C00BBF654 /* pios_spi.h */, 65E8F04E11EFF25C00BBF654 /* pios_spi_priv.h */, 65E8F04F11EFF25C00BBF654 /* pios_stm32.h */, @@ -7768,24 +7764,8 @@ 65E8F05811EFF25C00BBF654 /* STM32F10x */ = { isa = PBXGroup; children = ( - 65D1FBD813F51865006374A6 /* pios_bmp085.c */, - 6560A39D13EE277E00105DA5 /* pios_iap.c */, - 6560A39E13EE277E00105DA5 /* pios_sbus.c */, - 6560A38E13EE270C00105DA5 /* link_STM3210E_INS_BL_sections.ld */, - 6560A38F13EE270C00105DA5 /* link_STM3210E_INS_memory.ld */, - 6560A39013EE270C00105DA5 /* link_STM3210E_INS_sections.ld */, - 6560A39113EE270C00105DA5 /* link_STM3210E_OP_BL_sections.ld */, - 6560A39213EE270C00105DA5 /* link_STM3210E_OP_memory.ld */, - 6560A39313EE270C00105DA5 /* link_STM3210E_OP_sections.ld */, - 6560A39413EE270C00105DA5 /* link_STM32103CB_AHRS_BL_sections.ld */, - 6560A39513EE270C00105DA5 /* link_STM32103CB_AHRS_memory.ld */, - 6560A39613EE270C00105DA5 /* link_STM32103CB_AHRS_sections.ld */, - 6560A39713EE270C00105DA5 /* link_STM32103CB_CC_Rev1_BL_sections.ld */, 6572CB1613D0F2B200FC2972 /* link_STM32103CB_CC_Rev1_memory.ld */, 6572CB1713D0F2B200FC2972 /* link_STM32103CB_CC_Rev1_sections.ld */, - 6560A39813EE270C00105DA5 /* link_STM32103CB_PIPXTREME_BL_sections.ld */, - 6560A39913EE270C00105DA5 /* link_STM32103CB_PIPXTREME_memory.ld */, - 6560A39A13EE270C00105DA5 /* link_STM32103CB_PIPXTREME_sections.ld */, 65E8F05911EFF25C00BBF654 /* Libraries */, 65E8F0D811EFF25C00BBF654 /* link_stm32f10x_HD.ld */, 65E8F0DB11EFF25C00BBF654 /* link_stm32f10x_MD.ld */, @@ -7802,7 +7782,7 @@ 6589A9DB131DEE76006BD67C /* pios_rtc.c */, 65643CBA141350C200A32F59 /* pios_sbus.c */, 65E8F0E611EFF25C00BBF654 /* pios_servo.c */, - 65E8F0E711EFF25C00BBF654 /* pios_spektrum.c */, + 65E8F0E711EFF25C00BBF654 /* pios_dsm.c */, 65E8F0E811EFF25C00BBF654 /* pios_spi.c */, 65E8F0E911EFF25C00BBF654 /* pios_sys.c */, 65643CB91413456D00A32F59 /* pios_tim.c */, diff --git a/flight/UAVTalk/inc/uavtalk_priv.h b/flight/UAVTalk/inc/uavtalk_priv.h index 06f08b997..77863a6a8 100644 --- a/flight/UAVTalk/inc/uavtalk_priv.h +++ b/flight/UAVTalk/inc/uavtalk_priv.h @@ -64,6 +64,7 @@ typedef struct { uint32_t objId; uint16_t instId; uint32_t length; + uint8_t instanceLength; uint8_t cs; int32_t rxCount; UAVTalkRxState state; diff --git a/flight/UAVTalk/uavtalk.c b/flight/UAVTalk/uavtalk.c index 236915b28..900dc24b3 100644 --- a/flight/UAVTalk/uavtalk.c +++ b/flight/UAVTalk/uavtalk.c @@ -351,9 +351,15 @@ int32_t UAVTalkProcessInputStream(UAVTalkConnection connectionHandle, uint8_t rx // Determine data length if (iproc->type == UAVTALK_TYPE_OBJ_REQ || iproc->type == UAVTALK_TYPE_ACK || iproc->type == UAVTALK_TYPE_NACK) + { iproc->length = 0; + iproc->instanceLength = 0; + } else + { iproc->length = UAVObjGetNumBytes(iproc->obj); + iproc->instanceLength = (UAVObjIsSingleInstance(iproc->obj) ? 0 : 2); + } // Check length and determine next state if (iproc->length >= UAVTALK_MAX_PAYLOAD_LENGTH) @@ -364,7 +370,7 @@ int32_t UAVTalkProcessInputStream(UAVTalkConnection connectionHandle, uint8_t rx } // Check the lengths match - if ((iproc->rxPacketLength + iproc->length) != iproc->packet_size) + if ((iproc->rxPacketLength + iproc->instanceLength + iproc->length) != iproc->packet_size) { // packet error - mismatched packet size connection->stats.rxErrors++; iproc->state = UAVTALK_STATE_SYNC; diff --git a/ground/openpilotgcs/src/plugins/config/camerastabilization.ui b/ground/openpilotgcs/src/plugins/config/camerastabilization.ui index 28e7740c1..76ff38fcb 100644 --- a/ground/openpilotgcs/src/plugins/config/camerastabilization.ui +++ b/ground/openpilotgcs/src/plugins/config/camerastabilization.ui @@ -138,46 +138,6 @@ None - - - Channel 1 - - - - - Channel 2 - - - - - Channel 3 - - - - - Channel 4 - - - - - Channel 5 - - - - - Channel 6 - - - - - Channel 7 - - - - - Channel 8 - - @@ -187,46 +147,6 @@ None - - - Channel 1 - - - - - Channel 2 - - - - - Channel 3 - - - - - Channel 4 - - - - - Channel 5 - - - - - Channel 6 - - - - - Channel 7 - - - - - Channel 8 - - @@ -243,46 +163,6 @@ None - - - Channel 1 - - - - - Channel 2 - - - - - Channel 3 - - - - - Channel 4 - - - - - Channel 5 - - - - - Channel 6 - - - - - Channel 7 - - - - - Channel 8 - - @@ -323,6 +203,13 @@ + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/config/config_cc_hw_widget.cpp b/ground/openpilotgcs/src/plugins/config/config_cc_hw_widget.cpp index 10476db26..1d0f723d0 100644 --- a/ground/openpilotgcs/src/plugins/config/config_cc_hw_widget.cpp +++ b/ground/openpilotgcs/src/plugins/config/config_cc_hw_widget.cpp @@ -25,6 +25,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config_cc_hw_widget.h" +#include "hwsettings.h" #include #include @@ -63,10 +64,13 @@ void ConfigCCHWWidget::refreshValues() void ConfigCCHWWidget::widgetsContentsChanged() { ConfigTaskWidget::widgetsContentsChanged(); - enableControls(false); - if((m_telemetry->cbFlexi->currentText()==m_telemetry->cbTele->currentText()) && m_telemetry->cbTele->currentText()!="Disabled") + + if (((m_telemetry->cbTele->currentIndex() == HwSettings::CC_MAINPORT_TELEMETRY) && (m_telemetry->cbFlexi->currentIndex() == HwSettings::CC_FLEXIPORT_TELEMETRY)) || + ((m_telemetry->cbTele->currentIndex() == HwSettings::CC_MAINPORT_GPS) && (m_telemetry->cbFlexi->currentIndex() == HwSettings::CC_FLEXIPORT_GPS)) || + ((m_telemetry->cbTele->currentIndex() == HwSettings::CC_MAINPORT_COMAUX) && (m_telemetry->cbFlexi->currentIndex() == HwSettings::CC_FLEXIPORT_COMAUX))) { - m_telemetry->problems->setText("Warning: you have configured the MainPort and the FlexiPort for the same function, this is currently not suported"); + enableControls(false); + m_telemetry->problems->setText(tr("Warning: you have configured both MainPort and FlexiPort for the same function, this currently is not supported")); } else { @@ -84,4 +88,3 @@ void ConfigCCHWWidget::openHelp() * @} * @} */ - diff --git a/ground/openpilotgcs/src/plugins/config/configairframewidget.cpp b/ground/openpilotgcs/src/plugins/config/configairframewidget.cpp index 96393b381..9f118532e 100644 --- a/ground/openpilotgcs/src/plugins/config/configairframewidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configairframewidget.cpp @@ -105,10 +105,13 @@ ConfigAirframeWidget::ConfigAirframeWidget(QWidget *parent) : ConfigTaskWidget(p ffTuningInProgress = false; ffTuningPhase = false; - mixerTypes << "Mixer1Type" << "Mixer2Type" << "Mixer3Type" - << "Mixer4Type" << "Mixer5Type" << "Mixer6Type" << "Mixer7Type" << "Mixer8Type"; - mixerVectors << "Mixer1Vector" << "Mixer2Vector" << "Mixer3Vector" - << "Mixer4Vector" << "Mixer5Vector" << "Mixer6Vector" << "Mixer7Vector" << "Mixer8Vector"; + QStringList channels; + channels << "None"; + for (int i = 0; i < ActuatorSettings::CHANNELADDR_NUMELEM; i++) { + mixerTypes << QString("Mixer%1Type").arg(i+1); + mixerVectors << QString("Mixer%1Vector").arg(i+1); + channels << QString("Channel%1").arg(i+1); + } QStringList airframeTypes; airframeTypes << "Fixed Wing" << "Multirotor" << "Helicopter" << "Custom"; @@ -124,11 +127,6 @@ ConfigAirframeWidget::ConfigAirframeWidget(QWidget *parent) : ConfigTaskWidget(p << "Octo Coax X" << "Hexacopter Y6" << "Tricopter Y"; m_aircraft->multirotorFrameType->addItems(multiRotorTypes); - - - QStringList channels; - channels << "None" << "Channel1" << "Channel2" << "Channel3" << - "Channel4" << "Channel5" << "Channel6" << "Channel7" << "Channel8"; // Now load all the channel assignements for fixed wing m_aircraft->fwElevator1Channel->addItems(channels); m_aircraft->fwElevator2Channel->addItems(channels); diff --git a/ground/openpilotgcs/src/plugins/config/configcamerastabilizationwidget.cpp b/ground/openpilotgcs/src/plugins/config/configcamerastabilizationwidget.cpp index efb0d2164..a1e6c1afb 100644 --- a/ground/openpilotgcs/src/plugins/config/configcamerastabilizationwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configcamerastabilizationwidget.cpp @@ -41,12 +41,26 @@ #include "camerastabsettings.h" #include "hwsettings.h" #include "mixersettings.h" +#include "actuatorcommand.h" ConfigCameraStabilizationWidget::ConfigCameraStabilizationWidget(QWidget *parent) : ConfigTaskWidget(parent) { m_camerastabilization = new Ui_CameraStabilizationWidget(); m_camerastabilization->setupUi(this); + QComboBox * selectors[3] = { + m_camerastabilization->rollChannel, + m_camerastabilization->pitchChannel, + m_camerastabilization->yawChannel + }; + + for (int i = 0; i < 3; i++) { + selectors[i]->clear(); + selectors[i]->addItem("None"); + for (int j = 0; j < ActuatorCommand::CHANNEL_NUMELEM; j++) + selectors[i]->addItem(QString("Channel %1").arg(j+1)); + } + connectUpdates(); // Connect buttons @@ -95,7 +109,7 @@ void ConfigCameraStabilizationWidget::applySettings() // Update the mixer settings MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager()); MixerSettings::DataFields mixerSettingsData = mixerSettings->getData(); - const int NUM_MIXERS = 8; + const int NUM_MIXERS = 10; QComboBox * selectors[3] = { m_camerastabilization->rollChannel, @@ -114,8 +128,11 @@ void ConfigCameraStabilizationWidget::applySettings() &mixerSettingsData.Mixer6Type, &mixerSettingsData.Mixer7Type, &mixerSettingsData.Mixer8Type, + &mixerSettingsData.Mixer9Type, + &mixerSettingsData.Mixer10Type, }; + m_camerastabilization->message->setText(""); for (int i = 0; i < 3; i++) { // Channel 1 is second entry, so becomes zero @@ -127,6 +144,7 @@ void ConfigCameraStabilizationWidget::applySettings() // If the mixer channel already to something that isn't what we are // about to set it to reset to none selectors[i]->setCurrentIndex(0); + m_camerastabilization->message->setText("One of the channels is already assigned, reverted to none"); } else { // Make sure no other channels have this output set for (int j = 0; j < NUM_MIXERS; j++) @@ -188,7 +206,7 @@ void ConfigCameraStabilizationWidget::refreshValues() MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager()); MixerSettings::DataFields mixerSettingsData = mixerSettings->getData(); - const int NUM_MIXERS = 8; + const int NUM_MIXERS = 10; QComboBox * selectors[3] = { m_camerastabilization->rollChannel, m_camerastabilization->pitchChannel, @@ -206,6 +224,8 @@ void ConfigCameraStabilizationWidget::refreshValues() &mixerSettingsData.Mixer6Type, &mixerSettingsData.Mixer7Type, &mixerSettingsData.Mixer8Type, + &mixerSettingsData.Mixer9Type, + &mixerSettingsData.Mixer10Type, }; for (int i = 0; i < 3; i++) diff --git a/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp b/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp index 9e7cfdd04..407377d3c 100644 --- a/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp @@ -464,7 +464,7 @@ void ConfigInputWidget::wizardSetUpStep(enum wizardSteps step) case wizardIdentifyLimits: { dimOtherControls(false); - setTxMovement(moveAll); + setTxMovement(nothing); m_config->wzText->setText(QString(tr("Please move all controls to their maximum extents on both directions and press next when ready"))); fastMdata(); manualSettingsData=manualSettingsObj->getData(); @@ -474,6 +474,7 @@ void ConfigInputWidget::wizardSetUpStep(enum wizardSteps step) manualSettingsData.ChannelMax[i]=manualSettingsData.ChannelNeutral[i]; } connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits())); + connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks())); } break; case wizardIdentifyInverted: @@ -570,6 +571,7 @@ void ConfigInputWidget::wizardTearDownStep(enum wizardSteps step) break; case wizardIdentifyLimits: disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits())); + disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks())); manualSettingsObj->setData(manualSettingsData); restoreMdata(); break; @@ -618,224 +620,6 @@ void ConfigInputWidget::restoreMdata() manualCommandObj->setMetadata(manualControlMdata); } -//void ConfigInputWidget::setupWizardWidget(int step) -//{ -// if(step==wizardWelcome) -// { -// m_config->graphicsView->setVisible(false); -// setTxMovement(nothing); -// if(wizardStep==wizardChooseMode) -// { -// delete extraWidgets.at(0); -// delete extraWidgets.at(1); -// extraWidgets.clear(); -// } -// manualSettingsData=manualSettingsObj->getData(); -// manualSettingsData.Arming=ManualControlSettings::ARMING_ALWAYSDISARMED; -// manualSettingsObj->setData(manualSettingsData); -// m_config->wzText->setText(tr("Welcome to the inputs configuration wizard.\n" -// "Please follow the instructions on the screen and only move your controls when asked to.\n" -// "Make sure you already configured your hardware settings on the proper tab and restarted your board.\n" -// "At any time you can press 'back' to return to the previous screeen or 'Cancel' to cancel the wizard.\n")); -// m_config->stackedWidget->setCurrentIndex(1); -// m_config->wzBack->setEnabled(false); -// wizardStep=wizardWelcome; -// } -// else if(step==wizardChooseMode) -// { -// m_config->graphicsView->setVisible(true); -// setTxMovement(nothing); -// if(wizardStep==wizardIdentifySticks) -// { -// disconnect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls())); -// m_config->wzNext->setEnabled(true); -// } -// m_config->wzText->setText(tr("Please choose your transmiter type.\n" -// "Mode 1 means your throttle stick is on the right\n" -// "Mode 2 means your throttle stick is on the left\n")); -// m_config->wzBack->setEnabled(true); -// QRadioButton * mode1=new QRadioButton(tr("Mode 1"),this); -// QRadioButton * mode2=new QRadioButton(tr("Mode 2"),this); -// mode2->setChecked(true); -// extraWidgets.clear(); -// extraWidgets.append(mode1); -// extraWidgets.append(mode2); -// m_config->checkBoxesLayout->layout()->addWidget(mode1); -// m_config->checkBoxesLayout->layout()->addWidget(mode2); -// wizardStep=wizardChooseMode; -// } -// else if(step==wizardChooseType) -// { -// if(wizardStep==wizardChooseMode) -// { -// QRadioButton * mode=qobject_cast(extraWidgets.at(0)); -// if(mode->isChecked()) -// transmitterMode=mode1; -// else -// transmitterMode=mode2; -// delete extraWidgets.at(0); -// delete extraWidgets.at(1); -// extraWidgets.clear(); -// } - -// m_config->wzText->setText(tr("Please choose your transmiter mode.\n" -// "Acro means normal transmitter\n" -// "Heli means there is a collective pitch and throttle input\n")); -// m_config->wzBack->setEnabled(true); -// QRadioButton * typeAcro=new QRadioButton(tr("Acro"),this); -// QRadioButton * typeHeli=new QRadioButton(tr("Heli"),this); -// typeAcro->setChecked(true); -// typeHeli->setChecked(false); -// extraWidgets.clear(); -// extraWidgets.append(typeAcro); -// extraWidgets.append(typeHeli); -// m_config->checkBoxesLayout->layout()->addWidget(typeAcro); -// m_config->checkBoxesLayout->layout()->addWidget(typeHeli); -// wizardStep=wizardChooseType; -// } else if(step==wizardIdentifySticks && !isSimple) { -// usedChannels.clear(); -// if(wizardStep==wizardChooseType) -// { -// qDebug() << "Chosing type"; -// QRadioButton * type=qobject_cast(extraWidgets.at(0)); -// if(type->isChecked()) -// transmitterType=acro; -// else -// transmitterType=heli; -// qDebug() << "Checked: " << type->isChecked() << " " << "type is" << transmitterType; -// delete extraWidgets.at(0); -// delete extraWidgets.at(1); -// extraWidgets.clear(); -// } -// wizardStep=wizardIdentifySticks; -// currentCommand=0; -// getChannelFromStep(currentCommand); -// manualSettingsData=manualSettingsObj->getData(); -// connect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls())); -// m_config->wzNext->setEnabled(false); -// } -// else if(step==wizardIdentifyCenter || (isSimple && step==wizardIdentifySticks)) -// { -// setTxMovement(centerAll); -// if(wizardStep==wizardIdentifySticks) -// disconnect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls())); -// else -// { -// disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits())); -// manualSettingsObj->setData(manualSettingsData); -// manualCommandObj->setMetadata(manualCommandObj->getDefaultMetadata()); -// } -// wizardStep=wizardIdentifyCenter; -// m_config->wzText->setText(QString(tr("Please center all control controls and press next when ready (if your FlightMode switch has only two positions, leave it on either position)"))); -// } -// else if(step==wizardIdentifyLimits) -// { -// dimOtherControls(false); -// setTxMovement(moveAll); -// if(wizardStep==wizardIdentifyCenter) -// { -// wizardStep=wizardIdentifyLimits; -// manualCommandData=manualCommandObj->getData(); -// manualSettingsData=manualSettingsObj->getData(); -// for(unsigned int i=0;isetData(manualSettingsData); -// } -// if(wizardStep==wizardIdentifyInverted) -// { -// foreach(QWidget * wd,extraWidgets) -// { -// QCheckBox * cb=qobject_cast(wd); -// if(cb) -// { -// disconnect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls())); -// delete cb; -// } -// } -// } -// extraWidgets.clear(); -// disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks())); -// wizardStep=wizardIdentifyLimits; -// m_config->wzText->setText(QString(tr("Please move all controls to their maximum extents on both directions and press next when ready"))); -// UAVObject::Metadata mdata= manualCommandObj->getMetadata(); -// mdata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_PERIODIC; -// mdata.flightTelemetryUpdatePeriod = 150; -// manualCommandObj->setMetadata(mdata); -// manualSettingsData=manualSettingsObj->getData(); -// for(uint i=0;isetData(manualSettingsData); -// } -// extraWidgets.clear(); -// foreach(QString name,manualSettingsObj->getFields().at(0)->getElementNames()) -// { -// if(!name.contains("Access") && !name.contains("Flight")) -// { -// QCheckBox * cb=new QCheckBox(name,this); -// extraWidgets.append(cb); -// m_config->checkBoxesLayout->layout()->addWidget(cb); -// connect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls())); -// } -// } -// connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks())); -// wizardStep=wizardIdentifyInverted; -// m_config->wzText->setText(QString(tr("Please check the picture below and check all the sticks which show an inverted movement and press next when ready"))); -// } -// else if(step==wizardFinish) -// { -// foreach(QWidget * wd,extraWidgets) -// { -// QCheckBox * cb=qobject_cast(wd); -// if(cb) -// { -// disconnect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls())); -// delete cb; -// } -// } -// wizardStep=wizardFinish; -// extraWidgets.clear(); -// m_config->wzText->setText(QString(tr("You have completed this wizard, please check below if the picture below mimics your sticks movement.\n" -// "This new settings aren't saved to the board yet, after pressing next you will go to the initial screen where you can do that."))); - -// } - -// else if(step==wizardFinish+1) -// { -// setTxMovement(nothing); -// manualCommandObj->setMetadata(manualCommandObj->getDefaultMetadata()); -// disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks())); -// manualSettingsData=manualSettingsObj->getData(); -// manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_THROTTLE]= -// manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE]+ -// ((manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_THROTTLE]- -// manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE])*0.02); -// if((abs(manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_FLIGHTMODE]-manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE])<100) || -// (abs(manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE]-manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE])<100)) -// { -// manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE]=manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE]+ -// (manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_FLIGHTMODE]-manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE])/2; -// } -// manualSettingsObj->setData(manualSettingsData); -// m_config->stackedWidget->setCurrentIndex(0); -// wizardStep=wizardWelcome; -// } - -//} - /** * Set the display to indicate which channel the person should move */ @@ -849,12 +633,16 @@ void ConfigInputWidget::setChannel(int newChan) m_config->wzText->setText(QString(tr("Please move each control once at a time according to the instructions and picture below.\n\n" "Move the %1 stick")).arg(manualSettingsObj->getField("ChannelGroups")->getElementNames().at(newChan))); - if(manualSettingsObj->getField("ChannelGroups")->getElementNames().at(newChan).contains("Accessory")) + if(manualSettingsObj->getField("ChannelGroups")->getElementNames().at(newChan).contains("Accessory")) { m_config->wzNext->setEnabled(true); + m_config->wzText->setText(m_config->wzText->text() + tr(" or click next to skip this channel.")); + } else + m_config->wzNext->setEnabled(false); setMoveFromCommand(newChan); currentChannelNum = newChan; + channelDetected = false; } /** @@ -907,6 +695,8 @@ void ConfigInputWidget::identifyControls() receiverActivityData=receiverActivityObj->getData(); if(receiverActivityData.ActiveChannel==255) return; + if(channelDetected) + return; else { receiverActivityData=receiverActivityObj->getData(); @@ -918,6 +708,7 @@ void ConfigInputWidget::identifyControls() lastChannel.number=currentChannel.number; if(!usedChannels.contains(lastChannel) && debounce>1) { + channelDetected = true; debounce=0; usedChannels.append(lastChannel); manualSettingsData=manualSettingsObj->getData(); @@ -932,7 +723,7 @@ void ConfigInputWidget::identifyControls() m_config->wzText->clear(); setTxMovement(nothing); - QTimer::singleShot(300, this, SLOT(wzNext())); + QTimer::singleShot(500, this, SLOT(wzNext())); } void ConfigInputWidget::identifyLimits() @@ -945,6 +736,7 @@ void ConfigInputWidget::identifyLimits() if(manualSettingsData.ChannelMax[i]setData(manualSettingsData); } void ConfigInputWidget::setMoveFromCommand(int command) { @@ -1368,6 +1160,8 @@ void ConfigInputWidget::updateCalibration() void ConfigInputWidget::simpleCalibration(bool enable) { if (enable) { + m_config->configurationWizard->setEnabled(false); + QMessageBox msgBox; msgBox.setText(tr("Arming Settings are now set to Always Disarmed for your safety.")); msgBox.setDetailedText(tr("You will have to reconfigure arming settings yourself afterwards.")); @@ -1392,6 +1186,8 @@ void ConfigInputWidget::simpleCalibration(bool enable) connect(manualCommandObj, SIGNAL(objectUnpacked(UAVObject*)), this, SLOT(updateCalibration())); } else { + m_config->configurationWizard->setEnabled(true); + manualCommandData = manualCommandObj->getData(); manualSettingsData = manualSettingsObj->getData(); diff --git a/ground/openpilotgcs/src/plugins/config/configinputwidget.h b/ground/openpilotgcs/src/plugins/config/configinputwidget.h index 4828c2a20..0110bccb0 100644 --- a/ground/openpilotgcs/src/plugins/config/configinputwidget.h +++ b/ground/openpilotgcs/src/plugins/config/configinputwidget.h @@ -81,6 +81,7 @@ private: }lastChannel; channelsStruct currentChannel; QList usedChannels; + bool channelDetected; QEventLoop * loop; bool skipflag; diff --git a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp index 0adc41e2c..0fc683da4 100644 --- a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp @@ -38,28 +38,32 @@ #include #include #include +#include "actuatorcommand.h" +#include "systemalarms.h" ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(parent) { m_config = new Ui_OutputWidget(); m_config->setupUi(this); - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - setupButtons(m_config->saveRCOutputToRAM,m_config->saveRCOutputToSD); - addUAVObject("ActuatorSettings"); + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + setupButtons(m_config->saveRCOutputToRAM,m_config->saveRCOutputToSD); + addUAVObject("ActuatorSettings"); - // First of all, put all the channel widgets into lists, so that we can + // First of all, put all the channel widgets into lists, so that we can // manipulate those: - // NOTE: for historical reasons, we have objects below called ch0 to ch7, but the convention for OP is Channel 1 to Channel 8. + // NOTE: for historical reasons, we have objects below called ch0 to ch7, but the convention for OP is Channel 1 to Channel 8. outLabels << m_config->ch0OutValue - << m_config->ch1OutValue - << m_config->ch2OutValue - << m_config->ch3OutValue - << m_config->ch4OutValue - << m_config->ch5OutValue - << m_config->ch6OutValue - << m_config->ch7OutValue; + << m_config->ch1OutValue + << m_config->ch2OutValue + << m_config->ch3OutValue + << m_config->ch4OutValue + << m_config->ch5OutValue + << m_config->ch6OutValue + << m_config->ch7OutValue + << m_config->ch8OutValue + << m_config->ch9OutValue; outSliders << m_config->ch0OutSlider << m_config->ch1OutSlider @@ -68,7 +72,9 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren << m_config->ch4OutSlider << m_config->ch5OutSlider << m_config->ch6OutSlider - << m_config->ch7OutSlider; + << m_config->ch7OutSlider + << m_config->ch8OutSlider + << m_config->ch9OutSlider; outMin << m_config->ch0OutMin << m_config->ch1OutMin @@ -77,7 +83,9 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren << m_config->ch4OutMin << m_config->ch5OutMin << m_config->ch6OutMin - << m_config->ch7OutMin; + << m_config->ch7OutMin + << m_config->ch8OutMin + << m_config->ch9OutMin; outMax << m_config->ch0OutMax << m_config->ch1OutMax @@ -86,7 +94,9 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren << m_config->ch4OutMax << m_config->ch5OutMax << m_config->ch6OutMax - << m_config->ch7OutMax; + << m_config->ch7OutMax + << m_config->ch8OutMax + << m_config->ch9OutMax; reversals << m_config->ch0Rev << m_config->ch1Rev @@ -95,7 +105,9 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren << m_config->ch4Rev << m_config->ch5Rev << m_config->ch6Rev - << m_config->ch7Rev; + << m_config->ch7Rev + << m_config->ch8Rev + << m_config->ch9Rev; links << m_config->ch0Link << m_config->ch1Link @@ -104,15 +116,23 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren << m_config->ch4Link << m_config->ch5Link << m_config->ch6Link - << m_config->ch7Link; + << m_config->ch7Link + << m_config->ch8Link + << m_config->ch9Link; // Register for ActuatorSettings changes: - for (int i = 0; i < 8; i++) { + for (int i = 0; i < ActuatorCommand::CHANNEL_NUMELEM; i++) { connect(outMin[i], SIGNAL(editingFinished()), this, SLOT(setChOutRange())); connect(outMax[i], SIGNAL(editingFinished()), this, SLOT(setChOutRange())); connect(reversals[i], SIGNAL(toggled(bool)), this, SLOT(reverseChannel(bool))); // Now connect the channel out sliders to our signal to send updates in test mode connect(outSliders[i], SIGNAL(valueChanged(int)), this, SLOT(sendChannelTest(int))); + + addWidget(outMin[i]); + addWidget(outMax[i]); + addWidget(reversals[i]); + addWidget(outSliders[i]); + addWidget(links[i]); } connect(m_config->channelOutTest, SIGNAL(toggled(bool)), this, SLOT(runChannelTests(bool))); @@ -134,39 +154,7 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren addWidget(m_config->outputRate3); addWidget(m_config->outputRate2); addWidget(m_config->outputRate1); - addWidget(m_config->ch0OutMin); - addWidget(m_config->ch0OutSlider); - addWidget(m_config->ch0OutMax); - addWidget(m_config->ch0Rev); - addWidget(m_config->ch0Link); - addWidget(m_config->ch1OutMin); - addWidget(m_config->ch1OutSlider); - addWidget(m_config->ch1OutMax); - addWidget(m_config->ch1Rev); - addWidget(m_config->ch2OutMin); - addWidget(m_config->ch2OutSlider); - addWidget(m_config->ch2OutMax); - addWidget(m_config->ch2Rev); - addWidget(m_config->ch3OutMin); - addWidget(m_config->ch3OutSlider); - addWidget(m_config->ch3OutMax); - addWidget(m_config->ch3Rev); - addWidget(m_config->ch4OutMin); - addWidget(m_config->ch4OutSlider); - addWidget(m_config->ch4OutMax); - addWidget(m_config->ch4Rev); - addWidget(m_config->ch5OutMin); - addWidget(m_config->ch5OutSlider); - addWidget(m_config->ch5OutMax); - addWidget(m_config->ch5Rev); - addWidget(m_config->ch6OutMin); - addWidget(m_config->ch6OutSlider); - addWidget(m_config->ch6OutMax); - addWidget(m_config->ch6Rev); - addWidget(m_config->ch7OutMin); - addWidget(m_config->ch7OutSlider); - addWidget(m_config->ch7OutMax); - addWidget(m_config->ch7Rev); + addWidget(m_config->spinningArmed); } @@ -215,6 +203,22 @@ void ConfigOutputWidget::linkToggled(bool state) */ void ConfigOutputWidget::runChannelTests(bool state) { + SystemAlarms * systemAlarmsObj = SystemAlarms::GetInstance(getObjectManager()); + SystemAlarms::DataFields systemAlarms = systemAlarmsObj->getData(); + + if(state && systemAlarms.Alarm[SystemAlarms::ALARM_ACTUATOR] != SystemAlarms::ALARM_OK) { + QMessageBox mbox; + mbox.setText(QString(tr("The actuator module is in an error state. This can also occur because there are no inputs. Please fix these before testing outputs."))); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + + // Unfortunately must cache this since callback will reoccur + accInitialData = ActuatorCommand::GetInstance(getObjectManager())->getMetadata(); + + m_config->channelOutTest->setChecked(false); + return; + } + // Confirm this is definitely what they want if(state) { QMessageBox mbox; @@ -229,11 +233,7 @@ void ConfigOutputWidget::runChannelTests(bool state) } } - qDebug() << "Running with state " << state; - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - - UAVDataObject* obj = dynamic_cast(objManager->getObject(QString("ActuatorCommand"))); + ActuatorCommand * obj = ActuatorCommand::GetInstance(getObjectManager()); UAVObject::Metadata mdata = obj->getMetadata(); if (state) { @@ -252,6 +252,9 @@ void ConfigOutputWidget::runChannelTests(bool state) foreach (QSpinBox* box, outMax) { box->setEnabled(false); } + foreach (QCheckBox* box, reversals) { + box->setEnabled(false); + } } else @@ -263,6 +266,9 @@ void ConfigOutputWidget::runChannelTests(bool state) foreach (QSpinBox* box, outMax) { box->setEnabled(true); } + foreach (QCheckBox* box, reversals) { + box->setEnabled(true); + } } obj->setMetadata(mdata); @@ -301,6 +307,12 @@ void ConfigOutputWidget::assignOutputChannel(UAVDataObject *obj, QString str) case 7: m_config->ch7Output->setText(str); break; + case 8: + m_config->ch8Output->setText(str); + break; + case 9: + m_config->ch9Output->setText(str); + break; } } @@ -384,14 +396,8 @@ void ConfigOutputWidget::refreshWidgetsValues() UAVObjectManager *objManager = pm->getObject(); // Reset all channel assignements: - m_config->ch0Output->setText("-"); - m_config->ch1Output->setText("-"); - m_config->ch2Output->setText("-"); - m_config->ch3Output->setText("-"); - m_config->ch4Output->setText("-"); - m_config->ch5Output->setText("-"); - m_config->ch6Output->setText("-"); - m_config->ch7Output->setText("-"); + for (int i = 0; i < ActuatorCommand::CHANNEL_NUMELEM; i++) + outLabels[i]->setText("-"); // Get the channel assignements: UAVDataObject * obj = dynamic_cast(objManager->getObject(QString("ActuatorSettings"))); @@ -418,8 +424,8 @@ void ConfigOutputWidget::refreshWidgetsValues() // CopterControl family m_config->chBank1->setText("1-3"); m_config->chBank2->setText("4"); - m_config->chBank3->setText("5"); - m_config->chBank4->setText("6"); + m_config->chBank3->setText("5,7-8"); + m_config->chBank4->setText("6,9-10"); m_config->outputRate1->setEnabled(true); m_config->outputRate2->setEnabled(true); m_config->outputRate3->setEnabled(true); @@ -443,7 +449,7 @@ void ConfigOutputWidget::refreshWidgetsValues() // Get Channel ranges: - for (int i=0;i<8;i++) { + for (int i=0;igetField(QString("ChannelMin")); int minValue = field->getValue(i).toInt(); outMin[i]->setValue(minValue); @@ -462,7 +468,7 @@ void ConfigOutputWidget::refreshWidgetsValues() } field = obj->getField(QString("ChannelNeutral")); - for (int i=0; i<8; i++) { + for (int i=0; igetValue(i).toInt(); outSliders[i]->setValue(value); outLabels[i]->setText(QString::number(value)); @@ -483,17 +489,17 @@ void ConfigOutputWidget::updateObjectsFromWidgets() // Now send channel ranges: UAVObjectField * field = obj->getField(QString("ChannelMax")); - for (int i = 0; i < 8; i++) { + for (int i = 0; i < ActuatorCommand::CHANNEL_NUMELEM; i++) { field->setValue(outMax[i]->value(),i); } field = obj->getField(QString("ChannelMin")); - for (int i = 0; i < 8; i++) { + for (int i = 0; i < ActuatorCommand::CHANNEL_NUMELEM; i++) { field->setValue(outMin[i]->value(),i); } field = obj->getField(QString("ChannelNeutral")); - for (int i = 0; i < 8; i++) { + for (int i = 0; i < ActuatorCommand::CHANNEL_NUMELEM; i++) { field->setValue(outSliders[i]->value(),i); } diff --git a/ground/openpilotgcs/src/plugins/config/inputchannelform.cpp b/ground/openpilotgcs/src/plugins/config/inputchannelform.cpp index 70223d57f..1eca667a8 100644 --- a/ground/openpilotgcs/src/plugins/config/inputchannelform.cpp +++ b/ground/openpilotgcs/src/plugins/config/inputchannelform.cpp @@ -85,8 +85,8 @@ void inputChannelForm::groupUpdated() count = 8; // Need to make this 6 for CC break; case ManualControlSettings::CHANNELGROUPS_PPM: - case ManualControlSettings::CHANNELGROUPS_SPEKTRUM1: - case ManualControlSettings::CHANNELGROUPS_SPEKTRUM2: + case ManualControlSettings::CHANNELGROUPS_DSMMAINPORT: + case ManualControlSettings::CHANNELGROUPS_DSMFLEXIPORT: count = 12; break; case ManualControlSettings::CHANNELGROUPS_SBUS: diff --git a/ground/openpilotgcs/src/plugins/config/output.ui b/ground/openpilotgcs/src/plugins/config/output.ui index b7855221f..b66c12cdc 100644 --- a/ground/openpilotgcs/src/plugins/config/output.ui +++ b/ground/openpilotgcs/src/plugins/config/output.ui @@ -970,6 +970,172 @@ p, li { white-space: pre-wrap; } + + + + Channel 9: + + + + + + + Channel 10: + + + + + + + + 9 + + + + - + + + Qt::AlignCenter + + + + + + + + 9 + + + + - + + + Qt::AlignCenter + + + + + + + 9999 + + + + + + + 9999 + + + + + + + 9999 + + + Qt::Horizontal + + + + + + + 9999 + + + Qt::Horizontal + + + + + + + 9999 + + + + + + + 9999 + + + + + + + 0000 + + + + + + + 0000 + + + + + + + + FreeSans + 8 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Check to invert the channel.</p></body></html> + + + + + + + + + + + FreeSans + 8 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Check to invert the channel.</p></body></html> + + + + + + + + + + Only used with Test Output mode + + + + + + + + + + Only used with Test Output mode + + + + + + diff --git a/ground/openpilotgcs/src/plugins/debuggadget/debuggadget.pro b/ground/openpilotgcs/src/plugins/debuggadget/debuggadget.pro index 8434e723d..a45db6697 100644 --- a/ground/openpilotgcs/src/plugins/debuggadget/debuggadget.pro +++ b/ground/openpilotgcs/src/plugins/debuggadget/debuggadget.pro @@ -2,7 +2,7 @@ TEMPLATE = lib TARGET = DebugGadget include(../../openpilotgcsplugin.pri) -include(../../plugins/coreplugin/coreplugin.pri) +include(../../plugins/coreplugin/coreplugin.pri) include(../../libs/libqxt/core/logengines.pri) HEADERS += debugplugin.h \ debugengine.h diff --git a/ground/openpilotgcs/src/plugins/plugins.pro b/ground/openpilotgcs/src/plugins/plugins.pro index 8079fa880..9012582e6 100644 --- a/ground/openpilotgcs/src/plugins/plugins.pro +++ b/ground/openpilotgcs/src/plugins/plugins.pro @@ -19,10 +19,9 @@ plugin_emptygadget.subdir = emptygadget plugin_emptygadget.depends = plugin_coreplugin SUBDIRS += plugin_emptygadget -# UAV Settings Import/Export plugin +# Debug Gadget plugin plugin_debuggadget.subdir = debuggadget -#plugin_debughelper.depends = plugin_coreplugin -#plugin_debughelper.depends += plugin_uavobjects +plugin_debuggadget.depends = plugin_coreplugin SUBDIRS += plugin_debuggadget # Welcome plugin diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobjecttemplate.m b/ground/openpilotgcs/src/plugins/uavobjects/uavobjecttemplate.m index b6259b0a1..4ae4c8e48 100644 --- a/ground/openpilotgcs/src/plugins/uavobjects/uavobjecttemplate.m +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobjecttemplate.m @@ -1,58 +1,65 @@ function [] = OPLogConvert() - %% Define indices and arrays of structures to hold data +%% Define indices and arrays of structures to hold data +% THIS FILE IS AUTOMATICALLY GENERATED. $(ALLOCATIONCODE) - - %% Open file - %fid = fopen('log.opl'); - [FileName,PathName,FilterIndex] = uigetfile('*.opl'); - logfile = strcat(PathName,FileName); - fid = fopen(logfile); - - while (1) - %% Read logging header - timestamp = fread(fid, 1, 'uint32'); - if (feof(fid)); break; end - datasize = fread(fid, 1, 'int64'); - - - %% Read message header - % get sync field (0x3C, 1 byte) - sync = fread(fid, 1, 'uint8'); - if sync ~= hex2dec('3C') - disp ('Wrong sync byte'); - return - end - % get msg type (quint8 1 byte ) should be 0x20, ignore the rest? - msgType = fread(fid, 1, 'uint8'); - if msgType ~= hex2dec('20') - disp ('Wrong msgType'); - return - end - % get msg size (quint16 2 bytes) excludes crc, include msg header and data payload - msgSize = fread(fid, 1, 'uint16'); - % get obj id (quint32 4 bytes) - objID = fread(fid, 1, 'uint32'); - - - %% Read object - switch objID -$(SWITCHCODE) - otherwise - disp('Unknown object ID'); - msgBytesLeft = datasize - 1 - 1 - 2 - 4; - fread(fid, msgBytesLeft, 'uint8'); - end - - end - - %% Clean Up and Save mat file - fclose(fid); - - matfile = strrep(logfile,'opl','mat'); - save(matfile $(SAVEOBJECTSCODE)); - + +%% Open log file +% [FileName,PathName,FilterIndex] = uigetfile('*.opl'); + +FileName='OP-2011-10-22_22-27-09.opl'; +PathName='/Users/kenz/Movies/brisk_videos/rover_test_1/'; +FilterIndex=1; + + +logfile = fullfile(PathName,FileName); +fid = fopen(logfile); + +% Parse log file, entry by entry +while (1) + %% Read logging header + timestamp = fread(fid, 1, 'uint32'); + if (feof(fid)); break; end + datasize = fread(fid, 1, 'int64'); + + + %% Read message header + % get sync field (0x3C, 1 byte) + sync = fread(fid, 1, 'uint8'); + if sync ~= hex2dec('3C') + disp ('Wrong sync byte'); + return + end + % get msg type (quint8 1 byte ) should be 0x20, ignore the rest? + msgType = fread(fid, 1, 'uint8'); + if msgType ~= hex2dec('20') + disp ('Wrong msgType'); + return + end + % get msg size (quint16 2 bytes) excludes crc, include msg header and data payload + msgSize = fread(fid, 1, 'uint16'); + % get obj id (quint32 4 bytes) + objID = fread(fid, 1, 'uint32'); + + + %% Read object + switch objID +$(SWITCHCODE) + otherwise + disp(['Unknown object ID: 0x' dec2hex(objID)]); + msgBytesLeft = datasize - 1 - 1 - 2 - 4; + fread(fid, msgBytesLeft, 'uint8'); + end + end +%% Clean Up and Save mat file +fclose(fid); + +matfile = strrep(logfile,'opl','mat'); +save(matfile $(SAVEOBJECTSCODE)); + + + %% Object reading functions $(FUNCTIONSCODE) diff --git a/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.cpp b/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.cpp index 6a9d22d5f..7295f79c3 100644 --- a/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.cpp +++ b/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.cpp @@ -282,9 +282,15 @@ bool UAVTalk::processInputByte(quint8 rxbyte) // Determine data length if (rxType == TYPE_OBJ_REQ || rxType == TYPE_ACK || rxType == TYPE_NACK) + { rxLength = 0; + rxInstanceLength = 0; + } else + { rxLength = rxObj->getNumBytes(); + rxInstanceLength = (rxObj->isSingleInstance() ? 0 : 2); + } // Check length and determine next state if (rxLength >= MAX_PAYLOAD_LENGTH) @@ -295,7 +301,7 @@ bool UAVTalk::processInputByte(quint8 rxbyte) } // Check the lengths match - if ((rxPacketLength + rxLength + (rxObj->isSingleInstance() ? 0 : 2)) != packetSize) + if ((rxPacketLength + rxInstanceLength + rxLength) != packetSize) { // packet error - mismatched packet size stats.rxErrors++; rxState = STATE_SYNC; diff --git a/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.h b/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.h index 99549f691..163fb9fa3 100644 --- a/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.h +++ b/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.h @@ -107,6 +107,7 @@ private: quint16 rxInstId; quint16 rxLength; quint16 rxPacketLength; + quint8 rxInstanceLength; quint8 rxCSPacket, rxCS; qint32 rxCount; diff --git a/ground/uavobjgenerator/generators/generator_common.h b/ground/uavobjgenerator/generators/generator_common.h index 0ae6f470e..95dab21e5 100644 --- a/ground/uavobjgenerator/generators/generator_common.h +++ b/ground/uavobjgenerator/generators/generator_common.h @@ -31,7 +31,7 @@ #include "generator_io.h" // These special chars (regexp) will be removed from C/java identifiers -#define ENUM_SPECIAL_CHARS "[\\.\\-\\s/]" +#define ENUM_SPECIAL_CHARS "[\\.\\-\\s\\+/\\(\\)]" void replaceCommonTags(QString& out, ObjectInfo* info); void replaceCommonTags(QString& out); diff --git a/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.cpp b/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.cpp index 61882e6b9..f1dfa368d 100644 --- a/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.cpp +++ b/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.cpp @@ -50,7 +50,7 @@ bool UAVObjectGeneratorMatlab::generate(UAVObjectParser* parser,QString template } matlabCodeTemplate.replace( QString("$(ALLOCATIONCODE)"), matlabAllocationCode); - matlabCodeTemplate.replace( QString("$(SWITCHCODE)"), matlabSwithCode); + matlabCodeTemplate.replace( QString("$(SWITCHCODE)"), matlabSwitchCode); matlabCodeTemplate.replace( QString("$(SAVEOBJECTSCODE)"), matlabSaveObjectsCode); matlabCodeTemplate.replace( QString("$(FUNCTIONSCODE)"), matlabFunctionsCode); @@ -71,6 +71,7 @@ bool UAVObjectGeneratorMatlab::process_object(ObjectInfo* info) if (info == NULL) return false; + //Declare variables QString objectName(info->name); // QString objectTableName(objectName + "Objects"); QString objectTableName(objectName); @@ -80,39 +81,71 @@ bool UAVObjectGeneratorMatlab::process_object(ObjectInfo* info) QString objectID(QString().setNum(info->id)); QString isSingleInst = boolTo01String( info->isSingleInst ); - // Generate allocation code (will replace the $(ALLOCATIONCODE) tag) - matlabAllocationCode.append("\n " + tableIdxName + " = 1;\n"); - matlabAllocationCode.append(" " + objectTableName + ".timestamp = 0;\n"); - QString type; - QString allocfields; - for (int n = 0; n < info->fields.length(); ++n) { - // Determine type - type = fieldTypeStrMatlab[info->fields[n]->type]; - // Append field - if ( info->fields[n]->numElements > 1 ) - allocfields.append(" " + objectTableName + "(1)." + info->fields[n]->name + " = zeros(1," + QString::number(info->fields[n]->numElements, 10) + ");\n"); - else - allocfields.append(" " + objectTableName + "(1)." + info->fields[n]->name + " = 0;\n"); - } + + //===================================================================// + // Generate allocation code (will replace the $(ALLOCATIONCODE) tag) // + //===================================================================// + // matlabSwitchCode.append("\t\tcase " + objectID + "\n"); + matlabAllocationCode.append("\n\t" + tableIdxName + " = 1;\n"); + QString type; + QString allocfields; + if (0){ + matlabAllocationCode.append("\t" + objectTableName + ".timestamp = 0;\n"); + for (int n = 0; n < info->fields.length(); ++n) { + // Determine type + type = fieldTypeStrMatlab[info->fields[n]->type]; + // Append field + if ( info->fields[n]->numElements > 1 ) + allocfields.append("\t" + objectTableName + "(1)." + info->fields[n]->name + " = zeros(1," + QString::number(info->fields[n]->numElements, 10) + ");\n"); + else + allocfields.append("\t" + objectTableName + "(1)." + info->fields[n]->name + " = 0;\n"); + } + } + else{ + matlabAllocationCode.append("\t" + objectTableName + "=struct('timestamp', 0"); + for (int n = 0; n < info->fields.length(); ++n) { + // Determine type + type = fieldTypeStrMatlab[info->fields[n]->type]; + // Append field + if ( info->fields[n]->numElements > 1 ) + allocfields.append(",...\n\t\t '" + info->fields[n]->name + "', zeros(1," + QString::number(info->fields[n]->numElements, 10) + ")"); + else + allocfields.append(",...\n\t\t '" + info->fields[n]->name + "', 0"); + } + allocfields.append(");\n"); + } matlabAllocationCode.append(allocfields); + matlabAllocationCode.append("\t" + objectTableName.toUpper() + "_OBJID=" + objectID + ";\n"); - // Generate 'swith:' code (will replace the $(SWITCHCODE) tag) - matlabSwithCode.append(" case " + objectID + "\n"); - matlabSwithCode.append(" " + objectTableName + "(" + tableIdxName +") = " + functionCall + ";\n"); - matlabSwithCode.append(" " + tableIdxName + " = " + tableIdxName +" + 1;\n"); - // Generate objects saving code code (will replace the $(SAVEOBJECTSCODE) tag) + //=============================================================// + // Generate 'Switch:' code (will replace the $(SWITCHCODE) tag) // + //=============================================================// + matlabSwitchCode.append("\t\tcase " + objectTableName.toUpper() + "_OBJID\n"); + matlabSwitchCode.append("\t\t\t" + objectTableName + "(" + tableIdxName +") = " + functionCall + ";\n"); + matlabSwitchCode.append("\t\t\t" + tableIdxName + " = " + tableIdxName +" + 1;\n"); + + + //=============================================================================// + // Generate objects saving code code (will replace the $(SAVEOBJECTSCODE) tag) // + //=============================================================================// matlabSaveObjectsCode.append(",'"+objectTableName+"'"); - // Generate functions code (will replace the $(FUNCTIONSCODE) tag) + matlabFunctionsCode.append("%%\n% " + objectName + " read function\n"); + + + //=================================================================// + // Generate functions code (will replace the $(FUNCTIONSCODE) tag) // + //=================================================================// + //Generate function description comment matlabFunctionsCode.append("function [" + objectName + "] = " + functionCall + "\n"); - matlabFunctionsCode.append(" if " + isSingleInst + "\n"); - matlabFunctionsCode.append(" headerSize = 8;\n"); - matlabFunctionsCode.append(" else\n"); - matlabFunctionsCode.append(" " + objectName + ".instanceID = fread(fid, 1, 'uint16');\n"); - matlabFunctionsCode.append(" headerSize = 10;\n"); - matlabFunctionsCode.append(" end\n\n"); - matlabFunctionsCode.append(" " + objectName + ".timestamp = timestamp;\n"); + matlabFunctionsCode.append("\tif " + isSingleInst + "\n"); + matlabFunctionsCode.append("\t\theaderSize = 8;\n"); + matlabFunctionsCode.append("\telse\n"); + matlabFunctionsCode.append("\t\t" + objectName + ".instanceID = fread(fid, 1, 'uint16');\n"); + matlabFunctionsCode.append("\t\theaderSize = 10;\n"); + matlabFunctionsCode.append("\tend\n\n"); + matlabFunctionsCode.append("\t" + objectName + ".timestamp = timestamp;\n"); // Generate functions code, actual fields of the object QString funcfields; @@ -122,16 +155,16 @@ bool UAVObjectGeneratorMatlab::process_object(ObjectInfo* info) type = fieldTypeStrMatlab[info->fields[n]->type]; // Append field if ( info->fields[n]->numElements > 1 ) - funcfields.append(" " + objectName + "." + info->fields[n]->name + " = double(fread(fid, " + QString::number(info->fields[n]->numElements, 10) + ", '" + type + "'));\n"); + funcfields.append("\t" + objectName + "." + info->fields[n]->name + " = double(fread(fid, " + QString::number(info->fields[n]->numElements, 10) + ", '" + type + "'));\n"); else - funcfields.append(" " + objectName + "." + info->fields[n]->name + " = double(fread(fid, 1, '" + type + "'));\n"); + funcfields.append("\t" + objectName + "." + info->fields[n]->name + " = double(fread(fid, 1, '" + type + "'));\n"); } matlabFunctionsCode.append(funcfields); - matlabFunctionsCode.append(" % read CRC\n"); - matlabFunctionsCode.append(" fread(fid, 1, 'uint8');\n"); + matlabFunctionsCode.append("\t% read CRC\n"); + matlabFunctionsCode.append("\tfread(fid, 1, 'uint8');\n"); - matlabFunctionsCode.append("end\n\n"); + matlabFunctionsCode.append("\n\n"); return true; } diff --git a/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.h b/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.h index a5652b9e5..9a060bf41 100644 --- a/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.h +++ b/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.h @@ -37,7 +37,7 @@ public: private: bool process_object(ObjectInfo* info); QString matlabAllocationCode; - QString matlabSwithCode; + QString matlabSwitchCode; QString matlabSaveObjectsCode; QString matlabFunctionsCode; QStringList fieldTypeStrMatlab; diff --git a/shared/uavobjectdefinition/actuatorcommand.xml b/shared/uavobjectdefinition/actuatorcommand.xml index 0d7de05a6..c0b65bbbc 100644 --- a/shared/uavobjectdefinition/actuatorcommand.xml +++ b/shared/uavobjectdefinition/actuatorcommand.xml @@ -1,7 +1,7 @@ Contains the pulse duration sent to each of the channels. Set by @ref ActuatorModule - + diff --git a/shared/uavobjectdefinition/actuatorsettings.xml b/shared/uavobjectdefinition/actuatorsettings.xml index a4cf3bc76..1524797b4 100644 --- a/shared/uavobjectdefinition/actuatorsettings.xml +++ b/shared/uavobjectdefinition/actuatorsettings.xml @@ -1,27 +1,27 @@ Settings for the @ref ActuatorModule that controls the channel assignments for the mixer based on AircraftType - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - + + + + + diff --git a/shared/uavobjectdefinition/hwsettings.xml b/shared/uavobjectdefinition/hwsettings.xml index 4b600fd78..63e346fc5 100644 --- a/shared/uavobjectdefinition/hwsettings.xml +++ b/shared/uavobjectdefinition/hwsettings.xml @@ -1,13 +1,13 @@ Selection of optional hardware configurations. - - - + + + - + - + diff --git a/shared/uavobjectdefinition/manualcontrolsettings.xml b/shared/uavobjectdefinition/manualcontrolsettings.xml index ae7c9b24c..78f38011f 100644 --- a/shared/uavobjectdefinition/manualcontrolsettings.xml +++ b/shared/uavobjectdefinition/manualcontrolsettings.xml @@ -3,7 +3,7 @@ Settings to indicate how to decode receiver input by @ref ManualControlModule. + options="PWM,PPM,DSM (MainPort),DSM (FlexiPort),S.Bus,GCS,None" defaultvalue="None"/> + + + + diff --git a/shared/uavobjectdefinition/receiveractivity.xml b/shared/uavobjectdefinition/receiveractivity.xml index 2e98c1362..c2a741d7f 100644 --- a/shared/uavobjectdefinition/receiveractivity.xml +++ b/shared/uavobjectdefinition/receiveractivity.xml @@ -2,7 +2,7 @@ Monitors which receiver channels have been active within the last second.