diff --git a/conf/Makefile.stm32-upload b/conf/Makefile.stm32-upload index e4bc065d22..b43459ef7e 100644 --- a/conf/Makefile.stm32-upload +++ b/conf/Makefile.stm32-upload @@ -154,6 +154,13 @@ upload: $(OBJDIR)/$(TARGET).bin @echo "Using ST-LINK with SWD at $(STLINK_ADDR)" $(Q)st-flash write $^ $(STLINK_ADDR) +else ifeq ($(FLASH_MODE),PX4_BOOTLOADER) + # Program the device and start it. +upload: $(OBJDIR)/$(TARGET).bin + $(PAPARAZZI_SRC)/sw/tools/px4/px_mkfw.py --prototype $(PX4_PROTOTYPE) --image $(OBJDIR)/$(TARGET).bin > $(OBJDIR)/$(TARGET).px4 + $(PAPARAZZI_SRC)/sw/tools/px4/print_message.py + $(PAPARAZZI_SRC)/sw/tools/px4/px_uploader.py --port $(PX4_BL_PORT) $(OBJDIR)/$(TARGET).px4 + # # no known flash mode else diff --git a/conf/airframes/TUDELFT/tudelft_conf.xml b/conf/airframes/TUDELFT/tudelft_conf.xml index 99ffb7ac23..6b7ff13814 100644 --- a/conf/airframes/TUDELFT/tudelft_conf.xml +++ b/conf/airframes/TUDELFT/tudelft_conf.xml @@ -109,6 +109,17 @@ settings_modules="modules/gps_ubx_ucenter.xml modules/logger_sd_spi_direct.xml" gui_color="#9b69e5ce9e7a" /> + + + + + + + + + + + diff --git a/conf/airframes/TUDELFT/tudelft_iris_indi.xml b/conf/airframes/TUDELFT/tudelft_iris_indi.xml new file mode 100644 index 0000000000..d151b9df6c --- /dev/null +++ b/conf/airframes/TUDELFT/tudelft_iris_indi.xml @@ -0,0 +1,250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + + + + +
+ + + +
+ + +
+ + + + + + + +
+
+ + +
+
+ + + + + + + +
+
+ + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + +
+
+ + + + + + + + +
+
+ + +
+
+ + + +
+
+ + + + + +
+
+ + + + + +
+
diff --git a/conf/airframes/TUDELFT/tudelft_iris_pid.xml b/conf/airframes/TUDELFT/tudelft_iris_pid.xml new file mode 100644 index 0000000000..0833fd7434 --- /dev/null +++ b/conf/airframes/TUDELFT/tudelft_iris_pid.xml @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + + + + +
+ + + +
+ + +
+ + + + + + + +
+
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + +
+
+ + + + + + + + +
+
+ + +
+
+ + + +
+
+ + + + + +
+
+ + + + + +
+
diff --git a/conf/boards/px4fmu_2.4.makefile b/conf/boards/px4fmu_2.4.makefile index 9301b7424a..e1452f66f5 100644 --- a/conf/boards/px4fmu_2.4.makefile +++ b/conf/boards/px4fmu_2.4.makefile @@ -2,7 +2,7 @@ # # px4fmu_2.4.makefile # -# This is for the main MCU (STM32F427) on the pixhawk board +# This is for the main MCU (STM32F427) on the PX4 board # See https://pixhawk.org/modules/pixhawk for details # @@ -19,10 +19,12 @@ $(TARGET).LDSCRIPT=$(SRC_ARCH)/px4fmu_2.4.ld HARD_FLOAT=yes -# default flash mode is via usb dfu bootloader -# possibilities: DFU, SWD -FLASH_MODE ?= SWD - +# default flash mode is the PX4 bootloader +# possibilities: DFU, SWD, PX4 bootloader +FLASH_MODE ?= PX4_BOOTLOADER +PX4_PROTOTYPE ?= "${PAPARAZZI_HOME}/sw/tools/px4/px4fmu-v2.prototype" +PX4_BL_PORT ?= "/dev/serial/by-id/usb-3D_Robotics*,/dev/serial/by-id/pci-3D_Robotics*" +$(TARGET).MAKEFILE = stm32 # # default LED configuration @@ -40,12 +42,10 @@ SYS_TIME_LED ?= 1 MODEM_PORT ?= UART2 MODEM_BAUD ?= B57600 +#The GPS serial on px4 is called serial 3, but connected to uart4 on the f4 GPS_PORT ?= UART4 GPS_BAUD ?= B38400 -RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT ?= UART2 - - # # default actuator configuration # diff --git a/conf/boards/px4io_2.4.makefile b/conf/boards/px4io_2.4.makefile new file mode 100644 index 0000000000..42406c6d1d --- /dev/null +++ b/conf/boards/px4io_2.4.makefile @@ -0,0 +1,48 @@ +# Hey Emacs, this is a -*- makefile -*- +# +# px4io_2.4.makefile +# +# This is for the main MCU (STM32F427) on the PX4 board +# See https://pixhawk.org/modules/pixhawk for details +# + +BOARD=px4io +BOARD_VERSION=2.4 +BOARD_CFG=\"boards/$(BOARD)_$(BOARD_VERSION).h\" + +ARCH=stm32 +$(TARGET).ARCHDIR = $(ARCH) +$(TARGET).LDSCRIPT=$(SRC_ARCH)/px4io_2.4.ld + +# default flash mode is via usb dfu bootloader +# possibilities: DFU, SWD, PX4_BOOTLOADER +PX4_BL_PORT ?= "/dev/serial/by-id/usb-FTDI_*" +PX4_PROTOTYPE ?= "${PAPARAZZI_HOME}/sw/tools/px4/px4io-v2.prototype" + +FLASH_MODE ?= PX4_BOOTLOADER +$(TARGET).MAKEFILE = stm32 + +# +# default LED configuration +# +RADIO_CONTROL_LED ?= none +BARO_LED ?= none +AHRS_ALIGNER_LED ?= none +GPS_LED ?= none +SYS_TIME_LED ?= 1 +FBW_MODE_LED ?= 3 + +# +# default UART configuration (modem, gps, spektrum) +# +RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT ?= UART1 + +# +# default actuator configuration +# +# you can use different actuators by adding a configure option to your firmware section +# e.g. +# +ACTUATORS ?= actuators_pwm diff --git a/conf/firmwares/subsystems/fixedwing/intermcu_uart.makefile b/conf/firmwares/subsystems/fixedwing/intermcu_uart.makefile index 7bb2ce981b..2c220b3971 100644 --- a/conf/firmwares/subsystems/fixedwing/intermcu_uart.makefile +++ b/conf/firmwares/subsystems/fixedwing/intermcu_uart.makefile @@ -11,6 +11,7 @@ ifeq ($(TARGET),fbw) INTERMCU_PORT ?= UART2 INTERMCU_PORT_LOWER = $(shell echo $(INTERMCU_PORT) | tr A-Z a-z) fbw.CFLAGS += -DINTERMCU_LINK=$(INTERMCU_PORT_LOWER) -DUSE_$(INTERMCU_PORT) -D$(INTERMCU_PORT)_BAUD=B57600 + fbw.CFLAGS += -DFBW_MODE_LED=$(FBW_MODE_LED) else INTERMCU_PORT ?= UART5 INTERMCU_PORT_LOWER = $(shell echo $(INTERMCU_PORT) | tr A-Z a-z) diff --git a/conf/firmwares/subsystems/rotorcraft/intermcu_uart.makefile b/conf/firmwares/subsystems/rotorcraft/intermcu_uart.makefile index 3199bbd3fd..8b2feea188 100644 --- a/conf/firmwares/subsystems/rotorcraft/intermcu_uart.makefile +++ b/conf/firmwares/subsystems/rotorcraft/intermcu_uart.makefile @@ -4,18 +4,24 @@ ifeq ($(TARGET),fbw) INTERMCU_PORT ?= UART3 + INTERMCU_BAUD ?= B230400 INTERMCU_PORT_LOWER = $(shell echo $(INTERMCU_PORT) | tr A-Z a-z) - fbw.CFLAGS += -DINTERMCU_LINK=$(INTERMCU_PORT_LOWER) -DUSE_$(INTERMCU_PORT) -D$(INTERMCU_PORT)_BAUD=B230400 + fbw.CFLAGS += -DINTERMCU_LINK=$(INTERMCU_PORT_LOWER) -DUSE_$(INTERMCU_PORT) -D$(INTERMCU_PORT)_BAUD=$(INTERMCU_BAUD) fbw.CFLAGS += -DINTER_MCU_FBW -DDOWNLINK + fbw.CFLAGS += -DFBW_MODE_LED=$(FBW_MODE_LED) fbw.srcs += pprzlink/src/pprz_transport.c fbw.srcs += subsystems/intermcu/intermcu_fbw.c else INTERMCU_PORT ?= UART3 + INTERMCU_BAUD ?= B230400 INTERMCU_PORT_LOWER = $(shell echo $(INTERMCU_PORT) | tr A-Z a-z) ap.CFLAGS += -DINTER_MCU_AP -DINTERMCU_LINK=$(INTERMCU_PORT_LOWER) - ap.CFLAGS += -DUSE_$(INTERMCU_PORT) -D$(INTERMCU_PORT)_BAUD=B230400 + ap.CFLAGS += -DUSE_$(INTERMCU_PORT) -D$(INTERMCU_PORT)_BAUD=$(INTERMCU_BAUD) $(TARGET).CFLAGS += -DRADIO_CONTROL_TYPE_H=\"subsystems/intermcu/intermcu_ap.h\" -DRADIO_CONTROL - $(TARGET).CFLAGS += -DRADIO_CONTROL_LED=$(RADIO_CONTROL_LED) + RADIO_CONTROL_LED ?= none +ifneq ($(RADIO_CONTROL_LED),none) + $(TARGET).CFLAGS += -DRADIO_CONTROL_LED=$(RADIO_CONTROL_LED) +endif ap.srcs += subsystems/intermcu/intermcu_ap.c ap.srcs += pprzlink/src/pprz_transport.c diff --git a/conf/firmwares/subsystems/shared/baro_board.makefile b/conf/firmwares/subsystems/shared/baro_board.makefile index a6f9839cbd..096a079e4f 100644 --- a/conf/firmwares/subsystems/shared/baro_board.makefile +++ b/conf/firmwares/subsystems/shared/baro_board.makefile @@ -167,8 +167,8 @@ else ifeq ($(BOARD), krooz) BARO_BOARD_SRCS += boards/baro_board_ms5611_i2c.c # PX4FMU -else ifeq ($(BOARD), px4fmu) - BARO_BOARD_CFLAGS += -DUSE_I2C2 +else ifeq ($(BOARD),$(filter $(BOARD),px4fmu)) + BARO_BOARD_CFLAGS += -DUSE_I2C2 BARO_BOARD_CFLAGS += -DBB_MS5611_I2C_DEV=i2c2 BARO_BOARD_SRCS += peripherals/ms5611.c BARO_BOARD_SRCS += peripherals/ms5611_i2c.c diff --git a/conf/firmwares/test_progs.makefile b/conf/firmwares/test_progs.makefile index 46b00af392..1813b07a92 100644 --- a/conf/firmwares/test_progs.makefile +++ b/conf/firmwares/test_progs.makefile @@ -229,6 +229,23 @@ test_telemetry.CFLAGS += $(COMMON_TELEMETRY_CFLAGS) test_telemetry.srcs += $(COMMON_TELEMETRY_SRCS) test_telemetry.srcs += test/test_telemetry.c +# +# test_datalink : Sends ALIVE and pong telemetry messages +# +# configuration +# MODEM_PORT : +# MODEM_BAUD : +# +test_datalink.ARCHDIR = $(ARCH) +test_datalink.CFLAGS += $(COMMON_TEST_CFLAGS) +test_datalink.srcs += $(COMMON_TEST_SRCS) +test_datalink.CFLAGS += $(COMMON_DATALINK_CFLAGS) +test_datalink.CFLAGS += $(COMMON_TELEMETRY_CFLAGS) +test_datalink.srcs += $(COMMON_DATALINK_SRCS) +test_datalink.srcs += $(COMMON_TELEMETRY_SRCS) +test_datalink.srcs += test/test_datalink.c + + # # test_math_trig_compressed: Test math trigonometric using compressed data # diff --git a/conf/flash_modes.xml b/conf/flash_modes.xml index d3685e3044..826a198844 100644 --- a/conf/flash_modes.xml +++ b/conf/flash_modes.xml @@ -96,6 +96,13 @@ + + + + + + + diff --git a/conf/modules/px4io_flash.xml b/conf/modules/px4io_flash.xml new file mode 100644 index 0000000000..f16af5254a --- /dev/null +++ b/conf/modules/px4io_flash.xml @@ -0,0 +1,31 @@ + + + + + Flashes the px4io f1 through the px4 bootloader. + +
+ +
+ + + + + + + + + + + + + + + + + + + + +
+ diff --git a/conf/modules/spektrum_soft_bind.xml b/conf/modules/spektrum_soft_bind.xml new file mode 100644 index 0000000000..9920ada163 --- /dev/null +++ b/conf/modules/spektrum_soft_bind.xml @@ -0,0 +1,25 @@ + + + + + Puts Spektrum in binding mode through software + + + + + + + + +
+ +
+ + + + + + + +
+ diff --git a/conf/radios/FrSky3dr.xml b/conf/radios/FrSky3dr.xml new file mode 100644 index 0000000000..53287a7781 --- /dev/null +++ b/conf/radios/FrSky3dr.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/conf/system/udev/rules/50-paparazzi.rules b/conf/system/udev/rules/50-paparazzi.rules index 4cef376c31..893b0849e0 100644 --- a/conf/system/udev/rules/50-paparazzi.rules +++ b/conf/system/udev/rules/50-paparazzi.rules @@ -20,6 +20,9 @@ SUBSYSTEM=="tty", ATTRS{product}=="FT232R USB UART", SYMLINK+="ftdi-serial", GRO # Paparazzi STM32 Autopilot board USB CDC serial device SUBSYSTEM=="tty", ATTRS{manufacturer}=="Paparazzi UAV", ATTRS{product}=="CDC Serial STM32", SYMLINK+="paparazzi/stm32-usb-serial" +# Paparazzi 3dr radio +SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", SYMLINK+="paparazzi/link", GROUP="plugdev" + # MaxStream xbee pro box SUBSYSTEM=="tty", ATTRS{product}=="MaxStream PKG-U", SYMLINK+="paparazzi/xbee", GROUP="plugdev" diff --git a/conf/telemetry/TUDELFT/tudelft_xbee868.xml b/conf/telemetry/TUDELFT/tudelft_xbee868.xml index 9cee6119de..b7cdd56cc8 100644 --- a/conf/telemetry/TUDELFT/tudelft_xbee868.xml +++ b/conf/telemetry/TUDELFT/tudelft_xbee868.xml @@ -1,5 +1,5 @@ - + diff --git a/conf/telemetry/default_rotorcraft_slow.xml b/conf/telemetry/default_rotorcraft_slow.xml index 88a3995b1c..935598dcc0 100644 --- a/conf/telemetry/default_rotorcraft_slow.xml +++ b/conf/telemetry/default_rotorcraft_slow.xml @@ -27,7 +27,8 @@ - + + diff --git a/sw/airborne/arch/stm32/mcu_arch.c b/sw/airborne/arch/stm32/mcu_arch.c index e9c4683dd3..30a810dadd 100644 --- a/sw/airborne/arch/stm32/mcu_arch.c +++ b/sw/airborne/arch/stm32/mcu_arch.c @@ -42,50 +42,115 @@ #if defined(STM32F4) /* untested, should go into libopencm3 */ const clock_scale_t hse_24mhz_3v3[CLOCK_3V3_END] = { - { /* 48MHz */ - .pllm = 24, - .plln = 96, - .pllp = 2, - .pllq = 2, - .hpre = RCC_CFGR_HPRE_DIV_NONE, - .ppre1 = RCC_CFGR_PPRE_DIV_4, - .ppre2 = RCC_CFGR_PPRE_DIV_2, - .power_save = 1, - .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | - FLASH_ACR_LATENCY_3WS, - .apb1_frequency = 12000000, - .apb2_frequency = 24000000, - }, - { /* 120MHz */ - .pllm = 24, - .plln = 240, - .pllp = 2, - .pllq = 5, - .hpre = RCC_CFGR_HPRE_DIV_NONE, - .ppre1 = RCC_CFGR_PPRE_DIV_4, - .ppre2 = RCC_CFGR_PPRE_DIV_2, - .power_save = 1, - .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | - FLASH_ACR_LATENCY_3WS, - .apb1_frequency = 30000000, - .apb2_frequency = 60000000, - }, - { /* 168MHz */ - .pllm = 24, - .plln = 336, - .pllp = 2, - .pllq = 7, - .hpre = RCC_CFGR_HPRE_DIV_NONE, - .ppre1 = RCC_CFGR_PPRE_DIV_4, - .ppre2 = RCC_CFGR_PPRE_DIV_2, - .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | - FLASH_ACR_LATENCY_5WS, - .apb1_frequency = 42000000, - .apb2_frequency = 84000000, - }, + { /* 48MHz */ + .pllm = 24, + .plln = 96, + .pllp = 2, + .pllq = 2, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE_DIV_4, + .ppre2 = RCC_CFGR_PPRE_DIV_2, + .power_save = 1, + .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | + FLASH_ACR_LATENCY_3WS, + .apb1_frequency = 12000000, + .apb2_frequency = 24000000, + }, + { /* 120MHz */ + .pllm = 24, + .plln = 240, + .pllp = 2, + .pllq = 5, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE_DIV_4, + .ppre2 = RCC_CFGR_PPRE_DIV_2, + .power_save = 1, + .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | + FLASH_ACR_LATENCY_3WS, + .apb1_frequency = 30000000, + .apb2_frequency = 60000000, + }, + { /* 168MHz */ + .pllm = 24, + .plln = 336, + .pllp = 2, + .pllq = 7, + .hpre = RCC_CFGR_HPRE_DIV_NONE, + .ppre1 = RCC_CFGR_PPRE_DIV_4, + .ppre2 = RCC_CFGR_PPRE_DIV_2, + .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE | + FLASH_ACR_LATENCY_5WS, + .apb1_frequency = 42000000, + .apb2_frequency = 84000000, + }, }; #endif +#if defined(STM32F1) +/*---------------------------------------------------------------------------*/ +/** @brief RCC Set System Clock HSE at 24MHz from HSE at 24MHz + +*/ +void rcc_clock_setup_in_hse_24mhz_out_24mhz_pprz(void); +void rcc_clock_setup_in_hse_24mhz_out_24mhz_pprz(void) +{ + /* Enable internal high-speed oscillator. */ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + + /* Select HSI as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK); + + /* Enable external high-speed oscillator 24MHz. */ + rcc_osc_on(HSE); + rcc_wait_for_osc_ready(HSE); + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSECLK); + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 24MHz Max. 72MHz */ + rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2); /* Set. 12MHz Max. 14MHz */ + rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_NODIV); /* Set. 24MHz Max. 36MHz */ + rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 24MHz Max. 72MHz */ + + /* + * Sysclk runs with 24MHz -> 0 waitstates. + * 0WS from 0-24MHz + * 1WS from 24-48MHz + * 2WS from 48-72MHz + */ + flash_set_ws(FLASH_ACR_LATENCY_0WS); + + /* + * Set the PLL multiplication factor to 2. + * 24MHz (external) * 2 (multiplier) / 2 (RCC_CFGR_PLLXTPRE_HSE_CLK_DIV2) = 24MHz + */ + rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL2); + + /* Select HSE as PLL source. */ + rcc_set_pll_source(RCC_CFGR_PLLSRC_HSE_CLK); + + /* + * External frequency divide by 2 before entering PLL + * (only valid/needed for HSE). + */ + rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK_DIV2); + + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + + /* Select PLL as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK); + + /* Set the peripheral clock frequencies used */ + rcc_ahb_frequency = 24000000; + rcc_apb1_frequency = 24000000; + rcc_apb2_frequency = 24000000; +} +#endif + void mcu_arch_init(void) { #if LUFTBOOT @@ -121,6 +186,8 @@ void mcu_arch_init(void) #if defined(STM32F4) PRINT_CONFIG_MSG("Using 24MHz external clock to PLL it to 168MHz.") rcc_clock_setup_hse_3v3(&hse_24mhz_3v3[CLOCK_3V3_168MHZ]); +#elif defined(STM32F1) + rcc_clock_setup_in_hse_24mhz_out_24mhz_pprz(); #endif #elif EXT_CLK == 25000000 #if defined(STM32F4) @@ -142,6 +209,7 @@ void mcu_arch_init(void) } #if defined(STM32F1) + #define RCC_CFGR_PPRE2_SHIFT 11 #define RCC_CFGR_PPRE2 (7 << RCC_CFGR_PPRE2_SHIFT) @@ -191,8 +259,7 @@ uint32_t timer_get_frequency(uint32_t timer_peripheral) #ifdef TIM11 case TIM11: #endif - if (!rcc_get_ppre2()) - { + if (!rcc_get_ppre2()) { /* without APB2 prescaler, runs at APB2 freq */ return rcc_apb2_frequency; } else { @@ -216,8 +283,7 @@ uint32_t timer_get_frequency(uint32_t timer_peripheral) #ifdef TIM14 case TIM14: #endif - if (!rcc_get_ppre1()) - { + if (!rcc_get_ppre1()) { /* without APB1 prescaler, runs at APB1 freq */ return rcc_apb1_frequency; } else { diff --git a/sw/airborne/arch/stm32/mcu_periph/adc_arch.c b/sw/airborne/arch/stm32/mcu_periph/adc_arch.c index 839dfdbfbe..75ec2b1c60 100644 --- a/sw/airborne/arch/stm32/mcu_periph/adc_arch.c +++ b/sw/airborne/arch/stm32/mcu_periph/adc_arch.c @@ -147,7 +147,7 @@ PRINT_CONFIG_MSG("Analog to Digital Coverter 2 active") #if USE_AD3 PRINT_CONFIG_MSG("Analog to Digital Coverter 3 active") #endif -#if !USE_AD1 && !USE_AD2 && !USE_AD3 +#if !USE_AD1 && !USE_AD2 && !USE_AD3 && !defined FBW #warning ALL ADC CONVERTERS INACTIVE #endif @@ -222,11 +222,12 @@ static struct { void adc_init(void) { - +#if USE_AD1 || USE_AD2 || USE_AD3 uint8_t x = 0; // ADC channel mapping uint8_t adc_channel_map[4]; +#endif /* Init GPIO ports for ADC operation */ @@ -582,9 +583,11 @@ void adc1_2_isr(void) void adc_isr(void) #endif { +#if USE_AD1 || USE_AD2 || USE_AD3 uint8_t channel = 0; uint16_t value = 0; struct adc_buf *buf; +#endif #if USE_ADC_WATCHDOG /* diff --git a/sw/airborne/arch/stm32/mcu_periph/uart_arch.h b/sw/airborne/arch/stm32/mcu_periph/uart_arch.h index 910523b66c..79a9dd16ee 100644 --- a/sw/airborne/arch/stm32/mcu_periph/uart_arch.h +++ b/sw/airborne/arch/stm32/mcu_periph/uart_arch.h @@ -40,6 +40,7 @@ #define B115200 115200 #define B230400 230400 #define B921600 921600 +#define B1500000 1500000 #define UART_SPEED(_def) _def #endif /* STM32_UART_ARCH_H */ diff --git a/sw/airborne/arch/stm32/px4fmu_2.4.ld b/sw/airborne/arch/stm32/px4fmu_2.4.ld index c75ae6f361..e7158dbb88 100644 --- a/sw/airborne/arch/stm32/px4fmu_2.4.ld +++ b/sw/airborne/arch/stm32/px4fmu_2.4.ld @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Felix Ruess + * Copyright (C) 2016 The Paparazzi Team> * * This file is part of Paparazzi. * @@ -19,15 +19,14 @@ * Boston, MA 02111-1307, USA. */ -/* Linker script for Pixhawk PX4FMU v2.4 (STM32F427, 2048K flash, 256K RAM). */ +/* Linker script for Pixhawk PX4FMU v2.4 (STM32F427, 1024K flash, 192K RAM). */ /* Define memory regions. */ MEMORY { - /* only 192K (SRAM1 and SRAM2) are accessible by all AHB masters. */ - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 192K - /* Reserving 128kb flash for persistent settings. */ - rom (rx) : ORIGIN = 0x08000000, LENGTH = 1920K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 192K + /* Pixhawk seems to have had a bad badge of f4's, so only use the first 1mb */ + rom (rx) : ORIGIN = 0x08004000, LENGTH = 1008K } /* Include the common ld script. */ diff --git a/sw/airborne/arch/stm32/px4io_2.4.ld b/sw/airborne/arch/stm32/px4io_2.4.ld new file mode 100644 index 0000000000..b560cf8996 --- /dev/null +++ b/sw/airborne/arch/stm32/px4io_2.4.ld @@ -0,0 +1,36 @@ +/* + * Hey Emacs, this is a -*- makefile -*- + * + * Copyright (C) 2016 Kevin van Hecke + * + * This file is part of Paparazzi. + * + * Paparazzi 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 2, or (at your option) + * any later version. + * + * Paparazzi 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 Paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* Linker script for the PX4IO (STM32F103c8t6 medium density, 64 Kbytes Flash). */ + +/* Define memory regions. */ +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K + /* Leaving 2k of space at the end of rom for stored settings */ + rom (rx) : ORIGIN = 0x08001000, LENGTH = 60K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/sw/airborne/arch/stm32/subsystems/actuators/actuators_pwm_arch.c b/sw/airborne/arch/stm32/subsystems/actuators/actuators_pwm_arch.c index 0955809c76..4d136d0019 100644 --- a/sw/airborne/arch/stm32/subsystems/actuators/actuators_pwm_arch.c +++ b/sw/airborne/arch/stm32/subsystems/actuators/actuators_pwm_arch.c @@ -43,7 +43,6 @@ int32_t actuators_pwm_values[ACTUATORS_PWM_NB]; */ void actuators_pwm_arch_init(void) { - /*----------------------------------- * Configure timer peripheral clocks *-----------------------------------*/ diff --git a/sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.c b/sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.c index 0234b33c41..65fddebf4c 100644 --- a/sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.c +++ b/sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.c @@ -56,14 +56,55 @@ INFO("Radio-Control now follows PPRZ sign convention: this means you might need #define MIN_FRAME_SPACE 70 // 7ms #define MAX_BYTE_SPACE 3 // .3ms + +//not all f1's have a timer 6, so, some redefines have to happen +#define PASTER3(x,y,z) x ## y ## z +#define EVALUATOR3(x,y,z) PASTER3(x,y,z) +#define NVIC_TIMx_IRQ EVALUATOR3(NVIC_TIM, SPEKTRUM_TIMER,_IRQ) +#define NVIC_TIMx_DAC_IRQ EVALUATOR3(NVIC_TIM, SPEKTRUM_TIMER,_DAC_IRQ) // not really necessary, only for f4 which probably always has a timer 4 +#define TIMx_ISR EVALUATOR3(tim, SPEKTRUM_TIMER,_isr) +#define TIMx_DAC_ISR EVALUATOR3(tim, SPEKTRUM_TIMER,_dac_isr) + +#define PASTER2(x,y) x ## y +#define EVALUATOR2(x,y) PASTER2(x,y) +#define TIMx EVALUATOR2(TIM, SPEKTRUM_TIMER) +#define RCC_TIMx EVALUATOR2(RCC_TIM, SPEKTRUM_TIMER) + +#ifndef SPEKTRUM_TIMER +#define SPEKTRUM_TIMER 6 +#endif + +#if (SPEKTRUM_TIMER == 6) #ifndef NVIC_TIM6_IRQ_PRIO #define NVIC_TIM6_IRQ_PRIO 2 +#define NVIC_TIMx_IRQ_PRIO 2 +#else +#define NVIC_TIMx_IRQ_PRIO NVIC_TIM6_IRQ_PRIO #endif - #ifndef NVIC_TIM6_DAC_IRQ_PRIO #define NVIC_TIM6_DAC_IRQ_PRIO 2 +#define NVIC_TIMx_DAC_IRQ_PRIO 2 +#else +#define NVIC_TIMx_DAC_IRQ_PRIO NVIC_TIM6_DAC_IRQ_PRIO +#endif #endif +#if (SPEKTRUM_TIMER == 3) +#ifndef NVIC_TIM3_IRQ_PRIO +#define NVIC_TIM3_IRQ_PRIO 2 +#define NVIC_TIMx_IRQ_PRIO 2 +#else +#define NVIC_TIMx_IRQ_PRIO NVIC_TIM6_IRQ_PRIO +#endif +#ifndef NVIC_TIM3_DAC_IRQ_PRIO +#define NVIC_TIM3_DAC_IRQ_PRIO 2 +#define NVIC_TIMx_DAC_IRQ_PRIO 2 +#else +#define NVIC_TIMx_DAC_IRQ_PRIO NVIC_TIM6_DAC_IRQ_PRIO +#endif +#endif + +PRINT_CONFIG_MSG_VALUE("SPEKTRUM_TIMER: " , SPEKTRUM_TIMER) #ifdef NVIC_UART_IRQ_PRIO #define NVIC_PRIMARY_UART_PRIO NVIC_UART_IRQ_PRIO @@ -136,13 +177,10 @@ int8_t SpektrumSigns[] = RADIO_CONTROL_SPEKTRUM_SIGNS; /* Parser state variables */ static uint8_t EncodingType = 0; static uint8_t ExpectedFrames = 0; -/* initialise the uarts used by the parser */ -void SpektrumUartInit(void); + /* initialise the timer used by the parser to ensure sync */ void SpektrumTimerInit(void); -void tim6_irq_handler(void); - /** Set polarity using RC_POLARITY_GPIO. * SBUS signal has a reversed polarity compared to normal UART * this allows to using hardware UART peripheral by changing @@ -289,6 +327,8 @@ void radio_control_impl_init(void) static inline void SpektrumParser(uint8_t _c, SpektrumStateType *spektrum_state, bool_t secondary_receiver) { + + uint16_t ChannelData; uint8_t TimedOut; static uint8_t TmpEncType = 0; /* 0 = 10bit, 1 = 11 bit */ @@ -299,7 +339,7 @@ static inline void SpektrumParser(uint8_t _c, SpektrumStateType *spektrum_state, /* If we have just started the resync process or */ /* if we have recieved a character before our */ /* 7ms wait has finished */ - if ((spektrum_state->ReSync == 1) || + if ((spektrum_state->ReSync == 1) || ((spektrum_state->Sync == 0) && (!TimedOut))) { spektrum_state->ReSync = 0; @@ -310,6 +350,7 @@ static inline void SpektrumParser(uint8_t _c, SpektrumStateType *spektrum_state, spektrum_state->SecondFrame = 0; return; } +//LED_OFF(1); /* the first byte of a new frame. It was received */ /* more than 7ms after the last received byte. */ @@ -503,55 +544,56 @@ void RadioControlEventImp(void (*frame_handler)(void)) /***************************************************************************** * - * Initialise TIM6 to fire an interrupt every 100 microseconds to provide + * Initialise TIMx to fire an interrupt every 100 microseconds to provide * timebase for SpektrumParser * *****************************************************************************/ void SpektrumTimerInit(void) { - /* enable TIM6 clock */ - rcc_periph_clock_enable(RCC_TIM6); + /* enable TIMx clock */ + rcc_periph_clock_enable(RCC_TIMx); - /* TIM6 configuration, always counts up */ - timer_set_mode(TIM6, TIM_CR1_CKD_CK_INT, 0, 0); + timer_reset(TIMx); + /* TIMx configuration, always counts up */ + timer_set_mode(TIMx, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // used to be 0 0 /* 100 microseconds ie 0.1 millisecond */ - timer_set_period(TIM6, TIM_TICS_FOR_100us - 1); - uint32_t tim6_clk = timer_get_frequency(TIM6); + timer_set_period(TIMx, TIM_TICS_FOR_100us - 1); + uint32_t TIMx_clk = timer_get_frequency(TIMx); /* timer ticks with 1us */ - timer_set_prescaler(TIM6, ((tim6_clk / ONE_MHZ) - 1)); + timer_set_prescaler(TIMx, ((TIMx_clk / ONE_MHZ) - 1)); - /* Enable TIM6 interrupts */ + /* Enable TIMx interrupts */ #ifdef STM32F1 - nvic_set_priority(NVIC_TIM6_IRQ, NVIC_TIM6_IRQ_PRIO); - nvic_enable_irq(NVIC_TIM6_IRQ); + nvic_set_priority(NVIC_TIMx_IRQ, NVIC_TIMx_IRQ_PRIO); + nvic_enable_irq(NVIC_TIMx_IRQ); #elif defined STM32F4 - /* the define says DAC IRQ, but it is also the global TIM6 IRQ*/ - nvic_set_priority(NVIC_TIM6_DAC_IRQ, NVIC_TIM6_DAC_IRQ_PRIO); - nvic_enable_irq(NVIC_TIM6_DAC_IRQ); + /* the define says DAC IRQ, but it is also the global TIMx IRQ*/ + nvic_set_priority(NVIC_TIMx_DAC_IRQ, NVIC_TIMx_DAC_IRQ_PRIO); + nvic_enable_irq(NVIC_TIMx_DAC_IRQ); #endif - /* Enable TIM6 Update interrupt */ - timer_enable_irq(TIM6, TIM_DIER_UIE); - timer_clear_flag(TIM6, TIM_SR_UIF); + /* Enable TIMx Update interrupt */ + timer_enable_irq(TIMx, TIM_DIER_UIE); + timer_clear_flag(TIMx, TIM_SR_UIF); - /* TIM6 enable counter */ - timer_enable_counter(TIM6); + /* TIMx enable counter */ + timer_enable_counter(TIMx); } /***************************************************************************** * - * TIM6 interrupt request handler updates times used by SpektrumParser + * TIMx interrupt request handler updates times used by SpektrumParser * *****************************************************************************/ #ifdef STM32F1 -void tim6_isr(void) +void TIMx_ISR(void) { #elif defined STM32F4 -void tim6_dac_isr(void) { +void TIMx_DAC_ISR(void) { #endif - timer_clear_flag(TIM6, TIM_SR_UIF); + timer_clear_flag(TIMx, TIM_SR_UIF); if (PrimarySpektrumState.SpektrumTimer) { --PrimarySpektrumState.SpektrumTimer; @@ -582,7 +624,7 @@ void SpektrumUartInit(void) { gpio_setup_pin_af(PrimaryUart(_BANK), PrimaryUart(_PIN), PrimaryUart(_AF), FALSE); /* Configure Primary UART */ - usart_set_baudrate(PrimaryUart(_DEV), 115200); + usart_set_baudrate(PrimaryUart(_DEV), B115200); usart_set_databits(PrimaryUart(_DEV), 8); usart_set_stopbits(PrimaryUart(_DEV), USART_STOPBITS_1); usart_set_parity(PrimaryUart(_DEV), USART_PARITY_NONE); @@ -609,7 +651,7 @@ void SpektrumUartInit(void) { gpio_setup_pin_af(SecondaryUart(_BANK), SecondaryUart(_PIN), SecondaryUart(_AF), FALSE); /* Configure secondary UART */ - usart_set_baudrate(SecondaryUart(_DEV), 115200); + usart_set_baudrate(SecondaryUart(_DEV), B115200); usart_set_databits(SecondaryUart(_DEV), 8); usart_set_stopbits(SecondaryUart(_DEV), USART_STOPBITS_1); usart_set_parity(SecondaryUart(_DEV), USART_PARITY_NONE); @@ -701,7 +743,7 @@ void SecondaryUart(_ISR)(void) { * *****************************************************************************/ void radio_control_spektrum_try_bind(void) { - +#ifdef SPEKTRUM_BIND_PIN_PORT #ifdef SPEKTRUM_BIND_PIN_HIGH /* Init GPIO for the bind pin, we enable the pulldown resistor. * (esden) As far as I can tell only navstick is using the PIN LOW version of @@ -727,6 +769,7 @@ void radio_control_spektrum_try_bind(void) { if (gpio_get(SPEKTRUM_BIND_PIN_PORT, SPEKTRUM_BIND_PIN) != 0) { return; } +#endif #endif /* Master receiver Rx push-pull */ diff --git a/sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.h b/sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.h index caf21ae9d2..99971b0bda 100644 --- a/sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.h +++ b/sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.h @@ -79,5 +79,7 @@ #endif extern void RadioControlEventImp(void (*_received_frame_handler)(void)); +/* initialise the uarts used by the parser */ +void SpektrumUartInit(void); #endif /* RADIO_CONTROL_SPEKTRUM_ARCH_H */ diff --git a/sw/airborne/boards/px4fmu_2.4.h b/sw/airborne/boards/px4fmu_2.4.h index 4e9cd7853f..8c491502dd 100644 --- a/sw/airborne/boards/px4fmu_2.4.h +++ b/sw/airborne/boards/px4fmu_2.4.h @@ -4,14 +4,14 @@ #define BOARD_PX4FMU_v2 /* Pixhawk board (PX4FMUv2 has a 24MHz external clock and 168MHz internal. */ +//STM32F4 #define EXT_CLK 24000000 #define AHB_CLK 168000000 - /* * Onboard LEDs */ -/* red/amber , on PE12 */ +/* red, on PE12 */ #ifndef USE_LED_1 #define USE_LED_1 1 #endif @@ -23,13 +23,6 @@ /* * UART - */ -/* -#define UART1_GPIO_AF GPIO_AF7 -#define UART1_GPIO_PORT_RX GPIOA -#define UART1_GPIO_RX GPIO9 -#define UART1_GPIO_PORT_TX GPIOA -#define UART1_GPIO_TX GPIO10 */ //OK // conector telem1 @@ -156,24 +149,19 @@ // SDIO_CMD pd2 /* Onboard ADCs */ -#define USE_AD_TIM4 1 - -#define BOARD_ADC_CHANNEL_1 11 -#define BOARD_ADC_CHANNEL_2 12 -#define BOARD_ADC_CHANNEL_3 13 -#define BOARD_ADC_CHANNEL_4 10 +#define USE_AD_TIM5 1 /* provide defines that can be used to access the ADC_x in the code or airframe file * these directly map to the index number of the 4 adc channels defined above * 4th (index 3) is used for bat monitoring by default */ -#if USE_ADC_1 -#define AD1_1_CHANNEL 11 -#define ADC_1 AD1_1 -#define ADC_1_GPIO_PORT GPIOC -#define ADC_1_GPIO_PIN GPIO1 -#endif +//#if USE_ADC_1 +//#define AD1_1_CHANNEL 11 +//#define ADC_1 AD1_1 +//#define ADC_1_GPIO_PORT GPIOC +//#define ADC_1_GPIO_PIN GPIO1 +//#endif /* #if USE_ADC_2 #define AD1_2_CHANNEL 12 @@ -185,18 +173,19 @@ //OK current sens #if USE_ADC_3 -#define AD1_3_CHANNEL 13 +#define AD1_3_CHANNEL 3 #define ADC_3 AD1_3 #define ADC_3_GPIO_PORT GPIOA #define ADC_3_GPIO_PIN GPIO3 #endif +#define MilliAmpereOfAdc(adc)((float)adc) * (3.3f / 4096.0f) * (90.0f / 5.0f) // Internal ADC for battery enabled by default #ifndef USE_ADC_4 #define USE_ADC_4 1 #endif #if USE_ADC_4 -#define AD1_4_CHANNEL 10 +#define AD1_4_CHANNEL 2 #define ADC_4 AD1_4 #define ADC_4_GPIO_PORT GPIOA #define ADC_4_GPIO_PIN GPIO2 @@ -206,7 +195,7 @@ #ifndef ADC_CHANNEL_VSUPPLY #define ADC_CHANNEL_VSUPPLY ADC_4 #endif -#define DefaultVoltageOfAdc(adc) (0.006185*adc) +#define DefaultVoltageOfAdc(adc) (0.00975f*adc) // value comes from px4 code sensors.cpp _parameters.battery_voltage_scaling = 0.0082f; Manual calib on iris = 0.0096... /* @@ -229,45 +218,6 @@ #define I2C3_GPIO_SDA GPIO9 */ -/* - * PPM - */ - - -#define USE_PPM_TIM1 1 - -#define PPM_CHANNEL TIM_IC1 -#define PPM_TIMER_INPUT TIM_IC_IN_TI1 -#define PPM_IRQ NVIC_TIM1_CC_IRQ -#define PPM_IRQ2 NVIC_TIM1_UP_TIM10_IRQ -// Capture/Compare InteruptEnable and InterruptFlag -#define PPM_CC_IE TIM_DIER_CC1IE -#define PPM_CC_IF TIM_SR_CC1IF -#define PPM_GPIO_PORT GPIOA -#define PPM_GPIO_PIN GPIO10 -#define PPM_GPIO_AF GPIO_AF1 - -/* - * Spektrum - */ -/* The line that is pulled low at power up to initiate the bind process */ -/* GPIO_EXT1 on PX4FMU */ - -/* -#define SPEKTRUM_BIND_PIN GPIO4 -#define SPEKTRUM_BIND_PIN_PORT GPIOC -*/ -/* -#define SPEKTRUM_UART2_RCC RCC_USART2 -#define SPEKTRUM_UART2_BANK GPIOA -#define SPEKTRUM_UART2_PIN GPIO3 -#define SPEKTRUM_UART2_AF GPIO_AF7 -#define SPEKTRUM_UART2_IRQ NVIC_USART2_IRQ -#define SPEKTRUM_UART2_ISR usart2_isr -#define SPEKTRUM_UART2_DEV USART2 -*/ - - /* Activate onboard baro by default */ #ifndef USE_BARO_BOARD #define USE_BARO_BOARD 1 @@ -290,6 +240,7 @@ #define USE_PWM4 1 #define USE_PWM5 1 #define USE_PWM6 1 +//#define USE_BUZZER 1 // Servo numbering on the PX4 starts with 1 // PWM_SERVO_x is the index of the servo in the actuators_pwm_values array @@ -372,8 +323,7 @@ #define PWM_SERVO_6_OC_BIT 0 #endif -//Buzzer -/* +//Buzzer (alarm) #if USE_BUZZER #define PWM_BUZZER #define PWM_BUZZER_TIMER TIM2 @@ -385,11 +335,9 @@ #else #define PWM_BUZZER_OC_BIT 0 #endif -*/ - #define PWM_TIM1_CHAN_MASK (PWM_SERVO_1_OC_BIT|PWM_SERVO_2_OC_BIT|PWM_SERVO_3_OC_BIT|PWM_SERVO_4_OC_BIT) -//#define PWM_TIM2_CHAN_MASK (PWM_BUZZER_OC_BIT) +#define PWM_TIM2_CHAN_MASK (PWM_BUZZER_OC_BIT) #define PWM_TIM4_CHAN_MASK (PWM_SERVO_5_OC_BIT|PWM_SERVO_6_OC_BIT) #endif /* CONFIG_PX4FMU_2_4_H */ diff --git a/sw/airborne/boards/px4io_2.4.h b/sw/airborne/boards/px4io_2.4.h new file mode 100644 index 0000000000..c205e033bb --- /dev/null +++ b/sw/airborne/boards/px4io_2.4.h @@ -0,0 +1,243 @@ +#ifndef CONFIG_PX4IO_2_4_H +#define CONFIG_PX4IO_2_4_H + +#define BOARD_PX4IO +//STM32F103c8t6 (medium density!) + +/* Pixhawk board (PX4FIOv2 has a 24MHz external clock and 24MHz internal. */ +#define EXT_CLK 24000000 //this osc is actually outside of the specs (max 16MHz) +#define AHB_CLK 24000000 + + +/* + * LEDs + */ +/* blue led, a.k.a. ACT */ +#ifndef USE_LED_1 +#define USE_LED_1 1 +#endif +#define LED_1_GPIO GPIOB +#define LED_1_GPIO_PIN GPIO14 +#define LED_1_GPIO_ON gpio_clear +#define LED_1_GPIO_OFF gpio_set +#define LED_1_AFIO_REMAP ((void)0) + +//led Amber a.k.a b/e led +#ifndef USE_LED_2 +#define USE_LED_2 1 +#endif +#define LED_2_GPIO GPIOB +#define LED_2_GPIO_PIN GPIO15 +#define LED_2_GPIO_ON gpio_clear +#define LED_2_GPIO_OFF gpio_set +#define LED_2_AFIO_REMAP ((void)0) + +//safety led in the switch, red +#ifndef USE_LED_3 +#define USE_LED_3 1 +#endif +#define LED_3_GPIO GPIOB +#define LED_3_GPIO_PIN GPIO13 +#define LED_3_GPIO_ON gpio_clear +#define LED_3_GPIO_OFF gpio_set +#define LED_3_AFIO_REMAP ((void)0) + +//TODO: safety switch is on PB5! + +/* + * UART +*/ + +// fmu debug / spektrum receiver (only rx) +#define UART1_GPIO_AF 0 +#define UART1_GPIO_PORT_RX GPIOA +#define UART1_GPIO_RX GPIO10 +#define UART1_GPIO_PORT_TX GPIOA +#define UART1_GPIO_TX GPIO9 +// intermcu fmu +#define UART2_GPIO_AF 0 +#define UART2_GPIO_PORT_RX GPIOA +#define UART2_GPIO_RX GPIO3 +#define UART2_GPIO_PORT_TX GPIOA +#define UART2_GPIO_TX GPIO2 + + +/* + * Spektrum + */ +/* The line that is pulled low at power up to initiate the bind process */ +#define SPEKTRUM_POWER_PIN_PORT GPIOC +#define SPEKTRUM_POWER_PIN GPIO13 + +#define SPEKTRUM_TIMER 3 + +#define SPEKTRUM_UART1_RCC RCC_USART1 +#define SPEKTRUM_UART1_BANK GPIOA +#define SPEKTRUM_UART1_PIN GPIO10 +#define SPEKTRUM_UART1_AF 0 +#define SPEKTRUM_UART1_IRQ NVIC_USART1_IRQ +#define SPEKTRUM_UART1_ISR usart1_isr +#define SPEKTRUM_UART1_DEV USART1 + + +/* + * PPM input + */ +#define USE_PPM_TIM1 1 +#define PPM_CHANNEL TIM_IC1 +#define PPM_TIMER_INPUT TIM_IC_IN_TI1 +#define PPM_IRQ NVIC_TIM1_UP_IRQ +#define PPM_IRQ2 NVIC_TIM1_CC_IRQ +// Capture/Compare InteruptEnable and InterruptFlag +#define PPM_CC_IE TIM_DIER_CC1IE +#define PPM_CC_IF TIM_SR_CC1IF +#define PPM_GPIO_PORT GPIOA +#define PPM_GPIO_PIN GPIO8 +#define PPM_GPIO_AF 0 + +//#define USE_AD_TIM1 1 +#ifndef USE_ADC_1 +#define USE_ADC_1 0 +#endif +#if USE_ADC_1 // VDD servo ADC12_IN4, untested +#define AD1_1_CHANNEL 12 +#define ADC_1 AD1_4 +#define ADC_1_GPIO_PORT GPIOA +#define ADC_1_GPIO_PIN GPIO4 +#endif + +/* + * PWM + * + */ +//sevo outputs on px4io f1: +//chn: 1 2 3 4 5 6 7 8 +//pin: A0 A1 B8 B9 A6 A7 B0 B1 +//timer/channel: 2/1 2/2 4/3 4/4 3/1 3/2 3/3 3/4 +#define PWM_USE_TIM2 1 +//#define PWM_USE_TIM3 1 // spektrum already uses tim3 +#define PWM_USE_TIM4 1 + +//#define ACTUATORS_PWM_NB 4 + +#define USE_PWM1 1 +#define USE_PWM2 1 +#define USE_PWM3 1 +#define USE_PWM4 1 +//#define USE_PWM5 1 +//#define USE_PWM6 1 +//#define USE_PWM7 1 +//#define USE_PWM8 1 + +// PWM_SERVO_x is the index of the servo in the actuators_pwm_values array +#if USE_PWM1 +#define PWM_SERVO_1 0 +#define PWM_SERVO_1_TIMER TIM2 +#define PWM_SERVO_1_GPIO GPIOA +#define PWM_SERVO_1_PIN GPIO0 +#define PWM_SERVO_1_AF 0 +#define PWM_SERVO_1_OC TIM_OC1 +#define PWM_SERVO_1_OC_BIT (1<<0) +#else +#define PWM_SERVO_1_OC_BIT 0 +#endif + +#if USE_PWM2 +#define PWM_SERVO_2 1 +#define PWM_SERVO_2_TIMER TIM2 +#define PWM_SERVO_2_GPIO GPIOA +#define PWM_SERVO_2_PIN GPIO1 +#define PWM_SERVO_2_AF 0 +#define PWM_SERVO_2_OC TIM_OC2 +#define PWM_SERVO_2_OC_BIT (1<<1) +#else +#define PWM_SERVO_2_OC_BIT 0 +#endif + +#if USE_PWM3 +#define PWM_SERVO_3 2 +#define PWM_SERVO_3_TIMER TIM4 +#define PWM_SERVO_3_GPIO GPIOB +#define PWM_SERVO_3_PIN GPIO8 +#define PWM_SERVO_3_AF 0 +#define PWM_SERVO_3_OC TIM_OC3 +#define PWM_SERVO_3_OC_BIT (1<<2) +#else +#define PWM_SERVO_3_OC_BIT 0 +#endif + +#if USE_PWM4 +#define PWM_SERVO_4 3 +#define PWM_SERVO_4_TIMER TIM4 +#define PWM_SERVO_4_GPIO GPIOB +#define PWM_SERVO_4_PIN GPIO9 +#define PWM_SERVO_4_AF 0 +#define PWM_SERVO_4_OC TIM_OC4 +#define PWM_SERVO_4_OC_BIT (1<<3) +#else +#define PWM_SERVO_4_OC_BIT 0 +#endif + +#if USE_PWM5 +#define PWM_SERVO_5 4 +#define PWM_SERVO_5_TIMER TIM3 +#define PWM_SERVO_5_GPIO GPIOA +#define PWM_SERVO_5_PIN GPIO6 +#define PWM_SERVO_5_AF 0 +#define PWM_SERVO_5_OC TIM_OC1 +#define PWM_SERVO_5_OC_BIT (1<<0) +#else +#define PWM_SERVO_5_OC_BIT 0 +#endif + +#if USE_PWM6 +#define PWM_SERVO_6 5 +#define PWM_SERVO_6_TIMER TIM3 +#define PWM_SERVO_6_GPIO GPIOA +#define PWM_SERVO_6_PIN GPIO7 +#define PWM_SERVO_6_AF 0 +#define PWM_SERVO_6_OC TIM_OC2 +#define PWM_SERVO_6_OC_BIT (1<<1) +#else +#define PWM_SERVO_6_OC_BIT 0 +#endif + +#if USE_PWM7 +#define PWM_SERVO_7 6 +#define PWM_SERVO_7_TIMER TIM3 +#define PWM_SERVO_7_GPIO GPIOB +#define PWM_SERVO_7_PIN GPIO0 +#define PWM_SERVO_7_AF 0 +#define PWM_SERVO_7_OC TIM_OC3 +#define PWM_SERVO_7_OC_BIT (1<<2) +#else +#define PWM_SERVO_7_OC_BIT 0 +#endif + +#if USE_PWM8 +#define PWM_SERVO_8 7 +#define PWM_SERVO_8_TIMER TIM3 +#define PWM_SERVO_8_GPIO GPIOB +#define PWM_SERVO_8_PIN GPIO1 +#define PWM_SERVO_8_AF 0 +#define PWM_SERVO_8_OC TIM_OC4 +#define PWM_SERVO_8_OC_BIT (1<<3) +#else +#define PWM_SERVO_8_OC_BIT 0 +#endif + +/* servos 1-2 on TIM2 */ +#define PWM_TIM2_CHAN_MASK (PWM_SERVO_1_OC_BIT|PWM_SERVO_2_OC_BIT) +/* servos 3-4 on TIM4 */ +#define PWM_TIM4_CHAN_MASK (PWM_SERVO_3_OC_BIT|PWM_SERVO_4_OC_BIT) +/* servos 5-8 on TIM3 */ +//#define PWM_TIM3_CHAN_MASK (PWM_SERVO_5_OC_BIT|PWM_SERVO_6_OC_BIT|PWM_SERVO_7_OC_BIT|PWM_SERVO_8_OC_BIT) + +/* Default actuators driver */ +#define DEFAULT_ACTUATORS "subsystems/actuators/actuators_pwm.h" +#define ActuatorDefaultSet(_x,_y) ActuatorPwmSet(_x,_y) +#define ActuatorsDefaultInit() ActuatorsPwmInit() +#define ActuatorsDefaultCommit() ActuatorsPwmCommit() + + +#endif /* CONFIG_PX4IO_2_4_H */ diff --git a/sw/airborne/firmwares/rotorcraft/main_fbw.c b/sw/airborne/firmwares/rotorcraft/main_fbw.c index 7b528073d4..94ecee3a95 100644 --- a/sw/airborne/firmwares/rotorcraft/main_fbw.c +++ b/sw/airborne/firmwares/rotorcraft/main_fbw.c @@ -47,7 +47,8 @@ #include "firmwares/rotorcraft/main_fbw.h" #include "firmwares/rotorcraft/autopilot_rc_helpers.h" -//#include "generated/modules.h" +#define MODULES_C +#include "generated/modules.h" /** Fly by wire modes */ typedef enum {FBW_MODE_MANUAL = 0, FBW_MODE_AUTO = 1, FBW_MODE_FAILSAFE = 2} fbw_mode_enum; @@ -59,7 +60,7 @@ fbw_mode_enum fbw_mode; //PRINT_CONFIG_VAR(MODULES_FREQUENCY) tid_t main_periodic_tid; ///< id for main_periodic() timer -//tid_t modules_tid; ///< id for modules_periodic_task() timer +tid_t modules_tid; ///< id for modules_periodic_task() timer tid_t radio_control_tid; ///< id for radio_control_periodic_task() timer tid_t electrical_tid; ///< id for electrical_periodic() timer tid_t telemetry_tid; ///< id for telemetry_periodic() timer @@ -85,17 +86,17 @@ STATIC_INLINE void main_init(void) mcu_init(); + actuators_init(); + electrical_init(); - actuators_init(); #if USE_MOTOR_MIXING motor_mixing_init(); #endif radio_control_init(); - // TODO - //modules_init(); + modules_init(); mcu_int_enable(); @@ -103,7 +104,7 @@ STATIC_INLINE void main_init(void) // register the timers for the periodic functions main_periodic_tid = sys_time_register_timer((1. / PERIODIC_FREQUENCY), NULL); -// modules_tid = sys_time_register_timer(1. / MODULES_FREQUENCY, NULL); + modules_tid = sys_time_register_timer(1. / MODULES_FREQUENCY, NULL); radio_control_tid = sys_time_register_timer((1. / 60.), NULL); electrical_tid = sys_time_register_timer(0.1, NULL); telemetry_tid = sys_time_register_timer((1. / 20.), NULL); @@ -115,13 +116,15 @@ STATIC_INLINE void main_init(void) STATIC_INLINE void handle_periodic_tasks(void) { + + if (sys_time_check_and_ack_timer(main_periodic_tid)) { main_periodic(); } - //if (sys_time_check_and_ack_timer(modules_tid)) { - // TODO - //modules_periodic_task(); - //} + if (sys_time_check_and_ack_timer(modules_tid)) { + + modules_periodic_task(); + } if (sys_time_check_and_ack_timer(radio_control_tid)) { radio_control_periodic_task(); } @@ -175,9 +178,17 @@ STATIC_INLINE void main_periodic(void) } } + + static uint16_t dv = 0; + // TODO make module out of led blink? /* set failsafe commands */ if (fbw_mode == FBW_MODE_FAILSAFE) { SetCommands(commands_failsafe); + if (!(dv++ % (PERIODIC_FREQUENCY / 20))) { LED_TOGGLE(FBW_MODE_LED);} + } else if (fbw_mode == FBW_MODE_MANUAL) { + if (!(dv++ % (PERIODIC_FREQUENCY))) { LED_TOGGLE(FBW_MODE_LED);} + } else if (fbw_mode == FBW_MODE_AUTO) { + LED_TOGGLE(FBW_MODE_LED); // toggle instead of on, because then it is still visible when fbw_mode switches very fast } /* set actuators */ @@ -208,6 +219,7 @@ static void autopilot_on_rc_frame(void) /* if manual */ if (fbw_mode == FBW_MODE_MANUAL) { + autopilot_motors_on = TRUE; #ifdef SetCommandsFromRC SetCommandsFromRC(commands, radio_control.values); #else @@ -216,13 +228,15 @@ static void autopilot_on_rc_frame(void) } /* Forward radiocontrol to AP */ - intermcu_on_rc_frame(); + intermcu_on_rc_frame(fbw_mode); } static void autopilot_on_ap_command(void) { if (fbw_mode != FBW_MODE_MANUAL) { SetCommands(intermcu_commands); + } else { + autopilot_motors_on = TRUE; } } @@ -237,6 +251,6 @@ STATIC_INLINE void main_event(void) // InterMCU InterMcuEvent(autopilot_on_ap_command); - // TODO Modules - //modules_event_task(); + //Modules + modules_event_task(); } diff --git a/sw/airborne/mcu.c b/sw/airborne/mcu.c index 8dc94e6733..6136658415 100644 --- a/sw/airborne/mcu.c +++ b/sw/airborne/mcu.c @@ -83,7 +83,7 @@ void mcu_init(void) led_init(); #endif /* for now this means using spektrum */ -#if defined RADIO_CONTROL & defined RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT & defined RADIO_CONTROL_BIND_IMPL_FUNC +#if defined RADIO_CONTROL & defined RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT & defined RADIO_CONTROL_BIND_IMPL_FUNC & defined SPEKTRUM_BIND_PIN_PORT RADIO_CONTROL_BIND_IMPL_FUNC(); #endif #if USE_UART0 diff --git a/sw/airborne/mcu_periph/uart.h b/sw/airborne/mcu_periph/uart.h index 22be5f5800..615906af87 100644 --- a/sw/airborne/mcu_periph/uart.h +++ b/sw/airborne/mcu_periph/uart.h @@ -66,7 +66,7 @@ struct uart_periph { uint8_t tx_buf[UART_TX_BUFFER_SIZE]; uint16_t tx_insert_idx; uint16_t tx_extract_idx; - uint8_t tx_running; + volatile uint8_t tx_running; /** UART Register */ void *reg_addr; /** UART Baudrate */ diff --git a/sw/airborne/modules/px4io_flash/protocol.h b/sw/airborne/modules/px4io_flash/protocol.h new file mode 100644 index 0000000000..0317d7211e --- /dev/null +++ b/sw/airborne/modules/px4io_flash/protocol.h @@ -0,0 +1,390 @@ +/**************************************************************************** + * + * Copyright (c) 2012-2014 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#pragma once + +#define __STDC_FORMAT_MACROS +#include "std.h" + +/** + * @file protocol.h + * + * PX4IO interface protocol. + * + * Communication is performed via writes to and reads from 16-bit virtual + * registers organised into pages of 255 registers each. + * + * The first two bytes of each write select a page and offset address + * respectively. Subsequent reads and writes increment the offset within + * the page. + * + * Some pages are read- or write-only. + * + * Note that some pages may permit offset values greater than 255, which + * can only be achieved by long writes. The offset does not wrap. + * + * Writes to unimplemented registers are ignored. Reads from unimplemented + * registers return undefined values. + * + * As convention, values that would be floating point in other parts of + * the PX4 system are expressed as signed integer values scaled by 10000, + * e.g. control values range from -10000..10000. Use the REG_TO_SIGNED and + * SIGNED_TO_REG macros to convert between register representation and + * the signed version, and REG_TO_FLOAT/FLOAT_TO_REG to convert to float. + * + * Note that the implementation of readable pages prefers registers within + * readable pages to be densely packed. Page numbers do not need to be + * packed. + * + * Definitions marked [1] are only valid on PX4IOv1 boards. Likewise, + * [2] denotes definitions specific to the PX4IOv2 board. + */ + +/* Per C, this is safe for all 2's complement systems */ +#define REG_TO_SIGNED(_reg) ((int16_t)(_reg)) +#define SIGNED_TO_REG(_signed) ((uint16_t)(_signed)) + +#define REG_TO_FLOAT(_reg) ((float)REG_TO_SIGNED(_reg) / 10000.0f) +#define FLOAT_TO_REG(_float) SIGNED_TO_REG((int16_t)((_float) * 10000.0f)) + +#define PX4IO_PROTOCOL_VERSION 4 + +/* maximum allowable sizes on this protocol version */ +#define PX4IO_PROTOCOL_MAX_CONTROL_COUNT 8 /**< The protocol does not support more than set here, individual units might support less - see PX4IO_P_CONFIG_CONTROL_COUNT */ + +/* static configuration page */ +#define PX4IO_PAGE_CONFIG 0 +#define PX4IO_P_CONFIG_PROTOCOL_VERSION 0 /* PX4IO_PROTOCOL_VERSION */ +#define PX4IO_P_CONFIG_HARDWARE_VERSION 1 /* magic numbers TBD */ +#define PX4IO_P_CONFIG_BOOTLOADER_VERSION 2 /* get this how? */ +#define PX4IO_P_CONFIG_MAX_TRANSFER 3 /* maximum I2C transfer size */ +#define PX4IO_P_CONFIG_CONTROL_COUNT 4 /* hardcoded max control count supported */ +#define PX4IO_P_CONFIG_ACTUATOR_COUNT 5 /* hardcoded max actuator output count */ +#define PX4IO_P_CONFIG_RC_INPUT_COUNT 6 /* hardcoded max R/C input count supported */ +#define PX4IO_P_CONFIG_ADC_INPUT_COUNT 7 /* hardcoded max ADC inputs */ +#define PX4IO_P_CONFIG_RELAY_COUNT 8 /* hardcoded # of relay outputs */ +#define PX4IO_P_CONFIG_CONTROL_GROUP_COUNT 8 /**< hardcoded # of control groups*/ + +/* dynamic status page */ +#define PX4IO_PAGE_STATUS 1 +#define PX4IO_P_STATUS_FREEMEM 0 +#define PX4IO_P_STATUS_CPULOAD 1 + +#define PX4IO_P_STATUS_FLAGS 2 /* monitoring flags */ +#define PX4IO_P_STATUS_FLAGS_OUTPUTS_ARMED (1 << 0) /* arm-ok and locally armed */ +#define PX4IO_P_STATUS_FLAGS_OVERRIDE (1 << 1) /* in manual override */ +#define PX4IO_P_STATUS_FLAGS_RC_OK (1 << 2) /* RC input is valid */ +#define PX4IO_P_STATUS_FLAGS_RC_PPM (1 << 3) /* PPM input is valid */ +#define PX4IO_P_STATUS_FLAGS_RC_DSM (1 << 4) /* DSM input is valid */ +#define PX4IO_P_STATUS_FLAGS_RC_SBUS (1 << 5) /* SBUS input is valid */ +#define PX4IO_P_STATUS_FLAGS_FMU_OK (1 << 6) /* controls from FMU are valid */ +#define PX4IO_P_STATUS_FLAGS_RAW_PWM (1 << 7) /* raw PWM from FMU is bypassing the mixer */ +#define PX4IO_P_STATUS_FLAGS_MIXER_OK (1 << 8) /* mixer is OK */ +#define PX4IO_P_STATUS_FLAGS_ARM_SYNC (1 << 9) /* the arming state between IO and FMU is in sync */ +#define PX4IO_P_STATUS_FLAGS_INIT_OK (1 << 10) /* initialisation of the IO completed without error */ +#define PX4IO_P_STATUS_FLAGS_FAILSAFE (1 << 11) /* failsafe is active */ +#define PX4IO_P_STATUS_FLAGS_SAFETY_OFF (1 << 12) /* safety is off */ +#define PX4IO_P_STATUS_FLAGS_FMU_INITIALIZED (1 << 13) /* FMU was initialized and OK once */ +#define PX4IO_P_STATUS_FLAGS_RC_ST24 (1 << 14) /* ST24 input is valid */ +#define PX4IO_P_STATUS_FLAGS_RC_SUMD (1 << 15) /* SUMD input is valid */ + +#define PX4IO_P_STATUS_ALARMS 3 /* alarm flags - alarms latch, write 1 to a bit to clear it */ +#define PX4IO_P_STATUS_ALARMS_VBATT_LOW (1 << 0) /* [1] VBatt is very close to regulator dropout */ +#define PX4IO_P_STATUS_ALARMS_TEMPERATURE (1 << 1) /* board temperature is high */ +#define PX4IO_P_STATUS_ALARMS_SERVO_CURRENT (1 << 2) /* [1] servo current limit was exceeded */ +#define PX4IO_P_STATUS_ALARMS_ACC_CURRENT (1 << 3) /* [1] accessory current limit was exceeded */ +#define PX4IO_P_STATUS_ALARMS_FMU_LOST (1 << 4) /* timed out waiting for controls from FMU */ +#define PX4IO_P_STATUS_ALARMS_RC_LOST (1 << 5) /* timed out waiting for RC input */ +#define PX4IO_P_STATUS_ALARMS_PWM_ERROR (1 << 6) /* PWM configuration or output was bad */ +#define PX4IO_P_STATUS_ALARMS_VSERVO_FAULT (1 << 7) /* [2] VServo was out of the valid range (2.5 - 5.5 V) */ + +#define PX4IO_P_STATUS_VBATT 4 /* [1] battery voltage in mV */ +#define PX4IO_P_STATUS_IBATT 5 /* [1] battery current (raw ADC) */ +#define PX4IO_P_STATUS_VSERVO 6 /* [2] servo rail voltage in mV */ +#define PX4IO_P_STATUS_VRSSI 7 /* [2] RSSI voltage */ +#define PX4IO_P_STATUS_PRSSI 8 /* [2] RSSI PWM value */ + +#define PX4IO_P_STATUS_MIXER 9 /* mixer actuator limit flags */ +#define PX4IO_P_STATUS_MIXER_LOWER_LIMIT (1 << 0) /**< at least one actuator output has reached lower limit */ +#define PX4IO_P_STATUS_MIXER_UPPER_LIMIT (1 << 1) /**< at least one actuator output has reached upper limit */ +#define PX4IO_P_STATUS_MIXER_YAW_LIMIT (1 << 2) /**< yaw control is limited because it causes output clipping */ + +/* array of post-mix actuator outputs, -10000..10000 */ +#define PX4IO_PAGE_ACTUATORS 2 /* 0..CONFIG_ACTUATOR_COUNT-1 */ + +/* array of PWM servo output values, microseconds */ +#define PX4IO_PAGE_SERVOS 3 /* 0..CONFIG_ACTUATOR_COUNT-1 */ + +/* array of raw RC input values, microseconds */ +#define PX4IO_PAGE_RAW_RC_INPUT 4 +#define PX4IO_P_RAW_RC_COUNT 0 /* number of valid channels */ +#define PX4IO_P_RAW_RC_FLAGS 1 /* RC detail status flags */ +#define PX4IO_P_RAW_RC_FLAGS_FRAME_DROP (1 << 0) /* single frame drop */ +#define PX4IO_P_RAW_RC_FLAGS_FAILSAFE (1 << 1) /* receiver is in failsafe mode */ +#define PX4IO_P_RAW_RC_FLAGS_RC_DSM11 (1 << 2) /* DSM decoding is 11 bit mode */ +#define PX4IO_P_RAW_RC_FLAGS_MAPPING_OK (1 << 3) /* Channel mapping is ok */ +#define PX4IO_P_RAW_RC_FLAGS_RC_OK (1 << 4) /* RC reception ok */ + +#define PX4IO_P_RAW_RC_NRSSI 2 /* [2] Normalized RSSI value, 0: no reception, 255: perfect reception */ +#define PX4IO_P_RAW_RC_DATA 3 /* [1] + [2] Details about the RC source (PPM frame length, Spektrum protocol type) */ +#define PX4IO_P_RAW_FRAME_COUNT 4 /* Number of total received frames (wrapping counter) */ +#define PX4IO_P_RAW_LOST_FRAME_COUNT 5 /* Number of total dropped frames (wrapping counter) */ +#define PX4IO_P_RAW_RC_BASE 6 /* CONFIG_RC_INPUT_COUNT channels from here */ + +/* array of scaled RC input values, -10000..10000 */ +#define PX4IO_PAGE_RC_INPUT 5 +#define PX4IO_P_RC_VALID 0 /* bitmask of valid controls */ +#define PX4IO_P_RC_BASE 1 /* CONFIG_RC_INPUT_COUNT controls from here */ + +/* array of raw ADC values */ +#define PX4IO_PAGE_RAW_ADC_INPUT 6 /* 0..CONFIG_ADC_INPUT_COUNT-1 */ + +/* PWM servo information */ +#define PX4IO_PAGE_PWM_INFO 7 +#define PX4IO_RATE_MAP_BASE 0 /* 0..CONFIG_ACTUATOR_COUNT bitmaps of PWM rate groups */ + +/* setup page */ +#define PX4IO_PAGE_SETUP 50 +#define PX4IO_P_SETUP_FEATURES 0 +#define PX4IO_P_SETUP_FEATURES_SBUS1_OUT (1 << 0) /**< enable S.Bus v1 output */ +#define PX4IO_P_SETUP_FEATURES_SBUS2_OUT (1 << 1) /**< enable S.Bus v2 output */ +#define PX4IO_P_SETUP_FEATURES_PWM_RSSI (1 << 2) /**< enable PWM RSSI parsing */ +#define PX4IO_P_SETUP_FEATURES_ADC_RSSI (1 << 3) /**< enable ADC RSSI parsing */ + +#define PX4IO_P_SETUP_ARMING 1 /* arming controls */ +#define PX4IO_P_SETUP_ARMING_IO_ARM_OK (1 << 0) /* OK to arm the IO side */ +#define PX4IO_P_SETUP_ARMING_FMU_ARMED (1 << 1) /* FMU is already armed */ +#define PX4IO_P_SETUP_ARMING_MANUAL_OVERRIDE_OK (1 << 2) /* OK to switch to manual override via override RC channel */ +#define PX4IO_P_SETUP_ARMING_FAILSAFE_CUSTOM (1 << 3) /* use custom failsafe values, not 0 values of mixer */ +#define PX4IO_P_SETUP_ARMING_INAIR_RESTART_OK (1 << 4) /* OK to try in-air restart */ +#define PX4IO_P_SETUP_ARMING_ALWAYS_PWM_ENABLE (1 << 5) /* Output of PWM right after startup enabled to help ESCs initialize and prevent them from beeping */ +#define PX4IO_P_SETUP_ARMING_RC_HANDLING_DISABLED (1 << 6) /* Disable the IO-internal evaluation of the RC */ +#define PX4IO_P_SETUP_ARMING_LOCKDOWN (1 << 7) /* If set, the system operates normally, but won't actuate any servos */ +#define PX4IO_P_SETUP_ARMING_FORCE_FAILSAFE (1 << 8) /* If set, the system will always output the failsafe values */ +#define PX4IO_P_SETUP_ARMING_TERMINATION_FAILSAFE (1 << 9) /* If set, the system will never return from a failsafe, but remain in failsafe once triggered. */ +#define PX4IO_P_SETUP_ARMING_OVERRIDE_IMMEDIATE (1 << 10) /* If set then on FMU failure override is immediate. Othewise it waits for the mode switch to go past the override thrshold */ + +#define PX4IO_P_SETUP_PWM_RATES 2 /* bitmask, 0 = low rate, 1 = high rate */ +#define PX4IO_P_SETUP_PWM_DEFAULTRATE 3 /* 'low' PWM frame output rate in Hz */ +#define PX4IO_P_SETUP_PWM_ALTRATE 4 /* 'high' PWM frame output rate in Hz */ + +#if defined(CONFIG_ARCH_BOARD_PX4IO_V1) || defined(CONFIG_ARCH_BOARD_PX4FMU_V1) +#define PX4IO_P_SETUP_RELAYS 5 /* bitmask of relay/switch outputs, 0 = off, 1 = on */ +#define PX4IO_P_SETUP_RELAYS_POWER1 (1<<0) /* hardware rev [1] power relay 1 */ +#define PX4IO_P_SETUP_RELAYS_POWER2 (1<<1) /* hardware rev [1] power relay 2 */ +#define PX4IO_P_SETUP_RELAYS_ACC1 (1<<2) /* hardware rev [1] accessory power 1 */ +#define PX4IO_P_SETUP_RELAYS_ACC2 (1<<3) /* hardware rev [1] accessory power 2 */ +#else +#define PX4IO_P_SETUP_RELAYS_PAD 5 +#endif + +#define PX4IO_P_SETUP_VBATT_SCALE 6 /* hardware rev [1] battery voltage correction factor (float) */ +#define PX4IO_P_SETUP_VSERVO_SCALE 6 /* hardware rev [2] servo voltage correction factor (float) */ +#define PX4IO_P_SETUP_DSM 7 /* DSM bind state */ +enum { /* DSM bind states */ + dsm_bind_power_down = 0, + dsm_bind_power_up, + dsm_bind_set_rx_out, + dsm_bind_send_pulses, + dsm_bind_reinit_uart +}; +/* 8 */ +#define PX4IO_P_SETUP_SET_DEBUG 9 /* debug level for IO board */ + +#define PX4IO_P_SETUP_REBOOT_BL 10 /* reboot IO into bootloader */ +#define PX4IO_REBOOT_BL_MAGIC 14662 /* required argument for reboot (random) */ + +#define PX4IO_P_SETUP_CRC 11 /* get CRC of IO firmware */ +/* storage space of 12 occupied by CRC */ +#define PX4IO_P_SETUP_FORCE_SAFETY_OFF 12 /* force safety switch into + 'armed' (PWM enabled) state - this is a non-data write and + hence index 12 can safely be used. */ +#define PX4IO_P_SETUP_RC_THR_FAILSAFE_US 13 /**< the throttle failsafe pulse length in microseconds */ + +#define PX4IO_P_SETUP_FORCE_SAFETY_ON 14 /* force safety switch into 'disarmed' (PWM disabled state) */ +#define PX4IO_FORCE_SAFETY_MAGIC 22027 /* required argument for force safety (random) */ + +#define PX4IO_P_SETUP_PWM_REVERSE 15 /**< Bitmask to reverse PWM channels 1-8 */ +#define PX4IO_P_SETUP_TRIM_ROLL 16 /**< Roll trim, in actuator units */ +#define PX4IO_P_SETUP_TRIM_PITCH 17 /**< Pitch trim, in actuator units */ +#define PX4IO_P_SETUP_TRIM_YAW 18 /**< Yaw trim, in actuator units */ + +/* autopilot control values, -10000..10000 */ +#define PX4IO_PAGE_CONTROLS 51 /**< actuator control groups, one after the other, 8 wide */ +#define PX4IO_P_CONTROLS_GROUP_0 (PX4IO_PROTOCOL_MAX_CONTROL_COUNT * 0) /**< 0..PX4IO_PROTOCOL_MAX_CONTROL_COUNT - 1 */ +#define PX4IO_P_CONTROLS_GROUP_1 (PX4IO_PROTOCOL_MAX_CONTROL_COUNT * 1) /**< 0..PX4IO_PROTOCOL_MAX_CONTROL_COUNT - 1 */ +#define PX4IO_P_CONTROLS_GROUP_2 (PX4IO_PROTOCOL_MAX_CONTROL_COUNT * 2) /**< 0..PX4IO_PROTOCOL_MAX_CONTROL_COUNT - 1 */ +#define PX4IO_P_CONTROLS_GROUP_3 (PX4IO_PROTOCOL_MAX_CONTROL_COUNT * 3) /**< 0..PX4IO_PROTOCOL_MAX_CONTROL_COUNT - 1 */ + +#define PX4IO_P_CONTROLS_GROUP_VALID 64 +#define PX4IO_P_CONTROLS_GROUP_VALID_GROUP0 (1 << 0) /**< group 0 is valid / received */ +#define PX4IO_P_CONTROLS_GROUP_VALID_GROUP1 (1 << 1) /**< group 1 is valid / received */ +#define PX4IO_P_CONTROLS_GROUP_VALID_GROUP2 (1 << 2) /**< group 2 is valid / received */ +#define PX4IO_P_CONTROLS_GROUP_VALID_GROUP3 (1 << 3) /**< group 3 is valid / received */ + +/* raw text load to the mixer parser - ignores offset */ +#define PX4IO_PAGE_MIXERLOAD 52 + +/* R/C channel config */ +#define PX4IO_PAGE_RC_CONFIG 53 /**< R/C input configuration */ +#define PX4IO_P_RC_CONFIG_MIN 0 /**< lowest input value */ +#define PX4IO_P_RC_CONFIG_CENTER 1 /**< center input value */ +#define PX4IO_P_RC_CONFIG_MAX 2 /**< highest input value */ +#define PX4IO_P_RC_CONFIG_DEADZONE 3 /**< band around center that is ignored */ +#define PX4IO_P_RC_CONFIG_ASSIGNMENT 4 /**< mapped input value */ +#define PX4IO_P_RC_CONFIG_ASSIGNMENT_MODESWITCH 100 /**< magic value for mode switch */ +#define PX4IO_P_RC_CONFIG_OPTIONS 5 /**< channel options bitmask */ +#define PX4IO_P_RC_CONFIG_OPTIONS_ENABLED (1 << 0) +#define PX4IO_P_RC_CONFIG_OPTIONS_REVERSE (1 << 1) +#define PX4IO_P_RC_CONFIG_STRIDE 6 /**< spacing between channel config data */ + +/* PWM output - overrides mixer */ +#define PX4IO_PAGE_DIRECT_PWM 54 /**< 0..CONFIG_ACTUATOR_COUNT-1 */ + +/* PWM failsafe values - zero disables the output */ +#define PX4IO_PAGE_FAILSAFE_PWM 55 /**< 0..CONFIG_ACTUATOR_COUNT-1 */ + +/* PWM failsafe values - zero disables the output */ +#define PX4IO_PAGE_SENSORS 56 /**< Sensors connected to PX4IO */ +#define PX4IO_P_SENSORS_ALTITUDE 0 /**< Altitude of an external sensor (HoTT or S.BUS2) */ + +/* Debug and test page - not used in normal operation */ +#define PX4IO_PAGE_TEST 127 +#define PX4IO_P_TEST_LED 0 /**< set the amber LED on/off */ + +/* PWM minimum values for certain ESCs */ +#define PX4IO_PAGE_CONTROL_MIN_PWM 106 /**< 0..CONFIG_ACTUATOR_COUNT-1 */ + +/* PWM maximum values for certain ESCs */ +#define PX4IO_PAGE_CONTROL_MAX_PWM 107 /**< 0..CONFIG_ACTUATOR_COUNT-1 */ + +/* PWM disarmed values that are active, even when SAFETY_SAFE */ +#define PX4IO_PAGE_DISARMED_PWM 108 /* 0..CONFIG_ACTUATOR_COUNT-1 */ + +/** + * As-needed mixer data upload. + * + * This message adds text to the mixer text buffer; the text + * buffer is drained as the definitions are consumed. + */ +#pragma pack(push, 1) +struct px4io_mixdata { + uint16_t f2i_mixer_magic; +#define F2I_MIXER_MAGIC 0x6d74 + + uint8_t action; +#define F2I_MIXER_ACTION_RESET 0 +#define F2I_MIXER_ACTION_APPEND 1 + + char text[0]; /* actual text size may vary */ +}; +#pragma pack(pop) + +/** + * Serial protocol encapsulation. + */ + +#define PKT_MAX_REGS 32 // by agreement w/FMU + +#pragma pack(push, 1) +struct IOPacket { + uint8_t count_code; + uint8_t crc; + uint8_t page; + uint8_t offset; + uint16_t regs[PKT_MAX_REGS]; +}; +#pragma pack(pop) + +#define PKT_CODE_READ 0x00 /* FMU->IO read transaction */ +#define PKT_CODE_WRITE 0x40 /* FMU->IO write transaction */ +#define PKT_CODE_SUCCESS 0x00 /* IO->FMU success reply */ +#define PKT_CODE_CORRUPT 0x40 /* IO->FMU bad packet reply */ +#define PKT_CODE_ERROR 0x80 /* IO->FMU register op error reply */ + +#define PKT_CODE_MASK 0xc0 +#define PKT_COUNT_MASK 0x3f + +#define PKT_COUNT(_p) ((_p).count_code & PKT_COUNT_MASK) +#define PKT_CODE(_p) ((_p).count_code & PKT_CODE_MASK) +#define PKT_SIZE(_p) ((size_t)((uint8_t *)&((_p).regs[PKT_COUNT(_p)]) - ((uint8_t *)&(_p)))) + +static const uint8_t crc8_tab[256] __attribute__((unused)) = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, + 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, + 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, + 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, + 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, + 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, + 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, + 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, + 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, + 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, + 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, + 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, + 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, + 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, + 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, + 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, + 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 +}; + +static uint8_t crc_packet(struct IOPacket *pkt) __attribute__((unused)); +static uint8_t +crc_packet(struct IOPacket *pkt) +{ + uint8_t *end = (uint8_t *)(&pkt->regs[PKT_COUNT(*pkt)]); + uint8_t *p = (uint8_t *)pkt; + uint8_t c = 0; + + while (p < end) { + c = crc8_tab[c ^ * (p++)]; + } + + return c; +} diff --git a/sw/airborne/modules/px4io_flash/px4io_flash.c b/sw/airborne/modules/px4io_flash/px4io_flash.c new file mode 100644 index 0000000000..cba0de8b51 --- /dev/null +++ b/sw/airborne/modules/px4io_flash/px4io_flash.c @@ -0,0 +1,258 @@ +/* + * Copyright (C) Kevin van Hecke + * + * This file is part of paparazzi + * + * paparazzi 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 2, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, see + * . + */ +/** + * @file "modules/px4io_flash/px4io_flash.c" + * @author Kevin van Hecke + * Flashes the px4io f1 through the px4 bootloader. + * Assumes the telem2 port on the Pixhawk is connected to a ttyACM device (blackmagic probe) + */ + +#include "modules/px4io_flash/px4io_flash.h" +//#include "subsystems/datalink/downlink.h" +#include "modules/px4io_flash/protocol.h" +#include "mcu_periph/sys_time_arch.h" +#include "subsystems/intermcu/intermcu_ap.h" + +// Serial Port +#include "mcu_periph/uart.h" + +// define coms link for px4io f1 +#define PX4IO_PORT (&((PX4IO_UART).device)) +#define TELEM2_PORT (&((TELEM2_UART).device)) + +// weird that these below are not in protocol.h, which is from the firmware px4 repo +// below is copied from qgroundcontrol: +#define PROTO_INSYNC 0x12 ///< 'in sync' byte sent before status +#define PROTO_EOC 0x20 ///< end of command +// Reply bytes +#define PROTO_OK 0x10 ///< INSYNC/OK - 'ok' response +#define PROTO_FAILED 0x11 ///< INSYNC/FAILED - 'fail' response +#define PROTO_INVALID 0x13 ///< INSYNC/INVALID - 'invalid' response for bad commands +// Command bytes +#define PROTO_GET_SYNC 0x21 ///< NOP for re-establishing sync +#define PROTO_GET_DEVICE 0x22 ///< get device ID bytes +#define PROTO_CHIP_ERASE 0x23 ///< erase program area and reset program address +#define PROTO_LOAD_ADDRESS 0x24 ///< set next programming address +#define PROTO_PROG_MULTI 0x27 ///< write bytes at program address and increment +#define PROTO_GET_CRC 0x29 ///< compute & return a CRC +#define PROTO_BOOT 0x30 ///< boot the application + +bool_t setToBootloaderMode; + +void px4ioflash_init(void) +{ + setToBootloaderMode = FALSE; +} + +void px4ioflash_event(void) +{ + // setToBootloaderMode=true; + if (PX4IO_PORT->char_available(PX4IO_PORT->periph)) { + if (!setToBootloaderMode) { + //ignore anything coming from IO if not in bootloader mode (which should be nothing) + } else { + //relay everything from IO to the laptop + unsigned char b = PX4IO_PORT->get_byte(PX4IO_PORT->periph); + TELEM2_PORT->put_byte(TELEM2_PORT->periph, b); + } + } + + //TODO: check if timeout was surpassed + if (TELEM2_PORT->char_available(TELEM2_PORT->periph) && !setToBootloaderMode) { + //data was received on the pc uart, so + //stop all intermcu comminication: + disable_inter_comm(true); + //send the reboot to bootloader command: + + /* + * The progdieshit define is very usefull, if for whatever reason the (normal, not bootloader) firmware on the IO chip became disfunct. + * In that case: + * 1. enable this define + * 2. build and upload the fmu f4 chip (ap target in pprz center) + * 3. build the io code, and convert the firmware using the following command: + * /home/houjebek/paparazzi/sw/tools/pixhawk/px_mkfw.py --prototype "/home/houjebek/px4/Firmware/Images/px4io-v2.prototype" --image /home/houjebek/paparazzi/var/aircrafts/Iris/fbw/fbw.bin > /home/houjebek/paparazzi/var/aircrafts/Iris/fbw/fbw.px4 + * 4. Start the following command: + * /home/houjebek/paparazzi/sw/tools/pixhawk/px_uploader.py --port "/dev/serial/by-id/usb-FTDI_TTL232R-3V3_FT906KBO-if00-port0" /home/houjebek/paparazzi/var/aircrafts/Iris/fbw/fbw.px4 + * 5a. Either, boot the Pixhawk (reconnect usb) holding the IO reset button until the FMU led stops blinking fast (i.e. exits its own bootloader) + * 5b Or, press the IO reset button on the pixhawk + * 6. Watch the output of the command of step 4, it should recognize the IO bootloader and start flashing. If not try repeating step 5a. + * 7. Don forget to disable the define and upload the ap again :) + */ + //#define progdieshit + +#ifndef progdieshit + static struct IOPacket dma_packet; + dma_packet.count_code = 0x40 + 0x01; + dma_packet.crc = 0; + dma_packet.page = PX4IO_PAGE_SETUP; + dma_packet.offset = PX4IO_P_SETUP_REBOOT_BL; + dma_packet.regs[0] = PX4IO_REBOOT_BL_MAGIC; + dma_packet.crc = crc_packet(&dma_packet); + struct IOPacket *pkt = &dma_packet; + uint8_t *p = (uint8_t *)pkt; + PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[0]); + PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[1]); + PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[2]); + PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[3]); + PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[4]); + PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[5]); + + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'E'); + // for (int i=0;i<6;i++) { + // unsigned char tmp[3]; + // itoa(p[i],tmp,16); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,tmp[0]); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,tmp[1]); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r'); + // } + + sys_time_usleep(5000); // this seems to be close to the minimum delay necessary to process this packet at the IO side + //the pixhawk IO chip should respond with: + // 0x00 ( PKT_CODE_SUCCESS ) + // 0xe5 + // 0x32 + // 0x0a + //After that, the IO chips reboots into bootloader mode, in which it will stay for a short period + //The baudrate in bootloader mode ic changed to 115200 (normal operating baud is 1500000, at least for original pixhawk fmu firmware) + + //state machine + int state = 0; + while (state < 4 && PX4IO_PORT->char_available(PX4IO_PORT->periph)) { + + unsigned char b = PX4IO_PORT->get_byte(PX4IO_PORT->periph); + switch (state) { + case (0) : + if (b == PKT_CODE_SUCCESS) { state++; } else { state = 0; } + break; + case (1) : + if (b == 0xe5) { state++; } else { state = 0; } + break; + case (2) : + if (b == 0x32) { state++; } else { state = 0; } + break; + case (3) : + if (b == 0x0a) { state++; } else { state = 0; } + break; + default : + TELEM2_PORT->put_byte(TELEM2_PORT->periph, 'b'); + break; + } + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'S'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,state+48); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r'); + } +#else + int state = 4; +#endif + if (state == 4) { +#ifndef progdieshit + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'S'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'6'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r'); +#endif + uart_periph_set_baudrate(PX4IO_PORT->periph, B115200); + /* look for the bootloader for 150 ms */ + int ret = 0; + for (int i = 0; i < 15 && !ret ; i++) { + sys_time_usleep(10000); + + + //send a get_sync command in order to keep the io in bootloader mode + PX4IO_PORT->put_byte(PX4IO_PORT->periph, PROTO_GET_SYNC); + PX4IO_PORT->put_byte(PX4IO_PORT->periph, PROTO_EOC); + + +#ifndef progdieshit + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'S'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'6'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'a'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r'); +#endif + + //get_sync should be replied with, so check if that happens and + //all other bytes are discarded, hopefully those were not important + //(they may be caused by sending multiple syncs) + while (PX4IO_PORT->char_available(PX4IO_PORT->periph)) { + unsigned char b = PX4IO_PORT->get_byte(PX4IO_PORT->periph); + +#ifndef progdieshit + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'S'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'6'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'b'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r'); +#endif + + if (b == PROTO_INSYNC) { +#ifndef progdieshit + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'S'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'7'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r'); +#endif + + setToBootloaderMode = true; + ret = 1; + break; + } + } + } + if (setToBootloaderMode) { + +#ifndef progdieshit + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'S'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'8'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r'); +#endif + + //if successfully entered bootloader mode, clear any remaining bytes (which may have a function, but I did not check) + while (PX4IO_PORT->char_available(PX4IO_PORT->periph)) {PX4IO_PORT->get_byte(PX4IO_PORT->periph);} + } + +#ifndef progdieshit + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'S'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'9'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r'); +#endif + + } else { + TELEM2_PORT->put_byte(TELEM2_PORT->periph, 'E'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'r'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'r'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'o'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'r'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n'); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r'); + } + } else if (TELEM2_PORT->char_available(TELEM2_PORT->periph)) { + //already in bootloader mode, just directly relay data + unsigned char b = TELEM2_PORT->get_byte(TELEM2_PORT->periph); + PX4IO_PORT->put_byte(PX4IO_PORT->periph, b); + // TELEM2_PORT->put_byte(TELEM2_PORT->periph,b); + } + +} + diff --git a/sw/airborne/modules/px4io_flash/px4io_flash.h b/sw/airborne/modules/px4io_flash/px4io_flash.h new file mode 100644 index 0000000000..6e315e4f33 --- /dev/null +++ b/sw/airborne/modules/px4io_flash/px4io_flash.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) Kevin van Hecke + * + * This file is part of paparazzi + * + * paparazzi 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 2, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, see + * . + */ +/** + * @file "modules/px4io_flash/px4io_flash.h" + * @author Kevin van Hecke + * Flashes the px4io f1 through the px4 bootloader. + */ + +#ifndef PX4IO_FLASH_H +#define PX4IO_FLASH_H + +extern void px4ioflash_init(void); +extern void px4ioflash_event(void); + +#endif + diff --git a/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind.c b/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind.c new file mode 100644 index 0000000000..82213df990 --- /dev/null +++ b/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) Kevin van Hecke + * + * This file is part of paparazzi + * + * paparazzi 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 2, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, see + * . + */ +/** + * @file "modules/spektrum_soft_bind/spektrum_soft_bind.c" + * @author Kevin van Hecke + * Puts Spektrum in binding mode through software + */ + +#include "modules/spektrum_soft_bind/spektrum_soft_bind_fbw.h" + +void spektrum_soft_bind_init() {} + + diff --git a/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind.h b/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind.h new file mode 100644 index 0000000000..0b1289d0a3 --- /dev/null +++ b/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) Kevin van Hecke + * + * This file is part of paparazzi + * + * paparazzi 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 2, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, see + * . + */ +/** + * @file "modules/spektrum_soft_bind/spektrum_soft_bind.h" + * @author Kevin van Hecke + * Puts Spektrum in binding mode through software + */ + +#ifndef SPEKTRUM_SOFT_BIND_H +#define SPEKTRUM_SOFT_BIND_H + +#if defined FBW +#include "modules/spektrum_soft_bind/spektrum_soft_bind_fbw.h" +#else +#include "modules/spektrum_soft_bind/spektrum_soft_bind_ap.h" +#endif + +#endif + diff --git a/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind_ap.c b/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind_ap.c new file mode 100644 index 0000000000..e87f977742 --- /dev/null +++ b/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind_ap.c @@ -0,0 +1,38 @@ +/* + * Copyright (C) Kevin van Hecke + * + * This file is part of paparazzi + * + * paparazzi 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 2, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, see + * . + */ +/** + * @file "modules/spektrum_soft_bind/spektrum_soft_bind_ap.c" + * @author Kevin van Hecke + * Puts Spektrum in binding mode through software + */ + +#include "modules/spektrum_soft_bind/spektrum_soft_bind_ap.h" +#include "subsystems/intermcu/intermcu_ap.h" +#include "led.h" + +void spektrum_soft_bind_init(void) {} + +uint8_t bind_soft_value; +void spektrum_soft_bind_click(uint8_t val __attribute__((unused))) +{ + intermcu_send_spektrum_bind(); +} + + diff --git a/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind_ap.h b/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind_ap.h new file mode 100644 index 0000000000..6cfcbde3ff --- /dev/null +++ b/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind_ap.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) Kevin van Hecke + * + * This file is part of paparazzi + * + * paparazzi 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 2, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, see + * . + */ +/** + * @file "modules/spektrum_soft_bind/spektrum_soft_bind_ap.h" + * @author Kevin van Hecke + * Puts Spektrum in binding mode through software + */ + +#ifndef SPEKTRUM_AP_SOFT_BIND_H +#define SPEKTRUM_AP_SOFT_BIND_H + +#include "std.h" + +extern void spektrum_soft_bind_init(void); +extern void spektrum_soft_bind_click(uint8_t val); + +extern uint8_t bind_soft_value; + +#endif + diff --git a/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind_fbw.c b/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind_fbw.c new file mode 100644 index 0000000000..1496f27fad --- /dev/null +++ b/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind_fbw.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) Kevin van Hecke + * + * This file is part of paparazzi + * + * paparazzi 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 2, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, see + * . + */ +/** + * @file "modules/spektrum_soft_bind/spektrum_soft_bind_fbw.c" + * @author Kevin van Hecke + * Puts Spektrum in binding mode through software + */ + +#include "modules/spektrum_soft_bind/spektrum_soft_bind_fbw.h" +#include "subsystems/intermcu/intermcu_fbw.h" +#include "mcu.h" +#include "subsystems/radio_control.h" +#include "mcu_periph/sys_time_arch.h" + +#include "led.h" +#include "mcu_periph/gpio.h" + +void spektrum_soft_bind_init(void) +{ + gpio_setup_output(SPEKTRUM_POWER_PIN_PORT, SPEKTRUM_POWER_PIN); + gpio_set(SPEKTRUM_POWER_PIN_PORT, SPEKTRUM_POWER_PIN); +} + +void received_spektrum_soft_bind(void) +{ + + //power cycle the spektrum + gpio_clear(SPEKTRUM_POWER_PIN_PORT, SPEKTRUM_POWER_PIN); + sys_time_usleep(100000); + gpio_set(SPEKTRUM_POWER_PIN_PORT, SPEKTRUM_POWER_PIN); + + //put to bind mode + RADIO_CONTROL_BIND_IMPL_FUNC(); //basically = radio_control_spektrum_try_bind() + + SpektrumUartInit(); + +} diff --git a/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind_fbw.h b/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind_fbw.h new file mode 100644 index 0000000000..dcb262b003 --- /dev/null +++ b/sw/airborne/modules/spektrum_soft_bind/spektrum_soft_bind_fbw.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) Kevin van Hecke + * + * This file is part of paparazzi + * + * paparazzi 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 2, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, see + * . + */ +/** + * @file "modules/spektrum_soft_bind/spektrum_soft_bind_fbw.h" + * @author Kevin van Hecke + * Puts Spektrum in binding mode through software + */ + +#ifndef SPEKTRUM_FBW_SOFT_BIND_H +#define SPEKTRUM_FBW_SOFT_BIND_H +#include "std.h" + +extern void spektrum_soft_bind_init(void); +extern void received_spektrum_soft_bind(void); + +#endif + diff --git a/sw/airborne/subsystems/datalink/w5100.h b/sw/airborne/subsystems/datalink/w5100.h index 33cb150a13..360cb695cf 100644 --- a/sw/airborne/subsystems/datalink/w5100.h +++ b/sw/airborne/subsystems/datalink/w5100.h @@ -55,7 +55,7 @@ struct w5100_periph { volatile uint16_t tx_extract_idx[W5100_BUFFER_NUM]; volatile uint8_t work_tx[4]; volatile uint8_t work_rx[4]; - uint8_t tx_running; + volatile uint8_t tx_running; /** Generic device interface */ struct link_device device; }; @@ -90,7 +90,8 @@ static inline void w5100_read_buffer(struct pprz_transport *t) #define W5100CheckAndParse(_dev, _trans) w5100_check_and_parse(&(_dev).device, &(_trans)) -static inline void w5100_check_and_parse(struct link_device *dev, struct pprz_transport *trans) { +static inline void w5100_check_and_parse(struct link_device *dev, struct pprz_transport *trans) +{ if (dev->char_available(dev->periph)) { w5100_read_buffer(trans); if (trans->trans_rx.msg_received) { diff --git a/sw/airborne/subsystems/intermcu.h b/sw/airborne/subsystems/intermcu.h index d57047293a..eff1a9fcee 100644 --- a/sw/airborne/subsystems/intermcu.h +++ b/sw/airborne/subsystems/intermcu.h @@ -33,7 +33,9 @@ #define INTERMCU_AP 0 #define INTERMCU_FBW 1 +#ifndef INTERMCU_LOST_CNT #define INTERMCU_LOST_CNT 25 /* 50ms with a 512Hz timer TODO fixed value */ +#endif enum intermcu_status { INTERMCU_OK, diff --git a/sw/airborne/subsystems/intermcu/intermcu_ap.c b/sw/airborne/subsystems/intermcu/intermcu_ap.c index e9862cef18..7f4b5c68f2 100644 --- a/sw/airborne/subsystems/intermcu/intermcu_ap.c +++ b/sw/airborne/subsystems/intermcu/intermcu_ap.c @@ -30,6 +30,10 @@ #include "pprzlink/pprz_transport.h" #include "mcu_periph/uart.h" +#include "subsystems/datalink/telemetry.h" +#include "subsystems/electrical.h" +#include "autopilot.h" + #if COMMANDS_NB > 8 #error "INTERMCU UART CAN ONLY SEND 8 COMMANDS OR THE UART WILL BE OVERFILLED" #endif @@ -41,9 +45,21 @@ static struct pprz_transport intermcu_transport; struct intermcu_t inter_mcu; static inline void intermcu_parse_msg(struct transport_rx *trans, void (*rc_frame_handler)(void)); + + +static void send_status(struct transport_tx *trans, struct link_device *dev) +{ + pprz_msg_send_FBW_STATUS(trans, dev, AC_ID, + &(radio_control.status), &(radio_control.frame_rate), &(inter_mcu.status), &electrical.vsupply, + &electrical.current); // due to limitation of GCS, send the electrical from ap as if it comes from fbw... +} + void intermcu_init(void) { pprz_transport_init(&intermcu_transport); + + register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_FBW_STATUS, send_status); + } void intermcu_periodic(void) @@ -56,12 +72,28 @@ void intermcu_periodic(void) } } +static bool_t disable_comm; +void disable_inter_comm(bool_t value) +{ + disable_comm = value; +} + void intermcu_set_actuators(pprz_t *command_values, uint8_t ap_mode __attribute__((unused))) { - pprz_msg_send_IMCU_COMMANDS(&(intermcu_transport.trans_tx), intermcu_device, - INTERMCU_AP, 0, COMMANDS_NB, command_values); //TODO: Fix status + if (!disable_comm) { + pprz_msg_send_IMCU_COMMANDS(&(intermcu_transport.trans_tx), intermcu_device, + INTERMCU_AP, &autopilot_motors_on, COMMANDS_NB, command_values); //TODO: Append more status + } } +void intermcu_send_spektrum_bind(void) +{ + if (!disable_comm) { + pprz_msg_send_IMCU_SPEKTRUM_SOFT_BIND(&(intermcu_transport.trans_tx), intermcu_device, INTERMCU_AP); + } +} + + static inline void intermcu_parse_msg(struct transport_rx *trans, void (*rc_frame_handler)(void)) { /* Parse the Inter MCU message */ @@ -70,6 +102,7 @@ static inline void intermcu_parse_msg(struct transport_rx *trans, void (*rc_fram case DL_IMCU_RADIO_COMMANDS: { uint8_t i; uint8_t size = DL_IMCU_RADIO_COMMANDS_values_length(trans->payload); + inter_mcu.status = DL_IMCU_RADIO_COMMANDS_status(trans->payload); int16_t *rc_values = DL_IMCU_RADIO_COMMANDS_values(trans->payload); for (i = 0; i < size; i++) { radio_control.values[i] = rc_values[i]; @@ -92,14 +125,16 @@ static inline void intermcu_parse_msg(struct transport_rx *trans, void (*rc_fram void RadioControlEvent(void (*frame_handler)(void)) { - /* Parse incoming bytes */ - if (intermcu_device->char_available(intermcu_device->periph)) { - while (intermcu_device->char_available(intermcu_device->periph) && !intermcu_transport.trans_rx.msg_received) { - parse_pprz(&intermcu_transport, intermcu_device->get_byte(intermcu_device->periph)); - } + if (!disable_comm) { + /* Parse incoming bytes */ + if (intermcu_device->char_available(intermcu_device->periph)) { + while (intermcu_device->char_available(intermcu_device->periph) && !intermcu_transport.trans_rx.msg_received) { + parse_pprz(&intermcu_transport, intermcu_device->get_byte(intermcu_device->periph)); + } - if (intermcu_transport.trans_rx.msg_received) { - intermcu_parse_msg(&(intermcu_transport.trans_rx), frame_handler); + if (intermcu_transport.trans_rx.msg_received) { + intermcu_parse_msg(&(intermcu_transport.trans_rx), frame_handler); + } } } } diff --git a/sw/airborne/subsystems/intermcu/intermcu_ap.h b/sw/airborne/subsystems/intermcu/intermcu_ap.h index 4898978fbc..6cee9f703c 100644 --- a/sw/airborne/subsystems/intermcu/intermcu_ap.h +++ b/sw/airborne/subsystems/intermcu/intermcu_ap.h @@ -32,24 +32,20 @@ void intermcu_set_actuators(pprz_t *command_values, uint8_t ap_mode); void RadioControlEvent(void (*frame_handler)(void)); +void intermcu_send_spektrum_bind(void); +void disable_inter_comm(bool_t value); /* We need radio defines for the Autopilot */ #define RADIO_THROTTLE 0 #define RADIO_ROLL 1 #define RADIO_PITCH 2 #define RADIO_YAW 3 -#define RADIO_GEAR 4 -#define RADIO_FLAP 5 +#define RADIO_MODE 4 +#define RADIO_KILL_SWITCH 5 #define RADIO_AUX1 5 #define RADIO_AUX2 6 #define RADIO_AUX3 7 #define RADIO_CONTROL_NB_CHANNEL 8 -#ifndef RADIO_MODE -#define RADIO_MODE RADIO_GEAR -#endif -//#ifndef RADIO_KILL_SWITCH -//#define RADIO_KILL_SWITCH RADIO_FLAP -//#endif #endif /* INTERMCU_AP_ROTORCRAFT_H */ diff --git a/sw/airborne/subsystems/intermcu/intermcu_fbw.c b/sw/airborne/subsystems/intermcu/intermcu_fbw.c index f97a34badb..068e5df276 100644 --- a/sw/airborne/subsystems/intermcu/intermcu_fbw.c +++ b/sw/airborne/subsystems/intermcu/intermcu_fbw.c @@ -29,6 +29,18 @@ #include "subsystems/radio_control.h" #include "mcu_periph/uart.h" #include "pprzlink/pprz_transport.h" +#include "modules/spektrum_soft_bind/spektrum_soft_bind_fbw.h" + +#ifdef BOARD_PX4IO +#include "libopencm3/cm3/scb.h" +#include "led.h" +#include "mcu_periph/sys_time.h" +static uint8_t px4RebootSequence[] = {0x41, 0xd7, 0x32, 0x0a, 0x46, 0x39}; +static uint8_t px4RebootSequenceCount = 0; +static bool_t px4RebootTimeout = FALSE; +uint8_t autopilot_motors_on = FALSE; +tid_t px4bl_tid; ///< id for time out of the px4 bootloader reset +#endif #if RADIO_CONTROL_NB_CHANNEL > 8 #undef RADIO_CONTROL_NB_CHANNEL @@ -43,10 +55,15 @@ static struct pprz_transport intermcu_transport; struct intermcu_t inter_mcu; pprz_t intermcu_commands[COMMANDS_NB]; static inline void intermcu_parse_msg(struct transport_rx *trans, void (*commands_frame_handler)(void)); +static inline void checkPx4RebootCommand(unsigned char b); void intermcu_init(void) { pprz_transport_init(&intermcu_transport); +#ifdef BOARD_PX4IO + px4bl_tid = sys_time_register_timer(20.0, NULL); +#endif + } void intermcu_periodic(void) @@ -59,10 +76,38 @@ void intermcu_periodic(void) } } -void intermcu_on_rc_frame(void) +void intermcu_on_rc_frame(uint8_t fbw_mode) { + + pprz_t values[8]; + + values[INTERMCU_RADIO_THROTTLE] = radio_control.values[RADIO_THROTTLE]; + values[INTERMCU_RADIO_ROLL] = radio_control.values[RADIO_ROLL]; + values[INTERMCU_RADIO_PITCH] = radio_control.values[RADIO_PITCH]; + values[INTERMCU_RADIO_YAW] = radio_control.values[RADIO_YAW]; +#ifdef RADIO_MODE + values[INTERMCU_RADIO_MODE] = radio_control.values[RADIO_MODE]; +#endif +#ifdef RADIO_KILL_SWITCH + values[INTERMCU_RADIO_KILL_SWITCH] = radio_control.values[RADIO_KILL]; +#endif + +#if defined (RADIO_AUX1) && defined (RADIO_KILL_SWITCH) +#warning "RC AUX1 and KILL_SWITCH are on the same channel." +#endif + +#ifdef RADIO_AUX1 + values[INTERMCU_RADIO_AUX1] = radio_control.values[RADIO_AUX1]; +#endif +#ifdef RADIO_AUX2 + values[INTERMCU_RADIO_AUX2] = radio_control.values[RADIO_AUX2]; +#endif +#ifdef RADIO_AUX3 + values[INTERMCU_RADIO_AUX2] = radio_control.values[RADIO_AUX2]; +#endif + pprz_msg_send_IMCU_RADIO_COMMANDS(&(intermcu_transport.trans_tx), intermcu_device, - INTERMCU_FBW, 0, RADIO_CONTROL_NB_CHANNEL, radio_control.values); //TODO: Fix status + INTERMCU_FBW, &fbw_mode, RADIO_CONTROL_NB_CHANNEL, values); } void intermcu_send_status(uint8_t mode) @@ -81,6 +126,8 @@ static inline void intermcu_parse_msg(struct transport_rx *trans, void (*command uint8_t i; uint8_t size = DL_IMCU_COMMANDS_values_length(trans->payload); int16_t *new_commands = DL_IMCU_COMMANDS_values(trans->payload); + uint8_t status = DL_IMCU_COMMANDS_status(trans->payload); + autopilot_motors_on = status & 0x1; for (i = 0; i < size; i++) { intermcu_commands[i] = new_commands[i]; } @@ -91,6 +138,11 @@ static inline void intermcu_parse_msg(struct transport_rx *trans, void (*command break; } +#if defined(SPEKTRUM_HAS_SOFT_BIND_PIN) //TODO: make subscribable module parser + case DL_IMCU_SPEKTRUM_SOFT_BIND: + received_spektrum_soft_bind(); + break; +#endif default: break; } @@ -101,10 +153,15 @@ static inline void intermcu_parse_msg(struct transport_rx *trans, void (*command void InterMcuEvent(void (*frame_handler)(void)) { + /* Parse incoming bytes */ if (intermcu_device->char_available(intermcu_device->periph)) { while (intermcu_device->char_available(intermcu_device->periph) && !intermcu_transport.trans_rx.msg_received) { - parse_pprz(&intermcu_transport, intermcu_device->get_byte(intermcu_device->periph)); + unsigned char b = intermcu_device->get_byte(intermcu_device->periph); +#ifdef BOARD_PX4IO + checkPx4RebootCommand(b); +#endif + parse_pprz(&intermcu_transport, b); } if (intermcu_transport.trans_rx.msg_received) { @@ -112,3 +169,44 @@ void InterMcuEvent(void (*frame_handler)(void)) } } } +#ifdef BOARD_PX4IO +static inline void checkPx4RebootCommand(unsigned char b) +{ + if (!px4RebootTimeout) { + + + if (sys_time_check_and_ack_timer(px4bl_tid)) { + //time out the possibility to reboot to the px4 bootloader, to prevent unwanted restarts during flight + px4RebootTimeout = true; + sys_time_cancel_timer(px4bl_tid); + return; + } + + LED_ON(SYS_TIME_LED); + + if (b == px4RebootSequence[px4RebootSequenceCount]) { + px4RebootSequenceCount++; + } else { + px4RebootSequenceCount = 0; + } + + if (px4RebootSequenceCount >= 6) { // 6 = length of rebootSequence + 1 + px4RebootSequenceCount = 0; // should not be necessary... + + //send some magic back + //this is the same as the Pixhawk IO code would send + intermcu_device->put_byte(intermcu_device->periph, 0x00); + intermcu_device->put_byte(intermcu_device->periph, 0xe5); + intermcu_device->put_byte(intermcu_device->periph, 0x32); + intermcu_device->put_byte(intermcu_device->periph, 0x0a); + intermcu_device->put_byte(intermcu_device->periph, + 0x66); // dummy byte, seems to be necessary otherwise one byte is missing at the fmu side... + + while (((struct uart_periph *)(intermcu_device->periph))->tx_running) {LED_TOGGLE(SYS_TIME_LED);} // tx_running is volatile now, so LED_TOGGLE not necessary anymore + + LED_OFF(SYS_TIME_LED); + scb_reset_system(); + } + } +} +#endif diff --git a/sw/airborne/subsystems/intermcu/intermcu_fbw.h b/sw/airborne/subsystems/intermcu/intermcu_fbw.h index 82a23664b9..88d065bd00 100644 --- a/sw/airborne/subsystems/intermcu/intermcu_fbw.h +++ b/sw/airborne/subsystems/intermcu/intermcu_fbw.h @@ -29,9 +29,23 @@ #include "subsystems/intermcu.h" +extern uint8_t autopilot_motors_on; extern pprz_t intermcu_commands[COMMANDS_NB]; -void intermcu_on_rc_frame(void); +void intermcu_on_rc_frame(uint8_t fbw_mode); void intermcu_send_status(uint8_t mode); void InterMcuEvent(void (*frame_handler)(void)); + +/* We need radio defines for the Autopilot */ +#define INTERMCU_RADIO_THROTTLE 0 +#define INTERMCU_RADIO_ROLL 1 +#define INTERMCU_RADIO_PITCH 2 +#define INTERMCU_RADIO_YAW 3 +#define INTERMCU_RADIO_MODE 4 +#define INTERMCU_RADIO_KILL_SWITCH 5 +#define INTERMCU_RADIO_AUX1 5 +#define INTERMCU_RADIO_AUX2 6 +#define INTERMCU_RADIO_AUX3 7 +#define INTERMCU_RADIO_CONTROL_NB_CHANNEL 8 + #endif /* INTERMCU_FBW_ROTORCRAFT_H */ diff --git a/sw/airborne/subsystems/radio_control.c b/sw/airborne/subsystems/radio_control.c index 72a0c8a20d..dbbb4b3fdb 100644 --- a/sw/airborne/subsystems/radio_control.c +++ b/sw/airborne/subsystems/radio_control.c @@ -64,7 +64,7 @@ void radio_control_periodic_task(void) radio_control.time_since_last_frame++; } -#if defined RADIO_CONTROL_LED +#if defined(RADIO_CONTROL_LED) if (radio_control.status == RC_OK) { LED_ON(RADIO_CONTROL_LED); } else { diff --git a/sw/airborne/test/test_datalink.c b/sw/airborne/test/test_datalink.c index 6ff8575b4a..58beb110e0 100644 --- a/sw/airborne/test/test_datalink.c +++ b/sw/airborne/test/test_datalink.c @@ -19,6 +19,11 @@ * Boston, MA 02111-1307, USA. */ +/** + * @file test_datalink.c + * + * Periodically sends ALIVE (10Hz) and ping/pong (every 5s) telemetry messages. + */ #define DATALINK_C #include BOARD_CONFIG @@ -50,6 +55,7 @@ static inline void main_init(void) { mcu_init(); sys_time_register_timer((1. / PERIODIC_FREQUENCY), NULL); + downlink_init(); } static inline void main_periodic(void) @@ -74,3 +80,4 @@ void dl_parse_msg(void) break; } } + diff --git a/sw/tools/px4/print_message.py b/sw/tools/px4/print_message.py new file mode 100755 index 0000000000..d9593ab7ed --- /dev/null +++ b/sw/tools/px4/print_message.py @@ -0,0 +1,6 @@ +#!/usr/bin/python +# temporary solution to print a message to reconnect the usb cable +#At some point hopefully this can be automated (without replugging) +print("\n ") +print("**** Please reconnect the usb cable now! *****") +print(" \n") diff --git a/sw/tools/px4/px4fmu-v2.prototype b/sw/tools/px4/px4fmu-v2.prototype new file mode 100644 index 0000000000..5109b77d1e --- /dev/null +++ b/sw/tools/px4/px4fmu-v2.prototype @@ -0,0 +1,12 @@ +{ + "board_id": 9, + "magic": "PX4FWv1", + "description": "Firmware for the PX4FMUv2 board", + "image": "", + "build_time": 0, + "summary": "PX4FMUv2", + "version": "0.1", + "image_size": 0, + "git_identity": "", + "board_revision": 0 +} diff --git a/sw/tools/px4/px4io-v2.prototype b/sw/tools/px4/px4io-v2.prototype new file mode 100644 index 0000000000..af87924e90 --- /dev/null +++ b/sw/tools/px4/px4io-v2.prototype @@ -0,0 +1,12 @@ +{ + "board_id": 10, + "magic": "PX4FWv2", + "description": "Firmware for the PX4IOv2 board", + "image": "", + "build_time": 0, + "summary": "PX4IOv2", + "version": "2.0", + "image_size": 0, + "git_identity": "", + "board_revision": 0 +} diff --git a/sw/tools/px4/px_mkfw.py b/sw/tools/px4/px_mkfw.py new file mode 100755 index 0000000000..2f07fa1e73 --- /dev/null +++ b/sw/tools/px4/px_mkfw.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python +############################################################################ +# +# Copyright (C) 2012, 2013 PX4 Development Team. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name PX4 nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# +# PX4 firmware image generator +# +# The PX4 firmware file is a JSON-encoded Python object, containing +# metadata fields and a zlib-compressed base64-encoded firmware image. +# + +import sys +import argparse +import json +import base64 +import zlib +import time +import subprocess + +# +# Construct a basic firmware description +# +def mkdesc(): + proto = {} + proto['magic'] = "PX4FWv1" + proto['board_id'] = 0 + proto['board_revision'] = 0 + proto['version'] = "" + proto['summary'] = "" + proto['description'] = "" + proto['git_identity'] = "" + proto['build_time'] = 0 + proto['image'] = bytes() + proto['image_size'] = 0 + return proto + +# Parse commandline +parser = argparse.ArgumentParser(description="Firmware generator for the PX autopilot system.") +parser.add_argument("--prototype", action="store", help="read a prototype description from a file") +parser.add_argument("--board_id", action="store", help="set the board ID required") +parser.add_argument("--board_revision", action="store", help="set the board revision required") +parser.add_argument("--version", action="store", help="set a version string") +parser.add_argument("--summary", action="store", help="set a brief description") +parser.add_argument("--description", action="store", help="set a longer description") +parser.add_argument("--git_identity", action="store", help="the working directory to check for git identity") +parser.add_argument("--parameter_xml", action="store", help="the parameters.xml file") +parser.add_argument("--airframe_xml", action="store", help="the airframes.xml file") +parser.add_argument("--image", action="store", help="the firmware image") +args = parser.parse_args() + +# Fetch the firmware descriptor prototype if specified +if args.prototype != None: + f = open(args.prototype,"r") + desc = json.load(f) + f.close() +else: + desc = mkdesc() + +desc['build_time'] = int(time.time()) + +if args.board_id != None: + desc['board_id'] = int(args.board_id) +if args.board_revision != None: + desc['board_revision'] = int(args.board_revision) +if args.version != None: + desc['version'] = str(args.version) +if args.summary != None: + desc['summary'] = str(args.summary) +if args.description != None: + desc['description'] = str(args.description) +if args.git_identity != None: + cmd = " ".join(["git", "--git-dir", args.git_identity + "/.git", "describe", "--always", "--dirty"]) + p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout + desc['git_identity'] = str(p.read().strip()) + p.close() +if args.parameter_xml != None: + f = open(args.parameter_xml, "rb") + bytes = f.read() + desc['parameter_xml_size'] = len(bytes) + desc['parameter_xml'] = base64.b64encode(zlib.compress(bytes,9)).decode('utf-8') +if args.airframe_xml != None: + f = open(args.airframe_xml, "rb") + bytes = f.read() + desc['airframe_xml_size'] = len(bytes) + desc['airframe_xml'] = base64.b64encode(zlib.compress(bytes,9)).decode('utf-8') +if args.image != None: + f = open(args.image, "rb") + bytes = f.read() + desc['image_size'] = len(bytes) + desc['image'] = base64.b64encode(zlib.compress(bytes,9)).decode('utf-8') + +print(json.dumps(desc, indent=4)) diff --git a/sw/tools/px4/px_uploader.py b/sw/tools/px4/px_uploader.py new file mode 100755 index 0000000000..ea83273bfc --- /dev/null +++ b/sw/tools/px4/px_uploader.py @@ -0,0 +1,636 @@ +#!/usr/bin/env python +############################################################################ +# +# Copyright (C) 2012-2015 PX4 Development Team. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name PX4 nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# +# Serial firmware uploader for the PX4FMU bootloader +# +# The PX4 firmware file is a JSON-encoded Python object, containing +# metadata fields and a zlib-compressed base64-encoded firmware image. +# +# The uploader uses the following fields from the firmware file: +# +# image +# The firmware that will be uploaded. +# image_size +# The size of the firmware in bytes. +# board_id +# The board for which the firmware is intended. +# board_revision +# Currently only used for informational purposes. +# + +# for python2.7 compatibility +from __future__ import print_function + +import sys +import argparse +import binascii +import serial +import struct +import json +import zlib +import base64 +import time +import array +import os + +from sys import platform as _platform + + +class firmware(object): + '''Loads a firmware file''' + + desc = {} + image = bytes() + crctab = array.array('I', [ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d]) + crcpad = bytearray(b'\xff\xff\xff\xff') + + def __init__(self, path): + + # read the file + f = open(path, "r") + self.desc = json.load(f) + f.close() + + self.image = bytearray(zlib.decompress(base64.b64decode(self.desc['image']))) + + # pad image to 4-byte length + while ((len(self.image) % 4) != 0): + self.image.append('\xff') + + def property(self, propname): + return self.desc[propname] + + def __crc32(self, bytes, state): + for byte in bytes: + index = (state ^ byte) & 0xff + state = self.crctab[index] ^ (state >> 8) + return state + + def crc(self, padlen): + state = self.__crc32(self.image, int(0)) + for i in range(len(self.image), (padlen - 1), 4): + state = self.__crc32(self.crcpad, state) + return state + + +class uploader(object): + '''Uploads a firmware file to the PX FMU bootloader''' + + # protocol bytes + INSYNC = b'\x12' + EOC = b'\x20' + + # reply bytes + OK = b'\x10' + FAILED = b'\x11' + INVALID = b'\x13' # rev3+ + BAD_SILICON_REV = b'\x14' # rev5+ + + # command bytes + NOP = b'\x00' # guaranteed to be discarded by the bootloader + GET_SYNC = b'\x21' + GET_DEVICE = b'\x22' + CHIP_ERASE = b'\x23' + CHIP_VERIFY = b'\x24' # rev2 only + PROG_MULTI = b'\x27' + READ_MULTI = b'\x28' # rev2 only + GET_CRC = b'\x29' # rev3+ + GET_OTP = b'\x2a' # rev4+ , get a word from OTP area + GET_SN = b'\x2b' # rev4+ , get a word from SN area + GET_CHIP = b'\x2c' # rev5+ , get chip version + SET_BOOT_DELAY = b'\x2d' # rev5+ , set boot delay + GET_CHIP_DES = b'\x2e' # rev5+ , get chip description in ASCII + MAX_DES_LENGTH = 20 + + REBOOT = b'\x30' + + INFO_BL_REV = b'\x01' # bootloader protocol revision + BL_REV_MIN = 2 # minimum supported bootloader protocol + BL_REV_MAX = 5 # maximum supported bootloader protocol + INFO_BOARD_ID = b'\x02' # board type + INFO_BOARD_REV = b'\x03' # board revision + INFO_FLASH_SIZE = b'\x04' # max firmware size in bytes + + PROG_MULTI_MAX = 252 # protocol max is 255, must be multiple of 4 + READ_MULTI_MAX = 252 # protocol max is 255 + + NSH_INIT = bytearray(b'\x0d\x0d\x0d') + NSH_REBOOT_BL = b"reboot -b\n" + NSH_REBOOT = b"reboot\n" + MAVLINK_REBOOT_ID1 = bytearray(b'\xfe\x21\x72\xff\x00\x4c\x00\x00\x80\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x00\x01\x00\x00\x48\xf0') + MAVLINK_REBOOT_ID0 = bytearray(b'\xfe\x21\x45\xff\x00\x4c\x00\x00\x80\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x00\x00\x00\x00\xd7\xac') + + def __init__(self, portname, baudrate): + # open the port, keep the default timeout short so we can poll quickly + self.port = serial.Serial(portname, baudrate, timeout=0.5) + self.otp = b'' + self.sn = b'' + + def close(self): + if self.port is not None: + self.port.close() + + def __send(self, c): + #print("send " + binascii.hexlify(c)) + self.port.write(c) + + + def __recv(self, count=1): + c = self.port.read(count) + if len(c) < 1: + #print("Timeout") + raise RuntimeError("timeout waiting for data (%u bytes)" % count) + #print("recv " + binascii.hexlify(c)) + return c + + def __recv_int(self): + raw = self.__recv(4) + val = struct.unpack("= 9.0: + self.__drawProgressBar(label, 20.0-estimatedTimeRemaining, 9.0) + else: + self.__drawProgressBar(label, 10.0, 10.0) + sys.stdout.write(" (timeout: %d seconds) " % int(deadline-time.time()) ) + sys.stdout.flush() + + if self.__trySync(): + self.__drawProgressBar(label, 10.0, 10.0) + return; + + raise RuntimeError("timed out waiting for erase") + + # send a PROG_MULTI command to write a collection of bytes + def __program_multi(self, data): + + if runningPython3 == True: + length = len(data).to_bytes(1, byteorder='big') + else: + length = chr(len(data)) + + self.__send(uploader.PROG_MULTI) + self.__send(length) + self.__send(data) + self.__send(uploader.EOC) + self.__getSync() + + # verify multiple bytes in flash + def __verify_multi(self, data): + + if runningPython3 == True: + length = len(data).to_bytes(1, byteorder='big') + else: + length = chr(len(data)) + + self.__send(uploader.READ_MULTI) + self.__send(length) + self.__send(uploader.EOC) + self.port.flush() + programmed = self.__recv(len(data)) + if programmed != data: + print("got " + binascii.hexlify(programmed)) + print("expect " + binascii.hexlify(data)) + return False + self.__getSync() + return True + + # send the reboot command + def __reboot(self): + self.__send(uploader.REBOOT + + uploader.EOC) + self.port.flush() + + # v3+ can report failure if the first word flash fails + if self.bl_rev >= 3: + self.__getSync() + + # split a sequence into a list of size-constrained pieces + def __split_len(self, seq, length): + return [seq[i:i+length] for i in range(0, len(seq), length)] + + # upload code + def __program(self, label, fw): + print("\n", end='') + code = fw.image + groups = self.__split_len(code, uploader.PROG_MULTI_MAX) + + uploadProgress = 0 + for bytes in groups: + self.__program_multi(bytes) + + #Print upload progress (throttled, so it does not delay upload progress) + uploadProgress += 1 + if uploadProgress % 256 == 0: + self.__drawProgressBar(label, uploadProgress, len(groups)) + self.__drawProgressBar(label, 100, 100) + + # verify code + def __verify_v2(self, label, fw): + print("\n", end='') + self.__send(uploader.CHIP_VERIFY + + uploader.EOC) + self.__getSync() + code = fw.image + groups = self.__split_len(code, uploader.READ_MULTI_MAX) + verifyProgress = 0 + for bytes in groups: + verifyProgress += 1 + if verifyProgress % 256 == 0: + self.__drawProgressBar(label, verifyProgress, len(groups)) + if (not self.__verify_multi(bytes)): + raise RuntimeError("Verification failed") + self.__drawProgressBar(label, 100, 100) + + def __verify_v3(self, label, fw): + print("\n", end='') + self.__drawProgressBar(label, 1, 100) + expect_crc = fw.crc(self.fw_maxsize) + self.__send(uploader.GET_CRC + + uploader.EOC) + report_crc = self.__recv_int() + self.__getSync() + verifyProgress = 0 + if report_crc != expect_crc: + print("Expected 0x%x" % expect_crc) + print("Got 0x%x" % report_crc) + raise RuntimeError("Program CRC failed") + self.__drawProgressBar(label, 100, 100) + + def __set_boot_delay(self, boot_delay): + self.__send(uploader.SET_BOOT_DELAY + + struct.pack("b", boot_delay) + + uploader.EOC) + self.__getSync() + + # get basic data about the board + def identify(self): + # make sure we are in sync before starting + self.__sync() + + # get the bootloader protocol ID first + self.bl_rev = self.__getInfo(uploader.INFO_BL_REV) + if (self.bl_rev < uploader.BL_REV_MIN) or (self.bl_rev > uploader.BL_REV_MAX): + print("Unsupported bootloader protocol %d" % uploader.INFO_BL_REV) + raise RuntimeError("Bootloader protocol mismatch") + + self.board_type = self.__getInfo(uploader.INFO_BOARD_ID) + self.board_rev = self.__getInfo(uploader.INFO_BOARD_REV) + self.fw_maxsize = self.__getInfo(uploader.INFO_FLASH_SIZE) + + # upload the firmware + def upload(self, fw): + # Make sure we are doing the right thing + if self.board_type != fw.property('board_id'): + msg = "Firmware not suitable for this board (board_type=%u board_id=%u)" % ( + self.board_type, fw.property('board_id')) + if args.force: + print("WARNING: %s" % msg) + else: + raise IOError(msg) + if self.fw_maxsize < fw.property('image_size'): + raise RuntimeError("Firmware image is too large for this board") + + # OTP added in v4: + if self.bl_rev > 3: + for byte in range(0,32*6,4): + x = self.__getOTP(byte) + self.otp = self.otp + x + print(binascii.hexlify(x).decode('Latin-1') + ' ', end='') + # see src/modules/systemlib/otp.h in px4 code: + self.otp_id = self.otp[0:4] + self.otp_idtype = self.otp[4:5] + self.otp_vid = self.otp[8:4:-1] + self.otp_pid = self.otp[12:8:-1] + self.otp_coa = self.otp[32:160] + # show user: + try: + print("type: " + self.otp_id.decode('Latin-1')) + print("idtype: " + binascii.b2a_qp(self.otp_idtype).decode('Latin-1')) + print("vid: " + binascii.hexlify(self.otp_vid).decode('Latin-1')) + print("pid: "+ binascii.hexlify(self.otp_pid).decode('Latin-1')) + print("coa: "+ binascii.b2a_base64(self.otp_coa).decode('Latin-1')) + print("sn: ", end='') + for byte in range(0,12,4): + x = self.__getSN(byte) + x = x[::-1] # reverse the bytes + self.sn = self.sn + x + print(binascii.hexlify(x).decode('Latin-1'), end='') # show user + print('') + print("chip: %08x" % self.__getCHIP()) + if (self.bl_rev >= 5): + des = self.__getCHIPDes() + if (len(des) == 2): + print("family: %s" % des[0]) + print("revision: %s" % des[1]) + print("flash %d" % self.fw_maxsize) + except Exception: + # ignore bad character encodings + pass + + self.__erase("Erase ") + self.__program("Program", fw) + + if self.bl_rev == 2: + self.__verify_v2("Verify ", fw) + else: + self.__verify_v3("Verify ", fw) + + if args.boot_delay is not None: + self.__set_boot_delay(args.boot_delay) + + print("\nRebooting.\n") + self.__reboot() + self.port.close() + + def send_reboot(self): + try: + # try reboot via NSH first + self.__send(uploader.NSH_INIT) + self.__send(uploader.NSH_REBOOT_BL) + self.__send(uploader.NSH_INIT) + self.__send(uploader.NSH_REBOOT) + # then try MAVLINK command + self.__send(uploader.MAVLINK_REBOOT_ID1) + self.__send(uploader.MAVLINK_REBOOT_ID0) + except: + return + +# Detect python version +if sys.version_info[0] < 3: + runningPython3 = False +else: + runningPython3 = True + +# Parse commandline arguments +parser = argparse.ArgumentParser(description="Firmware uploader for the PX autopilot system.") +parser.add_argument('--port', action="store", required=True, help="Serial port(s) to which the FMU may be attached") +parser.add_argument('--baud', action="store", type=int, default=115200, help="Baud rate of the serial port (default is 115200), only required for true serial ports.") +parser.add_argument('--force', action='store_true', default=False, help='Override board type check and continue loading') +parser.add_argument('--boot-delay', type=int, default=None, help='minimum boot delay to store in flash') +parser.add_argument('firmware', action="store", help="Firmware file to be uploaded") +args = parser.parse_args() + +# warn people about ModemManager which interferes badly with Pixhawk +if os.path.exists("/usr/sbin/ModemManager"): + print("==========================================================================================================") + print("WARNING: You should uninstall ModemManager as it conflicts with any non-modem serial device (like Pixhawk)") + print("==========================================================================================================") + +# Load the firmware file +fw = firmware(args.firmware) +print("Loaded firmware for %x,%x, size: %d bytes, waiting for the bootloader..." % (fw.property('board_id'), fw.property('board_revision'), fw.property('image_size'))) +print("If the board does not respond within 1-2 seconds, unplug and re-plug the USB connector.") + +# Spin waiting for a device to show up +try: + while True: + portlist = [] + patterns = args.port.split(",") + # on unix-like platforms use glob to support wildcard ports. This allows + # the use of /dev/serial/by-id/usb-3D_Robotics on Linux, which prevents the upload from + # causing modem hangups etc + if "linux" in _platform or "darwin" in _platform: + import glob + for pattern in patterns: + portlist += glob.glob(pattern) + else: + portlist = patterns + + for port in portlist: + + #print("Trying %s" % port) + + # create an uploader attached to the port + try: + if "linux" in _platform: + # Linux, don't open Mac OS and Win ports + if not "COM" in port and not "tty.usb" in port: + up = uploader(port, args.baud) + elif "darwin" in _platform: + # OS X, don't open Windows and Linux ports + if not "COM" in port and not "ACM" in port: + up = uploader(port, args.baud) + elif "win" in _platform: + # Windows, don't open POSIX ports + if not "/" in port: + up = uploader(port, args.baud) + except Exception: + # open failed, rate-limit our attempts + time.sleep(0.05) + + # and loop to the next port + continue + # port is open, try talking to it + try: + # identify the bootloader + up.identify() + print("Found board %x,%x bootloader rev %x on %s" % (up.board_type, up.board_rev, up.bl_rev, port)) + + except Exception: + # most probably a timeout talking to the port, no bootloader, try to reboot the board + print("attempting reboot on %s..." % port) + print("if the board does not respond, unplug and re-plug the USB connector.") + up.send_reboot() + + # wait for the reboot, without we might run into Serial I/O Error 5 + time.sleep(0.5) + + # always close the port + up.close() + continue + + try: + # ok, we have a bootloader, try flashing it + up.upload(fw) + + except RuntimeError as ex: + # print the error + print("\nERROR: %s" % ex.args) + + except IOError as e: + up.close(); + continue + + finally: + # always close the port + up.close() + + # we could loop here if we wanted to wait for more boards... + sys.exit(0) + + # Delay retries to < 20 Hz to prevent spin-lock from hogging the CPU + time.sleep(0.05) + +# CTRL+C aborts the upload/spin-lock by interrupt mechanics +except KeyboardInterrupt: + print("\n Upload aborted by user.") + sys.exit(0)