mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2024-11-29 07:24:13 +01:00
Merge branch 'next' into os/GPS-on-CopterControl_next_v2
Conflicts: flight/OpenPilot/System/pios_board.c flight/OpenPilot/UAVObjects.inc shared/uavobjectdefinition/hwsettings.xml
This commit is contained in:
commit
53c098dd08
15
HISTORY.txt
15
HISTORY.txt
@ -1,5 +1,20 @@
|
||||
Short summary of changes. For a complete list see the git log.
|
||||
|
||||
2011-09-12
|
||||
Max rate now ONLY applies to attitude and axis lock mode. Manual rate is the
|
||||
only term that limits the rate mode now (and in axis lock when you push stick
|
||||
only manual rate applies). Also integrals are reset when unused.
|
||||
|
||||
2011-09-09
|
||||
Some large updates to the input system. Now multiple receivers can be
|
||||
connected at once. A wizard was added for configuring the input channels. A
|
||||
specific collective pitch channel was added.
|
||||
|
||||
2011-09-04
|
||||
Improvements to the failsafe handling code for inputs. PWM power off is now
|
||||
detected properly. Powering on transmitter for Spektrum Satellite no longer
|
||||
causes a glitch on servos.
|
||||
|
||||
2011-08-10
|
||||
Added Camera Stabilization and a gui to configure this. This is a software
|
||||
selectable module from the GUI. However, a restart is required to make it
|
||||
|
@ -82,7 +82,7 @@ C: Sami Korhonen (Sambas)
|
||||
D: February 2011
|
||||
V: http://vimeo.com/20159015
|
||||
|
||||
M: First Position Hold on a Fixed Wing
|
||||
M: First CopterControl Position Hold on a Fixed Wing
|
||||
C: Eric Price (Corvus Corax)
|
||||
D: March 2011
|
||||
V: http://www.youtube.com/watch?v=QtaefhmGbio
|
||||
@ -146,6 +146,12 @@ M: First CopterControl Flybared Heli funnel (4:18), loop (5:35)
|
||||
C: Sergey Solodennikov (alconaft43)
|
||||
D: August 2011
|
||||
V: http://www.youtube.com/watch?v=8SrfIS7OkB4
|
||||
|
||||
M: First CopterControl Return to Base Fixed Wing
|
||||
C: Eric Price (Corvus Corax)
|
||||
D: AUgust 2011
|
||||
V: http://www.youtube.com/watch?v=CugI0oBSQn8
|
||||
|
||||
|
||||
M: First Altitude Hold using Sonar
|
||||
C:
|
||||
@ -170,11 +176,11 @@ V:
|
||||
|
||||
An incomplete list of some future Milestones is below:
|
||||
|
||||
* First Y6 CopterControl flight
|
||||
* First Helicopter flight with OpenPilot
|
||||
* First Helicopter flight with OpenPilot Pro
|
||||
* First fixed wing navigation flight on CopterControl
|
||||
* First successful flight using the GCS only and no RC TX
|
||||
* First use of Magic Waypoint
|
||||
* First Flybarless Helicopter flight with OpenPilot
|
||||
* First Flybarless Helicopter flight with OpenPilot Pro
|
||||
* First fixed wing navigation flight
|
||||
* First Multirotor navigation flight
|
||||
* First Helicopter navigation flight
|
||||
@ -183,4 +189,3 @@ An incomplete list of some future Milestones is below:
|
||||
* First "Follow Me" navigation flight
|
||||
* First Channel Crossing with OpenPilot
|
||||
|
||||
|
||||
|
12
Makefile
12
Makefile
@ -183,13 +183,13 @@ qt_sdk_clean:
|
||||
ARM_SDK_DIR := $(TOOLS_DIR)/arm-2011.03
|
||||
|
||||
.PHONY: arm_sdk_install
|
||||
arm_sdk_install: ARM_SDK_URL := http://www.codesourcery.com/sgpp/lite/arm/portal/package8734/public/arm-none-eabi/arm-2011.03-42-arm-none-eabi-i686-pc-linux-gnu.tar.bz2
|
||||
arm_sdk_install: ARM_SDK_URL := https://sourcery.mentor.com/sgpp/lite/arm/portal/package8736/public/arm-none-eabi/arm-2011.03-42-arm-none-eabi-i686-pc-linux-gnu.tar.bz2
|
||||
arm_sdk_install: ARM_SDK_FILE := $(notdir $(ARM_SDK_URL))
|
||||
# order-only prereq on directory existance:
|
||||
arm_sdk_install: | $(DL_DIR) $(TOOLS_DIR)
|
||||
arm_sdk_install: arm_sdk_clean
|
||||
# download the source only if it's newer than what we already have
|
||||
$(V1) wget -N -P "$(DL_DIR)" "$(ARM_SDK_URL)"
|
||||
$(V1) wget --no-check-certificate -N -P "$(DL_DIR)" "$(ARM_SDK_URL)"
|
||||
|
||||
# binary only release so just extract it
|
||||
$(V1) tar -C $(TOOLS_DIR) -xjf "$(DL_DIR)/$(ARM_SDK_FILE)"
|
||||
@ -202,8 +202,8 @@ arm_sdk_clean:
|
||||
OPENOCD_DIR := $(TOOLS_DIR)/openocd
|
||||
|
||||
.PHONY: openocd_install
|
||||
openocd_install: OPENOCD_URL := http://sourceforge.net/projects/openocd/files/openocd/0.4.0/openocd-0.4.0.tar.bz2/download
|
||||
openocd_install: OPENOCD_FILE := openocd-0.4.0.tar.bz2
|
||||
openocd_install: OPENOCD_URL := http://sourceforge.net/projects/openocd/files/openocd/0.5.0/openocd-0.5.0.tar.bz2/download
|
||||
openocd_install: OPENOCD_FILE := openocd-0.5.0.tar.bz2
|
||||
# order-only prereq on directory existance:
|
||||
openocd_install: | $(DL_DIR) $(TOOLS_DIR)
|
||||
openocd_install: openocd_clean
|
||||
@ -218,8 +218,8 @@ openocd_install: openocd_clean
|
||||
# build and install
|
||||
$(V1) mkdir -p "$(OPENOCD_DIR)"
|
||||
$(V1) ( \
|
||||
cd $(DL_DIR)/openocd-build/openocd-0.4.0 ; \
|
||||
./configure --prefix="$(OPENOCD_DIR)" --enable-ft2232_libftdi ; \
|
||||
cd $(DL_DIR)/openocd-build/openocd-0.5.0 ; \
|
||||
./configure --prefix="$(OPENOCD_DIR)" --enable-ft2232_libftdi --enable-buspirate; \
|
||||
$(MAKE) ; \
|
||||
$(MAKE) install ; \
|
||||
)
|
||||
|
Binary file not shown.
@ -355,7 +355,7 @@ $(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin
|
||||
$(eval $(call OPFW_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BOARD_TYPE),$(BOARD_REVISION)))
|
||||
|
||||
# Add jtag targets (program and wipe)
|
||||
$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE)))
|
||||
$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE),$(OPENOCD_CONFIG)))
|
||||
|
||||
.PHONY: elf lss sym hex bin bino opfw
|
||||
elf: $(OUTDIR)/$(TARGET).elf
|
||||
|
@ -258,7 +258,9 @@ CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) -I.
|
||||
|
||||
CFLAGS += -mapcs-frame
|
||||
CFLAGS += -fomit-frame-pointer
|
||||
ifeq ($(CODE_SOURCERY), YES)
|
||||
CFLAGS += -fpromote-loop-indices
|
||||
endif
|
||||
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Werror
|
||||
|
@ -300,7 +300,9 @@ CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) -I.
|
||||
|
||||
CFLAGS += -mapcs-frame
|
||||
CFLAGS += -fomit-frame-pointer
|
||||
ifeq ($(CODE_SOURCERY), YES)
|
||||
CFLAGS += -fpromote-loop-indices
|
||||
endif
|
||||
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Werror
|
||||
|
@ -306,7 +306,9 @@ CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) -I.
|
||||
|
||||
CFLAGS += -mapcs-frame
|
||||
CFLAGS += -fomit-frame-pointer
|
||||
ifeq ($(CODE_SOURCERY), YES)
|
||||
CFLAGS += -fpromote-loop-indices
|
||||
endif
|
||||
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Werror
|
||||
|
@ -301,7 +301,9 @@ CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) -I.
|
||||
|
||||
CFLAGS += -mapcs-frame
|
||||
CFLAGS += -fomit-frame-pointer
|
||||
ifeq ($(CODE_SOURCERY), YES)
|
||||
CFLAGS += -fpromote-loop-indices
|
||||
endif
|
||||
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Werror
|
||||
|
@ -65,7 +65,8 @@ endif
|
||||
FLASH_TOOL = OPENOCD
|
||||
|
||||
# List of modules to include
|
||||
OPTMODULES = CameraStab GPS
|
||||
OPTMODULES = CameraStab
|
||||
OPTMODULES += GPS
|
||||
MODULES = Attitude Stabilization Actuator ManualControl FirmwareIAP
|
||||
# Telemetry must be last to grab the optional modules (why?)
|
||||
MODULES += Telemetry
|
||||
@ -170,7 +171,8 @@ SRC += $(OPUAVSYNTHDIR)/camerastabsettings.c
|
||||
SRC += $(OPUAVSYNTHDIR)/cameradesired.c
|
||||
SRC += $(OPUAVSYNTHDIR)/gpsposition.c
|
||||
SRC += $(OPUAVSYNTHDIR)/hwsettings.c
|
||||
|
||||
SRC += $(OPUAVSYNTHDIR)/gcsreceiver.c
|
||||
SRC += $(OPUAVSYNTHDIR)/receiveractivity.c
|
||||
SRC += $(OPUAVSYNTHDIR)/taskinfo.c
|
||||
SRC += $(OPUAVSYNTHDIR)/mixerstatus.c
|
||||
SRC += $(OPUAVSYNTHDIR)/ratedesired.c
|
||||
@ -196,6 +198,7 @@ SRC += $(PIOSSTM32F10X)/pios_gpio.c
|
||||
SRC += $(PIOSSTM32F10X)/pios_exti.c
|
||||
SRC += $(PIOSSTM32F10X)/pios_rtc.c
|
||||
SRC += $(PIOSSTM32F10X)/pios_wdg.c
|
||||
SRC += $(PIOSSTM32F10X)/pios_tim.c
|
||||
|
||||
|
||||
# PIOS USB related files (seperated to make code maintenance more easy)
|
||||
@ -214,6 +217,7 @@ SRC += $(PIOSCOMMON)/pios_i2c_esc.c
|
||||
SRC += $(PIOSCOMMON)/pios_iap.c
|
||||
SRC += $(PIOSCOMMON)/pios_bl_helper.c
|
||||
SRC += $(PIOSCOMMON)/pios_rcvr.c
|
||||
SRC += $(PIOSCOMMON)/pios_gcsrcvr.c
|
||||
SRC += $(PIOSCOMMON)/printf-stdarg.c
|
||||
## Libraries for flight calculations
|
||||
SRC += $(FLIGHTLIB)/fifo_buffer.c
|
||||
@ -443,7 +447,9 @@ CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) -I.
|
||||
|
||||
CFLAGS += -mapcs-frame
|
||||
CFLAGS += -fomit-frame-pointer
|
||||
ifeq ($(CODE_SOURCERY), YES)
|
||||
CFLAGS += -fpromote-loop-indices
|
||||
endif
|
||||
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Werror
|
||||
@ -568,7 +574,7 @@ $(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin
|
||||
$(eval $(call OPFW_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BOARD_TYPE),$(BOARD_REVISION)))
|
||||
|
||||
# Add jtag targets (program and wipe)
|
||||
$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE)))
|
||||
$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE),$(OPENOCD_CONFIG)))
|
||||
|
||||
.PHONY: elf lss sym hex bin bino opfw
|
||||
elf: $(OUTDIR)/$(TARGET).elf
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define configUSE_PREEMPTION 1
|
||||
#define configUSE_IDLE_HOOK 1
|
||||
#define configUSE_TICK_HOOK 0
|
||||
#define configUSE_MALLOC_FAILED_HOOK 1
|
||||
#define configCPU_CLOCK_HZ ( ( unsigned long ) 72000000 )
|
||||
#define configTICK_RATE_HZ ( ( portTickType ) 1000 )
|
||||
#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 )
|
||||
|
@ -48,8 +48,9 @@
|
||||
/* Supported receiver interfaces */
|
||||
#define PIOS_INCLUDE_SPEKTRUM
|
||||
#define PIOS_INCLUDE_SBUS
|
||||
//#define PIOS_INCLUDE_PPM
|
||||
#define PIOS_INCLUDE_PPM
|
||||
#define PIOS_INCLUDE_PWM
|
||||
#define PIOS_INCLUDE_GCSRCVR
|
||||
|
||||
/* Supported USART-based PIOS modules */
|
||||
#define PIOS_INCLUDE_TELEMETRY_RF
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <uavobjectsinit.h>
|
||||
#include <hwsettings.h>
|
||||
#include <manualcontrolsettings.h>
|
||||
#include <gcsreceiver.h>
|
||||
|
||||
#if defined(PIOS_INCLUDE_SPI)
|
||||
|
||||
@ -195,6 +196,220 @@ void PIOS_ADC_handler() {
|
||||
PIOS_ADC_DMA_Handler();
|
||||
}
|
||||
|
||||
#include "pios_tim_priv.h"
|
||||
|
||||
static const TIM_TimeBaseInitTypeDef tim_1_2_3_4_time_base = {
|
||||
.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1,
|
||||
.TIM_ClockDivision = TIM_CKD_DIV1,
|
||||
.TIM_CounterMode = TIM_CounterMode_Up,
|
||||
.TIM_Period = ((1000000 / PIOS_SERVO_UPDATE_HZ) - 1),
|
||||
.TIM_RepetitionCounter = 0x0000,
|
||||
};
|
||||
|
||||
static const struct pios_tim_clock_cfg tim_1_cfg = {
|
||||
.timer = TIM1,
|
||||
.time_base_init = &tim_1_2_3_4_time_base,
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannel = TIM1_CC_IRQn,
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct pios_tim_clock_cfg tim_2_cfg = {
|
||||
.timer = TIM2,
|
||||
.time_base_init = &tim_1_2_3_4_time_base,
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannel = TIM2_IRQn,
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct pios_tim_clock_cfg tim_3_cfg = {
|
||||
.timer = TIM3,
|
||||
.time_base_init = &tim_1_2_3_4_time_base,
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannel = TIM3_IRQn,
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct pios_tim_clock_cfg tim_4_cfg = {
|
||||
.timer = TIM4,
|
||||
.time_base_init = &tim_1_2_3_4_time_base,
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannel = TIM4_IRQn,
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct pios_tim_channel pios_tim_rcvrport_all_channels[] = {
|
||||
{
|
||||
.timer = TIM4,
|
||||
.timer_chan = TIM_Channel_1,
|
||||
.pin = {
|
||||
.gpio = GPIOB,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_6,
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.timer = TIM3,
|
||||
.timer_chan = TIM_Channel_2,
|
||||
.pin = {
|
||||
.gpio = GPIOB,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_5,
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
.remap = GPIO_PartialRemap_TIM3,
|
||||
},
|
||||
{
|
||||
.timer = TIM3,
|
||||
.timer_chan = TIM_Channel_3,
|
||||
.pin = {
|
||||
.gpio = GPIOB,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_0,
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.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_IPD,
|
||||
.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_IPD,
|
||||
.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_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct pios_tim_channel pios_tim_servoport_all_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,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
#if defined(PIOS_INCLUDE_USART)
|
||||
|
||||
#include "pios_usart_priv.h"
|
||||
@ -564,121 +779,40 @@ void PIOS_RTC_IRQ_Handler (void)
|
||||
* Servo outputs
|
||||
*/
|
||||
#include <pios_servo_priv.h>
|
||||
static const struct pios_servo_channel pios_servo_channels[] = {
|
||||
{
|
||||
.timer = TIM4,
|
||||
.port = GPIOB,
|
||||
.channel = TIM_Channel_4,
|
||||
.pin = GPIO_Pin_9,
|
||||
},
|
||||
{
|
||||
.timer = TIM4,
|
||||
.port = GPIOB,
|
||||
.channel = TIM_Channel_3,
|
||||
.pin = GPIO_Pin_8,
|
||||
},
|
||||
{
|
||||
.timer = TIM4,
|
||||
.port = GPIOB,
|
||||
.channel = TIM_Channel_2,
|
||||
.pin = GPIO_Pin_7,
|
||||
},
|
||||
{
|
||||
.timer = TIM1,
|
||||
.port = GPIOA,
|
||||
.channel = TIM_Channel_1,
|
||||
.pin = GPIO_Pin_8,
|
||||
},
|
||||
{ /* needs to remap to alternative function */
|
||||
.timer = TIM3,
|
||||
.port = GPIOB,
|
||||
.channel = TIM_Channel_1,
|
||||
.pin = GPIO_Pin_4,
|
||||
},
|
||||
{
|
||||
.timer = TIM2,
|
||||
.port = GPIOA,
|
||||
.channel = TIM_Channel_3,
|
||||
.pin = GPIO_Pin_2,
|
||||
},
|
||||
};
|
||||
|
||||
const struct pios_servo_cfg pios_servo_cfg = {
|
||||
.tim_base_init = {
|
||||
.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1,
|
||||
.TIM_ClockDivision = TIM_CKD_DIV1,
|
||||
.TIM_CounterMode = TIM_CounterMode_Up,
|
||||
.TIM_Period = ((1000000 / PIOS_SERVO_UPDATE_HZ) - 1),
|
||||
.TIM_RepetitionCounter = 0x0000,
|
||||
},
|
||||
.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_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,
|
||||
},
|
||||
.gpio_init = {
|
||||
.GPIO_Mode = GPIO_Mode_AF_PP,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
.remap = GPIO_PartialRemap_TIM3,
|
||||
.channels = pios_servo_channels,
|
||||
.num_channels = NELEMENTS(pios_servo_channels),
|
||||
.channels = pios_tim_servoport_all_pins,
|
||||
.num_channels = NELEMENTS(pios_tim_servoport_all_pins),
|
||||
};
|
||||
|
||||
#if defined(PIOS_INCLUDE_PWM) && defined(PIOS_INCLUDE_PPM)
|
||||
#error Cannot define both PIOS_INCLUDE_PWM and PIOS_INCLUDE_PPM at the same time (yet)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* PPM Inputs
|
||||
*/
|
||||
#if defined(PIOS_INCLUDE_PPM)
|
||||
#include <pios_ppm_priv.h>
|
||||
|
||||
void TIM4_IRQHandler();
|
||||
void TIM4_IRQHandler() __attribute__ ((alias ("PIOS_TIM4_irq_handler")));
|
||||
const struct pios_ppm_cfg pios_ppm_cfg = {
|
||||
.tim_base_init = {
|
||||
.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1, /* For 1 uS accuracy */
|
||||
.TIM_ClockDivision = TIM_CKD_DIV1,
|
||||
.TIM_CounterMode = TIM_CounterMode_Up,
|
||||
.TIM_Period = 0xFFFF, /* shared timer, make sure init correctly in outputs */
|
||||
.TIM_RepetitionCounter = 0x0000,
|
||||
},
|
||||
.tim_ic_init = {
|
||||
.TIM_Channel = TIM_Channel_1,
|
||||
.TIM_ICPolarity = TIM_ICPolarity_Rising,
|
||||
.TIM_ICSelection = TIM_ICSelection_DirectTI,
|
||||
.TIM_ICPrescaler = TIM_ICPSC_DIV1,
|
||||
.TIM_ICFilter = 0x0,
|
||||
},
|
||||
.gpio_init = {
|
||||
.GPIO_Pin = GPIO_Pin_6,
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
.remap = 0,
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
.timer = TIM4,
|
||||
.port = GPIOB,
|
||||
.ccr = TIM_IT_CC1,
|
||||
/* Use only the first channel for ppm */
|
||||
.channels = &pios_tim_rcvrport_all_channels[0],
|
||||
.num_channels = 1,
|
||||
};
|
||||
|
||||
void PIOS_TIM4_irq_handler()
|
||||
{
|
||||
PIOS_PPM_irq_handler();
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_PPM */
|
||||
|
||||
/*
|
||||
@ -687,98 +821,16 @@ void PIOS_TIM4_irq_handler()
|
||||
#if defined(PIOS_INCLUDE_PWM)
|
||||
#include <pios_pwm_priv.h>
|
||||
|
||||
static const struct pios_pwm_channel pios_pwm_channels[] = {
|
||||
{
|
||||
.timer = TIM4,
|
||||
.port = GPIOB,
|
||||
.ccr = TIM_IT_CC1,
|
||||
.channel = TIM_Channel_1,
|
||||
.pin = GPIO_Pin_6,
|
||||
},
|
||||
{
|
||||
.timer = TIM3,
|
||||
.port = GPIOB,
|
||||
.ccr = TIM_IT_CC2,
|
||||
.channel = TIM_Channel_2,
|
||||
.pin = GPIO_Pin_5,
|
||||
},
|
||||
{
|
||||
.timer = TIM3,
|
||||
.port = GPIOB,
|
||||
.ccr = TIM_IT_CC3,
|
||||
.channel = TIM_Channel_3,
|
||||
.pin = GPIO_Pin_0
|
||||
},
|
||||
{
|
||||
.timer = TIM3,
|
||||
.port = GPIOB,
|
||||
.ccr = TIM_IT_CC4,
|
||||
.channel = TIM_Channel_4,
|
||||
.pin = GPIO_Pin_1,
|
||||
},
|
||||
{
|
||||
.timer = TIM2,
|
||||
.port = GPIOA,
|
||||
.ccr = TIM_IT_CC1,
|
||||
.channel = TIM_Channel_1,
|
||||
.pin = GPIO_Pin_0,
|
||||
},
|
||||
{
|
||||
.timer = TIM2,
|
||||
.port = GPIOA,
|
||||
.ccr = TIM_IT_CC2,
|
||||
.channel = TIM_Channel_2,
|
||||
.pin = GPIO_Pin_1,
|
||||
},
|
||||
};
|
||||
|
||||
void TIM2_IRQHandler();
|
||||
void TIM3_IRQHandler();
|
||||
void TIM4_IRQHandler();
|
||||
void TIM2_IRQHandler() __attribute__ ((alias ("PIOS_TIM2_irq_handler")));
|
||||
void TIM3_IRQHandler() __attribute__ ((alias ("PIOS_TIM3_irq_handler")));
|
||||
void TIM4_IRQHandler() __attribute__ ((alias ("PIOS_TIM4_irq_handler")));
|
||||
const struct pios_pwm_cfg pios_pwm_cfg = {
|
||||
.tim_base_init = {
|
||||
.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1,
|
||||
.TIM_ClockDivision = TIM_CKD_DIV1,
|
||||
.TIM_CounterMode = TIM_CounterMode_Up,
|
||||
.TIM_Period = 0xFFFF,
|
||||
.TIM_RepetitionCounter = 0x0000,
|
||||
},
|
||||
.tim_ic_init = {
|
||||
.TIM_ICPolarity = TIM_ICPolarity_Rising,
|
||||
.TIM_ICSelection = TIM_ICSelection_DirectTI,
|
||||
.TIM_ICPrescaler = TIM_ICPSC_DIV1,
|
||||
.TIM_ICFilter = 0x0,
|
||||
.TIM_ICFilter = 0x0,
|
||||
},
|
||||
.gpio_init = {
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
.remap = 0,
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
.channels = pios_pwm_channels,
|
||||
.num_channels = NELEMENTS(pios_pwm_channels),
|
||||
.channels = pios_tim_rcvrport_all_channels,
|
||||
.num_channels = NELEMENTS(pios_tim_rcvrport_all_channels),
|
||||
};
|
||||
void PIOS_TIM2_irq_handler()
|
||||
{
|
||||
PIOS_PWM_irq_handler(TIM2);
|
||||
}
|
||||
void PIOS_TIM3_irq_handler()
|
||||
{
|
||||
PIOS_PWM_irq_handler(TIM3);
|
||||
}
|
||||
void PIOS_TIM4_irq_handler()
|
||||
{
|
||||
PIOS_PWM_irq_handler(TIM4);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PIOS_INCLUDE_I2C)
|
||||
@ -856,11 +908,19 @@ void PIOS_I2C_main_adapter_er_irq_handler(void)
|
||||
|
||||
#endif /* PIOS_INCLUDE_I2C */
|
||||
|
||||
#if defined(PIOS_INCLUDE_GCSRCVR)
|
||||
#include "pios_gcsrcvr_priv.h"
|
||||
#endif /* PIOS_INCLUDE_GCSRCVR */
|
||||
|
||||
#if defined(PIOS_INCLUDE_RCVR)
|
||||
#include "pios_rcvr_priv.h"
|
||||
|
||||
struct pios_rcvr_channel_map pios_rcvr_channel_to_id_map[PIOS_RCVR_MAX_CHANNELS];
|
||||
uint32_t pios_rcvr_max_channel;
|
||||
/* One slot per selectable receiver group.
|
||||
* eg. PWM, PPM, GCS, SPEKTRUM1, SPEKTRUM2, SBUS
|
||||
* NOTE: No slot in this map for NONE.
|
||||
*/
|
||||
uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE];
|
||||
|
||||
#endif /* PIOS_INCLUDE_RCVR */
|
||||
|
||||
#if defined(PIOS_INCLUDE_USB_HID)
|
||||
@ -909,7 +969,6 @@ void PIOS_Board_Init(void) {
|
||||
UAVObjInitialize();
|
||||
|
||||
HwSettingsInitialize();
|
||||
ManualControlSettingsInitialize();
|
||||
|
||||
#if defined(PIOS_INCLUDE_RTC)
|
||||
/* Initialize the real-time clock and its associated tick */
|
||||
@ -922,6 +981,12 @@ void PIOS_Board_Init(void) {
|
||||
/* Initialize the task monitor library */
|
||||
TaskMonitorInitialize();
|
||||
|
||||
/* Set up pulse timers */
|
||||
PIOS_TIM_InitClock(&tim_1_cfg);
|
||||
PIOS_TIM_InitClock(&tim_2_cfg);
|
||||
PIOS_TIM_InitClock(&tim_3_cfg);
|
||||
PIOS_TIM_InitClock(&tim_4_cfg);
|
||||
|
||||
/* Configure the main IO port */
|
||||
uint8_t hwsettings_DSMxBind;
|
||||
HwSettingsDSMxBindGet(&hwsettings_DSMxBind);
|
||||
@ -963,6 +1028,13 @@ void PIOS_Board_Init(void) {
|
||||
if (PIOS_SBUS_Init(&pios_sbus_id, &pios_sbus_cfg, &pios_usart_com_driver, pios_usart_sbus_id)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
|
||||
uint32_t pios_sbus_rcvr_id;
|
||||
if (PIOS_RCVR_Init(&pios_sbus_rcvr_id, &pios_sbus_rcvr_driver, pios_sbus_id)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS] = pios_sbus_rcvr_id;
|
||||
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_SBUS */
|
||||
break;
|
||||
@ -984,7 +1056,8 @@ void PIOS_Board_Init(void) {
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_GPS */
|
||||
break;
|
||||
case HWSETTINGS_CC_MAINPORT_SPEKTRUM:
|
||||
case HWSETTINGS_CC_MAINPORT_SPEKTRUM1:
|
||||
case HWSETTINGS_CC_MAINPORT_SPEKTRUM2:
|
||||
#if defined(PIOS_INCLUDE_SPEKTRUM)
|
||||
{
|
||||
uint32_t pios_usart_spektrum_id;
|
||||
@ -996,6 +1069,16 @@ void PIOS_Board_Init(void) {
|
||||
if (PIOS_SPEKTRUM_Init(&pios_spektrum_id, &pios_spektrum_main_cfg, &pios_usart_com_driver, pios_usart_spektrum_id, 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)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
if (hwsettings_cc_mainport == HWSETTINGS_CC_MAINPORT_SPEKTRUM1) {
|
||||
pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM1] = pios_spektrum_rcvr_id;
|
||||
} else {
|
||||
pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM2] = pios_spektrum_rcvr_id;
|
||||
}
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_SPEKTRUM */
|
||||
break;
|
||||
@ -1046,7 +1129,8 @@ void PIOS_Board_Init(void) {
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_GPS */
|
||||
break;
|
||||
case HWSETTINGS_CC_FLEXIPORT_SPEKTRUM:
|
||||
case HWSETTINGS_CC_FLEXIPORT_SPEKTRUM1:
|
||||
case HWSETTINGS_CC_FLEXIPORT_SPEKTRUM2:
|
||||
#if defined(PIOS_INCLUDE_SPEKTRUM)
|
||||
{
|
||||
uint32_t pios_usart_spektrum_id;
|
||||
@ -1058,6 +1142,16 @@ void PIOS_Board_Init(void) {
|
||||
if (PIOS_SPEKTRUM_Init(&pios_spektrum_id, &pios_spektrum_flexi_cfg, &pios_usart_com_driver, pios_usart_spektrum_id, 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)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
if (hwsettings_cc_flexiport == HWSETTINGS_CC_FLEXIPORT_SPEKTRUM1) {
|
||||
pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM1] = pios_spektrum_rcvr_id;
|
||||
} else {
|
||||
pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM2] = pios_spektrum_rcvr_id;
|
||||
}
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_SPEKTRUM */
|
||||
break;
|
||||
@ -1074,83 +1168,61 @@ void PIOS_Board_Init(void) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Configure the selected receiver */
|
||||
uint8_t manualcontrolsettings_inputmode;
|
||||
ManualControlSettingsInputModeGet(&manualcontrolsettings_inputmode);
|
||||
/* Configure the rcvr port */
|
||||
uint8_t hwsettings_rcvrport;
|
||||
HwSettingsCC_RcvrPortGet(&hwsettings_rcvrport);
|
||||
|
||||
switch (manualcontrolsettings_inputmode) {
|
||||
case MANUALCONTROLSETTINGS_INPUTMODE_PWM:
|
||||
switch (hwsettings_rcvrport) {
|
||||
case HWSETTINGS_CC_RCVRPORT_DISABLED:
|
||||
break;
|
||||
case HWSETTINGS_CC_RCVRPORT_PWM:
|
||||
#if defined(PIOS_INCLUDE_PWM)
|
||||
PIOS_PWM_Init();
|
||||
uint32_t pios_pwm_rcvr_id;
|
||||
if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, 0)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
for (uint8_t i = 0;
|
||||
i < PIOS_PWM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map);
|
||||
i++) {
|
||||
pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_pwm_rcvr_id;
|
||||
pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i;
|
||||
pios_rcvr_max_channel++;
|
||||
{
|
||||
uint32_t pios_pwm_id;
|
||||
PIOS_PWM_Init(&pios_pwm_id, &pios_pwm_cfg);
|
||||
|
||||
uint32_t pios_pwm_rcvr_id;
|
||||
if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, pios_pwm_id)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PWM] = pios_pwm_rcvr_id;
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_PWM */
|
||||
break;
|
||||
case MANUALCONTROLSETTINGS_INPUTMODE_PPM:
|
||||
case HWSETTINGS_CC_RCVRPORT_PPM:
|
||||
#if defined(PIOS_INCLUDE_PPM)
|
||||
PIOS_PPM_Init();
|
||||
uint32_t pios_ppm_rcvr_id;
|
||||
if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, 0)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
for (uint8_t i = 0;
|
||||
i < PIOS_PPM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map);
|
||||
i++) {
|
||||
pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_ppm_rcvr_id;
|
||||
pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i;
|
||||
pios_rcvr_max_channel++;
|
||||
{
|
||||
uint32_t pios_ppm_id;
|
||||
PIOS_PPM_Init(&pios_ppm_id, &pios_ppm_cfg);
|
||||
|
||||
uint32_t pios_ppm_rcvr_id;
|
||||
if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, pios_ppm_id)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM] = pios_ppm_rcvr_id;
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_PPM */
|
||||
break;
|
||||
case MANUALCONTROLSETTINGS_INPUTMODE_SPEKTRUM:
|
||||
#if defined(PIOS_INCLUDE_SPEKTRUM)
|
||||
if (hwsettings_cc_mainport == HWSETTINGS_CC_MAINPORT_SPEKTRUM ||
|
||||
hwsettings_cc_flexiport == HWSETTINGS_CC_FLEXIPORT_SPEKTRUM) {
|
||||
uint32_t pios_spektrum_rcvr_id;
|
||||
if (PIOS_RCVR_Init(&pios_spektrum_rcvr_id, &pios_spektrum_rcvr_driver, 0)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
for (uint8_t i = 0;
|
||||
i < PIOS_SPEKTRUM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map);
|
||||
i++) {
|
||||
pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_spektrum_rcvr_id;
|
||||
pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i;
|
||||
pios_rcvr_max_channel++;
|
||||
}
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_SPEKTRUM */
|
||||
break;
|
||||
case MANUALCONTROLSETTINGS_INPUTMODE_SBUS:
|
||||
#if defined(PIOS_INCLUDE_SBUS)
|
||||
if (hwsettings_cc_mainport == HWSETTINGS_CC_MAINPORT_SBUS) {
|
||||
uint32_t pios_sbus_rcvr_id;
|
||||
if (PIOS_RCVR_Init(&pios_sbus_rcvr_id, &pios_sbus_rcvr_driver, 0)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
for (uint8_t i = 0;
|
||||
i < SBUS_NUMBER_OF_CHANNELS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map);
|
||||
i++) {
|
||||
pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_sbus_rcvr_id;
|
||||
pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i;
|
||||
pios_rcvr_max_channel++;
|
||||
}
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_SBUS */
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(PIOS_INCLUDE_GCSRCVR)
|
||||
GCSReceiverInitialize();
|
||||
PIOS_GCSRCVR_Init();
|
||||
uint32_t pios_gcsrcvr_rcvr_id;
|
||||
if (PIOS_RCVR_Init(&pios_gcsrcvr_rcvr_id, &pios_gcsrcvr_rcvr_driver, 0)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_GCS] = pios_gcsrcvr_rcvr_id;
|
||||
#endif /* PIOS_INCLUDE_GCSRCVR */
|
||||
|
||||
/* Remap AFIO pin */
|
||||
GPIO_PinRemapConfig( GPIO_Remap_SWJ_NoJTRST, ENABLE);
|
||||
PIOS_Servo_Init();
|
||||
|
||||
#ifndef PIOS_DEBUG_ENABLE_DEBUG_PINS
|
||||
PIOS_Servo_Init(&pios_servo_cfg);
|
||||
#else
|
||||
PIOS_DEBUG_Init(&pios_tim_servo_all_channels, NELEMENTS(pios_tim_servo_all_channels));
|
||||
#endif /* PIOS_DEBUG_ENABLE_DEBUG_PINS */
|
||||
|
||||
PIOS_ADC_Init();
|
||||
PIOS_GPIO_Init();
|
||||
|
@ -363,7 +363,7 @@ $(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin
|
||||
$(eval $(call OPFW_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BOARD_TYPE),$(BOARD_REVISION)))
|
||||
|
||||
# Add jtag targets (program and wipe)
|
||||
$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE)))
|
||||
$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE),$(OPENOCD_CONFIG)))
|
||||
|
||||
.PHONY: elf lss sym hex bin bino opfw
|
||||
elf: $(OUTDIR)/$(TARGET).elf
|
||||
|
@ -24,6 +24,7 @@
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "pios.h"
|
||||
#include "ahrs_spi_comm.h"
|
||||
#include "pios_debug.h"
|
||||
|
||||
|
@ -42,7 +42,7 @@
|
||||
#include "mixersettings.h"
|
||||
#include "mixerstatus.h"
|
||||
#include "cameradesired.h"
|
||||
|
||||
#include "manualcontrolcommand.h"
|
||||
|
||||
// Private constants
|
||||
#define MAX_QUEUE_SIZE 2
|
||||
@ -74,7 +74,7 @@ static void actuatorTask(void* parameters);
|
||||
static void actuator_update_rate(UAVObjEvent *);
|
||||
static int16_t scaleChannel(float value, int16_t max, int16_t min, int16_t neutral);
|
||||
static void setFailsafe();
|
||||
static float MixerCurve(const float throttle, const float* curve);
|
||||
static float MixerCurve(const float throttle, const float* curve, uint8_t elements);
|
||||
static bool set_channel(uint8_t mixer_channel, uint16_t value);
|
||||
float ProcessMixer(const int index, const float curve1, const float curve2,
|
||||
MixerSettingsData* mixerSettings, ActuatorDesiredData* desired,
|
||||
@ -219,22 +219,29 @@ static void actuatorTask(void* parameters)
|
||||
bool positiveThrottle = desired.Throttle >= 0.00;
|
||||
bool spinWhileArmed = MotorsSpinWhileArmed == ACTUATORSETTINGS_MOTORSSPINWHILEARMED_TRUE;
|
||||
|
||||
float curve1 = MixerCurve(desired.Throttle,mixerSettings.ThrottleCurve1);
|
||||
float curve1 = MixerCurve(desired.Throttle,mixerSettings.ThrottleCurve1,MIXERSETTINGS_THROTTLECURVE1_NUMELEM);
|
||||
|
||||
//The source for the secondary curve is selectable
|
||||
float curve2 = 0;
|
||||
AccessoryDesiredData accessory;
|
||||
switch(mixerSettings.Curve2Source) {
|
||||
case MIXERSETTINGS_CURVE2SOURCE_THROTTLE:
|
||||
curve2 = MixerCurve(desired.Throttle,mixerSettings.ThrottleCurve2);
|
||||
curve2 = MixerCurve(desired.Throttle,mixerSettings.ThrottleCurve2,MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
||||
break;
|
||||
case MIXERSETTINGS_CURVE2SOURCE_ROLL:
|
||||
curve2 = MixerCurve(desired.Roll,mixerSettings.ThrottleCurve2);
|
||||
curve2 = MixerCurve(desired.Roll,mixerSettings.ThrottleCurve2,MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
||||
break;
|
||||
case MIXERSETTINGS_CURVE2SOURCE_PITCH:
|
||||
curve2 = MixerCurve(desired.Pitch,mixerSettings.ThrottleCurve2);
|
||||
curve2 = MixerCurve(desired.Pitch,mixerSettings.ThrottleCurve2,
|
||||
MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
||||
break;
|
||||
case MIXERSETTINGS_CURVE2SOURCE_YAW:
|
||||
curve2 = MixerCurve(desired.Yaw,mixerSettings.ThrottleCurve2);
|
||||
curve2 = MixerCurve(desired.Yaw,mixerSettings.ThrottleCurve2,MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
||||
break;
|
||||
case MIXERSETTINGS_CURVE2SOURCE_COLLECTIVE:
|
||||
ManualControlCommandCollectiveGet(&curve2);
|
||||
curve2 = MixerCurve(curve2,mixerSettings.ThrottleCurve2,
|
||||
MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
||||
break;
|
||||
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY0:
|
||||
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY1:
|
||||
@ -243,7 +250,7 @@ static void actuatorTask(void* parameters)
|
||||
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY4:
|
||||
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY5:
|
||||
if(AccessoryDesiredInstGet(mixerSettings.Curve2Source - MIXERSETTINGS_CURVE2SOURCE_ACCESSORY0,&accessory) == 0)
|
||||
curve2 = MixerCurve(accessory.AccessoryVal,mixerSettings.ThrottleCurve2);
|
||||
curve2 = MixerCurve(accessory.AccessoryVal,mixerSettings.ThrottleCurve2,MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
||||
else
|
||||
curve2 = 0;
|
||||
break;
|
||||
@ -423,12 +430,9 @@ float ProcessMixer(const int index, const float curve1, const float curve2,
|
||||
*Interpolate a throttle curve. Throttle input should be in the range 0 to 1.
|
||||
*Output is in the range 0 to 1.
|
||||
*/
|
||||
|
||||
#define MIXER_CURVE_ENTRIES 5
|
||||
|
||||
static float MixerCurve(const float throttle, const float* curve)
|
||||
static float MixerCurve(const float throttle, const float* curve, uint8_t elements)
|
||||
{
|
||||
float scale = throttle * MIXER_CURVE_ENTRIES;
|
||||
float scale = throttle * (elements - 1);
|
||||
int idx1 = scale;
|
||||
scale -= (float)idx1; //remainder
|
||||
if(curve[0] < -1)
|
||||
@ -441,12 +445,12 @@ static float MixerCurve(const float throttle, const float* curve)
|
||||
scale = 0;
|
||||
}
|
||||
int idx2 = idx1 + 1;
|
||||
if(idx2 >= MIXER_CURVE_ENTRIES)
|
||||
if(idx2 >= elements)
|
||||
{
|
||||
idx2 = MIXER_CURVE_ENTRIES -1; //clamp to highest entry in table
|
||||
if(idx1 >= MIXER_CURVE_ENTRIES)
|
||||
idx2 = elements -1; //clamp to highest entry in table
|
||||
if(idx1 >= elements)
|
||||
{
|
||||
idx1 = MIXER_CURVE_ENTRIES -1;
|
||||
idx1 = elements -1;
|
||||
}
|
||||
}
|
||||
return((curve[idx1] * (1 - scale)) + (curve[idx2] * scale));
|
||||
|
@ -105,4 +105,11 @@ int32_t ManualControlInitialize();
|
||||
( (int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_POSITIONHOLD == (int) FLIGHTSTATUS_FLIGHTMODE_POSITIONHOLD) \
|
||||
)
|
||||
|
||||
#define assumptions_channelcount ( \
|
||||
( (int)MANUALCONTROLCOMMAND_CHANNEL_NUMELEM == (int)MANUALCONTROLSETTINGS_CHANNELGROUPS_NUMELEM ) && \
|
||||
( (int)MANUALCONTROLCOMMAND_CHANNEL_NUMELEM == (int)MANUALCONTROLSETTINGS_CHANNELNUMBER_NUMELEM ) && \
|
||||
( (int)MANUALCONTROLCOMMAND_CHANNEL_NUMELEM == (int)MANUALCONTROLSETTINGS_CHANNELMIN_NUMELEM ) && \
|
||||
( (int)MANUALCONTROLCOMMAND_CHANNEL_NUMELEM == (int)MANUALCONTROLSETTINGS_CHANNELMAX_NUMELEM ) && \
|
||||
( (int)MANUALCONTROLCOMMAND_CHANNEL_NUMELEM == (int)MANUALCONTROLSETTINGS_CHANNELNEUTRAL_NUMELEM ) )
|
||||
|
||||
#endif // MANUALCONTROL_H
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "flighttelemetrystats.h"
|
||||
#include "flightstatus.h"
|
||||
#include "accessorydesired.h"
|
||||
#include "receiveractivity.h"
|
||||
|
||||
// Private constants
|
||||
#if defined(PIOS_MANUAL_STACK_SIZE)
|
||||
@ -80,6 +81,7 @@ static void updateActuatorDesired(ManualControlCommandData * cmd);
|
||||
static void updateStabilizationDesired(ManualControlCommandData * cmd, ManualControlSettingsData * settings);
|
||||
static void processFlightMode(ManualControlSettingsData * settings, float flightMode);
|
||||
static void processArm(ManualControlCommandData * cmd, ManualControlSettingsData * settings);
|
||||
static void setArmedIfChanged(uint8_t val);
|
||||
|
||||
static void manualControlTask(void *parameters);
|
||||
static float scaleChannel(int16_t value, int16_t max, int16_t min, int16_t neutral);
|
||||
@ -87,7 +89,19 @@ static uint32_t timeDifferenceMs(portTickType start_time, portTickType end_time)
|
||||
static bool okToArm(void);
|
||||
static bool validInputRange(int16_t min, int16_t max, uint16_t value);
|
||||
|
||||
#define assumptions (assumptions1 && assumptions3 && assumptions5 && assumptions7 && assumptions8 && assumptions_flightmode)
|
||||
#define RCVR_ACTIVITY_MONITOR_CHANNELS_PER_GROUP 12
|
||||
#define RCVR_ACTIVITY_MONITOR_MIN_RANGE 10
|
||||
struct rcvr_activity_fsm {
|
||||
ManualControlSettingsChannelGroupsOptions group;
|
||||
uint16_t prev[RCVR_ACTIVITY_MONITOR_CHANNELS_PER_GROUP];
|
||||
uint8_t sample_count;
|
||||
};
|
||||
static struct rcvr_activity_fsm activity_fsm;
|
||||
|
||||
static void resetRcvrActivity(struct rcvr_activity_fsm * fsm);
|
||||
static bool updateRcvrActivity(struct rcvr_activity_fsm * fsm);
|
||||
|
||||
#define assumptions (assumptions1 && assumptions3 && assumptions5 && assumptions7 && assumptions8 && assumptions_flightmode && assumptions_channelcount)
|
||||
|
||||
/**
|
||||
* Module starting
|
||||
@ -116,7 +130,7 @@ int32_t ManualControlInitialize()
|
||||
ManualControlCommandInitialize();
|
||||
FlightStatusInitialize();
|
||||
StabilizationDesiredInitialize();
|
||||
|
||||
ReceiverActivityInitialize();
|
||||
ManualControlSettingsInitialize();
|
||||
|
||||
return 0;
|
||||
@ -147,10 +161,14 @@ static void manualControlTask(void *parameters)
|
||||
flightStatus.Armed = FLIGHTSTATUS_ARMED_DISARMED;
|
||||
armState = ARM_STATE_DISARMED;
|
||||
|
||||
/* Initialize the RcvrActivty FSM */
|
||||
portTickType lastActivityTime = xTaskGetTickCount();
|
||||
resetRcvrActivity(&activity_fsm);
|
||||
|
||||
// Main task loop
|
||||
lastSysTime = xTaskGetTickCount();
|
||||
while (1) {
|
||||
float scaledChannel[MANUALCONTROLCOMMAND_CHANNEL_NUMELEM];
|
||||
float scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_NUMELEM];
|
||||
|
||||
// Wait until next update
|
||||
vTaskDelayUntil(&lastSysTime, UPDATE_PERIOD_MS / portTICK_RATE_MS);
|
||||
@ -159,6 +177,18 @@ static void manualControlTask(void *parameters)
|
||||
// Read settings
|
||||
ManualControlSettingsGet(&settings);
|
||||
|
||||
/* Update channel activity monitor */
|
||||
if (flightStatus.Armed == ARM_STATE_DISARMED) {
|
||||
if (updateRcvrActivity(&activity_fsm)) {
|
||||
/* Reset the aging timer because activity was detected */
|
||||
lastActivityTime = lastSysTime;
|
||||
}
|
||||
}
|
||||
if (timeDifferenceMs(lastActivityTime, lastSysTime) > 5000) {
|
||||
resetRcvrActivity(&activity_fsm);
|
||||
lastActivityTime = lastSysTime;
|
||||
}
|
||||
|
||||
if (ManualControlCommandReadOnly(&cmd)) {
|
||||
FlightTelemetryStatsData flightTelemStats;
|
||||
FlightTelemetryStatsGet(&flightTelemStats);
|
||||
@ -173,34 +203,64 @@ static void manualControlTask(void *parameters)
|
||||
|
||||
if (!ManualControlCommandReadOnly(&cmd)) {
|
||||
|
||||
bool valid_input_detected = true;
|
||||
|
||||
// Read channel values in us
|
||||
for (int n = 0; n < MANUALCONTROLCOMMAND_CHANNEL_NUMELEM; ++n) {
|
||||
if (pios_rcvr_channel_to_id_map[n].id) {
|
||||
cmd.Channel[n] = PIOS_RCVR_Read(pios_rcvr_channel_to_id_map[n].id,
|
||||
pios_rcvr_channel_to_id_map[n].channel);
|
||||
for (uint8_t n = 0;
|
||||
n < MANUALCONTROLSETTINGS_CHANNELGROUPS_NUMELEM && n < MANUALCONTROLCOMMAND_CHANNEL_NUMELEM;
|
||||
++n) {
|
||||
extern uint32_t pios_rcvr_group_map[];
|
||||
|
||||
if (settings.ChannelGroups[n] >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) {
|
||||
cmd.Channel[n] = PIOS_RCVR_INVALID;
|
||||
} else {
|
||||
cmd.Channel[n] = -1;
|
||||
cmd.Channel[n] = PIOS_RCVR_Read(pios_rcvr_group_map[settings.ChannelGroups[n]],
|
||||
settings.ChannelNumber[n]);
|
||||
}
|
||||
scaledChannel[n] = scaleChannel(cmd.Channel[n], settings.ChannelMax[n], settings.ChannelMin[n], settings.ChannelNeutral[n]);
|
||||
|
||||
// If a channel has timed out this is not valid data and we shouldn't update anything
|
||||
// until we decide to go to failsafe
|
||||
if(cmd.Channel[n] == PIOS_RCVR_TIMEOUT)
|
||||
valid_input_detected = false;
|
||||
else
|
||||
scaledChannel[n] = scaleChannel(cmd.Channel[n], settings.ChannelMax[n], settings.ChannelMin[n], settings.ChannelNeutral[n]);
|
||||
}
|
||||
|
||||
// Check settings, if error raise alarm
|
||||
if (settings.Roll >= MANUALCONTROLSETTINGS_ROLL_NONE ||
|
||||
settings.Pitch >= MANUALCONTROLSETTINGS_PITCH_NONE ||
|
||||
settings.Yaw >= MANUALCONTROLSETTINGS_YAW_NONE ||
|
||||
settings.Throttle >= MANUALCONTROLSETTINGS_THROTTLE_NONE ||
|
||||
settings.FlightMode >= MANUALCONTROLSETTINGS_FLIGHTMODE_NONE) {
|
||||
if (settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_ROLL] >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE ||
|
||||
settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_PITCH] >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE ||
|
||||
settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_YAW] >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE ||
|
||||
settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_THROTTLE] >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE ||
|
||||
settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_FLIGHTMODE] >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE ||
|
||||
// Check all channel mappings are valid
|
||||
cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_ROLL] == (uint16_t) PIOS_RCVR_INVALID ||
|
||||
cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_PITCH] == (uint16_t) PIOS_RCVR_INVALID ||
|
||||
cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_YAW] == (uint16_t) PIOS_RCVR_INVALID ||
|
||||
cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_THROTTLE] == (uint16_t) PIOS_RCVR_INVALID ||
|
||||
cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_FLIGHTMODE] == (uint16_t) PIOS_RCVR_INVALID ||
|
||||
// Check the driver is exists
|
||||
cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_ROLL] == (uint16_t) PIOS_RCVR_NODRIVER ||
|
||||
cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_PITCH] == (uint16_t) PIOS_RCVR_NODRIVER ||
|
||||
cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_YAW] == (uint16_t) PIOS_RCVR_NODRIVER ||
|
||||
cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_THROTTLE] == (uint16_t) PIOS_RCVR_NODRIVER ||
|
||||
cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_FLIGHTMODE] == (uint16_t) PIOS_RCVR_NODRIVER) {
|
||||
|
||||
AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_CRITICAL);
|
||||
cmd.Connected = MANUALCONTROLCOMMAND_CONNECTED_FALSE;
|
||||
ManualControlCommandSet(&cmd);
|
||||
|
||||
// Need to do this here since we don't process armed status. Since this shouldn't happen in flight (changed config)
|
||||
// immediately disarm
|
||||
setArmedIfChanged(FLIGHTSTATUS_ARMED_DISARMED);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// decide if we have valid manual input or not
|
||||
bool valid_input_detected = validInputRange(settings.ChannelMin[settings.Throttle], settings.ChannelMax[settings.Throttle], cmd.Channel[settings.Throttle]) &&
|
||||
validInputRange(settings.ChannelMin[settings.Roll], settings.ChannelMax[settings.Roll], cmd.Channel[settings.Roll]) &&
|
||||
validInputRange(settings.ChannelMin[settings.Yaw], settings.ChannelMax[settings.Yaw], cmd.Channel[settings.Yaw]) &&
|
||||
validInputRange(settings.ChannelMin[settings.Pitch], settings.ChannelMax[settings.Pitch], cmd.Channel[settings.Pitch]);
|
||||
valid_input_detected &= validInputRange(settings.ChannelMin[MANUALCONTROLSETTINGS_CHANNELGROUPS_THROTTLE], settings.ChannelMax[MANUALCONTROLSETTINGS_CHANNELGROUPS_THROTTLE], cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_THROTTLE]) &&
|
||||
validInputRange(settings.ChannelMin[MANUALCONTROLSETTINGS_CHANNELGROUPS_ROLL], settings.ChannelMax[MANUALCONTROLSETTINGS_CHANNELGROUPS_ROLL], cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_ROLL]) &&
|
||||
validInputRange(settings.ChannelMin[MANUALCONTROLSETTINGS_CHANNELGROUPS_YAW], settings.ChannelMax[MANUALCONTROLSETTINGS_CHANNELGROUPS_YAW], cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_YAW]) &&
|
||||
validInputRange(settings.ChannelMin[MANUALCONTROLSETTINGS_CHANNELGROUPS_PITCH], settings.ChannelMax[MANUALCONTROLSETTINGS_CHANNELGROUPS_PITCH], cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_PITCH]);
|
||||
|
||||
// Implement hysteresis loop on connection status
|
||||
if (valid_input_detected && (++connected_count > 10)) {
|
||||
@ -218,55 +278,88 @@ static void manualControlTask(void *parameters)
|
||||
cmd.Roll = 0;
|
||||
cmd.Yaw = 0;
|
||||
cmd.Pitch = 0;
|
||||
cmd.Collective = 0;
|
||||
//cmd.FlightMode = MANUALCONTROLCOMMAND_FLIGHTMODE_AUTO; // don't do until AUTO implemented and functioning
|
||||
// Important: Throttle < 0 will reset Stabilization coefficients among other things. Either change this,
|
||||
// or leave throttle at IDLE speed or above when going into AUTO-failsafe.
|
||||
AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING);
|
||||
ManualControlCommandSet(&cmd);
|
||||
} else {
|
||||
AlarmsClear(SYSTEMALARMS_ALARM_MANUALCONTROL);
|
||||
|
||||
// Scale channels to -1 -> +1 range
|
||||
cmd.Roll = scaledChannel[settings.Roll];
|
||||
cmd.Pitch = scaledChannel[settings.Pitch];
|
||||
cmd.Yaw = scaledChannel[settings.Yaw];
|
||||
cmd.Throttle = scaledChannel[settings.Throttle];
|
||||
flightMode = scaledChannel[settings.FlightMode];
|
||||
|
||||
|
||||
AccessoryDesiredData accessory;
|
||||
// Set Accessory 0
|
||||
if(settings.Accessory0 != MANUALCONTROLSETTINGS_ACCESSORY0_NONE) {
|
||||
accessory.AccessoryVal = scaledChannel[settings.Accessory0];
|
||||
if (settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY0] !=
|
||||
MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) {
|
||||
accessory.AccessoryVal = 0;
|
||||
if(AccessoryDesiredInstSet(0, &accessory) != 0)
|
||||
AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING);
|
||||
}
|
||||
// Set Accessory 1
|
||||
if(settings.Accessory1 != MANUALCONTROLSETTINGS_ACCESSORY1_NONE) {
|
||||
accessory.AccessoryVal = scaledChannel[settings.Accessory1];
|
||||
if (settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY1] !=
|
||||
MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) {
|
||||
accessory.AccessoryVal = 0;
|
||||
if(AccessoryDesiredInstSet(1, &accessory) != 0)
|
||||
AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING);
|
||||
}
|
||||
// Set Accsesory 2
|
||||
if(settings.Accessory2 != MANUALCONTROLSETTINGS_ACCESSORY2_NONE) {
|
||||
accessory.AccessoryVal = scaledChannel[settings.Accessory2];
|
||||
// Set Accessory 2
|
||||
if (settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY2] !=
|
||||
MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) {
|
||||
accessory.AccessoryVal = 0;
|
||||
if(AccessoryDesiredInstSet(2, &accessory) != 0)
|
||||
AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING);
|
||||
}
|
||||
|
||||
} else {
|
||||
AlarmsClear(SYSTEMALARMS_ALARM_MANUALCONTROL);
|
||||
|
||||
// Scale channels to -1 -> +1 range
|
||||
cmd.Roll = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_ROLL];
|
||||
cmd.Pitch = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_PITCH];
|
||||
cmd.Yaw = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_YAW];
|
||||
cmd.Throttle = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_THROTTLE];
|
||||
flightMode = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_FLIGHTMODE];
|
||||
|
||||
if(cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_COLLECTIVE] != PIOS_RCVR_INVALID &&
|
||||
cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_COLLECTIVE] != PIOS_RCVR_NODRIVER &&
|
||||
cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_COLLECTIVE] != PIOS_RCVR_TIMEOUT)
|
||||
cmd.Collective = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_COLLECTIVE];
|
||||
|
||||
AccessoryDesiredData accessory;
|
||||
// Set Accessory 0
|
||||
if (settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY0] !=
|
||||
MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) {
|
||||
accessory.AccessoryVal = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY0];
|
||||
if(AccessoryDesiredInstSet(0, &accessory) != 0)
|
||||
AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING);
|
||||
}
|
||||
// Set Accessory 1
|
||||
if (settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY1] !=
|
||||
MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) {
|
||||
accessory.AccessoryVal = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY1];
|
||||
if(AccessoryDesiredInstSet(1, &accessory) != 0)
|
||||
AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING);
|
||||
}
|
||||
// Set Accessory 2
|
||||
if (settings.ChannelGroups[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY2] !=
|
||||
MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) {
|
||||
accessory.AccessoryVal = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY2];
|
||||
if(AccessoryDesiredInstSet(2, &accessory) != 0)
|
||||
AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING);
|
||||
}
|
||||
|
||||
|
||||
processFlightMode(&settings, flightMode);
|
||||
processArm(&cmd, &settings);
|
||||
|
||||
// Update cmd object
|
||||
ManualControlCommandSet(&cmd);
|
||||
|
||||
}
|
||||
|
||||
// Process arming outside conditional so system will disarm when disconnected
|
||||
processArm(&cmd, &settings);
|
||||
|
||||
// Update cmd object
|
||||
ManualControlCommandSet(&cmd);
|
||||
|
||||
} else {
|
||||
ManualControlCommandGet(&cmd); /* Under GCS control */
|
||||
}
|
||||
|
||||
|
||||
FlightStatusGet(&flightStatus);
|
||||
|
||||
// Depending on the mode update the Stabilization or Actuator objects
|
||||
@ -288,6 +381,145 @@ static void manualControlTask(void *parameters)
|
||||
}
|
||||
}
|
||||
|
||||
static void resetRcvrActivity(struct rcvr_activity_fsm * fsm)
|
||||
{
|
||||
ReceiverActivityData data;
|
||||
bool updated = false;
|
||||
|
||||
/* Clear all channel activity flags */
|
||||
ReceiverActivityGet(&data);
|
||||
if (data.ActiveGroup != RECEIVERACTIVITY_ACTIVEGROUP_NONE &&
|
||||
data.ActiveChannel != 255) {
|
||||
data.ActiveGroup = RECEIVERACTIVITY_ACTIVEGROUP_NONE;
|
||||
data.ActiveChannel = 255;
|
||||
updated = true;
|
||||
}
|
||||
if (updated) {
|
||||
ReceiverActivitySet(&data);
|
||||
}
|
||||
|
||||
/* Reset the FSM state */
|
||||
fsm->group = 0;
|
||||
fsm->sample_count = 0;
|
||||
}
|
||||
|
||||
static void updateRcvrActivitySample(uint32_t rcvr_id, uint16_t samples[], uint8_t max_channels) {
|
||||
for (uint8_t channel = 1; channel <= max_channels; channel++) {
|
||||
// Subtract 1 because channels are 1 indexed
|
||||
samples[channel - 1] = PIOS_RCVR_Read(rcvr_id, channel);
|
||||
}
|
||||
}
|
||||
|
||||
static bool updateRcvrActivityCompare(uint32_t rcvr_id, struct rcvr_activity_fsm * fsm)
|
||||
{
|
||||
bool activity_updated = false;
|
||||
|
||||
/* Compare the current value to the previous sampled value */
|
||||
for (uint8_t channel = 1;
|
||||
channel <= RCVR_ACTIVITY_MONITOR_CHANNELS_PER_GROUP;
|
||||
channel++) {
|
||||
uint16_t delta;
|
||||
uint16_t prev = fsm->prev[channel - 1]; // Subtract 1 because channels are 1 indexed
|
||||
uint16_t curr = PIOS_RCVR_Read(rcvr_id, channel);
|
||||
if (curr > prev) {
|
||||
delta = curr - prev;
|
||||
} else {
|
||||
delta = prev - curr;
|
||||
}
|
||||
|
||||
if (delta > RCVR_ACTIVITY_MONITOR_MIN_RANGE) {
|
||||
/* Mark this channel as active */
|
||||
ReceiverActivityActiveGroupOptions group;
|
||||
|
||||
/* Don't assume manualcontrolsettings and receiveractivity are in the same order. */
|
||||
switch (fsm->group) {
|
||||
case MANUALCONTROLSETTINGS_CHANNELGROUPS_PWM:
|
||||
group = RECEIVERACTIVITY_ACTIVEGROUP_PWM;
|
||||
break;
|
||||
case MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM:
|
||||
group = RECEIVERACTIVITY_ACTIVEGROUP_PPM;
|
||||
break;
|
||||
case MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM1:
|
||||
group = RECEIVERACTIVITY_ACTIVEGROUP_SPEKTRUM1;
|
||||
break;
|
||||
case MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM2:
|
||||
group = RECEIVERACTIVITY_ACTIVEGROUP_SPEKTRUM2;
|
||||
break;
|
||||
case MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS:
|
||||
group = RECEIVERACTIVITY_ACTIVEGROUP_SBUS;
|
||||
break;
|
||||
case MANUALCONTROLSETTINGS_CHANNELGROUPS_GCS:
|
||||
group = RECEIVERACTIVITY_ACTIVEGROUP_GCS;
|
||||
break;
|
||||
default:
|
||||
PIOS_Assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
ReceiverActivityActiveGroupSet(&group);
|
||||
ReceiverActivityActiveChannelSet(&channel);
|
||||
activity_updated = true;
|
||||
}
|
||||
}
|
||||
return (activity_updated);
|
||||
}
|
||||
|
||||
static bool updateRcvrActivity(struct rcvr_activity_fsm * fsm)
|
||||
{
|
||||
bool activity_updated = false;
|
||||
|
||||
if (fsm->group >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) {
|
||||
/* We're out of range, reset things */
|
||||
resetRcvrActivity(fsm);
|
||||
}
|
||||
|
||||
extern uint32_t pios_rcvr_group_map[];
|
||||
if (!pios_rcvr_group_map[fsm->group]) {
|
||||
/* Unbound group, skip it */
|
||||
goto group_completed;
|
||||
}
|
||||
|
||||
if (fsm->sample_count == 0) {
|
||||
/* Take a sample of each channel in this group */
|
||||
updateRcvrActivitySample(pios_rcvr_group_map[fsm->group],
|
||||
fsm->prev,
|
||||
NELEMENTS(fsm->prev));
|
||||
fsm->sample_count++;
|
||||
return (false);
|
||||
}
|
||||
|
||||
/* Compare with previous sample */
|
||||
activity_updated = updateRcvrActivityCompare(pios_rcvr_group_map[fsm->group], fsm);
|
||||
|
||||
group_completed:
|
||||
/* Reset the sample counter */
|
||||
fsm->sample_count = 0;
|
||||
|
||||
/* Find the next active group, but limit search so we can't loop forever here */
|
||||
for (uint8_t i = 0; i < MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE; i++) {
|
||||
/* Move to the next group */
|
||||
fsm->group++;
|
||||
if (fsm->group >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) {
|
||||
/* Wrap back to the first group */
|
||||
fsm->group = 0;
|
||||
}
|
||||
if (pios_rcvr_group_map[fsm->group]) {
|
||||
/*
|
||||
* Found an active group, take a sample here to avoid an
|
||||
* extra 20ms delay in the main thread so we can speed up
|
||||
* this algorithm.
|
||||
*/
|
||||
updateRcvrActivitySample(pios_rcvr_group_map[fsm->group],
|
||||
fsm->prev,
|
||||
NELEMENTS(fsm->prev));
|
||||
fsm->sample_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (activity_updated);
|
||||
}
|
||||
|
||||
static void updateActuatorDesired(ManualControlCommandData * cmd)
|
||||
{
|
||||
ActuatorDesiredData actuator;
|
||||
@ -449,7 +681,7 @@ static void processArm(ManualControlCommandData * cmd, ManualControlSettingsData
|
||||
} else {
|
||||
// Not really needed since this function not called when disconnected
|
||||
if (cmd->Connected == MANUALCONTROLCOMMAND_CONNECTED_FALSE)
|
||||
return;
|
||||
lowThrottle = true;
|
||||
|
||||
// The throttle is not low, in case we where arming or disarming, abort
|
||||
if (!lowThrottle) {
|
||||
|
@ -235,6 +235,9 @@ static void stabilizationTask(void* parameters)
|
||||
{
|
||||
case STABILIZATIONDESIRED_STABILIZATIONMODE_RATE:
|
||||
rateDesiredAxis[i] = attitudeDesiredAxis[i];
|
||||
|
||||
// Zero attitude and axis lock accumulators
|
||||
pids[PID_ROLL + i].iAccumulator = 0;
|
||||
axis_lock_accum[i] = 0;
|
||||
break;
|
||||
|
||||
@ -249,11 +252,20 @@ static void stabilizationTask(void* parameters)
|
||||
|
||||
rateDesiredAxis[i] = attitudeDesiredAxis[i] + weak_leveling;
|
||||
|
||||
// Zero attitude and axis lock accumulators
|
||||
pids[PID_ROLL + i].iAccumulator = 0;
|
||||
axis_lock_accum[i] = 0;
|
||||
break;
|
||||
}
|
||||
case STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE:
|
||||
rateDesiredAxis[i] = ApplyPid(&pids[PID_ROLL + i], local_error[i]);
|
||||
|
||||
if(rateDesiredAxis[i] > settings.MaximumRate[i])
|
||||
rateDesiredAxis[i] = settings.MaximumRate[i];
|
||||
else if(rateDesiredAxis[i] < -settings.MaximumRate[i])
|
||||
rateDesiredAxis[i] = -settings.MaximumRate[i];
|
||||
|
||||
|
||||
axis_lock_accum[i] = 0;
|
||||
break;
|
||||
|
||||
@ -272,6 +284,12 @@ static void stabilizationTask(void* parameters)
|
||||
|
||||
rateDesiredAxis[i] = ApplyPid(&pids[PID_ROLL + i], axis_lock_accum[i]);
|
||||
}
|
||||
|
||||
if(rateDesiredAxis[i] > settings.MaximumRate[i])
|
||||
rateDesiredAxis[i] = settings.MaximumRate[i];
|
||||
else if(rateDesiredAxis[i] < -settings.MaximumRate[i])
|
||||
rateDesiredAxis[i] = -settings.MaximumRate[i];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -284,11 +302,6 @@ static void stabilizationTask(void* parameters)
|
||||
//Calculate desired command
|
||||
for(int8_t ct=0; ct< MAX_AXES; ct++)
|
||||
{
|
||||
if(rateDesiredAxis[ct] > settings.MaximumRate[ct])
|
||||
rateDesiredAxis[ct] = settings.MaximumRate[ct];
|
||||
else if(rateDesiredAxis[ct] < -settings.MaximumRate[ct])
|
||||
rateDesiredAxis[ct] = -settings.MaximumRate[ct];
|
||||
|
||||
switch(stabDesired.StabilizationMode[ct])
|
||||
{
|
||||
case STABILIZATIONDESIRED_STABILIZATIONMODE_RATE:
|
||||
@ -306,14 +319,20 @@ static void stabilizationTask(void* parameters)
|
||||
case ROLL:
|
||||
actuatorDesiredAxis[ct] = bound(attitudeDesiredAxis[ct]);
|
||||
shouldUpdate = 1;
|
||||
pids[PID_RATE_ROLL].iAccumulator = 0;
|
||||
pids[PID_ROLL].iAccumulator = 0;
|
||||
break;
|
||||
case PITCH:
|
||||
actuatorDesiredAxis[ct] = bound(attitudeDesiredAxis[ct]);
|
||||
shouldUpdate = 1;
|
||||
pids[PID_RATE_PITCH].iAccumulator = 0;
|
||||
pids[PID_PITCH].iAccumulator = 0;
|
||||
break;
|
||||
case YAW:
|
||||
actuatorDesiredAxis[ct] = bound(attitudeDesiredAxis[ct]);
|
||||
shouldUpdate = 1;
|
||||
pids[PID_RATE_YAW].iAccumulator = 0;
|
||||
pids[PID_YAW].iAccumulator = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -76,7 +76,8 @@
|
||||
static uint32_t idleCounter;
|
||||
static uint32_t idleCounterClear;
|
||||
static xTaskHandle systemTaskHandle;
|
||||
static int32_t stackOverflow;
|
||||
static bool stackOverflow;
|
||||
static bool mallocFailed;
|
||||
|
||||
// Private functions
|
||||
static void objectUpdatedCb(UAVObjEvent * ev);
|
||||
@ -94,7 +95,8 @@ static void updateWDGstats();
|
||||
int32_t SystemModStart(void)
|
||||
{
|
||||
// Initialize vars
|
||||
stackOverflow = 0;
|
||||
stackOverflow = false;
|
||||
mallocFailed = false;
|
||||
// Create system task
|
||||
xTaskCreate(systemTask, (signed char *)"System", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &systemTaskHandle);
|
||||
// Register task
|
||||
@ -423,12 +425,19 @@ static void updateSystemAlarms()
|
||||
}
|
||||
|
||||
// Check for stack overflow
|
||||
if (stackOverflow == 1) {
|
||||
if (stackOverflow) {
|
||||
AlarmsSet(SYSTEMALARMS_ALARM_STACKOVERFLOW, SYSTEMALARMS_ALARM_CRITICAL);
|
||||
} else {
|
||||
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) {
|
||||
@ -467,9 +476,29 @@ void vApplicationIdleHook(void)
|
||||
/**
|
||||
* Called by the RTOS when a stack overflow is detected.
|
||||
*/
|
||||
#define DEBUG_STACK_OVERFLOW 0
|
||||
void vApplicationStackOverflowHook(xTaskHandle * pxTask, signed portCHAR * pcTaskName)
|
||||
{
|
||||
stackOverflow = 1;
|
||||
stackOverflow = true;
|
||||
#if DEBUG_STACK_OVERFLOW
|
||||
static volatile bool wait_here = true;
|
||||
while(wait_here);
|
||||
wait_here = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the RTOS when a malloc call fails.
|
||||
*/
|
||||
#define DEBUG_MALLOC_FAILURES 0
|
||||
void vApplicationMallocFailedHook(void)
|
||||
{
|
||||
mallocFailed = true;
|
||||
#if DEBUG_MALLOC_FAILURES
|
||||
static volatile bool wait_here = true;
|
||||
while(wait_here);
|
||||
wait_here = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -171,6 +171,7 @@ SRC += $(PIOSSTM32F10X)/pios_ppm.c
|
||||
SRC += $(PIOSSTM32F10X)/pios_pwm.c
|
||||
SRC += $(PIOSSTM32F10X)/pios_spektrum.c
|
||||
SRC += $(PIOSSTM32F10X)/pios_sbus.c
|
||||
SRC += $(PIOSSTM32F10X)/pios_tim.c
|
||||
SRC += $(PIOSSTM32F10X)/pios_debug.c
|
||||
SRC += $(PIOSSTM32F10X)/pios_gpio.c
|
||||
SRC += $(PIOSSTM32F10X)/pios_exti.c
|
||||
@ -535,7 +536,7 @@ $(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin
|
||||
$(eval $(call OPFW_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BOARD_TYPE),$(BOARD_REVISION)))
|
||||
|
||||
# Add jtag targets (program and wipe)
|
||||
$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE)))
|
||||
$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE),$(OPENOCD_CONFIG)))
|
||||
|
||||
.PHONY: elf lss sym hex bin bino opfw
|
||||
elf: $(OUTDIR)/$(TARGET).elf
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define configUSE_PREEMPTION 1
|
||||
#define configUSE_IDLE_HOOK 1
|
||||
#define configUSE_TICK_HOOK 0
|
||||
#define configUSE_MALLOC_FAILED_HOOK 1
|
||||
#define configCPU_CLOCK_HZ ( ( unsigned long ) 72000000 )
|
||||
#define configTICK_RATE_HZ ( ( portTickType ) 1000 )
|
||||
#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 )
|
||||
|
@ -47,7 +47,7 @@
|
||||
#define PIOS_INCLUDE_SPEKTRUM
|
||||
//#define PIOS_INCLUDE_SBUS
|
||||
#define PIOS_INCLUDE_PWM
|
||||
//#define PIOS_INCLUDE_PPM
|
||||
#define PIOS_INCLUDE_PPM
|
||||
|
||||
#define PIOS_INCLUDE_TELEMETRY_RF
|
||||
|
||||
|
@ -30,8 +30,8 @@
|
||||
#include <pios.h>
|
||||
#include <openpilot.h>
|
||||
#include <uavobjectsinit.h>
|
||||
#include "manualcontrolsettings.h"
|
||||
#include "hwsettings.h"
|
||||
#include <hwsettings.h>
|
||||
#include <manualcontrolsettings.h>
|
||||
|
||||
//#define I2C_DEBUG_PIN 0
|
||||
//#define USART_GPS_DEBUG_PIN 1
|
||||
@ -302,6 +302,89 @@ void PIOS_ADC_handler() {
|
||||
PIOS_ADC_DMA_Handler();
|
||||
}
|
||||
|
||||
#include "pios_tim_priv.h"
|
||||
|
||||
static const TIM_TimeBaseInitTypeDef tim_4_8_time_base = {
|
||||
.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1,
|
||||
.TIM_ClockDivision = TIM_CKD_DIV1,
|
||||
.TIM_CounterMode = TIM_CounterMode_Up,
|
||||
.TIM_Period = ((1000000 / PIOS_SERVO_UPDATE_HZ) - 1),
|
||||
.TIM_RepetitionCounter = 0x0000,
|
||||
};
|
||||
|
||||
static const struct pios_tim_clock_cfg tim_4_cfg = {
|
||||
.timer = TIM4,
|
||||
.time_base_init = &tim_4_8_time_base,
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannel = TIM4_IRQn,
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct pios_tim_clock_cfg tim_8_cfg = {
|
||||
.timer = TIM8,
|
||||
.time_base_init = &tim_4_8_time_base,
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannel = TIM8_CC_IRQn,
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const TIM_TimeBaseInitTypeDef tim_1_3_5_time_base = {
|
||||
.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1,
|
||||
.TIM_ClockDivision = TIM_CKD_DIV1,
|
||||
.TIM_CounterMode = TIM_CounterMode_Up,
|
||||
.TIM_Period = 0xFFFF,
|
||||
.TIM_RepetitionCounter = 0x0000,
|
||||
};
|
||||
|
||||
static const struct pios_tim_clock_cfg tim_1_cfg = {
|
||||
.timer = TIM1,
|
||||
.time_base_init = &tim_1_3_5_time_base,
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannel = TIM1_CC_IRQn,
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct pios_tim_clock_cfg tim_3_cfg = {
|
||||
.timer = TIM3,
|
||||
.time_base_init = &tim_1_3_5_time_base,
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannel = TIM3_IRQn,
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct pios_tim_clock_cfg tim_5_cfg = {
|
||||
.timer = TIM5,
|
||||
.time_base_init = &tim_1_3_5_time_base,
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannel = TIM5_IRQn,
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
#if defined(PIOS_INCLUDE_USART)
|
||||
|
||||
#include "pios_usart_priv.h"
|
||||
@ -497,7 +580,6 @@ static const struct pios_usart_cfg pios_usart_spektrum_cfg = {
|
||||
},
|
||||
};
|
||||
|
||||
#include <pios_spektrum_priv.h>
|
||||
static const struct pios_spektrum_cfg pios_spektrum_cfg = {
|
||||
.bind = {
|
||||
.gpio = GPIOA,
|
||||
@ -536,65 +618,106 @@ static const struct pios_spektrum_cfg pios_spektrum_cfg = {
|
||||
* Pios servo configuration structures
|
||||
*/
|
||||
#include <pios_servo_priv.h>
|
||||
static const struct pios_servo_channel pios_servo_channels[] = {
|
||||
static const struct pios_tim_channel pios_tim_servoport_all_pins[] = {
|
||||
{
|
||||
.timer = TIM4,
|
||||
.port = GPIOB,
|
||||
.channel = TIM_Channel_1,
|
||||
.pin = GPIO_Pin_6,
|
||||
.timer_chan = TIM_Channel_1,
|
||||
.pin = {
|
||||
.gpio = GPIOB,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_6,
|
||||
.GPIO_Mode = GPIO_Mode_AF_PP,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.timer = TIM4,
|
||||
.port = GPIOB,
|
||||
.channel = TIM_Channel_2,
|
||||
.pin = GPIO_Pin_7,
|
||||
.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 = TIM4,
|
||||
.port = GPIOB,
|
||||
.channel = TIM_Channel_3,
|
||||
.pin = GPIO_Pin_8,
|
||||
.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,
|
||||
.port = GPIOB,
|
||||
.channel = TIM_Channel_4,
|
||||
.pin = GPIO_Pin_9,
|
||||
.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 = TIM8,
|
||||
.port = GPIOC,
|
||||
.channel = TIM_Channel_1,
|
||||
.pin = GPIO_Pin_6,
|
||||
.timer_chan = TIM_Channel_1,
|
||||
.pin = {
|
||||
.gpio = GPIOC,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_6,
|
||||
.GPIO_Mode = GPIO_Mode_AF_PP,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.timer = TIM8,
|
||||
.port = GPIOC,
|
||||
.channel = TIM_Channel_2,
|
||||
.pin = GPIO_Pin_7,
|
||||
.timer_chan = TIM_Channel_2,
|
||||
.pin = {
|
||||
.gpio = GPIOC,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_7,
|
||||
.GPIO_Mode = GPIO_Mode_AF_PP,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.timer = TIM8,
|
||||
.port = GPIOC,
|
||||
.channel = TIM_Channel_3,
|
||||
.pin = GPIO_Pin_8,
|
||||
.timer_chan = TIM_Channel_3,
|
||||
.pin = {
|
||||
.gpio = GPIOC,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_8,
|
||||
.GPIO_Mode = GPIO_Mode_AF_PP,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.timer = TIM8,
|
||||
.port = GPIOC,
|
||||
.channel = TIM_Channel_4,
|
||||
.pin = GPIO_Pin_9,
|
||||
.timer_chan = TIM_Channel_4,
|
||||
.pin = {
|
||||
.gpio = GPIOC,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_9,
|
||||
.GPIO_Mode = GPIO_Mode_AF_PP,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const struct pios_servo_cfg pios_servo_cfg = {
|
||||
.tim_base_init = {
|
||||
.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1,
|
||||
.TIM_ClockDivision = TIM_CKD_DIV1,
|
||||
.TIM_CounterMode = TIM_CounterMode_Up,
|
||||
.TIM_Period = ((1000000 / PIOS_SERVO_UPDATE_HZ) - 1),
|
||||
.TIM_RepetitionCounter = 0x0000,
|
||||
},
|
||||
.tim_oc_init = {
|
||||
.TIM_OCMode = TIM_OCMode_PWM1,
|
||||
.TIM_OutputState = TIM_OutputState_Enable,
|
||||
@ -605,127 +728,127 @@ const struct pios_servo_cfg pios_servo_cfg = {
|
||||
.TIM_OCIdleState = TIM_OCIdleState_Reset,
|
||||
.TIM_OCNIdleState = TIM_OCNIdleState_Reset,
|
||||
},
|
||||
.gpio_init = {
|
||||
.GPIO_Mode = GPIO_Mode_AF_PP,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
.remap = 0,
|
||||
.channels = pios_servo_channels,
|
||||
.num_channels = NELEMENTS(pios_servo_channels),
|
||||
.channels = pios_tim_servoport_all_pins,
|
||||
.num_channels = NELEMENTS(pios_tim_servoport_all_pins),
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* PWM Inputs
|
||||
*/
|
||||
#if defined(PIOS_INCLUDE_PWM)
|
||||
#if defined(PIOS_INCLUDE_PWM) || defined(PIOS_INCLUDE_PPM)
|
||||
#include <pios_pwm_priv.h>
|
||||
static const struct pios_pwm_channel pios_pwm_channels[] = {
|
||||
static const struct pios_tim_channel pios_tim_rcvrport_all_channels[] = {
|
||||
{
|
||||
.timer = TIM1,
|
||||
.port = GPIOA,
|
||||
.ccr = TIM_IT_CC2,
|
||||
.channel = TIM_Channel_2,
|
||||
.pin = GPIO_Pin_9,
|
||||
},
|
||||
.timer_chan = TIM_Channel_2,
|
||||
.pin = {
|
||||
.gpio = GPIOA,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_9,
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.timer = TIM1,
|
||||
.port = GPIOA,
|
||||
.ccr = TIM_IT_CC3,
|
||||
.channel = TIM_Channel_3,
|
||||
.pin = GPIO_Pin_10,
|
||||
.timer_chan = TIM_Channel_3,
|
||||
.pin = {
|
||||
.gpio = GPIOA,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_10,
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.timer = TIM5,
|
||||
.port = GPIOA,
|
||||
.ccr = TIM_IT_CC1,
|
||||
.channel = TIM_Channel_1,
|
||||
.pin = GPIO_Pin_0
|
||||
.timer_chan = TIM_Channel_1,
|
||||
.pin = {
|
||||
.gpio = GPIOA,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_0,
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.timer = TIM1,
|
||||
.port = GPIOA,
|
||||
.ccr = TIM_IT_CC1,
|
||||
.channel = TIM_Channel_1,
|
||||
.pin = GPIO_Pin_8,
|
||||
.timer_chan = TIM_Channel_1,
|
||||
.pin = {
|
||||
.gpio = GPIOA,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_8,
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.timer = TIM3,
|
||||
.port = GPIOB,
|
||||
.ccr = TIM_IT_CC4,
|
||||
.channel = TIM_Channel_4,
|
||||
.pin = GPIO_Pin_1,
|
||||
.timer_chan = TIM_Channel_4,
|
||||
.pin = {
|
||||
.gpio = GPIOB,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_1,
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.timer = TIM3,
|
||||
.port = GPIOB,
|
||||
.ccr = TIM_IT_CC3,
|
||||
.channel = TIM_Channel_3,
|
||||
.pin = GPIO_Pin_0,
|
||||
.timer_chan = TIM_Channel_3,
|
||||
.pin = {
|
||||
.gpio = GPIOB,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_0,
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.timer = TIM3,
|
||||
.port = GPIOB,
|
||||
.ccr = TIM_IT_CC1,
|
||||
.channel = TIM_Channel_1,
|
||||
.pin = GPIO_Pin_4,
|
||||
.timer_chan = TIM_Channel_1,
|
||||
.pin = {
|
||||
.gpio = GPIOB,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_4,
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
.remap = GPIO_PartialRemap_TIM3,
|
||||
},
|
||||
{
|
||||
.timer = TIM3,
|
||||
.port = GPIOB,
|
||||
.ccr = TIM_IT_CC2,
|
||||
.channel = TIM_Channel_2,
|
||||
.pin = GPIO_Pin_5,
|
||||
.timer_chan = TIM_Channel_2,
|
||||
.pin = {
|
||||
.gpio = GPIOB,
|
||||
.init = {
|
||||
.GPIO_Pin = GPIO_Pin_5,
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
},
|
||||
.remap = GPIO_PartialRemap_TIM3,
|
||||
},
|
||||
};
|
||||
|
||||
void TIM1_CC_IRQHandler();
|
||||
void TIM3_IRQHandler();
|
||||
void TIM5_IRQHandler();
|
||||
void TIM1_CC_IRQHandler() __attribute__ ((alias ("PIOS_TIM1_CC_irq_handler")));
|
||||
void TIM3_IRQHandler() __attribute__ ((alias ("PIOS_TIM3_irq_handler")));
|
||||
void TIM5_IRQHandler() __attribute__ ((alias ("PIOS_TIM5_irq_handler")));
|
||||
const struct pios_pwm_cfg pios_pwm_cfg = {
|
||||
.tim_base_init = {
|
||||
.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1,
|
||||
.TIM_ClockDivision = TIM_CKD_DIV1,
|
||||
.TIM_CounterMode = TIM_CounterMode_Up,
|
||||
.TIM_Period = 0xFFFF,
|
||||
.TIM_RepetitionCounter = 0x0000,
|
||||
},
|
||||
.tim_ic_init = {
|
||||
.TIM_ICPolarity = TIM_ICPolarity_Rising,
|
||||
.TIM_ICSelection = TIM_ICSelection_DirectTI,
|
||||
.TIM_ICPrescaler = TIM_ICPSC_DIV1,
|
||||
.TIM_ICFilter = 0x0,
|
||||
},
|
||||
.gpio_init = {
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
},
|
||||
.remap = GPIO_PartialRemap_TIM3,
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
.channels = pios_pwm_channels,
|
||||
.num_channels = NELEMENTS(pios_pwm_channels),
|
||||
.channels = pios_tim_rcvrport_all_channels,
|
||||
.num_channels = NELEMENTS(pios_tim_rcvrport_all_channels),
|
||||
};
|
||||
void PIOS_TIM1_CC_irq_handler()
|
||||
{
|
||||
PIOS_PWM_irq_handler(TIM1);
|
||||
}
|
||||
void PIOS_TIM3_irq_handler()
|
||||
{
|
||||
PIOS_PWM_irq_handler(TIM3);
|
||||
}
|
||||
void PIOS_TIM5_irq_handler()
|
||||
{
|
||||
PIOS_PWM_irq_handler(TIM5);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -733,42 +856,7 @@ void PIOS_TIM5_irq_handler()
|
||||
*/
|
||||
#if defined(PIOS_INCLUDE_PPM)
|
||||
#include <pios_ppm_priv.h>
|
||||
void TIM6_IRQHandler();
|
||||
void TIM6_IRQHandler() __attribute__ ((alias ("PIOS_TIM6_irq_handler")));
|
||||
static const struct pios_ppmsv_cfg pios_ppmsv_cfg = {
|
||||
.tim_base_init = {
|
||||
.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1, /* For 1 uS accuracy */
|
||||
.TIM_ClockDivision = TIM_CKD_DIV1,
|
||||
.TIM_CounterMode = TIM_CounterMode_Up,
|
||||
.TIM_Period = ((1000000 / 25) - 1), /* 25 Hz */
|
||||
.TIM_RepetitionCounter = 0x0000,
|
||||
},
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
.timer = TIM6,
|
||||
.ccr = TIM_IT_Update,
|
||||
};
|
||||
|
||||
void PIOS_TIM6_irq_handler(void)
|
||||
{
|
||||
PIOS_PPMSV_irq_handler();
|
||||
}
|
||||
|
||||
void TIM1_CC_IRQHandler();
|
||||
void TIM1_CC_IRQHandler() __attribute__ ((alias ("PIOS_TIM1_CC_irq_handler")));
|
||||
static const struct pios_ppm_cfg pios_ppm_cfg = {
|
||||
.tim_base_init = {
|
||||
.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1, /* For 1 uS accuracy */
|
||||
.TIM_ClockDivision = TIM_CKD_DIV1,
|
||||
.TIM_CounterMode = TIM_CounterMode_Up,
|
||||
.TIM_Period = 0xFFFF,
|
||||
.TIM_RepetitionCounter = 0x0000,
|
||||
},
|
||||
.tim_ic_init = {
|
||||
.TIM_ICPolarity = TIM_ICPolarity_Rising,
|
||||
.TIM_ICSelection = TIM_ICSelection_DirectTI,
|
||||
@ -776,30 +864,11 @@ static const struct pios_ppm_cfg pios_ppm_cfg = {
|
||||
.TIM_ICFilter = 0x0,
|
||||
.TIM_Channel = TIM_Channel_2,
|
||||
},
|
||||
.gpio_init = {
|
||||
.GPIO_Mode = GPIO_Mode_IPD,
|
||||
.GPIO_Speed = GPIO_Speed_2MHz,
|
||||
.GPIO_Pin = GPIO_Pin_9,
|
||||
},
|
||||
.remap = 0,
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
.NVIC_IRQChannel = TIM1_CC_IRQn,
|
||||
},
|
||||
},
|
||||
.timer = TIM1,
|
||||
.port = GPIOA,
|
||||
.ccr = TIM_IT_CC2,
|
||||
/* Use only the first channel for ppm */
|
||||
.channels = &pios_tim_rcvrport_all_channels[0],
|
||||
.num_channels = 1,
|
||||
};
|
||||
|
||||
void PIOS_TIM1_CC_irq_handler(void)
|
||||
{
|
||||
PIOS_PPM_irq_handler();
|
||||
}
|
||||
|
||||
#endif //PPM
|
||||
|
||||
#if defined(PIOS_INCLUDE_I2C)
|
||||
@ -965,8 +1034,12 @@ static const struct stm32_gpio pios_debug_pins[] = {
|
||||
#if defined(PIOS_INCLUDE_RCVR)
|
||||
#include "pios_rcvr_priv.h"
|
||||
|
||||
struct pios_rcvr_channel_map pios_rcvr_channel_to_id_map[PIOS_RCVR_MAX_CHANNELS];
|
||||
uint32_t pios_rcvr_max_channel;
|
||||
/* One slot per selectable receiver group.
|
||||
* eg. PWM, PPM, GCS, SPEKTRUM1, SPEKTRUM2, SBUS
|
||||
* NOTE: No slot in this map for NONE.
|
||||
*/
|
||||
uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE];
|
||||
|
||||
#endif /* PIOS_INCLUDE_RCVR */
|
||||
|
||||
#if defined(PIOS_INCLUDE_USB_HID)
|
||||
@ -1004,8 +1077,9 @@ void PIOS_Board_Init(void) {
|
||||
/* Remap AFIO pin */
|
||||
//GPIO_PinRemapConfig( GPIO_Remap_SWJ_NoJTRST, ENABLE);
|
||||
|
||||
/* Debug services */
|
||||
PIOS_DEBUG_Init();
|
||||
#ifdef PIOS_DEBUG_ENABLE_DEBUG_PINS
|
||||
PIOS_DEBUG_Init(&pios_tim_servo_all_channels, NELEMENTS(pios_tim_servo_all_channels));
|
||||
#endif /* PIOS_DEBUG_ENABLE_DEBUG_PINS */
|
||||
|
||||
/* Delay system */
|
||||
PIOS_DELAY_Init();
|
||||
@ -1026,7 +1100,6 @@ void PIOS_Board_Init(void) {
|
||||
UAVObjInitialize();
|
||||
|
||||
HwSettingsInitialize();
|
||||
ManualControlSettingsInitialize();
|
||||
|
||||
#if defined(PIOS_INCLUDE_RTC)
|
||||
/* Initialize the real-time clock and its associated tick */
|
||||
@ -1039,6 +1112,14 @@ void PIOS_Board_Init(void) {
|
||||
/* Initialize the task monitor library */
|
||||
TaskMonitorInitialize();
|
||||
|
||||
/* Set up pulse timers */
|
||||
PIOS_TIM_InitClock(&tim_1_cfg);
|
||||
PIOS_TIM_InitClock(&tim_3_cfg);
|
||||
PIOS_TIM_InitClock(&tim_5_cfg);
|
||||
|
||||
PIOS_TIM_InitClock(&tim_4_cfg);
|
||||
PIOS_TIM_InitClock(&tim_8_cfg);
|
||||
|
||||
/* Prepare the AHRS Comms upper layer protocol */
|
||||
AhrsInitComms();
|
||||
|
||||
@ -1050,127 +1131,128 @@ void PIOS_Board_Init(void) {
|
||||
/* Bind the AHRS comms layer to the AHRS SPI link */
|
||||
AhrsConnect(pios_spi_ahrs_id);
|
||||
|
||||
/* Initialize the PiOS library */
|
||||
#if defined(PIOS_INCLUDE_COM)
|
||||
/* Configure the main IO port */
|
||||
uint8_t hwsettings_op_mainport;
|
||||
HwSettingsOP_MainPortGet(&hwsettings_op_mainport);
|
||||
|
||||
switch (hwsettings_op_mainport) {
|
||||
case HWSETTINGS_OP_MAINPORT_DISABLED:
|
||||
break;
|
||||
case HWSETTINGS_OP_MAINPORT_TELEMETRY:
|
||||
#if defined(PIOS_INCLUDE_TELEMETRY_RF)
|
||||
{
|
||||
uint32_t pios_usart_telem_rf_id;
|
||||
if (PIOS_USART_Init(&pios_usart_telem_rf_id, &pios_usart_telem_cfg)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
{
|
||||
uint32_t pios_usart_telem_rf_id;
|
||||
if (PIOS_USART_Init(&pios_usart_telem_rf_id, &pios_usart_telem_cfg)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
|
||||
uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_RX_BUF_LEN);
|
||||
uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_TX_BUF_LEN);
|
||||
PIOS_Assert(rx_buffer);
|
||||
PIOS_Assert(tx_buffer);
|
||||
if (PIOS_COM_Init(&pios_com_telem_rf_id, &pios_usart_com_driver, pios_usart_telem_rf_id,
|
||||
rx_buffer, PIOS_COM_TELEM_RF_RX_BUF_LEN,
|
||||
tx_buffer, PIOS_COM_TELEM_RF_TX_BUF_LEN)) {
|
||||
PIOS_Assert(0);
|
||||
uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_RX_BUF_LEN);
|
||||
uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_TX_BUF_LEN);
|
||||
PIOS_Assert(rx_buffer);
|
||||
PIOS_Assert(tx_buffer);
|
||||
if (PIOS_COM_Init(&pios_com_telem_rf_id, &pios_usart_com_driver, pios_usart_telem_rf_id,
|
||||
rx_buffer, PIOS_COM_TELEM_RF_RX_BUF_LEN,
|
||||
tx_buffer, PIOS_COM_TELEM_RF_TX_BUF_LEN)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_TELEMETRY_RF */
|
||||
|
||||
#if defined(PIOS_INCLUDE_GPS)
|
||||
{
|
||||
uint32_t pios_usart_gps_id;
|
||||
if (PIOS_USART_Init(&pios_usart_gps_id, &pios_usart_gps_cfg)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_GPS_RX_BUF_LEN);
|
||||
PIOS_Assert(rx_buffer);
|
||||
if (PIOS_COM_Init(&pios_com_gps_id, &pios_usart_com_driver, pios_usart_gps_id,
|
||||
rx_buffer, PIOS_COM_GPS_RX_BUF_LEN,
|
||||
NULL, 0)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_GPS */
|
||||
#endif
|
||||
|
||||
PIOS_Servo_Init();
|
||||
/* Configure the flexi port */
|
||||
uint8_t hwsettings_op_flexiport;
|
||||
HwSettingsOP_FlexiPortGet(&hwsettings_op_flexiport);
|
||||
|
||||
switch (hwsettings_op_flexiport) {
|
||||
case HWSETTINGS_OP_FLEXIPORT_DISABLED:
|
||||
break;
|
||||
case HWSETTINGS_OP_FLEXIPORT_GPS:
|
||||
#if defined(PIOS_INCLUDE_GPS)
|
||||
{
|
||||
uint32_t pios_usart_gps_id;
|
||||
if (PIOS_USART_Init(&pios_usart_gps_id, &pios_usart_gps_cfg)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_GPS_RX_BUF_LEN);
|
||||
PIOS_Assert(rx_buffer);
|
||||
if (PIOS_COM_Init(&pios_com_gps_id, &pios_usart_com_driver, pios_usart_gps_id,
|
||||
rx_buffer, PIOS_COM_GPS_RX_BUF_LEN,
|
||||
NULL, 0)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_GPS */
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef PIOS_DEBUG_ENABLE_DEBUG_PINS
|
||||
PIOS_Servo_Init(&pios_servo_cfg);
|
||||
#endif /* PIOS_DEBUG_ENABLE_DEBUG_PINS */
|
||||
|
||||
PIOS_ADC_Init();
|
||||
PIOS_GPIO_Init();
|
||||
|
||||
/* Configure the selected receiver */
|
||||
uint8_t manualcontrolsettings_inputmode;
|
||||
ManualControlSettingsInitialize();
|
||||
ManualControlSettingsInputModeGet(&manualcontrolsettings_inputmode);
|
||||
/* Configure the rcvr port */
|
||||
uint8_t hwsettings_rcvrport;
|
||||
HwSettingsOP_RcvrPortGet(&hwsettings_rcvrport);
|
||||
|
||||
switch (manualcontrolsettings_inputmode) {
|
||||
case MANUALCONTROLSETTINGS_INPUTMODE_PWM:
|
||||
#if defined(PIOS_INCLUDE_PWM)
|
||||
#if (PIOS_PWM_NUM_INPUTS > PIOS_RCVR_MAX_CHANNELS)
|
||||
#error More receiver inputs than available devices
|
||||
#endif
|
||||
PIOS_PWM_Init();
|
||||
uint32_t pios_pwm_rcvr_id;
|
||||
if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, 0)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
for (uint8_t i = 0;
|
||||
i < PIOS_PWM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map);
|
||||
i++) {
|
||||
pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_pwm_rcvr_id;
|
||||
pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i;
|
||||
pios_rcvr_max_channel++;
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_PWM */
|
||||
break;
|
||||
case MANUALCONTROLSETTINGS_INPUTMODE_PPM:
|
||||
#if defined(PIOS_INCLUDE_PPM)
|
||||
#if (PIOS_PPM_NUM_INPUTS > PIOS_RCVR_MAX_CHANNELS)
|
||||
#error More receiver inputs than available devices
|
||||
#endif
|
||||
PIOS_PPM_Init();
|
||||
uint32_t pios_ppm_rcvr_id;
|
||||
if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, 0)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
for (uint8_t i = 0;
|
||||
i < PIOS_PPM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map);
|
||||
i++) {
|
||||
pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_ppm_rcvr_id;
|
||||
pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i;
|
||||
pios_rcvr_max_channel++;
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_PPM */
|
||||
break;
|
||||
case MANUALCONTROLSETTINGS_INPUTMODE_SPEKTRUM:
|
||||
|
||||
switch (hwsettings_rcvrport) {
|
||||
case HWSETTINGS_OP_RCVRPORT_DISABLED:
|
||||
break;
|
||||
case HWSETTINGS_OP_RCVRPORT_DEBUG:
|
||||
/* Not supported yet */
|
||||
break;
|
||||
case HWSETTINGS_OP_RCVRPORT_SPEKTRUM1:
|
||||
#if defined(PIOS_INCLUDE_SPEKTRUM)
|
||||
#if (PIOS_SPEKTRUM_NUM_INPUTS > PIOS_RCVR_MAX_CHANNELS)
|
||||
#error More receiver inputs than available devices
|
||||
#endif
|
||||
{
|
||||
uint32_t pios_usart_spektrum_id;
|
||||
if (PIOS_USART_Init(&pios_usart_spektrum_id, &pios_usart_spektrum_cfg)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
|
||||
uint32_t pios_spektrum_id;
|
||||
if (PIOS_SPEKTRUM_Init(&pios_spektrum_id, &pios_spektrum_cfg, &pios_usart_com_driver, pios_usart_spektrum_id, false)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
|
||||
uint32_t pios_spektrum_rcvr_id;
|
||||
if (PIOS_RCVR_Init(&pios_spektrum_rcvr_id, &pios_spektrum_rcvr_driver, 0)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
for (uint8_t i = 0;
|
||||
i < PIOS_SPEKTRUM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map);
|
||||
i++) {
|
||||
pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_spektrum_rcvr_id;
|
||||
pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i;
|
||||
pios_rcvr_max_channel++;
|
||||
}
|
||||
{
|
||||
uint32_t pios_usart_spektrum_id;
|
||||
if (PIOS_USART_Init(&pios_usart_spektrum_id, &pios_usart_spektrum_cfg)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
|
||||
uint32_t pios_spektrum_id;
|
||||
if (PIOS_SPEKTRUM_Init(&pios_spektrum_id, &pios_spektrum_cfg, &pios_usart_com_driver, pios_usart_spektrum_id, false)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
|
||||
uint32_t pios_spektrum_rcvr_id;
|
||||
if (PIOS_RCVR_Init(&pios_spektrum_rcvr_id, &pios_spektrum_rcvr_driver, pios_spektrum_id)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SPEKTRUM1] = pios_spektrum_rcvr_id;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case MANUALCONTROLSETTINGS_INPUTMODE_SBUS:
|
||||
#if defined(PIOS_INCLUDE_SBUS)
|
||||
#error SBUS NOT ON OP YET
|
||||
#endif /* PIOS_INCLUDE_SBUS */
|
||||
break;
|
||||
break;
|
||||
case HWSETTINGS_OP_RCVRPORT_PWM:
|
||||
#if defined(PIOS_INCLUDE_PWM)
|
||||
{
|
||||
uint32_t pios_pwm_id;
|
||||
PIOS_PWM_Init(&pios_pwm_id, &pios_pwm_cfg);
|
||||
|
||||
uint32_t pios_pwm_rcvr_id;
|
||||
if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, pios_pwm_id)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PWM] = pios_pwm_rcvr_id;
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_PWM */
|
||||
break;
|
||||
case HWSETTINGS_OP_RCVRPORT_PPM:
|
||||
#if defined(PIOS_INCLUDE_PPM)
|
||||
{
|
||||
uint32_t pios_ppm_id;
|
||||
PIOS_PPM_Init(&pios_ppm_id, &pios_ppm_cfg);
|
||||
|
||||
uint32_t pios_ppm_rcvr_id;
|
||||
if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, pios_ppm_id)) {
|
||||
PIOS_Assert(0);
|
||||
}
|
||||
pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM] = pios_ppm_rcvr_id;
|
||||
}
|
||||
#endif /* PIOS_INCLUDE_PPM */
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(PIOS_INCLUDE_USB_HID)
|
||||
|
@ -70,6 +70,7 @@ UAVOBJSRCFILENAMES += velocitydesired
|
||||
UAVOBJSRCFILENAMES += watchdogstatus
|
||||
UAVOBJSRCFILENAMES += flightstatus
|
||||
UAVOBJSRCFILENAMES += hwsettings
|
||||
UAVOBJSRCFILENAMES += receiveractivity
|
||||
UAVOBJSRCFILENAMES += cameradesired
|
||||
UAVOBJSRCFILENAMES += camerastabsettings
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
||||
* and we cannot define a linker script for each of them atm
|
||||
*/
|
||||
|
||||
#define MODULE_INITCALL(ifn, iparam, sfn, sparam, flags)
|
||||
#define MODULE_INITCALL(ifn, sfn)
|
||||
|
||||
#define MODULE_TASKCREATE_ALL
|
||||
|
||||
|
@ -206,22 +206,25 @@ extern uint32_t pios_com_telem_usb_id;
|
||||
// PIOS_RCVR
|
||||
// See also pios_board.c
|
||||
//------------------------
|
||||
#define PIOS_RCVR_MAX_DEVS 1
|
||||
#define PIOS_RCVR_MAX_DEVS 3
|
||||
#define PIOS_RCVR_MAX_CHANNELS 12
|
||||
|
||||
//-------------------------
|
||||
// Receiver PPM input
|
||||
//-------------------------
|
||||
#define PIOS_PPM_MAX_DEVS 1
|
||||
#define PIOS_PPM_NUM_INPUTS 12
|
||||
|
||||
//-------------------------
|
||||
// Receiver PWM input
|
||||
//-------------------------
|
||||
#define PIOS_PWM_MAX_DEVS 1
|
||||
#define PIOS_PWM_NUM_INPUTS 6
|
||||
|
||||
//-------------------------
|
||||
// Receiver SPEKTRUM input
|
||||
//-------------------------
|
||||
#define PIOS_SPEKTRUM_MAX_DEVS 2
|
||||
#define PIOS_SPEKTRUM_NUM_INPUTS 12
|
||||
|
||||
//-------------------------
|
||||
@ -230,6 +233,11 @@ extern uint32_t pios_com_telem_usb_id;
|
||||
#define PIOS_SERVO_UPDATE_HZ 50
|
||||
#define PIOS_SERVOS_INITIAL_POSITION 0 /* dont want to start motors, have no pulse till settings loaded */
|
||||
|
||||
//--------------------------
|
||||
// Timer controller settings
|
||||
//--------------------------
|
||||
#define PIOS_TIM_MAX_DEVS 3
|
||||
|
||||
//-------------------------
|
||||
// GPIO
|
||||
//-------------------------
|
||||
|
@ -185,16 +185,19 @@ extern uint32_t pios_com_aux_id;
|
||||
//-------------------------
|
||||
// Receiver PPM input
|
||||
//-------------------------
|
||||
#define PIOS_PPM_MAX_DEVS 1
|
||||
#define PIOS_PPM_NUM_INPUTS 12
|
||||
|
||||
//-------------------------
|
||||
// Receiver PWM input
|
||||
//-------------------------
|
||||
#define PIOS_PWM_MAX_DEVS 1
|
||||
#define PIOS_PWM_NUM_INPUTS 8
|
||||
|
||||
//-------------------------
|
||||
// Receiver SPEKTRUM input
|
||||
//-------------------------
|
||||
#define PIOS_SPEKTRUM_MAX_DEVS 1
|
||||
#define PIOS_SPEKTRUM_NUM_INPUTS 12
|
||||
|
||||
//-------------------------
|
||||
@ -203,6 +206,11 @@ extern uint32_t pios_com_aux_id;
|
||||
#define PIOS_SERVO_UPDATE_HZ 50
|
||||
#define PIOS_SERVOS_INITIAL_POSITION 0 /* dont want to start motors, have no pulse till settings loaded */
|
||||
|
||||
//--------------------------
|
||||
// Timer controller settings
|
||||
//--------------------------
|
||||
#define PIOS_TIM_MAX_DEVS 3
|
||||
|
||||
//-------------------------
|
||||
// ADC
|
||||
// PIOS_ADC_PinGet(0) = Temperature Sensor (On-board)
|
||||
|
@ -67,12 +67,12 @@ static bool PIOS_COM_validate(struct pios_com_dev * com_dev)
|
||||
return (com_dev && (com_dev->magic == PIOS_COM_DEV_MAGIC));
|
||||
}
|
||||
|
||||
#if defined(PIOS_INCLUDE_FREERTOS) && 0
|
||||
#if defined(PIOS_INCLUDE_FREERTOS)
|
||||
static struct pios_com_dev * PIOS_COM_alloc(void)
|
||||
{
|
||||
struct pios_com_dev * com_dev;
|
||||
|
||||
com_dev = (struct pios_com_dev *)malloc(sizeof(*com_dev));
|
||||
com_dev = (struct pios_com_dev *)pvPortMalloc(sizeof(*com_dev));
|
||||
if (!com_dev) return (NULL);
|
||||
|
||||
com_dev->magic = PIOS_COM_DEV_MAGIC;
|
||||
|
75
flight/PiOS/Common/pios_gcsrcvr.c
Normal file
75
flight/PiOS/Common/pios_gcsrcvr.c
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_GCSRCVR GCS Receiver Input Functions
|
||||
* @brief Code to read the channels within the GCS Receiver UAVObject
|
||||
* @{
|
||||
*
|
||||
* @file pios_gcsrcvr.c
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @brief GCS Input functions (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_GCSRCVR)
|
||||
|
||||
#include "pios_gcsrcvr_priv.h"
|
||||
|
||||
static GCSReceiverData gcsreceiverdata;
|
||||
|
||||
/* Provide a RCVR driver */
|
||||
static int32_t PIOS_GCSRCVR_Get(uint32_t rcvr_id, uint8_t channel);
|
||||
|
||||
const struct pios_rcvr_driver pios_gcsrcvr_rcvr_driver = {
|
||||
.read = PIOS_GCSRCVR_Get,
|
||||
};
|
||||
|
||||
static void gcsreceiver_updated(UAVObjEvent * ev)
|
||||
{
|
||||
if (ev->obj == GCSReceiverHandle()) {
|
||||
GCSReceiverGet(&gcsreceiverdata);
|
||||
}
|
||||
}
|
||||
|
||||
void PIOS_GCSRCVR_Init(void)
|
||||
{
|
||||
/* Register uavobj callback */
|
||||
GCSReceiverConnectCallback (gcsreceiver_updated);
|
||||
}
|
||||
|
||||
static int32_t PIOS_GCSRCVR_Get(uint32_t rcvr_id, uint8_t channel)
|
||||
{
|
||||
if (channel >= GCSRECEIVER_CHANNEL_NUMELEM) {
|
||||
/* channel is out of range */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (gcsreceiverdata.Channel[channel]);
|
||||
}
|
||||
|
||||
#endif /* PIOS_INCLUDE_GCSRCVR */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
@ -20,12 +20,12 @@ static bool PIOS_RCVR_validate(struct pios_rcvr_dev * rcvr_dev)
|
||||
return (rcvr_dev->magic == PIOS_RCVR_DEV_MAGIC);
|
||||
}
|
||||
|
||||
#if defined(PIOS_INCLUDE_FREERTOS) && 0
|
||||
#if defined(PIOS_INCLUDE_FREERTOS)
|
||||
static struct pios_rcvr_dev * PIOS_RCVR_alloc(void)
|
||||
{
|
||||
struct pios_rcvr_dev * rcvr_dev;
|
||||
|
||||
rcvr_dev = (struct pios_rcvr_dev *)malloc(sizeof(*rcvr_dev));
|
||||
rcvr_dev = (struct pios_rcvr_dev *)pvPortMalloc(sizeof(*rcvr_dev));
|
||||
if (!rcvr_dev) return (NULL);
|
||||
|
||||
rcvr_dev->magic = PIOS_RCVR_DEV_MAGIC;
|
||||
@ -76,8 +76,26 @@ out_fail:
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads an input channel from the appropriate driver
|
||||
* @param[in] rcvr_id driver to read from
|
||||
* @param[in] channel channel to read
|
||||
* @returns Unitless input value
|
||||
* @retval PIOS_RCVR_TIMEOUT indicates a failsafe or timeout from that channel
|
||||
* @retval PIOS_RCVR_INVALID invalid channel for this driver (usually out of range supported)
|
||||
* @retval PIOS_RCVR_NODRIVER driver was not initialized
|
||||
*/
|
||||
int32_t PIOS_RCVR_Read(uint32_t rcvr_id, uint8_t channel)
|
||||
{
|
||||
// Publicly facing API uses channel 1 for first channel
|
||||
if(channel == 0)
|
||||
return PIOS_RCVR_INVALID;
|
||||
else
|
||||
channel--;
|
||||
|
||||
if (rcvr_id == 0)
|
||||
return PIOS_RCVR_NODRIVER;
|
||||
|
||||
struct pios_rcvr_dev * rcvr_dev = (struct pios_rcvr_dev *)rcvr_id;
|
||||
|
||||
if (!PIOS_RCVR_validate(rcvr_dev)) {
|
||||
|
@ -1025,12 +1025,12 @@ typedef struct
|
||||
*/
|
||||
|
||||
void TIM_DeInit(TIM_TypeDef* TIMx);
|
||||
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
|
||||
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
|
||||
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
|
||||
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
|
||||
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
|
||||
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
|
||||
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, const TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
|
||||
void TIM_OC1Init(TIM_TypeDef* TIMx, const TIM_OCInitTypeDef* TIM_OCInitStruct);
|
||||
void TIM_OC2Init(TIM_TypeDef* TIMx, const TIM_OCInitTypeDef* TIM_OCInitStruct);
|
||||
void TIM_OC3Init(TIM_TypeDef* TIMx, const TIM_OCInitTypeDef* TIM_OCInitStruct);
|
||||
void TIM_OC4Init(TIM_TypeDef* TIMx, const TIM_OCInitTypeDef* TIM_OCInitStruct);
|
||||
void TIM_ICInit(TIM_TypeDef* TIMx, const TIM_ICInitTypeDef* TIM_ICInitStruct);
|
||||
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
|
||||
void TIM_BDTRConfig(TIM_TypeDef* TIMx, TIM_BDTRInitTypeDef *TIM_BDTRInitStruct);
|
||||
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
|
||||
|
@ -221,7 +221,7 @@ void TIM_DeInit(TIM_TypeDef* TIMx)
|
||||
* structure that contains the configuration information for the specified TIM peripheral.
|
||||
* @retval None
|
||||
*/
|
||||
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
|
||||
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, const TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
|
||||
{
|
||||
uint16_t tmpcr1 = 0;
|
||||
|
||||
@ -274,7 +274,7 @@ void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseIn
|
||||
* that contains the configuration information for the specified TIM peripheral.
|
||||
* @retval None
|
||||
*/
|
||||
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
|
||||
void TIM_OC1Init(TIM_TypeDef* TIMx, const TIM_OCInitTypeDef* TIM_OCInitStruct)
|
||||
{
|
||||
uint16_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0;
|
||||
|
||||
@ -357,7 +357,7 @@ void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
|
||||
* that contains the configuration information for the specified TIM peripheral.
|
||||
* @retval None
|
||||
*/
|
||||
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
|
||||
void TIM_OC2Init(TIM_TypeDef* TIMx, const TIM_OCInitTypeDef* TIM_OCInitStruct)
|
||||
{
|
||||
uint16_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0;
|
||||
|
||||
@ -439,7 +439,7 @@ void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
|
||||
* that contains the configuration information for the specified TIM peripheral.
|
||||
* @retval None
|
||||
*/
|
||||
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
|
||||
void TIM_OC3Init(TIM_TypeDef* TIMx, const TIM_OCInitTypeDef* TIM_OCInitStruct)
|
||||
{
|
||||
uint16_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0;
|
||||
|
||||
@ -518,7 +518,7 @@ void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
|
||||
* that contains the configuration information for the specified TIM peripheral.
|
||||
* @retval None
|
||||
*/
|
||||
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
|
||||
void TIM_OC4Init(TIM_TypeDef* TIMx, const TIM_OCInitTypeDef* TIM_OCInitStruct)
|
||||
{
|
||||
uint16_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0;
|
||||
|
||||
@ -582,7 +582,7 @@ void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
|
||||
* that contains the configuration information for the specified TIM peripheral.
|
||||
* @retval None
|
||||
*/
|
||||
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct)
|
||||
void TIM_ICInit(TIM_TypeDef* TIMx, const TIM_ICInitTypeDef* TIM_ICInitStruct)
|
||||
{
|
||||
/* Check the parameters */
|
||||
assert_param(IS_TIM_CHANNEL(TIM_ICInitStruct->TIM_Channel));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* This is the size of the stack for all FreeRTOS IRQs */
|
||||
_irq_stack_size = 0x180;
|
||||
_irq_stack_size = 0x1A0;
|
||||
/* This is the size of the stack for early init: life span is until scheduler starts */
|
||||
_init_stack_size = 0x100;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* This is the size of the stack for early init and for all FreeRTOS IRQs */
|
||||
_irq_stack_size = 0x400;
|
||||
_irq_stack_size = 0x800;
|
||||
/* This is the size of the stack for early init: life span is until scheduler starts */
|
||||
_init_stack_size = 0x400;
|
||||
_init_stack_size = 0x800;
|
||||
|
||||
/* Check valid alignment for VTOR */
|
||||
ASSERT(ORIGIN(FLASH) == ALIGN(ORIGIN(FLASH), 0x80), "Start of memory region flash not aligned for startup vector table");
|
||||
|
@ -34,39 +34,41 @@
|
||||
// Global variables
|
||||
const char *PIOS_DEBUG_AssertMsg = "ASSERT FAILED";
|
||||
|
||||
#include <pios_servo_priv.h>
|
||||
extern const struct pios_servo_channel pios_servo_channels[];
|
||||
#define PIOS_SERVO_GPIO_PORT_1TO4 pios_servo_channels[0].port
|
||||
#define PIOS_SERVO_GPIO_PORT_5TO8 pios_servo_channels[4].port
|
||||
#define PIOS_SERVO_GPIO_PIN_1 pios_servo_channels[0].pin
|
||||
#define PIOS_SERVO_GPIO_PIN_2 pios_servo_channels[1].pin
|
||||
#define PIOS_SERVO_GPIO_PIN_3 pios_servo_channels[2].pin
|
||||
#define PIOS_SERVO_GPIO_PIN_4 pios_servo_channels[3].pin
|
||||
#define PIOS_SERVO_GPIO_PIN_5 pios_servo_channels[4].pin
|
||||
#define PIOS_SERVO_GPIO_PIN_6 pios_servo_channels[5].pin
|
||||
#define PIOS_SERVO_GPIO_PIN_7 pios_servo_channels[6].pin
|
||||
#define PIOS_SERVO_GPIO_PIN_8 pios_servo_channels[7].pin
|
||||
/* Private Function Prototypes */
|
||||
#ifdef PIOS_ENABLE_DEBUG_PINS
|
||||
static const struct pios_tim_channel * debug_channels;
|
||||
static uint8_t debug_num_channels;
|
||||
#endif /* PIOS_ENABLE_DEBUG_PINS */
|
||||
|
||||
/**
|
||||
* Initialise Debug-features
|
||||
*/
|
||||
void PIOS_DEBUG_Init(void)
|
||||
void PIOS_DEBUG_Init(const struct pios_tim_channel * channels, uint8_t num_channels)
|
||||
{
|
||||
#ifdef PIOS_ENABLE_DEBUG_PINS
|
||||
// Initialise Servo pins as standard output pins
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
GPIO_StructInit(&GPIO_InitStructure);
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = PIOS_SERVO_GPIO_PIN_1 | PIOS_SERVO_GPIO_PIN_2 | PIOS_SERVO_GPIO_PIN_3 | PIOS_SERVO_GPIO_PIN_4;
|
||||
GPIO_Init(PIOS_SERVO_GPIO_PORT_1TO4, &GPIO_InitStructure);
|
||||
GPIO_InitStructure.GPIO_Pin = PIOS_SERVO_GPIO_PIN_5 | PIOS_SERVO_GPIO_PIN_6 | PIOS_SERVO_GPIO_PIN_7 | PIOS_SERVO_GPIO_PIN_8;
|
||||
GPIO_Init(PIOS_SERVO_GPIO_PORT_5TO8, &GPIO_InitStructure);
|
||||
PIOS_Assert(channels);
|
||||
PIOS_Assert(num_channels);
|
||||
|
||||
// Drive all pins low
|
||||
PIOS_SERVO_GPIO_PORT_1TO4->BRR = PIOS_SERVO_GPIO_PIN_1 | PIOS_SERVO_GPIO_PIN_2 | PIOS_SERVO_GPIO_PIN_3 | PIOS_SERVO_GPIO_PIN_4;
|
||||
PIOS_SERVO_GPIO_PORT_5TO8->BRR = PIOS_SERVO_GPIO_PIN_5 | PIOS_SERVO_GPIO_PIN_6 | PIOS_SERVO_GPIO_PIN_7 | PIOS_SERVO_GPIO_PIN_8;
|
||||
/* Store away the GPIOs we've been given */
|
||||
debug_channels = channels;
|
||||
debug_num_channels = num_channels;
|
||||
|
||||
/* Configure the GPIOs we've been given */
|
||||
for (uint8_t i = 0; i < num_channels; i++) {
|
||||
const struct pios_tim_channel * chan = &channels[i];
|
||||
|
||||
// Initialise pins as standard output pins
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
GPIO_StructInit(&GPIO_InitStructure);
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = chan->init->GPIO_Pin;
|
||||
|
||||
/* Initialize the GPIO */
|
||||
GPIO_Init(chan->init->port, &GPIO_InitStructure);
|
||||
|
||||
/* Set the pin low */
|
||||
GPIO_WriteBit(chan->init->port, chan->init->GPIO_Pin, Bit_RESET);
|
||||
}
|
||||
#endif // PIOS_ENABLE_DEBUG_PINS
|
||||
}
|
||||
|
||||
@ -74,14 +76,17 @@ void PIOS_DEBUG_Init(void)
|
||||
* Set debug-pin high
|
||||
* \param pin 0 for S1 output
|
||||
*/
|
||||
void PIOS_DEBUG_PinHigh(uint8_t Pin)
|
||||
void PIOS_DEBUG_PinHigh(uint8_t pin)
|
||||
{
|
||||
#ifdef PIOS_ENABLE_DEBUG_PINS
|
||||
if (Pin < 4) {
|
||||
PIOS_SERVO_GPIO_PORT_1TO4->BSRR = (PIOS_SERVO_GPIO_PIN_1 << Pin);
|
||||
} else if (Pin <= 7) {
|
||||
PIOS_SERVO_GPIO_PORT_5TO8->BSRR = (PIOS_SERVO_GPIO_PIN_5 << (Pin - 4));
|
||||
if (!debug_channels || pin >= debug_num_channels) {
|
||||
return;
|
||||
}
|
||||
|
||||
const struct pios_tim_channel * chan = &debug_channels[pin];
|
||||
|
||||
GPIO_WriteBit(chan->init->port, chan->init->GPIO_Pin, Bit_Set);
|
||||
|
||||
#endif // PIOS_ENABLE_DEBUG_PINS
|
||||
}
|
||||
|
||||
@ -89,14 +94,17 @@ void PIOS_DEBUG_PinHigh(uint8_t Pin)
|
||||
* Set debug-pin low
|
||||
* \param pin 0 for S1 output
|
||||
*/
|
||||
void PIOS_DEBUG_PinLow(uint8_t Pin)
|
||||
void PIOS_DEBUG_PinLow(uint8_t pin)
|
||||
{
|
||||
#ifdef PIOS_ENABLE_DEBUG_PINS
|
||||
if (Pin < 4) {
|
||||
PIOS_SERVO_GPIO_PORT_1TO4->BRR = (PIOS_SERVO_GPIO_PIN_1 << Pin);
|
||||
} else if (Pin <= 7) {
|
||||
PIOS_SERVO_GPIO_PORT_5TO8->BRR = (PIOS_SERVO_GPIO_PIN_5 << (Pin - 4));
|
||||
if (!debug_channels || pin >= debug_num_channels) {
|
||||
return;
|
||||
}
|
||||
|
||||
const struct pios_tim_channel * chan = &debug_channels[pin];
|
||||
|
||||
GPIO_WriteBit(chan->init->port, chan->init->GPIO_Pin, Bit_RESET);
|
||||
|
||||
#endif // PIOS_ENABLE_DEBUG_PINS
|
||||
}
|
||||
|
||||
@ -104,11 +112,22 @@ void PIOS_DEBUG_PinLow(uint8_t Pin)
|
||||
void PIOS_DEBUG_PinValue8Bit(uint8_t value)
|
||||
{
|
||||
#ifdef PIOS_ENABLE_DEBUG_PINS
|
||||
if (!debug_channels) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t bsrr_l = ( ((~value)&0x0F)<<(16+6) ) | ((value & 0x0F)<<6);
|
||||
uint32_t bsrr_h = ( ((~value)&0xF0)<<(16+6-4) ) | ((value & 0xF0)<<(6-4));
|
||||
|
||||
PIOS_IRQ_Disable();
|
||||
PIOS_SERVO_GPIO_PORT_1TO4->BSRR = bsrr_l;
|
||||
PIOS_SERVO_GPIO_PORT_5TO8->BSRR = bsrr_h;
|
||||
|
||||
/*
|
||||
* This is sketchy since it assumes a particular ordering
|
||||
* and bitwise layout of the channels provided to the debug code.
|
||||
*/
|
||||
debug_channels[0].init.port->BSRR = bsrr_l;
|
||||
debug_channels[4].init.port->BSRR = bsrr_h;
|
||||
|
||||
PIOS_IRQ_Enable();
|
||||
#endif // PIOS_ENABLE_DEBUG_PINS
|
||||
}
|
||||
@ -116,8 +135,16 @@ void PIOS_DEBUG_PinValue8Bit(uint8_t value)
|
||||
void PIOS_DEBUG_PinValue4BitL(uint8_t value)
|
||||
{
|
||||
#ifdef PIOS_ENABLE_DEBUG_PINS
|
||||
if (!debug_channels) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is sketchy since it assumes a particular ordering
|
||||
* and bitwise layout of the channels provided to the debug code.
|
||||
*/
|
||||
uint32_t bsrr_l = ((~(value & 0x0F)<<(16+6))) | ((value & 0x0F)<<6);
|
||||
PIOS_SERVO_GPIO_PORT_1TO4->BSRR = bsrr_l;
|
||||
debug_channels[0].init.port->BSRR = bsrr_l;
|
||||
#endif // PIOS_ENABLE_DEBUG_PINS
|
||||
}
|
||||
|
||||
|
@ -823,12 +823,12 @@ static bool PIOS_I2C_validate(struct pios_i2c_adapter * i2c_adapter)
|
||||
return (i2c_adapter->magic == PIOS_I2C_DEV_MAGIC);
|
||||
}
|
||||
|
||||
#if defined(PIOS_INCLUDE_FREERTOS) && 0
|
||||
static struct pios_i2c_dev * PIOS_I2C_alloc(void)
|
||||
#if defined(PIOS_INCLUDE_FREERTOS)
|
||||
static struct pios_i2c_adapter * PIOS_I2C_alloc(void)
|
||||
{
|
||||
struct pios_i2c_dev * i2c_adapter;
|
||||
struct pios_i2c_adapter * i2c_adapter;
|
||||
|
||||
i2c_adapter = (struct pios_i2c_adapter *)malloc(sizeof(*i2c_adapter));
|
||||
i2c_adapter = (struct pios_i2c_adapter *)pvPortMalloc(sizeof(*i2c_adapter));
|
||||
if (!i2c_adapter) return(NULL);
|
||||
|
||||
i2c_adapter->magic = PIOS_I2C_DEV_MAGIC;
|
||||
|
@ -47,108 +47,139 @@ const struct pios_rcvr_driver pios_ppm_rcvr_driver = {
|
||||
#define PIOS_PPM_IN_MIN_SYNC_PULSE_US 3800 // microseconds
|
||||
#define PIOS_PPM_IN_MIN_CHANNEL_PULSE_US 750 // microseconds
|
||||
#define PIOS_PPM_IN_MAX_CHANNEL_PULSE_US 2250 // microseconds
|
||||
#define PIOS_PPM_INPUT_INVALID 0
|
||||
|
||||
/* Local Variables */
|
||||
static TIM_ICInitTypeDef TIM_ICInitStructure;
|
||||
static uint8_t PulseIndex;
|
||||
static uint32_t PreviousTime;
|
||||
static uint32_t CurrentTime;
|
||||
static uint32_t DeltaTime;
|
||||
static uint32_t CaptureValue[PIOS_PPM_IN_MAX_NUM_CHANNELS];
|
||||
static uint32_t CaptureValueNewFrame[PIOS_PPM_IN_MAX_NUM_CHANNELS];
|
||||
static uint32_t LargeCounter;
|
||||
static int8_t NumChannels;
|
||||
static int8_t NumChannelsPrevFrame;
|
||||
static uint8_t NumChannelCounter;
|
||||
|
||||
static uint8_t supv_timer = 0;
|
||||
static bool Tracking;
|
||||
static bool Fresh;
|
||||
|
||||
static void PIOS_PPM_Supervisor(uint32_t ppm_id);
|
||||
|
||||
void PIOS_PPM_Init(void)
|
||||
enum pios_ppm_dev_magic {
|
||||
PIOS_PPM_DEV_MAGIC = 0xee014d8b,
|
||||
};
|
||||
|
||||
struct pios_ppm_dev {
|
||||
enum pios_ppm_dev_magic magic;
|
||||
const struct pios_ppm_cfg * cfg;
|
||||
|
||||
uint8_t PulseIndex;
|
||||
uint32_t PreviousTime;
|
||||
uint32_t CurrentTime;
|
||||
uint32_t DeltaTime;
|
||||
uint32_t CaptureValue[PIOS_PPM_IN_MAX_NUM_CHANNELS];
|
||||
uint32_t CaptureValueNewFrame[PIOS_PPM_IN_MAX_NUM_CHANNELS];
|
||||
uint32_t LargeCounter;
|
||||
int8_t NumChannels;
|
||||
int8_t NumChannelsPrevFrame;
|
||||
uint8_t NumChannelCounter;
|
||||
|
||||
uint8_t supv_timer;
|
||||
bool Tracking;
|
||||
bool Fresh;
|
||||
};
|
||||
|
||||
static bool PIOS_PPM_validate(struct pios_ppm_dev * ppm_dev)
|
||||
{
|
||||
/* Flush counter variables */
|
||||
int32_t i;
|
||||
return (ppm_dev->magic == PIOS_PPM_DEV_MAGIC);
|
||||
}
|
||||
|
||||
PulseIndex = 0;
|
||||
PreviousTime = 0;
|
||||
CurrentTime = 0;
|
||||
DeltaTime = 0;
|
||||
LargeCounter = 0;
|
||||
NumChannels = -1;
|
||||
NumChannelsPrevFrame = -1;
|
||||
NumChannelCounter = 0;
|
||||
Tracking = FALSE;
|
||||
Fresh = FALSE;
|
||||
#if defined(PIOS_INCLUDE_FREERTOS)
|
||||
static struct pios_ppm_dev * PIOS_PPM_alloc(void)
|
||||
{
|
||||
struct pios_ppm_dev * ppm_dev;
|
||||
|
||||
for (i = 0; i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) {
|
||||
CaptureValue[i] = 0;
|
||||
CaptureValueNewFrame[i] = 0;
|
||||
ppm_dev = (struct pios_ppm_dev *)pvPortMalloc(sizeof(*ppm_dev));
|
||||
if (!ppm_dev) return(NULL);
|
||||
|
||||
ppm_dev->magic = PIOS_PPM_DEV_MAGIC;
|
||||
return(ppm_dev);
|
||||
}
|
||||
#else
|
||||
static struct pios_ppm_dev pios_ppm_devs[PIOS_PPM_MAX_DEVS];
|
||||
static uint8_t pios_ppm_num_devs;
|
||||
static struct pios_ppm_dev * PIOS_PPM_alloc(void)
|
||||
{
|
||||
struct pios_ppm_dev * ppm_dev;
|
||||
|
||||
if (pios_ppm_num_devs >= PIOS_PPM_MAX_DEVS) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
NVIC_InitTypeDef NVIC_InitStructure = pios_ppm_cfg.irq.init;
|
||||
ppm_dev = &pios_ppm_devs[pios_ppm_num_devs++];
|
||||
ppm_dev->magic = PIOS_PPM_DEV_MAGIC;
|
||||
|
||||
/* Enable appropriate clock to timer module */
|
||||
switch((int32_t) pios_ppm_cfg.timer) {
|
||||
case (int32_t)TIM1:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM2:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM3:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM4:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
|
||||
break;
|
||||
#ifdef STM32F10X_HD
|
||||
case (int32_t)TIM5:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM6:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM7:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM8:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM8_CC_IRQn;
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
|
||||
break;
|
||||
return (ppm_dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void PIOS_PPM_tim_overflow_cb (uint32_t id, uint32_t context, uint8_t channel, uint16_t count);
|
||||
static void PIOS_PPM_tim_edge_cb (uint32_t id, uint32_t context, uint8_t channel, uint16_t count);
|
||||
const static struct pios_tim_callbacks tim_callbacks = {
|
||||
.overflow = PIOS_PPM_tim_overflow_cb,
|
||||
.edge = PIOS_PPM_tim_edge_cb,
|
||||
};
|
||||
|
||||
extern int32_t PIOS_PPM_Init(uint32_t * ppm_id, const struct pios_ppm_cfg * cfg)
|
||||
{
|
||||
PIOS_DEBUG_Assert(ppm_id);
|
||||
PIOS_DEBUG_Assert(cfg);
|
||||
|
||||
struct pios_ppm_dev * ppm_dev;
|
||||
|
||||
ppm_dev = (struct pios_ppm_dev *) PIOS_PPM_alloc();
|
||||
if (!ppm_dev) goto out_fail;
|
||||
|
||||
/* Bind the configuration to the device instance */
|
||||
ppm_dev->cfg = cfg;
|
||||
|
||||
/* Set up the state variables */
|
||||
ppm_dev->PulseIndex = 0;
|
||||
ppm_dev->PreviousTime = 0;
|
||||
ppm_dev->CurrentTime = 0;
|
||||
ppm_dev->DeltaTime = 0;
|
||||
ppm_dev->LargeCounter = 0;
|
||||
ppm_dev->NumChannels = -1;
|
||||
ppm_dev->NumChannelsPrevFrame = -1;
|
||||
ppm_dev->NumChannelCounter = 0;
|
||||
ppm_dev->Tracking = FALSE;
|
||||
ppm_dev->Fresh = FALSE;
|
||||
|
||||
for (uint8_t i = 0; i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) {
|
||||
/* Flush counter variables */
|
||||
ppm_dev->CaptureValue[i] = 0;
|
||||
ppm_dev->CaptureValueNewFrame[i] = 0;
|
||||
|
||||
}
|
||||
/* Enable timer interrupts */
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
/* Configure input pins */
|
||||
GPIO_InitTypeDef GPIO_InitStructure = pios_ppm_cfg.gpio_init;
|
||||
GPIO_Init(pios_ppm_cfg.port, &GPIO_InitStructure);
|
||||
uint32_t tim_id;
|
||||
if (PIOS_TIM_InitChannels(&tim_id, cfg->channels, cfg->num_channels, &tim_callbacks, (uint32_t)ppm_dev)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Configure timer for input capture */
|
||||
TIM_ICInitStructure = pios_ppm_cfg.tim_ic_init;
|
||||
TIM_ICInit(pios_ppm_cfg.timer, &TIM_ICInitStructure);
|
||||
/* Configure the channels to be in capture/compare mode */
|
||||
for (uint8_t i = 0; i < cfg->num_channels; i++) {
|
||||
const struct pios_tim_channel * chan = &cfg->channels[i];
|
||||
|
||||
/* Configure timer clocks */
|
||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = pios_ppm_cfg.tim_base_init;
|
||||
TIM_InternalClockConfig(pios_ppm_cfg.timer);
|
||||
TIM_TimeBaseInit(pios_ppm_cfg.timer, &TIM_TimeBaseStructure);
|
||||
/* Configure timer for input capture */
|
||||
TIM_ICInitTypeDef TIM_ICInitStructure = cfg->tim_ic_init;
|
||||
TIM_ICInitStructure.TIM_Channel = chan->timer_chan;
|
||||
TIM_ICInit(chan->timer, &TIM_ICInitStructure);
|
||||
|
||||
/* Enable the Capture Compare Interrupt Request */
|
||||
TIM_ITConfig(pios_ppm_cfg.timer, pios_ppm_cfg.ccr | TIM_IT_Update, ENABLE);
|
||||
|
||||
/* Enable timers */
|
||||
TIM_Cmd(pios_ppm_cfg.timer, ENABLE);
|
||||
/* Enable the Capture Compare Interrupt Request */
|
||||
switch (chan->timer_chan) {
|
||||
case TIM_Channel_1:
|
||||
TIM_ITConfig(chan->timer, TIM_IT_CC1 | TIM_IT_Update, ENABLE);
|
||||
break;
|
||||
case TIM_Channel_2:
|
||||
TIM_ITConfig(chan->timer, TIM_IT_CC2 | TIM_IT_Update, ENABLE);
|
||||
break;
|
||||
case TIM_Channel_3:
|
||||
TIM_ITConfig(chan->timer, TIM_IT_CC3 | TIM_IT_Update, ENABLE);
|
||||
break;
|
||||
case TIM_Channel_4:
|
||||
TIM_ITConfig(chan->timer, TIM_IT_CC4 | TIM_IT_Update, ENABLE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup local variable which stays in this scope */
|
||||
/* Doing this here and using a local variable saves doing it in the ISR */
|
||||
@ -156,9 +187,16 @@ void PIOS_PPM_Init(void)
|
||||
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
|
||||
TIM_ICInitStructure.TIM_ICFilter = 0x0;
|
||||
|
||||
if (!PIOS_RTC_RegisterTickCallback(PIOS_PPM_Supervisor, 0)) {
|
||||
if (!PIOS_RTC_RegisterTickCallback(PIOS_PPM_Supervisor, (uint32_t)ppm_dev)) {
|
||||
PIOS_DEBUG_Assert(0);
|
||||
}
|
||||
|
||||
*ppm_id = (uint32_t)ppm_dev;
|
||||
|
||||
return(0);
|
||||
|
||||
out_fail:
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,142 +207,146 @@ void PIOS_PPM_Init(void)
|
||||
*/
|
||||
static int32_t PIOS_PPM_Get(uint32_t rcvr_id, uint8_t channel)
|
||||
{
|
||||
/* Return error if channel not available */
|
||||
if (channel >= PIOS_PPM_IN_MAX_NUM_CHANNELS) {
|
||||
return -1;
|
||||
struct pios_ppm_dev * ppm_dev = (struct pios_ppm_dev *)rcvr_id;
|
||||
|
||||
if (!PIOS_PPM_validate(ppm_dev)) {
|
||||
/* Invalid device specified */
|
||||
return PIOS_RCVR_INVALID;
|
||||
}
|
||||
return CaptureValue[channel];
|
||||
|
||||
if (channel >= PIOS_PPM_IN_MAX_NUM_CHANNELS) {
|
||||
/* Channel out of range */
|
||||
return PIOS_RCVR_INVALID;
|
||||
}
|
||||
return ppm_dev->CaptureValue[channel];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle TIMx global interrupt request
|
||||
* Some work and testing still needed, need to detect start of frame and decode pulses
|
||||
*
|
||||
*/
|
||||
void PIOS_PPM_irq_handler(void)
|
||||
static void PIOS_PPM_tim_overflow_cb (uint32_t tim_id, uint32_t context, uint8_t channel, uint16_t count)
|
||||
{
|
||||
/* Timer Overflow Interrupt
|
||||
* The time between timer overflows must be greater than the PPM
|
||||
* frame period. If a full frame has not decoded in the between timer
|
||||
* overflows then capture values should be cleared.
|
||||
*/
|
||||
struct pios_ppm_dev * ppm_dev = (struct pios_ppm_dev *)context;
|
||||
|
||||
if (TIM_GetITStatus(pios_ppm_cfg.timer, TIM_IT_Update) == SET) {
|
||||
/* Clear TIMx overflow interrupt pending bit */
|
||||
TIM_ClearITPendingBit(pios_ppm_cfg.timer, TIM_IT_Update);
|
||||
|
||||
/* If sharing a timer with a servo output the ARR register will
|
||||
be set according to the PWM period. When timer reaches the
|
||||
ARR value a timer overflow interrupt will fire. We use the
|
||||
interrupt accumulate a 32-bit timer. */
|
||||
LargeCounter = LargeCounter + pios_ppm_cfg.timer->ARR;
|
||||
if (!PIOS_PPM_validate(ppm_dev)) {
|
||||
/* Invalid device specified */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Signal edge interrupt */
|
||||
if (TIM_GetITStatus(pios_ppm_cfg.timer, pios_ppm_cfg.ccr) == SET) {
|
||||
PreviousTime = CurrentTime;
|
||||
ppm_dev->LargeCounter += count;
|
||||
|
||||
switch((int32_t) pios_ppm_cfg.ccr) {
|
||||
case (int32_t)TIM_IT_CC1:
|
||||
CurrentTime = TIM_GetCapture1(pios_ppm_cfg.timer);
|
||||
break;
|
||||
case (int32_t)TIM_IT_CC2:
|
||||
CurrentTime = TIM_GetCapture2(pios_ppm_cfg.timer);
|
||||
break;
|
||||
case (int32_t)TIM_IT_CC3:
|
||||
CurrentTime = TIM_GetCapture3(pios_ppm_cfg.timer);
|
||||
break;
|
||||
case (int32_t)TIM_IT_CC4:
|
||||
CurrentTime = TIM_GetCapture4(pios_ppm_cfg.timer);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void PIOS_PPM_tim_edge_cb (uint32_t tim_id, uint32_t context, uint8_t chan_idx, uint16_t count)
|
||||
{
|
||||
/* Recover our device context */
|
||||
struct pios_ppm_dev * ppm_dev = (struct pios_ppm_dev *)context;
|
||||
|
||||
if (!PIOS_PPM_validate(ppm_dev)) {
|
||||
/* Invalid device specified */
|
||||
return;
|
||||
}
|
||||
|
||||
if (chan_idx >= ppm_dev->cfg->num_channels) {
|
||||
/* Channel out of range */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Shift the last measurement out */
|
||||
ppm_dev->PreviousTime = ppm_dev->CurrentTime;
|
||||
|
||||
/* Grab the new count */
|
||||
ppm_dev->CurrentTime = count;
|
||||
|
||||
/* Convert to 32-bit timer result */
|
||||
ppm_dev->CurrentTime += ppm_dev->LargeCounter;
|
||||
|
||||
/* Capture computation */
|
||||
ppm_dev->DeltaTime = ppm_dev->CurrentTime - ppm_dev->PreviousTime;
|
||||
|
||||
ppm_dev->PreviousTime = ppm_dev->CurrentTime;
|
||||
|
||||
/* Sync pulse detection */
|
||||
if (ppm_dev->DeltaTime > PIOS_PPM_IN_MIN_SYNC_PULSE_US) {
|
||||
if (ppm_dev->PulseIndex == ppm_dev->NumChannelsPrevFrame
|
||||
&& ppm_dev->PulseIndex >= PIOS_PPM_IN_MIN_NUM_CHANNELS
|
||||
&& ppm_dev->PulseIndex <= PIOS_PPM_IN_MAX_NUM_CHANNELS)
|
||||
{
|
||||
/* If we see n simultaneous frames of the same
|
||||
number of channels we save it as our frame size */
|
||||
if (ppm_dev->NumChannelCounter < PIOS_PPM_STABLE_CHANNEL_COUNT)
|
||||
ppm_dev->NumChannelCounter++;
|
||||
else
|
||||
ppm_dev->NumChannels = ppm_dev->PulseIndex;
|
||||
} else {
|
||||
ppm_dev->NumChannelCounter = 0;
|
||||
}
|
||||
|
||||
/* Clear TIMx Capture compare interrupt pending bit */
|
||||
TIM_ClearITPendingBit(pios_ppm_cfg.timer, pios_ppm_cfg.ccr);
|
||||
|
||||
/* Convert to 32-bit timer result */
|
||||
CurrentTime = CurrentTime + LargeCounter;
|
||||
|
||||
/* Capture computation */
|
||||
DeltaTime = CurrentTime - PreviousTime;
|
||||
|
||||
PreviousTime = CurrentTime;
|
||||
|
||||
/* Sync pulse detection */
|
||||
if (DeltaTime > PIOS_PPM_IN_MIN_SYNC_PULSE_US) {
|
||||
if (PulseIndex == NumChannelsPrevFrame
|
||||
&& PulseIndex >= PIOS_PPM_IN_MIN_NUM_CHANNELS
|
||||
&& PulseIndex <= PIOS_PPM_IN_MAX_NUM_CHANNELS)
|
||||
{
|
||||
/* If we see n simultaneous frames of the same
|
||||
number of channels we save it as our frame size */
|
||||
if (NumChannelCounter < PIOS_PPM_STABLE_CHANNEL_COUNT)
|
||||
NumChannelCounter++;
|
||||
else
|
||||
NumChannels = PulseIndex;
|
||||
} else {
|
||||
NumChannelCounter = 0;
|
||||
/* Check if the last frame was well formed */
|
||||
if (ppm_dev->PulseIndex == ppm_dev->NumChannels && ppm_dev->Tracking) {
|
||||
/* The last frame was well formed */
|
||||
for (uint32_t i = 0; i < ppm_dev->NumChannels; i++) {
|
||||
ppm_dev->CaptureValue[i] = ppm_dev->CaptureValueNewFrame[i];
|
||||
}
|
||||
|
||||
/* Check if the last frame was well formed */
|
||||
if (PulseIndex == NumChannels && Tracking) {
|
||||
/* The last frame was well formed */
|
||||
for (uint32_t i = 0; i < NumChannels; i++) {
|
||||
CaptureValue[i] = CaptureValueNewFrame[i];
|
||||
}
|
||||
for (uint32_t i = NumChannels;
|
||||
i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) {
|
||||
CaptureValue[i] = PIOS_PPM_INPUT_INVALID;
|
||||
}
|
||||
for (uint32_t i = ppm_dev->NumChannels;
|
||||
i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) {
|
||||
ppm_dev->CaptureValue[i] = PIOS_RCVR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
Fresh = TRUE;
|
||||
Tracking = TRUE;
|
||||
NumChannelsPrevFrame = PulseIndex;
|
||||
PulseIndex = 0;
|
||||
ppm_dev->Fresh = TRUE;
|
||||
ppm_dev->Tracking = TRUE;
|
||||
ppm_dev->NumChannelsPrevFrame = ppm_dev->PulseIndex;
|
||||
ppm_dev->PulseIndex = 0;
|
||||
|
||||
/* We rely on the supervisor to set CaptureValue to invalid
|
||||
if no valid frame is found otherwise we ride over it */
|
||||
/* We rely on the supervisor to set CaptureValue to invalid
|
||||
if no valid frame is found otherwise we ride over it */
|
||||
|
||||
} else if (Tracking) {
|
||||
/* Valid pulse duration 0.75 to 2.5 ms*/
|
||||
if (DeltaTime > PIOS_PPM_IN_MIN_CHANNEL_PULSE_US
|
||||
&& DeltaTime < PIOS_PPM_IN_MAX_CHANNEL_PULSE_US
|
||||
&& PulseIndex < PIOS_PPM_IN_MAX_NUM_CHANNELS) {
|
||||
|
||||
CaptureValueNewFrame[PulseIndex] = DeltaTime;
|
||||
PulseIndex++;
|
||||
} else {
|
||||
/* Not a valid pulse duration */
|
||||
Tracking = FALSE;
|
||||
for (uint32_t i = 0; i < PIOS_PPM_IN_MAX_NUM_CHANNELS ; i++) {
|
||||
CaptureValueNewFrame[i] = PIOS_PPM_INPUT_INVALID;
|
||||
}
|
||||
} else if (ppm_dev->Tracking) {
|
||||
/* Valid pulse duration 0.75 to 2.5 ms*/
|
||||
if (ppm_dev->DeltaTime > PIOS_PPM_IN_MIN_CHANNEL_PULSE_US
|
||||
&& ppm_dev->DeltaTime < PIOS_PPM_IN_MAX_CHANNEL_PULSE_US
|
||||
&& ppm_dev->PulseIndex < PIOS_PPM_IN_MAX_NUM_CHANNELS) {
|
||||
|
||||
ppm_dev->CaptureValueNewFrame[ppm_dev->PulseIndex] = ppm_dev->DeltaTime;
|
||||
ppm_dev->PulseIndex++;
|
||||
} else {
|
||||
/* Not a valid pulse duration */
|
||||
ppm_dev->Tracking = FALSE;
|
||||
for (uint32_t i = 0; i < PIOS_PPM_IN_MAX_NUM_CHANNELS ; i++) {
|
||||
ppm_dev->CaptureValueNewFrame[i] = PIOS_RCVR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void PIOS_PPM_Supervisor(uint32_t ppm_id) {
|
||||
/* Recover our device context */
|
||||
struct pios_ppm_dev * ppm_dev = (struct pios_ppm_dev *)ppm_id;
|
||||
|
||||
if (!PIOS_PPM_validate(ppm_dev)) {
|
||||
/* Invalid device specified */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* RTC runs at 625Hz so divide down the base rate so
|
||||
* that this loop runs at 25Hz.
|
||||
*/
|
||||
if(++supv_timer < 25) {
|
||||
if(++(ppm_dev->supv_timer) < 25) {
|
||||
return;
|
||||
}
|
||||
supv_timer = 0;
|
||||
ppm_dev->supv_timer = 0;
|
||||
|
||||
if (!Fresh) {
|
||||
Tracking = FALSE;
|
||||
if (!ppm_dev->Fresh) {
|
||||
ppm_dev->Tracking = FALSE;
|
||||
|
||||
for (int32_t i = 0; i < PIOS_PPM_IN_MAX_NUM_CHANNELS ; i++) {
|
||||
CaptureValue[i] = PIOS_PPM_INPUT_INVALID;
|
||||
CaptureValueNewFrame[i] = PIOS_PPM_INPUT_INVALID;
|
||||
ppm_dev->CaptureValue[i] = PIOS_RCVR_TIMEOUT;
|
||||
ppm_dev->CaptureValueNewFrame[i] = PIOS_RCVR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
Fresh = FALSE;
|
||||
ppm_dev->Fresh = FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -42,96 +42,131 @@ const struct pios_rcvr_driver pios_pwm_rcvr_driver = {
|
||||
};
|
||||
|
||||
/* Local Variables */
|
||||
static uint8_t CaptureState[PIOS_PWM_NUM_INPUTS];
|
||||
static uint16_t RiseValue[PIOS_PWM_NUM_INPUTS];
|
||||
static uint16_t FallValue[PIOS_PWM_NUM_INPUTS];
|
||||
static uint32_t CaptureValue[PIOS_PWM_NUM_INPUTS];
|
||||
/* 100 ms timeout without updates on channels */
|
||||
const static uint32_t PWM_SUPERVISOR_TIMEOUT = 100000;
|
||||
|
||||
static uint32_t CapCounter[PIOS_PWM_NUM_INPUTS];
|
||||
enum pios_pwm_dev_magic {
|
||||
PIOS_PWM_DEV_MAGIC = 0xab30293c,
|
||||
};
|
||||
|
||||
struct pios_pwm_dev {
|
||||
enum pios_pwm_dev_magic magic;
|
||||
const struct pios_pwm_cfg * cfg;
|
||||
|
||||
uint8_t CaptureState[PIOS_PWM_NUM_INPUTS];
|
||||
uint16_t RiseValue[PIOS_PWM_NUM_INPUTS];
|
||||
uint16_t FallValue[PIOS_PWM_NUM_INPUTS];
|
||||
uint32_t CaptureValue[PIOS_PWM_NUM_INPUTS];
|
||||
uint32_t CapCounter[PIOS_PWM_NUM_INPUTS];
|
||||
uint32_t us_since_update[PIOS_PWM_NUM_INPUTS];
|
||||
};
|
||||
|
||||
static bool PIOS_PWM_validate(struct pios_pwm_dev * pwm_dev)
|
||||
{
|
||||
return (pwm_dev->magic == PIOS_PWM_DEV_MAGIC);
|
||||
}
|
||||
|
||||
#if defined(PIOS_INCLUDE_FREERTOS)
|
||||
static struct pios_pwm_dev * PIOS_PWM_alloc(void)
|
||||
{
|
||||
struct pios_pwm_dev * pwm_dev;
|
||||
|
||||
pwm_dev = (struct pios_pwm_dev *)pvPortMalloc(sizeof(*pwm_dev));
|
||||
if (!pwm_dev) return(NULL);
|
||||
|
||||
pwm_dev->magic = PIOS_PWM_DEV_MAGIC;
|
||||
return(pwm_dev);
|
||||
}
|
||||
#else
|
||||
static struct pios_pwm_dev pios_pwm_devs[PIOS_PWM_MAX_DEVS];
|
||||
static uint8_t pios_pwm_num_devs;
|
||||
static struct pios_pwm_dev * PIOS_PWM_alloc(void)
|
||||
{
|
||||
struct pios_pwm_dev * pwm_dev;
|
||||
|
||||
if (pios_pwm_num_devs >= PIOS_PWM_MAX_DEVS) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
pwm_dev = &pios_pwm_devs[pios_pwm_num_devs++];
|
||||
pwm_dev->magic = PIOS_PWM_DEV_MAGIC;
|
||||
|
||||
return (pwm_dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void PIOS_PWM_tim_overflow_cb (uint32_t id, uint32_t context, uint8_t channel, uint16_t count);
|
||||
static void PIOS_PWM_tim_edge_cb (uint32_t id, uint32_t context, uint8_t channel, uint16_t count);
|
||||
const static struct pios_tim_callbacks tim_callbacks = {
|
||||
.overflow = PIOS_PWM_tim_overflow_cb,
|
||||
.edge = PIOS_PWM_tim_edge_cb,
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialises all the pins
|
||||
*/
|
||||
void PIOS_PWM_Init(void)
|
||||
int32_t PIOS_PWM_Init(uint32_t * pwm_id, const struct pios_pwm_cfg * cfg)
|
||||
{
|
||||
for (uint8_t i = 0; i < pios_pwm_cfg.num_channels; i++) {
|
||||
/* Flush counter variables */
|
||||
CaptureState[i] = 0;
|
||||
RiseValue[i] = 0;
|
||||
FallValue[i] = 0;
|
||||
CaptureValue[i] = 0;
|
||||
|
||||
NVIC_InitTypeDef NVIC_InitStructure = pios_pwm_cfg.irq.init;
|
||||
GPIO_InitTypeDef GPIO_InitStructure = pios_pwm_cfg.gpio_init;
|
||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = pios_pwm_cfg.tim_base_init;
|
||||
TIM_ICInitTypeDef TIM_ICInitStructure = pios_pwm_cfg.tim_ic_init;
|
||||
|
||||
struct pios_pwm_channel channel = pios_pwm_cfg.channels[i];
|
||||
|
||||
/* Enable appropriate clock to timer module */
|
||||
switch((int32_t) channel.timer) {
|
||||
case (int32_t)TIM1:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM2:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM3:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM4:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
|
||||
break;
|
||||
#ifdef STM32F10X_HD
|
||||
|
||||
case (int32_t)TIM5:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM6:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM7:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM8:
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM8_CC_IRQn;
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
PIOS_DEBUG_Assert(pwm_id);
|
||||
PIOS_DEBUG_Assert(cfg);
|
||||
|
||||
struct pios_pwm_dev * pwm_dev;
|
||||
|
||||
pwm_dev = (struct pios_pwm_dev *) PIOS_PWM_alloc();
|
||||
if (!pwm_dev) goto out_fail;
|
||||
|
||||
/* Bind the configuration to the device instance */
|
||||
pwm_dev->cfg = cfg;
|
||||
|
||||
for (uint8_t i = 0; i < PIOS_PWM_NUM_INPUTS; i++) {
|
||||
/* Flush counter variables */
|
||||
pwm_dev->CaptureState[i] = 0;
|
||||
pwm_dev->RiseValue[i] = 0;
|
||||
pwm_dev->FallValue[i] = 0;
|
||||
pwm_dev->CaptureValue[i] = PIOS_RCVR_TIMEOUT;
|
||||
}
|
||||
|
||||
uint32_t tim_id;
|
||||
if (PIOS_TIM_InitChannels(&tim_id, cfg->channels, cfg->num_channels, &tim_callbacks, (uint32_t)pwm_dev)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Configure the channels to be in capture/compare mode */
|
||||
for (uint8_t i = 0; i < cfg->num_channels; i++) {
|
||||
const struct pios_tim_channel * chan = &cfg->channels[i];
|
||||
|
||||
/* Enable GPIO */
|
||||
GPIO_InitStructure.GPIO_Pin = channel.pin;
|
||||
GPIO_Init(channel.port, &GPIO_InitStructure);
|
||||
|
||||
/* Configure timer for input capture */
|
||||
TIM_ICInitStructure.TIM_Channel = channel.channel;
|
||||
TIM_ICInit(channel.timer, &TIM_ICInitStructure);
|
||||
|
||||
/* Configure timer clocks */
|
||||
TIM_InternalClockConfig(channel.timer);
|
||||
if(channel.timer->PSC != ((PIOS_MASTER_CLOCK / 1000000) - 1))
|
||||
TIM_TimeBaseInit(channel.timer, &TIM_TimeBaseStructure);
|
||||
TIM_ICInitTypeDef TIM_ICInitStructure = cfg->tim_ic_init;
|
||||
TIM_ICInitStructure.TIM_Channel = chan->timer_chan;
|
||||
TIM_ICInit(chan->timer, &TIM_ICInitStructure);
|
||||
|
||||
/* Enable the Capture Compare Interrupt Request */
|
||||
TIM_ITConfig(channel.timer, channel.ccr, ENABLE);
|
||||
switch (chan->timer_chan) {
|
||||
case TIM_Channel_1:
|
||||
TIM_ITConfig(chan->timer, TIM_IT_CC1, ENABLE);
|
||||
break;
|
||||
case TIM_Channel_2:
|
||||
TIM_ITConfig(chan->timer, TIM_IT_CC2, ENABLE);
|
||||
break;
|
||||
case TIM_Channel_3:
|
||||
TIM_ITConfig(chan->timer, TIM_IT_CC3, ENABLE);
|
||||
break;
|
||||
case TIM_Channel_4:
|
||||
TIM_ITConfig(chan->timer, TIM_IT_CC4, ENABLE);
|
||||
break;
|
||||
}
|
||||
|
||||
// Need the update event for that timer to detect timeouts
|
||||
TIM_ITConfig(chan->timer, TIM_IT_Update, ENABLE);
|
||||
|
||||
/* Enable timers */
|
||||
TIM_Cmd(channel.timer, ENABLE);
|
||||
}
|
||||
|
||||
if(pios_pwm_cfg.remap) {
|
||||
/* Warning, I don't think this will work for multiple remaps at once */
|
||||
GPIO_PinRemapConfig(pios_pwm_cfg.remap, ENABLE);
|
||||
}
|
||||
*pwm_id = (uint32_t) pwm_dev;
|
||||
|
||||
return (0);
|
||||
|
||||
out_fail:
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,75 +177,101 @@ void PIOS_PWM_Init(void)
|
||||
*/
|
||||
static int32_t PIOS_PWM_Get(uint32_t rcvr_id, uint8_t channel)
|
||||
{
|
||||
/* Return error if channel not available */
|
||||
if (channel >= pios_pwm_cfg.num_channels) {
|
||||
return -1;
|
||||
struct pios_pwm_dev * pwm_dev = (struct pios_pwm_dev *)rcvr_id;
|
||||
|
||||
if (!PIOS_PWM_validate(pwm_dev)) {
|
||||
/* Invalid device specified */
|
||||
return PIOS_RCVR_INVALID;
|
||||
}
|
||||
return CaptureValue[channel];
|
||||
|
||||
if (channel >= PIOS_PWM_NUM_INPUTS) {
|
||||
/* Channel out of range */
|
||||
return PIOS_RCVR_INVALID;
|
||||
}
|
||||
return pwm_dev->CaptureValue[channel];
|
||||
}
|
||||
|
||||
void PIOS_PWM_irq_handler(TIM_TypeDef * timer)
|
||||
static void PIOS_PWM_tim_overflow_cb (uint32_t tim_id, uint32_t context, uint8_t channel, uint16_t count)
|
||||
{
|
||||
uint16_t val = 0;
|
||||
for(uint8_t i = 0; i < pios_pwm_cfg.num_channels; i++) {
|
||||
struct pios_pwm_channel channel = pios_pwm_cfg.channels[i];
|
||||
if ((channel.timer == timer) && (TIM_GetITStatus(channel.timer, channel.ccr) == SET)) {
|
||||
|
||||
TIM_ClearITPendingBit(channel.timer, channel.ccr);
|
||||
|
||||
switch(channel.channel) {
|
||||
case TIM_Channel_1:
|
||||
val = TIM_GetCapture1(channel.timer);
|
||||
break;
|
||||
case TIM_Channel_2:
|
||||
val = TIM_GetCapture2(channel.timer);
|
||||
break;
|
||||
case TIM_Channel_3:
|
||||
val = TIM_GetCapture3(channel.timer);
|
||||
break;
|
||||
case TIM_Channel_4:
|
||||
val = TIM_GetCapture4(channel.timer);
|
||||
break;
|
||||
}
|
||||
|
||||
if (CaptureState[i] == 0) {
|
||||
RiseValue[i] = val;
|
||||
} else {
|
||||
FallValue[i] = val;
|
||||
}
|
||||
|
||||
// flip state machine and capture value here
|
||||
/* Simple rise or fall state machine */
|
||||
TIM_ICInitTypeDef TIM_ICInitStructure = pios_pwm_cfg.tim_ic_init;
|
||||
if (CaptureState[i] == 0) {
|
||||
/* Switch states */
|
||||
CaptureState[i] = 1;
|
||||
|
||||
/* Switch polarity of input capture */
|
||||
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
|
||||
TIM_ICInitStructure.TIM_Channel = channel.channel;
|
||||
TIM_ICInit(channel.timer, &TIM_ICInitStructure);
|
||||
} else {
|
||||
/* Capture computation */
|
||||
if (FallValue[i] > RiseValue[i]) {
|
||||
CaptureValue[i] = (FallValue[i] - RiseValue[i]);
|
||||
} else {
|
||||
CaptureValue[i] = ((channel.timer->ARR - RiseValue[i]) + FallValue[i]);
|
||||
}
|
||||
|
||||
/* Switch states */
|
||||
CaptureState[i] = 0;
|
||||
|
||||
/* Increase supervisor counter */
|
||||
CapCounter[i]++;
|
||||
|
||||
/* Switch polarity of input capture */
|
||||
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
|
||||
TIM_ICInitStructure.TIM_Channel = channel.channel;
|
||||
TIM_ICInit(channel.timer, &TIM_ICInitStructure);
|
||||
}
|
||||
}
|
||||
struct pios_pwm_dev * pwm_dev = (struct pios_pwm_dev *)context;
|
||||
|
||||
if (!PIOS_PWM_validate(pwm_dev)) {
|
||||
/* Invalid device specified */
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel >= pwm_dev->cfg->num_channels) {
|
||||
/* Channel out of range */
|
||||
return;
|
||||
}
|
||||
|
||||
pwm_dev->us_since_update[channel] += count;
|
||||
if(pwm_dev->us_since_update[channel] >= PWM_SUPERVISOR_TIMEOUT) {
|
||||
pwm_dev->CaptureState[channel] = 0;
|
||||
pwm_dev->RiseValue[channel] = 0;
|
||||
pwm_dev->FallValue[channel] = 0;
|
||||
pwm_dev->CaptureValue[channel] = PIOS_RCVR_TIMEOUT;
|
||||
pwm_dev->us_since_update[channel] = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void PIOS_PWM_tim_edge_cb (uint32_t tim_id, uint32_t context, uint8_t chan_idx, uint16_t count)
|
||||
{
|
||||
/* Recover our device context */
|
||||
struct pios_pwm_dev * pwm_dev = (struct pios_pwm_dev *)context;
|
||||
|
||||
if (!PIOS_PWM_validate(pwm_dev)) {
|
||||
/* Invalid device specified */
|
||||
return;
|
||||
}
|
||||
|
||||
if (chan_idx >= pwm_dev->cfg->num_channels) {
|
||||
/* Channel out of range */
|
||||
return;
|
||||
}
|
||||
|
||||
const struct pios_tim_channel * chan = &pwm_dev->cfg->channels[chan_idx];
|
||||
|
||||
if (pwm_dev->CaptureState[chan_idx] == 0) {
|
||||
pwm_dev->RiseValue[chan_idx] = count;
|
||||
pwm_dev->us_since_update[chan_idx] = 0;
|
||||
} else {
|
||||
pwm_dev->FallValue[chan_idx] = count;
|
||||
}
|
||||
|
||||
// flip state machine and capture value here
|
||||
/* Simple rise or fall state machine */
|
||||
TIM_ICInitTypeDef TIM_ICInitStructure = pwm_dev->cfg->tim_ic_init;
|
||||
if (pwm_dev->CaptureState[chan_idx] == 0) {
|
||||
/* Switch states */
|
||||
pwm_dev->CaptureState[chan_idx] = 1;
|
||||
|
||||
/* Switch polarity of input capture */
|
||||
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
|
||||
TIM_ICInitStructure.TIM_Channel = chan->timer_chan;
|
||||
TIM_ICInit(chan->timer, &TIM_ICInitStructure);
|
||||
} else {
|
||||
/* Capture computation */
|
||||
if (pwm_dev->FallValue[chan_idx] > pwm_dev->RiseValue[chan_idx]) {
|
||||
pwm_dev->CaptureValue[chan_idx] = (pwm_dev->FallValue[chan_idx] - pwm_dev->RiseValue[chan_idx]);
|
||||
} else {
|
||||
pwm_dev->CaptureValue[chan_idx] = ((chan->timer->ARR - pwm_dev->RiseValue[chan_idx]) + pwm_dev->FallValue[chan_idx]);
|
||||
}
|
||||
|
||||
/* Switch states */
|
||||
pwm_dev->CaptureState[chan_idx] = 0;
|
||||
|
||||
/* Increase supervisor counter */
|
||||
pwm_dev->CapCounter[chan_idx]++;
|
||||
|
||||
/* Switch polarity of input capture */
|
||||
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
|
||||
TIM_ICInitStructure.TIM_Channel = chan->timer_chan;
|
||||
TIM_ICInit(chan->timer, &TIM_ICInitStructure);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -34,8 +34,6 @@
|
||||
|
||||
#if defined(PIOS_INCLUDE_SBUS)
|
||||
|
||||
/* Global Variables */
|
||||
|
||||
/* Provide a RCVR driver */
|
||||
static int32_t PIOS_SBUS_Get(uint32_t rcvr_id, uint8_t channel);
|
||||
|
||||
@ -59,27 +57,23 @@ static void PIOS_SBUS_Supervisor(uint32_t sbus_id);
|
||||
static void reset_channels(void)
|
||||
{
|
||||
for (int i = 0; i < SBUS_NUMBER_OF_CHANNELS; i++) {
|
||||
channel_data[i] = 0;
|
||||
channel_data[i] = PIOS_RCVR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* unroll_channels() function computes channel_data[] from received_data[]
|
||||
* For efficiency it unrolls first 8 channels without loops. If other
|
||||
* 8 channels are needed they can be unrolled using the same code
|
||||
* starting from s[11] instead of s[0]. Two extra digital channels are
|
||||
* accessible using (s[22] & SBUS_FLAG_DGx) logical expressions.
|
||||
* 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)
|
||||
{
|
||||
uint8_t *s = received_data;
|
||||
uint16_t *d = channel_data;
|
||||
|
||||
#if (SBUS_NUMBER_OF_CHANNELS != 8)
|
||||
#error Current S.Bus code unrolls only first 8 channels
|
||||
#endif
|
||||
|
||||
#define F(v,s) ((v) >> s) & 0x7ff
|
||||
|
||||
/* unroll channels 1-8 */
|
||||
*d++ = F(s[0] | s[1] << 8, 0);
|
||||
*d++ = F(s[1] | s[2] << 8, 3);
|
||||
*d++ = F(s[2] | s[3] << 8 | s[4] << 16, 6);
|
||||
@ -88,6 +82,20 @@ static void unroll_channels(void)
|
||||
*d++ = F(s[6] | s[7] << 8 | s[8] << 16, 7);
|
||||
*d++ = F(s[8] | s[9] << 8, 2);
|
||||
*d++ = F(s[9] | s[10] << 8, 5);
|
||||
|
||||
/* unroll channels 9-16 */
|
||||
*d++ = F(s[11] | s[12] << 8, 0);
|
||||
*d++ = F(s[12] | s[13] << 8, 3);
|
||||
*d++ = F(s[13] | s[14] << 8 | s[15] << 16, 6);
|
||||
*d++ = F(s[15] | s[16] << 8, 1);
|
||||
*d++ = F(s[16] | s[17] << 8, 4);
|
||||
*d++ = F(s[17] | s[18] << 8 | s[19] << 16, 7);
|
||||
*d++ = F(s[19] | s[20] << 8, 2);
|
||||
*d++ = F(s[20] | s[21] << 8, 5);
|
||||
|
||||
/* unroll discrete channels 17 and 18 */
|
||||
*d++ = (s[22] & SBUS_FLAG_DC1) ? SBUS_VALUE_MAX : SBUS_VALUE_MIN;
|
||||
*d++ = (s[22] & SBUS_FLAG_DC2) ? SBUS_VALUE_MAX : SBUS_VALUE_MIN;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -183,7 +191,7 @@ 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 -1;
|
||||
return PIOS_RCVR_INVALID;
|
||||
}
|
||||
return channel_data[channel];
|
||||
}
|
||||
|
@ -31,97 +31,55 @@
|
||||
/* Project Includes */
|
||||
#include "pios.h"
|
||||
#include "pios_servo_priv.h"
|
||||
#include "pios_tim_priv.h"
|
||||
|
||||
/* Private Function Prototypes */
|
||||
|
||||
static const struct pios_servo_cfg * servo_cfg;
|
||||
|
||||
/**
|
||||
* Initialise Servos
|
||||
*/
|
||||
void PIOS_Servo_Init(void)
|
||||
int32_t PIOS_Servo_Init(const struct pios_servo_cfg * cfg)
|
||||
{
|
||||
#ifndef PIOS_ENABLE_DEBUG_PINS
|
||||
#if defined(PIOS_INCLUDE_SERVO)
|
||||
uint32_t tim_id;
|
||||
if (PIOS_TIM_InitChannels(&tim_id, cfg->channels, cfg->num_channels, NULL, 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Store away the requested configuration */
|
||||
servo_cfg = cfg;
|
||||
|
||||
for (uint8_t i = 0; i < pios_servo_cfg.num_channels; i++) {
|
||||
GPIO_InitTypeDef GPIO_InitStructure = pios_servo_cfg.gpio_init;
|
||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = pios_servo_cfg.tim_base_init;
|
||||
TIM_OCInitTypeDef TIM_OCInitStructure = pios_servo_cfg.tim_oc_init;
|
||||
|
||||
struct pios_servo_channel channel = pios_servo_cfg.channels[i];
|
||||
|
||||
/* Enable appropriate clock to timer module */
|
||||
switch((int32_t) channel.timer) {
|
||||
case (int32_t)TIM1:
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM2:
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM3:
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM4:
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM5:
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM6:
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM7:
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
|
||||
break;
|
||||
case (int32_t)TIM8:
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable GPIO */
|
||||
GPIO_InitStructure.GPIO_Pin = channel.pin;
|
||||
GPIO_Init(channel.port, &GPIO_InitStructure);
|
||||
|
||||
/* Enable time base */
|
||||
TIM_TimeBaseInit(channel.timer, &TIM_TimeBaseStructure);
|
||||
|
||||
channel.timer->PSC = (PIOS_MASTER_CLOCK / 1000000) - 1;
|
||||
/* Configure the channels to be in output compare mode */
|
||||
for (uint8_t i = 0; i < cfg->num_channels; i++) {
|
||||
const struct pios_tim_channel * chan = &cfg->channels[i];
|
||||
|
||||
/* Set up for output compare function */
|
||||
switch(channel.channel) {
|
||||
switch(chan->timer_chan) {
|
||||
case TIM_Channel_1:
|
||||
TIM_OC1Init(channel.timer, &TIM_OCInitStructure);
|
||||
TIM_OC1PreloadConfig(channel.timer, TIM_OCPreload_Enable);
|
||||
TIM_OC1Init(chan->timer, &cfg->tim_oc_init);
|
||||
TIM_OC1PreloadConfig(chan->timer, TIM_OCPreload_Enable);
|
||||
break;
|
||||
case TIM_Channel_2:
|
||||
TIM_OC2Init(channel.timer, &TIM_OCInitStructure);
|
||||
TIM_OC2PreloadConfig(channel.timer, TIM_OCPreload_Enable);
|
||||
TIM_OC2Init(chan->timer, &cfg->tim_oc_init);
|
||||
TIM_OC2PreloadConfig(chan->timer, TIM_OCPreload_Enable);
|
||||
break;
|
||||
case TIM_Channel_3:
|
||||
TIM_OC3Init(channel.timer, &TIM_OCInitStructure);
|
||||
TIM_OC3PreloadConfig(channel.timer, TIM_OCPreload_Enable);
|
||||
TIM_OC3Init(chan->timer, &cfg->tim_oc_init);
|
||||
TIM_OC3PreloadConfig(chan->timer, TIM_OCPreload_Enable);
|
||||
break;
|
||||
case TIM_Channel_4:
|
||||
TIM_OC4Init(channel.timer, &TIM_OCInitStructure);
|
||||
TIM_OC4PreloadConfig(channel.timer, TIM_OCPreload_Enable);
|
||||
TIM_OC4Init(chan->timer, &cfg->tim_oc_init);
|
||||
TIM_OC4PreloadConfig(chan->timer, TIM_OCPreload_Enable);
|
||||
break;
|
||||
}
|
||||
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
||||
TIM_ARRPreloadConfig(channel.timer, ENABLE);
|
||||
TIM_CtrlPWMOutputs(channel.timer, ENABLE);
|
||||
TIM_Cmd(channel.timer, ENABLE);
|
||||
|
||||
TIM_ARRPreloadConfig(chan->timer, ENABLE);
|
||||
TIM_CtrlPWMOutputs(chan->timer, ENABLE);
|
||||
TIM_Cmd(chan->timer, ENABLE);
|
||||
}
|
||||
|
||||
if(pios_servo_cfg.remap) {
|
||||
/* Warning, I don't think this will work for multiple remaps at once */
|
||||
GPIO_PinRemapConfig(pios_servo_cfg.remap, ENABLE);
|
||||
}
|
||||
|
||||
|
||||
#endif // PIOS_INCLUDE_SERVO
|
||||
#endif // PIOS_ENABLE_DEBUG_PINS
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,31 +89,31 @@ void PIOS_Servo_Init(void)
|
||||
*/
|
||||
void PIOS_Servo_SetHz(uint16_t * speeds, uint8_t banks)
|
||||
{
|
||||
#ifndef PIOS_ENABLE_DEBUG_PINS
|
||||
#if defined(PIOS_INCLUDE_SERVO)
|
||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = pios_servo_cfg.tim_base_init;
|
||||
if (!servo_cfg) {
|
||||
return;
|
||||
}
|
||||
|
||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = servo_cfg->tim_base_init;
|
||||
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||
TIM_TimeBaseStructure.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1;
|
||||
|
||||
uint8_t set = 0;
|
||||
|
||||
for(uint8_t i = 0; (i < pios_servo_cfg.num_channels) && (set < banks); i++) {
|
||||
for(uint8_t i = 0; (i < servo_cfg->num_channels) && (set < banks); i++) {
|
||||
bool new = true;
|
||||
struct pios_servo_channel channel = pios_servo_cfg.channels[i];
|
||||
const struct pios_tim_channel * chan = &servo_cfg->channels[i];
|
||||
|
||||
/* See if any previous channels use that same timer */
|
||||
for(uint8_t j = 0; (j < i) && new; j++)
|
||||
new &= channel.timer != pios_servo_cfg.channels[j].timer;
|
||||
new &= chan->timer != servo_cfg->channels[j].timer;
|
||||
|
||||
if(new) {
|
||||
TIM_TimeBaseStructure.TIM_Period = ((1000000 / speeds[set]) - 1);
|
||||
TIM_TimeBaseInit(channel.timer, &TIM_TimeBaseStructure);
|
||||
TIM_TimeBaseInit(chan->timer, &TIM_TimeBaseStructure);
|
||||
set++;
|
||||
}
|
||||
}
|
||||
#endif // PIOS_INCLUDE_SERVO
|
||||
#endif // PIOS_ENABLE_DEBUG_PINS
|
||||
}
|
||||
|
||||
/**
|
||||
@ -163,29 +121,27 @@ void PIOS_Servo_SetHz(uint16_t * speeds, uint8_t banks)
|
||||
* \param[in] Servo Servo number (0-7)
|
||||
* \param[in] Position Servo position in microseconds
|
||||
*/
|
||||
void PIOS_Servo_Set(uint8_t Servo, uint16_t Position)
|
||||
void PIOS_Servo_Set(uint8_t servo, uint16_t position)
|
||||
{
|
||||
#ifndef PIOS_ENABLE_DEBUG_PINS
|
||||
#if defined(PIOS_INCLUDE_SERVO)
|
||||
/* Make sure servo exists */
|
||||
if (Servo < pios_servo_cfg.num_channels && Servo >= 0) {
|
||||
/* Update the position */
|
||||
|
||||
switch(pios_servo_cfg.channels[Servo].channel) {
|
||||
case TIM_Channel_1:
|
||||
TIM_SetCompare1(pios_servo_cfg.channels[Servo].timer, Position);
|
||||
break;
|
||||
case TIM_Channel_2:
|
||||
TIM_SetCompare2(pios_servo_cfg.channels[Servo].timer, Position);
|
||||
break;
|
||||
case TIM_Channel_3:
|
||||
TIM_SetCompare3(pios_servo_cfg.channels[Servo].timer, Position);
|
||||
break;
|
||||
case TIM_Channel_4:
|
||||
TIM_SetCompare4(pios_servo_cfg.channels[Servo].timer, Position);
|
||||
break;
|
||||
}
|
||||
if (!servo_cfg || servo >= servo_cfg->num_channels) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update the position */
|
||||
const struct pios_tim_channel * chan = &servo_cfg->channels[servo];
|
||||
switch(chan->timer_chan) {
|
||||
case TIM_Channel_1:
|
||||
TIM_SetCompare1(chan->timer, position);
|
||||
break;
|
||||
case TIM_Channel_2:
|
||||
TIM_SetCompare2(chan->timer, position);
|
||||
break;
|
||||
case TIM_Channel_3:
|
||||
TIM_SetCompare3(chan->timer, position);
|
||||
break;
|
||||
case TIM_Channel_4:
|
||||
TIM_SetCompare4(chan->timer, position);
|
||||
break;
|
||||
}
|
||||
#endif // PIOS_INCLUDE_SERVO
|
||||
#endif // PIOS_ENABLE_DEBUG_PINS
|
||||
}
|
||||
|
@ -30,10 +30,11 @@
|
||||
|
||||
/* Project Includes */
|
||||
#include "pios.h"
|
||||
#include "pios_spektrum_priv.h"
|
||||
|
||||
#if defined(PIOS_INCLUDE_SPEKTRUM)
|
||||
|
||||
#include "pios_spektrum_priv.h"
|
||||
|
||||
/**
|
||||
* @Note Framesyncing:
|
||||
* The code resets the watchdog timer whenever a single byte is received, so what watchdog code
|
||||
@ -51,22 +52,80 @@ const struct pios_rcvr_driver pios_spektrum_rcvr_driver = {
|
||||
.read = PIOS_SPEKTRUM_Get,
|
||||
};
|
||||
|
||||
/* Local Variables */
|
||||
static uint16_t CaptureValue[PIOS_SPEKTRUM_NUM_INPUTS],CaptureValueTemp[PIOS_SPEKTRUM_NUM_INPUTS];
|
||||
static uint8_t prev_byte = 0xFF, sync = 0, bytecount = 0, datalength=0, frame_error=0, byte_array[20] = { 0 };
|
||||
uint8_t sync_of = 0;
|
||||
uint16_t supv_timer=0;
|
||||
enum pios_spektrum_dev_magic {
|
||||
PIOS_SPEKTRUM_DEV_MAGIC = 0xa9b9c9d9,
|
||||
};
|
||||
|
||||
struct pios_spektrum_fsm {
|
||||
uint16_t channel;
|
||||
uint16_t CaptureValue[PIOS_SPEKTRUM_NUM_INPUTS];
|
||||
uint16_t CaptureValueTemp[PIOS_SPEKTRUM_NUM_INPUTS];
|
||||
uint8_t prev_byte;
|
||||
uint8_t sync;
|
||||
uint8_t bytecount;
|
||||
uint8_t datalength;
|
||||
uint8_t frame_error;
|
||||
uint8_t sync_of;
|
||||
};
|
||||
|
||||
struct pios_spektrum_dev {
|
||||
enum pios_spektrum_dev_magic magic;
|
||||
const struct pios_spektrum_cfg * cfg;
|
||||
|
||||
struct pios_spektrum_fsm fsm;
|
||||
|
||||
uint16_t supv_timer;
|
||||
};
|
||||
|
||||
static bool PIOS_SPEKTRUM_validate(struct pios_spektrum_dev * spektrum_dev)
|
||||
{
|
||||
return (spektrum_dev->magic == PIOS_SPEKTRUM_DEV_MAGIC);
|
||||
}
|
||||
|
||||
#if defined(PIOS_INCLUDE_FREERTOS)
|
||||
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_Decode(uint8_t b);
|
||||
static int32_t PIOS_SPEKTRUM_UpdateFSM(struct pios_spektrum_fsm * fsm, uint8_t b);
|
||||
|
||||
static uint16_t PIOS_SPEKTRUM_RxInCallback(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * need_yield)
|
||||
{
|
||||
struct pios_spektrum_dev * spektrum_dev = (struct pios_spektrum_dev *)context;
|
||||
|
||||
bool valid = PIOS_SPEKTRUM_validate(spektrum_dev);
|
||||
PIOS_Assert(valid);
|
||||
|
||||
/* process byte(s) and clear receive timer */
|
||||
for (uint8_t i = 0; i < buf_len; i++) {
|
||||
PIOS_SPEKTRUM_Decode(buf[i]);
|
||||
supv_timer = 0;
|
||||
PIOS_SPEKTRUM_UpdateFSM(&(spektrum_dev->fsm), buf[i]);
|
||||
spektrum_dev->supv_timer = 0;
|
||||
}
|
||||
|
||||
/* Always signal that we can accept another byte */
|
||||
@ -81,23 +140,114 @@ static uint16_t PIOS_SPEKTRUM_RxInCallback(uint32_t context, uint8_t * buf, uint
|
||||
return (buf_len);
|
||||
}
|
||||
|
||||
static void PIOS_SPEKTRUM_ResetFSM(struct pios_spektrum_fsm * fsm)
|
||||
{
|
||||
fsm->channel = 0;
|
||||
fsm->prev_byte = 0xFF;
|
||||
fsm->sync = 0;
|
||||
fsm->bytecount = 0;
|
||||
fsm->datalength = 0;
|
||||
fsm->frame_error = 0;
|
||||
fsm->sync_of = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a byte
|
||||
* \param[in] b byte which should be spektrum decoded
|
||||
* \return 0 if no error
|
||||
* \return -1 if USART not available
|
||||
* \return -2 if buffer full (retry)
|
||||
*/
|
||||
static int32_t PIOS_SPEKTRUM_UpdateFSM(struct pios_spektrum_fsm * fsm, uint8_t b)
|
||||
{
|
||||
fsm->bytecount++;
|
||||
if (fsm->sync == 0) {
|
||||
/* Known sync bytes, 0x01, 0x02, 0x12, 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;i<PIOS_SPEKTRUM_NUM_INPUTS;i++)
|
||||
{
|
||||
fsm->CaptureValue[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)
|
||||
{
|
||||
// TODO: need setting flag for bind on next powerup
|
||||
PIOS_DEBUG_Assert(spektrum_id);
|
||||
PIOS_DEBUG_Assert(cfg);
|
||||
PIOS_DEBUG_Assert(driver);
|
||||
|
||||
struct pios_spektrum_dev * spektrum_dev;
|
||||
|
||||
spektrum_dev = (struct pios_spektrum_dev *) PIOS_SPEKTRUM_alloc();
|
||||
if (!spektrum_dev) goto out_fail;
|
||||
|
||||
/* Bind the configuration to the device instance */
|
||||
spektrum_dev->cfg = cfg;
|
||||
|
||||
if (bind) {
|
||||
PIOS_SPEKTRUM_Bind(cfg,bind);
|
||||
}
|
||||
|
||||
(driver->bind_rx_cb)(lower_id, PIOS_SPEKTRUM_RxInCallback, 0);
|
||||
PIOS_SPEKTRUM_ResetFSM(&(spektrum_dev->fsm));
|
||||
|
||||
if (!PIOS_RTC_RegisterTickCallback(PIOS_SPEKTRUM_Supervisor, 0)) {
|
||||
*spektrum_id = (uint32_t)spektrum_dev;
|
||||
|
||||
(driver->bind_rx_cb)(lower_id, PIOS_SPEKTRUM_RxInCallback, *spektrum_id);
|
||||
|
||||
if (!PIOS_RTC_RegisterTickCallback(PIOS_SPEKTRUM_Supervisor, *spektrum_id)) {
|
||||
PIOS_DEBUG_Assert(0);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
out_fail:
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,11 +258,16 @@ int32_t PIOS_SPEKTRUM_Init(uint32_t * spektrum_id, const struct pios_spektrum_cf
|
||||
*/
|
||||
static int32_t PIOS_SPEKTRUM_Get(uint32_t rcvr_id, uint8_t channel)
|
||||
{
|
||||
struct pios_spektrum_dev * spektrum_dev = (struct pios_spektrum_dev *)rcvr_id;
|
||||
|
||||
if(!PIOS_SPEKTRUM_validate(spektrum_dev))
|
||||
return PIOS_RCVR_INVALID;
|
||||
|
||||
/* Return error if channel not available */
|
||||
if (channel >= PIOS_SPEKTRUM_NUM_INPUTS) {
|
||||
return -1;
|
||||
return PIOS_RCVR_INVALID;
|
||||
}
|
||||
return CaptureValue[channel];
|
||||
return spektrum_dev->fsm.CaptureValue[channel];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -151,115 +306,39 @@ static bool PIOS_SPEKTRUM_Bind(const struct pios_spektrum_cfg * cfg, uint8_t bin
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a byte
|
||||
* \param[in] b byte which should be spektrum decoded
|
||||
* \return 0 if no error
|
||||
* \return -1 if USART not available
|
||||
* \return -2 if buffer full (retry)
|
||||
* \note Applications shouldn't call these functions directly
|
||||
*/
|
||||
static int32_t PIOS_SPEKTRUM_Decode(uint8_t b)
|
||||
{
|
||||
static uint16_t channel = 0; /*, sync_word = 0;*/
|
||||
uint8_t channeln = 0, frame = 0;
|
||||
uint16_t data = 0;
|
||||
byte_array[bytecount] = b;
|
||||
bytecount++;
|
||||
if (sync == 0) {
|
||||
//sync_word = (prev_byte << 8) + b;
|
||||
#if 0
|
||||
/* maybe create object to show this data */
|
||||
if(bytecount==1)
|
||||
{
|
||||
/* record losscounter into channel8 */
|
||||
CaptureValueTemp[7]=b;
|
||||
/* instant write */
|
||||
CaptureValue[7]=b;
|
||||
}
|
||||
#endif
|
||||
/* Known sync bytes, 0x01, 0x02, 0x12, 0xb2 */
|
||||
/* 0xb2 DX8 3bind pulses only */
|
||||
if (bytecount == 2) {
|
||||
if ((b == 0x01) || (b == 0xb2)) {
|
||||
datalength=0; // 10bit
|
||||
//frames=1;
|
||||
sync = 1;
|
||||
bytecount = 2;
|
||||
}
|
||||
else if(b == 0x02) {
|
||||
datalength=0; // 10bit
|
||||
//frames=2;
|
||||
sync = 1;
|
||||
bytecount = 2;
|
||||
}
|
||||
else if(b == 0x12) {
|
||||
datalength=1; // 11bit
|
||||
//frames=2;
|
||||
sync = 1;
|
||||
bytecount = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytecount = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((bytecount % 2) == 0) {
|
||||
channel = (prev_byte << 8) + b;
|
||||
frame = channel >> 15;
|
||||
channeln = (channel >> (10+datalength)) & 0x0F;
|
||||
data = channel & (0x03FF+(0x0400*datalength));
|
||||
if(channeln==0 && data<10) // discard frame if throttle misbehaves
|
||||
{
|
||||
frame_error=1;
|
||||
}
|
||||
if (channeln < PIOS_SPEKTRUM_NUM_INPUTS && !frame_error)
|
||||
CaptureValueTemp[channeln] = data;
|
||||
}
|
||||
}
|
||||
if (bytecount == 16) {
|
||||
//PIOS_COM_SendBufferNonBlocking(PIOS_COM_TELEM_RF,byte_array,16); //00 2c 58 84 b0 dc ff
|
||||
bytecount = 0;
|
||||
sync = 0;
|
||||
sync_of = 0;
|
||||
if (!frame_error)
|
||||
{
|
||||
for(int i=0;i<PIOS_SPEKTRUM_NUM_INPUTS;i++)
|
||||
{
|
||||
CaptureValue[i] = CaptureValueTemp[i];
|
||||
}
|
||||
}
|
||||
frame_error=0;
|
||||
}
|
||||
prev_byte = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*@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) {
|
||||
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 */
|
||||
supv_timer++;
|
||||
if(supv_timer > 4) {
|
||||
spektrum_dev->supv_timer++;
|
||||
if(spektrum_dev->supv_timer > 4) {
|
||||
/* sync between frames */
|
||||
sync = 0;
|
||||
bytecount = 0;
|
||||
prev_byte = 0xFF;
|
||||
frame_error = 0;
|
||||
sync_of++;
|
||||
struct pios_spektrum_fsm * fsm = &(spektrum_dev->fsm);
|
||||
|
||||
fsm->sync = 0;
|
||||
fsm->bytecount = 0;
|
||||
fsm->prev_byte = 0xFF;
|
||||
fsm->frame_error = 0;
|
||||
fsm->sync_of++;
|
||||
/* watchdog activated after 200ms silence */
|
||||
if (sync_of > 30) {
|
||||
if (fsm->sync_of > 30) {
|
||||
|
||||
/* signal lost */
|
||||
sync_of = 0;
|
||||
fsm->sync_of = 0;
|
||||
for (int i = 0; i < PIOS_SPEKTRUM_NUM_INPUTS; i++) {
|
||||
CaptureValue[i] = 0;
|
||||
CaptureValueTemp[i] = 0;
|
||||
fsm->CaptureValue[i] = PIOS_RCVR_TIMEOUT;
|
||||
fsm->CaptureValueTemp[i] = PIOS_RCVR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
supv_timer = 0;
|
||||
spektrum_dev->supv_timer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,10 +46,10 @@ static bool PIOS_SPI_validate(struct pios_spi_dev * com_dev)
|
||||
return(true);
|
||||
}
|
||||
|
||||
#if defined(PIOS_INCLUDE_FREERTOS) && 0
|
||||
#if defined(PIOS_INCLUDE_FREERTOS)
|
||||
static struct pios_spi_dev * PIOS_SPI_alloc(void)
|
||||
{
|
||||
return (malloc(sizeof(struct pios_spi_dev)));
|
||||
return (pvPortMalloc(sizeof(struct pios_spi_dev)));
|
||||
}
|
||||
#else
|
||||
static struct pios_spi_dev pios_spi_devs[PIOS_SPI_MAX_DEVS];
|
||||
|
427
flight/PiOS/STM32F10x/pios_tim.c
Normal file
427
flight/PiOS/STM32F10x/pios_tim.c
Normal file
@ -0,0 +1,427 @@
|
||||
#include "pios.h"
|
||||
|
||||
#include "pios_tim.h"
|
||||
#include "pios_tim_priv.h"
|
||||
|
||||
enum pios_tim_dev_magic {
|
||||
PIOS_TIM_DEV_MAGIC = 0x87654098,
|
||||
};
|
||||
|
||||
struct pios_tim_dev {
|
||||
enum pios_tim_dev_magic magic;
|
||||
|
||||
const struct pios_tim_channel * channels;
|
||||
uint8_t num_channels;
|
||||
|
||||
const struct pios_tim_callbacks * callbacks;
|
||||
uint32_t context;
|
||||
};
|
||||
|
||||
#if 0
|
||||
static bool PIOS_TIM_validate(struct pios_tim_dev * tim_dev)
|
||||
{
|
||||
return (tim_dev->magic == PIOS_TIM_DEV_MAGIC);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PIOS_INCLUDE_FREERTOS) && 0
|
||||
static struct pios_tim_dev * PIOS_TIM_alloc(void)
|
||||
{
|
||||
struct pios_tim_dev * tim_dev;
|
||||
|
||||
tim_dev = (struct pios_tim_dev *)malloc(sizeof(*tim_dev));
|
||||
if (!tim_dev) return(NULL);
|
||||
|
||||
tim_dev->magic = PIOS_TIM_DEV_MAGIC;
|
||||
return(tim_dev);
|
||||
}
|
||||
#else
|
||||
static struct pios_tim_dev pios_tim_devs[PIOS_TIM_MAX_DEVS];
|
||||
static uint8_t pios_tim_num_devs;
|
||||
static struct pios_tim_dev * PIOS_TIM_alloc(void)
|
||||
{
|
||||
struct pios_tim_dev * tim_dev;
|
||||
|
||||
if (pios_tim_num_devs >= PIOS_TIM_MAX_DEVS) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
tim_dev = &pios_tim_devs[pios_tim_num_devs++];
|
||||
tim_dev->magic = PIOS_TIM_DEV_MAGIC;
|
||||
|
||||
return (tim_dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
int32_t PIOS_TIM_InitClock(const struct pios_tim_clock_cfg * cfg)
|
||||
{
|
||||
PIOS_DEBUG_Assert(cfg);
|
||||
|
||||
/* Enable appropriate clock to timer module */
|
||||
switch((uint32_t) cfg->timer) {
|
||||
case (uint32_t)TIM1:
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
|
||||
break;
|
||||
case (uint32_t)TIM2:
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
|
||||
break;
|
||||
case (uint32_t)TIM3:
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
|
||||
break;
|
||||
case (uint32_t)TIM4:
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
|
||||
break;
|
||||
#ifdef STM32F10X_HD
|
||||
case (uint32_t)TIM5:
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
|
||||
break;
|
||||
case (uint32_t)TIM6:
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
|
||||
break;
|
||||
case (uint32_t)TIM7:
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
|
||||
break;
|
||||
case (uint32_t)TIM8:
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Configure the dividers for this timer */
|
||||
TIM_TimeBaseInit(cfg->timer, cfg->time_base_init);
|
||||
|
||||
/* Configure internal timer clocks */
|
||||
TIM_InternalClockConfig(cfg->timer);
|
||||
|
||||
/* Enable timers */
|
||||
TIM_Cmd(cfg->timer, ENABLE);
|
||||
|
||||
/* Enable Interrupts */
|
||||
NVIC_Init(&cfg->irq.init);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t PIOS_TIM_InitChannels(uint32_t * tim_id, const struct pios_tim_channel * channels, uint8_t num_channels, const struct pios_tim_callbacks * callbacks, uint32_t context)
|
||||
{
|
||||
PIOS_Assert(channels);
|
||||
PIOS_Assert(num_channels);
|
||||
|
||||
struct pios_tim_dev * tim_dev;
|
||||
tim_dev = (struct pios_tim_dev *) PIOS_TIM_alloc();
|
||||
if (!tim_dev) goto out_fail;
|
||||
|
||||
/* Bind the configuration to the device instance */
|
||||
tim_dev->channels = channels;
|
||||
tim_dev->num_channels = num_channels;
|
||||
tim_dev->callbacks = callbacks;
|
||||
tim_dev->context = context;
|
||||
|
||||
/* Configure the pins */
|
||||
for (uint8_t i = 0; i < num_channels; i++) {
|
||||
const struct pios_tim_channel * chan = &(channels[i]);
|
||||
|
||||
/* Enable the peripheral clock for the GPIO */
|
||||
switch ((uint32_t)chan->pin.gpio) {
|
||||
case (uint32_t) GPIOA:
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
||||
break;
|
||||
case (uint32_t) GPIOB:
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
|
||||
break;
|
||||
case (uint32_t) GPIOC:
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
|
||||
break;
|
||||
default:
|
||||
PIOS_Assert(0);
|
||||
break;
|
||||
}
|
||||
GPIO_Init(chan->pin.gpio, &chan->pin.init);
|
||||
|
||||
if (chan->remap) {
|
||||
GPIO_PinRemapConfig(chan->remap, ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
*tim_id = (uint32_t)tim_dev;
|
||||
|
||||
return(0);
|
||||
|
||||
out_fail:
|
||||
return(-1);
|
||||
}
|
||||
|
||||
static void PIOS_TIM_generic_irq_handler(TIM_TypeDef * timer)
|
||||
{
|
||||
/* Iterate over all registered clients of the TIM layer to find channels on this timer */
|
||||
for (uint8_t i = 0; i < pios_tim_num_devs; i++) {
|
||||
const struct pios_tim_dev * tim_dev = &pios_tim_devs[i];
|
||||
|
||||
if (!tim_dev->channels || tim_dev->num_channels == 0) {
|
||||
/* No channels to process on this client */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check for an overflow event on this timer */
|
||||
bool overflow_event;
|
||||
uint16_t overflow_count;
|
||||
if (TIM_GetITStatus(timer, TIM_IT_Update) == SET) {
|
||||
TIM_ClearITPendingBit(timer, TIM_IT_Update);
|
||||
overflow_count = timer->ARR;
|
||||
overflow_event = true;
|
||||
} else {
|
||||
overflow_count = 0;
|
||||
overflow_event = false;
|
||||
}
|
||||
|
||||
for (uint8_t j = 0; j < tim_dev->num_channels; j++) {
|
||||
const struct pios_tim_channel * chan = &tim_dev->channels[j];
|
||||
|
||||
if (chan->timer != timer) {
|
||||
/* channel is not on this timer */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Figure out which interrupt bit we should be looking at */
|
||||
uint16_t timer_it;
|
||||
switch (chan->timer_chan) {
|
||||
case TIM_Channel_1:
|
||||
timer_it = TIM_IT_CC1;
|
||||
break;
|
||||
case TIM_Channel_2:
|
||||
timer_it = TIM_IT_CC2;
|
||||
break;
|
||||
case TIM_Channel_3:
|
||||
timer_it = TIM_IT_CC3;
|
||||
break;
|
||||
case TIM_Channel_4:
|
||||
timer_it = TIM_IT_CC4;
|
||||
break;
|
||||
default:
|
||||
PIOS_Assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
bool edge_event;
|
||||
uint16_t edge_count;
|
||||
if (TIM_GetITStatus(chan->timer, timer_it) == SET) {
|
||||
TIM_ClearITPendingBit(chan->timer, timer_it);
|
||||
|
||||
/* Read the current counter */
|
||||
switch(chan->timer_chan) {
|
||||
case TIM_Channel_1:
|
||||
edge_count = TIM_GetCapture1(chan->timer);
|
||||
break;
|
||||
case TIM_Channel_2:
|
||||
edge_count = TIM_GetCapture2(chan->timer);
|
||||
break;
|
||||
case TIM_Channel_3:
|
||||
edge_count = TIM_GetCapture3(chan->timer);
|
||||
break;
|
||||
case TIM_Channel_4:
|
||||
edge_count = TIM_GetCapture4(chan->timer);
|
||||
break;
|
||||
default:
|
||||
PIOS_Assert(0);
|
||||
break;
|
||||
}
|
||||
edge_event = true;
|
||||
} else {
|
||||
edge_event = false;
|
||||
edge_count = 0;
|
||||
}
|
||||
|
||||
if (!tim_dev->callbacks) {
|
||||
/* No callbacks registered, we're done with this channel */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Generate the appropriate callbacks */
|
||||
if (overflow_event & edge_event) {
|
||||
/*
|
||||
* When both edge and overflow happen in the same interrupt, we
|
||||
* need a heuristic to determine the order of the edge and overflow
|
||||
* events so that the callbacks happen in the right order. If we
|
||||
* get the order wrong, our pulse width calculations could be off by up
|
||||
* to ARR ticks. That could be bad.
|
||||
*
|
||||
* Heuristic: If the edge_count is < 16 ticks above zero then we assume the
|
||||
* edge happened just after the overflow.
|
||||
*/
|
||||
|
||||
if (edge_count < 16) {
|
||||
/* Call the overflow callback first */
|
||||
if (tim_dev->callbacks->overflow) {
|
||||
(*tim_dev->callbacks->overflow)((uint32_t)tim_dev,
|
||||
tim_dev->context,
|
||||
j,
|
||||
overflow_count);
|
||||
}
|
||||
/* Call the edge callback second */
|
||||
if (tim_dev->callbacks->edge) {
|
||||
(*tim_dev->callbacks->edge)((uint32_t)tim_dev,
|
||||
tim_dev->context,
|
||||
j,
|
||||
edge_count);
|
||||
}
|
||||
} else {
|
||||
/* Call the edge callback first */
|
||||
if (tim_dev->callbacks->edge) {
|
||||
(*tim_dev->callbacks->edge)((uint32_t)tim_dev,
|
||||
tim_dev->context,
|
||||
j,
|
||||
edge_count);
|
||||
}
|
||||
/* Call the overflow callback second */
|
||||
if (tim_dev->callbacks->overflow) {
|
||||
(*tim_dev->callbacks->overflow)((uint32_t)tim_dev,
|
||||
tim_dev->context,
|
||||
j,
|
||||
overflow_count);
|
||||
}
|
||||
}
|
||||
} else if (overflow_event && tim_dev->callbacks->overflow) {
|
||||
(*tim_dev->callbacks->overflow)((uint32_t)tim_dev,
|
||||
tim_dev->context,
|
||||
j,
|
||||
overflow_count);
|
||||
} else if (edge_event && tim_dev->callbacks->edge) {
|
||||
(*tim_dev->callbacks->edge)((uint32_t)tim_dev,
|
||||
tim_dev->context,
|
||||
j,
|
||||
edge_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
uint16_t val = 0;
|
||||
for(uint8_t i = 0; i < pios_pwm_cfg.num_channels; i++) {
|
||||
struct pios_pwm_channel channel = pios_pwm_cfg.channels[i];
|
||||
if ((channel.timer == timer) && (TIM_GetITStatus(channel.timer, channel.ccr) == SET)) {
|
||||
|
||||
TIM_ClearITPendingBit(channel.timer, channel.ccr);
|
||||
|
||||
switch(channel.channel) {
|
||||
case TIM_Channel_1:
|
||||
val = TIM_GetCapture1(channel.timer);
|
||||
break;
|
||||
case TIM_Channel_2:
|
||||
val = TIM_GetCapture2(channel.timer);
|
||||
break;
|
||||
case TIM_Channel_3:
|
||||
val = TIM_GetCapture3(channel.timer);
|
||||
break;
|
||||
case TIM_Channel_4:
|
||||
val = TIM_GetCapture4(channel.timer);
|
||||
break;
|
||||
}
|
||||
|
||||
if (CaptureState[i] == 0) {
|
||||
RiseValue[i] = val;
|
||||
} else {
|
||||
FallValue[i] = val;
|
||||
}
|
||||
|
||||
// flip state machine and capture value here
|
||||
/* Simple rise or fall state machine */
|
||||
TIM_ICInitTypeDef TIM_ICInitStructure = pios_pwm_cfg.tim_ic_init;
|
||||
if (CaptureState[i] == 0) {
|
||||
/* Switch states */
|
||||
CaptureState[i] = 1;
|
||||
|
||||
/* Switch polarity of input capture */
|
||||
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
|
||||
TIM_ICInitStructure.TIM_Channel = channel.channel;
|
||||
TIM_ICInit(channel.timer, &TIM_ICInitStructure);
|
||||
} else {
|
||||
/* Capture computation */
|
||||
if (FallValue[i] > RiseValue[i]) {
|
||||
CaptureValue[i] = (FallValue[i] - RiseValue[i]);
|
||||
} else {
|
||||
CaptureValue[i] = ((channel.timer->ARR - RiseValue[i]) + FallValue[i]);
|
||||
}
|
||||
|
||||
/* Switch states */
|
||||
CaptureState[i] = 0;
|
||||
|
||||
/* Increase supervisor counter */
|
||||
CapCounter[i]++;
|
||||
|
||||
/* Switch polarity of input capture */
|
||||
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
|
||||
TIM_ICInitStructure.TIM_Channel = channel.channel;
|
||||
TIM_ICInit(channel.timer, &TIM_ICInitStructure);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Bind Interrupt Handlers
|
||||
*
|
||||
* Map all valid TIM IRQs to the common interrupt handler
|
||||
* and give it enough context to properly demux the various timers
|
||||
*/
|
||||
void TIM1_UP_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_1_UP_irq_handler")));
|
||||
static void PIOS_TIM_1_UP_irq_handler (void)
|
||||
{
|
||||
PIOS_TIM_generic_irq_handler (TIM1);
|
||||
}
|
||||
|
||||
void TIM1_CC_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_1_CC_irq_handler")));
|
||||
static void PIOS_TIM_1_CC_irq_handler (void)
|
||||
{
|
||||
PIOS_TIM_generic_irq_handler (TIM1);
|
||||
}
|
||||
|
||||
void TIM2_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_2_irq_handler")));
|
||||
static void PIOS_TIM_2_irq_handler (void)
|
||||
{
|
||||
PIOS_TIM_generic_irq_handler (TIM2);
|
||||
}
|
||||
|
||||
void TIM3_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_3_irq_handler")));
|
||||
static void PIOS_TIM_3_irq_handler (void)
|
||||
{
|
||||
PIOS_TIM_generic_irq_handler (TIM3);
|
||||
}
|
||||
|
||||
void TIM4_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_4_irq_handler")));
|
||||
static void PIOS_TIM_4_irq_handler (void)
|
||||
{
|
||||
PIOS_TIM_generic_irq_handler (TIM4);
|
||||
}
|
||||
|
||||
void TIM5_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_5_irq_handler")));
|
||||
static void PIOS_TIM_5_irq_handler (void)
|
||||
{
|
||||
PIOS_TIM_generic_irq_handler (TIM5);
|
||||
}
|
||||
|
||||
void TIM6_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_6_irq_handler")));
|
||||
static void PIOS_TIM_6_irq_handler (void)
|
||||
{
|
||||
PIOS_TIM_generic_irq_handler (TIM6);
|
||||
}
|
||||
|
||||
void TIM7_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_7_irq_handler")));
|
||||
static void PIOS_TIM_7_irq_handler (void)
|
||||
{
|
||||
PIOS_TIM_generic_irq_handler (TIM7);
|
||||
}
|
||||
|
||||
void TIM8_UP_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_8_UP_irq_handler")));
|
||||
static void PIOS_TIM_8_UP_irq_handler (void)
|
||||
{
|
||||
PIOS_TIM_generic_irq_handler (TIM8);
|
||||
}
|
||||
|
||||
void TIM8_CC_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_8_CC_irq_handler")));
|
||||
static void PIOS_TIM_8_CC_irq_handler (void)
|
||||
{
|
||||
PIOS_TIM_generic_irq_handler (TIM8);
|
||||
}
|
||||
|
@ -70,12 +70,12 @@ static bool PIOS_USART_validate(struct pios_usart_dev * usart_dev)
|
||||
return (usart_dev->magic == PIOS_USART_DEV_MAGIC);
|
||||
}
|
||||
|
||||
#if defined(PIOS_INCLUDE_FREERTOS) && 0
|
||||
#if defined(PIOS_INCLUDE_FREERTOS)
|
||||
static struct pios_usart_dev * PIOS_USART_alloc(void)
|
||||
{
|
||||
struct pios_usart_dev * usart_dev;
|
||||
|
||||
usart_dev = (struct pios_usart_dev *)malloc(sizeof(*usart_dev));
|
||||
usart_dev = (struct pios_usart_dev *)pvPortMalloc(sizeof(*usart_dev));
|
||||
if (!usart_dev) return(NULL);
|
||||
|
||||
usart_dev->magic = PIOS_USART_DEV_MAGIC;
|
||||
|
@ -75,12 +75,12 @@ static bool PIOS_USB_HID_validate(struct pios_usb_hid_dev * usb_hid_dev)
|
||||
return (usb_hid_dev->magic == PIOS_USB_HID_DEV_MAGIC);
|
||||
}
|
||||
|
||||
#if defined(PIOS_INCLUDE_FREERTOS) && 0
|
||||
#if defined(PIOS_INCLUDE_FREERTOS)
|
||||
static struct pios_usb_hid_dev * PIOS_USB_HID_alloc(void)
|
||||
{
|
||||
struct pios_usb_hid_dev * usb_hid_dev;
|
||||
|
||||
usb_hid_dev = (struct pios_usb_hid_dev *)malloc(sizeof(*usb_hid_dev));
|
||||
usb_hid_dev = (struct pios_usb_hid_dev *)pvPortMalloc(sizeof(*usb_hid_dev));
|
||||
if (!usb_hid_dev) return(NULL);
|
||||
|
||||
usb_hid_dev->magic = PIOS_USB_HID_DEV_MAGIC;
|
||||
|
@ -33,7 +33,9 @@
|
||||
|
||||
extern const char *PIOS_DEBUG_AssertMsg;
|
||||
|
||||
void PIOS_DEBUG_Init(void);
|
||||
#include <pios_tim_priv.h>
|
||||
|
||||
void PIOS_DEBUG_Init(const struct pios_tim_channel * channels, uint8_t num_channels);
|
||||
void PIOS_DEBUG_PinHigh(uint8_t pin);
|
||||
void PIOS_DEBUG_PinLow(uint8_t pin);
|
||||
void PIOS_DEBUG_PinValue8Bit(uint8_t value);
|
||||
|
47
flight/PiOS/inc/pios_gcsrcvr_priv.h
Normal file
47
flight/PiOS/inc/pios_gcsrcvr_priv.h
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_GCSRCVR GCS Receiver Functions
|
||||
* @brief PIOS interface to read from GCS receiver port
|
||||
* @{
|
||||
*
|
||||
* @file pios_gcsrcvr_priv.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @brief GCS receiver private functions
|
||||
* @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_GCSRCVR_PRIV_H
|
||||
#define PIOS_GCSRCVR_PRIV_H
|
||||
|
||||
#include <pios.h>
|
||||
|
||||
#include "gcsreceiver.h"
|
||||
|
||||
extern const struct pios_rcvr_driver pios_gcsrcvr_rcvr_driver;
|
||||
|
||||
extern void PIOS_GCSRCVR_Init(void);
|
||||
|
||||
#endif /* PIOS_GCSRCVR_PRIV_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
@ -35,24 +35,14 @@
|
||||
#include <pios_stm32.h>
|
||||
|
||||
struct pios_ppm_cfg {
|
||||
TIM_TimeBaseInitTypeDef tim_base_init;
|
||||
TIM_ICInitTypeDef tim_ic_init;
|
||||
GPIO_InitTypeDef gpio_init;
|
||||
uint32_t remap; /* GPIO_Remap_* */
|
||||
struct stm32_irq irq;
|
||||
TIM_TypeDef * timer;
|
||||
GPIO_TypeDef * port;
|
||||
uint16_t ccr;
|
||||
const struct pios_tim_channel * channels;
|
||||
uint8_t num_channels;
|
||||
};
|
||||
|
||||
extern void PIOS_PPM_irq_handler();
|
||||
|
||||
extern uint8_t pios_ppm_num_channels;
|
||||
extern const struct pios_ppm_cfg pios_ppm_cfg;
|
||||
|
||||
extern const struct pios_rcvr_driver pios_ppm_rcvr_driver;
|
||||
|
||||
extern void PIOS_PPM_Init(void);
|
||||
extern int32_t PIOS_PPM_Init(uint32_t * ppm_id, const struct pios_ppm_cfg * cfg);
|
||||
|
||||
#endif /* PIOS_PPM_PRIV_H */
|
||||
|
||||
|
@ -34,32 +34,17 @@
|
||||
#include <pios.h>
|
||||
#include <pios_stm32.h>
|
||||
|
||||
struct pios_pwm_channel {
|
||||
TIM_TypeDef * timer;
|
||||
GPIO_TypeDef * port;
|
||||
uint16_t ccr;
|
||||
uint8_t channel;
|
||||
uint16_t pin;
|
||||
};
|
||||
#include <pios_tim_priv.h>
|
||||
|
||||
struct pios_pwm_cfg {
|
||||
TIM_TimeBaseInitTypeDef tim_base_init;
|
||||
TIM_ICInitTypeDef tim_ic_init;
|
||||
GPIO_InitTypeDef gpio_init;
|
||||
uint32_t remap; /* GPIO_Remap_* */
|
||||
struct stm32_irq irq;
|
||||
const struct pios_pwm_channel *const channels;
|
||||
const struct pios_tim_channel * channels;
|
||||
uint8_t num_channels;
|
||||
};
|
||||
|
||||
extern void PIOS_PWM_irq_handler(TIM_TypeDef * timer);
|
||||
|
||||
extern uint8_t pios_pwm_num_channels;
|
||||
extern const struct pios_pwm_cfg pios_pwm_cfg;
|
||||
|
||||
extern const struct pios_rcvr_driver pios_pwm_rcvr_driver;
|
||||
|
||||
extern void PIOS_PWM_Init(void);
|
||||
extern int32_t PIOS_PWM_Init(uint32_t * pwm_id, const struct pios_pwm_cfg * cfg);
|
||||
|
||||
#endif /* PIOS_PWM_PRIV_H */
|
||||
|
||||
|
@ -31,13 +31,6 @@
|
||||
#ifndef PIOS_RCVR_H
|
||||
#define PIOS_RCVR_H
|
||||
|
||||
struct pios_rcvr_channel_map {
|
||||
uint32_t id;
|
||||
uint8_t channel;
|
||||
};
|
||||
|
||||
extern struct pios_rcvr_channel_map pios_rcvr_channel_to_id_map[];
|
||||
|
||||
struct pios_rcvr_driver {
|
||||
void (*init)(uint32_t id);
|
||||
int32_t (*read)(uint32_t id, uint8_t channel);
|
||||
@ -46,6 +39,16 @@ struct pios_rcvr_driver {
|
||||
/* Public Functions */
|
||||
extern int32_t PIOS_RCVR_Read(uint32_t rcvr_id, uint8_t channel);
|
||||
|
||||
/*! Define error codes for PIOS_RCVR_Get */
|
||||
enum PIOS_RCVR_errors {
|
||||
/*! Indicates that a failsafe condition or missing receiver detected for that channel */
|
||||
PIOS_RCVR_TIMEOUT = 0,
|
||||
/*! Channel is invalid for this driver (usually out of range supported) */
|
||||
PIOS_RCVR_INVALID = -1,
|
||||
/*! Indicates that the driver for this channel has not been initialized */
|
||||
PIOS_RCVR_NODRIVER = -2
|
||||
};
|
||||
|
||||
#endif /* PIOS_RCVR_H */
|
||||
|
||||
/**
|
||||
|
@ -44,8 +44,8 @@
|
||||
* 1 byte - 0x0f (start of frame byte)
|
||||
* 22 bytes - channel data (11 bit/channel, 16 channels, LSB first)
|
||||
* 1 byte - bit flags:
|
||||
* 0x01 - digital channel 1,
|
||||
* 0x02 - digital channel 2,
|
||||
* 0x01 - discrete channel 1,
|
||||
* 0x02 - discrete channel 2,
|
||||
* 0x04 - lost frame flag,
|
||||
* 0x08 - failsafe flag,
|
||||
* 0xf0 - reserved
|
||||
@ -54,16 +54,20 @@
|
||||
#define SBUS_FRAME_LENGTH (1+22+1+1)
|
||||
#define SBUS_SOF_BYTE 0x0f
|
||||
#define SBUS_EOF_BYTE 0x00
|
||||
#define SBUS_FLAG_DG1 0x01
|
||||
#define SBUS_FLAG_DG2 0x02
|
||||
#define SBUS_FLAG_DC1 0x01
|
||||
#define SBUS_FLAG_DC2 0x02
|
||||
#define SBUS_FLAG_FL 0x04
|
||||
#define SBUS_FLAG_FS 0x08
|
||||
|
||||
/*
|
||||
* S.Bus protocol provides up to 16 analog and 2 digital channels.
|
||||
* Only 8 channels are currently supported by the OpenPilot.
|
||||
* S.Bus protocol provides 16 proportional and 2 discrete channels.
|
||||
* Do not change unless driver code is updated accordingly.
|
||||
*/
|
||||
#define SBUS_NUMBER_OF_CHANNELS 8
|
||||
#define SBUS_NUMBER_OF_CHANNELS (16 + 2)
|
||||
|
||||
/* Discrete channels represented as bits, provide values for them */
|
||||
#define SBUS_VALUE_MIN 352
|
||||
#define SBUS_VALUE_MAX 1696
|
||||
|
||||
/*
|
||||
* S.Bus configuration programmable invertor
|
||||
|
@ -31,7 +31,6 @@
|
||||
#define PIOS_SERVO_H
|
||||
|
||||
/* Public Functions */
|
||||
extern void PIOS_Servo_Init(void);
|
||||
extern void PIOS_Servo_SetHz(uint16_t * update_rates, uint8_t channels);
|
||||
extern void PIOS_Servo_Set(uint8_t Servo, uint16_t Position);
|
||||
|
||||
|
@ -33,25 +33,18 @@
|
||||
|
||||
#include <pios.h>
|
||||
#include <pios_stm32.h>
|
||||
|
||||
struct pios_servo_channel {
|
||||
TIM_TypeDef * timer;
|
||||
GPIO_TypeDef * port;
|
||||
uint8_t channel;
|
||||
uint16_t pin;
|
||||
};
|
||||
#include <pios_tim_priv.h>
|
||||
|
||||
struct pios_servo_cfg {
|
||||
TIM_TimeBaseInitTypeDef tim_base_init;
|
||||
TIM_OCInitTypeDef tim_oc_init;
|
||||
GPIO_InitTypeDef gpio_init;
|
||||
uint32_t remap;
|
||||
const struct pios_servo_channel *const channels;
|
||||
const struct pios_tim_channel * channels;
|
||||
uint8_t num_channels;
|
||||
};
|
||||
|
||||
|
||||
extern const struct pios_servo_cfg pios_servo_cfg;
|
||||
extern int32_t PIOS_Servo_Init(const struct pios_servo_cfg * cfg);
|
||||
|
||||
#endif /* PIOS_SERVO_PRIV_H */
|
||||
|
||||
|
@ -44,7 +44,7 @@ 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_PWM_PRIV_H */
|
||||
#endif /* PIOS_SPEKTRUM_PRIV_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
4
flight/PiOS/inc/pios_tim.h
Normal file
4
flight/PiOS/inc/pios_tim.h
Normal file
@ -0,0 +1,4 @@
|
||||
#ifndef PIOS_TIM_H
|
||||
#define PIOS_TIM_H
|
||||
|
||||
#endif /* PIOS_TIM_H */
|
28
flight/PiOS/inc/pios_tim_priv.h
Normal file
28
flight/PiOS/inc/pios_tim_priv.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef PIOS_TIM_PRIV_H
|
||||
#define PIOS_TIM_PRIV_H
|
||||
|
||||
#include <pios_stm32.h>
|
||||
|
||||
struct pios_tim_clock_cfg {
|
||||
TIM_TypeDef * timer;
|
||||
const TIM_TimeBaseInitTypeDef * time_base_init;
|
||||
struct stm32_irq irq;
|
||||
};
|
||||
|
||||
struct pios_tim_channel {
|
||||
TIM_TypeDef * timer;
|
||||
uint8_t timer_chan;
|
||||
|
||||
struct stm32_gpio pin;
|
||||
uint32_t remap;
|
||||
};
|
||||
|
||||
struct pios_tim_callbacks {
|
||||
void (*overflow)(uint32_t tim_id, uint32_t context, uint8_t chan_idx, uint16_t count);
|
||||
void (*edge)(uint32_t tim_id, uint32_t context, uint8_t chan_idx, uint16_t count);
|
||||
};
|
||||
|
||||
extern int32_t PIOS_TIM_InitClock(const struct pios_tim_clock_cfg * cfg);
|
||||
extern int32_t PIOS_TIM_InitChannels(uint32_t * tim_id, const struct pios_tim_channel * channels, uint8_t num_channels, const struct pios_tim_callbacks * callbacks, uint32_t context);
|
||||
|
||||
#endif /* PIOS_TIM_PRIV_H */
|
@ -394,7 +394,7 @@ $(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin
|
||||
$(eval $(call OPFW_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BOARD_TYPE),$(BOARD_REVISION)))
|
||||
|
||||
# Add jtag targets (program and wipe)
|
||||
$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE)))
|
||||
$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE),$(OPENOCD_CONFIG)))
|
||||
|
||||
.PHONY: elf lss sym hex bin bino opfw
|
||||
elf: $(OUTDIR)/$(TARGET).elf
|
||||
|
75
flight/Project/OpenOCD/stm32f1x.cfg
Normal file
75
flight/Project/OpenOCD/stm32f1x.cfg
Normal file
@ -0,0 +1,75 @@
|
||||
# script for stm32
|
||||
|
||||
if { [info exists CHIPNAME] } {
|
||||
set _CHIPNAME $CHIPNAME
|
||||
} else {
|
||||
set _CHIPNAME stm32
|
||||
}
|
||||
|
||||
if { [info exists ENDIAN] } {
|
||||
set _ENDIAN $ENDIAN
|
||||
} else {
|
||||
set _ENDIAN little
|
||||
}
|
||||
|
||||
# Work-area is a space in RAM used for flash programming
|
||||
# By default use 16kB
|
||||
if { [info exists WORKAREASIZE] } {
|
||||
set _WORKAREASIZE $WORKAREASIZE
|
||||
} else {
|
||||
set _WORKAREASIZE 0x4000
|
||||
}
|
||||
|
||||
# JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz
|
||||
adapter_khz 1000
|
||||
|
||||
adapter_nsrst_delay 100
|
||||
jtag_ntrst_delay 100
|
||||
|
||||
#jtag scan chain
|
||||
if { [info exists CPUTAPID ] } {
|
||||
set _CPUTAPID $CPUTAPID
|
||||
} else {
|
||||
# See STM Document RM0008
|
||||
# Section 26.6.3
|
||||
set _CPUTAPID 0x3ba00477
|
||||
}
|
||||
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
|
||||
|
||||
if { [info exists BSTAPID ] } {
|
||||
# FIXME this never gets used to override defaults...
|
||||
set _BSTAPID $BSTAPID
|
||||
} else {
|
||||
# See STM Document RM0008
|
||||
# Section 29.6.2
|
||||
# Low density devices, Rev A
|
||||
set _BSTAPID1 0x06412041
|
||||
# Medium density devices, Rev A
|
||||
set _BSTAPID2 0x06410041
|
||||
# Medium density devices, Rev B and Rev Z
|
||||
set _BSTAPID3 0x16410041
|
||||
set _BSTAPID4 0x06420041
|
||||
# High density devices, Rev A
|
||||
set _BSTAPID5 0x06414041
|
||||
# Connectivity line devices, Rev A and Rev Z
|
||||
set _BSTAPID6 0x06418041
|
||||
# XL line devices, Rev A
|
||||
set _BSTAPID7 0x06430041
|
||||
}
|
||||
jtag newtap $_CHIPNAME bs -irlen 5 -expected-id $_BSTAPID1 \
|
||||
-expected-id $_BSTAPID2 -expected-id $_BSTAPID3 \
|
||||
-expected-id $_BSTAPID4 -expected-id $_BSTAPID5 \
|
||||
-expected-id $_BSTAPID6 -expected-id $_BSTAPID7
|
||||
|
||||
set _TARGETNAME $_CHIPNAME.cpu
|
||||
target create $_TARGETNAME cortex_m3 -endian $_ENDIAN -chain-position $_TARGETNAME -rtos auto
|
||||
|
||||
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
|
||||
|
||||
# flash size will be probed
|
||||
set _FLASHNAME $_CHIPNAME.flash
|
||||
flash bank $_FLASHNAME stm32f1x 0x08000000 0 0 0 $_TARGETNAME
|
||||
|
||||
# if srst is not fitted use SYSRESETREQ to
|
||||
# perform a soft reset
|
||||
cortex_m3 reset_config sysresetreq
|
61
flight/Project/OpenOCD/stm32f2x.cfg
Normal file
61
flight/Project/OpenOCD/stm32f2x.cfg
Normal file
@ -0,0 +1,61 @@
|
||||
# script for stm32f2xxx
|
||||
|
||||
if { [info exists CHIPNAME] } {
|
||||
set _CHIPNAME $CHIPNAME
|
||||
} else {
|
||||
set _CHIPNAME stm32f2xxx
|
||||
}
|
||||
|
||||
if { [info exists ENDIAN] } {
|
||||
set _ENDIAN $ENDIAN
|
||||
} else {
|
||||
set _ENDIAN little
|
||||
}
|
||||
|
||||
# Work-area is a space in RAM used for flash programming
|
||||
# By default use 64kB
|
||||
if { [info exists WORKAREASIZE] } {
|
||||
set _WORKAREASIZE $WORKAREASIZE
|
||||
} else {
|
||||
set _WORKAREASIZE 0x10000
|
||||
}
|
||||
|
||||
# JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz
|
||||
#
|
||||
# Since we may be running of an RC oscilator, we crank down the speed a
|
||||
# bit more to be on the safe side. Perhaps superstition, but if are
|
||||
# running off a crystal, we can run closer to the limit. Note
|
||||
# that there can be a pretty wide band where things are more or less stable.
|
||||
jtag_khz 1000
|
||||
|
||||
jtag_nsrst_delay 100
|
||||
jtag_ntrst_delay 100
|
||||
|
||||
#jtag scan chain
|
||||
if { [info exists CPUTAPID ] } {
|
||||
set _CPUTAPID $CPUTAPID
|
||||
} else {
|
||||
# See STM Document RM0033
|
||||
# Section 32.6.3 - corresponds to Cortex-M3 r2p0
|
||||
set _CPUTAPID 0x4ba00477
|
||||
}
|
||||
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
|
||||
|
||||
if { [info exists BSTAPID ] } {
|
||||
set _BSTAPID $BSTAPID
|
||||
} else {
|
||||
# See STM Document RM0033
|
||||
# Section 32.6.2
|
||||
#
|
||||
set _BSTAPID 0x06411041
|
||||
}
|
||||
jtag newtap $_CHIPNAME bs -irlen 5 -expected-id $_BSTAPID
|
||||
|
||||
set _TARGETNAME $_CHIPNAME.cpu
|
||||
target create $_TARGETNAME cortex_m3 -endian $_ENDIAN -chain-position $_TARGETNAME -rtos auto
|
||||
|
||||
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
|
||||
|
||||
set _FLASHNAME $_CHIPNAME.flash
|
||||
flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME
|
||||
|
@ -91,6 +91,16 @@
|
||||
65632DF51251650300469B77 /* pios_board.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_board.h; sourceTree = "<group>"; };
|
||||
65632DF61251650300469B77 /* STM32103CB_AHRS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STM32103CB_AHRS.h; sourceTree = "<group>"; };
|
||||
65632DF71251650300469B77 /* STM3210E_OP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STM3210E_OP.h; sourceTree = "<group>"; };
|
||||
65643CAB1413322000A32F59 /* pios_rcvr_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_rcvr_priv.h; sourceTree = "<group>"; };
|
||||
65643CAC1413322000A32F59 /* pios_rcvr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_rcvr.h; sourceTree = "<group>"; };
|
||||
65643CAD1413322000A32F59 /* pios_rtc_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_rtc_priv.h; sourceTree = "<group>"; };
|
||||
65643CAE1413322000A32F59 /* pios_sbus_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_sbus_priv.h; sourceTree = "<group>"; };
|
||||
65643CAF1413322000A32F59 /* pios_sbus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_sbus.h; sourceTree = "<group>"; };
|
||||
65643CB01413322000A32F59 /* pios_spektrum_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_spektrum_priv.h; sourceTree = "<group>"; };
|
||||
65643CB91413456D00A32F59 /* pios_tim.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pios_tim.c; sourceTree = "<group>"; };
|
||||
65643CBA141350C200A32F59 /* pios_sbus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pios_sbus.c; sourceTree = "<group>"; };
|
||||
65643CEC141429A100A32F59 /* NMEA.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = NMEA.c; sourceTree = "<group>"; };
|
||||
65643CEE141429AF00A32F59 /* NMEA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NMEA.h; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
@ -7724,11 +7734,17 @@
|
||||
65E8F04811EFF25C00BBF654 /* pios_ppm.h */,
|
||||
65E8F04911EFF25C00BBF654 /* pios_pwm.h */,
|
||||
657FF86A12EA8BFB00801617 /* pios_pwm_priv.h */,
|
||||
65643CAC1413322000A32F59 /* pios_rcvr.h */,
|
||||
65643CAB1413322000A32F59 /* pios_rcvr_priv.h */,
|
||||
6589A9E2131DF1C7006BD67C /* pios_rtc.h */,
|
||||
65643CAD1413322000A32F59 /* pios_rtc_priv.h */,
|
||||
65643CAE1413322000A32F59 /* pios_sbus_priv.h */,
|
||||
65643CAF1413322000A32F59 /* pios_sbus.h */,
|
||||
65E8F04A11EFF25C00BBF654 /* pios_sdcard.h */,
|
||||
65E8F04B11EFF25C00BBF654 /* pios_servo.h */,
|
||||
65FBE14412E7C98100176B5A /* pios_servo_priv.h */,
|
||||
65E8F04C11EFF25C00BBF654 /* pios_spektrum.h */,
|
||||
65643CB01413322000A32F59 /* pios_spektrum_priv.h */,
|
||||
65E8F04D11EFF25C00BBF654 /* pios_spi.h */,
|
||||
65E8F04E11EFF25C00BBF654 /* pios_spi_priv.h */,
|
||||
65E8F04F11EFF25C00BBF654 /* pios_stm32.h */,
|
||||
@ -7752,6 +7768,24 @@
|
||||
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 */,
|
||||
@ -7766,10 +7800,12 @@
|
||||
65E8F0E411EFF25C00BBF654 /* pios_ppm.c */,
|
||||
65E8F0E511EFF25C00BBF654 /* pios_pwm.c */,
|
||||
6589A9DB131DEE76006BD67C /* pios_rtc.c */,
|
||||
65643CBA141350C200A32F59 /* pios_sbus.c */,
|
||||
65E8F0E611EFF25C00BBF654 /* pios_servo.c */,
|
||||
65E8F0E711EFF25C00BBF654 /* pios_spektrum.c */,
|
||||
65E8F0E811EFF25C00BBF654 /* pios_spi.c */,
|
||||
65E8F0E911EFF25C00BBF654 /* pios_sys.c */,
|
||||
65643CB91413456D00A32F59 /* pios_tim.c */,
|
||||
65E8F0EA11EFF25C00BBF654 /* pios_usart.c */,
|
||||
65E8F0ED11EFF25C00BBF654 /* pios_usb_hid.c */,
|
||||
651CF9E5120B5D8300EEFD70 /* pios_usb_hid_desc.c */,
|
||||
@ -7787,8 +7823,6 @@
|
||||
65E8F05911EFF25C00BBF654 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6572CB1613D0F2B200FC2972 /* link_STM32103CB_CC_Rev1_memory.ld */,
|
||||
6572CB1713D0F2B200FC2972 /* link_STM32103CB_CC_Rev1_sections.ld */,
|
||||
65E8F05A11EFF25C00BBF654 /* CMSIS */,
|
||||
65E8F06B11EFF25C00BBF654 /* dosfs */,
|
||||
65E8F07111EFF25C00BBF654 /* FreeRTOS */,
|
||||
|
@ -1,99 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Generate a version blob for
|
||||
# the OpenPilot firmware.
|
||||
#
|
||||
# By E. Lafargue (c) 2011 E. Lafargue & the OpenPilot team
|
||||
# Licence: GPLv3
|
||||
#
|
||||
###
|
||||
# Usage:
|
||||
# versionblob.py --append --firmware=<Firmware file name> --boardid=<Board code>
|
||||
#
|
||||
# append: if present, then append blob to firmware file directly, otherwise create "blob.bin"
|
||||
# firmware: the filename of the firmware binary
|
||||
# boardid: as a string, the board code, for example "0401" for CC board version 1.
|
||||
# should match the codes in firmware description files.
|
||||
#
|
||||
# We have 100 bytes for the whole description.
|
||||
#
|
||||
# Only the first 40 are visible on the FirmwareIAP uavobject, the remaining
|
||||
# 60 are ok to use for packaging and will be saved in the flash
|
||||
#
|
||||
# Structure is:
|
||||
# 4 bytes: header: "OpFw"
|
||||
# 4 bytes: GIT commit tag (short version of SHA1)
|
||||
# 4 bytes: Unix timestamp of compile time
|
||||
# 2 bytes: target platform. Should follow same rule as BOARD_TYPE and BOARD_REVISION in board define files.
|
||||
# 26 bytes: commit tag if it is there, otherwise branch name. Zero-padded
|
||||
# ---- 40 bytes limit ---
|
||||
# 20 bytes: SHA1 sum of the firmware.
|
||||
# 40 bytes: free for now.
|
||||
|
||||
import binascii
|
||||
import os
|
||||
from time import time
|
||||
import argparse
|
||||
|
||||
# Do the argument parsing:
|
||||
parser = argparse.ArgumentParser(description='Generate firmware desciption blob')
|
||||
parser.add_argument('--append', action='store_true')
|
||||
parser.add_argument('--firmware', help='name of firmware binary file' , required=True)
|
||||
parser.add_argument('--boardid', help='ID of board model, for example 0401 for CopterControl', required=True)
|
||||
args = parser.parse_args()
|
||||
print args
|
||||
|
||||
if args.append == True:
|
||||
print 'Appending description blob directly to ' + args.firmware
|
||||
filename = args.firmware
|
||||
file = open(filename,"ab")
|
||||
else:
|
||||
filename = 'blob.bin'
|
||||
file = open(filename,"wb")
|
||||
|
||||
|
||||
# Write the magic value:
|
||||
file.write("OpFw")
|
||||
# Get the short commit tag of the current git repository.
|
||||
# Strip it to 8 characters for a 4 byte (int32) value.
|
||||
# We have no full guarantee of unicity, but it is good enough
|
||||
# with the rest of the information in the structure.
|
||||
hs= os.popen('git rev-parse --short=8 HEAD').read().strip()
|
||||
print "Version: " + hs
|
||||
hb=binascii.a2b_hex(hs)
|
||||
file.write(hb)
|
||||
# Then the Unix time into a 32 bit integer:
|
||||
print "Date: " + hex(int(time())).lstrip('0x')
|
||||
hb = binascii.a2b_hex(hex(int(time())).lstrip('0x'))
|
||||
file.write(hb)
|
||||
|
||||
# Then write board type and board revision
|
||||
hb = binascii.a2b_hex(args.boardid)
|
||||
file.write(hb)
|
||||
|
||||
# Last: a user-friendly description if it exists in GIT, otherwise
|
||||
# just "unreleased"
|
||||
hs = os.popen('git describe --exact-match').read()
|
||||
if len(hs) == 0 :
|
||||
print "Unreleased: get branch name instead"
|
||||
hs = os.popen('git branch --contains HEAD').read()
|
||||
|
||||
file.write(hs[0:26])
|
||||
file.write("\0"*(26-len(hs)))
|
||||
|
||||
## Now we are at the 40 bytes mark.
|
||||
|
||||
## Add the 20 byte SHA1 hash of the firmware:
|
||||
import hashlib
|
||||
sha1 = hashlib.sha1()
|
||||
with open('build/coptercontrol/CopterControl.bin','rb') as f:
|
||||
for chunk in iter(lambda: f.read(8192), ''):
|
||||
sha1.update(chunk)
|
||||
file.write(sha1.digest())
|
||||
|
||||
# Pad will null bytes:
|
||||
file.write('\0'*40)
|
||||
|
||||
|
||||
file.close()
|
||||
|
@ -65,7 +65,7 @@ MyTabbedStackWidget::MyTabbedStackWidget(QWidget *parent, bool isVertical, bool
|
||||
m_stackWidget->setContentsMargins(0, 0, 0, 0);
|
||||
setLayout(toplevelLayout);
|
||||
|
||||
connect(m_listWidget, SIGNAL(currentRowChanged(int)), this, SLOT(showWidget(int)));
|
||||
connect(m_listWidget, SIGNAL(currentRowChanged(int)), this, SLOT(showWidget(int)),Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void MyTabbedStackWidget::insertTab(const int index, QWidget *tab, const QIcon &icon, const QString &label)
|
||||
@ -97,9 +97,19 @@ void MyTabbedStackWidget::setCurrentIndex(int index)
|
||||
|
||||
void MyTabbedStackWidget::showWidget(int index)
|
||||
{
|
||||
emit currentAboutToShow(index);
|
||||
m_stackWidget->setCurrentIndex(index);
|
||||
emit currentChanged(index);
|
||||
if(m_stackWidget->currentIndex()==index)
|
||||
return;
|
||||
bool proceed=false;
|
||||
emit currentAboutToShow(index,&proceed);
|
||||
if(proceed)
|
||||
{
|
||||
m_stackWidget->setCurrentIndex(index);
|
||||
emit currentChanged(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_listWidget->setCurrentRow(m_stackWidget->currentIndex(),QItemSelectionModel::ClearAndSelect);
|
||||
}
|
||||
}
|
||||
|
||||
void MyTabbedStackWidget::insertCornerWidget(int index, QWidget *widget)
|
||||
|
@ -51,9 +51,10 @@ public:
|
||||
|
||||
void insertCornerWidget(int index, QWidget *widget);
|
||||
int cornerWidgetCount() { return m_cornerWidgetCount; }
|
||||
QWidget * currentWidget(){return m_stackWidget->currentWidget();}
|
||||
|
||||
signals:
|
||||
void currentAboutToShow(int index);
|
||||
void currentAboutToShow(int index,bool * proceed);
|
||||
void currentChanged(int index);
|
||||
|
||||
public slots:
|
||||
|
@ -87,7 +87,7 @@
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Receiver type</string>
|
||||
<string>RcvrPort</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
@ -95,7 +95,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QComboBox" name="receiverType"/>
|
||||
<widget class="QComboBox" name="cbRcvr"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
@ -70,7 +70,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="BasicTab">
|
||||
<attribute name="title">
|
||||
@ -880,7 +880,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="ccpmLinkRoll">
|
||||
<property name="text">
|
||||
<string>Link Roll/Pitch</string>
|
||||
@ -890,7 +890,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="ccpmLinkCyclic">
|
||||
<property name="text">
|
||||
<string>Link Cyclic/Collective</string>
|
||||
@ -900,80 +900,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout" name="ccpmCollectiveChannelBox">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetNoConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="ccpmCollectiveChLabel">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>11</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Collective Ch</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="ccpmCollectiveChannel">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -38,6 +38,7 @@ HEADERS += configplugin.h \
|
||||
defaultattitudewidget.h \
|
||||
smartsavebutton.h \
|
||||
defaulthwsettingswidget.h \
|
||||
inputchannelform.h \
|
||||
configcamerastabilizationwidget.h
|
||||
|
||||
SOURCES += configplugin.cpp \
|
||||
@ -67,6 +68,7 @@ SOURCES += configplugin.cpp \
|
||||
defaultattitudewidget.cpp \
|
||||
smartsavebutton.cpp \
|
||||
defaulthwsettingswidget.cpp \
|
||||
inputchannelform.cpp \
|
||||
configcamerastabilizationwidget.cpp
|
||||
|
||||
FORMS += \
|
||||
@ -81,6 +83,7 @@ FORMS += \
|
||||
ccattitude.ui \
|
||||
defaultattitude.ui \
|
||||
defaulthwsettings.ui \
|
||||
inputchannelform.ui \
|
||||
camerastabilization.ui
|
||||
|
||||
RESOURCES += configgadget.qrc
|
||||
|
@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
*
|
||||
* @file configtelemetrywidget.h
|
||||
* @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup ConfigPlugin Config Plugin
|
||||
@ -43,7 +43,7 @@ ConfigCCHWWidget::ConfigCCHWWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
addUAVObjectToWidgetRelation("TelemetrySettings","Speed",m_telemetry->telemetrySpeed);
|
||||
addUAVObjectToWidgetRelation("HwSettings","CC_FlexiPort",m_telemetry->cbFlexi);
|
||||
addUAVObjectToWidgetRelation("HwSettings","CC_MainPort",m_telemetry->cbTele);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","InputMode",m_telemetry->receiverType);
|
||||
addUAVObjectToWidgetRelation("HwSettings","CC_RcvrPort",m_telemetry->cbRcvr);
|
||||
connect(m_telemetry->cchwHelp,SIGNAL(clicked()),this,SLOT(openHelp()));
|
||||
enableControls(false);
|
||||
populateWidgets();
|
||||
@ -67,22 +67,6 @@ void ConfigCCHWWidget::widgetsContentsChanged()
|
||||
{
|
||||
m_telemetry->problems->setText("Warning: you have configured the MainPort and the FlexiPort for the same function, this is currently not suported");
|
||||
}
|
||||
else if((m_telemetry->cbTele->currentText()=="Spektrum" ||m_telemetry->cbFlexi->currentText()=="Spektrum") && m_telemetry->receiverType->currentText()!="Spektrum")
|
||||
{
|
||||
m_telemetry->problems->setText("Warning: you have a port configured as 'Spektrum' however that is not your selected receiver type");
|
||||
}
|
||||
else if(m_telemetry->cbTele->currentText()=="S.Bus" && m_telemetry->receiverType->currentText()!="S.Bus")
|
||||
{
|
||||
m_telemetry->problems->setText("Warning: you have a port configured as 'S.Bus' however that is not your selected receiver type");
|
||||
}
|
||||
else if(m_telemetry->cbTele->currentText()!="S.Bus" && m_telemetry->receiverType->currentText()=="S.Bus")
|
||||
{
|
||||
m_telemetry->problems->setText("Warning: you have selected 'S.Bus' as your receiver type however you have no port configured for that protocol");
|
||||
}
|
||||
else if((m_telemetry->cbTele->currentText()!="Spektrum" && m_telemetry->cbFlexi->currentText()!="Spektrum") && m_telemetry->receiverType->currentText()=="Spektrum")
|
||||
{
|
||||
m_telemetry->problems->setText("Warning: you have selected 'Spektrum' as your receiver type however you have no port configured for that protocol");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_telemetry->problems->setText("");
|
||||
|
@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
*
|
||||
* @file configtelemetrywidget.h
|
||||
* @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup ConfigPlugin Config Plugin
|
||||
|
@ -92,26 +92,7 @@ ConfigAirframeWidget::ConfigAirframeWidget(QWidget *parent) : ConfigTaskWidget(p
|
||||
m_aircraft->setupUi(this);
|
||||
|
||||
setupButtons(m_aircraft->saveAircraftToRAM,m_aircraft->saveAircraftToSD);
|
||||
addWidget(m_aircraft->customMixerTable);
|
||||
addWidget(m_aircraft->customThrottle2Curve);
|
||||
addWidget(m_aircraft->customThrottle1Curve);
|
||||
addWidget(m_aircraft->multiThrottleCurve);
|
||||
addWidget(m_aircraft->fixedWingThrottle);
|
||||
addWidget(m_aircraft->fixedWingType);
|
||||
addWidget(m_aircraft->feedForwardSlider);
|
||||
addWidget(m_aircraft->accelTime);
|
||||
addWidget(m_aircraft->decelTime);
|
||||
addWidget(m_aircraft->maxAccelSlider);
|
||||
addWidget(m_aircraft->multirotorFrameType);
|
||||
addWidget(m_aircraft->multiMotor1);
|
||||
addWidget(m_aircraft->multiMotor2);
|
||||
addWidget(m_aircraft->multiMotor3);
|
||||
addWidget(m_aircraft->multiMotor4);
|
||||
addWidget(m_aircraft->multiMotor5);
|
||||
addWidget(m_aircraft->multiMotor6);
|
||||
addWidget(m_aircraft->multiMotor7);
|
||||
addWidget(m_aircraft->multiMotor8);
|
||||
addWidget(m_aircraft->triYawChannel);
|
||||
|
||||
addUAVObject("SystemSettings");
|
||||
addUAVObject("MixerSettings");
|
||||
addUAVObject("ActuatorSettings");
|
||||
@ -217,7 +198,7 @@ ConfigAirframeWidget::ConfigAirframeWidget(QWidget *parent) : ConfigTaskWidget(p
|
||||
|
||||
// Connect the help button
|
||||
connect(m_aircraft->airframeHelp, SIGNAL(clicked()), this, SLOT(openHelp()));
|
||||
|
||||
addToDirtyMonitor();
|
||||
}
|
||||
|
||||
ConfigAirframeWidget::~ConfigAirframeWidget()
|
||||
@ -462,6 +443,7 @@ void ConfigAirframeWidget::updateCustomThrottle2CurveValue(QList<double> list, d
|
||||
*/
|
||||
void ConfigAirframeWidget::refreshWidgetsValues()
|
||||
{
|
||||
bool dirty=isDirty();
|
||||
// Get the Airframe type from the system settings:
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("SystemSettings")));
|
||||
Q_ASSERT(obj);
|
||||
@ -913,6 +895,7 @@ void ConfigAirframeWidget::refreshWidgetsValues()
|
||||
}
|
||||
|
||||
updateCustomAirframeUI();
|
||||
setDirty(dirty);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -921,6 +904,7 @@ void ConfigAirframeWidget::refreshWidgetsValues()
|
||||
*/
|
||||
void ConfigAirframeWidget::setupAirframeUI(QString frameType)
|
||||
{
|
||||
bool dirty=isDirty();
|
||||
if (frameType == "FixedWing" || frameType == "Elevator aileron rudder") {
|
||||
// Setup the UI
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
|
||||
@ -1118,6 +1102,7 @@ void ConfigAirframeWidget::setupAirframeUI(QString frameType)
|
||||
}
|
||||
m_aircraft->quadShape->setSceneRect(quad->boundingRect());
|
||||
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
|
||||
setDirty(dirty);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2139,3 +2124,77 @@ void ConfigAirframeWidget::openHelp()
|
||||
QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Airframe+configuration", QUrl::StrictMode) );
|
||||
}
|
||||
|
||||
void ConfigAirframeWidget::addToDirtyMonitor()
|
||||
{
|
||||
addWidget(m_aircraft->customMixerTable);
|
||||
addWidget(m_aircraft->customThrottle2Curve);
|
||||
addWidget(m_aircraft->customThrottle1Curve);
|
||||
addWidget(m_aircraft->multiThrottleCurve);
|
||||
addWidget(m_aircraft->fixedWingThrottle);
|
||||
addWidget(m_aircraft->fixedWingType);
|
||||
addWidget(m_aircraft->feedForwardSlider);
|
||||
addWidget(m_aircraft->accelTime);
|
||||
addWidget(m_aircraft->decelTime);
|
||||
addWidget(m_aircraft->maxAccelSlider);
|
||||
addWidget(m_aircraft->multirotorFrameType);
|
||||
addWidget(m_aircraft->multiMotor1);
|
||||
addWidget(m_aircraft->multiMotor2);
|
||||
addWidget(m_aircraft->multiMotor3);
|
||||
addWidget(m_aircraft->multiMotor4);
|
||||
addWidget(m_aircraft->multiMotor5);
|
||||
addWidget(m_aircraft->multiMotor6);
|
||||
addWidget(m_aircraft->multiMotor7);
|
||||
addWidget(m_aircraft->multiMotor8);
|
||||
addWidget(m_aircraft->triYawChannel);
|
||||
addWidget(m_aircraft->aircraftType);
|
||||
addWidget(m_aircraft->fwEngineChannel);
|
||||
addWidget(m_aircraft->fwAileron1Channel);
|
||||
addWidget(m_aircraft->fwAileron2Channel);
|
||||
addWidget(m_aircraft->fwElevator1Channel);
|
||||
addWidget(m_aircraft->fwElevator2Channel);
|
||||
addWidget(m_aircraft->fwRudder1Channel);
|
||||
addWidget(m_aircraft->fwRudder2Channel);
|
||||
addWidget(m_aircraft->elevonSlider1);
|
||||
addWidget(m_aircraft->elevonSlider2);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmType);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->TabObject);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmTailChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmEngineChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoWChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoXChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoYChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmSingleServo);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoZChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleW);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleX);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCorrectionAngle);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleZ);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleY);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivePassthrough);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkRoll);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkCyclic);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRevoSlider);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmREVOspinBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveSlider);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivespinBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScaleBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCyclicScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScaleBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScaleBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSlider);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSpinBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveType);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->NumCurvePoints);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue1);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue2);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue3);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveToGenerate);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveSettings);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ThrottleCurve);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->PitchCurve);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAdvancedSettingsTable);
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ private:
|
||||
void updateCustomAirframeUI();
|
||||
bool setupMixer(double mixerFactors[8][3]);
|
||||
void setupMotors(QList<QString> motorList);
|
||||
|
||||
void addToDirtyMonitor();
|
||||
void resetField(UAVObjectField * field);
|
||||
void resetMixer (MixerCurveWidget *mixer, int numElements, double maxvalue);
|
||||
void resetActuators();
|
||||
|
@ -40,22 +40,19 @@ ConfigCCAttitudeWidget::ConfigCCAttitudeWidget(QWidget *parent) :
|
||||
{
|
||||
ui->setupUi(this);
|
||||
connect(ui->zeroBias,SIGNAL(clicked()),this,SLOT(startAccelCalibration()));
|
||||
connect(ui->saveButton,SIGNAL(clicked()),this,SLOT(saveAttitudeSettings()));
|
||||
connect(ui->applyButton,SIGNAL(clicked()),this,SLOT(applyAttitudeSettings()));
|
||||
|
||||
// Make it smart:
|
||||
connect(parent, SIGNAL(autopilotConnected()),this, SLOT(onAutopilotConnect()));
|
||||
connect(parent, SIGNAL(autopilotDisconnected()), this, SLOT(onAutopilotDisconnect()));
|
||||
|
||||
enableControls(true);
|
||||
refreshValues(); // The 1st time this panel is instanciated, the autopilot is already connected.
|
||||
UAVObject * settings = AttitudeSettings::GetInstance(getObjectManager());
|
||||
connect(settings,SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshValues()));
|
||||
setupButtons(ui->applyButton,ui->saveButton);
|
||||
addUAVObject("AttitudeSettings");
|
||||
|
||||
// Connect the help button
|
||||
connect(ui->ccAttitudeHelp, SIGNAL(clicked()), this, SLOT(openHelp()));
|
||||
addUAVObjectToWidgetRelation("AttitudeSettings","ZeroDuringArming",ui->zeroGyroBiasOnArming);
|
||||
|
||||
|
||||
addUAVObjectToWidgetRelation("AttitudeSettings","BoardRotation",ui->rollBias,AttitudeSettings::BOARDROTATION_ROLL);
|
||||
addUAVObjectToWidgetRelation("AttitudeSettings","BoardRotation",ui->pitchBias,AttitudeSettings::BOARDROTATION_PITCH);
|
||||
addUAVObjectToWidgetRelation("AttitudeSettings","BoardRotation",ui->yawBias,AttitudeSettings::BOARDROTATION_YAW);
|
||||
addWidget(ui->zeroBias);
|
||||
}
|
||||
|
||||
ConfigCCAttitudeWidget::~ConfigCCAttitudeWidget()
|
||||
@ -63,12 +60,6 @@ ConfigCCAttitudeWidget::~ConfigCCAttitudeWidget()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ConfigCCAttitudeWidget::enableControls(bool enable)
|
||||
{
|
||||
//ui->applyButton->setEnabled(enable);
|
||||
ui->saveButton->setEnabled(enable);
|
||||
}
|
||||
|
||||
void ConfigCCAttitudeWidget::attitudeRawUpdated(UAVObject * obj) {
|
||||
QMutexLocker locker(&startStop);
|
||||
|
||||
@ -130,26 +121,6 @@ void ConfigCCAttitudeWidget::timeout() {
|
||||
|
||||
}
|
||||
|
||||
void ConfigCCAttitudeWidget::applyAttitudeSettings() {
|
||||
AttitudeSettings::DataFields attitudeSettingsData = AttitudeSettings::GetInstance(getObjectManager())->getData();
|
||||
attitudeSettingsData.BoardRotation[AttitudeSettings::BOARDROTATION_ROLL] = ui->rollBias->value();
|
||||
attitudeSettingsData.BoardRotation[AttitudeSettings::BOARDROTATION_PITCH] = ui->pitchBias->value();
|
||||
attitudeSettingsData.BoardRotation[AttitudeSettings::BOARDROTATION_YAW] = ui->yawBias->value();
|
||||
attitudeSettingsData.ZeroDuringArming = ui->zeroGyroBiasOnArming->isChecked() ? AttitudeSettings::ZERODURINGARMING_TRUE :
|
||||
AttitudeSettings::ZERODURINGARMING_FALSE;
|
||||
AttitudeSettings::GetInstance(getObjectManager())->setData(attitudeSettingsData);
|
||||
}
|
||||
|
||||
void ConfigCCAttitudeWidget::refreshValues() {
|
||||
AttitudeSettings::DataFields attitudeSettingsData = AttitudeSettings::GetInstance(getObjectManager())->getData();
|
||||
|
||||
ui->rollBias->setValue(attitudeSettingsData.BoardRotation[0]);
|
||||
ui->pitchBias->setValue(attitudeSettingsData.BoardRotation[1]);
|
||||
ui->yawBias->setValue(attitudeSettingsData.BoardRotation[2]);
|
||||
ui->zeroGyroBiasOnArming->setChecked(attitudeSettingsData.ZeroDuringArming == AttitudeSettings::ZERODURINGARMING_TRUE);
|
||||
|
||||
}
|
||||
|
||||
void ConfigCCAttitudeWidget::startAccelCalibration() {
|
||||
QMutexLocker locker(&startStop);
|
||||
|
||||
@ -184,16 +155,16 @@ void ConfigCCAttitudeWidget::startAccelCalibration() {
|
||||
|
||||
}
|
||||
|
||||
void ConfigCCAttitudeWidget::saveAttitudeSettings() {
|
||||
applyAttitudeSettings();
|
||||
|
||||
UAVDataObject * obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("AttitudeSettings")));
|
||||
saveObjectToSD(obj);
|
||||
}
|
||||
|
||||
void ConfigCCAttitudeWidget::openHelp()
|
||||
{
|
||||
|
||||
QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/CopterControl+Attitude+Configuration", QUrl::StrictMode) );
|
||||
}
|
||||
|
||||
void ConfigCCAttitudeWidget::enableControls(bool enable)
|
||||
{
|
||||
if(ui->zeroBias)
|
||||
ui->zeroBias->setEnabled(enable);
|
||||
ConfigTaskWidget::enableControls(enable);
|
||||
|
||||
}
|
||||
|
@ -50,9 +50,6 @@ private slots:
|
||||
void attitudeRawUpdated(UAVObject * obj);
|
||||
void timeout();
|
||||
void startAccelCalibration();
|
||||
void saveAttitudeSettings();
|
||||
void applyAttitudeSettings();
|
||||
virtual void refreshValues();
|
||||
void openHelp();
|
||||
|
||||
private:
|
||||
@ -69,6 +66,7 @@ private:
|
||||
|
||||
static const int NUM_ACCEL_UPDATES = 60;
|
||||
static const float ACCEL_SCALE = 0.004f * 9.81f;
|
||||
protected:
|
||||
virtual void enableControls(bool enable);
|
||||
|
||||
};
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
#include "mixersettings.h"
|
||||
#include "systemsettings.h"
|
||||
#include "actuatorcommand.h"
|
||||
|
||||
#define Pi 3.14159265358979323846
|
||||
|
||||
@ -70,8 +71,6 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
m_ccpm->SwashplateImage->setSceneRect(-50,-30,500,500);
|
||||
//m_ccpm->SwashplateImage->scale(.85,.85);
|
||||
|
||||
|
||||
|
||||
QSvgRenderer *renderer = new QSvgRenderer();
|
||||
renderer->load(QString(":/configgadget/images/ccpm_setup.svg"));
|
||||
|
||||
@ -132,78 +131,25 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
|
||||
SwashLvlSpinBoxes[i] = new QSpinBox(m_ccpm->SwashLvlSwashplateImage); // use QGraphicsView
|
||||
m_ccpm->SwashLvlSwashplateImage->scene()->addWidget(SwashLvlSpinBoxes[i]);
|
||||
//SwashLvlSpinBoxes[i]->move(i*50+50,20);
|
||||
//SwashLvlSpinBoxes[i]->resize(40,20);
|
||||
//SwashLvlSpinBoxes[i]->heightForWidth()
|
||||
SwashLvlSpinBoxes[i]->setFixedSize(50,20);
|
||||
SwashLvlSpinBoxes[i]->setMaximum(10000);
|
||||
SwashLvlSpinBoxes[i]->setMinimum(0);
|
||||
SwashLvlSpinBoxes[i]->setValue(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Servos[0] = new QGraphicsSvgItem();
|
||||
Servos[0]->setSharedRenderer(renderer);
|
||||
Servos[0]->setElementId("ServoW");
|
||||
m_ccpm->SwashplateImage->scene()->addItem(Servos[0]);
|
||||
|
||||
Servos[1] = new QGraphicsSvgItem();
|
||||
Servos[1]->setSharedRenderer(renderer);
|
||||
Servos[1]->setElementId("ServoX");
|
||||
m_ccpm->SwashplateImage->scene()->addItem(Servos[1]);
|
||||
|
||||
Servos[2] = new QGraphicsSvgItem();
|
||||
Servos[2]->setSharedRenderer(renderer);
|
||||
Servos[2]->setElementId("ServoY");
|
||||
m_ccpm->SwashplateImage->scene()->addItem(Servos[2]);
|
||||
|
||||
Servos[3] = new QGraphicsSvgItem();
|
||||
Servos[3]->setSharedRenderer(renderer);
|
||||
Servos[3]->setElementId("ServoZ");
|
||||
m_ccpm->SwashplateImage->scene()->addItem(Servos[3]);
|
||||
|
||||
|
||||
ServosText[0] = new QGraphicsTextItem();
|
||||
ServosText[0]->setDefaultTextColor(Qt::red);
|
||||
ServosText[0]->setPlainText(QString("-"));
|
||||
ServosText[0]->setFont(serifFont);
|
||||
m_ccpm->SwashplateImage->scene()->addItem(ServosText[0]);
|
||||
|
||||
ServosText[1] = new QGraphicsTextItem();
|
||||
ServosText[1]->setDefaultTextColor(Qt::red);
|
||||
ServosText[1]->setPlainText(QString("-"));
|
||||
ServosText[1]->setFont(serifFont);
|
||||
m_ccpm->SwashplateImage->scene()->addItem(ServosText[1]);
|
||||
|
||||
ServosText[2] = new QGraphicsTextItem();
|
||||
ServosText[2]->setDefaultTextColor(Qt::red);
|
||||
ServosText[2]->setPlainText(QString("-"));
|
||||
ServosText[2]->setFont(serifFont);
|
||||
m_ccpm->SwashplateImage->scene()->addItem(ServosText[2]);
|
||||
|
||||
ServosText[3] = new QGraphicsTextItem();
|
||||
ServosText[3]->setDefaultTextColor(Qt::red);
|
||||
ServosText[3]->setPlainText(QString("-"));
|
||||
ServosText[3]->setFont(serifFont);
|
||||
m_ccpm->SwashplateImage->scene()->addItem(ServosText[3]);
|
||||
*/
|
||||
m_ccpm->PitchCurve->setMin(-1);
|
||||
|
||||
resetMixer(m_ccpm->PitchCurve, 5);
|
||||
resetMixer(m_ccpm->ThrottleCurve, 5);
|
||||
|
||||
|
||||
|
||||
|
||||
MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager());
|
||||
Q_ASSERT(mixerSettings);
|
||||
UAVObjectField * curve2source = mixerSettings->getField("Curve2Source");
|
||||
Q_ASSERT(curve2source);
|
||||
|
||||
QStringList channels;
|
||||
channels << "Channel1" << "Channel2" <<
|
||||
"Channel3" << "Channel4" << "Channel5" << "Channel6" << "Channel7" << "Channel8" ;
|
||||
m_ccpm->ccpmCollectiveChannel->addItems(channels);
|
||||
m_ccpm->ccpmCollectiveChannel->setCurrentIndex(8);
|
||||
channels << "None" ;
|
||||
channels << "Channel1" << "Channel2" << "Channel3" << "Channel4" <<
|
||||
"Channel5" << "Channel6" << "Channel7" << "Channel8" << "None";
|
||||
m_ccpm->ccpmEngineChannel->addItems(channels);
|
||||
m_ccpm->ccpmEngineChannel->setCurrentIndex(8);
|
||||
m_ccpm->ccpmTailChannel->addItems(channels);
|
||||
@ -218,17 +164,17 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
|
||||
|
||||
QStringList Types;
|
||||
Types << "CCPM 2 Servo 90º" << "CCPM 3 Servo 90º" << "CCPM 4 Servo 90º" << "CCPM 3 Servo 120º" << "CCPM 3 Servo 140º" << "FP 2 Servo 90º" << "Custom - User Angles" << "Custom - Advanced Settings" ;
|
||||
Types << QString::fromUtf8("CCPM 2 Servo 90º") << QString::fromUtf8("CCPM 3 Servo 90º") <<
|
||||
QString::fromUtf8("CCPM 4 Servo 90º") << QString::fromUtf8("CCPM 3 Servo 120º") <<
|
||||
QString::fromUtf8("CCPM 3 Servo 140º") << QString::fromUtf8("FP 2 Servo 90º") <<
|
||||
QString::fromUtf8("Custom - User Angles") << QString::fromUtf8("Custom - Advanced Settings");
|
||||
m_ccpm->ccpmType->addItems(Types);
|
||||
m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->count() - 1);
|
||||
requestccpmUpdate();
|
||||
UpdateCurveSettings();
|
||||
|
||||
|
||||
//disable changing number of points in curves until UAVObjects have more than 5
|
||||
m_ccpm->NumCurvePoints->setEnabled(0);
|
||||
|
||||
|
||||
|
||||
UpdateType();
|
||||
|
||||
@ -270,15 +216,12 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
connect(m_ccpm->SwashLvlCancelButton, SIGNAL(clicked()), this, SLOT(SwashLvlCancelButtonPressed()));
|
||||
connect(m_ccpm->SwashLvlFinishButton, SIGNAL(clicked()), this, SLOT(SwashLvlFinishButtonPressed()));
|
||||
|
||||
connect(m_ccpm->ccpmCollectivePassthrough, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities()));
|
||||
connect(m_ccpm->ccpmLinkCyclic, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities()));
|
||||
connect(m_ccpm->ccpmLinkRoll, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities()));
|
||||
|
||||
|
||||
|
||||
ccpmSwashplateRedraw();
|
||||
// connect(parent, SIGNAL(autopilotConnected()),this, SLOT(requestccpmUpdate()));
|
||||
|
||||
}
|
||||
|
||||
ConfigccpmWidget::~ConfigccpmWidget()
|
||||
@ -292,7 +235,7 @@ void ConfigccpmWidget::UpdateType()
|
||||
QString TypeText;
|
||||
double AdjustmentAngle=0;
|
||||
|
||||
UpdatCCPMOptionsFromUI();
|
||||
UpdateCCPMOptionsFromUI();
|
||||
SetUIComponentVisibilities();
|
||||
|
||||
TypeInt = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1;
|
||||
@ -332,7 +275,7 @@ void ConfigccpmWidget::UpdateType()
|
||||
|
||||
NumServosDefined=4;
|
||||
//set values for pre defined heli types
|
||||
if (TypeText.compare(QString("CCPM 2 Servo 90º"), Qt::CaseInsensitive)==0)
|
||||
if (TypeText.compare(QString::fromUtf8("CCPM 2 Servo 90º"), Qt::CaseInsensitive)==0)
|
||||
{
|
||||
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
|
||||
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360));
|
||||
@ -348,7 +291,7 @@ void ConfigccpmWidget::UpdateType()
|
||||
NumServosDefined=2;
|
||||
|
||||
}
|
||||
if (TypeText.compare(QString("CCPM 3 Servo 90º"), Qt::CaseInsensitive)==0)
|
||||
if (TypeText.compare(QString::fromUtf8("CCPM 3 Servo 90º"), Qt::CaseInsensitive)==0)
|
||||
{
|
||||
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
|
||||
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360));
|
||||
@ -361,7 +304,7 @@ void ConfigccpmWidget::UpdateType()
|
||||
NumServosDefined=3;
|
||||
|
||||
}
|
||||
if (TypeText.compare(QString("CCPM 4 Servo 90º"), Qt::CaseInsensitive)==0)
|
||||
if (TypeText.compare(QString::fromUtf8("CCPM 4 Servo 90º"), Qt::CaseInsensitive)==0)
|
||||
{
|
||||
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
|
||||
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360));
|
||||
@ -373,7 +316,7 @@ void ConfigccpmWidget::UpdateType()
|
||||
NumServosDefined=4;
|
||||
|
||||
}
|
||||
if (TypeText.compare(QString("CCPM 3 Servo 120º"), Qt::CaseInsensitive)==0)
|
||||
if (TypeText.compare(QString::fromUtf8("CCPM 3 Servo 120º"), Qt::CaseInsensitive)==0)
|
||||
{
|
||||
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
|
||||
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 120,360));
|
||||
@ -386,7 +329,7 @@ void ConfigccpmWidget::UpdateType()
|
||||
NumServosDefined=3;
|
||||
|
||||
}
|
||||
if (TypeText.compare(QString("CCPM 3 Servo 140º"), Qt::CaseInsensitive)==0)
|
||||
if (TypeText.compare(QString::fromUtf8("CCPM 3 Servo 140º"), Qt::CaseInsensitive)==0)
|
||||
{
|
||||
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
|
||||
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 140,360));
|
||||
@ -399,7 +342,7 @@ void ConfigccpmWidget::UpdateType()
|
||||
NumServosDefined=3;
|
||||
|
||||
}
|
||||
if (TypeText.compare(QString("FP 2 Servo 90º"), Qt::CaseInsensitive)==0)
|
||||
if (TypeText.compare(QString::fromUtf8("FP 2 Servo 90º"), Qt::CaseInsensitive)==0)
|
||||
{
|
||||
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
|
||||
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360));
|
||||
@ -505,6 +448,9 @@ void ConfigccpmWidget::UpdateCurveWidgets()
|
||||
|
||||
void ConfigccpmWidget::updatePitchCurveValue(QList<double> curveValues0,double Value0)
|
||||
{
|
||||
Q_UNUSED(curveValues0);
|
||||
Q_UNUSED(Value0);
|
||||
|
||||
int NumCurvePoints,i;
|
||||
double CurrentValue;
|
||||
QList<double> internalCurveValues;
|
||||
@ -526,6 +472,9 @@ void ConfigccpmWidget::updatePitchCurveValue(QList<double> curveValues0,double V
|
||||
|
||||
void ConfigccpmWidget::updateThrottleCurveValue(QList<double> curveValues0,double Value0)
|
||||
{
|
||||
Q_UNUSED(curveValues0);
|
||||
Q_UNUSED(Value0);
|
||||
|
||||
int NumCurvePoints,i;
|
||||
double CurrentValue;
|
||||
QList<double> internalCurveValues;
|
||||
@ -915,14 +864,10 @@ void ConfigccpmWidget::UpdateMixer()
|
||||
bool useCyclic;
|
||||
int i,j,ThisEnable[6];
|
||||
float CollectiveConstant,PitchConstant,RollConstant,ThisAngle[6];
|
||||
//QTableWidgetItem *newItem;// = new QTableWidgetItem();
|
||||
QString Channel;
|
||||
|
||||
ccpmChannelCheck();
|
||||
//Type = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1;
|
||||
//CollectiveConstant=m_ccpm->ccpmCollectiveSlider->value()/100.0;
|
||||
//CorrectionAngle=m_ccpm->ccpmCorrectionAngle->value();
|
||||
UpdatCCPMOptionsFromUI();
|
||||
UpdateCCPMOptionsFromUI();
|
||||
|
||||
useCCPM = !(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState);
|
||||
useCyclic = GUIConfigData.heli.ccpmLinkRollState;
|
||||
@ -978,15 +923,6 @@ void ConfigccpmWidget::UpdateMixer()
|
||||
//go through the user data and update the mixer matrix
|
||||
for (i=0;i<6;i++)
|
||||
{
|
||||
/*
|
||||
data.Mixer0Type = 0;//Disabled,Motor,Servo
|
||||
data.Mixer0Vector[0] = 0;//ThrottleCurve1
|
||||
data.Mixer0Vector[1] = 0;//ThrottleCurve2
|
||||
data.Mixer0Vector[2] = 0;//Roll
|
||||
data.Mixer0Vector[3] = 0;//Pitch
|
||||
data.Mixer0Vector[4] = 0;//Yaw
|
||||
|
||||
*/
|
||||
if ((MixerChannelData[i]<8)&&((ThisEnable[i])||(i<2)))
|
||||
{
|
||||
m_ccpm->ccpmAdvancedSettingsTable->item(i,0)->setText(QString("%1").arg( MixerChannelData[i]+1 ));
|
||||
@ -1055,7 +991,7 @@ void ConfigccpmWidget::UpdateMixer()
|
||||
} __attribute__((packed)) heliGUISettingsStruct;
|
||||
|
||||
*/
|
||||
void ConfigccpmWidget::UpdatCCPMOptionsFromUI()
|
||||
void ConfigccpmWidget::UpdateCCPMOptionsFromUI()
|
||||
{
|
||||
bool useCCPM;
|
||||
bool useCyclic;
|
||||
@ -1076,9 +1012,6 @@ void ConfigccpmWidget::UpdatCCPMOptionsFromUI()
|
||||
//correction angle
|
||||
GUIConfigData.heli.CorrectionAngle = m_ccpm->ccpmCorrectionAngle->value();
|
||||
|
||||
//CollectiveChannel
|
||||
GUIConfigData.heli.CollectiveChannel = m_ccpm->ccpmCollectiveChannel->currentIndex();
|
||||
|
||||
//update sliders
|
||||
if (useCCPM)
|
||||
{
|
||||
@ -1097,7 +1030,6 @@ void ConfigccpmWidget::UpdatCCPMOptionsFromUI()
|
||||
GUIConfigData.heli.SliderValue1 = m_ccpm->ccpmPitchScale->value();
|
||||
}
|
||||
GUIConfigData.heli.SliderValue2 = m_ccpm->ccpmRollScale->value();
|
||||
//GUIConfigData.heli.RevoSlider = m_ccpm->ccpmREVOScale->value();
|
||||
|
||||
//servo assignments
|
||||
GUIConfigData.heli.ServoIndexW = m_ccpm->ccpmServoWChannel->currentIndex();
|
||||
@ -1106,7 +1038,7 @@ void ConfigccpmWidget::UpdatCCPMOptionsFromUI()
|
||||
GUIConfigData.heli.ServoIndexZ = m_ccpm->ccpmServoZChannel->currentIndex();
|
||||
|
||||
}
|
||||
void ConfigccpmWidget::UpdatCCPMUIFromOptions()
|
||||
void ConfigccpmWidget::UpdateCCPMUIFromOptions()
|
||||
{
|
||||
//swashplate config
|
||||
m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->count() - (GUIConfigData.heli.SwasplateType +1));
|
||||
@ -1119,10 +1051,7 @@ void ConfigccpmWidget::UpdatCCPMUIFromOptions()
|
||||
|
||||
//correction angle
|
||||
m_ccpm->ccpmCorrectionAngle->setValue(GUIConfigData.heli.CorrectionAngle);
|
||||
|
||||
//CollectiveChannel
|
||||
m_ccpm->ccpmCollectiveChannel->setCurrentIndex(GUIConfigData.heli.CollectiveChannel);
|
||||
|
||||
|
||||
//update sliders
|
||||
m_ccpm->ccpmCollectiveScale->setValue(GUIConfigData.heli.SliderValue0);
|
||||
m_ccpm->ccpmCollectiveScaleBox->setValue(GUIConfigData.heli.SliderValue0);
|
||||
@ -1134,7 +1063,6 @@ void ConfigccpmWidget::UpdatCCPMUIFromOptions()
|
||||
m_ccpm->ccpmRollScaleBox->setValue(GUIConfigData.heli.SliderValue2);
|
||||
m_ccpm->ccpmCollectiveSlider->setValue(GUIConfigData.heli.SliderValue0);
|
||||
m_ccpm->ccpmCollectivespinBox->setValue(GUIConfigData.heli.SliderValue0);
|
||||
//m_ccpm->ccpmREVOScale->setValue(GUIConfigData.heli.RevoSlider);
|
||||
|
||||
//servo assignments
|
||||
m_ccpm->ccpmServoWChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexW);
|
||||
@ -1147,16 +1075,13 @@ void ConfigccpmWidget::UpdatCCPMUIFromOptions()
|
||||
|
||||
void ConfigccpmWidget::SetUIComponentVisibilities()
|
||||
{
|
||||
UpdatCCPMOptionsFromUI();
|
||||
UpdateCCPMOptionsFromUI();
|
||||
//set which sliders are user...
|
||||
m_ccpm->ccpmRevoMixingBox->setVisible(0);
|
||||
|
||||
m_ccpm->ccpmPitchMixingBox->setVisible(!GUIConfigData.heli.ccpmCollectivePassthroughState && GUIConfigData.heli.ccpmLinkCyclicState);
|
||||
m_ccpm->ccpmCollectiveScalingBox->setVisible(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState);
|
||||
|
||||
m_ccpm->ccpmCollectiveChLabel->setVisible(GUIConfigData.heli.ccpmCollectivePassthroughState);
|
||||
m_ccpm->ccpmCollectiveChannel->setVisible(GUIConfigData.heli.ccpmCollectivePassthroughState);
|
||||
|
||||
m_ccpm->ccpmLinkCyclic->setVisible(!GUIConfigData.heli.ccpmCollectivePassthroughState);
|
||||
|
||||
m_ccpm->ccpmCyclicScalingBox->setVisible((GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState) && GUIConfigData.heli.ccpmLinkRollState);
|
||||
@ -1183,20 +1108,17 @@ void ConfigccpmWidget::requestccpmUpdate()
|
||||
#define MaxAngleError 2
|
||||
int MixerDataFromHeli[8][5];
|
||||
quint8 MixerOutputType[8];
|
||||
int EngineChannel,TailRotorChannel,ServoChannels[4],ServoAngles[4],SortAngles[4],CalcAngles[4],ServoCurve2[4];
|
||||
int EngineChannel,TailRotorChannel,ServoChannels[4],ServoAngles[4],SortAngles[4],ServoCurve2[4];
|
||||
int NumServos=0;
|
||||
double Collective=0.0;
|
||||
double a1,a2;
|
||||
int HeadRotation,temp;
|
||||
int isCCPM=0;
|
||||
|
||||
if (SwashLvlConfigurationInProgress)return;
|
||||
if (updatingToHardware)return;
|
||||
updatingFromHardware=TRUE;
|
||||
|
||||
int i,j;
|
||||
unsigned int i,j;
|
||||
|
||||
SystemSettings * systemSettings = SystemSettings::GetInstance(getObjectManager());
|
||||
Q_ASSERT(systemSettings);
|
||||
SystemSettings::DataFields systemSettingsData = systemSettings->getData();
|
||||
|
||||
Q_ASSERT(SystemSettings::GUICONFIGDATA_NUMELEM ==
|
||||
@ -1205,7 +1127,7 @@ void ConfigccpmWidget::requestccpmUpdate()
|
||||
for(i = 0; i < SystemSettings::GUICONFIGDATA_NUMELEM; i++)
|
||||
GUIConfigData.UAVObject[i]=systemSettingsData.GUIConfigData[i];
|
||||
|
||||
UpdatCCPMUIFromOptions();
|
||||
UpdateCCPMUIFromOptions();
|
||||
|
||||
// Get existing mixer settings
|
||||
MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager());
|
||||
@ -1299,7 +1221,7 @@ void ConfigccpmWidget::requestccpmUpdate()
|
||||
}
|
||||
|
||||
updatingFromHardware=FALSE;
|
||||
UpdatCCPMUIFromOptions();
|
||||
UpdateCCPMUIFromOptions();
|
||||
ccpmSwashplateUpdate();
|
||||
}
|
||||
|
||||
@ -1310,116 +1232,83 @@ void ConfigccpmWidget::requestccpmUpdate()
|
||||
void ConfigccpmWidget::sendccpmUpdate()
|
||||
{
|
||||
int i,j;
|
||||
UAVObjectField *field;
|
||||
UAVDataObject* obj;
|
||||
|
||||
if (SwashLvlConfigurationInProgress)return;
|
||||
updatingToHardware=TRUE;
|
||||
//ShowDisclaimer(1);
|
||||
|
||||
UpdateCCPMOptionsFromUI();
|
||||
|
||||
// Store the data required to reconstruct
|
||||
SystemSettings * systemSettings = SystemSettings::GetInstance(getObjectManager());
|
||||
Q_ASSERT(systemSettings);
|
||||
SystemSettings::DataFields systemSettingsData = systemSettings->getData();
|
||||
systemSettingsData.GUIConfigData[0] = GUIConfigData.UAVObject[0];
|
||||
systemSettingsData.GUIConfigData[1] = GUIConfigData.UAVObject[1];
|
||||
systemSettings->setData(systemSettingsData);
|
||||
systemSettings->updated();
|
||||
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
|
||||
MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager());
|
||||
Q_ASSERT(mixerSettings);
|
||||
MixerSettings::DataFields mixerSettingsData = mixerSettings->getData();
|
||||
|
||||
UpdatCCPMOptionsFromUI();
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("SystemSettings")));
|
||||
field = obj->getField(QString("GUIConfigData"));
|
||||
field->setValue(GUIConfigData.UAVObject[0],0);
|
||||
field->setValue(GUIConfigData.UAVObject[1],1);
|
||||
obj->updated();
|
||||
|
||||
UpdateMixer();
|
||||
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// Set up some helper pointers
|
||||
qint8 * mixers[8] = {mixerSettingsData.Mixer1Vector,
|
||||
mixerSettingsData.Mixer2Vector,
|
||||
mixerSettingsData.Mixer3Vector,
|
||||
mixerSettingsData.Mixer4Vector,
|
||||
mixerSettingsData.Mixer5Vector,
|
||||
mixerSettingsData.Mixer6Vector,
|
||||
mixerSettingsData.Mixer7Vector,
|
||||
mixerSettingsData.Mixer8Vector
|
||||
};
|
||||
|
||||
UpdateMixer();
|
||||
quint8 * mixerTypes[8] = {
|
||||
&mixerSettingsData.Mixer1Type,
|
||||
&mixerSettingsData.Mixer2Type,
|
||||
&mixerSettingsData.Mixer3Type,
|
||||
&mixerSettingsData.Mixer4Type,
|
||||
&mixerSettingsData.Mixer5Type,
|
||||
&mixerSettingsData.Mixer6Type,
|
||||
&mixerSettingsData.Mixer7Type,
|
||||
&mixerSettingsData.Mixer8Type
|
||||
};
|
||||
|
||||
//clear the output types
|
||||
for (i=0;i<8;i++)
|
||||
//go through the user data and update the mixer matrix
|
||||
for (i=0;i<6;i++)
|
||||
{
|
||||
if (MixerChannelData[i]<8)
|
||||
{
|
||||
field = obj->getField( QString( "Mixer%1Type" ).arg( i+1 ));
|
||||
//clear the mixer type
|
||||
field->setValue("Disabled");
|
||||
//set the mixer type
|
||||
*(mixerTypes[MixerChannelData[i]]) = i==0 ?
|
||||
MixerSettings::MIXER1TYPE_MOTOR :
|
||||
MixerSettings::MIXER1TYPE_SERVO;
|
||||
|
||||
//config the vector
|
||||
for (j=0;j<5;j++)
|
||||
mixers[MixerChannelData[i]][j] = m_ccpm->ccpmAdvancedSettingsTable->item(i,j+1)->text().toInt();
|
||||
}
|
||||
}
|
||||
|
||||
//get the user data for the curve into the mixer settings
|
||||
for (i=0;i<5;i++)
|
||||
mixerSettingsData.ThrottleCurve1[i] = m_ccpm->CurveSettings->item(i, 0)->text().toDouble();
|
||||
|
||||
//go through the user data and update the mixer matrix
|
||||
for (i=0;i<6;i++)
|
||||
{
|
||||
/*
|
||||
data.Mixer0Type = 0;//Disabled,Motor,Servo
|
||||
data.Mixer0Vector[0] = 0;//ThrottleCurve1
|
||||
data.Mixer0Vector[1] = 0;//ThrottleCurve2
|
||||
data.Mixer0Vector[2] = 0;//Roll
|
||||
data.Mixer0Vector[3] = 0;//Pitch
|
||||
data.Mixer0Vector[4] = 0;//Yaw
|
||||
|
||||
*/
|
||||
if (MixerChannelData[i]<8)
|
||||
{
|
||||
//select the correct mixer for this config element
|
||||
field = obj->getField(QString( "Mixer%1Type" ).arg( MixerChannelData[i]+1 ));
|
||||
//set the mixer type
|
||||
if (i==0)
|
||||
{
|
||||
field->setValue("Motor");
|
||||
}
|
||||
else
|
||||
{
|
||||
field->setValue("Servo");
|
||||
}
|
||||
|
||||
//select the correct mixer for this config element
|
||||
field = obj->getField(QString( "Mixer%1Vector" ).arg( MixerChannelData[i]+1 ));
|
||||
//config the vector
|
||||
for (j=0;j<5;j++)
|
||||
{
|
||||
field->setValue(m_ccpm->ccpmAdvancedSettingsTable->item(i,j+1)->text().toInt(),j);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//get the user data for the curve into the mixer settings
|
||||
field = obj->getField(QString("ThrottleCurve1"));
|
||||
for (i=0;i<5;i++)
|
||||
{
|
||||
field->setValue(m_ccpm->CurveSettings->item(i, 0)->text().toDouble(),i);
|
||||
}
|
||||
field = obj->getField(QString("ThrottleCurve2"));
|
||||
for (i=0;i<5;i++)
|
||||
{
|
||||
field->setValue(m_ccpm->CurveSettings->item(i, 1)->text().toDouble(),i);
|
||||
}
|
||||
|
||||
obj->updated();
|
||||
|
||||
field = obj->getField(QString("Curve2Source"));
|
||||
for (i=0;i<5;i++)
|
||||
mixerSettingsData.ThrottleCurve2[i] = m_ccpm->CurveSettings->item(i, 1)->text().toDouble();
|
||||
|
||||
//mapping of collective input to curve 2...
|
||||
//MixerSettings.Curve2Source = Throttle,Roll,Pitch,Yaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5
|
||||
//check if we are using throttle or directly from a channel...
|
||||
if (GUIConfigData.heli.ccpmCollectivePassthroughState)
|
||||
{// input channel
|
||||
field->setValue("Accessory0");
|
||||
obj->updated();
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ManualControlSettings")));
|
||||
Q_ASSERT(obj);
|
||||
field = obj->getField(QString("Accessory0"));
|
||||
field->setValue(tr( "Channel%1" ).arg(GUIConfigData.heli.CollectiveChannel+1));
|
||||
|
||||
}
|
||||
mixerSettingsData.Curve2Source = MixerSettings::CURVE2SOURCE_COLLECTIVE;
|
||||
else
|
||||
{// throttle
|
||||
|
||||
field->setValue("Throttle");
|
||||
}
|
||||
mixerSettingsData.Curve2Source = MixerSettings::CURVE2SOURCE_THROTTLE;
|
||||
|
||||
obj->updated();
|
||||
mixerSettings->setData(mixerSettingsData);
|
||||
mixerSettings->updated();
|
||||
updatingToHardware=FALSE;
|
||||
|
||||
}
|
||||
@ -1820,7 +1709,6 @@ void ConfigccpmWidget::enableSwashplateLevellingControl(bool state)
|
||||
mdata.gcsTelemetryUpdateMode = UAVObject::UPDATEMODE_ONCHANGE;
|
||||
mdata.gcsTelemetryUpdatePeriod = 100;
|
||||
SwashLvlConfigurationInProgress=1;
|
||||
connect(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)),this, SLOT(FocusChanged(QWidget*,QWidget*)));
|
||||
m_ccpm->TabObject->setTabEnabled(0,0);
|
||||
m_ccpm->TabObject->setTabEnabled(2,0);
|
||||
m_ccpm->TabObject->setTabEnabled(3,0);
|
||||
@ -1831,7 +1719,6 @@ void ConfigccpmWidget::enableSwashplateLevellingControl(bool state)
|
||||
mdata = SwashLvlaccInitialData; // Restore metadata
|
||||
SwashLvlConfigurationInProgress=0;
|
||||
|
||||
disconnect(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)),this, SLOT(FocusChanged(QWidget*,QWidget*)));
|
||||
m_ccpm->TabObject->setTabEnabled(0,1);
|
||||
m_ccpm->TabObject->setTabEnabled(2,1);
|
||||
m_ccpm->TabObject->setTabEnabled(3,1);
|
||||
@ -1857,41 +1744,24 @@ void ConfigccpmWidget::setSwashplateLevel(int percent)
|
||||
|
||||
SwashLvlServoInterlock=1;
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorCommand")));
|
||||
UAVObjectField * channel = obj->getField("Channel");
|
||||
ActuatorCommand * actuatorCommand = ActuatorCommand::GetInstance(getObjectManager());
|
||||
ActuatorCommand::DataFields actuatorCommandData = actuatorCommand->getData();
|
||||
|
||||
|
||||
|
||||
if (level==0)
|
||||
{
|
||||
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
|
||||
{
|
||||
channel->setValue(newSwashLvlConfiguration.Neutral[i],newSwashLvlConfiguration.ServoChannels[i]);
|
||||
SwashLvlSpinBoxes[i]->setValue(newSwashLvlConfiguration.Neutral[i]);
|
||||
}
|
||||
|
||||
}
|
||||
else if (level>0)
|
||||
{
|
||||
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
|
||||
{
|
||||
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++) {
|
||||
if (level==0)
|
||||
value = newSwashLvlConfiguration.Neutral[i];
|
||||
else if (level > 0)
|
||||
value = (newSwashLvlConfiguration.Max[i] - newSwashLvlConfiguration.Neutral[i])*level + newSwashLvlConfiguration.Neutral[i];
|
||||
channel->setValue(value,newSwashLvlConfiguration.ServoChannels[i]);
|
||||
SwashLvlSpinBoxes[i]->setValue(value);
|
||||
}
|
||||
|
||||
}
|
||||
else if (level<0)
|
||||
{
|
||||
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
|
||||
{
|
||||
else if (level < 0)
|
||||
value = (newSwashLvlConfiguration.Neutral[i] - newSwashLvlConfiguration.Min[i])*level + newSwashLvlConfiguration.Neutral[i];
|
||||
channel->setValue(value,newSwashLvlConfiguration.ServoChannels[i]);
|
||||
SwashLvlSpinBoxes[i]->setValue(value);
|
||||
}
|
||||
|
||||
actuatorCommandData.Channel[newSwashLvlConfiguration.ServoChannels[i]] = value;
|
||||
SwashLvlSpinBoxes[i]->setValue(value);
|
||||
}
|
||||
obj->updated();
|
||||
|
||||
actuatorCommand->setData(actuatorCommandData);
|
||||
actuatorCommand->updated();
|
||||
|
||||
SwashLvlServoInterlock=0;
|
||||
|
||||
return;
|
||||
@ -1900,76 +1770,41 @@ return;
|
||||
|
||||
void ConfigccpmWidget::SwashLvlSpinBoxChanged(int value)
|
||||
{
|
||||
Q_UNUSED(value);
|
||||
int i;
|
||||
if (SwashLvlServoInterlock==1)return;
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorCommand")));
|
||||
UAVObjectField * channel = obj->getField("Channel");
|
||||
|
||||
switch (SwashLvlState)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1: //Neutral levelling
|
||||
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
|
||||
ActuatorCommand * actuatorCommand = ActuatorCommand::GetInstance(getObjectManager());
|
||||
ActuatorCommand::DataFields actuatorCommandData = actuatorCommand->getData();
|
||||
|
||||
for (i = 0; i < CCPM_MAX_SWASH_SERVOS; i++) {
|
||||
value = SwashLvlSpinBoxes[i]->value();
|
||||
|
||||
switch (SwashLvlState)
|
||||
{
|
||||
newSwashLvlConfiguration.Neutral[i]=SwashLvlSpinBoxes[i]->value();
|
||||
channel->setValue(newSwashLvlConfiguration.Neutral[i],newSwashLvlConfiguration.ServoChannels[i]);
|
||||
case 1: //Neutral levelling
|
||||
newSwashLvlConfiguration.Neutral[i]=value;
|
||||
break;
|
||||
case 2: //Max levelling
|
||||
newSwashLvlConfiguration.Max[i] = value;
|
||||
break;
|
||||
case 3: //Min levelling
|
||||
newSwashLvlConfiguration.Min[i]= value;
|
||||
break;
|
||||
case 4: //levelling verification
|
||||
break;
|
||||
case 5: //levelling complete
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
obj->updated();
|
||||
break;
|
||||
case 2: //Max levelling
|
||||
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
|
||||
{
|
||||
newSwashLvlConfiguration.Max[i]=SwashLvlSpinBoxes[i]->value();
|
||||
channel->setValue(newSwashLvlConfiguration.Max[i],newSwashLvlConfiguration.ServoChannels[i]);
|
||||
}
|
||||
obj->updated();
|
||||
break;
|
||||
case 3: //Min levelling
|
||||
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
|
||||
{
|
||||
newSwashLvlConfiguration.Min[i]=SwashLvlSpinBoxes[i]->value();
|
||||
channel->setValue(newSwashLvlConfiguration.Min[i],newSwashLvlConfiguration.ServoChannels[i]);
|
||||
}
|
||||
obj->updated();
|
||||
break;
|
||||
case 4: //levelling verification
|
||||
break;
|
||||
case 5: //levelling complete
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
actuatorCommandData.Channel[newSwashLvlConfiguration.ServoChannels[i]] = value;
|
||||
}
|
||||
|
||||
|
||||
actuatorCommand->setData(actuatorCommandData);
|
||||
actuatorCommand->updated();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void ConfigccpmWidget::FocusChanged(QWidget *oldFocus, QWidget *newFocus)
|
||||
{
|
||||
if (SwashLvlConfigurationInProgress!=1) return;
|
||||
QMessageBox msgBox;
|
||||
int ret;
|
||||
msgBox.setText("<h1>Warning!!!</h1>");
|
||||
|
||||
if ((this->isAncestorOf(oldFocus))&&(!this->isAncestorOf(newFocus)))
|
||||
{
|
||||
msgBox.setInformativeText("<b>You are in the middle of the levelling routine</b><br>Changing focus will cancel all levelling and return the OP hardware to the state it was in before levelling began.<p>Do you want to continue the levelling routine?");
|
||||
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
msgBox.setDefaultButton(QMessageBox::Yes);
|
||||
msgBox.setIcon(QMessageBox::Information);
|
||||
ret = msgBox.exec();
|
||||
|
||||
if (ret == QMessageBox::Yes)
|
||||
{
|
||||
|
||||
//m_ccpm->TabObject->setCurrentIndex(1);
|
||||
//m_ccpm->SwashPlateLevel->setFocus(Qt::MouseFocusReason);
|
||||
//m_ccpm->SwashLvlInstructionsBox->setFocus(Qt::MouseFocusReason);
|
||||
oldFocus->setFocus(Qt::MouseFocusReason);
|
||||
}
|
||||
if (ret == QMessageBox::No)
|
||||
{
|
||||
SwashLvlCancelButtonPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,6 @@ typedef struct {
|
||||
uint ccpmCollectivePassthroughState:1;
|
||||
uint ccpmLinkCyclicState:1;
|
||||
uint ccpmLinkRollState:1;
|
||||
uint CollectiveChannel:3;//20bits
|
||||
uint SliderValue0:7;
|
||||
uint SliderValue1:7;
|
||||
uint SliderValue2:7;//41bits
|
||||
@ -82,6 +81,8 @@ public:
|
||||
ConfigccpmWidget(QWidget *parent = 0);
|
||||
~ConfigccpmWidget();
|
||||
|
||||
friend class ConfigAirframeWidget;
|
||||
|
||||
private:
|
||||
Ui_ccpmWidget *m_ccpm;
|
||||
QGraphicsSvgItem *SwashplateImg;
|
||||
@ -134,8 +135,8 @@ private:
|
||||
void SwashLvlCancelButtonPressed();
|
||||
void SwashLvlFinishButtonPressed();
|
||||
|
||||
void UpdatCCPMOptionsFromUI();
|
||||
void UpdatCCPMUIFromOptions();
|
||||
void UpdateCCPMOptionsFromUI();
|
||||
void UpdateCCPMUIFromOptions();
|
||||
|
||||
void SetUIComponentVisibilities();
|
||||
void ccpmChannelCheck();
|
||||
@ -143,8 +144,6 @@ private:
|
||||
void enableSwashplateLevellingControl(bool state);
|
||||
void setSwashplateLevel(int percent);
|
||||
void SwashLvlSpinBoxChanged(int value);
|
||||
void FocusChanged(QWidget *oldFocus, QWidget *newFocus);
|
||||
|
||||
virtual void refreshValues() {}; // Not used
|
||||
|
||||
public slots:
|
||||
|
@ -15,6 +15,7 @@
|
||||
<file>images/coptercontrol.svg</file>
|
||||
<file>images/hw_config.png</file>
|
||||
<file>images/gyroscope.png</file>
|
||||
<file>images/TX.svg</file>
|
||||
<file>images/camera.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -102,6 +102,8 @@ ConfigGadgetWidget::ConfigGadgetWidget(QWidget *parent) : QWidget(parent)
|
||||
onAutopilotConnect();
|
||||
|
||||
help = 0;
|
||||
connect(ftw,SIGNAL(currentAboutToShow(int,bool*)),this,SLOT(tabAboutToChange(int,bool*)));//,Qt::BlockingQueuedConnection);
|
||||
|
||||
}
|
||||
|
||||
ConfigGadgetWidget::~ConfigGadgetWidget()
|
||||
@ -118,6 +120,15 @@ void ConfigGadgetWidget::resizeEvent(QResizeEvent *event)
|
||||
}
|
||||
|
||||
void ConfigGadgetWidget::onAutopilotDisconnect() {
|
||||
ftw->setCurrentIndex(ConfigGadgetWidget::hardware);
|
||||
ftw->removeTab(ConfigGadgetWidget::ins);
|
||||
QWidget *qwd = new DefaultAttitudeWidget(this);
|
||||
ftw->insertTab(ConfigGadgetWidget::ins, qwd, QIcon(":/configgadget/images/AHRS-v1.3.png"), QString("INS"));
|
||||
ftw->removeTab(ConfigGadgetWidget::hardware);
|
||||
qwd = new DefaultHwSettingsWidget(this);
|
||||
ftw->insertTab(ConfigGadgetWidget::hardware, qwd, QIcon(":/configgadget/images/hw_config.png"), QString("HW Settings"));
|
||||
ftw->setCurrentIndex(ConfigGadgetWidget::hardware);
|
||||
|
||||
emit autopilotDisconnected();
|
||||
}
|
||||
|
||||
@ -156,5 +167,24 @@ void ConfigGadgetWidget::onAutopilotConnect() {
|
||||
emit autopilotConnected();
|
||||
}
|
||||
|
||||
void ConfigGadgetWidget::tabAboutToChange(int i,bool * proceed)
|
||||
{
|
||||
Q_UNUSED(i);
|
||||
*proceed=true;
|
||||
ConfigTaskWidget * wid=qobject_cast<ConfigTaskWidget *>(ftw->currentWidget());
|
||||
if(!wid)
|
||||
return;
|
||||
if(wid->isDirty())
|
||||
{
|
||||
int ans=QMessageBox::warning(this,tr("Unsaved changes"),tr("The tab you are leaving has unsaved changes,"
|
||||
"if you proceed they will be lost."
|
||||
"Do you still want to proceed?"),QMessageBox::Yes,QMessageBox::No);
|
||||
if(ans==QMessageBox::No)
|
||||
*proceed=false;
|
||||
else
|
||||
wid->setDirty(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -37,10 +37,10 @@
|
||||
//#include <QtWebKit/QWebView>
|
||||
#include <QTextBrowser>
|
||||
#include "utils/pathutils.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
//#include "fancytabwidget.h"
|
||||
#include "utils/mytabbedstackwidget.h"
|
||||
|
||||
#include "configtaskwidget.h"
|
||||
|
||||
class ConfigGadgetWidget: public QWidget
|
||||
{
|
||||
@ -55,6 +55,7 @@ public:
|
||||
public slots:
|
||||
void onAutopilotConnect();
|
||||
void onAutopilotDisconnect();
|
||||
void tabAboutToChange(int i,bool *);
|
||||
|
||||
signals:
|
||||
void autopilotConnected();
|
||||
|
@ -1,8 +1,8 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file configservowidget.cpp
|
||||
* @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file configinputwidget.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup ConfigPlugin Config Plugin
|
||||
@ -38,614 +38,233 @@
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QMessageBox>
|
||||
#include <utils/stylehelper.h>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "manualcontrolsettings.h"
|
||||
#define ACCESS_MIN_MOVE -6
|
||||
#define ACCESS_MAX_MOVE 6
|
||||
#define STICK_MIN_MOVE -8
|
||||
#define STICK_MAX_MOVE 8
|
||||
|
||||
ConfigInputWidget::ConfigInputWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
ConfigInputWidget::ConfigInputWidget(QWidget *parent) : ConfigTaskWidget(parent),wizardStep(wizardNone),loop(NULL),skipflag(false),transmitterType(heli)
|
||||
{
|
||||
manualCommandObj = ManualControlCommand::GetInstance(getObjectManager());
|
||||
manualSettingsObj = ManualControlSettings::GetInstance(getObjectManager());
|
||||
receiverActivityObj=ReceiverActivity::GetInstance(getObjectManager());
|
||||
m_config = new Ui_InputWidget();
|
||||
m_config->setupUi(this);
|
||||
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
|
||||
setupButtons(m_config->saveRCInputToRAM,m_config->saveRCInputToSD);
|
||||
|
||||
// First of all, put all the channel widgets into lists, so that we can
|
||||
// manipulate those:
|
||||
|
||||
|
||||
inMaxLabels << m_config->ch0Max
|
||||
<< m_config->ch1Max
|
||||
<< m_config->ch2Max
|
||||
<< m_config->ch3Max
|
||||
<< m_config->ch4Max
|
||||
<< m_config->ch5Max
|
||||
<< m_config->ch6Max
|
||||
<< m_config->ch7Max;
|
||||
|
||||
inMinLabels << m_config->ch0Min
|
||||
<< m_config->ch1Min
|
||||
<< m_config->ch2Min
|
||||
<< m_config->ch3Min
|
||||
<< m_config->ch4Min
|
||||
<< m_config->ch5Min
|
||||
<< m_config->ch6Min
|
||||
<< m_config->ch7Min;
|
||||
|
||||
inSliders << m_config->inSlider0
|
||||
<< m_config->inSlider1
|
||||
<< m_config->inSlider2
|
||||
<< m_config->inSlider3
|
||||
<< m_config->inSlider4
|
||||
<< m_config->inSlider5
|
||||
<< m_config->inSlider6
|
||||
<< m_config->inSlider7;
|
||||
|
||||
inRevCheckboxes << m_config->ch0Rev
|
||||
<< m_config->ch1Rev
|
||||
<< m_config->ch2Rev
|
||||
<< m_config->ch3Rev
|
||||
<< m_config->ch4Rev
|
||||
<< m_config->ch5Rev
|
||||
<< m_config->ch6Rev
|
||||
<< m_config->ch7Rev;
|
||||
|
||||
inChannelAssign << m_config->ch0Assign
|
||||
<< m_config->ch1Assign
|
||||
<< m_config->ch2Assign
|
||||
<< m_config->ch3Assign
|
||||
<< m_config->ch4Assign
|
||||
<< m_config->ch5Assign
|
||||
<< m_config->ch6Assign
|
||||
<< m_config->ch7Assign;
|
||||
|
||||
// Now connect the widget to the ManualControlCommand / Channel UAVObject
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ManualControlCommand")));
|
||||
connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(updateChannels(UAVObject*)));
|
||||
|
||||
// Register for ManualControlSettings changes:
|
||||
obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ManualControlSettings")));
|
||||
connect(obj,SIGNAL(objectUpdated(UAVObject*)),this,SLOT(refreshValues()));
|
||||
|
||||
|
||||
// Get the receiver types supported by OpenPilot and fill the corresponding
|
||||
// dropdown menu:
|
||||
obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ManualControlSettings")));
|
||||
UAVObjectField * field;
|
||||
// Fill in the dropdown menus for the channel RC Input assignement.
|
||||
QStringList channelsList;
|
||||
channelsList << "None";
|
||||
QList<UAVObjectField*> fieldList = obj->getFields();
|
||||
foreach (UAVObjectField* field, fieldList) {
|
||||
if (field->getUnits().contains("channel")) {
|
||||
channelsList.append(field->getName());
|
||||
}
|
||||
unsigned int index=0;
|
||||
foreach(QString name,manualSettingsObj->getFields().at(0)->getElementNames())
|
||||
{
|
||||
Q_ASSERT(index < ManualControlSettings::CHANNELGROUPS_NUMELEM);
|
||||
inputChannelForm * inp=new inputChannelForm(this,index==0);
|
||||
m_config->channelSettings->layout()->addWidget(inp);
|
||||
inp->ui->channelName->setText(name);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelGroups",inp->ui->channelGroup,index);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelNumber",inp->ui->channelNumber,index);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelMin",inp->ui->channelMin,index);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelNeutral",inp->ui->channelNeutral,index);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelMax",inp->ui->channelMax,index);
|
||||
++index;
|
||||
}
|
||||
|
||||
m_config->ch0Assign->addItems(channelsList);
|
||||
m_config->ch1Assign->addItems(channelsList);
|
||||
m_config->ch2Assign->addItems(channelsList);
|
||||
m_config->ch3Assign->addItems(channelsList);
|
||||
m_config->ch4Assign->addItems(channelsList);
|
||||
m_config->ch5Assign->addItems(channelsList);
|
||||
m_config->ch6Assign->addItems(channelsList);
|
||||
m_config->ch7Assign->addItems(channelsList);
|
||||
connect(m_config->configurationWizard,SIGNAL(clicked()),this,SLOT(goToWizard()));
|
||||
connect(m_config->runCalibration,SIGNAL(toggled(bool)),this, SLOT(simpleCalibration(bool)));
|
||||
|
||||
// And the flight mode settings:
|
||||
field = obj->getField(QString("FlightModePosition"));
|
||||
m_config->fmsModePos1->addItems(field->getOptions());
|
||||
m_config->fmsModePos2->addItems(field->getOptions());
|
||||
m_config->fmsModePos3->addItems(field->getOptions());
|
||||
field = obj->getField(QString("Stabilization1Settings"));
|
||||
channelsList.clear();
|
||||
channelsList.append(field->getOptions());
|
||||
m_config->fmsSsPos1Roll->addItems(channelsList);
|
||||
m_config->fmsSsPos1Pitch->addItems(channelsList);
|
||||
m_config->fmsSsPos1Yaw->addItems(channelsList);
|
||||
m_config->fmsSsPos2Roll->addItems(channelsList);
|
||||
m_config->fmsSsPos2Pitch->addItems(channelsList);
|
||||
m_config->fmsSsPos2Yaw->addItems(channelsList);
|
||||
m_config->fmsSsPos3Roll->addItems(channelsList);
|
||||
m_config->fmsSsPos3Pitch->addItems(channelsList);
|
||||
m_config->fmsSsPos3Yaw->addItems(channelsList);
|
||||
connect(m_config->wzNext,SIGNAL(clicked()),this,SLOT(wzNext()));
|
||||
connect(m_config->wzCancel,SIGNAL(clicked()),this,SLOT(wzCancel()));
|
||||
connect(m_config->wzBack,SIGNAL(clicked()),this,SLOT(wzBack()));
|
||||
|
||||
// And the Armin configurations:
|
||||
field = obj->getField(QString("Arming"));
|
||||
m_config->armControl->clear();
|
||||
m_config->armControl->addItems(field->getOptions());
|
||||
m_config->stackedWidget->setCurrentIndex(0);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","FlightModePosition",m_config->fmsModePos1,0);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","FlightModePosition",m_config->fmsModePos2,1);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","FlightModePosition",m_config->fmsModePos3,2);
|
||||
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","Stabilization1Settings",m_config->fmsSsPos1Roll,"Roll");
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","Stabilization2Settings",m_config->fmsSsPos2Roll,"Roll");
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","Stabilization3Settings",m_config->fmsSsPos3Roll,"Roll");
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","Stabilization1Settings",m_config->fmsSsPos1Pitch,"Pitch");
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","Stabilization2Settings",m_config->fmsSsPos2Pitch,"Pitch");
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","Stabilization3Settings",m_config->fmsSsPos3Pitch,"Pitch");
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","Stabilization1Settings",m_config->fmsSsPos1Yaw,"Yaw");
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","Stabilization2Settings",m_config->fmsSsPos2Yaw,"Yaw");
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","Stabilization3Settings",m_config->fmsSsPos3Yaw,"Yaw");
|
||||
|
||||
connect(m_config->saveRCInputToSD, SIGNAL(clicked()), this, SLOT(saveRCInputObject()));
|
||||
connect(m_config->saveRCInputToRAM, SIGNAL(clicked()), this, SLOT(sendRCInputUpdate()));
|
||||
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","Arming",m_config->armControl);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ArmedTimeout",m_config->armTimeout,0,1000);
|
||||
connect( ManualControlCommand::GetInstance(getObjectManager()),SIGNAL(objectUpdated(UAVObject*)),this,SLOT(moveFMSlider()));
|
||||
enableControls(false);
|
||||
refreshValues();
|
||||
connect(parent, SIGNAL(autopilotConnected()),this, SLOT(onAutopilotConnect()));
|
||||
connect(parent, SIGNAL(autopilotDisconnected()), this, SLOT(onAutopilotDisconnect()));
|
||||
|
||||
connect(m_config->ch0Rev, SIGNAL(toggled(bool)), this, SLOT(reverseCheckboxClicked(bool)));
|
||||
connect(m_config->ch1Rev, SIGNAL(toggled(bool)), this, SLOT(reverseCheckboxClicked(bool)));
|
||||
connect(m_config->ch2Rev, SIGNAL(toggled(bool)), this, SLOT(reverseCheckboxClicked(bool)));
|
||||
connect(m_config->ch3Rev, SIGNAL(toggled(bool)), this, SLOT(reverseCheckboxClicked(bool)));
|
||||
connect(m_config->ch4Rev, SIGNAL(toggled(bool)), this, SLOT(reverseCheckboxClicked(bool)));
|
||||
connect(m_config->ch5Rev, SIGNAL(toggled(bool)), this, SLOT(reverseCheckboxClicked(bool)));
|
||||
connect(m_config->ch6Rev, SIGNAL(toggled(bool)), this, SLOT(reverseCheckboxClicked(bool)));
|
||||
connect(m_config->ch7Rev, SIGNAL(toggled(bool)), this, SLOT(reverseCheckboxClicked(bool)));
|
||||
connect(m_config->doRCInputCalibration,SIGNAL(stateChanged(int)),this,SLOT(updateTips(int)));
|
||||
firstUpdate = true;
|
||||
|
||||
populateWidgets();
|
||||
refreshWidgetsValues();
|
||||
// Connect the help button
|
||||
connect(m_config->inputHelp, SIGNAL(clicked()), this, SLOT(openHelp()));
|
||||
updateTips(Qt::Unchecked);
|
||||
|
||||
m_config->graphicsView->setScene(new QGraphicsScene(this));
|
||||
m_config->graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
|
||||
m_renderer = new QSvgRenderer();
|
||||
QGraphicsScene *l_scene = m_config->graphicsView->scene();
|
||||
m_config->graphicsView->setBackgroundBrush(QBrush(Utils::StyleHelper::baseColor()));
|
||||
if (QFile::exists(":/configgadget/images/TX.svg") && m_renderer->load(QString(":/configgadget/images/TX.svg")) && m_renderer->isValid())
|
||||
{
|
||||
l_scene->clear(); // Deletes all items contained in the scene as well.
|
||||
|
||||
m_txBackground = new QGraphicsSvgItem();
|
||||
// All other items will be clipped to the shape of the background
|
||||
m_txBackground->setFlags(QGraphicsItem::ItemClipsChildrenToShape|
|
||||
QGraphicsItem::ItemClipsToShape);
|
||||
m_txBackground->setSharedRenderer(m_renderer);
|
||||
m_txBackground->setElementId("background");
|
||||
l_scene->addItem(m_txBackground);
|
||||
|
||||
m_txMainBody = new QGraphicsSvgItem();
|
||||
m_txMainBody->setParentItem(m_txBackground);
|
||||
m_txMainBody->setSharedRenderer(m_renderer);
|
||||
m_txMainBody->setElementId("body");
|
||||
l_scene->addItem(m_txMainBody);
|
||||
|
||||
m_txLeftStick = new QGraphicsSvgItem();
|
||||
m_txLeftStick->setParentItem(m_txBackground);
|
||||
m_txLeftStick->setSharedRenderer(m_renderer);
|
||||
m_txLeftStick->setElementId("ljoy");
|
||||
|
||||
m_txRightStick = new QGraphicsSvgItem();
|
||||
m_txRightStick->setParentItem(m_txBackground);
|
||||
m_txRightStick->setSharedRenderer(m_renderer);
|
||||
m_txRightStick->setElementId("rjoy");
|
||||
|
||||
m_txAccess0 = new QGraphicsSvgItem();
|
||||
m_txAccess0->setParentItem(m_txBackground);
|
||||
m_txAccess0->setSharedRenderer(m_renderer);
|
||||
m_txAccess0->setElementId("access0");
|
||||
|
||||
m_txAccess1 = new QGraphicsSvgItem();
|
||||
m_txAccess1->setParentItem(m_txBackground);
|
||||
m_txAccess1->setSharedRenderer(m_renderer);
|
||||
m_txAccess1->setElementId("access1");
|
||||
|
||||
m_txAccess2 = new QGraphicsSvgItem();
|
||||
m_txAccess2->setParentItem(m_txBackground);
|
||||
m_txAccess2->setSharedRenderer(m_renderer);
|
||||
m_txAccess2->setElementId("access2");
|
||||
|
||||
m_txFlightMode = new QGraphicsSvgItem();
|
||||
m_txFlightMode->setParentItem(m_txBackground);
|
||||
m_txFlightMode->setSharedRenderer(m_renderer);
|
||||
m_txFlightMode->setElementId("flightModeCenter");
|
||||
m_txFlightMode->setZValue(-10);
|
||||
|
||||
m_txArrows = new QGraphicsSvgItem();
|
||||
m_txArrows->setParentItem(m_txBackground);
|
||||
m_txArrows->setSharedRenderer(m_renderer);
|
||||
m_txArrows->setElementId("arrows");
|
||||
m_txArrows->setVisible(false);
|
||||
|
||||
QRectF orig=m_renderer->boundsOnElement("ljoy");
|
||||
QMatrix Matrix = m_renderer->matrixForElement("ljoy");
|
||||
orig=Matrix.mapRect(orig);
|
||||
m_txLeftStickOrig.translate(orig.x(),orig.y());
|
||||
m_txLeftStick->setTransform(m_txLeftStickOrig,false);
|
||||
|
||||
orig=m_renderer->boundsOnElement("arrows");
|
||||
Matrix = m_renderer->matrixForElement("arrows");
|
||||
orig=Matrix.mapRect(orig);
|
||||
m_txArrowsOrig.translate(orig.x(),orig.y());
|
||||
m_txArrows->setTransform(m_txArrowsOrig,false);
|
||||
|
||||
orig=m_renderer->boundsOnElement("body");
|
||||
Matrix = m_renderer->matrixForElement("body");
|
||||
orig=Matrix.mapRect(orig);
|
||||
m_txMainBodyOrig.translate(orig.x(),orig.y());
|
||||
m_txMainBody->setTransform(m_txMainBodyOrig,false);
|
||||
|
||||
orig=m_renderer->boundsOnElement("flightModeCenter");
|
||||
Matrix = m_renderer->matrixForElement("flightModeCenter");
|
||||
orig=Matrix.mapRect(orig);
|
||||
m_txFlightModeCOrig.translate(orig.x(),orig.y());
|
||||
m_txFlightMode->setTransform(m_txFlightModeCOrig,false);
|
||||
|
||||
orig=m_renderer->boundsOnElement("flightModeLeft");
|
||||
Matrix = m_renderer->matrixForElement("flightModeLeft");
|
||||
orig=Matrix.mapRect(orig);
|
||||
m_txFlightModeLOrig.translate(orig.x(),orig.y());
|
||||
orig=m_renderer->boundsOnElement("flightModeRight");
|
||||
Matrix = m_renderer->matrixForElement("flightModeRight");
|
||||
orig=Matrix.mapRect(orig);
|
||||
m_txFlightModeROrig.translate(orig.x(),orig.y());
|
||||
|
||||
orig=m_renderer->boundsOnElement("rjoy");
|
||||
Matrix = m_renderer->matrixForElement("rjoy");
|
||||
orig=Matrix.mapRect(orig);
|
||||
m_txRightStickOrig.translate(orig.x(),orig.y());
|
||||
m_txRightStick->setTransform(m_txRightStickOrig,false);
|
||||
|
||||
orig=m_renderer->boundsOnElement("access0");
|
||||
Matrix = m_renderer->matrixForElement("access0");
|
||||
orig=Matrix.mapRect(orig);
|
||||
m_txAccess0Orig.translate(orig.x(),orig.y());
|
||||
m_txAccess0->setTransform(m_txAccess0Orig,false);
|
||||
|
||||
orig=m_renderer->boundsOnElement("access1");
|
||||
Matrix = m_renderer->matrixForElement("access1");
|
||||
orig=Matrix.mapRect(orig);
|
||||
m_txAccess1Orig.translate(orig.x(),orig.y());
|
||||
m_txAccess1->setTransform(m_txAccess1Orig,false);
|
||||
|
||||
orig=m_renderer->boundsOnElement("access2");
|
||||
Matrix = m_renderer->matrixForElement("access2");
|
||||
orig=Matrix.mapRect(orig);
|
||||
m_txAccess2Orig.translate(orig.x(),orig.y());
|
||||
m_txAccess2->setTransform(m_txAccess2Orig,true);
|
||||
}
|
||||
m_config->graphicsView->fitInView(m_txMainBody, Qt::KeepAspectRatio );
|
||||
animate=new QTimer(this);
|
||||
connect(animate,SIGNAL(timeout()),this,SLOT(moveTxControls()));
|
||||
|
||||
heliChannelOrder << ManualControlSettings::CHANNELGROUPS_COLLECTIVE <<
|
||||
ManualControlSettings::CHANNELGROUPS_THROTTLE <<
|
||||
ManualControlSettings::CHANNELGROUPS_ROLL <<
|
||||
ManualControlSettings::CHANNELGROUPS_PITCH <<
|
||||
ManualControlSettings::CHANNELGROUPS_YAW <<
|
||||
ManualControlSettings::CHANNELGROUPS_FLIGHTMODE <<
|
||||
ManualControlSettings::CHANNELGROUPS_ACCESSORY0 <<
|
||||
ManualControlSettings::CHANNELGROUPS_ACCESSORY1 <<
|
||||
ManualControlSettings::CHANNELGROUPS_ACCESSORY2;
|
||||
|
||||
acroChannelOrder << ManualControlSettings::CHANNELGROUPS_THROTTLE <<
|
||||
ManualControlSettings::CHANNELGROUPS_ROLL <<
|
||||
ManualControlSettings::CHANNELGROUPS_PITCH <<
|
||||
ManualControlSettings::CHANNELGROUPS_YAW <<
|
||||
ManualControlSettings::CHANNELGROUPS_FLIGHTMODE <<
|
||||
ManualControlSettings::CHANNELGROUPS_ACCESSORY0 <<
|
||||
ManualControlSettings::CHANNELGROUPS_ACCESSORY1 <<
|
||||
ManualControlSettings::CHANNELGROUPS_ACCESSORY2;
|
||||
}
|
||||
void ConfigInputWidget::resetTxControls()
|
||||
{
|
||||
|
||||
m_txLeftStick->setTransform(m_txLeftStickOrig,false);
|
||||
m_txRightStick->setTransform(m_txRightStickOrig,false);
|
||||
m_txAccess0->setTransform(m_txAccess0Orig,false);
|
||||
m_txAccess1->setTransform(m_txAccess1Orig,false);
|
||||
m_txAccess2->setTransform(m_txAccess2Orig,false);
|
||||
m_txFlightMode->setElementId("flightModeCenter");
|
||||
m_txFlightMode->setTransform(m_txFlightModeCOrig,false);
|
||||
m_txArrows->setVisible(false);
|
||||
}
|
||||
|
||||
ConfigInputWidget::~ConfigInputWidget()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
Slot called whenever we revert a signal
|
||||
*/
|
||||
void ConfigInputWidget::reverseCheckboxClicked(bool state)
|
||||
{
|
||||
QObject* obj = sender();
|
||||
int i = inRevCheckboxes.indexOf((QCheckBox*)obj);
|
||||
|
||||
inSliders[i]->setInvertedAppearance(state);
|
||||
int max = inMaxLabels[i]->text().toInt();
|
||||
int min = inMinLabels[i]->text().toInt();
|
||||
if ((state && (max>min)) ||
|
||||
(!state && (max < min))) {
|
||||
inMaxLabels[i]->setText(QString::number(min));
|
||||
inMinLabels[i]->setText(QString::number(max));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************
|
||||
|
||||
/*
|
||||
Enable or disable some controls depending on whether we are connected
|
||||
or not to the board. Actually, this i mostly useless IMHO, I don't
|
||||
know who added this into the code (Ed's note)
|
||||
*/
|
||||
void ConfigInputWidget::enableControls(bool enable)
|
||||
{
|
||||
//m_config->saveRCInputToRAM->setEnabled(enable);
|
||||
m_config->saveRCInputToSD->setEnabled(enable);
|
||||
m_config->doRCInputCalibration->setEnabled(enable);
|
||||
}
|
||||
|
||||
|
||||
/********************************
|
||||
* Input settings
|
||||
*******************************/
|
||||
|
||||
/**
|
||||
Request the current config from the board
|
||||
*/
|
||||
void ConfigInputWidget::refreshValues()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlSettings")));
|
||||
Q_ASSERT(obj);
|
||||
//obj->requestUpdate();
|
||||
UAVObjectField *field;
|
||||
|
||||
// Now update all the slider values:
|
||||
|
||||
UAVObjectField *field_max = obj->getField(QString("ChannelMax"));
|
||||
UAVObjectField *field_min = obj->getField(QString("ChannelMin"));
|
||||
UAVObjectField *field_neu = obj->getField(QString("ChannelNeutral"));
|
||||
Q_ASSERT(field_max);
|
||||
Q_ASSERT(field_min);
|
||||
Q_ASSERT(field_neu);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
QVariant max = field_max->getValue(i);
|
||||
QVariant min = field_min->getValue(i);
|
||||
QVariant neutral = field_neu->getValue(i);
|
||||
inMaxLabels[i]->setText(max.toString());
|
||||
inMinLabels[i]->setText(min.toString());
|
||||
if (max.toInt()> min.toInt()) {
|
||||
inRevCheckboxes[i]->setChecked(false);
|
||||
inSliders[i]->setMaximum(max.toInt());
|
||||
inSliders[i]->setMinimum(min.toInt());
|
||||
} else {
|
||||
inRevCheckboxes[i]->setChecked(true);
|
||||
inSliders[i]->setMaximum(min.toInt());
|
||||
inSliders[i]->setMinimum(max.toInt());
|
||||
}
|
||||
inSliders[i]->setValue(neutral.toInt());
|
||||
}
|
||||
|
||||
// Update receiver type
|
||||
field = obj->getField(QString("InputMode"));
|
||||
m_config->receiverType->setText(field->getValue().toString());
|
||||
|
||||
// Reset all channel assignement dropdowns:
|
||||
foreach (QComboBox *combo, inChannelAssign) {
|
||||
combo->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
// Update all channels assignements
|
||||
QList<UAVObjectField *> fieldList = obj->getFields();
|
||||
foreach (UAVObjectField *field, fieldList) {
|
||||
if (field->getUnits().contains("channel"))
|
||||
assignChannel(obj, field->getName());
|
||||
}
|
||||
|
||||
// Update all the flight mode settingsin the relevant tab
|
||||
field = obj->getField(QString("FlightModePosition"));
|
||||
m_config->fmsModePos1->setCurrentIndex((m_config->fmsModePos1->findText(field->getValue(0).toString())));
|
||||
m_config->fmsModePos2->setCurrentIndex((m_config->fmsModePos2->findText(field->getValue(1).toString())));
|
||||
m_config->fmsModePos3->setCurrentIndex((m_config->fmsModePos3->findText(field->getValue(2).toString())));
|
||||
|
||||
field = obj->getField(QString("Stabilization1Settings"));
|
||||
m_config->fmsSsPos1Roll->setCurrentIndex(m_config->fmsSsPos1Roll->findText(field->getValue(field->getElementNames().indexOf("Roll")).toString()));
|
||||
m_config->fmsSsPos1Pitch->setCurrentIndex(m_config->fmsSsPos1Pitch->findText(field->getValue(field->getElementNames().indexOf("Pitch")).toString()));
|
||||
m_config->fmsSsPos1Yaw->setCurrentIndex(m_config->fmsSsPos1Yaw->findText(field->getValue(field->getElementNames().indexOf("Yaw")).toString()));
|
||||
field = obj->getField(QString("Stabilization2Settings"));
|
||||
m_config->fmsSsPos2Roll->setCurrentIndex(m_config->fmsSsPos2Roll->findText(field->getValue(field->getElementNames().indexOf("Roll")).toString()));
|
||||
m_config->fmsSsPos2Pitch->setCurrentIndex(m_config->fmsSsPos2Pitch->findText(field->getValue(field->getElementNames().indexOf("Pitch")).toString()));
|
||||
m_config->fmsSsPos2Yaw->setCurrentIndex(m_config->fmsSsPos2Yaw->findText(field->getValue(field->getElementNames().indexOf("Yaw")).toString()));
|
||||
field = obj->getField(QString("Stabilization3Settings"));
|
||||
m_config->fmsSsPos3Roll->setCurrentIndex(m_config->fmsSsPos3Roll->findText(field->getValue(field->getElementNames().indexOf("Roll")).toString()));
|
||||
m_config->fmsSsPos3Pitch->setCurrentIndex(m_config->fmsSsPos3Pitch->findText(field->getValue(field->getElementNames().indexOf("Pitch")).toString()));
|
||||
m_config->fmsSsPos3Yaw->setCurrentIndex(m_config->fmsSsPos3Yaw->findText(field->getValue(field->getElementNames().indexOf("Yaw")).toString()));
|
||||
|
||||
// Load the arming settings
|
||||
field = obj->getField(QString("Arming"));
|
||||
m_config->armControl->setCurrentIndex(m_config->armControl->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("ArmedTimeout"));
|
||||
m_config->armTimeout->setValue(field->getValue().toInt()/1000);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sends the config to the board, without saving to the SD card
|
||||
*/
|
||||
void ConfigInputWidget::sendRCInputUpdate()
|
||||
{
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ManualControlSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// Now update all fields from the sliders:
|
||||
QString fieldName = QString("ChannelMax");
|
||||
UAVObjectField * field = obj->getField(fieldName);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
field->setValue(inMaxLabels[i]->text().toInt(), i);
|
||||
}
|
||||
|
||||
fieldName = QString("ChannelMin");
|
||||
field = obj->getField(fieldName);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
field->setValue(inMinLabels[i]->text().toInt(), i);
|
||||
}
|
||||
|
||||
fieldName = QString("ChannelNeutral");
|
||||
field = obj->getField(fieldName);
|
||||
for (int i = 0; i < 8; i++)
|
||||
field->setValue(inSliders[i]->value(), i);
|
||||
|
||||
// Set Roll/Pitch/Yaw/Etc assignement:
|
||||
// Rule: if two channels have the same setting (which is wrong!) the higher channel
|
||||
// will get the setting.
|
||||
|
||||
// First, reset all channel assignements:
|
||||
QList<UAVObjectField*> fieldList = obj->getFields();
|
||||
foreach (UAVObjectField* field, fieldList) {
|
||||
if (field->getUnits().contains("channel")) {
|
||||
field->setValue(field->getOptions().last());
|
||||
}
|
||||
}
|
||||
|
||||
// Then assign according to current GUI state:
|
||||
if (m_config->ch0Assign->currentIndex() != 0) {
|
||||
field = obj->getField(m_config->ch0Assign->currentText());
|
||||
field->setValue(field->getOptions().at(0)); // -> This way we don't depend on channel naming convention
|
||||
}
|
||||
if (m_config->ch1Assign->currentIndex() != 0) {
|
||||
field = obj->getField(m_config->ch1Assign->currentText());
|
||||
field->setValue(field->getOptions().at(1));
|
||||
}
|
||||
if (m_config->ch2Assign->currentIndex() != 0) {
|
||||
field = obj->getField(m_config->ch2Assign->currentText());
|
||||
field->setValue(field->getOptions().at(2));
|
||||
}
|
||||
if (m_config->ch3Assign->currentIndex() != 0) {
|
||||
field = obj->getField(m_config->ch3Assign->currentText());
|
||||
field->setValue(field->getOptions().at(3));
|
||||
}
|
||||
if (m_config->ch4Assign->currentIndex() != 0) {
|
||||
field = obj->getField(m_config->ch4Assign->currentText());
|
||||
field->setValue(field->getOptions().at(4));
|
||||
}
|
||||
if (m_config->ch5Assign->currentIndex() != 0) {
|
||||
field = obj->getField(m_config->ch5Assign->currentText());
|
||||
field->setValue(field->getOptions().at(5));
|
||||
}
|
||||
if (m_config->ch6Assign->currentIndex() != 0) {
|
||||
field = obj->getField(m_config->ch6Assign->currentText());
|
||||
field->setValue(field->getOptions().at(6));
|
||||
}
|
||||
if (m_config->ch7Assign->currentIndex() != 0) {
|
||||
field = obj->getField(m_config->ch7Assign->currentText());
|
||||
field->setValue(field->getOptions().at(7));
|
||||
}
|
||||
|
||||
// Send all the flight mode settings
|
||||
field = obj->getField(QString("FlightModePosition"));
|
||||
field->setValue(m_config->fmsModePos1->currentText(),0);
|
||||
field->setValue(m_config->fmsModePos2->currentText(),1);
|
||||
field->setValue(m_config->fmsModePos3->currentText(),2);
|
||||
|
||||
field = obj->getField(QString("Stabilization1Settings"));
|
||||
field->setValue(m_config->fmsSsPos1Roll->currentText(), field->getElementNames().indexOf("Roll"));
|
||||
field->setValue(m_config->fmsSsPos1Pitch->currentText(), field->getElementNames().indexOf("Pitch"));
|
||||
field->setValue(m_config->fmsSsPos1Yaw->currentText(), field->getElementNames().indexOf("Yaw"));
|
||||
field = obj->getField(QString("Stabilization2Settings"));
|
||||
field->setValue(m_config->fmsSsPos2Roll->currentText(), field->getElementNames().indexOf("Roll"));
|
||||
field->setValue(m_config->fmsSsPos2Pitch->currentText(), field->getElementNames().indexOf("Pitch"));
|
||||
field->setValue(m_config->fmsSsPos2Yaw->currentText(), field->getElementNames().indexOf("Yaw"));
|
||||
field = obj->getField(QString("Stabilization3Settings"));
|
||||
field->setValue(m_config->fmsSsPos3Roll->currentText(), field->getElementNames().indexOf("Roll"));
|
||||
field->setValue(m_config->fmsSsPos3Pitch->currentText(), field->getElementNames().indexOf("Pitch"));
|
||||
field->setValue(m_config->fmsSsPos3Yaw->currentText(), field->getElementNames().indexOf("Yaw"));
|
||||
|
||||
// Save the arming settings
|
||||
field = obj->getField(QString("Arming"));
|
||||
field->setValue(m_config->armControl->currentText());
|
||||
field = obj->getField(QString("ArmedTimeout"));
|
||||
field->setValue(m_config->armTimeout->value()*1000);
|
||||
|
||||
// ... and send to the OP Board
|
||||
obj->updated();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Sends the config to the board and request saving into the SD card
|
||||
*/
|
||||
void ConfigInputWidget::saveRCInputObject()
|
||||
void ConfigInputWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
// Send update so that the latest value is saved
|
||||
sendRCInputUpdate();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlSettings")));
|
||||
Q_ASSERT(obj);
|
||||
saveObjectToSD(obj);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the dropdown option for a channel Input assignement
|
||||
*/
|
||||
void ConfigInputWidget::assignChannel(UAVDataObject *obj, QString str)
|
||||
{
|
||||
UAVObjectField* field = obj->getField(str);
|
||||
QStringList options = field->getOptions();
|
||||
switch (options.indexOf(field->getValue().toString())) {
|
||||
case 0:
|
||||
m_config->ch0Assign->setCurrentIndex(m_config->ch0Assign->findText(str));
|
||||
break;
|
||||
case 1:
|
||||
m_config->ch1Assign->setCurrentIndex(m_config->ch0Assign->findText(str));
|
||||
break;
|
||||
case 2:
|
||||
m_config->ch2Assign->setCurrentIndex(m_config->ch0Assign->findText(str));
|
||||
break;
|
||||
case 3:
|
||||
m_config->ch3Assign->setCurrentIndex(m_config->ch0Assign->findText(str));
|
||||
break;
|
||||
case 4:
|
||||
m_config->ch4Assign->setCurrentIndex(m_config->ch0Assign->findText(str));
|
||||
break;
|
||||
case 5:
|
||||
m_config->ch5Assign->setCurrentIndex(m_config->ch0Assign->findText(str));
|
||||
break;
|
||||
case 6:
|
||||
m_config->ch6Assign->setCurrentIndex(m_config->ch0Assign->findText(str));
|
||||
break;
|
||||
case 7:
|
||||
m_config->ch7Assign->setCurrentIndex(m_config->ch0Assign->findText(str));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the slider positions and min/max values
|
||||
*
|
||||
*/
|
||||
void ConfigInputWidget::updateChannels(UAVObject* controlCommand)
|
||||
{
|
||||
|
||||
QString fieldName = QString("Connected");
|
||||
UAVObjectField *field = controlCommand->getField(fieldName);
|
||||
if (field->getValue().toBool())
|
||||
{
|
||||
m_config->RCInputConnected->setText("RC Receiver connected");
|
||||
m_config->lblMissingInputs->setText("");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_config->RCInputConnected->setText("RC Receiver not connected or invalid input configuration (missing channels)");
|
||||
receiverHelp();
|
||||
}
|
||||
if (m_config->doRCInputCalibration->isChecked()) {
|
||||
if (firstUpdate) {
|
||||
// Increase the data rate from the board so that the sliders
|
||||
// move faster
|
||||
UAVObject::Metadata mdata = controlCommand->getMetadata();
|
||||
mdata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_PERIODIC;
|
||||
mccDataRate = mdata.flightTelemetryUpdatePeriod;
|
||||
mdata.flightTelemetryUpdatePeriod = 150;
|
||||
controlCommand->setMetadata(mdata);
|
||||
|
||||
// Also protect the user by setting all values to zero
|
||||
// and making the ActuatorCommand object readonly
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorCommand")));
|
||||
mdata = obj->getMetadata();
|
||||
mdata.flightAccess = UAVObject::ACCESS_READONLY;
|
||||
obj->setMetadata(mdata);
|
||||
UAVObjectField *field = obj->getField("Channel");
|
||||
for (uint i=0; i< field->getNumElements(); i++) {
|
||||
field->setValue(0,i);
|
||||
}
|
||||
obj->updated();
|
||||
|
||||
// OP-534: make sure the airframe can NEVER arm
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlSettings")));
|
||||
field = obj->getField("Arming");
|
||||
field->setValue("Always Disarmed");
|
||||
obj->updated();
|
||||
|
||||
// Last, make sure the user won't apply/save during calibration
|
||||
m_config->saveRCInputToRAM->setEnabled(false);
|
||||
m_config->saveRCInputToSD->setEnabled(false);
|
||||
|
||||
// Reset all slider values to zero
|
||||
field = controlCommand->getField(QString("Channel"));
|
||||
for (int i = 0; i < 8; i++)
|
||||
updateChannelInSlider(inSliders[i], inMinLabels[i], inMaxLabels[i], field->getValue(i).toInt(),inRevCheckboxes[i]->isChecked());
|
||||
firstUpdate = false;
|
||||
// Tell a few things to the user:
|
||||
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."));
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setDefaultButton(QMessageBox::Ok);
|
||||
msgBox.exec();
|
||||
|
||||
}
|
||||
|
||||
field = controlCommand->getField(QString("Channel"));
|
||||
for (int i = 0; i < 8; i++)
|
||||
updateChannelInSlider(inSliders[i], inMinLabels[i], inMaxLabels[i], field->getValue(i).toInt(),inRevCheckboxes[i]->isChecked());
|
||||
}
|
||||
else {
|
||||
if (!firstUpdate) {
|
||||
// Restore original data rate from the board:
|
||||
UAVObject::Metadata mdata = controlCommand->getMetadata();
|
||||
mdata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_PERIODIC;
|
||||
mdata.flightTelemetryUpdatePeriod = mccDataRate;
|
||||
controlCommand->setMetadata(mdata);
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorCommand")));
|
||||
mdata = obj->getMetadata();
|
||||
mdata.flightAccess = UAVObject::ACCESS_READWRITE;
|
||||
obj->setMetadata(mdata);
|
||||
|
||||
// Set some slider values to better defaults
|
||||
// Find some channels first
|
||||
int throttleChannel = -1;
|
||||
int fmChannel = -1;
|
||||
for (int i=0; i < inChannelAssign.length(); i++) {
|
||||
if (inChannelAssign.at(i)->currentText() == "Throttle") {
|
||||
// TODO: this is very ugly, because this relies on the name of the
|
||||
// channel input, everywhere else in the gadget we don't rely on the
|
||||
// naming...
|
||||
throttleChannel = i;
|
||||
}
|
||||
if (inChannelAssign.at(i)->currentText() == "FlightMode") {
|
||||
// TODO: this is very ugly, because this relies on the name of the
|
||||
// channel input, everywhere else in the gadget we don't rely on the
|
||||
// naming...
|
||||
fmChannel = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Throttle neutral defaults to 2% of range
|
||||
if (throttleChannel > -1) {
|
||||
inSliders.at(throttleChannel)->setValue(
|
||||
inSliders.at(throttleChannel)->minimum() +
|
||||
(inSliders.at(throttleChannel)->maximum()-
|
||||
inSliders.at(throttleChannel)->minimum())*0.02);
|
||||
}
|
||||
|
||||
// Flight mode at 50% of range:
|
||||
if (fmChannel > -1) {
|
||||
inSliders.at(fmChannel)->setValue(
|
||||
inSliders.at(fmChannel)->minimum()+
|
||||
(inSliders.at(fmChannel)->maximum()-
|
||||
inSliders.at(fmChannel)->minimum())*0.5);
|
||||
}
|
||||
|
||||
m_config->saveRCInputToRAM->setEnabled(true);
|
||||
m_config->saveRCInputToSD->setEnabled(true);
|
||||
}
|
||||
firstUpdate = true;
|
||||
}
|
||||
|
||||
//Update the Flight mode channel slider
|
||||
ManualControlSettings * manualSettings = ManualControlSettings::GetInstance(getObjectManager());
|
||||
ManualControlSettings::DataFields manualSettingsData = manualSettings->getData();
|
||||
uint chIndex = manualSettingsData.FlightMode;
|
||||
if (chIndex < manualSettings->FLIGHTMODE_NONE) {
|
||||
float valueScaled;
|
||||
|
||||
int chMin = manualSettingsData.ChannelMin[chIndex];
|
||||
int chMax = manualSettingsData.ChannelMax[chIndex];
|
||||
int chNeutral = manualSettingsData.ChannelNeutral[chIndex];
|
||||
|
||||
int value = controlCommand->getField("Channel")->getValue(chIndex).toInt();
|
||||
if ((chMax > chMin && value >= chNeutral) || (chMin > chMax && value <= chNeutral))
|
||||
{
|
||||
if (chMax != chNeutral)
|
||||
valueScaled = (float)(value - chNeutral) / (float)(chMax - chNeutral);
|
||||
else
|
||||
valueScaled = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chMin != chNeutral)
|
||||
valueScaled = (float)(value - chNeutral) / (float)(chNeutral - chMin);
|
||||
else
|
||||
valueScaled = 0;
|
||||
}
|
||||
|
||||
if(valueScaled < -(1.0 / 3.0))
|
||||
m_config->fmsSlider->setValue(-100);
|
||||
else if (valueScaled > (1.0/3.0))
|
||||
m_config->fmsSlider->setValue(100);
|
||||
else
|
||||
m_config->fmsSlider->setValue(0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigInputWidget::updateChannelInSlider(QSlider *slider, QLabel *min, QLabel *max, int value, bool reversed)
|
||||
{
|
||||
if (!slider || !min || !max)
|
||||
return;
|
||||
|
||||
if (firstUpdate) {
|
||||
// Reset all the min/max values of the progress bar since we are starting the calibration.
|
||||
slider->setMaximum(value);
|
||||
slider->setMinimum(value);
|
||||
slider->setValue(value);
|
||||
max->setText(QString::number(value));
|
||||
min->setText(QString::number(value));
|
||||
return;
|
||||
}
|
||||
|
||||
if (value > 0) {
|
||||
// avoids glitches...
|
||||
if (value > slider->maximum()) {
|
||||
slider->setMaximum(value);
|
||||
if (reversed)
|
||||
min->setText(QString::number(value));
|
||||
else
|
||||
max->setText(QString::number(value));
|
||||
}
|
||||
if (value < slider->minimum()) {
|
||||
slider->setMinimum(value);
|
||||
if (reversed)
|
||||
max->setText(QString::number(value));
|
||||
else
|
||||
min->setText(QString::number(value));
|
||||
}
|
||||
slider->setValue(value);
|
||||
}
|
||||
QWidget::resizeEvent(event);
|
||||
m_config->graphicsView->fitInView(m_txBackground, Qt::KeepAspectRatio );
|
||||
}
|
||||
|
||||
void ConfigInputWidget::openHelp()
|
||||
@ -653,77 +272,1147 @@ void ConfigInputWidget::openHelp()
|
||||
|
||||
QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Input+Configuration", QUrl::StrictMode) );
|
||||
}
|
||||
void ConfigInputWidget::receiverHelp()
|
||||
void ConfigInputWidget::goToWizard()
|
||||
{
|
||||
QString unassigned;
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
|
||||
UAVDataObject* controlCommand = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ManualControlSettings")));
|
||||
|
||||
UAVObjectField *field;
|
||||
|
||||
field= controlCommand->getField("Roll");
|
||||
if(field->getValue().toString()=="None")
|
||||
unassigned.append("Roll");
|
||||
|
||||
field =controlCommand->getField("Pitch");
|
||||
if(field->getValue().toString()=="None")
|
||||
{
|
||||
if(unassigned.length()>0)
|
||||
unassigned.append(", ");
|
||||
unassigned.append("Pitch");
|
||||
}
|
||||
|
||||
field =controlCommand->getField("Yaw");
|
||||
if(field->getValue().toString()=="None")
|
||||
{
|
||||
if(unassigned.length()>0)
|
||||
unassigned.append(", ");
|
||||
unassigned.append("Yaw");
|
||||
}
|
||||
|
||||
field =controlCommand->getField("Throttle");
|
||||
if(field->getValue().toString()=="None")
|
||||
{
|
||||
if(unassigned.length()>0)
|
||||
unassigned.append(", ");
|
||||
unassigned.append("Throttle");
|
||||
}
|
||||
|
||||
field =controlCommand->getField("FlightMode");
|
||||
if(field->getValue().toString()=="None")
|
||||
{
|
||||
if(unassigned.length()>0)
|
||||
unassigned.append(", ");
|
||||
unassigned.append("FlightMode");
|
||||
}
|
||||
if(unassigned.length()>0)
|
||||
m_config->lblMissingInputs->setText(QString("Channels left to assign: ")+unassigned);
|
||||
else
|
||||
m_config->lblMissingInputs->setText("");
|
||||
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."));
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setDefaultButton(QMessageBox::Ok);
|
||||
msgBox.exec();
|
||||
wizardSetUpStep(wizardWelcome);
|
||||
m_config->graphicsView->fitInView(m_txBackground, Qt::KeepAspectRatio );
|
||||
}
|
||||
void ConfigInputWidget::updateTips(int value)
|
||||
|
||||
void ConfigInputWidget::wzCancel()
|
||||
{
|
||||
if(value==Qt::Checked)
|
||||
dimOtherControls(false);
|
||||
manualCommandObj->setMetadata(manualCommandObj->getDefaultMetadata());
|
||||
m_config->stackedWidget->setCurrentIndex(0);
|
||||
|
||||
if(wizardStep != wizardNone)
|
||||
wizardTearDownStep(wizardStep);
|
||||
wizardStep=wizardNone;
|
||||
|
||||
// Load settings back from beginning of wizard
|
||||
manualSettingsObj->setData(previousManualSettingsData);
|
||||
}
|
||||
|
||||
void ConfigInputWidget::wzNext()
|
||||
{
|
||||
// In identify sticks mode the next button can indicate
|
||||
// channel advance
|
||||
if(wizardStep != wizardNone &&
|
||||
wizardStep != wizardIdentifySticks)
|
||||
wizardTearDownStep(wizardStep);
|
||||
|
||||
// State transitions for next button
|
||||
switch(wizardStep) {
|
||||
case wizardWelcome:
|
||||
wizardSetUpStep(wizardChooseMode);
|
||||
break;
|
||||
case wizardChooseMode:
|
||||
wizardSetUpStep(wizardChooseType);
|
||||
break;
|
||||
case wizardChooseType:
|
||||
wizardSetUpStep(wizardIdentifySticks);
|
||||
break;
|
||||
case wizardIdentifySticks:
|
||||
nextChannel();
|
||||
if(currentChannelNum==-1) { // Gone through all channels
|
||||
wizardTearDownStep(wizardIdentifySticks);
|
||||
wizardSetUpStep(wizardIdentifyCenter);
|
||||
}
|
||||
break;
|
||||
case wizardIdentifyCenter:
|
||||
wizardSetUpStep(wizardIdentifyLimits);
|
||||
break;
|
||||
case wizardIdentifyLimits:
|
||||
wizardSetUpStep(wizardIdentifyInverted);
|
||||
break;
|
||||
case wizardIdentifyInverted:
|
||||
wizardSetUpStep(wizardFinish);
|
||||
break;
|
||||
case wizardFinish:
|
||||
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=wizardNone;
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigInputWidget::wzBack()
|
||||
{
|
||||
if(wizardStep != wizardNone &&
|
||||
wizardStep != wizardIdentifySticks)
|
||||
wizardTearDownStep(wizardStep);
|
||||
|
||||
// State transitions for next button
|
||||
switch(wizardStep) {
|
||||
case wizardChooseMode:
|
||||
wizardSetUpStep(wizardWelcome);
|
||||
break;
|
||||
case wizardChooseType:
|
||||
wizardSetUpStep(wizardChooseMode);
|
||||
break;
|
||||
case wizardIdentifySticks:
|
||||
prevChannel();
|
||||
if(currentChannelNum == -1) {
|
||||
wizardTearDownStep(wizardIdentifySticks);
|
||||
wizardSetUpStep(wizardChooseType);
|
||||
}
|
||||
break;
|
||||
case wizardIdentifyCenter:
|
||||
wizardSetUpStep(wizardIdentifySticks);
|
||||
break;
|
||||
case wizardIdentifyLimits:
|
||||
wizardSetUpStep(wizardIdentifyCenter);
|
||||
break;
|
||||
case wizardIdentifyInverted:
|
||||
wizardSetUpStep(wizardIdentifyLimits);
|
||||
break;
|
||||
case wizardFinish:
|
||||
wizardSetUpStep(wizardIdentifyInverted);
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigInputWidget::wizardSetUpStep(enum wizardSteps step)
|
||||
{
|
||||
switch(step) {
|
||||
case wizardWelcome:
|
||||
m_config->graphicsView->setVisible(false);
|
||||
setTxMovement(nothing);
|
||||
manualSettingsData=manualSettingsObj->getData();
|
||||
manualSettingsData.Arming=ManualControlSettings::ARMING_ALWAYSDISARMED;
|
||||
previousManualSettingsData = manualSettingsData;
|
||||
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);
|
||||
break;
|
||||
case wizardChooseMode:
|
||||
{
|
||||
m_config->ch0Cur->setToolTip("Current channel value");
|
||||
m_config->ch1Cur->setToolTip("Current channel value");
|
||||
m_config->ch2Cur->setToolTip("Current channel value");
|
||||
m_config->ch3Cur->setToolTip("Current channel value");
|
||||
m_config->ch4Cur->setToolTip("Current channel value");
|
||||
m_config->ch5Cur->setToolTip("Current channel value");
|
||||
m_config->ch6Cur->setToolTip("Current channel value");
|
||||
m_config->ch7Cur->setToolTip("Current channel value");
|
||||
m_config->graphicsView->setVisible(true);
|
||||
setTxMovement(nothing);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case wizardChooseType:
|
||||
{
|
||||
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"
|
||||
"If you are using a heli transmitter please engage throttle hold now please.\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;
|
||||
}
|
||||
break;
|
||||
case wizardIdentifySticks:
|
||||
usedChannels.clear();
|
||||
currentChannelNum=-1;
|
||||
nextChannel();
|
||||
manualSettingsData=manualSettingsObj->getData();
|
||||
connect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls()));
|
||||
m_config->wzNext->setEnabled(false);
|
||||
break;
|
||||
case wizardIdentifyCenter:
|
||||
setTxMovement(centerAll);
|
||||
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)")));
|
||||
break;
|
||||
case wizardIdentifyLimits:
|
||||
{
|
||||
dimOtherControls(false);
|
||||
setTxMovement(moveAll);
|
||||
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();
|
||||
for(uint i=0;i<ManualControlSettings::CHANNELMAX_NUMELEM;++i)
|
||||
{
|
||||
manualSettingsData.ChannelMin[i]=manualSettingsData.ChannelNeutral[i];
|
||||
manualSettingsData.ChannelMax[i]=manualSettingsData.ChannelNeutral[i];
|
||||
}
|
||||
connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits()));
|
||||
}
|
||||
break;
|
||||
case wizardIdentifyInverted:
|
||||
dimOtherControls(true);
|
||||
setTxMovement(nothing);
|
||||
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()));
|
||||
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")));
|
||||
fastMdata();
|
||||
break;
|
||||
case wizardFinish:
|
||||
foreach(QWidget * wd,extraWidgets)
|
||||
{
|
||||
QCheckBox * cb=qobject_cast<QCheckBox *>(wd);
|
||||
if(cb)
|
||||
{
|
||||
disconnect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls()));
|
||||
delete cb;
|
||||
}
|
||||
}
|
||||
extraWidgets.clear();
|
||||
connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks()));
|
||||
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.")));
|
||||
fastMdata();
|
||||
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(0);
|
||||
}
|
||||
wizardStep = step;
|
||||
}
|
||||
|
||||
void ConfigInputWidget::wizardTearDownStep(enum wizardSteps step)
|
||||
{
|
||||
QRadioButton * mode, * type;
|
||||
Q_ASSERT(step == wizardStep);
|
||||
switch(step) {
|
||||
case wizardWelcome:
|
||||
break;
|
||||
case wizardChooseMode:
|
||||
mode=qobject_cast<QRadioButton *>(extraWidgets.at(0));
|
||||
if(mode->isChecked())
|
||||
transmitterMode=mode1;
|
||||
else
|
||||
transmitterMode=mode2;
|
||||
delete extraWidgets.at(0);
|
||||
delete extraWidgets.at(1);
|
||||
extraWidgets.clear();
|
||||
break;
|
||||
case wizardChooseType:
|
||||
type=qobject_cast<QRadioButton *>(extraWidgets.at(0));
|
||||
if(type->isChecked())
|
||||
transmitterType=acro;
|
||||
else
|
||||
transmitterType=heli;
|
||||
delete extraWidgets.at(0);
|
||||
delete extraWidgets.at(1);
|
||||
extraWidgets.clear();
|
||||
break;
|
||||
case wizardIdentifySticks:
|
||||
disconnect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls()));
|
||||
m_config->wzNext->setEnabled(true);
|
||||
break;
|
||||
case wizardIdentifyCenter:
|
||||
manualCommandData=manualCommandObj->getData();
|
||||
manualSettingsData=manualSettingsObj->getData();
|
||||
for(unsigned int i=0;i<ManualControlCommand::CHANNEL_NUMELEM;++i)
|
||||
{
|
||||
manualSettingsData.ChannelNeutral[i]=manualCommandData.Channel[i];
|
||||
}
|
||||
manualSettingsObj->setData(manualSettingsData);
|
||||
break;
|
||||
case wizardIdentifyLimits:
|
||||
disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits()));
|
||||
manualSettingsObj->setData(manualSettingsData);
|
||||
restoreMdata();
|
||||
break;
|
||||
case wizardIdentifyInverted:
|
||||
foreach(QWidget * wd,extraWidgets)
|
||||
{
|
||||
QCheckBox * cb=qobject_cast<QCheckBox *>(wd);
|
||||
if(cb)
|
||||
{
|
||||
disconnect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls()));
|
||||
delete cb;
|
||||
}
|
||||
}
|
||||
extraWidgets.clear();
|
||||
disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks()));
|
||||
restoreMdata();
|
||||
break;
|
||||
case wizardFinish:
|
||||
setTxMovement(nothing);
|
||||
m_config->stackedWidget->setCurrentIndex(0);
|
||||
disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks()));
|
||||
restoreMdata();
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set manual control command to fast updates
|
||||
*/
|
||||
void ConfigInputWidget::fastMdata()
|
||||
{
|
||||
manualControlMdata = manualCommandObj->getMetadata();
|
||||
UAVObject::Metadata mdata = manualControlMdata;
|
||||
mdata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_PERIODIC;
|
||||
mdata.flightTelemetryUpdatePeriod = 150;
|
||||
manualCommandObj->setMetadata(mdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore previous update settings for manual control data
|
||||
*/
|
||||
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<QRadioButton *>(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<QRadioButton *>(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;i<ManualControlCommand::CHANNEL_NUMELEM;++i)
|
||||
// {
|
||||
// manualSettingsData.ChannelNeutral[i]=manualCommandData.Channel[i];
|
||||
// }
|
||||
// manualSettingsObj->setData(manualSettingsData);
|
||||
// }
|
||||
// if(wizardStep==wizardIdentifyInverted)
|
||||
// {
|
||||
// foreach(QWidget * wd,extraWidgets)
|
||||
// {
|
||||
// QCheckBox * cb=qobject_cast<QCheckBox *>(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;i<ManualControlSettings::CHANNELMAX_NUMELEM;++i)
|
||||
// {
|
||||
// manualSettingsData.ChannelMin[i]=manualSettingsData.ChannelNeutral[i];
|
||||
// manualSettingsData.ChannelMax[i]=manualSettingsData.ChannelNeutral[i];
|
||||
// }
|
||||
// connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits()));
|
||||
// }
|
||||
// else if(step==wizardIdentifyInverted)
|
||||
// {
|
||||
// dimOtherControls(true);
|
||||
// setTxMovement(nothing);
|
||||
// if(wizardStep==wizardIdentifyLimits)
|
||||
// {
|
||||
// disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits()));
|
||||
// manualSettingsObj->setData(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<QCheckBox *>(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
|
||||
*/
|
||||
void ConfigInputWidget::setChannel(int newChan)
|
||||
{
|
||||
if(newChan == ManualControlSettings::CHANNELGROUPS_COLLECTIVE)
|
||||
m_config->wzText->setText(QString(tr("Please enable throttle hold mode and move the collective pitch stick")));
|
||||
else if (newChan == ManualControlSettings::CHANNELGROUPS_FLIGHTMODE)
|
||||
m_config->wzText->setText(QString(tr("Please flick the flight mode switch. For switches you may have to repeat this rapidly.")));
|
||||
else
|
||||
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"))
|
||||
m_config->wzNext->setEnabled(true);
|
||||
|
||||
setMoveFromCommand(newChan);
|
||||
|
||||
currentChannelNum = newChan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unfortunately order of channel should be different in different conditions. Selects
|
||||
* next channel based on heli or acro mode
|
||||
*/
|
||||
void ConfigInputWidget::nextChannel()
|
||||
{
|
||||
QList <int> order = (transmitterType == heli) ? heliChannelOrder : acroChannelOrder;
|
||||
|
||||
if(currentChannelNum == -1) {
|
||||
setChannel(order[0]);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < order.length() - 1; i++) {
|
||||
if(order[i] == currentChannelNum) {
|
||||
setChannel(order[i+1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
currentChannelNum = -1; // hit end of list
|
||||
}
|
||||
|
||||
/**
|
||||
* Unfortunately order of channel should be different in different conditions. Selects
|
||||
* previous channel based on heli or acro mode
|
||||
*/
|
||||
void ConfigInputWidget::prevChannel()
|
||||
{
|
||||
QList <int> order = transmitterType == heli ? heliChannelOrder : acroChannelOrder;
|
||||
|
||||
// No previous from unset channel or next state
|
||||
if(currentChannelNum == -1)
|
||||
return;
|
||||
|
||||
for (int i = 1; i < order.length(); i++) {
|
||||
if(order[i] == currentChannelNum) {
|
||||
setChannel(order[i-1]);
|
||||
usedChannels.removeLast();
|
||||
return;
|
||||
}
|
||||
}
|
||||
currentChannelNum = -1; // hit end of list
|
||||
}
|
||||
|
||||
void ConfigInputWidget::identifyControls()
|
||||
{
|
||||
static int debounce=0;
|
||||
|
||||
receiverActivityData=receiverActivityObj->getData();
|
||||
if(receiverActivityData.ActiveChannel==255)
|
||||
return;
|
||||
else
|
||||
{
|
||||
receiverActivityData=receiverActivityObj->getData();
|
||||
currentChannel.group=receiverActivityData.ActiveGroup;
|
||||
currentChannel.number=receiverActivityData.ActiveChannel;
|
||||
if(currentChannel==lastChannel)
|
||||
++debounce;
|
||||
lastChannel.group= currentChannel.group;
|
||||
lastChannel.number=currentChannel.number;
|
||||
if(!usedChannels.contains(lastChannel) && debounce>1)
|
||||
{
|
||||
debounce=0;
|
||||
usedChannels.append(lastChannel);
|
||||
manualSettingsData=manualSettingsObj->getData();
|
||||
manualSettingsData.ChannelGroups[currentChannelNum]=currentChannel.group;
|
||||
manualSettingsData.ChannelNumber[currentChannelNum]=currentChannel.number;
|
||||
manualSettingsObj->setData(manualSettingsData);
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
m_config->wzText->clear();
|
||||
setTxMovement(nothing);
|
||||
|
||||
QTimer::singleShot(300, this, SLOT(wzNext()));
|
||||
}
|
||||
|
||||
void ConfigInputWidget::identifyLimits()
|
||||
{
|
||||
manualCommandData=manualCommandObj->getData();
|
||||
for(uint i=0;i<ManualControlSettings::CHANNELMAX_NUMELEM;++i)
|
||||
{
|
||||
if(manualSettingsData.ChannelMin[i]>manualCommandData.Channel[i])
|
||||
manualSettingsData.ChannelMin[i]=manualCommandData.Channel[i];
|
||||
if(manualSettingsData.ChannelMax[i]<manualCommandData.Channel[i])
|
||||
manualSettingsData.ChannelMax[i]=manualCommandData.Channel[i];
|
||||
}
|
||||
}
|
||||
void ConfigInputWidget::setMoveFromCommand(int command)
|
||||
{
|
||||
//CHANNELNUMBER_ROLL=0, CHANNELNUMBER_PITCH=1, CHANNELNUMBER_YAW=2, CHANNELNUMBER_THROTTLE=3, CHANNELNUMBER_FLIGHTMODE=4, CHANNELNUMBER_ACCESSORY0=5, CHANNELNUMBER_ACCESSORY1=6, CHANNELNUMBER_ACCESSORY2=7 } ChannelNumberElem;
|
||||
if(command==ManualControlSettings::CHANNELNUMBER_ROLL)
|
||||
{
|
||||
setTxMovement(moveRightHorizontalStick);
|
||||
}
|
||||
else if(command==ManualControlSettings::CHANNELNUMBER_PITCH)
|
||||
{
|
||||
if(transmitterMode==mode2)
|
||||
setTxMovement(moveRightVerticalStick);
|
||||
else
|
||||
setTxMovement(moveLeftVerticalStick);
|
||||
}
|
||||
else if(command==ManualControlSettings::CHANNELNUMBER_YAW)
|
||||
{
|
||||
setTxMovement(moveLeftHorizontalStick);
|
||||
}
|
||||
else if(command==ManualControlSettings::CHANNELNUMBER_THROTTLE)
|
||||
{
|
||||
if(transmitterMode==mode2)
|
||||
setTxMovement(moveLeftVerticalStick);
|
||||
else
|
||||
setTxMovement(moveRightVerticalStick);
|
||||
}
|
||||
else if(command==ManualControlSettings::CHANNELNUMBER_COLLECTIVE)
|
||||
{
|
||||
if(transmitterMode==mode2)
|
||||
setTxMovement(moveLeftVerticalStick);
|
||||
else
|
||||
setTxMovement(moveRightVerticalStick);
|
||||
}
|
||||
else if(command==ManualControlSettings::CHANNELNUMBER_FLIGHTMODE)
|
||||
{
|
||||
setTxMovement(moveFlightMode);
|
||||
}
|
||||
else if(command==ManualControlSettings::CHANNELNUMBER_ACCESSORY0)
|
||||
{
|
||||
setTxMovement(moveAccess0);
|
||||
}
|
||||
else if(command==ManualControlSettings::CHANNELNUMBER_ACCESSORY1)
|
||||
{
|
||||
setTxMovement(moveAccess1);
|
||||
}
|
||||
else if(command==ManualControlSettings::CHANNELNUMBER_ACCESSORY2)
|
||||
{
|
||||
setTxMovement(moveAccess2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ConfigInputWidget::setTxMovement(txMovements movement)
|
||||
{
|
||||
resetTxControls();
|
||||
switch(movement)
|
||||
{
|
||||
case moveLeftVerticalStick:
|
||||
movePos=0;
|
||||
growing=true;
|
||||
currentMovement=moveLeftVerticalStick;
|
||||
animate->start(100);
|
||||
break;
|
||||
case moveRightVerticalStick:
|
||||
movePos=0;
|
||||
growing=true;
|
||||
currentMovement=moveRightVerticalStick;
|
||||
animate->start(100);
|
||||
break;
|
||||
case moveLeftHorizontalStick:
|
||||
movePos=0;
|
||||
growing=true;
|
||||
currentMovement=moveLeftHorizontalStick;
|
||||
animate->start(100);
|
||||
break;
|
||||
case moveRightHorizontalStick:
|
||||
movePos=0;
|
||||
growing=true;
|
||||
currentMovement=moveRightHorizontalStick;
|
||||
animate->start(100);
|
||||
break;
|
||||
case moveAccess0:
|
||||
movePos=0;
|
||||
growing=true;
|
||||
currentMovement=moveAccess0;
|
||||
animate->start(100);
|
||||
break;
|
||||
case moveAccess1:
|
||||
movePos=0;
|
||||
growing=true;
|
||||
currentMovement=moveAccess1;
|
||||
animate->start(100);
|
||||
break;
|
||||
case moveAccess2:
|
||||
movePos=0;
|
||||
growing=true;
|
||||
currentMovement=moveAccess2;
|
||||
animate->start(100);
|
||||
break;
|
||||
case moveFlightMode:
|
||||
movePos=0;
|
||||
growing=true;
|
||||
currentMovement=moveFlightMode;
|
||||
animate->start(1000);
|
||||
break;
|
||||
case centerAll:
|
||||
movePos=0;
|
||||
currentMovement=centerAll;
|
||||
animate->start(1000);
|
||||
break;
|
||||
case moveAll:
|
||||
movePos=0;
|
||||
growing=true;
|
||||
currentMovement=moveAll;
|
||||
animate->start(50);
|
||||
break;
|
||||
case nothing:
|
||||
movePos=0;
|
||||
animate->stop();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigInputWidget::moveTxControls()
|
||||
{
|
||||
QTransform trans;
|
||||
QGraphicsItem * item;
|
||||
txMovementType move;
|
||||
int limitMax;
|
||||
int limitMin;
|
||||
static bool auxFlag=false;
|
||||
switch(currentMovement)
|
||||
{
|
||||
case moveLeftVerticalStick:
|
||||
item=m_txLeftStick;
|
||||
trans=m_txLeftStickOrig;
|
||||
limitMax=STICK_MAX_MOVE;
|
||||
limitMin=STICK_MIN_MOVE;
|
||||
move=vertical;
|
||||
break;
|
||||
case moveRightVerticalStick:
|
||||
item=m_txRightStick;
|
||||
trans=m_txRightStickOrig;
|
||||
limitMax=STICK_MAX_MOVE;
|
||||
limitMin=STICK_MIN_MOVE;
|
||||
move=vertical;
|
||||
break;
|
||||
case moveLeftHorizontalStick:
|
||||
item=m_txLeftStick;
|
||||
trans=m_txLeftStickOrig;
|
||||
limitMax=STICK_MAX_MOVE;
|
||||
limitMin=STICK_MIN_MOVE;
|
||||
move=horizontal;
|
||||
break;
|
||||
case moveRightHorizontalStick:
|
||||
item=m_txRightStick;
|
||||
trans=m_txRightStickOrig;
|
||||
limitMax=STICK_MAX_MOVE;
|
||||
limitMin=STICK_MIN_MOVE;
|
||||
move=horizontal;
|
||||
break;
|
||||
case moveAccess0:
|
||||
item=m_txAccess0;
|
||||
trans=m_txAccess0Orig;
|
||||
limitMax=ACCESS_MAX_MOVE;
|
||||
limitMin=ACCESS_MIN_MOVE;
|
||||
move=horizontal;
|
||||
break;
|
||||
case moveAccess1:
|
||||
item=m_txAccess1;
|
||||
trans=m_txAccess1Orig;
|
||||
limitMax=ACCESS_MAX_MOVE;
|
||||
limitMin=ACCESS_MIN_MOVE;
|
||||
move=horizontal;
|
||||
break;
|
||||
case moveAccess2:
|
||||
item=m_txAccess2;
|
||||
trans=m_txAccess2Orig;
|
||||
limitMax=ACCESS_MAX_MOVE;
|
||||
limitMin=ACCESS_MIN_MOVE;
|
||||
move=horizontal;
|
||||
break;
|
||||
case moveFlightMode:
|
||||
item=m_txFlightMode;
|
||||
move=jump;
|
||||
break;
|
||||
case centerAll:
|
||||
item=m_txArrows;
|
||||
move=jump;
|
||||
break;
|
||||
case moveAll:
|
||||
limitMax=STICK_MAX_MOVE;
|
||||
limitMin=STICK_MIN_MOVE;
|
||||
move=mix;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(move==vertical)
|
||||
item->setTransform(trans.translate(0,movePos*10),false);
|
||||
else if(move==horizontal)
|
||||
item->setTransform(trans.translate(movePos*10,0),false);
|
||||
else if(move==jump)
|
||||
{
|
||||
if(item==m_txArrows)
|
||||
{
|
||||
m_txArrows->setVisible(!m_txArrows->isVisible());
|
||||
}
|
||||
else if(item==m_txFlightMode)
|
||||
{
|
||||
QGraphicsSvgItem * svg;
|
||||
svg=(QGraphicsSvgItem *)item;
|
||||
if (svg)
|
||||
{
|
||||
if(svg->elementId()=="flightModeCenter")
|
||||
{
|
||||
if(growing)
|
||||
{
|
||||
svg->setElementId("flightModeRight");
|
||||
m_txFlightMode->setTransform(m_txFlightModeROrig,false);
|
||||
}
|
||||
else
|
||||
{
|
||||
svg->setElementId("flightModeLeft");
|
||||
m_txFlightMode->setTransform(m_txFlightModeLOrig,false);
|
||||
}
|
||||
}
|
||||
else if(svg->elementId()=="flightModeRight")
|
||||
{
|
||||
growing=false;
|
||||
svg->setElementId("flightModeCenter");
|
||||
m_txFlightMode->setTransform(m_txFlightModeCOrig,false);
|
||||
}
|
||||
else if(svg->elementId()=="flightModeLeft")
|
||||
{
|
||||
growing=true;
|
||||
svg->setElementId("flightModeCenter");
|
||||
m_txFlightMode->setTransform(m_txFlightModeCOrig,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(move==mix)
|
||||
{
|
||||
trans=m_txAccess0Orig;
|
||||
m_txAccess0->setTransform(trans.translate(movePos*10*ACCESS_MAX_MOVE/STICK_MAX_MOVE,0),false);
|
||||
trans=m_txAccess1Orig;
|
||||
m_txAccess1->setTransform(trans.translate(movePos*10*ACCESS_MAX_MOVE/STICK_MAX_MOVE,0),false);
|
||||
trans=m_txAccess2Orig;
|
||||
m_txAccess2->setTransform(trans.translate(movePos*10*ACCESS_MAX_MOVE/STICK_MAX_MOVE,0),false);
|
||||
|
||||
if(auxFlag)
|
||||
{
|
||||
trans=m_txLeftStickOrig;
|
||||
m_txLeftStick->setTransform(trans.translate(0,movePos*10),false);
|
||||
trans=m_txRightStickOrig;
|
||||
m_txRightStick->setTransform(trans.translate(0,movePos*10),false);
|
||||
}
|
||||
else
|
||||
{
|
||||
trans=m_txLeftStickOrig;
|
||||
m_txLeftStick->setTransform(trans.translate(movePos*10,0),false);
|
||||
trans=m_txRightStickOrig;
|
||||
m_txRightStick->setTransform(trans.translate(movePos*10,0),false);
|
||||
}
|
||||
|
||||
if(movePos==0)
|
||||
{
|
||||
m_txFlightMode->setElementId("flightModeCenter");
|
||||
m_txFlightMode->setTransform(m_txFlightModeCOrig,false);
|
||||
}
|
||||
else if(movePos==ACCESS_MAX_MOVE/2)
|
||||
{
|
||||
m_txFlightMode->setElementId("flightModeRight");
|
||||
m_txFlightMode->setTransform(m_txFlightModeROrig,false);
|
||||
}
|
||||
else if(movePos==ACCESS_MIN_MOVE/2)
|
||||
{
|
||||
m_txFlightMode->setElementId("flightModeLeft");
|
||||
m_txFlightMode->setTransform(m_txFlightModeLOrig,false);
|
||||
}
|
||||
}
|
||||
if(move==horizontal || move==vertical ||move==mix)
|
||||
{
|
||||
if(movePos==0 && growing)
|
||||
auxFlag=!auxFlag;
|
||||
if(growing)
|
||||
++movePos;
|
||||
else
|
||||
--movePos;
|
||||
if(movePos>limitMax)
|
||||
{
|
||||
movePos=movePos-2;
|
||||
growing=false;
|
||||
}
|
||||
if(movePos<limitMin)
|
||||
{
|
||||
movePos=movePos+2;
|
||||
growing=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigInputWidget::moveSticks()
|
||||
{
|
||||
QTransform trans;
|
||||
manualCommandData=manualCommandObj->getData();
|
||||
if(transmitterMode==mode2)
|
||||
{
|
||||
trans=m_txLeftStickOrig;
|
||||
m_txLeftStick->setTransform(trans.translate(manualCommandData.Yaw*STICK_MAX_MOVE*10,-manualCommandData.Throttle*STICK_MAX_MOVE*10),false);
|
||||
trans=m_txRightStickOrig;
|
||||
m_txRightStick->setTransform(trans.translate(manualCommandData.Roll*STICK_MAX_MOVE*10,manualCommandData.Pitch*STICK_MAX_MOVE*10),false);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_config->ch0Cur->setToolTip("Channel neutral point");
|
||||
m_config->ch1Cur->setToolTip("Channel neutral point");
|
||||
m_config->ch2Cur->setToolTip("Channel neutral point");
|
||||
m_config->ch3Cur->setToolTip("Channel neutral point");
|
||||
m_config->ch4Cur->setToolTip("Channel neutral point");
|
||||
m_config->ch5Cur->setToolTip("Channel neutral point");
|
||||
m_config->ch6Cur->setToolTip("Channel neutral point");
|
||||
m_config->ch7Cur->setToolTip("Channel neutral point");
|
||||
trans=m_txRightStickOrig;
|
||||
m_txRightStick->setTransform(trans.translate(manualCommandData.Roll*STICK_MAX_MOVE*10,-manualCommandData.Throttle*STICK_MAX_MOVE*10),false);
|
||||
trans=m_txLeftStickOrig;
|
||||
m_txLeftStick->setTransform(trans.translate(manualCommandData.Yaw*STICK_MAX_MOVE*10,manualCommandData.Pitch*STICK_MAX_MOVE*10),false);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigInputWidget::dimOtherControls(bool value)
|
||||
{
|
||||
qreal opac;
|
||||
if(value)
|
||||
opac=0.1;
|
||||
else
|
||||
opac=1;
|
||||
m_txAccess0->setOpacity(opac);
|
||||
m_txAccess1->setOpacity(opac);
|
||||
m_txAccess2->setOpacity(opac);
|
||||
m_txFlightMode->setOpacity(opac);
|
||||
}
|
||||
|
||||
void ConfigInputWidget::enableControls(bool enable)
|
||||
{
|
||||
m_config->configurationWizard->setEnabled(enable);
|
||||
m_config->runCalibration->setEnabled(enable);
|
||||
|
||||
ConfigTaskWidget::enableControls(enable);
|
||||
|
||||
}
|
||||
|
||||
void ConfigInputWidget::invertControls()
|
||||
{
|
||||
manualSettingsData=manualSettingsObj->getData();
|
||||
foreach(QWidget * wd,extraWidgets)
|
||||
{
|
||||
QCheckBox * cb=qobject_cast<QCheckBox *>(wd);
|
||||
if(cb)
|
||||
{
|
||||
int index=manualSettingsObj->getFields().at(0)->getElementNames().indexOf(cb->text());
|
||||
if((cb->isChecked() && (manualSettingsData.ChannelMax[index]>manualSettingsData.ChannelMin[index])) ||
|
||||
(!cb->isChecked() && (manualSettingsData.ChannelMax[index]<manualSettingsData.ChannelMin[index])))
|
||||
{
|
||||
qint16 aux;
|
||||
aux=manualSettingsData.ChannelMax[index];
|
||||
manualSettingsData.ChannelMax[index]=manualSettingsData.ChannelMin[index];
|
||||
manualSettingsData.ChannelMin[index]=aux;
|
||||
}
|
||||
}
|
||||
}
|
||||
manualSettingsObj->setData(manualSettingsData);
|
||||
}
|
||||
void ConfigInputWidget::moveFMSlider()
|
||||
{
|
||||
ManualControlSettings::DataFields manualSettingsDataPriv = manualSettingsObj->getData();
|
||||
ManualControlCommand::DataFields manualCommandDataPriv=manualCommandObj->getData();
|
||||
|
||||
float valueScaled;
|
||||
int chMin = manualSettingsDataPriv.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE];
|
||||
int chMax = manualSettingsDataPriv.ChannelMax[ManualControlSettings::CHANNELMAX_FLIGHTMODE];
|
||||
int chNeutral = manualSettingsDataPriv.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE];
|
||||
|
||||
int value = manualCommandDataPriv.Channel[ManualControlSettings::CHANNELMIN_FLIGHTMODE];
|
||||
if ((chMax > chMin && value >= chNeutral) || (chMin > chMax && value <= chNeutral))
|
||||
{
|
||||
if (chMax != chNeutral)
|
||||
valueScaled = (float)(value - chNeutral) / (float)(chMax - chNeutral);
|
||||
else
|
||||
valueScaled = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chMin != chNeutral)
|
||||
valueScaled = (float)(value - chNeutral) / (float)(chNeutral - chMin);
|
||||
else
|
||||
valueScaled = 0;
|
||||
}
|
||||
|
||||
if(valueScaled < -(1.0 / 3.0))
|
||||
m_config->fmsSlider->setValue(-100);
|
||||
else if (valueScaled > (1.0/3.0))
|
||||
m_config->fmsSlider->setValue(100);
|
||||
else
|
||||
m_config->fmsSlider->setValue(0);
|
||||
}
|
||||
|
||||
void ConfigInputWidget::updateCalibration()
|
||||
{
|
||||
manualCommandData=manualCommandObj->getData();
|
||||
for(uint i=0;i<ManualControlSettings::CHANNELMAX_NUMELEM;++i)
|
||||
{
|
||||
if((!reverse[i] && manualSettingsData.ChannelMin[i]>manualCommandData.Channel[i]) ||
|
||||
(reverse[i] && manualSettingsData.ChannelMin[i]<manualCommandData.Channel[i]))
|
||||
manualSettingsData.ChannelMin[i]=manualCommandData.Channel[i];
|
||||
if((!reverse[i] && manualSettingsData.ChannelMax[i]<manualCommandData.Channel[i]) ||
|
||||
(reverse[i] && manualSettingsData.ChannelMax[i]>manualCommandData.Channel[i]))
|
||||
manualSettingsData.ChannelMax[i]=manualCommandData.Channel[i];
|
||||
manualSettingsData.ChannelNeutral[i] = manualCommandData.Channel[i];
|
||||
}
|
||||
|
||||
manualSettingsObj->setData(manualSettingsData);
|
||||
manualSettingsObj->updated();
|
||||
}
|
||||
|
||||
void ConfigInputWidget::simpleCalibration(bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
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."));
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setDefaultButton(QMessageBox::Ok);
|
||||
msgBox.exec();
|
||||
|
||||
manualCommandData = manualCommandObj->getData();
|
||||
|
||||
manualSettingsData=manualSettingsObj->getData();
|
||||
manualSettingsData.Arming=ManualControlSettings::ARMING_ALWAYSDISARMED;
|
||||
manualSettingsObj->setData(manualSettingsData);
|
||||
|
||||
for (unsigned int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM; i++) {
|
||||
reverse[i] = manualSettingsData.ChannelMax[i] < manualSettingsData.ChannelMin[i];
|
||||
manualSettingsData.ChannelMin[i] = manualCommandData.Channel[i];
|
||||
manualSettingsData.ChannelNeutral[i] = manualCommandData.Channel[i];
|
||||
manualSettingsData.ChannelMax[i] = manualCommandData.Channel[i];
|
||||
}
|
||||
|
||||
fastMdata();
|
||||
|
||||
connect(manualCommandObj, SIGNAL(objectUnpacked(UAVObject*)), this, SLOT(updateCalibration()));
|
||||
} else {
|
||||
manualCommandData = manualCommandObj->getData();
|
||||
manualSettingsData = manualSettingsObj->getData();
|
||||
|
||||
restoreMdata();
|
||||
|
||||
for (int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM; i++)
|
||||
manualSettingsData.ChannelNeutral[i] = manualCommandData.Channel[i];
|
||||
|
||||
// Force flight mode neutral to middle
|
||||
manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNUMBER_FLIGHTMODE] =
|
||||
(manualSettingsData.ChannelMax[ManualControlSettings::CHANNELNUMBER_FLIGHTMODE] +
|
||||
manualSettingsData.ChannelMin[ManualControlSettings::CHANNELNUMBER_FLIGHTMODE]) / 2;
|
||||
|
||||
// Force throttle to be near min
|
||||
manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_THROTTLE]=
|
||||
manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE]+
|
||||
((manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_THROTTLE]-
|
||||
manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE])*0.02);
|
||||
|
||||
manualSettingsObj->setData(manualSettingsData);
|
||||
|
||||
disconnect(manualCommandObj, SIGNAL(objectUnpacked(UAVObject*)), this, SLOT(updateCalibration()));
|
||||
}
|
||||
}
|
||||
|
@ -34,52 +34,125 @@
|
||||
#include "uavobject.h"
|
||||
#include <QtGui/QWidget>
|
||||
#include <QList>
|
||||
#include "inputchannelform.h"
|
||||
#include "ui_inputchannelform.h"
|
||||
#include <QRadioButton>
|
||||
#include "manualcontrolcommand.h"
|
||||
#include "manualcontrolsettings.h"
|
||||
#include "receiveractivity.h"
|
||||
#include <QGraphicsView>
|
||||
#include <QtSvg/QSvgRenderer>
|
||||
#include <QtSvg/QGraphicsSvgItem>
|
||||
|
||||
class Ui_InputWidget;
|
||||
|
||||
class ConfigInputWidget: public ConfigTaskWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ConfigInputWidget(QWidget *parent = 0);
|
||||
~ConfigInputWidget();
|
||||
|
||||
enum wizardSteps{wizardWelcome,wizardChooseMode,wizardChooseType,wizardIdentifySticks,wizardIdentifyCenter,wizardIdentifyLimits,wizardIdentifyInverted,wizardFinish,wizardNone};
|
||||
enum txMode{mode1,mode2};
|
||||
enum txMovements{moveLeftVerticalStick,moveRightVerticalStick,moveLeftHorizontalStick,moveRightHorizontalStick,moveAccess0,moveAccess1,moveAccess2,moveFlightMode,centerAll,moveAll,nothing};
|
||||
enum txMovementType{vertical,horizontal,jump,mix};
|
||||
enum txType {acro, heli};
|
||||
public slots:
|
||||
|
||||
private:
|
||||
bool growing;
|
||||
bool reverse[ManualControlSettings::CHANNELNEUTRAL_NUMELEM];
|
||||
txMovements currentMovement;
|
||||
int movePos;
|
||||
void setTxMovement(txMovements movement);
|
||||
Ui_InputWidget *m_config;
|
||||
wizardSteps wizardStep;
|
||||
QList<QWidget*> extraWidgets;
|
||||
txMode transmitterMode;
|
||||
txType transmitterType;
|
||||
struct channelsStruct
|
||||
{
|
||||
bool operator ==(const channelsStruct& rhs) const
|
||||
{
|
||||
return((group==rhs.group) &&(number==rhs.number));
|
||||
}
|
||||
int group;
|
||||
int number;
|
||||
}lastChannel;
|
||||
channelsStruct currentChannel;
|
||||
QList<channelsStruct> usedChannels;
|
||||
QEventLoop * loop;
|
||||
bool skipflag;
|
||||
|
||||
QList<QSlider> sliders;
|
||||
int currentChannelNum;
|
||||
QList<int> heliChannelOrder;
|
||||
QList<int> acroChannelOrder;
|
||||
|
||||
void updateChannelInSlider(QSlider *slider, QLabel *min, QLabel *max, int value, bool reversed);
|
||||
ManualControlCommand * manualCommandObj;
|
||||
ManualControlCommand::DataFields manualCommandData;
|
||||
UAVObject::Metadata manualControlMdata;
|
||||
ManualControlSettings * manualSettingsObj;
|
||||
ManualControlSettings::DataFields manualSettingsData;
|
||||
ManualControlSettings::DataFields previousManualSettingsData;
|
||||
ReceiverActivity * receiverActivityObj;
|
||||
ReceiverActivity::DataFields receiverActivityData;
|
||||
|
||||
void assignChannel(UAVDataObject *obj, QString str);
|
||||
void assignOutputChannel(UAVDataObject *obj, QString str);
|
||||
QSvgRenderer *m_renderer;
|
||||
|
||||
int mccDataRate;
|
||||
// Background: background
|
||||
QGraphicsSvgItem *m_txMainBody;
|
||||
QGraphicsSvgItem *m_txLeftStick;
|
||||
QGraphicsSvgItem *m_txRightStick;
|
||||
QGraphicsSvgItem *m_txAccess0;
|
||||
QGraphicsSvgItem *m_txAccess1;
|
||||
QGraphicsSvgItem *m_txAccess2;
|
||||
QGraphicsSvgItem *m_txFlightMode;
|
||||
QGraphicsSvgItem *m_txBackground;
|
||||
QGraphicsSvgItem *m_txArrows;
|
||||
QTransform m_txLeftStickOrig;
|
||||
QTransform m_txRightStickOrig;
|
||||
QTransform m_txAccess0Orig;
|
||||
QTransform m_txAccess1Orig;
|
||||
QTransform m_txAccess2Orig;
|
||||
QTransform m_txFlightModeCOrig;
|
||||
QTransform m_txFlightModeLOrig;
|
||||
QTransform m_txFlightModeROrig;
|
||||
QTransform m_txMainBodyOrig;
|
||||
QTransform m_txArrowsOrig;
|
||||
QTimer * animate;
|
||||
void resetTxControls();
|
||||
void setMoveFromCommand(int command);
|
||||
|
||||
UAVObject::Metadata accInitialData;
|
||||
void fastMdata();
|
||||
void restoreMdata();
|
||||
|
||||
QList<QSlider*> inSliders;
|
||||
QList<QLabel*> inMaxLabels;
|
||||
QList<QLabel*> inMinLabels;
|
||||
QList<QLabel*> inNeuLabels;
|
||||
QList<QCheckBox*> inRevCheckboxes;
|
||||
QList<QComboBox*> inChannelAssign;
|
||||
void setChannel(int);
|
||||
void nextChannel();
|
||||
void prevChannel();
|
||||
|
||||
bool firstUpdate;
|
||||
|
||||
virtual void enableControls(bool enable);
|
||||
void receiverHelp();
|
||||
void wizardSetUpStep(enum wizardSteps);
|
||||
void wizardTearDownStep(enum wizardSteps);
|
||||
private slots:
|
||||
void updateChannels(UAVObject* obj);
|
||||
virtual void refreshValues();
|
||||
void sendRCInputUpdate();
|
||||
void saveRCInputObject();
|
||||
void reverseCheckboxClicked(bool state);
|
||||
void wzNext();
|
||||
void wzBack();
|
||||
void wzCancel();
|
||||
void goToWizard();
|
||||
|
||||
void openHelp();
|
||||
void updateTips(int);
|
||||
void identifyControls();
|
||||
void identifyLimits();
|
||||
void moveTxControls();
|
||||
void moveSticks();
|
||||
void dimOtherControls(bool value);
|
||||
void moveFMSlider();
|
||||
void invertControls();
|
||||
void simpleCalibration(bool state);
|
||||
void updateCalibration();
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
virtual void enableControls(bool enable);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -45,7 +45,8 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren
|
||||
m_config->setupUi(this);
|
||||
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
|
||||
setupButtons(m_config->saveRCOutputToRAM,m_config->saveRCOutputToSD);
|
||||
addUAVObject("ActuatorSettings");
|
||||
|
||||
// First of all, put all the channel widgets into lists, so that we can
|
||||
// manipulate those:
|
||||
@ -106,10 +107,7 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren
|
||||
<< m_config->ch7Link;
|
||||
|
||||
// Register for ActuatorSettings changes:
|
||||
UAVDataObject * obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ActuatorSettings")));
|
||||
connect(obj,SIGNAL(objectUpdated(UAVObject*)),this,SLOT(refreshValues()));
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int i = 0; i < 8; 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)));
|
||||
@ -124,13 +122,8 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren
|
||||
for (int i = 0; i < links.count(); i++)
|
||||
connect(links[i], SIGNAL(toggled(bool)), this, SLOT(linkToggled(bool)));
|
||||
|
||||
connect(m_config->saveRCOutputToSD, SIGNAL(clicked()), this, SLOT(saveRCOutputObject()));
|
||||
connect(m_config->saveRCOutputToRAM, SIGNAL(clicked()), this, SLOT(sendRCOutputUpdate()));
|
||||
|
||||
enableControls(false);
|
||||
refreshValues();
|
||||
connect(parent, SIGNAL(autopilotConnected()),this, SLOT(onAutopilotConnect()));
|
||||
connect(parent, SIGNAL(autopilotDisconnected()), this, SLOT(onAutopilotDisconnect()));
|
||||
refreshWidgetsValues();
|
||||
|
||||
firstUpdate = true;
|
||||
|
||||
@ -138,6 +131,43 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren
|
||||
|
||||
// Connect the help button
|
||||
connect(m_config->outputHelp, SIGNAL(clicked()), this, SLOT(openHelp()));
|
||||
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);
|
||||
}
|
||||
|
||||
ConfigOutputWidget::~ConfigOutputWidget()
|
||||
@ -146,14 +176,6 @@ ConfigOutputWidget::~ConfigOutputWidget()
|
||||
}
|
||||
|
||||
|
||||
// ************************************
|
||||
|
||||
void ConfigOutputWidget::enableControls(bool enable)
|
||||
{
|
||||
m_config->saveRCOutputToSD->setEnabled(enable);
|
||||
//m_config->saveRCOutputToRAM->setEnabled(enable);
|
||||
}
|
||||
|
||||
// ************************************
|
||||
|
||||
/**
|
||||
@ -355,8 +377,9 @@ void ConfigOutputWidget::sendChannelTest(int value)
|
||||
/**
|
||||
Request the current config from the board (RC Output)
|
||||
*/
|
||||
void ConfigOutputWidget::refreshValues()
|
||||
void ConfigOutputWidget::refreshWidgetsValues()
|
||||
{
|
||||
bool dirty=isDirty();
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
|
||||
|
||||
@ -444,14 +467,14 @@ void ConfigOutputWidget::refreshValues()
|
||||
outSliders[i]->setValue(value);
|
||||
outLabels[i]->setText(QString::number(value));
|
||||
}
|
||||
|
||||
setDirty(dirty);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the config to the board, without saving to the SD card (RC Output)
|
||||
*/
|
||||
void ConfigOutputWidget::sendRCOutputUpdate()
|
||||
void ConfigOutputWidget::updateObjectsFromWidgets()
|
||||
{
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
|
||||
@ -479,27 +502,8 @@ void ConfigOutputWidget::sendRCOutputUpdate()
|
||||
field->setValue(m_config->outputRate2->value(),1);
|
||||
field->setValue(m_config->outputRate3->value(),2);
|
||||
field->setValue(m_config->outputRate4->value(),3);
|
||||
|
||||
// ... and send to the OP Board
|
||||
obj->updated();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Sends the config to the board and request saving into the SD card (RC Output)
|
||||
*/
|
||||
void ConfigOutputWidget::saveRCOutputObject()
|
||||
{
|
||||
// Send update so that the latest value is saved
|
||||
sendRCOutputUpdate();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
saveObjectToSD(obj);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Sets the minimum/maximum value of the channel 0 to seven output sliders.
|
||||
Have to do it here because setMinimum is not a slot.
|
||||
|
@ -69,12 +69,10 @@ private:
|
||||
|
||||
bool firstUpdate;
|
||||
|
||||
virtual void enableControls(bool enable);
|
||||
|
||||
private slots:
|
||||
virtual void refreshValues();
|
||||
void sendRCOutputUpdate();
|
||||
void saveRCOutputObject();
|
||||
virtual void refreshWidgetsValues();
|
||||
void updateObjectsFromWidgets();
|
||||
void runChannelTests(bool state);
|
||||
void sendChannelTest(int value);
|
||||
void setChOutRange();
|
||||
|
@ -43,21 +43,15 @@ ConfigStabilizationWidget::ConfigStabilizationWidget(QWidget *parent) : ConfigTa
|
||||
m_stabilization->setupUi(this);
|
||||
|
||||
|
||||
connect(m_stabilization->saveStabilizationToSD, SIGNAL(clicked()), this, SLOT(saveStabilizationUpdate()));
|
||||
connect(m_stabilization->saveStabilizationToRAM, SIGNAL(clicked()), this, SLOT(sendStabilizationUpdate()));
|
||||
setupButtons(m_stabilization->saveStabilizationToRAM,m_stabilization->saveStabilizationToSD);
|
||||
|
||||
enableControls(false);
|
||||
refreshValues();
|
||||
connect(parent, SIGNAL(autopilotConnected()),this, SLOT(onAutopilotConnect()));
|
||||
connect(parent, SIGNAL(autopilotDisconnected()),this, SLOT(onAutopilotDisconnect()));
|
||||
addUAVObject("StabilizationSettings");
|
||||
|
||||
// Now connect the widget to the StabilizationSettings object
|
||||
UAVObject *obj = getObjectManager()->getObject(QString("StabilizationSettings"));
|
||||
connect(obj,SIGNAL(objectUpdated(UAVObject*)),this,SLOT(refreshValues()));
|
||||
refreshWidgetsValues();
|
||||
|
||||
// Create a timer to regularly send the object update in case
|
||||
// we want realtime updates.
|
||||
connect(&updateTimer, SIGNAL(timeout()), this, SLOT(sendStabilizationUpdate()));
|
||||
connect(&updateTimer, SIGNAL(timeout()), this, SLOT(updateObjectsFromWidgets()));
|
||||
connect(m_stabilization->realTimeUpdates, SIGNAL(toggled(bool)), this, SLOT(realtimeUpdateToggle(bool)));
|
||||
|
||||
// Connect the updates of the stab values
|
||||
@ -79,6 +73,35 @@ ConfigStabilizationWidget::ConfigStabilizationWidget(QWidget *parent) : ConfigTa
|
||||
|
||||
// Connect the help button
|
||||
connect(m_stabilization->stabilizationHelp, SIGNAL(clicked()), this, SLOT(openHelp()));
|
||||
addWidget(m_stabilization->rateRollKp);
|
||||
addWidget(m_stabilization->rateRollKi);
|
||||
addWidget(m_stabilization->rateRollILimit);
|
||||
addWidget(m_stabilization->ratePitchKp);
|
||||
addWidget(m_stabilization->ratePitchKi);
|
||||
addWidget(m_stabilization->ratePitchILimit);
|
||||
addWidget(m_stabilization->rateYawKp);
|
||||
addWidget(m_stabilization->rateYawKi);
|
||||
addWidget(m_stabilization->rateYawILimit);
|
||||
addWidget(m_stabilization->rollKp);
|
||||
addWidget(m_stabilization->rollKi);
|
||||
addWidget(m_stabilization->rollILimit);
|
||||
addWidget(m_stabilization->yawILimit);
|
||||
addWidget(m_stabilization->yawKi);
|
||||
addWidget(m_stabilization->yawKp);
|
||||
addWidget(m_stabilization->pitchKp);
|
||||
addWidget(m_stabilization->pitchKi);
|
||||
addWidget(m_stabilization->pitchILimit);
|
||||
addWidget(m_stabilization->rollMax);
|
||||
addWidget(m_stabilization->pitchMax);
|
||||
addWidget(m_stabilization->yawMax);
|
||||
addWidget(m_stabilization->manualRoll);
|
||||
addWidget(m_stabilization->manualPitch);
|
||||
addWidget(m_stabilization->manualYaw);
|
||||
addWidget(m_stabilization->maximumRoll);
|
||||
addWidget(m_stabilization->maximumPitch);
|
||||
addWidget(m_stabilization->maximumYaw);
|
||||
addWidget(m_stabilization->lowThrottleZeroIntegral);
|
||||
|
||||
}
|
||||
|
||||
ConfigStabilizationWidget::~ConfigStabilizationWidget()
|
||||
@ -86,13 +109,6 @@ ConfigStabilizationWidget::~ConfigStabilizationWidget()
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
|
||||
void ConfigStabilizationWidget::enableControls(bool enable)
|
||||
{
|
||||
//m_stabilization->saveStabilizationToRAM->setEnabled(enable);
|
||||
m_stabilization->saveStabilizationToSD->setEnabled(enable);
|
||||
}
|
||||
|
||||
void ConfigStabilizationWidget::updateRateRollKP(double val)
|
||||
{
|
||||
if (m_stabilization->linkRateRP->isChecked()) {
|
||||
@ -187,8 +203,9 @@ void ConfigStabilizationWidget::updatePitchILimit(double val)
|
||||
/**
|
||||
Request stabilization settings from the board
|
||||
*/
|
||||
void ConfigStabilizationWidget::refreshValues()
|
||||
void ConfigStabilizationWidget::refreshWidgetsValues()
|
||||
{
|
||||
bool dirty=isDirty();
|
||||
// Not needed anymore as this slot is only called whenever we get
|
||||
// a signal that the object was just updated
|
||||
// stabSettings->requestUpdate();
|
||||
@ -229,9 +246,9 @@ void ConfigStabilizationWidget::refreshValues()
|
||||
m_stabilization->maximumRoll->setValue(stabData.MaximumRate[StabilizationSettings::MAXIMUMRATE_ROLL]);
|
||||
m_stabilization->maximumPitch->setValue(stabData.MaximumRate[StabilizationSettings::MAXIMUMRATE_PITCH]);
|
||||
m_stabilization->maximumYaw->setValue(stabData.MaximumRate[StabilizationSettings::MAXIMUMRATE_YAW]);
|
||||
m_stabilization->lowThrottleZeroIntegral->setChecked(stabData.LowThrottleZeroIntegral==StabilizationSettings::LOWTHROTTLEZEROINTEGRAL_TRUE ? true : false);
|
||||
|
||||
m_stabilization->lowThrottleZeroIntegral->setChecked(
|
||||
stabData.LowThrottleZeroIntegral == StabilizationSettings::LOWTHROTTLEZEROINTEGRAL_TRUE);
|
||||
setDirty(dirty);
|
||||
}
|
||||
|
||||
|
||||
@ -239,7 +256,7 @@ void ConfigStabilizationWidget::refreshValues()
|
||||
Send telemetry settings to the board
|
||||
*/
|
||||
|
||||
void ConfigStabilizationWidget::sendStabilizationUpdate()
|
||||
void ConfigStabilizationWidget::updateObjectsFromWidgets()
|
||||
{
|
||||
StabilizationSettings::DataFields stabData = stabSettings->getData();
|
||||
|
||||
@ -279,28 +296,12 @@ void ConfigStabilizationWidget::sendStabilizationUpdate()
|
||||
stabData.MaximumRate[StabilizationSettings::MAXIMUMRATE_PITCH] = m_stabilization->maximumPitch->value();
|
||||
stabData.MaximumRate[StabilizationSettings::MAXIMUMRATE_YAW] = m_stabilization->maximumYaw->value();
|
||||
|
||||
stabData.LowThrottleZeroIntegral = m_stabilization->lowThrottleZeroIntegral->isChecked() ?
|
||||
StabilizationSettings::LOWTHROTTLEZEROINTEGRAL_TRUE :
|
||||
StabilizationSettings::LOWTHROTTLEZEROINTEGRAL_FALSE;
|
||||
stabData.LowThrottleZeroIntegral = (m_stabilization->lowThrottleZeroIntegral->isChecked() ? StabilizationSettings::LOWTHROTTLEZEROINTEGRAL_TRUE :StabilizationSettings::LOWTHROTTLEZEROINTEGRAL_FALSE);
|
||||
|
||||
|
||||
stabSettings->setData(stabData); // this is atomic
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Send telemetry settings to the board and request saving to SD card
|
||||
*/
|
||||
|
||||
void ConfigStabilizationWidget::saveStabilizationUpdate()
|
||||
{
|
||||
// Send update so that the latest value is saved
|
||||
sendStabilizationUpdate();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("StabilizationSettings")));
|
||||
Q_ASSERT(obj);
|
||||
saveObjectToSD(obj);
|
||||
}
|
||||
|
||||
|
||||
void ConfigStabilizationWidget::realtimeUpdateToggle(bool state)
|
||||
{
|
||||
if (state) {
|
||||
|
@ -49,12 +49,10 @@ private:
|
||||
Ui_StabilizationWidget *m_stabilization;
|
||||
StabilizationSettings* stabSettings;
|
||||
QTimer updateTimer;
|
||||
virtual void enableControls(bool enable);
|
||||
|
||||
private slots:
|
||||
virtual void refreshValues();
|
||||
void sendStabilizationUpdate();
|
||||
void saveStabilizationUpdate();
|
||||
virtual void refreshWidgetsValues();
|
||||
void updateObjectsFromWidgets();
|
||||
void realtimeUpdateToggle(bool);
|
||||
void openHelp();
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include <QtGui/QWidget>
|
||||
|
||||
|
||||
ConfigTaskWidget::ConfigTaskWidget(QWidget *parent) : QWidget(parent),smartsave(NULL),dirty(false)
|
||||
ConfigTaskWidget::ConfigTaskWidget(QWidget *parent) : QWidget(parent),isConnected(false),smartsave(NULL),dirty(false)
|
||||
{
|
||||
pm = ExtensionSystem::PluginManager::instance();
|
||||
objManager = pm->getObject<UAVObjectManager>();
|
||||
@ -43,13 +43,27 @@ void ConfigTaskWidget::addUAVObject(QString objectName)
|
||||
{
|
||||
addUAVObjectToWidgetRelation(objectName,"",NULL);
|
||||
}
|
||||
void ConfigTaskWidget::addUAVObjectToWidgetRelation(QString object, QString field, QWidget * widget)
|
||||
void ConfigTaskWidget::addUAVObjectToWidgetRelation(QString object, QString field, QWidget * widget, QString index)
|
||||
{
|
||||
UAVObject *obj=NULL;
|
||||
UAVObjectField *_field=NULL;
|
||||
obj = objManager->getObject(QString(object));
|
||||
Q_ASSERT(obj);
|
||||
_field = obj->getField(QString(field));
|
||||
Q_ASSERT(_field);
|
||||
addUAVObjectToWidgetRelation(object,field,widget,_field->getElementNames().indexOf(index));
|
||||
}
|
||||
|
||||
void ConfigTaskWidget::addUAVObjectToWidgetRelation(QString object, QString field, QWidget * widget, int index,int scale)
|
||||
{
|
||||
UAVObject *obj=NULL;
|
||||
UAVObjectField *_field=NULL;
|
||||
if(!object.isEmpty())
|
||||
{
|
||||
obj = objManager->getObject(QString(object));
|
||||
connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshWidgetsValues()));
|
||||
Q_ASSERT(obj);
|
||||
connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshWidgetsValues()));
|
||||
}
|
||||
//smartsave->addObject(obj);
|
||||
if(!field.isEmpty() && obj)
|
||||
_field = obj->getField(QString(field));
|
||||
@ -57,9 +71,11 @@ void ConfigTaskWidget::addUAVObjectToWidgetRelation(QString object, QString fiel
|
||||
ow->field=_field;
|
||||
ow->object=obj;
|
||||
ow->widget=widget;
|
||||
ow->index=index;
|
||||
ow->scale=scale;
|
||||
objOfInterest.append(ow);
|
||||
if(obj)
|
||||
smartsave->addObject(obj);
|
||||
smartsave->addObject((UAVDataObject*)obj);
|
||||
if(widget==NULL)
|
||||
{
|
||||
// do nothing
|
||||
@ -88,6 +104,15 @@ void ConfigTaskWidget::addUAVObjectToWidgetRelation(QString object, QString fiel
|
||||
{
|
||||
connect(cb,SIGNAL(valueChanged(double)),this,SLOT(widgetsContentsChanged()));
|
||||
}
|
||||
else if(QCheckBox * cb=qobject_cast<QCheckBox *>(widget))
|
||||
{
|
||||
connect(cb,SIGNAL(clicked()),this,SLOT(widgetsContentsChanged()));
|
||||
}
|
||||
else if(QPushButton * cb=qobject_cast<QPushButton *>(widget))
|
||||
{
|
||||
connect(cb,SIGNAL(clicked()),this,SLOT(widgetsContentsChanged()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -126,17 +151,21 @@ double ConfigTaskWidget::listMean(QList<double> list)
|
||||
|
||||
void ConfigTaskWidget::onAutopilotDisconnect()
|
||||
{
|
||||
enableControls(false);
|
||||
isConnected=false;
|
||||
enableControls(false);
|
||||
}
|
||||
|
||||
void ConfigTaskWidget::onAutopilotConnect()
|
||||
{
|
||||
enableControls(true);
|
||||
refreshWidgetsValues();
|
||||
dirty=false;
|
||||
isConnected=true;
|
||||
enableControls(true);
|
||||
refreshWidgetsValues();
|
||||
}
|
||||
|
||||
void ConfigTaskWidget::populateWidgets()
|
||||
{
|
||||
bool dirtyBack=dirty;
|
||||
foreach(objectToWidget * ow,objOfInterest)
|
||||
{
|
||||
if(ow->object==NULL || ow->field==NULL)
|
||||
@ -146,18 +175,27 @@ void ConfigTaskWidget::populateWidgets()
|
||||
else if(QComboBox * cb=qobject_cast<QComboBox *>(ow->widget))
|
||||
{
|
||||
cb->addItems(ow->field->getOptions());
|
||||
cb->setCurrentIndex(cb->findText(ow->field->getValue().toString()));
|
||||
cb->setCurrentIndex(cb->findText(ow->field->getValue(ow->index).toString()));
|
||||
}
|
||||
else if(QLabel * cb=qobject_cast<QLabel *>(ow->widget))
|
||||
{
|
||||
cb->setText(ow->field->getValue().toString());
|
||||
cb->setText(ow->field->getValue(ow->index).toString());
|
||||
}
|
||||
else if(QSpinBox * cb=qobject_cast<QSpinBox *>(ow->widget))
|
||||
{
|
||||
cb->setValue(ow->field->getValue(ow->index).toInt()/ow->scale);
|
||||
}
|
||||
else if(QSlider * cb=qobject_cast<QSlider *>(ow->widget))
|
||||
{
|
||||
cb->setValue(ow->field->getValue(ow->index).toInt()/ow->scale);
|
||||
}
|
||||
}
|
||||
dirty=false;
|
||||
setDirty(dirtyBack);
|
||||
}
|
||||
|
||||
void ConfigTaskWidget::refreshWidgetsValues()
|
||||
{
|
||||
bool dirtyBack=dirty;
|
||||
foreach(objectToWidget * ow,objOfInterest)
|
||||
{
|
||||
if(ow->object==NULL || ow->field==NULL)
|
||||
@ -166,13 +204,22 @@ void ConfigTaskWidget::refreshWidgetsValues()
|
||||
}
|
||||
else if(QComboBox * cb=qobject_cast<QComboBox *>(ow->widget))
|
||||
{
|
||||
cb->setCurrentIndex(cb->findText(ow->field->getValue().toString()));
|
||||
cb->setCurrentIndex(cb->findText(ow->field->getValue(ow->index).toString()));
|
||||
}
|
||||
else if(QLabel * cb=qobject_cast<QLabel *>(ow->widget))
|
||||
{
|
||||
cb->setText(ow->field->getValue().toString());
|
||||
cb->setText(ow->field->getValue(ow->index).toString());
|
||||
}
|
||||
else if(QSpinBox * cb=qobject_cast<QSpinBox *>(ow->widget))
|
||||
{
|
||||
cb->setValue(ow->field->getValue(ow->index).toInt()/ow->scale);
|
||||
}
|
||||
else if(QSlider * cb=qobject_cast<QSlider *>(ow->widget))
|
||||
{
|
||||
cb->setValue(ow->field->getValue(ow->index).toInt()/ow->scale);
|
||||
}
|
||||
}
|
||||
setDirty(dirtyBack);
|
||||
}
|
||||
|
||||
void ConfigTaskWidget::updateObjectsFromWidgets()
|
||||
@ -185,11 +232,19 @@ void ConfigTaskWidget::updateObjectsFromWidgets()
|
||||
}
|
||||
else if(QComboBox * cb=qobject_cast<QComboBox *>(ow->widget))
|
||||
{
|
||||
ow->field->setValue(cb->currentText());
|
||||
ow->field->setValue(cb->currentText(),ow->index);
|
||||
}
|
||||
else if(QLabel * cb=qobject_cast<QLabel *>(ow->widget))
|
||||
{
|
||||
ow->field->setValue(cb->text());
|
||||
ow->field->setValue(cb->text(),ow->index);
|
||||
}
|
||||
else if(QSpinBox * cb=qobject_cast<QSpinBox *>(ow->widget))
|
||||
{
|
||||
ow->field->setValue(cb->value()* ow->scale,ow->index);
|
||||
}
|
||||
else if(QSlider * cb=qobject_cast<QSlider *>(ow->widget))
|
||||
{
|
||||
ow->field->setValue(cb->value()* ow->scale,ow->index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -197,10 +252,11 @@ void ConfigTaskWidget::updateObjectsFromWidgets()
|
||||
void ConfigTaskWidget::setupButtons(QPushButton *update, QPushButton *save)
|
||||
{
|
||||
smartsave=new smartSaveButton(update,save);
|
||||
connect(smartsave, SIGNAL(preProcessOperations()), this, SLOT(updateObjectsFromWidgets()));
|
||||
connect(smartsave,SIGNAL(preProcessOperations()), this, SLOT(updateObjectsFromWidgets()));
|
||||
connect(smartsave,SIGNAL(saveSuccessfull()),this,SLOT(clearDirty()));
|
||||
connect(smartsave,SIGNAL(beginOp()),this,SLOT(disableObjUpdates()));
|
||||
connect(smartsave,SIGNAL(endOp()),this,SLOT(enableObjUpdates()));
|
||||
enableControls(false);
|
||||
}
|
||||
|
||||
void ConfigTaskWidget::enableControls(bool enable)
|
||||
@ -211,17 +267,23 @@ void ConfigTaskWidget::enableControls(bool enable)
|
||||
|
||||
void ConfigTaskWidget::widgetsContentsChanged()
|
||||
{
|
||||
dirty=true;
|
||||
setDirty(true);
|
||||
}
|
||||
|
||||
void ConfigTaskWidget::clearDirty()
|
||||
{
|
||||
dirty=false;
|
||||
setDirty(false);
|
||||
}
|
||||
void ConfigTaskWidget::setDirty(bool value)
|
||||
{
|
||||
dirty=value;
|
||||
}
|
||||
|
||||
bool ConfigTaskWidget::isDirty()
|
||||
{
|
||||
return dirty;
|
||||
if(isConnected)
|
||||
return dirty;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConfigTaskWidget::refreshValues()
|
||||
|
@ -41,6 +41,9 @@
|
||||
#include <QTableWidget>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QSpinBox>
|
||||
#include <QCheckBox>
|
||||
#include <QPushButton>
|
||||
|
||||
class ConfigTaskWidget: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -51,6 +54,8 @@ public:
|
||||
UAVObject * object;
|
||||
UAVObjectField * field;
|
||||
QWidget * widget;
|
||||
int index;
|
||||
int scale;
|
||||
};
|
||||
|
||||
ConfigTaskWidget(QWidget *parent = 0);
|
||||
@ -60,9 +65,12 @@ public:
|
||||
static double listMean(QList<double> list);
|
||||
void addUAVObject(QString objectName);
|
||||
void addWidget(QWidget * widget);
|
||||
void addUAVObjectToWidgetRelation(QString object,QString field,QWidget * widget);
|
||||
void addUAVObjectToWidgetRelation(QString object,QString field,QWidget * widget,int index=0,int scale=1);
|
||||
|
||||
void setupButtons(QPushButton * update,QPushButton * save);
|
||||
bool isDirty();
|
||||
void setDirty(bool value);
|
||||
void addUAVObjectToWidgetRelation(QString object, QString field, QWidget *widget, QString index);
|
||||
public slots:
|
||||
void onAutopilotDisconnect();
|
||||
void onAutopilotConnect();
|
||||
@ -71,6 +79,8 @@ private slots:
|
||||
virtual void refreshValues();
|
||||
virtual void updateObjectsFromWidgets();
|
||||
private:
|
||||
bool isConnected;
|
||||
QStringList objectsList;
|
||||
QList <objectToWidget*> objOfInterest;
|
||||
ExtensionSystem::PluginManager *pm;
|
||||
UAVObjectManager *objManager;
|
||||
|
@ -284,6 +284,10 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const
|
||||
}
|
||||
|
||||
void FancyTabBar::setCurrentIndex(int index) {
|
||||
bool proceed=true;
|
||||
emit aboutToChange(&proceed);
|
||||
if(!proceed)
|
||||
return;
|
||||
m_currentIndex = index;
|
||||
update();
|
||||
emit currentChanged(index);
|
||||
@ -319,7 +323,6 @@ FancyTabWidget::FancyTabWidget(QWidget *parent, bool isVertical)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_tabBar = new FancyTabBar(this, isVertical);
|
||||
|
||||
m_selectionWidget = new QWidget(this);
|
||||
QBoxLayout *selectionLayout;
|
||||
if (isVertical) {
|
||||
@ -477,3 +480,7 @@ void FancyTabWidget::setTabToolTip(int index, const QString &toolTip)
|
||||
{
|
||||
m_tabBar->setTabToolTip(index, toolTip);
|
||||
}
|
||||
QWidget * FancyTabWidget::currentWidget()
|
||||
{
|
||||
return m_modesStack->currentWidget();
|
||||
}
|
||||
|
@ -91,6 +91,7 @@ public:
|
||||
|
||||
signals:
|
||||
void currentChanged(int);
|
||||
void aboutToChange(bool *);
|
||||
|
||||
public slots:
|
||||
void updateHover();
|
||||
@ -116,7 +117,7 @@ class FancyTabWidget : public QWidget
|
||||
|
||||
public:
|
||||
FancyTabWidget(QWidget *parent = 0, bool isVertical = false);
|
||||
|
||||
FancyTabBar *m_tabBar;
|
||||
void insertTab(int index, QWidget *tab, const QIcon &icon, const QString &label);
|
||||
void removeTab(int index);
|
||||
void setBackgroundBrush(const QBrush &brush);
|
||||
@ -132,6 +133,7 @@ public:
|
||||
int currentIndex() const;
|
||||
QStatusBar *statusBar() const;
|
||||
|
||||
QWidget * currentWidget();
|
||||
signals:
|
||||
void currentAboutToShow(int index);
|
||||
void currentChanged(int index);
|
||||
@ -143,7 +145,6 @@ private slots:
|
||||
void showWidget(int index);
|
||||
|
||||
private:
|
||||
FancyTabBar *m_tabBar;
|
||||
QWidget *m_cornerWidgetContainer;
|
||||
QStackedLayout *m_modesStack;
|
||||
QWidget *m_selectionWidget;
|
||||
|
571
ground/openpilotgcs/src/plugins/config/images/TX.svg
Normal file
571
ground/openpilotgcs/src/plugins/config/images/TX.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 31 KiB |
@ -25,770 +25,105 @@
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Receiver Type:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="RCInputConnected">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>234</width>
|
||||
<height>54</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Indicates whether OpenPilot is getting a signal from the RC receiver.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>RC Receiver not connected or invalid input configuration (missing channels)</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="9">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Rev.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QComboBox" name="ch0Assign">
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frame">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5" colspan="3">
|
||||
<widget class="QSlider" name="inSlider0">
|
||||
<property name="mouseTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>2000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1500</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="8">
|
||||
<widget class="QLabel" name="ch0Max">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Maximum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>2000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="9">
|
||||
<widget class="QCheckBox" name="ch0Rev">
|
||||
<property name="toolTip">
|
||||
<string>Check this to reverse the channel.
|
||||
(Useful for transmitters without channel
|
||||
reversal capabilities).</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QComboBox" name="ch1Assign"/>
|
||||
</item>
|
||||
<item row="2" column="5" colspan="3">
|
||||
<widget class="QSlider" name="inSlider1">
|
||||
<property name="mouseTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>2000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1500</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="8">
|
||||
<widget class="QLabel" name="ch1Max">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Maximum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>2000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="9">
|
||||
<widget class="QCheckBox" name="ch1Rev">
|
||||
<property name="toolTip">
|
||||
<string>Check this to reverse the channel.
|
||||
(Useful for transmitters without channel
|
||||
reversal capabilities).</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QComboBox" name="ch2Assign"/>
|
||||
</item>
|
||||
<item row="3" column="5" colspan="3">
|
||||
<widget class="QSlider" name="inSlider2">
|
||||
<property name="mouseTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>2000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1500</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="8">
|
||||
<widget class="QLabel" name="ch2Max">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Maximum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>2000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="9">
|
||||
<widget class="QCheckBox" name="ch2Rev">
|
||||
<property name="toolTip">
|
||||
<string>Check this to reverse the channel.
|
||||
(Useful for transmitters without channel
|
||||
reversal capabilities).</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QComboBox" name="ch3Assign"/>
|
||||
</item>
|
||||
<item row="4" column="5" colspan="3">
|
||||
<widget class="QSlider" name="inSlider3">
|
||||
<property name="mouseTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>2000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1500</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="8">
|
||||
<widget class="QLabel" name="ch3Max">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Maximum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>2000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="9">
|
||||
<widget class="QCheckBox" name="ch3Rev">
|
||||
<property name="toolTip">
|
||||
<string>Check this to reverse the channel.
|
||||
(Useful for transmitters without channel
|
||||
reversal capabilities).</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QComboBox" name="ch4Assign"/>
|
||||
</item>
|
||||
<item row="5" column="5" colspan="3">
|
||||
<widget class="QSlider" name="inSlider4">
|
||||
<property name="mouseTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>2000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1500</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="8">
|
||||
<widget class="QLabel" name="ch4Max">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Maximum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>2000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="9">
|
||||
<widget class="QCheckBox" name="ch4Rev">
|
||||
<property name="toolTip">
|
||||
<string>Check this to reverse the channel.
|
||||
(Useful for transmitters without channel
|
||||
reversal capabilities).</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QComboBox" name="ch5Assign"/>
|
||||
</item>
|
||||
<item row="6" column="5" colspan="3">
|
||||
<widget class="QSlider" name="inSlider5">
|
||||
<property name="mouseTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>2000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1500</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="8">
|
||||
<widget class="QLabel" name="ch5Max">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Maximum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>2000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="9">
|
||||
<widget class="QCheckBox" name="ch5Rev">
|
||||
<property name="toolTip">
|
||||
<string>Check this to reverse the channel.
|
||||
(Useful for transmitters without channel
|
||||
reversal capabilities).</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QComboBox" name="ch6Assign"/>
|
||||
</item>
|
||||
<item row="7" column="5" colspan="3">
|
||||
<widget class="QSlider" name="inSlider6">
|
||||
<property name="mouseTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>2000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1500</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="8">
|
||||
<widget class="QLabel" name="ch6Max">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Maximum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>2000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="9">
|
||||
<widget class="QCheckBox" name="ch6Rev">
|
||||
<property name="toolTip">
|
||||
<string>Check this to reverse the channel.
|
||||
(Useful for transmitters without channel
|
||||
reversal capabilities).</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QComboBox" name="ch7Assign"/>
|
||||
</item>
|
||||
<item row="8" column="5" colspan="3">
|
||||
<widget class="QSlider" name="inSlider7">
|
||||
<property name="mouseTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>2000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1500</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="8">
|
||||
<widget class="QLabel" name="ch7Max">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Maximum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>2000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="9">
|
||||
<widget class="QCheckBox" name="ch7Rev">
|
||||
<property name="toolTip">
|
||||
<string>Check this to reverse the channel.
|
||||
(Useful for transmitters without channel
|
||||
reversal capabilities).</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0" colspan="10">
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>BEWARE: make sure your engines are not connected when running calibration!
|
||||
</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0" colspan="10">
|
||||
<widget class="QLabel" name="lblMissingInputs">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QCheckBox" name="doRCInputCalibration">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Start calibrating the RC Inputs.
|
||||
Uncheck/Check to restart calibration.
|
||||
During calibration: move your RC controls over their whole range,
|
||||
then leave them on Neutral, uncheck calibration and save.
|
||||
Neutral should be put at the bottom of the slider for the throttle.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Run Calibration</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="receiverType">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QLabel" name="ch0Min">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Minimum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QLabel" name="ch1Min">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Minimum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QLabel" name="ch2Min">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Minimum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="4">
|
||||
<widget class="QLabel" name="ch3Min">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Minimum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="4">
|
||||
<widget class="QLabel" name="ch4Min">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Minimum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="4">
|
||||
<widget class="QLabel" name="ch5Min">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Minimum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="4">
|
||||
<widget class="QLabel" name="ch6Min">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Minimum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="4">
|
||||
<widget class="QLabel" name="ch7Min">
|
||||
<property name="toolTip">
|
||||
<string><!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;">Minimum channel pulse width</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="ch0Cur">
|
||||
<property name="toolTip">
|
||||
<string><!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:10pt; 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;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1500</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="ch1Cur">
|
||||
<property name="toolTip">
|
||||
<string><!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:10pt; 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;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1500</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLabel" name="ch2Cur">
|
||||
<property name="toolTip">
|
||||
<string><!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:10pt; 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;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1500</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QLabel" name="ch3Cur">
|
||||
<property name="toolTip">
|
||||
<string><!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:10pt; 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;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1500</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QLabel" name="ch4Cur">
|
||||
<property name="toolTip">
|
||||
<string><!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:10pt; 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;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1500</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="2">
|
||||
<widget class="QLabel" name="ch5Cur">
|
||||
<property name="toolTip">
|
||||
<string><!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:10pt; 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;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1500</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="2">
|
||||
<widget class="QLabel" name="ch6Cur">
|
||||
<property name="toolTip">
|
||||
<string><!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:10pt; 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;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1500</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="2">
|
||||
<widget class="QLabel" name="ch7Cur">
|
||||
<property name="toolTip">
|
||||
<string><!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:10pt; 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;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1500</string>
|
||||
</property>
|
||||
<widget class="QStackedWidget" name="stackedWidget">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="advancedPage">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="channelSettings"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="configurationWizard">
|
||||
<property name="text">
|
||||
<string>Start Configuration Wizard</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="runCalibration">
|
||||
<property name="text">
|
||||
<string>Run Calibration</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="wizard">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="wzText">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>70</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QGraphicsView" name="graphicsView"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="checkBoxesLayout"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="wzBack">
|
||||
<property name="text">
|
||||
<string>Back</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="wzNext">
|
||||
<property name="text">
|
||||
<string>Next</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="wzCancel">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -1243,14 +578,6 @@ Applies and Saves all settings to SD</string>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>ch0Assign</tabstop>
|
||||
<tabstop>ch1Assign</tabstop>
|
||||
<tabstop>ch2Assign</tabstop>
|
||||
<tabstop>ch3Assign</tabstop>
|
||||
<tabstop>ch4Assign</tabstop>
|
||||
<tabstop>ch5Assign</tabstop>
|
||||
<tabstop>ch6Assign</tabstop>
|
||||
<tabstop>ch7Assign</tabstop>
|
||||
<tabstop>fmsSlider</tabstop>
|
||||
<tabstop>fmsModePos3</tabstop>
|
||||
<tabstop>fmsSsPos3Roll</tabstop>
|
||||
@ -1268,134 +595,5 @@ Applies and Saves all settings to SD</string>
|
||||
<resources>
|
||||
<include location="../coreplugin/core.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>inSlider0</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ch0Cur</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>291</x>
|
||||
<y>93</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>150</x>
|
||||
<y>104</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>inSlider1</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ch1Cur</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>283</x>
|
||||
<y>137</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>160</x>
|
||||
<y>138</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>inSlider2</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ch2Cur</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>341</x>
|
||||
<y>163</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>156</x>
|
||||
<y>167</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>inSlider3</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ch3Cur</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>283</x>
|
||||
<y>211</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>159</x>
|
||||
<y>210</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>inSlider4</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ch4Cur</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>287</x>
|
||||
<y>239</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>156</x>
|
||||
<y>242</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>inSlider5</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ch5Cur</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>309</x>
|
||||
<y>272</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>164</x>
|
||||
<y>276</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>inSlider6</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ch6Cur</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>282</x>
|
||||
<y>300</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>144</x>
|
||||
<y>311</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>inSlider7</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ch7Cur</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>278</x>
|
||||
<y>339</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>168</x>
|
||||
<y>340</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
125
ground/openpilotgcs/src/plugins/config/inputchannelform.cpp
Normal file
125
ground/openpilotgcs/src/plugins/config/inputchannelform.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
#include "inputchannelform.h"
|
||||
#include "ui_inputchannelform.h"
|
||||
|
||||
#include "manualcontrolsettings.h"
|
||||
|
||||
inputChannelForm::inputChannelForm(QWidget *parent,bool showlegend) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::inputChannelForm)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
if(!showlegend)
|
||||
{
|
||||
layout()->removeWidget(ui->legend0);
|
||||
layout()->removeWidget(ui->legend1);
|
||||
layout()->removeWidget(ui->legend2);
|
||||
layout()->removeWidget(ui->legend3);
|
||||
layout()->removeWidget(ui->legend4);
|
||||
layout()->removeWidget(ui->legend5);
|
||||
delete ui->legend0;
|
||||
delete ui->legend1;
|
||||
delete ui->legend2;
|
||||
delete ui->legend3;
|
||||
delete ui->legend4;
|
||||
delete ui->legend5;
|
||||
}
|
||||
|
||||
connect(ui->channelMin,SIGNAL(valueChanged(int)),this,SLOT(minMaxUpdated()));
|
||||
connect(ui->channelMax,SIGNAL(valueChanged(int)),this,SLOT(minMaxUpdated()));
|
||||
connect(ui->channelGroup,SIGNAL(currentIndexChanged(int)),this,SLOT(groupUpdated()));
|
||||
connect(ui->channelNeutral,SIGNAL(valueChanged(int)), this, SLOT(neutralUpdated(int)));
|
||||
|
||||
// This is awkward but since we want the UI to be a dropdown but the field is not an enum
|
||||
// it breaks the UAUVObject widget relation of the task gadget. Running the data through
|
||||
// a spin box fixes this
|
||||
connect(ui->channelNumberDropdown,SIGNAL(currentIndexChanged(int)),this,SLOT(channelDropdownUpdated(int)));
|
||||
connect(ui->channelNumber,SIGNAL(valueChanged(int)),this,SLOT(channelNumberUpdated(int)));
|
||||
}
|
||||
|
||||
inputChannelForm::~inputChannelForm()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the direction of the slider and boundaries
|
||||
*/
|
||||
void inputChannelForm::minMaxUpdated()
|
||||
{
|
||||
bool reverse = ui->channelMin->value() > ui->channelMax->value();
|
||||
if(reverse) {
|
||||
ui->channelNeutral->setMinimum(ui->channelMax->value());
|
||||
ui->channelNeutral->setMaximum(ui->channelMin->value());
|
||||
} else {
|
||||
ui->channelNeutral->setMinimum(ui->channelMin->value());
|
||||
ui->channelNeutral->setMaximum(ui->channelMax->value());
|
||||
}
|
||||
ui->channelRev->setChecked(reverse);
|
||||
ui->channelNeutral->setInvertedAppearance(reverse);
|
||||
ui->channelNeutral->setInvertedControls(reverse);
|
||||
}
|
||||
|
||||
void inputChannelForm::neutralUpdated(int newval)
|
||||
{
|
||||
ui->neutral->setText(QString::number(newval));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the channel options based on the selected receiver type
|
||||
*
|
||||
* I fully admit this is terrible practice to embed data within UI
|
||||
* like this. Open to suggestions. JC 2011-09-07
|
||||
*/
|
||||
void inputChannelForm::groupUpdated()
|
||||
{
|
||||
ui->channelNumberDropdown->clear();
|
||||
ui->channelNumberDropdown->addItem("Disabled");
|
||||
|
||||
quint8 count = 0;
|
||||
|
||||
switch(ui->channelGroup->currentIndex()) {
|
||||
case -1: // Nothing selected
|
||||
count = 0;
|
||||
break;
|
||||
case ManualControlSettings::CHANNELGROUPS_PWM:
|
||||
count = 8; // Need to make this 6 for CC
|
||||
break;
|
||||
case ManualControlSettings::CHANNELGROUPS_PPM:
|
||||
case ManualControlSettings::CHANNELGROUPS_SPEKTRUM1:
|
||||
case ManualControlSettings::CHANNELGROUPS_SPEKTRUM2:
|
||||
count = 12;
|
||||
break;
|
||||
case ManualControlSettings::CHANNELGROUPS_SBUS:
|
||||
count = 18;
|
||||
break;
|
||||
case ManualControlSettings::CHANNELGROUPS_GCS:
|
||||
count = 5;
|
||||
case ManualControlSettings::CHANNELGROUPS_NONE:
|
||||
count = 0;
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
ui->channelNumberDropdown->addItem(QString(tr("Chan %1").arg(i+1)));
|
||||
|
||||
ui->channelNumber->setMaximum(count);
|
||||
ui->channelNumber->setMinimum(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the dropdown from the hidden control
|
||||
*/
|
||||
void inputChannelForm::channelDropdownUpdated(int newval)
|
||||
{
|
||||
ui->channelNumber->setValue(newval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the hidden control from the dropdown
|
||||
*/
|
||||
void inputChannelForm::channelNumberUpdated(int newval)
|
||||
{
|
||||
ui->channelNumberDropdown->setCurrentIndex(newval);
|
||||
}
|
30
ground/openpilotgcs/src/plugins/config/inputchannelform.h
Normal file
30
ground/openpilotgcs/src/plugins/config/inputchannelform.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef INPUTCHANNELFORM_H
|
||||
#define INPUTCHANNELFORM_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "configinputwidget.h"
|
||||
namespace Ui {
|
||||
class inputChannelForm;
|
||||
}
|
||||
|
||||
class inputChannelForm : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit inputChannelForm(QWidget *parent = 0,bool showlegend=false);
|
||||
~inputChannelForm();
|
||||
friend class ConfigInputWidget;
|
||||
|
||||
private slots:
|
||||
void minMaxUpdated();
|
||||
void neutralUpdated(int);
|
||||
void groupUpdated();
|
||||
void channelDropdownUpdated(int);
|
||||
void channelNumberUpdated(int);
|
||||
|
||||
private:
|
||||
Ui::inputChannelForm *ui;
|
||||
};
|
||||
|
||||
#endif // INPUTCHANNELFORM_H
|
260
ground/openpilotgcs/src/plugins/config/inputchannelform.ui
Normal file
260
ground/openpilotgcs/src/plugins/config/inputchannelform.ui
Normal file
@ -0,0 +1,260 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>inputChannelForm</class>
|
||||
<widget class="QWidget" name="inputChannelForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>543</width>
|
||||
<height>49</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="topMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="channelName">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QComboBox" name="channelGroup">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>6</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QSpinBox" name="channelMin">
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="8">
|
||||
<widget class="QSpinBox" name="channelMax">
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="legend0">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Function</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="legend2">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Number</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="legend1">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="8">
|
||||
<widget class="QLabel" name="legend5">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Max</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="legend3">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Min</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="6">
|
||||
<widget class="QLabel" name="legend4">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Neutral</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="6">
|
||||
<widget class="QSlider" name="channelNeutral">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QComboBox" name="channelNumberDropdown">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>4</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maxVisibleItems">
|
||||
<number>7</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QSpinBox" name="channelNumber">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="10">
|
||||
<widget class="QCheckBox" name="channelRev">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Rev</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="9">
|
||||
<widget class="QLabel" name="neutral">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="5">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="7">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -949,6 +949,27 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Min</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Neutral (slowest for motor)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Max</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -24,8 +24,11 @@ void smartSaveButton::processClick()
|
||||
bool error=false;
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
UAVObjectUtilManager* utilMngr = pm->getObject<UAVObjectUtilManager>();
|
||||
foreach(UAVObject * obj,objects)
|
||||
foreach(UAVDataObject * obj,objects)
|
||||
{
|
||||
UAVObject::Metadata mdata= obj->getMetadata();
|
||||
if(mdata.gcsAccess==UAVObject::ACCESS_READONLY)
|
||||
continue;
|
||||
up_result=false;
|
||||
current_object=obj;
|
||||
for(int i=0;i<3;++i)
|
||||
@ -35,7 +38,9 @@ void smartSaveButton::processClick()
|
||||
connect(&timer,SIGNAL(timeout()),&loop,SLOT(quit()));
|
||||
obj->updated();
|
||||
timer.start(1000);
|
||||
//qDebug()<<"begin loop";
|
||||
loop.exec();
|
||||
//qDebug()<<"end loop";
|
||||
timer.stop();
|
||||
disconnect(obj,SIGNAL(transactionCompleted(UAVObject*,bool)),this,SLOT(transaction_finished(UAVObject*, bool)));
|
||||
disconnect(&timer,SIGNAL(timeout()),&loop,SLOT(quit()));
|
||||
@ -44,30 +49,32 @@ void smartSaveButton::processClick()
|
||||
}
|
||||
if(up_result==false)
|
||||
{
|
||||
//qDebug()<<"Object upload error:"<<obj->getName();
|
||||
error=true;
|
||||
continue;
|
||||
}
|
||||
sv_result=false;
|
||||
current_objectID=obj->getObjID();
|
||||
if(save)
|
||||
if(save && (obj->isSettings()))
|
||||
{
|
||||
for(int i=0;i<3;++i)
|
||||
{
|
||||
connect(utilMngr,SIGNAL(saveCompleted(int,bool)),this,SLOT(saving_finished(int,bool)));
|
||||
connect(&timer,SIGNAL(timeout()),&loop,SLOT(quit()));
|
||||
utilMngr->saveObjectToSD(obj);
|
||||
timer.start(1000);
|
||||
loop.exec();
|
||||
timer.stop();
|
||||
disconnect(utilMngr,SIGNAL(saveCompleted(int,bool)),this,SLOT(saving_finished(int,bool)));
|
||||
disconnect(&timer,SIGNAL(timeout()),&loop,SLOT(quit()));
|
||||
if(sv_result)
|
||||
break;
|
||||
}
|
||||
if(sv_result==false)
|
||||
{
|
||||
error=true;
|
||||
}
|
||||
for(int i=0;i<3;++i)
|
||||
{
|
||||
//qDebug()<<"try to save:"<<obj->getName();
|
||||
connect(utilMngr,SIGNAL(saveCompleted(int,bool)),this,SLOT(saving_finished(int,bool)));
|
||||
connect(&timer,SIGNAL(timeout()),&loop,SLOT(quit()));
|
||||
utilMngr->saveObjectToSD(obj);
|
||||
timer.start(1000);
|
||||
loop.exec();
|
||||
timer.stop();
|
||||
disconnect(utilMngr,SIGNAL(saveCompleted(int,bool)),this,SLOT(saving_finished(int,bool)));
|
||||
disconnect(&timer,SIGNAL(timeout()),&loop,SLOT(quit()));
|
||||
if(sv_result)
|
||||
break;
|
||||
}
|
||||
if(sv_result==false)
|
||||
{
|
||||
error=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
button->setEnabled(true);
|
||||
@ -83,14 +90,15 @@ void smartSaveButton::processClick()
|
||||
emit endOp();
|
||||
}
|
||||
|
||||
void smartSaveButton::setObjects(QList<UAVObject *> list)
|
||||
void smartSaveButton::setObjects(QList<UAVDataObject *> list)
|
||||
{
|
||||
objects=list;
|
||||
}
|
||||
|
||||
void smartSaveButton::addObject(UAVObject * obj)
|
||||
void smartSaveButton::addObject(UAVDataObject * obj)
|
||||
{
|
||||
objects.append(obj);
|
||||
if(!objects.contains(obj))
|
||||
objects.append(obj);
|
||||
}
|
||||
|
||||
void smartSaveButton::clearObjects()
|
||||
@ -111,6 +119,7 @@ void smartSaveButton::saving_finished(int id, bool result)
|
||||
if(id==current_objectID)
|
||||
{
|
||||
sv_result=result;
|
||||
//qDebug()<<"saving_finished result="<<result;
|
||||
loop.quit();
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,8 @@ public:
|
||||
Q_OBJECT
|
||||
public:
|
||||
smartSaveButton(QPushButton * update,QPushButton * save);
|
||||
void setObjects(QList<UAVObject *>);
|
||||
void addObject(UAVObject *);
|
||||
void setObjects(QList<UAVDataObject *>);
|
||||
void addObject(UAVDataObject *);
|
||||
void clearObjects();
|
||||
signals:
|
||||
void preProcessOperations();
|
||||
@ -34,11 +34,11 @@ private:
|
||||
QPushButton *bupdate;
|
||||
QPushButton *bsave;
|
||||
quint32 current_objectID;
|
||||
UAVObject * current_object;
|
||||
UAVDataObject * current_object;
|
||||
bool up_result;
|
||||
bool sv_result;
|
||||
QEventLoop loop;
|
||||
QList<UAVObject *> objects;
|
||||
QList<UAVDataObject *> objects;
|
||||
protected:
|
||||
public slots:
|
||||
void enableControls(bool value);
|
||||
|
@ -601,21 +601,21 @@ When you change one, the other is updated.</string>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="manualRoll">
|
||||
<property name="maximum">
|
||||
<number>300</number>
|
||||
<number>500</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QSpinBox" name="manualPitch">
|
||||
<property name="maximum">
|
||||
<number>300</number>
|
||||
<number>500</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QSpinBox" name="manualYaw">
|
||||
<property name="maximum">
|
||||
<number>300</number>
|
||||
<number>500</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -644,21 +644,21 @@ When you change one, the other is updated.</string>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="maximumRoll">
|
||||
<property name="maximum">
|
||||
<number>300</number>
|
||||
<number>500</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QSpinBox" name="maximumPitch">
|
||||
<property name="maximum">
|
||||
<number>300</number>
|
||||
<number>500</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QSpinBox" name="maximumYaw">
|
||||
<property name="maximum">
|
||||
<number>300</number>
|
||||
<number>500</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -385,8 +385,15 @@ void ScopeGadgetWidget::addCurvePlot(QString uavObject, QString uavFieldSubField
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(objManager->getObject((plotData->uavObject)));
|
||||
|
||||
if(!obj) {
|
||||
qDebug() << "Object " << plotData->uavObject << " is missing";
|
||||
return;
|
||||
}
|
||||
UAVObjectField* field = obj->getField(plotData->uavField);
|
||||
if(!field) {
|
||||
qDebug() << "Field " << plotData->uavField << " of object " << plotData->uavObject << " is missing";
|
||||
return;
|
||||
}
|
||||
QString units = field->getUnits();
|
||||
|
||||
if(units == 0)
|
||||
|
@ -70,6 +70,8 @@ HEADERS += $$UAVOBJECT_SYNTHETICS/accessorydesired.h \
|
||||
$$UAVOBJECT_SYNTHETICS/sonaraltitude.h \
|
||||
$$UAVOBJECT_SYNTHETICS/flightstatus.h \
|
||||
$$UAVOBJECT_SYNTHETICS/hwsettings.h \
|
||||
$$UAVOBJECT_SYNTHETICS/gcsreceiver.h \
|
||||
$$UAVOBJECT_SYNTHETICS/receiveractivity.h \
|
||||
$$UAVOBJECT_SYNTHETICS/attitudesettings.h \
|
||||
$$UAVOBJECT_SYNTHETICS/cameradesired.h
|
||||
|
||||
@ -121,5 +123,7 @@ SOURCES += $$UAVOBJECT_SYNTHETICS/accessorydesired.cpp \
|
||||
$$UAVOBJECT_SYNTHETICS/uavobjectsinit.cpp \
|
||||
$$UAVOBJECT_SYNTHETICS/flightstatus.cpp \
|
||||
$$UAVOBJECT_SYNTHETICS/hwsettings.cpp \
|
||||
$$UAVOBJECT_SYNTHETICS/gcsreceiver.cpp \
|
||||
$$UAVOBJECT_SYNTHETICS/receiveractivity.cpp \
|
||||
$$UAVOBJECT_SYNTHETICS/attitudesettings.cpp \
|
||||
$$UAVOBJECT_SYNTHETICS/cameradesired.cpp
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include <QDebug>
|
||||
#include <QEventLoop>
|
||||
#include <QTimer>
|
||||
#include <QErrorMessage>
|
||||
#include <objectpersistence.h>
|
||||
|
||||
// ******************************
|
||||
// constructor/destructor
|
||||
@ -168,18 +170,30 @@ void UAVObjectUtilManager::objectPersistenceTransactionCompleted(UAVObject* obj,
|
||||
*/
|
||||
void UAVObjectUtilManager::objectPersistenceOperationFailed()
|
||||
{
|
||||
qDebug() << "objectPersistenceOperationFailed";
|
||||
if(saveState == AWAITING_COMPLETED) {
|
||||
//TODO: some warning that this operation failed somehow
|
||||
// We have to disconnect the object persistence 'updated' signal
|
||||
// and ask to save the next object:
|
||||
UAVObject *obj = getObjectManager()->getObject(ObjectPersistence::NAME);
|
||||
obj->disconnect(this);
|
||||
queue.dequeue(); // We can now remove the object, it failed anyway.
|
||||
|
||||
ObjectPersistence * objectPersistence = ObjectPersistence::GetInstance(getObjectManager());
|
||||
Q_ASSERT(objectPersistence);
|
||||
|
||||
UAVObject* obj = queue.dequeue(); // We can now remove the object, it failed anyway.
|
||||
Q_ASSERT(obj);
|
||||
|
||||
objectPersistence->disconnect(this);
|
||||
|
||||
saveState = IDLE;
|
||||
emit saveCompleted(obj->getField("ObjectID")->getValue().toInt(), false);
|
||||
emit saveCompleted(obj->getObjID(), false);
|
||||
|
||||
// For now cause error message here to make sure user knows
|
||||
QErrorMessage err;
|
||||
err.showMessage("Saving object " + obj->getName() + " failed. Please try again");
|
||||
err.exec();
|
||||
|
||||
saveNextObject();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user