diff --git a/CREDITS.txt b/CREDITS.txt index dbfb057e2..b6e6db727 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1,13 +1,13 @@ -This is a credits file of people that are or have been key contributors to the OpenPilot project. -Without the work of the people in this file OpenPilot would not be what it is today. +This is a credits file of people that are or have been key contributors to the OpenPilot project. +Without the work of the people in this file OpenPilot would not be what it is today. -It is sorted alphabetically by name and formatted so that it allows for easy grepping and beautification by scripts. +It is sorted alphabetically by name and formatted so that it allows for easy grepping and beautification by scripts. -The fields are: +The fields are: Name (N) Email (E), -Description of work (D) +Description of work (D) Current maintainer function (M) ---------- @@ -19,29 +19,33 @@ M: SITL Win32 N: David Ankers E: david (at) openpilot (dot) org -D: Co-founder, Project Coordination -D: Minor GCS infrastructure, updating the credit file +D: Co-founder, Project Coordination +D: Minor GCS infrastructure, updating the credit file M: Admin N: Pedro Assuncao E: pedro (dot) agda (plus) openpilot (at) gmail (dot) com D: Initial GCS Settings Gadget work +N: Werner Backes +E: werner (at) bit-1 (dot) de +D: Port of CopterControl to PS3 Move Controller (MoveCopter) + N: Jose Barros E: josembarros (at) hotmail (dot) com D: Next-Gen OP Map Lib, Y-Modem Library, Uploader Plugin D: OP Bootloader, AHRS Bootloader, OPUploadTool -M: Bootloader, OP MAP Lib - -N: David "Buzz" Carlson +M: Bootloader, OP MAP Lib + +N: David "Buzz" Carlson E: chebuzz (plus) openpilot (at) gmail (dot) com D: 3D ModelView GCS Plugin, sponsor of HITL merge work and XPlane addition M: 3D Modelview N: James Cotton E: peabody124 (plus) openpilot (at) gmail (dot) com -D: Multiplatform HID implementation (firmware & GCS), GCS Joystick control -D: Posix OpenPilot work and Mac implementation +D: Multiplatform HID implementation (firmware & GCS), GCS Joystick control +D: Posix OpenPilot work and Mac implementation D: Firmware implementation of Professor Schinstock's INS/GPS M: Architecture co-lead @@ -52,7 +56,7 @@ D: Floss-JTAG Rev A, 4-layer initial design N: Frederic Goddeeris E: fredericgoddeeris (at) hotmail (dot) com D: I2C work and FreeRTOS work, MK integration -D: EagleTree OSD implementation +D: EagleTree OSD implementation M: OSD Module N: Daniel Godin @@ -83,21 +87,21 @@ M: Hardware Architecture Team N: Mark James E: mjames (plus) openpilot (at) gmail (dot) com -D: Some of Silk Icon set used in GCS - http://www.famfamfam.com/lab/icons/silk +D: Some of Silk Icon set used in GCS - http://www.famfamfam.com/lab/icons/silk N: Sami Korhonen E: samik (dot) korhonen (plus) openpilot (at) gmail (dot) com -D: GPS Module, Spektrum RC Module, OSD work +D: GPS Module, Spektrum RC Module, OSD work N: Thorsten Klose E: thorsten (dot) klose (at) dmx (dot) de -D: Embedded STM32 infrastructure +D: Embedded STM32 infrastructure N: Hallvard Kristiansen E: hal (at) fleshmx (dot) com D: GCS Artwork, Quad layout diagrams -N: Edouard Lafargue +N: Edouard Lafargue E: edouard (at) lafargue (dot) name D: GCS Dial Plugins, GCS PFD Plugin, GCS GPS plugin, GCS Config plugin D: Artwork including standard display dials @@ -105,7 +109,7 @@ M: GCS Core N: Matt Lipski E: mattlipski (plus) openpilot (at) gmail (dot) com -D: Deluxe Dials Set artwork, (Artificial Horizon, Compass, Turn Indicator) +D: Deluxe Dials Set artwork, (Artificial Horizon, Compass, Turn Indicator) N: Les Newell E: les (dot) newell (at) fastmail (dot) co (dot) uk @@ -113,9 +117,9 @@ D: Advanced mixer matrix, SPI protocol based on UAVObjects N: Ken Northup E: helos360 (at) bellsouth (dot) net -D: 3D Modelling, Easystar adaption from FMS +D: 3D Modelling, Easystar adaption from FMS -N: Guy McCaldin +N: Guy McCaldin E: guymcc (at) gmail (dot) com D: Artwork and design including work on the Deluxe Dial Set @@ -123,11 +127,11 @@ N: Cathy Moss E: cmoss296 (at) blueyonder (dot) co (dot) uk D: Hardware design Lead: Gen 2 Mainboard, PipXtreme, Current Sensor D: Lead dev PipXtreme, creator OP Map Plugin -M: Hardware Architecture Team / PipX Modem +M: Hardware Architecture Team / PipX Modem N: Angus Peart E: gussy (at) openpilot (dot) org -D: Co-founder, Principal hardware architect. +D: Co-founder, Principal hardware architect. D: Hardware design of OpenPilot, AHRS, GPS and other hardware D: Core developer embedded code @@ -152,7 +156,7 @@ D: GCS Framework and Plugins for the GCS N: Zik Saleeba E: zik (at) zikzak (dot) net -D: Initial schematic based on Zik's Flying Fox schematic +D: Initial schematic based on Zik's Flying Fox schematic N: Professor Dale Schinstock E: dales (at) ksu (dot) edu @@ -162,16 +166,18 @@ D: Creator of the OpenPilot INS / EKF N: Oleg Semyonov E: os-openpilot-org (at) os-propo (dot) info D: Core tester & Project organisation +M: Common part of multi-platform packaging system +M: Windows NSIS Installer M: Russian Documentation Lead N: Stacey Sheldon E: stac (at) solidgoldbomb (dot) org D: Core Embedded Developer -D: SPI protocol for AHRS, I2C rewrite and much core work +D: SPI protocol for AHRS, I2C rewrite and much core work N: Troy Schultz E: troy (dot) schultz (at) rogers (dot) com -D: INS design review and optimisation +D: INS design review and optimisation M: Hardware Architecture Team N: Dr. Erhard Siegl @@ -194,11 +200,10 @@ D: Helicopter support code and mixing for CCPM N: Vassilis Varveropoulos E: vassilis (at) openpilot (dot) org -D: Co-founder, Principal embedded software architect. +D: Co-founder, Principal embedded software architect. D: Module architecture and UAVTalk/UAVObjects implementation. M: Architecture co-lead N: Alex Vrubel E: alex (dot) vrubel (plus) openpilot (at) gmail (dot) com D: Russian translation of the GCS - diff --git a/HISTORY.txt b/HISTORY.txt new file mode 100644 index 000000000..b0e1ce8b0 --- /dev/null +++ b/HISTORY.txt @@ -0,0 +1,43 @@ +Short summary of changes. For a complete list see the git log. + +2011-08-10 +Added Camera Stabilization and a gui to configure this. This is a software +selectable module from the GUI. However, a restart is required to make it +active. The GUI does not currently expose the configuration for using the +transmitter to change the view angle but this is supported by the hardware. + +2011-08-10 +By default a lot of diagnostic objects that were enabled by default are now +disabled in the build. This include TaskInfo (and all the FreeRTOS options +that provide that debugging information). Also MixerStatus, I2CStatus, +WatchdogStatus and RateDesired. These can be reenabled for debugging with +-DDIAGNOSTICS. + +2011-08-04 +Fixed packaging aesthetic issues. Also avoid runtime issues on OSX Lion by +disabling the ModelView and Notify plugins for now (sorry). + +2011-07-29 +Added support for PPM receivers from James W. Now all 4 interfaces (R/C +standard PWM, combined PPM (MK), Spektrum satellite, Futaba S.Bus) are +supported and configurable through the GCS hardware configuration tab. + +2011-07-17 +Updated module initialization from Mathieu which separates the initialization +from the task startup. Also implements a method to reclaim unused ram from +initialization and end of memory for the FreeRTOS heap. + +2011-07-12 +Improvements to the stabilization code. Included a LPF on the gyros to smooth +out noise in high vibration environments. Also two new modes: axis-lock and +weak leveling. Axis-lock will try and hold an axis at a fixed position and +reject any disturbances. This is like heading-hold on a heli for the tail but +can be useful for other axes. Weak leveling is rate mode with a weak +correction to self level the craft - good for easier rate mode flying. + +2011-07-07 +Dynamic hardware configuration from Stac. The input type is now +selected from ManualControlSettings.InputMode and the aircraft must be rebooted +after changing this. Also for CopterControl the HwSettings object must +indicate which modules are connected to which ports. PPM currently not +working. diff --git a/MILESTONES.txt b/MILESTONES.txt index 4f259c856..14db545d6 100644 --- a/MILESTONES.txt +++ b/MILESTONES.txt @@ -1,12 +1,12 @@ -This is the Milestones file of the OpenPilot project, its intent is to record the major accomplishments achieved by people using the OpenPilot platform and who gets the karma for performing them. +This is the Milestones file of the OpenPilot project, its intent is to record the major accomplishments achieved by people using the OpenPilot platform and who gets the karma for performing them. -The CREDITS.txt in SVN records the developers and the achievements made by each individual; this file is different as it is aimed at recording and giving credit to the people who achieve milestones in the use of OpenPilot. +The CREDITS.txt in SVN records the developers and the achievements made by each individual; this file is different as it is aimed at recording and giving credit to the people who achieve milestones in the use of OpenPilot. -The fields are: +The fields are: -Milestone description (M) +Milestone description (M) Credited to (C) Date (D) Video (V) - Optional link to video showing milestone @@ -22,7 +22,7 @@ C: James Cotton D: September 2010 M: First stabilised fixed wing flight -C: Edouard Lafargue +C: Edouard Lafargue D: September 2010 M: First stabilised Quad flight @@ -38,7 +38,7 @@ C: Cathy Moss D: October 2010 M: First OpenPilot night flight -C: Dale Schintock +C: Dale Schinstock D: October 2010 V: http://www.youtube.com/watch?v=yk8ckeRMV8U @@ -53,7 +53,7 @@ D: November 2010 V: http://vimeo.com/17488702 M: First solid OpenPilot Position Hold -C: Dale Schintock +C: Dale Schinstock D: December 2010 V: http://www.youtube.com/watch?v=BBCGVP0Vpgw @@ -93,39 +93,89 @@ D: March 2011 V: http://vimeo.com/22221798 M: First CopterControl flight on a Hexa -C: Edouard Lafargue - -D: March 2011 - -V: http://vimeo.com/21476466 - +C: Edouard Lafargue +D: March 2011 +V: http://vimeo.com/21476466 M: First CopterControl flight on a Tri C: Gary Mortimer and the Scorpion D: March 2011 V: http://vimeo.com/22104334 +M: First Y6 OpenPilot flight +C: Sami Korhonen (Sambas) +D: May 2011 +V: http://www.vimeo.com/23637586 + M: First CopterControl flight on a Flybarless Heli -C: ? -D: ? -V: +C: Oleg Semyonov (osnwt) +D: May 2011 +V: http://www.youtube.com/watch?v=-J8cxqzxxWw + +M: First V8 Octo OpenPilot flight +C: Sami Korhonen (Sambas) +D: May 2011 +V: http://vimeo.com/24258192 M: First Y6 CopterControl flight -C: ? -D: ? +C: Michel Pet +D: June 2011 +V: http://www.youtube.com/watch?v=QsE2MQELPZY + +M: First MoveCopter flight +C: Werner Backes +D: July 2011 +V: http://vimeo.com/25983655 + +M: First Y4 CopterControl flight +C: Mat Wellington +D: July 2011 +V: http://www.youtube.com/watch?v=TxZ4MDGIj1o + +M: First V-Tail4 CopterControl flight +C: Mat Wellington +D: July 2011 +V: http://www.youtube.com/watch?v=YE4Fd9vdg1I + +M: First CopterControl Flybared Heli inverted flight (2:33) +C: Maxim Izergin (Maximus43) +D: August 2011 +V: http://www.youtube.com/watch?v=8SrfIS7OkB4 + +M: First CopterControl Flybared Heli funnel (4:18), loop (5:35) +C: Sergey Solodennikov (alconaft43) +D: August 2011 +V: http://www.youtube.com/watch?v=8SrfIS7OkB4 + +M: First Altitude Hold using Sonar +C: +D: V: +M: First CopterControl Navigation on RC Ground Vechicle +C: +D: +V: + +M: First CopterControl Navigation on RC Water Vechicle +C: +D: +V: + +M: First CopterControl flip on a Flybarless Heli +C: +D: +V: An incomplete list of some future Milestones is below: -* First Helicopter flight with OpenPilot -* First Octo flight with OpenPilot +* First Y6 CopterControl flight +* First Helicopter flight with OpenPilot * First successful flight using the GCS only and no RC TX * First use of Magic Waypoint * First Flybarless Helicopter flight with OpenPilot -* First flight with CopterControl -* First fixed wing navigation flight +* First fixed wing navigation flight * First Multirotor navigation flight * First Helicopter navigation flight * First over 1km navigation flight diff --git a/Makefile b/Makefile index e7e0bea48..18cdb3b2e 100644 --- a/Makefile +++ b/Makefile @@ -71,36 +71,46 @@ help: @echo " qt_sdk_install - Install the QT v4.6.2 tools" @echo " arm_sdk_install - Install the Code Sourcery ARM gcc toolchain" @echo " openocd_install - Install the OpenOCD JTAG daemon" + @echo " stm32flash_install - Install the stm32flash tool for unbricking boards" @echo @echo " [Big Hammer]" @echo " all - Generate UAVObjects, build openpilot firmware and gcs" @echo " all_flight - Build all firmware, bootloaders and bootloader updaters" @echo " all_fw - Build only firmware for all boards" @echo " all_bl - Build only bootloaders for all boards" - @echo " all_blupd - Build only bootloader updaters for all boards" + @echo " all_bu - Build only bootloader updaters for all boards" @echo @echo " all_clean - Remove your build directory ($(BUILD_DIR))" @echo " all_flight_clean - Remove all firmware, bootloaders and bootloader updaters" @echo " all_fw_clean - Remove firmware for all boards" @echo " all_bl_clean - Remove bootlaoders for all boards" - @echo " all_blupd_clean - Remove bootloader updaters for all boards" + @echo " all_bu_clean - Remove bootloader updaters for all boards" + @echo + @echo " all_ - Build all available images for " + @echo " all__clean - Remove all available images for " @echo @echo " [Firmware]" @echo " - Build firmware for " - @echo " supported boards are ($(FW_TARGETS))" - @echo " _clean - Remove firmware for " - @echo " _program - Use OpenOCD + JTAG to write firmware to " + @echo " supported boards are ($(ALL_BOARDS))" + @echo " fw_ - Build firmware for " + @echo " supported boards are ($(FW_BOARDS))" + @echo " fw__clean - Remove firmware for " + @echo " fw__program - Use OpenOCD + JTAG to write firmware to " @echo @echo " [Bootloader]" @echo " bl_ - Build bootloader for " - @echo " supported boards are ($(BL_TARGETS))" + @echo " supported boards are ($(BL_BOARDS))" @echo " bl__clean - Remove bootloader for " @echo " bl__program - Use OpenOCD + JTAG to write bootloader to " @echo @echo " [Bootloader Updater]" - @echo " blupd_ - Build bootloader updater for " - @echo " supported boards are ($(BLUPD_TARGETS))" - @echo " blupd__clean - Remove bootloader updater for " + @echo " bu_ - Build bootloader updater for " + @echo " supported boards are ($(BU_BOARDS))" + @echo " bu__clean - Remove bootloader updater for " + @echo + @echo " [Unbrick a board]" + @echo " unbrick_ - Use the STM32's built in boot ROM to write a bootloader to " + @echo " supported boards are ($(BL_BOARDS))" @echo @echo " [Simulation]" @echo " sim_posix - Build OpenPilot simulation firmware for" @@ -170,10 +180,10 @@ qt_sdk_clean: $(V1) [ ! -d "$(QT_SDK_DIR)" ] || $(RM) -rf $(QT_SDK_DIR) # Set up ARM (STM32) SDK -ARM_SDK_DIR := $(TOOLS_DIR)/arm-2009q3 +ARM_SDK_DIR := $(TOOLS_DIR)/arm-2011.03 .PHONY: arm_sdk_install -arm_sdk_install: ARM_SDK_URL := http://www.codesourcery.com/sgpp/lite/arm/portal/package5353/public/arm-none-eabi/arm-2009q3-68-arm-none-eabi-i686-pc-linux-gnu.tar.bz2 +arm_sdk_install: ARM_SDK_URL := http://www.codesourcery.com/sgpp/lite/arm/portal/package8734/public/arm-none-eabi/arm-2011.03-42-arm-none-eabi-i686-pc-linux-gnu.tar.bz2 arm_sdk_install: ARM_SDK_FILE := $(notdir $(ARM_SDK_URL)) # order-only prereq on directory existance: arm_sdk_install: | $(DL_DIR) $(TOOLS_DIR) @@ -221,6 +231,25 @@ openocd_install: openocd_clean openocd_clean: $(V1) [ ! -d "$(OPENOCD_DIR)" ] || $(RM) -r "$(OPENOCD_DIR)" +STM32FLASH_DIR := $(TOOLS_DIR)/stm32flash + +.PHONY: stm32flash_install +stm32flash_install: STM32FLASH_URL := http://stm32flash.googlecode.com/svn/trunk +stm32flash_install: STM32FLASH_REV := 52 +stm32flash_install: stm32flash_clean + # download the source + $(V0) @echo " DOWNLOAD $(STM32FLASH_URL) @ r$(STM32FLASH_REV)" + $(V1) svn export -q -r "$(STM32FLASH_REV)" "$(STM32FLASH_URL)" "$(STM32FLASH_DIR)" + + # build + $(V0) @echo " BUILD $(STM32FLASH_DIR)" + $(V1) $(MAKE) --silent -C $(STM32FLASH_DIR) all + +.PHONY: stm32flash_clean +stm32flash_clean: + $(V0) @echo " CLEAN $(STM32FLASH_DIR)" + $(V1) [ ! -d "$(STM32FLASH_DIR)" ] || $(RM) -r "$(STM32FLASH_DIR)" + ############################## # # Set up paths to tools @@ -265,33 +294,21 @@ gcs_clean: openpilotgcs_clean .PHONY: openpilotgcs openpilotgcs: uavobjects_gcs $(V1) mkdir -p $(BUILD_DIR)/ground/$@ - $(V1) ( cd $(BUILD_DIR)/ground/$@ ; \ - $(QMAKE) $(ROOT_DIR)/ground/openpilotgcs/openpilotgcs.pro -spec $(QT_SPEC) -r CONFIG+=$(GCS_BUILD_CONF) ; \ + $(V1) ( cd $(BUILD_DIR)/ground/$@ && \ + $(QMAKE) $(ROOT_DIR)/ground/openpilotgcs/openpilotgcs.pro -spec $(QT_SPEC) -r CONFIG+=$(GCS_BUILD_CONF) && \ $(MAKE) -w ; \ ) -.PHONY: gcs_installer -gcs_installer: openpilotgcs -ifeq ($(QT_SPEC), win32-g++) -ifeq ($(GCS_BUILD_CONF), release) - $(V1) cd $(BUILD_DIR)/ground/openpilotgcs/packaging/winx86 && $(MAKE) -r --no-print-directory $@ -else - $(error $@ can be generated for release build only (GCS_BUILD_CONF=release)) -endif -else - $(error $@ is currently only available on Windows) -endif - .PHONY: openpilotgcs_clean openpilotgcs_clean: - $(V0) @echo " CLEAN $@" + $(V0) @echo " CLEAN $@" $(V1) [ ! -d "$(BUILD_DIR)/ground/openpilotgcs" ] || $(RM) -r "$(BUILD_DIR)/ground/openpilotgcs" .PHONY: uavobjgenerator uavobjgenerator: $(V1) mkdir -p $(BUILD_DIR)/ground/$@ - $(V1) ( cd $(BUILD_DIR)/ground/$@ ; \ - $(QMAKE) $(ROOT_DIR)/ground/uavobjgenerator/uavobjgenerator.pro -spec $(QT_SPEC) -r CONFIG+=debug ; \ + $(V1) ( cd $(BUILD_DIR)/ground/$@ && \ + $(QMAKE) $(ROOT_DIR)/ground/uavobjgenerator/uavobjgenerator.pro -spec $(QT_SPEC) -r CONFIG+=debug && \ $(MAKE) --no-print-directory -w ; \ ) @@ -306,7 +323,7 @@ $(UAVOBJ_OUT_DIR): $(V1) mkdir -p $@ uavobjects_%: $(UAVOBJ_OUT_DIR) uavobjgenerator - $(V1) ( cd $(UAVOBJ_OUT_DIR) ; \ + $(V1) ( cd $(UAVOBJ_OUT_DIR) && \ $(UAVOBJGENERATOR) -$* $(UAVOBJ_XML_DIR) $(ROOT_DIR) ; \ ) @@ -314,7 +331,7 @@ uavobjects_test: $(UAVOBJ_OUT_DIR) uavobjgenerator $(V1) $(UAVOBJGENERATOR) -v -none $(UAVOBJ_XML_DIR) $(ROOT_DIR) uavobjects_clean: - $(V0) @echo " CLEAN $@" + $(V0) @echo " CLEAN $@" $(V1) [ ! -d "$(UAVOBJ_OUT_DIR)" ] || $(RM) -r "$(UAVOBJ_OUT_DIR)" ############################## @@ -323,254 +340,149 @@ uavobjects_clean: # ############################## -FW_TARGETS := openpilot ahrs coptercontrol pipxtreme ins -BL_TARGETS := $(addprefix bl_, $(FW_TARGETS)) -BLUPD_TARGETS := $(addprefix blupd_, $(FW_TARGETS)) +# $(1) = Canonical board name all in lower case (e.g. coptercontrol) +# $(2) = Name of board used in source tree (e.g. CopterControl) +define FW_TEMPLATE +.PHONY: $(1) fw_$(1) +$(1): fw_$(1)_opfw +fw_$(1): fw_$(1)_opfw + +fw_$(1)_%: uavobjects_flight + $(V1) mkdir -p $(BUILD_DIR)/fw_$(1)/dep + $(V1) cd $(ROOT_DIR)/flight/$(2) && \ + $$(MAKE) -r --no-print-directory \ + BOARD_NAME=$(1) \ + TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ + REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" \ + $$* + +.PHONY: $(1)_clean +$(1)_clean: fw_$(1)_clean +fw_$(1)_clean: + $(V0) @echo " CLEAN $$@" + $(V1) $(RM) -fr $(BUILD_DIR)/fw_$(1) +endef + +# $(1) = Canonical board name all in lower case (e.g. coptercontrol) +# $(2) = Name of board used in source tree (e.g. CopterControl) +define BL_TEMPLATE +.PHONY: bl_$(1) +bl_$(1): bl_$(1)_bin +bl_$(1)_bino: bl_$(1)_bin + +bl_$(1)_%: + $(V1) mkdir -p $(BUILD_DIR)/bl_$(1)/dep + $(V1) cd $(ROOT_DIR)/flight/Bootloaders/$(2) && \ + $$(MAKE) -r --no-print-directory \ + BOARD_NAME=$(1) \ + TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ + REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" \ + $$* + +.PHONY: unbrick_$(1) +unbrick_$(1): bl_$(1)_hex +$(if $(filter-out undefined,$(origin UNBRICK_TTY)), + $(V0) @echo " UNBRICK $(1) via $$(UNBRICK_TTY)" + $(V1) $(STM32FLASH_DIR)/stm32flash \ + -w $(BUILD_DIR)/bl_$(1)/bl_$(1).hex \ + -g 0x0 \ + $$(UNBRICK_TTY) +, + $(V0) @echo + $(V0) @echo "ERROR: You must specify UNBRICK_TTY= to use for unbricking." + $(V0) @echo " eg. $$(MAKE) $$@ UNBRICK_TTY=/dev/ttyUSB0" +) + +.PHONY: bl_$(1)_clean +bl_$(1)_clean: + $(V0) @echo " CLEAN $$@" + $(V1) $(RM) -fr $(BUILD_DIR)/bl_$(1) +endef + +# $(1) = Canonical board name all in lower case (e.g. coptercontrol) +define BU_TEMPLATE +.PHONY: bu_$(1) +bu_$(1): bu_$(1)_opfw + +bu_$(1)_%: bl_$(1)_bino + $(V1) mkdir -p $(BUILD_DIR)/bu_$(1)/dep + $(V1) cd $(ROOT_DIR)/flight/Bootloaders/BootloaderUpdater && \ + $$(MAKE) -r --no-print-directory \ + BOARD_NAME=$(1) \ + TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ + REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" \ + $$* + +.PHONY: bu_$(1)_clean +bu_$(1)_clean: + $(V0) @echo " CLEAN $$@" + $(V1) $(RM) -fr $(BUILD_DIR)/bu_$(1) +endef + +# $(1) = Canonical board name all in lower case (e.g. coptercontrol) +define BOARD_PHONY_TEMPLATE +.PHONY: all_$(1) +all_$(1): $$(filter fw_$(1), $$(FW_TARGETS)) +all_$(1): $$(filter bl_$(1), $$(BL_TARGETS)) +all_$(1): $$(filter bu_$(1), $$(BU_TARGETS)) + +.PHONY: all_$(1)_clean +all_$(1)_clean: $$(addsuffix _clean, $$(filter fw_$(1), $$(FW_TARGETS))) +all_$(1)_clean: $$(addsuffix _clean, $$(filter bl_$(1), $$(BL_TARGETS))) +all_$(1)_clean: $$(addsuffix _clean, $$(filter bu_$(1), $$(BU_TARGETS))) +endef + +ALL_BOARDS := openpilot ahrs coptercontrol pipxtreme ins + +# Friendly names of each board (used to find source tree) +openpilot_friendly := OpenPilot +coptercontrol_friendly := CopterControl +pipxtreme_friendly := PipXtreme +ins_friendly := INS +ahrs_friendly := AHRS + +# Start out assuming that we'll build fw, bl and bu for all boards +FW_BOARDS := $(ALL_BOARDS) +BL_BOARDS := $(ALL_BOARDS) +BU_BOARDS := $(ALL_BOARDS) # FIXME: The INS build doesn't have a bootloader or bootloader # updater yet so we need to filter them out to prevent errors. -BL_TARGETS := $(filter-out bl_ins, $(BL_TARGETS)) -BLUPD_TARGETS := $(filter-out blupd_ins, $(BLUPD_TARGETS)) +BL_BOARDS := $(filter-out ins, $(ALL_BOARDS)) +BU_BOARDS := $(filter-out ins, $(ALL_BOARDS)) + +# Generate the targets for whatever boards are left in each list +FW_TARGETS := $(addprefix fw_, $(FW_BOARDS)) +BL_TARGETS := $(addprefix bl_, $(BL_BOARDS)) +BU_TARGETS := $(addprefix bu_, $(BU_BOARDS)) .PHONY: all_fw all_fw_clean -all_fw: $(addsuffix _bin, $(FW_TARGETS)) -all_fw_clean: $(addsuffix _clean, $(FW_TARGETS)) +all_fw: $(addsuffix _opfw, $(FW_TARGETS)) +all_fw_clean: $(addsuffix _clean, $(FW_TARGETS)) .PHONY: all_bl all_bl_clean -all_bl: $(addsuffix _bin, $(BL_TARGETS)) -all_bl_clean: $(addsuffix _clean, $(BL_TARGETS)) +all_bl: $(addsuffix _bin, $(BL_TARGETS)) +all_bl_clean: $(addsuffix _clean, $(BL_TARGETS)) -.PHONY: all_blupd all_blupd_clean -all_blupd: $(addsuffix _bin, $(BLUPD_TARGETS)) -all_blupd_clean: $(addsuffix _clean, $(BLUPD_TARGETS)) +.PHONY: all_bu all_bu_clean +all_bu: $(addsuffix _opfw, $(BU_TARGETS)) +all_bu_clean: $(addsuffix _clean, $(BU_TARGETS)) .PHONY: all_flight all_flight_clean -all_flight: all_fw all_bl all_blupd -all_flight_clean: all_fw_clean all_bl_clean all_blupd_clean +all_flight: all_fw all_bl all_bu +all_flight_clean: all_fw_clean all_bl_clean all_bu_clean -.PHONY: openpilot -openpilot: openpilot_bin +# Expand the groups of targets for each board +$(foreach board, $(ALL_BOARDS), $(eval $(call BOARD_PHONY_TEMPLATE,$(board)))) -openpilot_%: uavobjects_flight - $(V1) mkdir -p $(BUILD_DIR)/openpilot/dep - $(V1) cd $(ROOT_DIR)/flight/OpenPilot && \ - $(MAKE) -r --no-print-directory \ - OUTDIR="$(BUILD_DIR)/openpilot" TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ - REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" $* +# Expand the bootloader updater rules +$(foreach board, $(ALL_BOARDS), $(eval $(call BU_TEMPLATE,$(board),$($(board)_friendly)))) -.PHONY: openpilot_clean -openpilot_clean: - $(V0) @echo " CLEAN $@" - $(V1) $(RM) -fr $(BUILD_DIR)/openpilot - -.PHONY: bl_openpilot -bl_openpilot: bl_openpilot_bin -bl_openpilot_bino: bl_openpilot_bin - -bl_openpilot_%: - $(V1) mkdir -p $(BUILD_DIR)/bl_openpilot/dep - $(V1) cd $(ROOT_DIR)/flight/Bootloaders/OpenPilot && \ - $(MAKE) -r --no-print-directory \ - OUTDIR="$(BUILD_DIR)/bl_openpilot" TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ - REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" $* - -.PHONY: bl_openpilot_clean -bl_openpilot_clean: - $(V0) @echo " CLEAN $@" - $(V1) $(RM) -fr $(BUILD_DIR)/bl_openpilot - -.PHONY: blupd_openpilot -blupd_openpilot: blupd_openpilot_bin - -blupd_openpilot_%: bl_openpilot_bino - $(V1) mkdir -p $(BUILD_DIR)/blupd_openpilot/dep - $(V1) cd $(ROOT_DIR)/flight/Bootloaders/BootloaderUpdater && \ - $(MAKE) -r --no-print-directory \ - OUTDIR="$(BUILD_DIR)/blupd_openpilot" TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ - REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" \ - BOARD=STM3210E_OP MODEL=HD MODEL_SUFFIX=_OP \ - BLOBJ=$(BUILD_DIR)/bl_openpilot/OpenPilot_BL.bin.o $* - -.PHONY: blupd_openpilot_clean -blupd_openpilot_clean: - $(V0) @echo " CLEAN $@" - $(V1) $(RM) -fr $(BUILD_DIR)/blupd_openpilot - -.PHONY: ahrs -ahrs: ahrs_bin - -ahrs_%: uavobjects_flight - $(V1) mkdir -p $(BUILD_DIR)/ahrs/dep - $(V1) cd $(ROOT_DIR)/flight/AHRS && \ - $(MAKE) -r --no-print-directory \ - OUTDIR="$(BUILD_DIR)/ahrs" TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ - REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" $* - -.PHONY: ahrs_clean -ahrs_clean: - $(V0) @echo " CLEAN $@" - $(V1) $(RM) -fr $(BUILD_DIR)/ahrs - -.PHONY: bl_ahrs -bl_ahrs: bl_ahrs_bin -bl_ahrs_bino: bl_ahrs_bin - -bl_ahrs_%: - $(V1) mkdir -p $(BUILD_DIR)/bl_ahrs/dep - $(V1) cd $(ROOT_DIR)/flight/Bootloaders/AHRS && \ - $(MAKE) -r --no-print-directory \ - OUTDIR="$(BUILD_DIR)/bl_ahrs" TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ - REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" $* - -.PHONY: bl_ahrs_clean -bl_ahrs_clean: - $(V0) @echo " CLEAN $@" - $(V1) $(RM) -fr $(BUILD_DIR)/bl_ahrs - -.PHONY: blupd_ahrs -blupd_ahrs: blupd_ahrs_bin - -blupd_ahrs_%: bl_ahrs_bino bl_ahrs - $(V1) mkdir -p $(BUILD_DIR)/blupd_ahrs/dep - $(V1) cd $(ROOT_DIR)/flight/Bootloaders/BootloaderUpdater && \ - $(MAKE) -r --no-print-directory \ - OUTDIR="$(BUILD_DIR)/blupd_ahrs" TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ - REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" \ - BOARD=STM32103CB_AHRS MODEL=MD \ - BLOBJ=$(BUILD_DIR)/bl_ahrs/AHRS_BL.bin.o $* - -.PHONY: blupd_ahrs_clean -blupd_ahrs_clean: - $(V0) @echo " CLEAN $@" - $(V1) $(RM) -fr $(BUILD_DIR)/blupd_ahrs - -.PHONY: coptercontrol -coptercontrol: coptercontrol_bin - -coptercontrol_%: uavobjects_flight - $(V1) mkdir -p $(BUILD_DIR)/coptercontrol/dep - $(V1) cd $(ROOT_DIR)/flight/CopterControl && \ - $(MAKE) -r --no-print-directory \ - OUTDIR="$(BUILD_DIR)/coptercontrol" TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ - REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" $* - -.PHONY: coptercontrol_clean -coptercontrol_clean: - $(V0) @echo " CLEAN $@" - $(V1) $(RM) -fr $(BUILD_DIR)/coptercontrol - -.PHONY: bl_coptercontrol -bl_coptercontrol: bl_coptercontrol_bin -bl_coptercontrol_bino: bl_coptercontrol_bin - -bl_coptercontrol_%: - $(V1) mkdir -p $(BUILD_DIR)/bl_coptercontrol/dep - $(V1) cd $(ROOT_DIR)/flight/Bootloaders/CopterControl && \ - $(MAKE) -r --no-print-directory \ - OUTDIR="$(BUILD_DIR)/bl_coptercontrol" TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ - REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" $* - -.PHONY: bl_coptercontrol_clean -bl_coptercontrol_clean: - $(V0) @echo " CLEAN $@" - $(V1) $(RM) -fr $(BUILD_DIR)/bl_coptercontrol - -.PHONY: blupd_coptercontrol -blupd_coptercontrol: blupd_coptercontrol_bin - -blupd_coptercontrol_%: bl_coptercontrol_bino - $(V1) mkdir -p $(BUILD_DIR)/blupd_coptercontrol/dep - $(V1) cd $(ROOT_DIR)/flight/Bootloaders/BootloaderUpdater && \ - $(MAKE) -r --no-print-directory \ - OUTDIR="$(BUILD_DIR)/blupd_coptercontrol" TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ - REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" \ - BOARD=STM32103CB_CC_Rev1 MODEL=MD MODEL_SUFFIX=_CC \ - BLOBJ=$(BUILD_DIR)/bl_coptercontrol/CopterControl_BL.bin.o $* - -.PHONY: blupd_coptercontrol_clean -blupd_coptercontrol_clean: - $(V0) @echo " CLEAN $@" - $(V1) $(RM) -fr $(BUILD_DIR)/blupd_coptercontrol - -.PHONY: pipxtreme -pipxtreme: pipxtreme_bin - -pipxtreme_%: uavobjects_flight - $(V1) mkdir -p $(BUILD_DIR)/pipxtreme/dep - $(V1) cd $(ROOT_DIR)/flight/PipXtreme && \ - $(MAKE) -r --no-print-directory \ - OUTDIR="$(BUILD_DIR)/pipxtreme" TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ - REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" $* - -.PHONY: pipxtreme_clean -pipxtreme_clean: - $(V0) @echo " CLEAN $@" - $(V1) $(RM) -fr $(BUILD_DIR)/pipxtreme - -.PHONY: bl_pipxtreme -bl_pipxtreme: bl_pipxtreme_bin -bl_pipxtreme_bino: bl_pipxtreme_bin - -bl_pipxtreme_%: - $(V1) mkdir -p $(BUILD_DIR)/bl_pipxtreme/dep - $(V1) cd $(ROOT_DIR)/flight/Bootloaders/PipXtreme && \ - $(MAKE) -r --no-print-directory \ - OUTDIR="$(BUILD_DIR)/bl_pipxtreme" TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ - REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" $* - -.PHONY: bl_pipxtreme_clean -bl_pipxtreme_clean: - $(V0) @echo " CLEAN $@" - $(V1) $(RM) -fr $(BUILD_DIR)/bl_pipxtreme - -.PHONY: blupd_pipxtreme -blupd_pipxtreme: blupd_pipxtreme_bin - -blupd_pipxtreme_%: bl_pipxtreme_bino - $(V1) mkdir -p $(BUILD_DIR)/blupd_pipxtreme/dep - $(V1) cd $(ROOT_DIR)/flight/Bootloaders/BootloaderUpdater && \ - $(MAKE) -r --no-print-directory \ - OUTDIR="$(BUILD_DIR)/blupd_pipxtreme" TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ - REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" \ - BOARD=STM32103CB_PIPXTREME MODEL=MD MODEL_SUFFIX=_CC \ - BLOBJ=$(BUILD_DIR)/bl_pipxtreme/PipXtreme_BL.bin.o $* - -.PHONY: blupd_pipxtreme_clean -blupd_pipxtreme_clean: - $(V0) @echo " CLEAN $@" - $(V1) $(RM) -fr $(BUILD_DIR)/blupd_pipxtreme - - -.PHONY: ins -ins: ins_bin - -ins_%: uavobjects_flight - $(V1) mkdir -p $(BUILD_DIR)/ins/dep - $(V1) cd $(ROOT_DIR)/flight/INS && \ - $(MAKE) -r --no-print-directory \ - OUTDIR="$(BUILD_DIR)/ins" TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ - REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" $* - -.PHONY: ins_clean -ins_clean: - $(V0) @echo " CLEAN $@" - $(V1) $(RM) -fr $(BUILD_DIR)/ins - -.PHONY: bl_ins -bl_ins: bl_ins_elf - -bl_ins_%: - $(V1) mkdir -p $(BUILD_DIR)/bl_ins/dep - $(V1) cd $(ROOT_DIR)/flight/Bootloaders/INS && \ - $(MAKE) -r --no-print-directory \ - OUTDIR="$(BUILD_DIR)/bl_ins" TCHAIN_PREFIX="$(ARM_SDK_PREFIX)" \ - REMOVE_CMD="$(RM)" OOCD_EXE="$(OPENOCD)" $* - -.PHONY: bl_ins_clean -bl_ins_clean: - $(V0) @echo " CLEAN $@" - $(V1) $(RM) -fr $(BUILD_DIR)/bl_ins +# Expand the firmware rules +$(foreach board, $(ALL_BOARDS), $(eval $(call FW_TEMPLATE,$(board),$($(board)_friendly)))) +# Expand the bootloader rules +$(foreach board, $(ALL_BOARDS), $(eval $(call BL_TEMPLATE,$(board),$($(board)_friendly)))) .PHONY: sim_posix sim_posix: sim_posix_elf @@ -587,3 +499,12 @@ sim_win32_%: uavobjects_flight $(V1) mkdir -p $(BUILD_DIR)/sitl_win32 $(V1) $(MAKE) --no-print-directory \ -C $(ROOT_DIR)/flight/OpenPilot --file=$(ROOT_DIR)/flight/OpenPilot/Makefile.win32 $* + +############################## +# +# Packaging components +# +############################## +.PHONY: package +package: + $(V1) cd $@ && $(MAKE) --no-print-directory $@ diff --git a/artwork/3D Model/boards/CopterControl/CopterControl.3ds b/artwork/3D Model/boards/CopterControl/CopterControl.3ds new file mode 100644 index 000000000..c158dba99 Binary files /dev/null and b/artwork/3D Model/boards/CopterControl/CopterControl.3ds differ diff --git a/artwork/3D Model/boards/CopterControl/TEXTURE.PNG b/artwork/3D Model/boards/CopterControl/TEXTURE.PNG new file mode 100644 index 000000000..6a8cf8344 Binary files /dev/null and b/artwork/3D Model/boards/CopterControl/TEXTURE.PNG differ diff --git a/artwork/3D Model/multi/joes_cnc/CC.PNG b/artwork/3D Model/multi/joes_cnc/CC.PNG new file mode 100644 index 000000000..467f34a97 Binary files /dev/null and b/artwork/3D Model/multi/joes_cnc/CC.PNG differ diff --git a/artwork/3D Model/multi/joes_cnc/J14-QT_+.3DS b/artwork/3D Model/multi/joes_cnc/J14-QT_+.3DS new file mode 100644 index 000000000..1879b07c6 Binary files /dev/null and b/artwork/3D Model/multi/joes_cnc/J14-QT_+.3DS differ diff --git a/artwork/3D Model/multi/joes_cnc/J14-QT_+.jpg b/artwork/3D Model/multi/joes_cnc/J14-QT_+.jpg new file mode 100644 index 000000000..bb5d7a8de Binary files /dev/null and b/artwork/3D Model/multi/joes_cnc/J14-QT_+.jpg differ diff --git a/artwork/3D Model/multi/joes_cnc/J14-QT_X.3DS b/artwork/3D Model/multi/joes_cnc/J14-QT_X.3DS new file mode 100644 index 000000000..f26dacb45 Binary files /dev/null and b/artwork/3D Model/multi/joes_cnc/J14-QT_X.3DS differ diff --git a/artwork/3D Model/multi/joes_cnc/J14-QT_X.jpg b/artwork/3D Model/multi/joes_cnc/J14-QT_X.jpg new file mode 100644 index 000000000..24bd15569 Binary files /dev/null and b/artwork/3D Model/multi/joes_cnc/J14-QT_X.jpg differ diff --git a/artwork/3D Model/multi/joes_cnc/J14-Q_+.3DS b/artwork/3D Model/multi/joes_cnc/J14-Q_+.3DS new file mode 100644 index 000000000..21fbccf01 Binary files /dev/null and b/artwork/3D Model/multi/joes_cnc/J14-Q_+.3DS differ diff --git a/artwork/3D Model/multi/joes_cnc/J14-Q_+.jpg b/artwork/3D Model/multi/joes_cnc/J14-Q_+.jpg new file mode 100644 index 000000000..bdc45dd07 Binary files /dev/null and b/artwork/3D Model/multi/joes_cnc/J14-Q_+.jpg differ diff --git a/artwork/3D Model/multi/joes_cnc/J14-Q_X.3DS b/artwork/3D Model/multi/joes_cnc/J14-Q_X.3DS new file mode 100644 index 000000000..529e60fac Binary files /dev/null and b/artwork/3D Model/multi/joes_cnc/J14-Q_X.3DS differ diff --git a/artwork/3D Model/multi/joes_cnc/J14-Q_X.jpg b/artwork/3D Model/multi/joes_cnc/J14-Q_X.jpg new file mode 100644 index 000000000..8e1de3196 Binary files /dev/null and b/artwork/3D Model/multi/joes_cnc/J14-Q_X.jpg differ diff --git a/artwork/3D Model/multi/joes_cnc/TEXTURE.PNG b/artwork/3D Model/multi/joes_cnc/TEXTURE.PNG new file mode 100644 index 000000000..5d26bb120 Binary files /dev/null and b/artwork/3D Model/multi/joes_cnc/TEXTURE.PNG differ diff --git a/artwork/Dials/default/flightmode-status.svg b/artwork/Dials/default/flightmode-status.svg index dca4d213a..80935d0c3 100644 --- a/artwork/Dials/default/flightmode-status.svg +++ b/artwork/Dials/default/flightmode-status.svg @@ -14,7 +14,7 @@ height="80.827866" id="svg10068" version="1.1" - inkscape:version="0.47 r22583" + inkscape:version="0.48.1 r9760" sodipodi:docname="flightmode-status.svg" inkscape:export-filename="H:\Documents\Hobbies\W433\My Gauges\vbat-001.png" inkscape:export-xdpi="103.61" @@ -949,6 +949,94 @@ fx="29.77438" fy="7.0922189" r="25.380436" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/artwork/Dials/deluxe/lineardial-horizontal.svg b/artwork/Dials/deluxe/lineardial-horizontal.svg new file mode 100644 index 000000000..2f6f71b17 --- /dev/null +++ b/artwork/Dials/deluxe/lineardial-horizontal.svg @@ -0,0 +1,1329 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Edouard Lafargue + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/artwork/Dials/deluxe/lineardial-vertical.svg b/artwork/Dials/deluxe/lineardial-vertical.svg new file mode 100644 index 000000000..010283c2c --- /dev/null +++ b/artwork/Dials/deluxe/lineardial-vertical.svg @@ -0,0 +1,929 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Edouard Lafargue + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/artwork/Font/Copyright.txt b/artwork/Font/Copyright.txt index 52dfdf7de..92b0a4d87 100644 --- a/artwork/Font/Copyright.txt +++ b/artwork/Font/Copyright.txt @@ -16,5 +16,7 @@ Symbols: Capital A = OpenPilot Logo Capital B = CC-BY-SA +Capital B = CC-BY-NC-SA +Capital D = RoHS \ No newline at end of file diff --git a/artwork/Font/OpenPilot.ttf b/artwork/Font/OpenPilot.ttf index 60cada62a..852f8914a 100644 Binary files a/artwork/Font/OpenPilot.ttf and b/artwork/Font/OpenPilot.ttf differ diff --git a/artwork/GCS Icons/README.txt b/artwork/GCS Icons/README.txt new file mode 100644 index 000000000..5c290233f --- /dev/null +++ b/artwork/GCS Icons/README.txt @@ -0,0 +1 @@ +Those icons come from the Tango set and are used in the GCS. diff --git a/artwork/GCS Icons/application-certificate.svg b/artwork/GCS Icons/application-certificate.svg new file mode 100644 index 000000000..077f741d8 --- /dev/null +++ b/artwork/GCS Icons/application-certificate.svg @@ -0,0 +1,443 @@ + + + + + + image/svg+xml + + + + + + CertificateJakub Steinercertificate + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/artwork/GCS Icons/dialog-warning.svg b/artwork/GCS Icons/dialog-warning.svg new file mode 100644 index 000000000..8de454769 --- /dev/null +++ b/artwork/GCS Icons/dialog-warning.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/artwork/GCS Icons/edit-delete.svg b/artwork/GCS Icons/edit-delete.svg new file mode 100644 index 000000000..8c6df9685 --- /dev/null +++ b/artwork/GCS Icons/edit-delete.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/artwork/GCS Icons/help-contents.svg b/artwork/GCS Icons/help-contents.svg new file mode 100644 index 000000000..620acb6ae --- /dev/null +++ b/artwork/GCS Icons/help-contents.svg @@ -0,0 +1,37 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/artwork/GCS Icons/help-hint.svg b/artwork/GCS Icons/help-hint.svg new file mode 100644 index 000000000..675b93dd6 --- /dev/null +++ b/artwork/GCS Icons/help-hint.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/artwork/GCS Icons/icon-checkbox.svg b/artwork/GCS Icons/icon-checkbox.svg new file mode 100644 index 000000000..185dfc615 --- /dev/null +++ b/artwork/GCS Icons/icon-checkbox.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/artwork/GCS Icons/icon-gears.svg b/artwork/GCS Icons/icon-gears.svg new file mode 100644 index 000000000..8e2572fce --- /dev/null +++ b/artwork/GCS Icons/icon-gears.svg @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/artwork/GCS Icons/icon-info.svg b/artwork/GCS Icons/icon-info.svg new file mode 100644 index 000000000..62c2cecd6 --- /dev/null +++ b/artwork/GCS Icons/icon-info.svg @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/artwork/GCS Icons/icon-refresh.svg b/artwork/GCS Icons/icon-refresh.svg new file mode 100644 index 000000000..3d0cc562d --- /dev/null +++ b/artwork/GCS Icons/icon-refresh.svg @@ -0,0 +1,230 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/artwork/GCS Icons/icon-stop.svg b/artwork/GCS Icons/icon-stop.svg new file mode 100644 index 000000000..8955e4375 --- /dev/null +++ b/artwork/GCS Icons/icon-stop.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/artwork/GCS Icons/window-close.svg b/artwork/GCS Icons/window-close.svg new file mode 100644 index 000000000..f8e6a8d63 --- /dev/null +++ b/artwork/GCS Icons/window-close.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/artwork/Misc/multirotor-shapes.svg b/artwork/Misc/multirotor-shapes.svg index 2ff48cfdc..0d7a79c42 100644 --- a/artwork/Misc/multirotor-shapes.svg +++ b/artwork/Misc/multirotor-shapes.svg @@ -12,11 +12,11 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg4183" version="1.1" - inkscape:version="0.48+devel r10146" + inkscape:version="0.48.1 r9760" width="4065.2493" height="1760.019" xml:space="preserve" - sodipodi:docname="quad-shapes.svg">image/svg+xml + + + + + + + - - - - - - - - - - - - - - 20 - 20 - - - - 10 - 10 - - - - 10 - 10 - - - - 20 - 20 - + transform="matrix(4.6362185,0,0,1.5267412,-1475.4746,-169.05952)" + id="g4280"> + + + + 10 + 10 + + + + + 20 + 20 + + + + + -10 + -10 + + + + + + + + + + + + + + + + + + + -20 + -20 + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2094,141 +2075,585 @@ id="tspan4328" sodipodi:role="line">GPS - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + inkscape:label="#g5089"> + id="angle-3"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + id="g7953"> + + + + + + + + + + + + + + + + + + + + inkscape:label="#path3779-1" + inkscape:connector-curvature="0" /> + inkscape:label="#path3779-7" + inkscape:connector-curvature="0" /> - - - - + inkscape:label="#g4577"> + + + style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3.06858087;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" + inkscape:connector-curvature="0" /> + d="m 280.28409,30.123177 5.7832,0 7.54688,11.08789 0,-11.08789 5.83789,0 0,20.042968 -5.83789,0 -7.50586,-11.005859 0,11.005859 -5.82422,0 z" + inkscape:connector-curvature="0" /> + id="path6986" + inkscape:connector-curvature="0" /> + d="m -217.0715,43.535286 5.89258,-0.369141 c 0.12759,0.957038 0.38736,1.686204 0.77929,2.1875 0.63801,0.811202 1.54947,1.216801 2.73438,1.216797 0.8841,4e-6 1.56542,-0.207353 2.04394,-0.62207 0.47851,-0.414709 0.71776,-0.895503 0.71778,-1.442383 -2e-5,-0.519525 -0.22788,-0.984368 -0.6836,-1.394531 -0.45574,-0.410149 -1.51303,-0.797518 -3.17187,-1.16211 -2.71616,-0.610668 -4.653,-1.421865 -5.81055,-2.433593 -1.16667,-1.011707 -1.75,-2.30142 -1.75,-3.869141 0,-1.029932 0.2985,-2.002913 0.89551,-2.918945 0.597,-0.915998 1.49479,-1.636049 2.69336,-2.160156 1.19856,-0.524069 2.84146,-0.786113 4.92871,-0.786133 2.56118,2e-5 4.51398,0.476257 5.8584,1.428711 1.34438,0.952492 2.14418,2.46779 2.39941,4.545898 l -5.83789,0.341797 c -0.15496,-0.902329 -0.48081,-1.558578 -0.97754,-1.96875 -0.49675,-0.41014 -1.18263,-0.615218 -2.05762,-0.615234 -0.72006,1.6e-5 -1.26237,0.152685 -1.62695,0.458007 -0.36459,0.305355 -0.54688,0.676774 -0.54687,1.114258 -1e-5,0.319025 0.15038,0.606134 0.45117,0.861328 0.29166,0.264337 0.98436,0.510431 2.07812,0.738282 2.70702,0.583346 4.64615,1.173514 5.81739,1.770507 1.1712,0.597017 2.02342,1.337576 2.55664,2.22168 0.53318,0.884123 0.79978,1.873055 0.7998,2.966797 -2e-5,1.285161 -0.35549,2.470056 -1.06641,3.554687 -0.71095,1.084638 -1.70444,1.907228 -2.98046,2.467774 -1.27606,0.560547 -2.88478,0.84082 -4.82618,0.84082 -3.40886,0 -5.76953,-0.656249 -7.08203,-1.96875 -1.3125,-1.312497 -2.05534,-2.980464 -2.22851,-5.003906 z" + inkscape:connector-curvature="0" /> + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" /> + d="m 778.62402,43.535286 5.89258,-0.369141 c 0.1276,0.957038 0.38736,1.686204 0.7793,2.1875 0.63801,0.811202 1.54947,1.216801 2.73437,1.216797 0.88411,4e-6 1.56542,-0.207353 2.04395,-0.62207 0.4785,-0.414709 0.71776,-0.895503 0.71777,-1.442383 -1e-5,-0.519525 -0.22788,-0.984368 -0.68359,-1.394531 -0.45574,-0.410149 -1.51303,-0.797518 -3.17188,-1.16211 -2.71615,-0.610668 -4.653,-1.421865 -5.81054,-2.433593 -1.16667,-1.011707 -1.75001,-2.30142 -1.75,-3.869141 -10e-6,-1.029932 0.2985,-2.002913 0.8955,-2.918945 0.59701,-0.915998 1.49479,-1.636049 2.69336,-2.160156 1.19856,-0.524069 2.84147,-0.786113 4.92871,-0.786133 2.56119,2e-5 4.51399,0.476257 5.8584,1.428711 1.34439,0.952492 2.14419,2.46779 2.39942,4.545898 l -5.83789,0.341797 c -0.15496,-0.902329 -0.48081,-1.558578 -0.97754,-1.96875 -0.49676,-0.41014 -1.18263,-0.615218 -2.05762,-0.615234 -0.72006,1.6e-5 -1.26238,0.152685 -1.62695,0.458007 -0.36459,0.305355 -0.54689,0.676774 -0.54688,1.114258 -1e-5,0.319025 0.15039,0.606134 0.45117,0.861328 0.29166,0.264337 0.98437,0.510431 2.07813,0.738282 2.70702,0.583346 4.64614,1.173514 5.81738,1.770507 1.17121,0.597017 2.02342,1.337576 2.55664,2.22168 0.53319,0.884123 0.79979,1.873055 0.79981,2.966797 -2e-5,1.285161 -0.35549,2.470056 -1.06641,3.554687 -0.71095,1.084638 -1.70444,1.907228 -2.98047,2.467774 -1.27605,0.560547 -2.88478,0.84082 -4.82617,0.84082 -3.40886,0 -5.76954,-0.656249 -7.08203,-1.96875 -1.3125,-1.312497 -2.05534,-2.980464 -2.22852,-5.003906 z" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + d="m 26.930511,30.123177 5.878907,0 2.11914,11.197265 3.089844,-11.197265 5.865234,0 3.103516,11.197265 2.119141,-11.197265 5.851562,0 -4.416015,20.042968 -6.070313,0 -3.513672,-12.61914 -3.5,12.61914 -6.070312,0 z" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + d="m 530.34277,30.123177 16.59766,0 0,4.279296 -10.39063,0 0,3.185547 9.63868,0 0,4.087891 -9.63868,0 0,3.951172 10.69141,0 0,4.539062 -16.89844,0 z" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3048" + inkscape:connector-curvature="0" /> + id="path3651" + inkscape:connector-curvature="0" /> + id="path3653" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3656" + inkscape:connector-curvature="0" /> + id="path3658" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3661" + inkscape:connector-curvature="0" /> + id="path3663" + inkscape:connector-curvature="0" /> + id="path3056" + inkscape:connector-curvature="0" /> + id="path3666" + inkscape:connector-curvature="0" /> + id="path3668" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3671" + inkscape:connector-curvature="0" /> + id="path3673" + inkscape:connector-curvature="0" /> + id="path3060" + inkscape:connector-curvature="0" /> + id="path3676" + inkscape:connector-curvature="0" /> + id="path3678" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3681" + inkscape:connector-curvature="0" /> + id="path3683" + inkscape:connector-curvature="0" /> + id="path3685" + inkscape:connector-curvature="0" /> + id="path3924" + inkscape:connector-curvature="0" /> + id="path3688" + inkscape:connector-curvature="0" /> + id="path3690" + inkscape:connector-curvature="0" /> + id="path3692" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3695" + inkscape:connector-curvature="0" /> + id="path3697" + inkscape:connector-curvature="0" /> + id="path3699" + inkscape:connector-curvature="0" /> + id="path3940" + inkscape:connector-curvature="0" /> + id="path3702" + inkscape:connector-curvature="0" /> + id="path3704" + inkscape:connector-curvature="0" /> + id="path3706" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3709" + inkscape:connector-curvature="0" /> + id="path3711" + inkscape:connector-curvature="0" /> + id="path3713" + inkscape:connector-curvature="0" /> + id="path3956" + inkscape:connector-curvature="0" /> + id="path3716" + inkscape:connector-curvature="0" /> + id="path3718" + inkscape:connector-curvature="0" /> + id="path3720" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3723" + inkscape:connector-curvature="0" /> + id="path3725" + inkscape:connector-curvature="0" /> + id="path3727" + inkscape:connector-curvature="0" /> + id="path3972" + inkscape:connector-curvature="0" /> + id="path3730" + inkscape:connector-curvature="0" /> + id="path3732" + inkscape:connector-curvature="0" /> + id="path3734" + inkscape:connector-curvature="0" /> + id="path4052" + inkscape:connector-curvature="0" /> + id="path3737" + inkscape:connector-curvature="0" /> + id="path3739" + inkscape:connector-curvature="0" /> + id="path3741" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3744" + inkscape:connector-curvature="0" /> + id="path3746" + inkscape:connector-curvature="0" /> + id="path3748" + inkscape:connector-curvature="0" /> + id="path4068" + inkscape:connector-curvature="0" /> + id="path3751" + inkscape:connector-curvature="0" /> + id="path3753" + inkscape:connector-curvature="0" /> + id="path3755" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3758" + inkscape:connector-curvature="0" /> + id="path3760" + inkscape:connector-curvature="0" /> + id="path3762" + inkscape:connector-curvature="0" /> + id="path4084" + inkscape:connector-curvature="0" /> + id="path3765" + inkscape:connector-curvature="0" /> + id="path3767" + inkscape:connector-curvature="0" /> + id="path3769" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3772" + inkscape:connector-curvature="0" /> + id="path3774" + inkscape:connector-curvature="0" /> + id="path3776" + inkscape:connector-curvature="0" /> + id="path4100" + inkscape:connector-curvature="0" /> + id="path3780" + inkscape:connector-curvature="0" /> + id="path3782" + inkscape:connector-curvature="0" /> + id="path3784" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3787" + inkscape:connector-curvature="0" /> + id="path3789" + inkscape:connector-curvature="0" /> + id="path3791" + inkscape:connector-curvature="0" /> + id="path4116" + inkscape:connector-curvature="0" /> + id="path3794" + inkscape:connector-curvature="0" /> + id="path3796" + inkscape:connector-curvature="0" /> + id="path3798" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3801" + inkscape:connector-curvature="0" /> + id="path3803" + inkscape:connector-curvature="0" /> + id="path3805" + inkscape:connector-curvature="0" /> + id="path4228" + inkscape:connector-curvature="0" /> + id="path3809" + inkscape:connector-curvature="0" /> + id="path3811" + inkscape:connector-curvature="0" /> + id="path3813" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3816" + inkscape:connector-curvature="0" /> + id="path3818" + inkscape:connector-curvature="0" /> + id="path3820" + inkscape:connector-curvature="0" /> + id="path4244" + inkscape:connector-curvature="0" /> + id="path3823" + inkscape:connector-curvature="0" /> + id="path3825" + inkscape:connector-curvature="0" /> + id="path3827" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3830" + inkscape:connector-curvature="0" /> + id="path3832" + inkscape:connector-curvature="0" /> + id="path3834" + inkscape:connector-curvature="0" /> + id="path4260" + inkscape:connector-curvature="0" /> + id="path3837" + inkscape:connector-curvature="0" /> + id="path3839" + inkscape:connector-curvature="0" /> + id="path3841" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3844" + inkscape:connector-curvature="0" /> + id="path3846" + inkscape:connector-curvature="0" /> + id="path3848" + inkscape:connector-curvature="0" /> + id="path3306" + inkscape:connector-curvature="0" /> + id="path3851" + inkscape:connector-curvature="0" /> + id="path3853" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3856" + inkscape:connector-curvature="0" /> + id="path3858" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" + inkscape:connector-curvature="0" /> + id="path4116-9" + inkscape:connector-curvature="0" /> + id="path3794-8" + inkscape:connector-curvature="0" /> + id="path3796-8" + inkscape:connector-curvature="0" /> + id="path3798-2" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3801-1" + inkscape:connector-curvature="0" /> + id="path3803-7" + inkscape:connector-curvature="0" /> + id="path3805-1" + inkscape:connector-curvature="0" /> + id="path4228-5" + inkscape:connector-curvature="0" /> + id="path3809-7" + inkscape:connector-curvature="0" /> + id="path3811-6" + inkscape:connector-curvature="0" /> + id="path3813-1" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3816-2" + inkscape:connector-curvature="0" /> + id="path3818-2" + inkscape:connector-curvature="0" /> + id="path3820-1" + inkscape:connector-curvature="0" /> + id="path4244-8" + inkscape:connector-curvature="0" /> + id="path3823-7" + inkscape:connector-curvature="0" /> + id="path3825-6" + inkscape:connector-curvature="0" /> + id="path3827-1" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3830-7" + inkscape:connector-curvature="0" /> + id="path3832-9" + inkscape:connector-curvature="0" /> + id="path3834-5" + inkscape:connector-curvature="0" /> + id="path4260-3" + inkscape:connector-curvature="0" /> + id="path3837-2" + inkscape:connector-curvature="0" /> + id="path3839-3" + inkscape:connector-curvature="0" /> + id="path3841-3" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3844-3" + inkscape:connector-curvature="0" /> + id="path3846-8" + inkscape:connector-curvature="0" /> + id="path3848-7" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3681-1" + inkscape:connector-curvature="0" /> + id="path3683-9" + inkscape:connector-curvature="0" /> + id="path3685-8" + inkscape:connector-curvature="0" /> + id="path3924-5" + inkscape:connector-curvature="0" /> + id="path3688-2" + inkscape:connector-curvature="0" /> + id="path3690-8" + inkscape:connector-curvature="0" /> + id="path3692-6" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3695-8" + inkscape:connector-curvature="0" /> + id="path3697-6" + inkscape:connector-curvature="0" /> + id="path3699-5" + inkscape:connector-curvature="0" /> + id="path3940-9" + inkscape:connector-curvature="0" /> + id="path3702-0" + inkscape:connector-curvature="0" /> + id="path3704-6" + inkscape:connector-curvature="0" /> + id="path3706-1" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3709-3" + inkscape:connector-curvature="0" /> + id="path3711-4" + inkscape:connector-curvature="0" /> + id="path3713-4" + inkscape:connector-curvature="0" /> + id="path3956-0" + inkscape:connector-curvature="0" /> + id="path3716-6" + inkscape:connector-curvature="0" /> + id="path3718-1" + inkscape:connector-curvature="0" /> + id="path3720-8" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3723-3" + inkscape:connector-curvature="0" /> + id="path3725-7" + inkscape:connector-curvature="0" /> + id="path3727-8" + inkscape:connector-curvature="0" /> + id="path3972-2" + inkscape:connector-curvature="0" /> + id="path3730-1" + inkscape:connector-curvature="0" /> + id="path3732-3" + inkscape:connector-curvature="0" /> + id="path3734-5" + inkscape:connector-curvature="0" /> @@ -3570,7 +4191,8 @@ inkscape:groupmode="layer" id="layer6" inkscape:label="Bottom area" - style="display:inline"> + style="display:none" + sodipodi:insensitive="true"> + id="path10183" + inkscape:connector-curvature="0" /> + id="path10185" + inkscape:connector-curvature="0" /> @@ -3630,19 +4254,22 @@ id="gcstelemetry-Connected" d="m -109.55949,412.40842 0,9.28125 -31.40625,0 0,4.90625 0,0.0937 0,4.90625 31.40625,0 0,9.28125 14.250003,-14.25 -14.250003,-14.21875 z" style="fill:#1c870b;fill-opacity:1;stroke:#113b05;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - inkscape:label="#path7548" /> + inkscape:label="#path7548" + inkscape:connector-curvature="0" /> + sodipodi:nodetypes="ccccccccccccccccc" + inkscape:connector-curvature="0" /> + sodipodi:nodetypes="cccccccccc" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#1c5313;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#1c5313;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + inkscape:connector-curvature="0" /> + id="path5044" + inkscape:connector-curvature="0" /> + id="path5046" + inkscape:connector-curvature="0" /> + id="path4035" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4039" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4043" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4061" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4065" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4071" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4075" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4079" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4085" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4089" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4095" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4099" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4103" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4109" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4113" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4119" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5650" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5654" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5658" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5662" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5666" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5670" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5674" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5678" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5682" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5686" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5690" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5694" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5698" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5702" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5706" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> @@ -4020,6 +4713,7 @@ style="fill:#453e3e;fill-opacity:1;stroke:#000000;stroke-width:4.08031273;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" d="m -115.54603,-47.690059 c -2.50791,0 -4.54785,1.99743 -4.54785,4.50534 l 0,807.009359 c 0,2.5079 2.03994,4.54785 4.54785,4.54785 l 807.00936,0 c 2.5079,0 4.50534,-2.03995 4.50534,-4.54785 l 0,-807.009359 c 0,-2.50791 -1.99744,-4.50534 -4.50534,-4.50534 l -807.00936,0 z M 289.34,11.395534 c 150.15374,0 271.88009,59.618647 272.02085,133.162706 l 0.21252,48.57516 -0.38253,374.99409 C 556.30557,639.62843 436.47945,673.69951 289.34,673.69951 c -147.13944,0 -266.965544,-34.07108 -271.850832,-105.57202 l -0.212516,0 0,-374.99409 0.0425,-48.58122 C 17.459912,71.008115 139.18627,11.395534 289.34,11.395534 z" id="rect2816" - sodipodi:nodetypes="cccccccccccccsccccc" /> + sodipodi:nodetypes="cccccccccccccsccccc" + inkscape:connector-curvature="0" /> diff --git a/flight/AHRS/Makefile b/flight/AHRS/Makefile index 4b0a6417b..46405ca6c 100644 --- a/flight/AHRS/Makefile +++ b/flight/AHRS/Makefile @@ -25,6 +25,13 @@ WHEREAMI := $(dir $(lastword $(MAKEFILE_LIST))) TOP := $(realpath $(WHEREAMI)/../../) include $(TOP)/make/firmware-defs.mk +include $(TOP)/make/boards/$(BOARD_NAME)/board-info.mk + +# Target file name (without extension). +TARGET := fw_$(BOARD_NAME) + +# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) +OUTDIR := $(TOP)/build/$(TARGET) # Set developer code and compile options # Set to YES for debugging @@ -41,21 +48,6 @@ endif FLASH_TOOL = OPENOCD -# MCU name, submodel and board -# - MCU used for compiler-option (-mcpu) -# - MODEL used for linker-script name (-T) and passed as define -# - BOARD just passed as define (optional) -MCU = cortex-m3 -CHIP = STM32F103CBT -BOARD = STM32103CB_AHRS -MODEL = MD - -# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) -OUTDIR = $(TOP)/build/ahrs - -# Target file name (without extension). -TARGET = AHRS - # Paths AHRS = ./ AHRSINC = $(AHRS)/inc @@ -160,7 +152,7 @@ CPPSRCARM = # Even though the DOS/Win* filesystem matches both .s and .S the same, # it will preserve the spelling of the filenames, and gcc itself does # care about how the name is spelled on its command-line. -ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL).S +ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL)$(MODEL_SUFFIX).S # List Assembler source files here which must be assembled in ARM-Mode.. ASRCARM = @@ -223,7 +215,6 @@ CDEFS = -DSTM32F10X_$(MODEL) CDEFS += -DUSE_STDPERIPH_DRIVER CDEFS += -DUSE_$(BOARD) CDEFS += -DIN_AHRS -CDEFS += -DUSE_BOOTLOADER # Place project-specific -D and/or -U options for # Assembler with preprocessor here. @@ -299,21 +290,8 @@ LDFLAGS += -lc -lgcc LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_memory.ld LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_sections.ld -OOCD_LOADFILE+=$(OUTDIR)/$(TARGET).bin -# Program -OOCD_CL+=-c "flash write_image erase $(OOCD_LOADFILE) 0x08002000 bin" -# Verify -OOCD_CL+=-c "verify_image $(OOCD_LOADFILE) 0x08002000 bin" -# reset target -OOCD_CL+=-c "reset run" -# terminate OOCD after programming -OOCD_CL+=-c shutdown - - # Define programs and commands. REMOVE = $(REMOVE_CMD) -f -###SHELL = sh -###COPY = cp # List of all source files. ALLSRC = $(ASRCARM) $(ASRC) $(SRCARM) $(SRC) $(CPPSRCARM) $(CPPSRC) @@ -345,14 +323,6 @@ endif endif endif -# Program the device. -ifeq ($(FLASH_TOOL),OPENOCD) -# Program the device with Dominic Rath's OPENOCD in "batch-mode", needs cfg and "reset-script". -program: $(OUTDIR)/$(TARGET).bin - @echo ${quote}Programming with OPENOCD${quote} - $(OOCD_EXE) $(OOCD_CL) -endif - # Link: create ELF output file from object files. $(eval $(call LINK_TEMPLATE, $(OUTDIR)/$(TARGET).elf, $(ALLOBJ))) @@ -382,23 +352,37 @@ $(eval $(call PARTIAL_COMPILE_ARM_TEMPLATE, SRCARM)) $(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin -.PHONY: elf lss sym hex bin bino +$(eval $(call OPFW_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BOARD_TYPE),$(BOARD_REVISION))) + +# Add jtag targets (program and wipe) +$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE))) + +.PHONY: elf lss sym hex bin bino opfw elf: $(OUTDIR)/$(TARGET).elf lss: $(OUTDIR)/$(TARGET).lss sym: $(OUTDIR)/$(TARGET).sym hex: $(OUTDIR)/$(TARGET).hex bin: $(OUTDIR)/$(TARGET).bin bino: $(OUTDIR)/$(TARGET).bin.o +opfw: $(OUTDIR)/$(TARGET).opfw # Display sizes of sections. $(eval $(call SIZE_TEMPLATE, $(OUTDIR)/$(TARGET).elf)) -.PHONY: size -size: $(OUTDIR)/$(TARGET).elf_size # Generate Doxygen documents docs: doxygen $(DOXYGENDIR)/doxygen.cfg +# Install: install binary file with prefix/suffix into install directory +install: $(OUTDIR)/$(TARGET).opfw +ifneq ($(INSTALL_DIR),) + @echo $(MSG_INSTALLING) $(call toprel, $<) + $(V1) mkdir -p $(INSTALL_DIR) + $(V1) $(INSTALL) $< $(INSTALL_DIR)/$(INSTALL_PFX)$(TARGET)$(INSTALL_SFX).opfw +else + $(error INSTALL_DIR must be specified for $@) +endif + # Target: clean project. clean: clean_list @@ -434,6 +418,5 @@ else -include $(shell mkdir $(OUTDIR) 2>/dev/null) $(shell mkdir $(OUTDIR)/dep 2>/dev/null) $(wildcard $(OUTDIR)/dep/*) endif - # Listing of phony targets. -.PHONY : all build clean clean_list program +.PHONY : all build clean clean_list install diff --git a/flight/AHRS/ahrs.c b/flight/AHRS/ahrs.c index 57f9e11e2..830245572 100644 --- a/flight/AHRS/ahrs.c +++ b/flight/AHRS/ahrs.c @@ -33,6 +33,7 @@ /* OpenPilot Includes */ #include "ahrs.h" +#include #include "pios.h" #include "ahrs_timer.h" #include "ahrs_spi_comm.h" @@ -1228,6 +1229,8 @@ void homelocation_callback(AhrsObjHandle obj) void firmwareiapobj_callback(AhrsObjHandle obj) { + const struct pios_board_info * bdinfo = &pios_board_info_blob; + FirmwareIAPObjData firmwareIAPObj; FirmwareIAPObjGet(&firmwareIAPObj); if(firmwareIAPObj.ArmReset==0) @@ -1235,7 +1238,7 @@ void firmwareiapobj_callback(AhrsObjHandle obj) if(firmwareIAPObj.ArmReset==1) { - if((firmwareIAPObj.BoardType==BOARD_TYPE) || (firmwareIAPObj.BoardType==0xFF)) + if((firmwareIAPObj.BoardType==bdinfo->board_type) || (firmwareIAPObj.BoardType==0xFF)) { ++reset_count; @@ -1247,11 +1250,11 @@ void firmwareiapobj_callback(AhrsObjHandle obj) } } } - else if(firmwareIAPObj.BoardType==BOARD_TYPE && firmwareIAPObj.crc!=PIOS_BL_HELPER_CRC_Memory_Calc()) + else if(firmwareIAPObj.BoardType==bdinfo->board_type && firmwareIAPObj.crc!=PIOS_BL_HELPER_CRC_Memory_Calc()) { - PIOS_BL_HELPER_FLASH_Read_Description(firmwareIAPObj.Description,SIZE_OF_DESCRIPTION); + PIOS_BL_HELPER_FLASH_Read_Description(firmwareIAPObj.Description,bdinfo->desc_size); firmwareIAPObj.crc=PIOS_BL_HELPER_CRC_Memory_Calc(); - firmwareIAPObj.BoardRevision=BOARD_REVISION; + firmwareIAPObj.BoardRevision=bdinfo->board_rev; FirmwareIAPObjSet(&firmwareIAPObj); } } diff --git a/flight/AHRS/pios_board.c b/flight/AHRS/pios_board.c index 395eadd39..aa5b20855 100644 --- a/flight/AHRS/pios_board.c +++ b/flight/AHRS/pios_board.c @@ -54,7 +54,6 @@ static const struct pios_spi_cfg pios_spi_op_cfg = { .ahb_clk = RCC_AHBPeriph_DMA1, .irq = { - .handler = PIOS_SPI_op_irq_handler, .flags = (DMA1_FLAG_TC4 | DMA1_FLAG_TE4 | DMA1_FLAG_HT4 | DMA1_FLAG_GL4), @@ -153,11 +152,10 @@ void PIOS_SPI_op_irq_handler(void) extern void PIOS_ADC_handler(void); void DMA1_Channel1_IRQHandler() __attribute__ ((alias("PIOS_ADC_handler"))); // Remap the ADC DMA handler to this one -const struct pios_adc_cfg pios_adc_cfg = { +static const struct pios_adc_cfg pios_adc_cfg = { .dma = { .ahb_clk = RCC_AHBPeriph_DMA1, .irq = { - .handler = PIOS_ADC_DMA_Handler, .flags = (DMA1_FLAG_TC1 | DMA1_FLAG_TE1 | DMA1_FLAG_HT1 | DMA1_FLAG_GL1), .init = { .NVIC_IRQChannel = DMA1_Channel1_IRQn, @@ -205,17 +203,10 @@ void PIOS_ADC_handler() { /* * AUX USART */ -void PIOS_USART_aux_irq_handler(void); -void USART3_IRQHandler() - __attribute__ ((alias("PIOS_USART_aux_irq_handler"))); -const struct pios_usart_cfg pios_usart_aux_cfg = { +static const struct pios_usart_cfg pios_usart_aux_cfg = { .regs = USART3, .init = { -#if defined (PIOS_USART_BAUDRATE) - .USART_BaudRate = PIOS_USART_BAUDRATE, -#else - .USART_BaudRate = 57600, -#endif + .USART_BaudRate = 230400, .USART_WordLength = USART_WordLength_8b, .USART_Parity = USART_Parity_No, .USART_StopBits = USART_StopBits_1, @@ -224,7 +215,6 @@ const struct pios_usart_cfg pios_usart_aux_cfg = { .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, }, .irq = { - .handler = PIOS_USART_aux_irq_handler, .init = { .NVIC_IRQChannel = USART3_IRQn, .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, @@ -250,18 +240,15 @@ const struct pios_usart_cfg pios_usart_aux_cfg = { }, }; -static uint32_t pios_usart_aux_id; -void PIOS_USART_aux_irq_handler(void) -{ - PIOS_USART_IRQ_Handler(pios_usart_aux_id); -} - #endif /* PIOS_INCLUDE_USART */ #if defined(PIOS_INCLUDE_COM) #include +#define PIOS_COM_AUX_TX_BUF_LEN 192 +static uint8_t pios_com_aux_tx_buffer[PIOS_COM_AUX_TX_BUF_LEN]; + #endif /* PIOS_INCLUDE_COM */ #if defined(PIOS_INCLUDE_I2C) @@ -279,7 +266,7 @@ void I2C1_EV_IRQHandler() void I2C1_ER_IRQHandler() __attribute__ ((alias("PIOS_I2C_main_adapter_er_irq_handler"))); -const struct pios_i2c_adapter_cfg pios_i2c_main_adapter_cfg = { +static const struct pios_i2c_adapter_cfg pios_i2c_main_adapter_cfg = { .regs = I2C1, .init = { .I2C_Mode = I2C_Mode_I2C, @@ -307,7 +294,6 @@ const struct pios_i2c_adapter_cfg pios_i2c_main_adapter_cfg = { }, }, .event = { - .handler = PIOS_I2C_main_adapter_ev_irq_handler, .flags = 0, /* FIXME: check this */ .init = { .NVIC_IRQChannel = I2C1_EV_IRQn, @@ -317,7 +303,6 @@ const struct pios_i2c_adapter_cfg pios_i2c_main_adapter_cfg = { }, }, .error = { - .handler = PIOS_I2C_main_adapter_er_irq_handler, .flags = 0, /* FIXME: check this */ .init = { .NVIC_IRQChannel = I2C1_ER_IRQn, @@ -388,11 +373,16 @@ void PIOS_Board_Init(void) { /* Communication system */ #if !defined(PIOS_ENABLE_DEBUG_PINS) #if defined(PIOS_INCLUDE_COM) - if (PIOS_USART_Init(&pios_usart_aux_id, &pios_usart_aux_cfg)) { - PIOS_DEBUG_Assert(0); - } - if (PIOS_COM_Init(&pios_com_aux_id, &pios_usart_com_driver, pios_usart_aux_id)) { - PIOS_DEBUG_Assert(0); + { + uint32_t pios_usart_aux_id; + if (PIOS_USART_Init(&pios_usart_aux_id, &pios_usart_aux_cfg)) { + PIOS_DEBUG_Assert(0); + } + if (PIOS_COM_Init(&pios_com_aux_id, &pios_usart_com_driver, pios_usart_aux_id, + NULL, 0, + pios_com_aux_tx_buffer, sizeof(pios_com_aux_tx_buffer))) { + PIOS_DEBUG_Assert(0); + } } #endif /* PIOS_INCLUDE_COM */ #endif diff --git a/flight/Bootloaders/AHRS/Makefile b/flight/Bootloaders/AHRS/Makefile index 24512a5b5..18bf8a269 100644 --- a/flight/Bootloaders/AHRS/Makefile +++ b/flight/Bootloaders/AHRS/Makefile @@ -25,6 +25,13 @@ WHEREAMI := $(dir $(lastword $(MAKEFILE_LIST))) TOP := $(realpath $(WHEREAMI)/../../../) include $(TOP)/make/firmware-defs.mk +include $(TOP)/make/boards/$(BOARD_NAME)/board-info.mk + +# Target file name (without extension). +TARGET := bl_$(BOARD_NAME) + +# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) +OUTDIR := $(TOP)/build/$(TARGET) # Set developer code and compile options # Set to YES for debugging @@ -41,23 +48,6 @@ endif FLASH_TOOL = OPENOCD -# MCU name, submodel and board -# - MCU used for compiler-option (-mcpu) -# - MODEL used for linker-script name (-T) and passed as define -# - BOARD just passed as define (optional) -MCU = cortex-m3 -CHIP = STM32F103CBT -BOARD = STM32103CB_AHRS -MODEL = MD - - - -# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) -OUTDIR = $(TOP)/build/bl_ahrs - -# Target file name (without extension). -TARGET = AHRS_BL - # Paths AHRS_BL = ./ AHRS_BLINC = $(AHRS_BL)/inc @@ -100,6 +90,7 @@ SRC += $(PIOSSTM32F10X)/pios_spi.c ## PIOS Hardware (Common) #SRC += $(PIOSCOMMON)/pios_com.c #SRC += $(PIOSCOMMON)/pios_hmc5843.c +SRC += $(PIOSCOMMON)/pios_board_info.c SRC += $(PIOSCOMMON)/pios_opahrs_proto.c SRC += $(PIOSCOMMON)/printf-stdarg.c SRC += $(PIOSCOMMON)/pios_bl_helper.c @@ -148,7 +139,7 @@ CPPSRCARM = # Even though the DOS/Win* filesystem matches both .s and .S the same, # it will preserve the spelling of the filenames, and gcc itself does # care about how the name is spelled on its command-line. -ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL).S +ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL)$(MODEL_SUFFIX).S # List Assembler source files here which must be assembled in ARM-Mode.. ASRCARM = @@ -208,6 +199,15 @@ CDEFS = -DSTM32F10X_$(MODEL) CDEFS += -DUSE_STDPERIPH_DRIVER CDEFS += -DUSE_$(BOARD) +# Provide (only) the bootloader with board-specific defines +BLONLY_CDEFS += -DBOARD_TYPE=$(BOARD_TYPE) +BLONLY_CDEFS += -DBOARD_REVISION=$(BOARD_REVISION) +BLONLY_CDEFS += -DHW_TYPE=$(HW_TYPE) +BLONLY_CDEFS += -DBOOTLOADER_VERSION=$(BOOTLOADER_VERSION) +BLONLY_CDEFS += -DFW_BANK_BASE=$(FW_BANK_BASE) +BLONLY_CDEFS += -DFW_BANK_SIZE=$(FW_BANK_SIZE) +BLONLY_CDEFS += -DFW_DESC_SIZE=$(FW_DESC_SIZE) + # Place project-specific -D and/or -U options for # Assembler with preprocessor here. #ADEFS = -DUSE_IRQ_ASM_WRAPPER @@ -242,8 +242,9 @@ CFLAGS += -O$(OPT) ifeq ($(DEBUG),NO) CFLAGS += -fdata-sections -ffunction-sections endif -CFLAGS += -mcpu=$(MCU) -mthumb +CFLAGS += -mcpu=$(MCU) CFLAGS += $(CDEFS) +CFLAGS += $(BLONLY_CDEFS) CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) -I. CFLAGS += -mapcs-frame @@ -265,7 +266,7 @@ CONLYFLAGS += $(CSTANDARD) # Assembler flags. # -Wa,...: tell GCC to pass this to the assembler. # -ahlns: create listing -ASFLAGS = -mcpu=$(MCU) -mthumb -I. -x assembler-with-cpp +ASFLAGS = -mcpu=$(MCU) -I. -x assembler-with-cpp ASFLAGS += $(ADEFS) ASFLAGS += -Wa,-adhlns=$(addprefix $(OUTDIR)/, $(notdir $(addsuffix .lst, $(basename $<)))) ASFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) @@ -290,20 +291,8 @@ LDFLAGS += -lc -lgcc LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_memory.ld LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_BL_sections.ld -OOCD_LOADFILE+=$(OUTDIR)/$(TARGET).bin -# Program -OOCD_CL+=-c "flash write_image erase $(OOCD_LOADFILE) 0x08000000 bin" -# Verify -OOCD_CL+=-c "verify_image $(OOCD_LOADFILE) 0x08000000 bin" -# reset target -OOCD_CL+=-c "reset run" -# terminate OOCD after programming -OOCD_CL+=-c shutdown - # Define programs and commands. REMOVE = $(REMOVE_CMD) -f -###SHELL = sh -###COPY = cp # List of all source files. ALLSRC = $(ASRCARM) $(ASRC) $(SRCARM) $(SRC) $(CPPSRCARM) $(CPPSRC) @@ -335,14 +324,6 @@ endif endif endif -# Program the device. -ifeq ($(FLASH_TOOL),OPENOCD) -# Program the device with Dominic Rath's OPENOCD in "batch-mode", needs cfg and "reset-script". -program: $(OUTDIR)/$(TARGET).bin - @echo "Programming with OPENOCD" - $(OOCD_EXE) $(OOCD_CL) -endif - # Link: create ELF output file from object files. $(eval $(call LINK_TEMPLATE, $(OUTDIR)/$(TARGET).elf, $(ALLOBJ))) @@ -372,6 +353,9 @@ $(eval $(call PARTIAL_COMPILE_ARM_TEMPLATE, SRCARM)) $(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin +# Add jtag targets (program and wipe) +$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BL_BANK_BASE),$(BL_BANK_SIZE))) + .PHONY: elf lss sym hex bin bino elf: $(OUTDIR)/$(TARGET).elf lss: $(OUTDIR)/$(TARGET).lss @@ -382,13 +366,21 @@ bino: $(OUTDIR)/$(TARGET).bin.o # Display sizes of sections. $(eval $(call SIZE_TEMPLATE, $(OUTDIR)/$(TARGET).elf)) -.PHONY: size -size: $(OUTDIR)/$(TARGET).elf_size # Generate Doxygen documents docs: doxygen $(DOXYGENDIR)/doxygen.cfg +# Install: install binary file with prefix/suffix into install directory +install: $(OUTDIR)/$(TARGET).bin +ifneq ($(INSTALL_DIR),) + @echo $(MSG_INSTALLING) $(call toprel, $<) + $(V1) mkdir -p $(INSTALL_DIR) + $(V1) $(INSTALL) $< $(INSTALL_DIR)/$(INSTALL_PFX)$(TARGET)$(INSTALL_SFX).bin +else + $(error INSTALL_DIR must be specified for $@) +endif + # Target: clean project. clean: clean_list @@ -426,4 +418,4 @@ else endif # Listing of phony targets. -.PHONY : all build clean clean_list program +.PHONY : all build clean clean_list install diff --git a/flight/Bootloaders/AHRS/main.c b/flight/Bootloaders/AHRS/main.c index 30915cef0..b284e6365 100644 --- a/flight/Bootloaders/AHRS/main.c +++ b/flight/Bootloaders/AHRS/main.c @@ -33,6 +33,7 @@ /* OpenPilot Includes */ #include "ahrs_bl.h" +#include #include "pios_opahrs_proto.h" #include "bl_fsm.h" /* lfsm_state */ #include "stm32f10x_flash.h" @@ -108,6 +109,7 @@ static struct opahrs_msg_v0 link_rx_v0; static struct opahrs_msg_v0 user_tx_v0; static struct opahrs_msg_v0 user_rx_v0; void process_spi_request(void) { + const struct pios_board_info * bdinfo = &pios_board_info_blob; bool msg_to_process = FALSE; PIOS_IRQ_Disable(); @@ -166,15 +168,15 @@ void process_spi_request(void) { break; case OPAHRS_MSG_V0_REQ_MEM_MAP: opahrs_msg_v0_init_user_tx(&user_tx_v0, OPAHRS_MSG_V0_RSP_MEM_MAP); - user_tx_v0.payload.user.v.rsp.mem_map.density = HW_TYPE; + user_tx_v0.payload.user.v.rsp.mem_map.density = bdinfo->hw_type; user_tx_v0.payload.user.v.rsp.mem_map.rw_flags = (BOARD_READABLE - | (BOARD_WRITABLA << 1)); + | (BOARD_WRITABLE << 1)); user_tx_v0.payload.user.v.rsp.mem_map.size_of_code_memory - = SIZE_OF_CODE; + = bdinfo->fw_size; user_tx_v0.payload.user.v.rsp.mem_map.size_of_description - = SIZE_OF_DESCRIPTION; + = bdinfo->desc_size; user_tx_v0.payload.user.v.rsp.mem_map.start_of_user_code - = START_OF_USER_CODE; + = bdinfo->fw_base; lfsm_user_set_tx_v0(&user_tx_v0); break; case OPAHRS_MSG_V0_REQ_SERIAL: @@ -192,7 +194,7 @@ void process_spi_request(void) { PIOS_LED_On(LED1); opahrs_msg_v0_init_user_tx(&user_tx_v0, OPAHRS_MSG_V0_RSP_FWUP_STATUS); if (!(user_rx_v0.payload.user.v.req.fwup_data.adress - < START_OF_USER_CODE)) { + < bdinfo->fw_base)) { for (uint8_t x = 0; x < user_rx_v0.payload.user.v.req.fwup_data.size; ++x) { if (FLASH_ProgramWord( @@ -250,13 +252,10 @@ void process_spi_request(void) { return; } void jump_to_app() { - //while(TRUE) - //{ - // PIOS_LED_Toggle(LED1); - // PIOS_DELAY_WaitmS(1000); - //} + const struct pios_board_info * bdinfo = &pios_board_info_blob; + PIOS_LED_On(LED1); - if (((*(__IO uint32_t*) START_OF_USER_CODE) & 0x2FFE0000) == 0x20000000) { /* Jump to user application */ + if (((*(__IO uint32_t*) bdinfo->fw_base) & 0x2FFE0000) == 0x20000000) { /* Jump to user application */ FLASH_Lock(); RCC_APB2PeriphResetCmd(0xffffffff, ENABLE); RCC_APB1PeriphResetCmd(0xffffffff, ENABLE); @@ -265,10 +264,10 @@ void jump_to_app() { //_SetCNTR(0); // clear interrupt mask //_SetISTR(0); // clear all requests - JumpAddress = *(__IO uint32_t*) (START_OF_USER_CODE + 4); + JumpAddress = *(__IO uint32_t*) (bdinfo->fw_base + 4); Jump_To_Application = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */ - __set_MSP(*(__IO uint32_t*) START_OF_USER_CODE); + __set_MSP(*(__IO uint32_t*) bdinfo->fw_base); Jump_To_Application(); } else { boot_status = jump_failed; diff --git a/flight/Bootloaders/AHRS/pios_board.c b/flight/Bootloaders/AHRS/pios_board.c index 2d3c33a8c..756da9288 100644 --- a/flight/Bootloaders/AHRS/pios_board.c +++ b/flight/Bootloaders/AHRS/pios_board.c @@ -55,7 +55,6 @@ static const struct pios_spi_cfg .ahb_clk = RCC_AHBPeriph_DMA1, .irq = { - .handler = PIOS_SPI_op_irq_handler, .flags = (DMA1_FLAG_TC4 | DMA1_FLAG_TE4 | DMA1_FLAG_HT4 | DMA1_FLAG_GL4), .init = { .NVIC_IRQChannel = DMA1_Channel4_IRQn, @@ -133,11 +132,18 @@ void PIOS_SPI_op_irq_handler(void) { #include "bl_fsm.h" /* lfsm_* */ +static bool board_init_complete = false; void PIOS_Board_Init() { + if (board_init_complete) { + return; + } + /* Set up the SPI interface to the OP board */ if (PIOS_SPI_Init(&pios_spi_op_id, &pios_spi_op_cfg)) { PIOS_DEBUG_Assert(0); } lfsm_attach(pios_spi_op_id); lfsm_init(); + + board_init_complete = true; } diff --git a/flight/Bootloaders/BootloaderUpdater/Makefile b/flight/Bootloaders/BootloaderUpdater/Makefile index 5f48d327f..81aa163ec 100644 --- a/flight/Bootloaders/BootloaderUpdater/Makefile +++ b/flight/Bootloaders/BootloaderUpdater/Makefile @@ -25,6 +25,13 @@ WHEREAMI := $(dir $(lastword $(MAKEFILE_LIST))) TOP := $(realpath $(WHEREAMI)/../../../) include $(TOP)/make/firmware-defs.mk +include $(TOP)/make/boards/$(BOARD_NAME)/board-info.mk + +# Target file name (without extension). +TARGET = bu_$(BOARD_NAME) + +# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) +OUTDIR := $(TOP)/build/$(TARGET) # Set developer code and compile options # Set to YES to compile for debugging @@ -51,21 +58,6 @@ endif FLASH_TOOL = OPENOCD -# MCU name, submodel and board -# - MCU used for compiler-option (-mcpu) -# - MODEL used for linker-script name (-T) and passed as define -# - BOARD just passed as define (optional) -MCU = cortex-m3 -CHIP = STM32F103CBT -BOARD ?= NULL -MODEL ?= NULL - -# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) -OUTDIR = ../../../build/bootloaders/BootloaderUpdater - -# Target file name (without extension). -TARGET = BL_Updater - # Paths OPSYSTEM = . OPSYSTEMINC = $(OPSYSTEM)/inc @@ -224,7 +216,6 @@ endif ifeq ($(ENABLE_AUX_UART), YES) CDEFS += -DPIOS_ENABLE_AUX_UART endif -CDEFS += -DUSE_BOOTLOADER # Place project-specific -D and/or -U options for # Assembler with preprocessor here. @@ -309,9 +300,9 @@ LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_sections.ld OOCD_LOADFILE+=$(OUTDIR)/$(TARGET).bin # Program -OOCD_CL+=-c "flash write_image erase $(OOCD_LOADFILE) 0x08003000 bin" +OOCD_CL+=-c "flash write_image erase $(OOCD_LOADFILE) $(START_OF_FW_CODE) bin" # Verify -OOCD_CL+=-c "verify_image $(OOCD_LOADFILE) 0x08003000 bin" +OOCD_CL+=-c "verify_image $(OOCD_LOADFILE) $(START_OF_FW_CODE) bin" # reset target OOCD_CL+=-c "reset run" # terminate OOCD after programming @@ -364,6 +355,7 @@ program: $(OUTDIR)/$(TARGET).bin endif # Link: create ELF output file from object files. +BLOBJ := $(TOP)/build/bl_$(BOARD_NAME)/bl_$(BOARD_NAME).bin.o $(eval $(call LINK_TEMPLATE, $(OUTDIR)/$(TARGET).elf, $(ALLOBJ) $(BLOBJ))) # Assemble: create object files from assembler source files. @@ -392,14 +384,16 @@ $(eval $(call PARTIAL_COMPILE_ARM_TEMPLATE, SRCARM)) $(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin -.PHONY: elf lss sym hex bin bino +$(eval $(call OPFW_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BOARD_TYPE),$(BOARD_REVISION))) + +.PHONY: elf lss sym hex bin bino opfw elf: $(OUTDIR)/$(TARGET).elf -elf.stripped: $(OUTDIR)/$(TARGET).elf.stripped lss: $(OUTDIR)/$(TARGET).lss sym: $(OUTDIR)/$(TARGET).sym hex: $(OUTDIR)/$(TARGET).hex bin: $(OUTDIR)/$(TARGET).bin bino: $(OUTDIR)/$(TARGET).bin.o +opfw: $(OUTDIR)/$(TARGET).opfw # Display sizes of sections. $(eval $(call SIZE_TEMPLATE, $(OUTDIR)/$(TARGET).elf)) @@ -410,6 +404,16 @@ size: $(OUTDIR)/$(TARGET).elf_size docs: doxygen $(DOXYGENDIR)/doxygen.cfg +# Install: install binary file with prefix/suffix into install directory +install: $(OUTDIR)/$(TARGET).opfw +ifneq ($(INSTALL_DIR),) + @echo $(MSG_INSTALLING) $(call toprel, $<) + $(V1) mkdir -p $(INSTALL_DIR) + $(V1) $(INSTALL) $< $(INSTALL_DIR)/$(INSTALL_PFX)$(TARGET)$(INSTALL_SFX).opfw +else + $(error INSTALL_DIR must be specified for $@) +endif + # Target: clean project. clean: begin clean_list finished end @@ -430,7 +434,6 @@ clean_list : $(V1) $(REMOVE) $(CPPSRC:.cpp=.s) $(V1) $(REMOVE) $(CPPSRCARM:.cpp=.s) - # Create output files directory # all known MS Windows OS define the ComSpec environment variable ifdef ComSpec @@ -447,4 +450,4 @@ else endif # Listing of phony targets. -.PHONY : all build clean clean_list program +.PHONY : all build clean clean_list program install diff --git a/flight/Bootloaders/BootloaderUpdater/test.bin b/flight/Bootloaders/BootloaderUpdater/test.bin deleted file mode 100644 index 4b1f21a61..000000000 Binary files a/flight/Bootloaders/BootloaderUpdater/test.bin and /dev/null differ diff --git a/flight/Bootloaders/CopterControl/Makefile b/flight/Bootloaders/CopterControl/Makefile index 7c7d8e812..fe613f909 100644 --- a/flight/Bootloaders/CopterControl/Makefile +++ b/flight/Bootloaders/CopterControl/Makefile @@ -25,6 +25,13 @@ WHEREAMI := $(dir $(lastword $(MAKEFILE_LIST))) TOP := $(realpath $(WHEREAMI)/../../../) include $(TOP)/make/firmware-defs.mk +include $(TOP)/make/boards/$(BOARD_NAME)/board-info.mk + +# Target file name (without extension). +TARGET := bl_$(BOARD_NAME) + +# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) +OUTDIR := $(TOP)/build/$(TARGET) # Set developer code and compile options # Set to YES to compile for debugging @@ -48,21 +55,6 @@ endif FLASH_TOOL = OPENOCD -# MCU name, submodel and board -# - MCU used for compiler-option (-mcpu) -# - MODEL used for linker-script name (-T) and passed as define -# - BOARD just passed as define (optional) -MCU = cortex-m3 -CHIP = STM32F103CBT -BOARD = STM32103CB_CC_Rev1 -MODEL = MD - -# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) -OUTDIR = $(TOP)/build/bl_coptercontrol - -# Target file name (without extension). -TARGET = CopterControl_BL - # Paths OPSYSTEM = . OPSYSTEMINC = $(OPSYSTEM)/inc @@ -102,8 +94,6 @@ DOXYGENDIR = ../Doc/Doxygen SRC += $(OPSYSTEM)/main.c SRC += $(OPSYSTEM)/pios_board.c SRC += $(OPSYSTEM)/op_dfu.c -SRC += $(FLIGHTLIB)/stopwatch.c - ## PIOS Hardware (STM32F10x) SRC += $(PIOSSTM32F10X)/pios_sys.c @@ -123,6 +113,7 @@ SRC += $(PIOSSTM32F10X)/pios_usb_hid_prop.c SRC += $(PIOSSTM32F10X)/pios_usb_hid_pwr.c ## PIOS Hardware (Common) +SRC += $(PIOSCOMMON)/pios_board_info.c SRC += $(PIOSCOMMON)/pios_com.c SRC += $(PIOSCOMMON)/pios_bl_helper.c SRC += $(PIOSCOMMON)/pios_iap.c @@ -146,7 +137,6 @@ SRC += $(STMSPDSRCDIR)/stm32f10x_pwr.c SRC += $(STMSPDSRCDIR)/stm32f10x_rcc.c SRC += $(STMSPDSRCDIR)/stm32f10x_rtc.c SRC += $(STMSPDSRCDIR)/stm32f10x_spi.c -SRC += $(STMSPDSRCDIR)/stm32f10x_tim.c SRC += $(STMSPDSRCDIR)/stm32f10x_usart.c SRC += $(STMSPDSRCDIR)/stm32f10x_dbgmcu.c SRC += $(STMSPDSRCDIR)/misc.c @@ -180,7 +170,7 @@ CPPSRCARM = # Even though the DOS/Win* filesystem matches both .s and .S the same, # it will preserve the spelling of the filenames, and gcc itself does # care about how the name is spelled on its command-line. -ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL).S +ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL)$(MODEL_SUFFIX).S # List Assembler source files here which must be assembled in ARM-Mode.. ASRCARM = @@ -259,6 +249,15 @@ ifeq ($(ENABLE_AUX_UART), YES) CDEFS += -DPIOS_ENABLE_AUX_UART endif +# Provide (only) the bootloader with board-specific defines +BLONLY_CDEFS += -DBOARD_TYPE=$(BOARD_TYPE) +BLONLY_CDEFS += -DBOARD_REVISION=$(BOARD_REVISION) +BLONLY_CDEFS += -DHW_TYPE=$(HW_TYPE) +BLONLY_CDEFS += -DBOOTLOADER_VERSION=$(BOOTLOADER_VERSION) +BLONLY_CDEFS += -DFW_BANK_BASE=$(FW_BANK_BASE) +BLONLY_CDEFS += -DFW_BANK_SIZE=$(FW_BANK_SIZE) +BLONLY_CDEFS += -DFW_DESC_SIZE=$(FW_DESC_SIZE) + # Place project-specific -D and/or -U options for # Assembler with preprocessor here. #ADEFS = -DUSE_IRQ_ASM_WRAPPER @@ -294,8 +293,9 @@ ifeq ($(DEBUG),NO) CFLAGS += -ffunction-sections endif -CFLAGS += -mcpu=$(MCU) -mthumb +CFLAGS += -mcpu=$(MCU) CFLAGS += $(CDEFS) +CFLAGS += $(BLONLY_CDEFS) CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) -I. CFLAGS += -mapcs-frame @@ -315,7 +315,7 @@ CONLYFLAGS += $(CSTANDARD) # Assembler flags. # -Wa,...: tell GCC to pass this to the assembler. # -ahlns: create listing -ASFLAGS = -mcpu=$(MCU) -mthumb -I. -x assembler-with-cpp +ASFLAGS = -mcpu=$(MCU) -I. -x assembler-with-cpp ASFLAGS += $(ADEFS) ASFLAGS += -Wa,-adhlns=$(addprefix $(OUTDIR)/, $(notdir $(addsuffix .lst, $(basename $<)))) ASFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) @@ -340,20 +340,8 @@ LDFLAGS += -lc -lgcc LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_memory.ld LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_BL_sections.ld -OOCD_LOADFILE+=$(OUTDIR)/$(TARGET).bin -# Program -OOCD_CL+=-c "flash write_image erase $(OOCD_LOADFILE) 0x08000000 bin" -# Verify -OOCD_CL+=-c "verify_image $(OOCD_LOADFILE) 0x08000000 bin" -# reset target -OOCD_CL+=-c "reset run" -# terminate OOCD after programming -OOCD_CL+=-c shutdown - # Define programs and commands. REMOVE = $(REMOVE_CMD) -f -###SHELL = sh -###COPY = cp # List of all source files. ALLSRC = $(ASRCARM) $(ASRC) $(SRCARM) $(SRC) $(CPPSRCARM) $(CPPSRC) @@ -393,14 +381,6 @@ ${OUTDIR}/InitMods.c: Makefile @echo ${quote}${foreach MOD, ${MODNAMES}, ${MOD}Initialize();}${quote} >> ${OUTDIR}/InitMods.c @echo ${quote}}${quote} >> ${OUTDIR}/InitMods.c -# Program the device. -ifeq ($(FLASH_TOOL),OPENOCD) -# Program the device with Dominic Rath's OPENOCD in "batch-mode", needs cfg and "reset-script". -program: $(OUTDIR)/$(TARGET).bin - @echo ${quote}Programming with OPENOCD${quote} - $(OOCD_EXE) $(OOCD_CL) -endif - # Link: create ELF output file from object files. $(eval $(call LINK_TEMPLATE, $(OUTDIR)/$(TARGET).elf, $(ALLOBJ))) @@ -428,12 +408,11 @@ $(eval $(call PARTIAL_COMPILE_TEMPLATE, SRC)) # Compile: create assembler files from C source files. ARM only $(eval $(call PARTIAL_COMPILE_ARM_TEMPLATE, SRCARM)) -# Generate Doxygen documents -docs: - doxygen $(DOXYGENDIR)/doxygen.cfg - $(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin +# Add jtag targets (program and wipe) +$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BL_BANK_BASE),$(BL_BANK_SIZE))) + .PHONY: elf lss sym hex bin bino elf: $(OUTDIR)/$(TARGET).elf lss: $(OUTDIR)/$(TARGET).lss @@ -444,8 +423,20 @@ bino: $(OUTDIR)/$(TARGET).bin.o # Display sizes of sections. $(eval $(call SIZE_TEMPLATE, $(OUTDIR)/$(TARGET).elf)) -.PHONY: size -size: $(OUTDIR)/$(TARGET).elf_size + +# Generate Doxygen documents +docs: + doxygen $(DOXYGENDIR)/doxygen.cfg + +# Install: install binary file with prefix/suffix into install directory +install: $(OUTDIR)/$(TARGET).bin +ifneq ($(INSTALL_DIR),) + @echo $(MSG_INSTALLING) $(call toprel, $<) + $(V1) mkdir -p $(INSTALL_DIR) + $(V1) $(INSTALL) $< $(INSTALL_DIR)/$(INSTALL_PFX)$(TARGET)$(INSTALL_SFX).bin +else + $(error INSTALL_DIR must be specified for $@) +endif # Target: clean project. clean: clean_list @@ -484,4 +475,4 @@ else endif # Listing of phony targets. -.PHONY : all build clean clean_list program +.PHONY : all build clean clean_list install diff --git a/flight/Bootloaders/CopterControl/main.c b/flight/Bootloaders/CopterControl/main.c index 23a8f16c1..aa375a49c 100644 --- a/flight/Bootloaders/CopterControl/main.c +++ b/flight/Bootloaders/CopterControl/main.c @@ -27,7 +27,7 @@ */ /* Bootloader Includes */ #include -#include "stopwatch.h" +#include #include "op_dfu.h" #include "usb_lib.h" #include "pios_iap.h" @@ -46,9 +46,9 @@ pFunction Jump_To_Application; uint32_t JumpAddress; /// LEDs PWM -uint32_t period1 = 50; // *100 uS -> 5 mS +uint32_t period1 = 5000; // 5 mS uint32_t sweep_steps1 = 100; // * 5 mS -> 500 mS -uint32_t period2 = 50; // *100 uS -> 5 mS +uint32_t period2 = 5000; // 5 mS uint32_t sweep_steps2 = 100; // * 5 mS -> 500 mS @@ -69,7 +69,6 @@ uint8_t processRX(); void jump_to_app(); #define BLUE LED1 -#define LED_PWM_TIMER TIM1 int main() { PIOS_SYS_Init(); if (BSL_HOLD_STATE == 0) @@ -92,13 +91,17 @@ int main() { DeviceState = DFUidle; else DeviceState = BLidle; - STOPWATCH_Init(100, LED_PWM_TIMER); } else JumpToApp = TRUE; - STOPWATCH_Reset(LED_PWM_TIMER); - + uint32_t stopwatch = 0; + uint32_t prev_ticks = PIOS_DELAY_GetuS(); while (TRUE) { + /* Update the stopwatch */ + uint32_t elapsed_ticks = PIOS_DELAY_GetuSSince(prev_ticks); + prev_ticks += elapsed_ticks; + stopwatch += elapsed_ticks; + if (JumpToApp == TRUE) jump_to_app(); @@ -106,19 +109,19 @@ int main() { case Last_operation_Success: case uploadingStarting: case DFUidle: - period1 = 50; + period1 = 5000; sweep_steps1 = 100; PIOS_LED_Off(BLUE); period2 = 0; break; case uploading: - period1 = 50; + period1 = 5000; sweep_steps1 = 100; - period2 = 25; + period2 = 2500; sweep_steps2 = 50; break; case downloading: - period1 = 25; + period1 = 2500; sweep_steps1 = 50; PIOS_LED_Off(BLUE); period2 = 0; @@ -129,14 +132,14 @@ int main() { period2 = 0; break; default://error - period1 = 50; + period1 = 5000; sweep_steps1 = 100; - period2 = 50; + period2 = 5000; sweep_steps2 = 100; } if (period1 != 0) { - if (LedPWM(period1, sweep_steps1, STOPWATCH_ValueGet(LED_PWM_TIMER))) + if (LedPWM(period1, sweep_steps1, stopwatch)) PIOS_LED_On(BLUE); else PIOS_LED_Off(BLUE); @@ -144,16 +147,16 @@ int main() { PIOS_LED_On(BLUE); if (period2 != 0) { - if (LedPWM(period2, sweep_steps2, STOPWATCH_ValueGet(LED_PWM_TIMER))) + if (LedPWM(period2, sweep_steps2, stopwatch)) PIOS_LED_On(BLUE); else PIOS_LED_Off(BLUE); } else PIOS_LED_Off(BLUE); - if (STOPWATCH_ValueGet(LED_PWM_TIMER) > 100 * 50 * 100) - STOPWATCH_Reset(LED_PWM_TIMER); - if ((STOPWATCH_ValueGet(LED_PWM_TIMER) > 60000) && (DeviceState + if (stopwatch > 50 * 1000 * 1000) + stopwatch = 0; + if ((stopwatch > 6 * 1000 * 1000) && (DeviceState == BLidle)) JumpToApp = TRUE; @@ -163,7 +166,9 @@ int main() { } void jump_to_app() { - if (((*(__IO uint32_t*) START_OF_USER_CODE) & 0x2FFE0000) == 0x20000000) { /* Jump to user application */ + const struct pios_board_info * bdinfo = &pios_board_info_blob; + + if (((*(__IO uint32_t*) bdinfo->fw_base) & 0x2FFE0000) == 0x20000000) { /* Jump to user application */ FLASH_Lock(); RCC_APB2PeriphResetCmd(0xffffffff, ENABLE); RCC_APB1PeriphResetCmd(0xffffffff, ENABLE); @@ -171,10 +176,10 @@ void jump_to_app() { RCC_APB1PeriphResetCmd(0xffffffff, DISABLE); _SetCNTR(0); // clear interrupt mask _SetISTR(0); // clear all requests - JumpAddress = *(__IO uint32_t*) (START_OF_USER_CODE + 4); + JumpAddress = *(__IO uint32_t*) (bdinfo->fw_base + 4); Jump_To_Application = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */ - __set_MSP(*(__IO uint32_t*) START_OF_USER_CODE); + __set_MSP(*(__IO uint32_t*) bdinfo->fw_base); Jump_To_Application(); } else { DeviceState = failed_jump; @@ -182,20 +187,21 @@ void jump_to_app() { } } uint32_t LedPWM(uint32_t pwm_period, uint32_t pwm_sweep_steps, uint32_t count) { - uint32_t pwm_duty = ((count / pwm_period) % pwm_sweep_steps) - / (pwm_sweep_steps / pwm_period); - if ((count % (2 * pwm_period * pwm_sweep_steps)) > pwm_period - * pwm_sweep_steps) - pwm_duty = pwm_period - pwm_duty; // negative direction each 50*100 ticks + uint32_t curr_step = (count / pwm_period) % pwm_sweep_steps; /* 0 - pwm_sweep_steps */ + uint32_t pwm_duty = pwm_period * curr_step / pwm_sweep_steps; /* fraction of pwm_period */ + + uint32_t curr_sweep = (count / (pwm_period * pwm_sweep_steps)); /* ticks once per full sweep */ + if (curr_sweep & 1) { + pwm_duty = pwm_period - pwm_duty; /* reverse direction in odd sweeps */ + } return ((count % pwm_period) > pwm_duty) ? 1 : 0; } uint8_t processRX() { while (PIOS_COM_ReceiveBufferUsed(PIOS_COM_TELEM_USB) >= 63) { - for (int32_t x = 0; x < 63; ++x) { - mReceive_Buffer[x] = PIOS_COM_ReceiveBuffer(PIOS_COM_TELEM_USB); + if (PIOS_COM_ReceiveBuffer(PIOS_COM_TELEM_USB, mReceive_Buffer, 63, 0) == 63) { + processComand(mReceive_Buffer); } - processComand(mReceive_Buffer); } return TRUE; } diff --git a/flight/Bootloaders/CopterControl/op_dfu.c b/flight/Bootloaders/CopterControl/op_dfu.c index 854c7cb71..b45e1e798 100644 --- a/flight/Bootloaders/CopterControl/op_dfu.c +++ b/flight/Bootloaders/CopterControl/op_dfu.c @@ -30,6 +30,7 @@ #include "pios.h" #include "op_dfu.h" #include "pios_bl_helper.h" +#include //programmable devices Device devicesTable[10]; uint8_t numberOfDevices = 0; @@ -382,16 +383,18 @@ void processComand(uint8_t *xReceive_Buffer) { return; } void OPDfuIni(uint8_t discover) { + const struct pios_board_info * bdinfo = &pios_board_info_blob; Device dev; + dev.programmingType = Self_flash; - dev.readWriteFlags = (BOARD_READABLE | (BOARD_WRITABLA << 1)); - dev.startOfUserCode = START_OF_USER_CODE; - dev.sizeOfCode = SIZE_OF_CODE; - dev.sizeOfDescription = SIZE_OF_DESCRIPTION; - dev.BL_Version = BOOTLOADER_VERSION; + dev.readWriteFlags = (BOARD_READABLE | (BOARD_WRITABLE << 1)); + dev.startOfUserCode = bdinfo->fw_base; + dev.sizeOfCode = bdinfo->fw_size; + dev.sizeOfDescription = bdinfo->desc_size; + dev.BL_Version = bdinfo->bl_rev; dev.FW_Crc = CalcFirmCRC(); - dev.devID = (BOARD_TYPE << 8) | BOARD_REVISION; - dev.devType = HW_TYPE; + dev.devID = (bdinfo->board_type << 8) | (bdinfo->board_rev); + dev.devType = bdinfo->hw_type; numberOfDevices = 1; devicesTable[0] = dev; if (discover) { diff --git a/flight/Bootloaders/CopterControl/pios_board.c b/flight/Bootloaders/CopterControl/pios_board.c index 2277080d8..28a280f4b 100644 --- a/flight/Bootloaders/CopterControl/pios_board.c +++ b/flight/Bootloaders/CopterControl/pios_board.c @@ -31,10 +31,31 @@ #include +#define PIOS_COM_TELEM_USB_RX_BUF_LEN 192 +#define PIOS_COM_TELEM_USB_TX_BUF_LEN 192 + +static uint8_t pios_com_telem_usb_rx_buffer[PIOS_COM_TELEM_USB_RX_BUF_LEN]; +static uint8_t pios_com_telem_usb_tx_buffer[PIOS_COM_TELEM_USB_TX_BUF_LEN]; + #endif /* PIOS_INCLUDE_COM */ // *********************************************************************************** +#if defined(PIOS_INCLUDE_USB_HID) +#include "pios_usb_hid_priv.h" + +static const struct pios_usb_hid_cfg pios_usb_hid_main_cfg = { + .irq = { + .init = { + .NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; +#endif /* PIOS_INCLUDE_USB_HID */ + extern const struct pios_com_driver pios_usb_com_driver; uint32_t pios_com_telem_usb_id; @@ -44,7 +65,12 @@ uint32_t pios_com_telem_usb_id; * initializes all the core subsystems on this specific hardware * called from System/openpilot.c */ +static bool board_init_complete = false; void PIOS_Board_Init(void) { + if (board_init_complete) { + return; + } + /* Enable Prefetch Buffer */ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); @@ -58,13 +84,20 @@ void PIOS_Board_Init(void) { PIOS_GPIO_Init(); #if defined(PIOS_INCLUDE_USB_HID) - PIOS_USB_HID_Init(0); + uint32_t pios_usb_hid_id; + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_main_cfg)) { + PIOS_Assert(0); + } #if defined(PIOS_INCLUDE_COM) - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_com_driver, 0)) { - PIOS_DEBUG_Assert(0); + if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_com_driver, pios_usb_hid_id, + pios_com_telem_usb_rx_buffer, sizeof(pios_com_telem_usb_rx_buffer), + pios_com_telem_usb_tx_buffer, sizeof(pios_com_telem_usb_tx_buffer))) { + PIOS_Assert(0); } #endif /* PIOS_INCLUDE_COM */ -#endif /* PIOS_INCLUDE_USB_HID */ +#endif /* PIOS_INCLUDE_USB_HID */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);//TODO Tirar + + board_init_complete = true; } diff --git a/flight/Bootloaders/OpenPilot/Makefile b/flight/Bootloaders/OpenPilot/Makefile index fe9454f5f..e4285f7e0 100644 --- a/flight/Bootloaders/OpenPilot/Makefile +++ b/flight/Bootloaders/OpenPilot/Makefile @@ -25,6 +25,13 @@ WHEREAMI := $(dir $(lastword $(MAKEFILE_LIST))) TOP := $(realpath $(WHEREAMI)/../../../) include $(TOP)/make/firmware-defs.mk +include $(TOP)/make/boards/$(BOARD_NAME)/board-info.mk + +# Target file name (without extension). +TARGET := bl_$(BOARD_NAME) + +# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) +OUTDIR := $(TOP)/build/$(TARGET) # Set developer code and compile options # Set to YES to compile for debugging @@ -48,21 +55,6 @@ endif FLASH_TOOL = OPENOCD -# MCU name, submodel and board -# - MCU used for compiler-option (-mcpu) -# - MODEL used for linker-script name (-T) and passed as define -# - BOARD just passed as define (optional) -MCU = cortex-m3 -CHIP = STM32F103RET -BOARD = STM3210E_OP -MODEL = HD - -# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) -OUTDIR = $(TOP)/build/bl_openpilot - -# Target file name (without extension). -TARGET = OpenPilot_BL - # Paths OPSYSTEM = . OPSYSTEMINC = $(OPSYSTEM)/inc @@ -124,6 +116,7 @@ SRC += $(PIOSSTM32F10X)/pios_usb_hid_prop.c SRC += $(PIOSSTM32F10X)/pios_usb_hid_pwr.c ## PIOS Hardware (Common) +SRC += $(PIOSCOMMON)/pios_board_info.c SRC += $(PIOSCOMMON)/pios_com.c SRC += $(PIOSCOMMON)/pios_opahrs_v0.c SRC += $(PIOSCOMMON)/pios_bl_helper.c @@ -183,7 +176,7 @@ CPPSRCARM = # Even though the DOS/Win* filesystem matches both .s and .S the same, # it will preserve the spelling of the filenames, and gcc itself does # care about how the name is spelled on its command-line. -ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL)_OP.S +ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL)$(MODEL_SUFFIX).S # List Assembler source files here which must be assembled in ARM-Mode.. ASRCARM = @@ -262,6 +255,15 @@ ifeq ($(ENABLE_AUX_UART), YES) CDEFS += -DPIOS_ENABLE_AUX_UART endif +# Provide (only) the bootloader with board-specific defines +BLONLY_CDEFS += -DBOARD_TYPE=$(BOARD_TYPE) +BLONLY_CDEFS += -DBOARD_REVISION=$(BOARD_REVISION) +BLONLY_CDEFS += -DHW_TYPE=$(HW_TYPE) +BLONLY_CDEFS += -DBOOTLOADER_VERSION=$(BOOTLOADER_VERSION) +BLONLY_CDEFS += -DFW_BANK_BASE=$(FW_BANK_BASE) +BLONLY_CDEFS += -DFW_BANK_SIZE=$(FW_BANK_SIZE) +BLONLY_CDEFS += -DFW_DESC_SIZE=$(FW_DESC_SIZE) + # Place project-specific -D and/or -U options for # Assembler with preprocessor here. #ADEFS = -DUSE_IRQ_ASM_WRAPPER @@ -299,6 +301,7 @@ endif CFLAGS += -mcpu=$(MCU) CFLAGS += $(CDEFS) +CFLAGS += $(BLONLY_CDEFS) CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) -I. CFLAGS += -mapcs-frame @@ -343,20 +346,8 @@ LDFLAGS += -lc -lgcc LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_memory.ld LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_BL_sections.ld -OOCD_LOADFILE+=$(OUTDIR)/$(TARGET).bin -# Program -OOCD_CL+=-c "flash write_image erase $(OOCD_LOADFILE) 0x08000000 bin" -# Verify -OOCD_CL+=-c "verify_image $(OOCD_LOADFILE) 0x08000000 bin" -# reset target -OOCD_CL+=-c "reset run" -# terminate OOCD after programming -OOCD_CL+=-c shutdown - # Define programs and commands. REMOVE = $(REMOVE_CMD) -f -###SHELL = sh -###COPY = cp # List of all source files. ALLSRC = $(ASRCARM) $(ASRC) $(SRCARM) $(SRC) $(CPPSRCARM) $(CPPSRC) @@ -396,14 +387,6 @@ ${OUTDIR}/InitMods.c: Makefile @echo ${quote}${foreach MOD, ${MODNAMES}, ${MOD}Initialize();}${quote} >> ${OUTDIR}/InitMods.c @echo ${quote}}${quote} >> ${OUTDIR}/InitMods.c -# Program the device. -ifeq ($(FLASH_TOOL),OPENOCD) -# Program the device with Dominic Rath's OPENOCD in "batch-mode", needs cfg and "reset-script". -program: $(OUTDIR)/$(TARGET).bin - @echo ${quote}Programming with OPENOCD${quote} - $(OOCD_EXE) $(OOCD_CL) -endif - # Link: create ELF output file from object files. $(eval $(call LINK_TEMPLATE, $(OUTDIR)/$(TARGET).elf, $(ALLOBJ))) @@ -433,6 +416,9 @@ $(eval $(call PARTIAL_COMPILE_ARM_TEMPLATE, SRCARM)) $(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin +# Add jtag targets (program and wipe) +$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BL_BANK_BASE),$(BL_BANK_SIZE))) + .PHONY: elf lss sym hex bin bino elf: $(OUTDIR)/$(TARGET).elf lss: $(OUTDIR)/$(TARGET).lss @@ -443,13 +429,21 @@ bino: $(OUTDIR)/$(TARGET).bin.o # Display sizes of sections. $(eval $(call SIZE_TEMPLATE, $(OUTDIR)/$(TARGET).elf)) -.PHONY: size -size: $(OUTDIR)/$(TARGET).elf_size # Generate Doxygen documents docs: doxygen $(DOXYGENDIR)/doxygen.cfg +# Install: install binary file with prefix/suffix into install directory +install: $(OUTDIR)/$(TARGET).bin +ifneq ($(INSTALL_DIR),) + @echo $(MSG_INSTALLING) $(call toprel, $<) + $(V1) mkdir -p $(INSTALL_DIR) + $(V1) $(INSTALL) $< $(INSTALL_DIR)/$(INSTALL_PFX)$(TARGET)$(INSTALL_SFX).bin +else + $(error INSTALL_DIR must be specified for $@) +endif + # Target: clean project. clean: clean_list @@ -487,4 +481,4 @@ else endif # Listing of phony targets. -.PHONY : all build clean clean_list program +.PHONY : all build clean clean_list install diff --git a/flight/Bootloaders/OpenPilot/main.c b/flight/Bootloaders/OpenPilot/main.c index 4766caf41..8e15952ea 100644 --- a/flight/Bootloaders/OpenPilot/main.c +++ b/flight/Bootloaders/OpenPilot/main.c @@ -27,6 +27,7 @@ */ /* Bootloader Includes */ #include +#include #include "pios_opahrs.h" #include "stopwatch.h" #include "op_dfu.h" @@ -216,7 +217,9 @@ int main() { } void jump_to_app() { - if (((*(__IO uint32_t*) START_OF_USER_CODE) & 0x2FFE0000) == 0x20000000) { /* Jump to user application */ + const struct pios_board_info * bdinfo = &pios_board_info_blob; + + if (((*(__IO uint32_t*) bdinfo->fw_base) & 0x2FFE0000) == 0x20000000) { /* Jump to user application */ FLASH_Lock(); RCC_APB2PeriphResetCmd(0xffffffff, ENABLE); RCC_APB1PeriphResetCmd(0xffffffff, ENABLE); @@ -225,10 +228,10 @@ void jump_to_app() { _SetCNTR(0); // clear interrupt mask _SetISTR(0); // clear all requests - JumpAddress = *(__IO uint32_t*) (START_OF_USER_CODE + 4); + JumpAddress = *(__IO uint32_t*) (bdinfo->fw_base + 4); Jump_To_Application = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */ - __set_MSP(*(__IO uint32_t*) START_OF_USER_CODE); + __set_MSP(*(__IO uint32_t*) bdinfo->fw_base); Jump_To_Application(); } else { DeviceState = failed_jump; @@ -247,10 +250,9 @@ uint32_t LedPWM(uint32_t pwm_period, uint32_t pwm_sweep_steps, uint32_t count) { uint8_t processRX() { if (ProgPort == Usb) { while (PIOS_COM_ReceiveBufferUsed(PIOS_COM_TELEM_USB) >= 63) { - for (int32_t x = 0; x < 63; ++x) { - mReceive_Buffer[x] = PIOS_COM_ReceiveBuffer(PIOS_COM_TELEM_USB); + if (PIOS_COM_ReceiveBuffer(PIOS_COM_TELEM_USB, mReceive_Buffer, 63, 0) == 63) { + processComand(mReceive_Buffer); } - processComand(mReceive_Buffer); } } else if (ProgPort == Serial) { @@ -276,7 +278,12 @@ void SSP_CallBack(uint8_t *buf, uint16_t len) { } int16_t SSP_SerialRead(void) { if (PIOS_COM_ReceiveBufferUsed(PIOS_COM_TELEM_RF) > 0) { - return PIOS_COM_ReceiveBuffer(PIOS_COM_TELEM_RF); + uint8_t byte; + if (PIOS_COM_ReceiveBuffer(PIOS_COM_TELEM_RF, &byte, 1, 0) == 1) { + return byte; + } else { + return -1; + } } else return -1; } diff --git a/flight/Bootloaders/OpenPilot/op_dfu.c b/flight/Bootloaders/OpenPilot/op_dfu.c index 77b4c2c59..bc62fff6c 100644 --- a/flight/Bootloaders/OpenPilot/op_dfu.c +++ b/flight/Bootloaders/OpenPilot/op_dfu.c @@ -30,6 +30,7 @@ #include "pios.h" #include "op_dfu.h" #include "pios_bl_helper.h" +#include #include "pios_opahrs.h" #include "ssp.h" /* Private typedef -----------------------------------------------------------*/ @@ -447,16 +448,18 @@ void processComand(uint8_t *xReceive_Buffer) { return; } void OPDfuIni(uint8_t discover) { + const struct pios_board_info * bdinfo = &pios_board_info_blob; Device dev; + dev.programmingType = Self_flash; - dev.readWriteFlags = (BOARD_READABLE | (BOARD_WRITABLA << 1)); - dev.startOfUserCode = START_OF_USER_CODE; - dev.sizeOfCode = SIZE_OF_CODE; - dev.sizeOfDescription = SIZE_OF_DESCRIPTION; - dev.BL_Version = BOOTLOADER_VERSION; + dev.readWriteFlags = (BOARD_READABLE | (BOARD_WRITABLE << 1)); + dev.startOfUserCode = bdinfo->fw_base; + dev.sizeOfCode = bdinfo->fw_size; + dev.sizeOfDescription = bdinfo->desc_size; + dev.BL_Version = bdinfo->bl_rev; dev.FW_Crc = CalcFirmCRC(); - dev.devID = (BOARD_TYPE << 8) | BOARD_REVISION; - dev.devType = HW_TYPE; + dev.devID = (bdinfo->board_type << 8) | (bdinfo->board_rev); + dev.devType = bdinfo->hw_type; numberOfDevices = 1; devicesTable[0] = dev; if (discover) { diff --git a/flight/Bootloaders/OpenPilot/pios_board.c b/flight/Bootloaders/OpenPilot/pios_board.c index 0f8e4ae81..5defbb626 100644 --- a/flight/Bootloaders/OpenPilot/pios_board.c +++ b/flight/Bootloaders/OpenPilot/pios_board.c @@ -60,7 +60,6 @@ const struct pios_spi_cfg .ahb_clk = RCC_AHBPeriph_DMA1, .irq = { - .handler = PIOS_SPI_ahrs_irq_handler, .flags = (DMA1_FLAG_TC4 | DMA1_FLAG_TE4 | DMA1_FLAG_HT4 | DMA1_FLAG_GL4), .init = { .NVIC_IRQChannel = DMA1_Channel4_IRQn, @@ -143,9 +142,9 @@ void PIOS_SPI_ahrs_irq_handler(void) { /* * Telemetry USART */ -void PIOS_USART_telem_irq_handler(void); -void USART2_IRQHandler() __attribute__ ((alias ("PIOS_USART_telem_irq_handler"))); -const struct pios_usart_cfg pios_usart_telem_cfg = { .regs = USART2, .init = { +const struct pios_usart_cfg pios_usart_telem_cfg = { + .regs = USART2, + .init = { #if defined (PIOS_COM_TELEM_BAUDRATE) .USART_BaudRate = PIOS_COM_TELEM_BAUDRATE, #else @@ -157,7 +156,6 @@ const struct pios_usart_cfg pios_usart_telem_cfg = { .regs = USART2, .init = { .USART_HardwareFlowControl = USART_HardwareFlowControl_None, .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, }, .irq = { - .handler = PIOS_USART_telem_irq_handler, .init = { .NVIC_IRQChannel = USART2_IRQn, .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, @@ -180,19 +178,41 @@ const struct pios_usart_cfg pios_usart_telem_cfg = { .regs = USART2, .init = { }, }, }; -static uint32_t pios_usart_telem_rf_id; -void PIOS_USART_telem_irq_handler(void) { - PIOS_USART_IRQ_Handler(pios_usart_telem_rf_id); -} - #endif /* PIOS_INCLUDE_USART */ #if defined(PIOS_INCLUDE_COM) #include "pios_com_priv.h" +#define PIOS_COM_TELEM_USB_RX_BUF_LEN 192 +#define PIOS_COM_TELEM_USB_TX_BUF_LEN 192 + +static uint8_t pios_com_telem_usb_rx_buffer[PIOS_COM_TELEM_USB_RX_BUF_LEN]; +static uint8_t pios_com_telem_usb_tx_buffer[PIOS_COM_TELEM_USB_TX_BUF_LEN]; + +#define PIOS_COM_TELEM_RF_RX_BUF_LEN 192 +#define PIOS_COM_TELEM_RF_TX_BUF_LEN 192 + +static uint8_t pios_com_telem_rf_rx_buffer[PIOS_COM_TELEM_RF_RX_BUF_LEN]; +static uint8_t pios_com_telem_rf_tx_buffer[PIOS_COM_TELEM_RF_TX_BUF_LEN]; + #endif /* PIOS_INCLUDE_COM */ +#if defined(PIOS_INCLUDE_USB_HID) +#include "pios_usb_hid_priv.h" + +static const struct pios_usb_hid_cfg pios_usb_hid_main_cfg = { + .irq = { + .init = { + .NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; +#endif /* PIOS_INCLUDE_USB_HID */ + extern const struct pios_com_driver pios_usb_com_driver; uint32_t pios_com_telem_rf_id; @@ -205,7 +225,11 @@ uint32_t pios_com_telem_usb_id; * initializes all the core subsystems on this specific hardware * called from System/openpilot.c */ +static bool board_init_complete = false; void PIOS_Board_Init(void) { + if (board_init_complete) { + return; + } /* Enable Prefetch Buffer */ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); @@ -218,11 +242,14 @@ void PIOS_Board_Init(void) { /* Initialize the PiOS library */ #if defined(PIOS_INCLUDE_COM) + uint32_t pios_usart_telem_rf_id; if (PIOS_USART_Init(&pios_usart_telem_rf_id, &pios_usart_telem_cfg)) { PIOS_DEBUG_Assert(0); } if (PIOS_COM_Init(&pios_com_telem_rf_id, &pios_usart_com_driver, - pios_usart_telem_rf_id)) { + pios_usart_telem_rf_id, + pios_com_telem_rf_rx_buffer, sizeof(pios_com_telem_rf_rx_buffer), + pios_com_telem_rf_tx_buffer, sizeof(pios_com_telem_rf_tx_buffer))) { PIOS_DEBUG_Assert(0); } #endif /* PIOS_INCLUDE_COM */ @@ -230,13 +257,16 @@ void PIOS_Board_Init(void) { PIOS_GPIO_Init(); #if defined(PIOS_INCLUDE_USB_HID) - PIOS_USB_HID_Init(0); + uint32_t pios_usb_hid_id; + PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_main_cfg); #if defined(PIOS_INCLUDE_COM) - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_com_driver, 0)) { - PIOS_DEBUG_Assert(0); + if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_com_driver, pios_usb_hid_id, + pios_com_telem_usb_rx_buffer, sizeof(pios_com_telem_usb_rx_buffer), + pios_com_telem_usb_tx_buffer, sizeof(pios_com_telem_usb_tx_buffer))) { + PIOS_Assert(0); } #endif /* PIOS_INCLUDE_COM */ -#endif /* PIOS_INCLUDE_USB_HID */ +#endif /* PIOS_INCLUDE_USB_HID */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);//TODO Tirar @@ -247,6 +277,8 @@ void PIOS_Board_Init(void) { /* Bind the AHRS comms layer to the AHRS SPI link */ PIOS_OPAHRS_Attach(pios_spi_ahrs_id); + + board_init_complete = true; } /** diff --git a/flight/Bootloaders/PipXtreme/Makefile b/flight/Bootloaders/PipXtreme/Makefile index 32b889e3d..64f13d0d2 100644 --- a/flight/Bootloaders/PipXtreme/Makefile +++ b/flight/Bootloaders/PipXtreme/Makefile @@ -25,6 +25,13 @@ WHEREAMI := $(dir $(lastword $(MAKEFILE_LIST))) TOP := $(realpath $(WHEREAMI)/../../../) include $(TOP)/make/firmware-defs.mk +include $(TOP)/make/boards/$(BOARD_NAME)/board-info.mk + +# Target file name (without extension). +TARGET := bl_$(BOARD_NAME) + +# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) +OUTDIR := $(TOP)/build/$(TARGET) # Set developer code and compile options # Set to YES to compile for debugging @@ -48,21 +55,6 @@ endif FLASH_TOOL = OPENOCD -# MCU name, submodel and board -# - MCU used for compiler-option (-mcpu) -# - MODEL used for linker-script name (-T) and passed as define -# - BOARD just passed as define (optional) -MCU = cortex-m3 -CHIP = STM32F103CBT -BOARD = STM32103CB_PIPXTREME -MODEL = MD - -# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) -OUTDIR = $(TOP)/build/bl_pipxtreme - -# Target file name (without extension). -TARGET = PipXtreme_BL - # Paths OPSYSTEM = . OPSYSTEMINC = $(OPSYSTEM)/inc @@ -102,8 +94,6 @@ DOXYGENDIR = ../Doc/Doxygen SRC += $(OPSYSTEM)/main.c SRC += $(OPSYSTEM)/pios_board.c SRC += $(OPSYSTEM)/op_dfu.c -SRC += $(FLIGHTLIB)/stopwatch.c - ## PIOS Hardware (STM32F10x) SRC += $(PIOSSTM32F10X)/pios_sys.c @@ -122,6 +112,7 @@ SRC += $(PIOSSTM32F10X)/pios_usb_hid_prop.c SRC += $(PIOSSTM32F10X)/pios_usb_hid_pwr.c ## PIOS Hardware (Common) +SRC += $(PIOSCOMMON)/pios_board_info.c SRC += $(PIOSCOMMON)/pios_com.c SRC += $(PIOSCOMMON)/pios_bl_helper.c SRC += $(PIOSCOMMON)/pios_iap.c @@ -145,7 +136,6 @@ SRC += $(STMSPDSRCDIR)/stm32f10x_pwr.c SRC += $(STMSPDSRCDIR)/stm32f10x_rcc.c SRC += $(STMSPDSRCDIR)/stm32f10x_rtc.c SRC += $(STMSPDSRCDIR)/stm32f10x_spi.c -SRC += $(STMSPDSRCDIR)/stm32f10x_tim.c SRC += $(STMSPDSRCDIR)/stm32f10x_usart.c SRC += $(STMSPDSRCDIR)/stm32f10x_dbgmcu.c SRC += $(STMSPDSRCDIR)/misc.c @@ -179,7 +169,7 @@ CPPSRCARM = # Even though the DOS/Win* filesystem matches both .s and .S the same, # it will preserve the spelling of the filenames, and gcc itself does # care about how the name is spelled on its command-line. -ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL).S +ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL)$(MODEL_SUFFIX).S # List Assembler source files here which must be assembled in ARM-Mode.. ASRCARM = @@ -258,6 +248,17 @@ ifeq ($(ENABLE_AUX_UART), YES) CDEFS += -DPIOS_ENABLE_AUX_UART endif +# Provide (only) the bootloader with board-specific defines +BLONLY_CDEFS += -DBOARD_TYPE=$(BOARD_TYPE) +BLONLY_CDEFS += -DBOARD_REVISION=$(BOARD_REVISION) +BLONLY_CDEFS += -DHW_TYPE=$(HW_TYPE) +BLONLY_CDEFS += -DBOOTLOADER_VERSION=$(BOOTLOADER_VERSION) +BLONLY_CDEFS += -DFW_BANK_BASE=$(FW_BANK_BASE) +BLONLY_CDEFS += -DFW_BANK_SIZE=$(FW_BANK_SIZE) +BLONLY_CDEFS += -DFW_DESC_SIZE=$(FW_DESC_SIZE) +BLONLY_CDEFS += -DEE_BANK_BASE=$(EE_BANK_BASE) +BLONLY_CDEFS += -DEE_BANK_SIZE=$(EE_BANK_SIZE) + # Place project-specific -D and/or -U options for # Assembler with preprocessor here. #ADEFS = -DUSE_IRQ_ASM_WRAPPER @@ -293,8 +294,9 @@ ifeq ($(DEBUG),NO) CFLAGS += -ffunction-sections endif -CFLAGS += -mcpu=$(MCU) -mthumb +CFLAGS += -mcpu=$(MCU) CFLAGS += $(CDEFS) +CFLAGS += $(BLONLY_CDEFS) CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) -I. CFLAGS += -mapcs-frame @@ -314,7 +316,7 @@ CONLYFLAGS += $(CSTANDARD) # Assembler flags. # -Wa,...: tell GCC to pass this to the assembler. # -ahlns: create listing -ASFLAGS = -mcpu=$(MCU) -mthumb -I. -x assembler-with-cpp +ASFLAGS = -mcpu=$(MCU) -I. -x assembler-with-cpp ASFLAGS += $(ADEFS) ASFLAGS += -Wa,-adhlns=$(addprefix $(OUTDIR)/, $(notdir $(addsuffix .lst, $(basename $<)))) ASFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) @@ -339,20 +341,8 @@ LDFLAGS += -lc -lgcc LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_memory.ld LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_BL_sections.ld -OOCD_LOADFILE+=$(OUTDIR)/$(TARGET).bin -# Program -OOCD_CL+=-c "flash write_image erase $(OOCD_LOADFILE) 0x08000000 bin" -# Verify -OOCD_CL+=-c "verify_image $(OOCD_LOADFILE) 0x08000000 bin" -# reset target -OOCD_CL+=-c "reset run" -# terminate OOCD after programming -OOCD_CL+=-c shutdown - # Define programs and commands. REMOVE = $(REMOVE_CMD) -f -###SHELL = sh -###COPY = cp # List of all source files. ALLSRC = $(ASRCARM) $(ASRC) $(SRCARM) $(SRC) $(CPPSRCARM) $(CPPSRC) @@ -392,14 +382,6 @@ ${OUTDIR}/InitMods.c: Makefile @echo ${quote}${foreach MOD, ${MODNAMES}, ${MOD}Initialize();}${quote} >> ${OUTDIR}/InitMods.c @echo ${quote}}${quote} >> ${OUTDIR}/InitMods.c -# Program the device. -ifeq ($(FLASH_TOOL),OPENOCD) -# Program the device with Dominic Rath's OPENOCD in "batch-mode", needs cfg and "reset-script". -program: $(OUTDIR)/$(TARGET).bin - @echo ${quote}Programming with OPENOCD${quote} - $(OOCD_EXE) $(OOCD_CL) -endif - # Link: create ELF output file from object files. $(eval $(call LINK_TEMPLATE, $(OUTDIR)/$(TARGET).elf, $(ALLOBJ))) @@ -429,6 +411,9 @@ $(eval $(call PARTIAL_COMPILE_ARM_TEMPLATE, SRCARM)) $(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin +# Add jtag targets (program and wipe) +$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BL_BANK_BASE),$(BL_BANK_SIZE))) + .PHONY: elf lss sym hex bin bino elf: $(OUTDIR)/$(TARGET).elf lss: $(OUTDIR)/$(TARGET).lss @@ -439,13 +424,21 @@ bino: $(OUTDIR)/$(TARGET).bin.o # Display sizes of sections. $(eval $(call SIZE_TEMPLATE, $(OUTDIR)/$(TARGET).elf)) -.PHONY: size -size: $(OUTDIR)/$(TARGET).elf_size # Generate Doxygen documents docs: doxygen $(DOXYGENDIR)/doxygen.cfg +# Install: install binary file with prefix/suffix into install directory +install: $(OUTDIR)/$(TARGET).bin +ifneq ($(INSTALL_DIR),) + @echo $(MSG_INSTALLING) $(call toprel, $<) + $(V1) mkdir -p $(INSTALL_DIR) + $(V1) $(INSTALL) $< $(INSTALL_DIR)/$(INSTALL_PFX)$(TARGET)$(INSTALL_SFX).bin +else + $(error INSTALL_DIR must be specified for $@) +endif + # Target: clean project. clean: clean_list @@ -483,5 +476,4 @@ else endif # Listing of phony targets. -.PHONY : all build clean clean_list program - +.PHONY : all build clean clean_list install diff --git a/flight/Bootloaders/PipXtreme/main.c b/flight/Bootloaders/PipXtreme/main.c index a8eb5bcc6..3f1c4bd54 100644 --- a/flight/Bootloaders/PipXtreme/main.c +++ b/flight/Bootloaders/PipXtreme/main.c @@ -27,7 +27,7 @@ */ /* Bootloader Includes */ #include -#include "stopwatch.h" +#include #include "op_dfu.h" #include "usb_lib.h" #include "pios_iap.h" @@ -46,9 +46,9 @@ pFunction Jump_To_Application; uint32_t JumpAddress; /// LEDs PWM -uint32_t period1 = 50; // *100 uS -> 5 mS +uint32_t period1 = 5000; // 5 mS uint32_t sweep_steps1 = 100; // * 5 mS -> 500 mS -uint32_t period2 = 50; // *100 uS -> 5 mS +uint32_t period2 = 5000; // 5 mS uint32_t sweep_steps2 = 100; // * 5 mS -> 500 mS @@ -70,7 +70,6 @@ void jump_to_app(); #define BLUE LED1 #define RED LED4 -#define LED_PWM_TIMER TIM3 int main() { /* NOTE: Do NOT modify the following start-up sequence */ /* Any new initialization functions should be added in OpenPilotInit() */ @@ -97,35 +96,37 @@ int main() { DeviceState = DFUidle; else DeviceState = BLidle; - STOPWATCH_Init(100, LED_PWM_TIMER); } else JumpToApp = TRUE; - STOPWATCH_Reset(LED_PWM_TIMER); - + uint32_t stopwatch = 0; + uint32_t prev_ticks = PIOS_DELAY_GetuS(); while (TRUE) { + /* Update the stopwatch */ + uint32_t elapsed_ticks = PIOS_DELAY_GetuSSince(prev_ticks); + prev_ticks += elapsed_ticks; + stopwatch += elapsed_ticks; + if (JumpToApp == TRUE) jump_to_app(); - //pwm_period = 50; // *100 uS -> 5 mS - //pwm_sweep_steps =100; // * 5 mS -> 500 mS switch (DeviceState) { case Last_operation_Success: case uploadingStarting: case DFUidle: - period1 = 50; + period1 = 5000; sweep_steps1 = 100; PIOS_LED_Off(RED); period2 = 0; break; case uploading: - period1 = 50; + period1 = 5000; sweep_steps1 = 100; - period2 = 25; + period2 = 2500; sweep_steps2 = 50; break; case downloading: - period1 = 25; + period1 = 2500; sweep_steps1 = 50; PIOS_LED_Off(RED); period2 = 0; @@ -136,14 +137,14 @@ int main() { period2 = 0; break; default://error - period1 = 50; + period1 = 5000; sweep_steps1 = 100; - period2 = 50; + period2 = 5000; sweep_steps2 = 100; } if (period1 != 0) { - if (LedPWM(period1, sweep_steps1, STOPWATCH_ValueGet(LED_PWM_TIMER))) + if (LedPWM(period1, sweep_steps1, stopwatch)) PIOS_LED_On(BLUE); else PIOS_LED_Off(BLUE); @@ -151,16 +152,16 @@ int main() { PIOS_LED_On(BLUE); if (period2 != 0) { - if (LedPWM(period2, sweep_steps2, STOPWATCH_ValueGet(LED_PWM_TIMER))) + if (LedPWM(period2, sweep_steps2, stopwatch)) PIOS_LED_On(RED); else PIOS_LED_Off(RED); } else PIOS_LED_Off(RED); - if (STOPWATCH_ValueGet(LED_PWM_TIMER) > 100 * 50 * 100) - STOPWATCH_Reset(LED_PWM_TIMER); - if ((STOPWATCH_ValueGet(LED_PWM_TIMER) > 60000) && (DeviceState + if (stopwatch > 50 * 1000 * 1000) + stopwatch = 0; + if ((stopwatch > 6 * 1000 * 1000) && (DeviceState == BLidle)) JumpToApp = TRUE; @@ -170,7 +171,9 @@ int main() { } void jump_to_app() { - if (((*(__IO uint32_t*) START_OF_USER_CODE) & 0x2FFE0000) == 0x20000000) { /* Jump to user application */ + const struct pios_board_info * bdinfo = &pios_board_info_blob; + + if (((*(__IO uint32_t*) bdinfo->fw_base) & 0x2FFE0000) == 0x20000000) { /* Jump to user application */ FLASH_Lock(); RCC_APB2PeriphResetCmd(0xffffffff, ENABLE); RCC_APB1PeriphResetCmd(0xffffffff, ENABLE); @@ -179,10 +182,10 @@ void jump_to_app() { _SetCNTR(0); // clear interrupt mask _SetISTR(0); // clear all requests - JumpAddress = *(__IO uint32_t*) (START_OF_USER_CODE + 4); + JumpAddress = *(__IO uint32_t*) (bdinfo->fw_base + 4); Jump_To_Application = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */ - __set_MSP(*(__IO uint32_t*) START_OF_USER_CODE); + __set_MSP(*(__IO uint32_t*) bdinfo->fw_base); Jump_To_Application(); } else { DeviceState = failed_jump; @@ -190,20 +193,21 @@ void jump_to_app() { } } uint32_t LedPWM(uint32_t pwm_period, uint32_t pwm_sweep_steps, uint32_t count) { - uint32_t pwm_duty = ((count / pwm_period) % pwm_sweep_steps) - / (pwm_sweep_steps / pwm_period); - if ((count % (2 * pwm_period * pwm_sweep_steps)) > pwm_period - * pwm_sweep_steps) - pwm_duty = pwm_period - pwm_duty; // negative direction each 50*100 ticks + uint32_t curr_step = (count / pwm_period) % pwm_sweep_steps; /* 0 - pwm_sweep_steps */ + uint32_t pwm_duty = pwm_period * curr_step / pwm_sweep_steps; /* fraction of pwm_period */ + + uint32_t curr_sweep = (count / (pwm_period * pwm_sweep_steps)); /* ticks once per full sweep */ + if (curr_sweep & 1) { + pwm_duty = pwm_period - pwm_duty; /* reverse direction in odd sweeps */ + } return ((count % pwm_period) > pwm_duty) ? 1 : 0; } uint8_t processRX() { while (PIOS_COM_ReceiveBufferUsed(PIOS_COM_TELEM_USB) >= 63) { - for (int32_t x = 0; x < 63; ++x) { - mReceive_Buffer[x] = PIOS_COM_ReceiveBuffer(PIOS_COM_TELEM_USB); + if (PIOS_COM_ReceiveBuffer(PIOS_COM_TELEM_USB, mReceive_Buffer, 63, 0) == 63) { + processComand(mReceive_Buffer); } - processComand(mReceive_Buffer); } return TRUE; } diff --git a/flight/Bootloaders/PipXtreme/op_dfu.c b/flight/Bootloaders/PipXtreme/op_dfu.c index c413c31ba..770ce8237 100644 --- a/flight/Bootloaders/PipXtreme/op_dfu.c +++ b/flight/Bootloaders/PipXtreme/op_dfu.c @@ -30,6 +30,7 @@ #include "pios.h" #include "op_dfu.h" #include "pios_bl_helper.h" +#include /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ @@ -414,16 +415,18 @@ void processComand(uint8_t *xReceive_Buffer) { return; } void OPDfuIni(uint8_t discover) { + const struct pios_board_info * bdinfo = &pios_board_info_blob; Device dev; + dev.programmingType = Self_flash; - dev.readWriteFlags = (BOARD_READABLE | (BOARD_WRITABLA << 1)); - dev.startOfUserCode = START_OF_USER_CODE; - dev.sizeOfCode = SIZE_OF_CODE; - dev.sizeOfDescription = SIZE_OF_DESCRIPTION; - dev.BL_Version = BOOTLOADER_VERSION; + dev.readWriteFlags = (BOARD_READABLE | (BOARD_WRITABLE << 1)); + dev.startOfUserCode = bdinfo->fw_base; + dev.sizeOfCode = bdinfo->fw_size; + dev.sizeOfDescription = bdinfo->desc_size; + dev.BL_Version = bdinfo->bl_rev; dev.FW_Crc = CalcFirmCRC(); - dev.devID = (BOARD_TYPE << 8) | BOARD_REVISION; - dev.devType = HW_TYPE; + dev.devID = (bdinfo->board_type << 8) | (bdinfo->board_rev); + dev.devType = bdinfo->hw_type; numberOfDevices = 1; devicesTable[0] = dev; if (discover) { diff --git a/flight/Bootloaders/PipXtreme/pios_board.c b/flight/Bootloaders/PipXtreme/pios_board.c index 2277080d8..83f0f407a 100644 --- a/flight/Bootloaders/PipXtreme/pios_board.c +++ b/flight/Bootloaders/PipXtreme/pios_board.c @@ -31,10 +31,31 @@ #include +#define PIOS_COM_TELEM_USB_RX_BUF_LEN 192 +#define PIOS_COM_TELEM_USB_TX_BUF_LEN 192 + +static uint8_t pios_com_telem_usb_rx_buffer[PIOS_COM_TELEM_USB_RX_BUF_LEN]; +static uint8_t pios_com_telem_usb_tx_buffer[PIOS_COM_TELEM_USB_TX_BUF_LEN]; + #endif /* PIOS_INCLUDE_COM */ // *********************************************************************************** +#if defined(PIOS_INCLUDE_USB_HID) +#include "pios_usb_hid_priv.h" + +static const struct pios_usb_hid_cfg pios_usb_hid_main_cfg = { + .irq = { + .init = { + .NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; +#endif /* PIOS_INCLUDE_USB_HID */ + extern const struct pios_com_driver pios_usb_com_driver; uint32_t pios_com_telem_usb_id; @@ -44,7 +65,12 @@ uint32_t pios_com_telem_usb_id; * initializes all the core subsystems on this specific hardware * called from System/openpilot.c */ +static bool board_init_complete = false; void PIOS_Board_Init(void) { + if (board_init_complete) { + return; + } + /* Enable Prefetch Buffer */ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); @@ -58,13 +84,18 @@ void PIOS_Board_Init(void) { PIOS_GPIO_Init(); #if defined(PIOS_INCLUDE_USB_HID) - PIOS_USB_HID_Init(0); + uint32_t pios_usb_hid_id; + PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_main_cfg); #if defined(PIOS_INCLUDE_COM) - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_com_driver, 0)) { - PIOS_DEBUG_Assert(0); + if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_com_driver, pios_usb_hid_id, + pios_com_telem_usb_rx_buffer, sizeof(pios_com_telem_usb_rx_buffer), + pios_com_telem_usb_tx_buffer, sizeof(pios_com_telem_usb_tx_buffer))) { + PIOS_Assert(0); } #endif /* PIOS_INCLUDE_COM */ -#endif /* PIOS_INCLUDE_USB_HID */ +#endif /* PIOS_INCLUDE_USB_HID */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);//TODO Tirar + + board_init_complete = true; } diff --git a/flight/CopterControl/Makefile b/flight/CopterControl/Makefile index f499d549a..2d7663853 100644 --- a/flight/CopterControl/Makefile +++ b/flight/CopterControl/Makefile @@ -25,11 +25,21 @@ WHEREAMI := $(dir $(lastword $(MAKEFILE_LIST))) TOP := $(realpath $(WHEREAMI)/../../) include $(TOP)/make/firmware-defs.mk +include $(TOP)/make/boards/$(BOARD_NAME)/board-info.mk + +# Target file name (without extension). +TARGET := fw_$(BOARD_NAME) + +# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) +OUTDIR := $(TOP)/build/$(TARGET) # Set developer code and compile options # Set to YES to compile for debugging DEBUG ?= NO +# Include objects that are just nice information to show +DIAGNOSTICS ?= NO + # Set to YES to build a FW version that will erase all flash memory ERASE_FLASH ?= NO # Set to YES to use the Servo output pins for debugging via scope or logic analyser @@ -38,7 +48,7 @@ ENABLE_DEBUG_PINS ?= NO # Set to Yes to enable the AUX UART which is mapped on the S1 (Tx) and S2 (Rx) servo outputs ENABLE_AUX_UART ?= NO -USE_SPEKTRUM ?= NO +USE_GPS ?= NO USE_I2C ?= NO @@ -55,22 +65,9 @@ endif FLASH_TOOL = OPENOCD # List of modules to include -MODULES = Telemetry Attitude Stabilization Actuator ManualControl FirmwareIAP - -# MCU name, submodel and board -# - MCU used for compiler-option (-mcpu) -# - MODEL used for linker-script name (-T) and passed as define -# - BOARD just passed as define (optional) -MCU = cortex-m3 -CHIP = STM32F103CBT -BOARD = STM32103CB_CC_Rev1 -MODEL = MD - -# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) -OUTDIR = $(TOP)/build/coptercontrol - -# Target file name (without extension). -TARGET = CopterControl +MODULES = Attitude Stabilization Actuator ManualControl FirmwareIAP CameraStab +# Telemetry must be last to grab the optional modules +MODULES += Telemetry # Paths OPSYSTEM = ./System @@ -121,12 +118,9 @@ OPUAVSYNTHDIR = $(OUTDIR)/../uavobject-synthetics/flight # List C source files here. (C dependencies are automatically generated.) # use file-extension c for "c-only"-files -MODNAMES = $(notdir ${MODULES}) - ifndef TESTAPP ## MODULES SRC += ${foreach MOD, ${MODULES}, ${wildcard ${OPMODULEDIR}/${MOD}/*.c}} -SRC += ${OUTDIR}/InitMods.c ## OPENPILOT CORE: SRC += ${OPMODULEDIR}/System/systemmod.c SRC += $(OPSYSTEM)/coptercontrol.c @@ -136,7 +130,6 @@ SRC += $(OPSYSTEM)/taskmonitor.c SRC += $(OPUAVTALK)/uavtalk.c SRC += $(OPUAVOBJ)/uavobjectmanager.c SRC += $(OPUAVOBJ)/eventdispatcher.c -SRC += $(OPUAVOBJ)/uavobjectsinit_linker.c SRC += $(OPSYSTEM)/pios_usb_hid_desc.c else ## TESTCODE @@ -148,6 +141,7 @@ endif ## UAVOBJECTS ifndef TESTAPP +SRC += $(OPUAVSYNTHDIR)/accessorydesired.c SRC += $(OPUAVSYNTHDIR)/objectpersistence.c SRC += $(OPUAVSYNTHDIR)/gcstelemetrystats.c SRC += $(OPUAVSYNTHDIR)/flighttelemetrystats.c @@ -163,20 +157,21 @@ SRC += $(OPUAVSYNTHDIR)/actuatorsettings.c SRC += $(OPUAVSYNTHDIR)/attituderaw.c SRC += $(OPUAVSYNTHDIR)/attitudeactual.c SRC += $(OPUAVSYNTHDIR)/manualcontrolcommand.c -SRC += $(OPUAVSYNTHDIR)/taskinfo.c SRC += $(OPUAVSYNTHDIR)/i2cstats.c SRC += $(OPUAVSYNTHDIR)/watchdogstatus.c SRC += $(OPUAVSYNTHDIR)/telemetrysettings.c -SRC += $(OPUAVSYNTHDIR)/ratedesired.c SRC += $(OPUAVSYNTHDIR)/manualcontrolsettings.c SRC += $(OPUAVSYNTHDIR)/mixersettings.c -SRC += $(OPUAVSYNTHDIR)/mixerstatus.c SRC += $(OPUAVSYNTHDIR)/firmwareiapobj.c SRC += $(OPUAVSYNTHDIR)/attitudesettings.c -#${wildcard ${OBJ}/$(shell echo $(VAR) | tr A-Z a-z)/*.c} -#SRC += ${foreach OBJ, ${UAVOBJECTS}, $(UAVOBJECTS)/$(OBJ).c} -# Cant use until i can automatically generate list of UAVObjects -#SRC += ${OUTDIR}/InitObjects.c +SRC += $(OPUAVSYNTHDIR)/camerastabsettings.c +SRC += $(OPUAVSYNTHDIR)/cameradesired.c +SRC += $(OPUAVSYNTHDIR)/hwsettings.c + +SRC += $(OPUAVSYNTHDIR)/taskinfo.c +SRC += $(OPUAVSYNTHDIR)/mixerstatus.c +SRC += $(OPUAVSYNTHDIR)/ratedesired.c + endif ## PIOS Hardware (STM32F10x) @@ -192,9 +187,11 @@ SRC += $(PIOSSTM32F10X)/pios_spi.c SRC += $(PIOSSTM32F10X)/pios_ppm.c SRC += $(PIOSSTM32F10X)/pios_pwm.c SRC += $(PIOSSTM32F10X)/pios_spektrum.c +SRC += $(PIOSSTM32F10X)/pios_sbus.c SRC += $(PIOSSTM32F10X)/pios_debug.c SRC += $(PIOSSTM32F10X)/pios_gpio.c SRC += $(PIOSSTM32F10X)/pios_exti.c +SRC += $(PIOSSTM32F10X)/pios_rtc.c SRC += $(PIOSSTM32F10X)/pios_wdg.c @@ -205,12 +202,15 @@ SRC += $(PIOSSTM32F10X)/pios_usb_hid_prop.c SRC += $(PIOSSTM32F10X)/pios_usb_hid_pwr.c ## PIOS Hardware (Common) +SRC += $(PIOSCOMMON)/pios_crc.c +SRC += $(PIOSCOMMON)/pios_flashfs_objlist.c SRC += $(PIOSCOMMON)/pios_flash_w25x.c SRC += $(PIOSCOMMON)/pios_adxl345.c SRC += $(PIOSCOMMON)/pios_com.c SRC += $(PIOSCOMMON)/pios_i2c_esc.c SRC += $(PIOSCOMMON)/pios_iap.c SRC += $(PIOSCOMMON)/pios_bl_helper.c +SRC += $(PIOSCOMMON)/pios_rcvr.c SRC += $(PIOSCOMMON)/printf-stdarg.c ## Libraries for flight calculations SRC += $(FLIGHTLIB)/fifo_buffer.c @@ -298,7 +298,7 @@ CPPSRCARM = # Even though the DOS/Win* filesystem matches both .s and .S the same, # it will preserve the spelling of the filenames, and gcc itself does # care about how the name is spelled on its command-line. -ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL)_CC.S +ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL)$(MODEL_SUFFIX).S # List Assembler source files here which must be assembled in ARM-Mode.. ASRCARM = @@ -380,19 +380,18 @@ endif ifeq ($(ENABLE_AUX_UART), YES) CDEFS += -DPIOS_ENABLE_AUX_UART endif -CDEFS += -DUSE_BOOTLOADER ifeq ($(ERASE_FLASH), YES) CDEFS += -DERASE_FLASH endif -ifeq ($(USE_SPEKTRUM), YES) -CDEFS += -DUSE_SPEKTRUM + +ifneq ($(USE_GPS), NO) +CDEFS += -DUSE_GPS endif ifeq ($(USE_I2C), YES) CDEFS += -DUSE_I2C endif - # Place project-specific -D and/or -U options for # Assembler with preprocessor here. #ADEFS = -DUSE_IRQ_ASM_WRAPPER @@ -419,9 +418,14 @@ CSTANDARD = -std=gnu99 # Flags for C and C++ (arm-elf-gcc/arm-elf-g++) ifeq ($(DEBUG),YES) -CFLAGS = -g$(DEBUGF) -DDEBUG +CFLAGS = -DDEBUG endif +ifeq ($(DIAGNOSTICS),YES) +CFLAGS = -DDIAGNOSTICS +endif + +CFLAGS += -g$(DEBUGF) CFLAGS += -O$(OPT) CFLAGS += -mcpu=$(MCU) CFLAGS += $(CDEFS) @@ -429,7 +433,7 @@ CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) -I. #CFLAGS += -fno-cprop-registers -fno-defer-pop -fno-guess-branch-probability -fno-section-anchors #CFLAGS += -fno-if-conversion -fno-if-conversion2 -fno-ipa-pure-const -fno-ipa-reference -fno-merge-constants -#CFLAGS += -fno-split-wide-types -fno-tree-ccp -fno-tree-ch -fno-tree-copy-prop -fno-tree-copyrename +#CFLAGS += -fno-split-wide-types -fno-tree-ccp -fno-tree-ch -fno-tree-copy-prop -fno-tree-copyrename #CFLAGS += -fno-tree-dce -fno-tree-dominator-opts -fno-tree-dse -fno-tree-fre -fno-tree-sink -fno-tree-sra #CFLAGS += -fno-tree-ter #CFLAGS += -g$(DEBUGF) -DDEBUG @@ -473,21 +477,9 @@ LDFLAGS += -lc -lgcc LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_memory.ld LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_sections.ld -OOCD_LOADFILE+=$(OUTDIR)/$(TARGET).bin -# Program -OOCD_CL+=-c "flash write_image erase $(OOCD_LOADFILE) 0x08003000 bin" -# Verify -OOCD_CL+=-c "verify_image $(OOCD_LOADFILE) 0x08003000 bin" -# reset target -OOCD_CL+=-c "reset run" -# terminate OOCD after programming -OOCD_CL+=-c shutdown - # Define programs and commands. REMOVE = $(REMOVE_CMD) -f PYTHON = python -###SHELL = sh -###COPY = cp # List of all source files. ALLSRC = $(ASRCARM) $(ASRC) $(SRCARM) $(SRC) $(CPPSRCARM) $(CPPSRC) @@ -503,7 +495,7 @@ LSTFILES = $(addprefix $(OUTDIR)/, $(addsuffix .lst, $(ALLSRCBASE))) DEPFILES = $(addprefix $(OUTDIR)/dep/, $(addsuffix .o.d, $(ALLSRCBASE))) # Default target. -all: gencode build +all: build ifeq ($(LOADFORMAT),ihex) build: elf hex lss sym @@ -519,32 +511,13 @@ endif endif endif -# Generate intermediate code for objects -gencode: ${OUTDIR}/InitMods.c - -# Generate code for module initialization -${OUTDIR}/InitMods.c: Makefile - @echo $(MSG_MODINIT) $(call toprel, $@) - @echo ${quote}// Autogenerated file${quote} > ${OUTDIR}/InitMods.c - @echo ${quote}${foreach MOD, ${MODNAMES}, extern unsigned int ${MOD}Initialize(void);}${quote} >> ${OUTDIR}/InitMods.c - @echo ${quote}void InitModules() {${quote} >> ${OUTDIR}/InitMods.c - @echo ${quote}${foreach MOD, ${MODNAMES}, ${MOD}Initialize();}${quote} >> ${OUTDIR}/InitMods.c - @echo ${quote}}${quote} >> ${OUTDIR}/InitMods.c - # Generate code for PyMite -#$(OUTDIR)/pmlib_img.c $(OUTDIR)/pmlib_nat.c $(OUTDIR)/pmlibusr_img.c $(OUTDIR)/pmlibusr_nat.c $(OUTDIR)/pmfeatures.h: $(wildcard $(PYMITELIB)/*.py) $(wildcard $(PYMITEPLAT)/*.py) $(wildcard $(FLIGHTPLANLIB)/*.py) $(wildcard $(FLIGHTPLANS)/*.py) +#$(OUTDIR)/pmlib_img.c $(OUTDIR)/pmlib_nat.c $(OUTDIR)/pmlibusr_img.c $(OUTDIR)/pmlibusr_nat.c $(OUTDIR)/pmfeatures.h: $(wildcard $(PYMITELIB)/*.py) $(wildcard $(PYMITEPLAT)/*.py) $(wildcard $(FLIGHTPLANLIB)/*.py) $(wildcard $(FLIGHTPLANS)/*.py) # @echo $(MSG_PYMITEINIT) $(call toprel, $@) # @$(PYTHON) $(PYMITETOOLS)/pmImgCreator.py -f $(PYMITEPLAT)/pmfeatures.py -c -s --memspace=flash -o $(OUTDIR)/pmlib_img.c --native-file=$(OUTDIR)/pmlib_nat.c $(PYMITELIB)/list.py $(PYMITELIB)/dict.py $(PYMITELIB)/__bi.py $(PYMITELIB)/sys.py $(PYMITELIB)/string.py $(wildcard $(FLIGHTPLANLIB)/*.py) # @$(PYTHON) $(PYMITETOOLS)/pmGenPmFeatures.py $(PYMITEPLAT)/pmfeatures.py > $(OUTDIR)/pmfeatures.h # @$(PYTHON) $(PYMITETOOLS)/pmImgCreator.py -f $(PYMITEPLAT)/pmfeatures.py -c -u -o $(OUTDIR)/pmlibusr_img.c --native-file=$(OUTDIR)/pmlibusr_nat.c $(FLIGHTPLANS)/test.py -ifeq ($(FLASH_TOOL),OPENOCD) -# Program the device with Dominic Rath's OPENOCD in "batch-mode", needs cfg and "reset-script". -program: $(OUTDIR)/$(TARGET).bin - @echo ${quote}Programming with OPENOCD${quote} - $(OOCD_EXE) $(OOCD_CL) -endif - # Link: create ELF output file from object files. $(eval $(call LINK_TEMPLATE, $(OUTDIR)/$(TARGET).elf, $(ALLOBJ))) @@ -574,23 +547,37 @@ $(eval $(call PARTIAL_COMPILE_ARM_TEMPLATE, SRCARM)) $(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin -.PHONY: elf lss sym hex bin bino +$(eval $(call OPFW_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BOARD_TYPE),$(BOARD_REVISION))) + +# Add jtag targets (program and wipe) +$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE))) + +.PHONY: elf lss sym hex bin bino opfw elf: $(OUTDIR)/$(TARGET).elf lss: $(OUTDIR)/$(TARGET).lss sym: $(OUTDIR)/$(TARGET).sym hex: $(OUTDIR)/$(TARGET).hex bin: $(OUTDIR)/$(TARGET).bin bino: $(OUTDIR)/$(TARGET).bin.o +opfw: $(OUTDIR)/$(TARGET).opfw # Display sizes of sections. $(eval $(call SIZE_TEMPLATE, $(OUTDIR)/$(TARGET).elf)) -.PHONY: size -size: $(OUTDIR)/$(TARGET).elf_size # Generate Doxygen documents docs: doxygen $(DOXYGENDIR)/doxygen.cfg +# Install: install binary file with prefix/suffix into install directory +install: $(OUTDIR)/$(TARGET).opfw +ifneq ($(INSTALL_DIR),) + @echo $(MSG_INSTALLING) $(call toprel, $<) + $(V1) mkdir -p $(INSTALL_DIR) + $(V1) $(INSTALL) $< $(INSTALL_DIR)/$(INSTALL_PFX)$(TARGET)$(INSTALL_SFX).opfw +else + $(error INSTALL_DIR must be specified for $@) +endif + # Target: clean project. clean: clean_list @@ -630,5 +617,4 @@ else endif # Listing of phony targets. -.PHONY : all build clean clean_list program gencode - +.PHONY : all build clean clean_list install diff --git a/flight/CopterControl/System/alarms.c b/flight/CopterControl/System/alarms.c index e899be779..01d79a1e5 100644 --- a/flight/CopterControl/System/alarms.c +++ b/flight/CopterControl/System/alarms.c @@ -41,10 +41,12 @@ static xSemaphoreHandle lock; static int32_t hasSeverity(SystemAlarmsAlarmOptions severity); /** - * Initialize the alarms library + * Initialize the alarms library */ int32_t AlarmsInitialize(void) { + SystemAlarmsInitialize(); + lock = xSemaphoreCreateRecursiveMutex(); //do not change the default states of the alarms, let the init code generated by the uavobjectgenerator handle that //AlarmsClearAll(); @@ -56,7 +58,7 @@ int32_t AlarmsInitialize(void) * Set an alarm * @param alarm The system alarm to be modified * @param severity The alarm severity - * @return 0 if success, -1 if an error + * @return 0 if success, -1 if an error */ int32_t AlarmsSet(SystemAlarmsAlarmElem alarm, SystemAlarmsAlarmOptions severity) { @@ -151,7 +153,7 @@ void AlarmsClearAll() /** * Check if there are any alarms with the given or higher severity - * @return 0 if no alarms are found, 1 if at least one alarm is found + * @return 0 if no alarms are found, 1 if at least one alarm is found */ int32_t AlarmsHasWarnings() { @@ -208,5 +210,5 @@ static int32_t hasSeverity(SystemAlarmsAlarmOptions severity) /** * @} * @} - */ + */ diff --git a/flight/CopterControl/System/coptercontrol.c b/flight/CopterControl/System/coptercontrol.c index 588fa4a9f..33cb096c2 100644 --- a/flight/CopterControl/System/coptercontrol.c +++ b/flight/CopterControl/System/coptercontrol.c @@ -1,106 +1,107 @@ -/** - ****************************************************************************** - * @addtogroup OpenPilotSystem OpenPilot System - * @brief These files are the core system files of OpenPilot. - * They are the ground layer just above PiOS. In practice, OpenPilot actually starts - * in the main() function of openpilot.c - * @{ - * @addtogroup OpenPilotCore OpenPilot Core - * @brief This is where the OP firmware starts. Those files also define the compile-time - * options of the firmware. - * @{ - * @file openpilot.c - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @brief Sets up and runs main OpenPilot tasks. - * @see The GNU Public License (GPL) Version 3 - * - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -/* OpenPilot Includes */ -#include "openpilot.h" -#include "uavobjectsinit.h" -#include "systemmod.h" - -/* Task Priorities */ -#define PRIORITY_TASK_HOOKS (tskIDLE_PRIORITY + 3) - -/* Global Variables */ - -/* Prototype of generated InitModules() function */ -extern void InitModules(void); - -/* Prototype of PIOS_Board_Init() function */ -extern void PIOS_Board_Init(void); - -/** -* OpenPilot Main function: -* -* Initialize PiOS
-* Create the "System" task (SystemModInitializein Modules/System/systemmod.c)
-* Start FreeRTOS Scheduler (vTaskStartScheduler)
-* If something goes wrong, blink LED1 and LED2 every 100ms -* -*/ -int main() -{ - /* NOTE: Do NOT modify the following start-up sequence */ - /* Any new initialization functions should be added in OpenPilotInit() */ - - /* Brings up System using CMSIS functions, enables the LEDs. */ - PIOS_SYS_Init(); - - /* Initialize the system thread */ - SystemModInitialize(); - - /* Start the FreeRTOS scheduler */ - vTaskStartScheduler(); - - /* If all is well we will never reach here as the scheduler will now be running. */ - /* If we do get here, it will most likely be because we ran out of heap space. */ - - return 0; -} - -/** - * Initialize the hardware, libraries and modules (called by the System thread in systemmod.c) - */ -void OpenPilotInit() -{ - - /* Architecture dependant Hardware and - * core subsystem initialisation - * (see pios_board.c for your arch) - * */ - - PIOS_Board_Init(); - -#ifdef ERASE_FLASH - PIOS_Flash_W25X_EraseChip(); -#endif - - /* Initialize modules */ - InitModules(); -} - - -/** - * @} - * @} - */ - +/** + ****************************************************************************** + * @addtogroup OpenPilotSystem OpenPilot System + * @brief These files are the core system files of OpenPilot. + * They are the ground layer just above PiOS. In practice, OpenPilot actually starts + * in the main() function of openpilot.c + * @{ + * @addtogroup OpenPilotCore OpenPilot Core + * @brief This is where the OP firmware starts. Those files also define the compile-time + * options of the firmware. + * @{ + * @file openpilot.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Sets up and runs main OpenPilot tasks. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* OpenPilot Includes */ +#include "openpilot.h" +#include "uavobjectsinit.h" +#include "hwsettings.h" +#include "camerastab.h" +#include "systemmod.h" + +/* Task Priorities */ +#define PRIORITY_TASK_HOOKS (tskIDLE_PRIORITY + 3) + +/* Global Variables */ + +/* Prototype of PIOS_Board_Init() function */ +extern void PIOS_Board_Init(void); +extern void Stack_Change(void); + +/** +* OpenPilot Main function: +* +* Initialize PiOS
+* Create the "System" task (SystemModInitializein Modules/System/systemmod.c)
+* Start FreeRTOS Scheduler (vTaskStartScheduler) (Now handled by caller) +* If something goes wrong, blink LED1 and LED2 every 100ms +* +*/ +int main() +{ + /* NOTE: Do NOT modify the following start-up sequence */ + /* Any new initialization functions should be added in OpenPilotInit() */ + + /* Brings up System using CMSIS functions, enables the LEDs. */ + PIOS_SYS_Init(); + + /* Architecture dependant Hardware and + * core subsystem initialisation + * (see pios_board.c for your arch) + * */ + PIOS_Board_Init(); + + /* Initialize modules */ + MODULE_INITIALISE_ALL + + /* Optional module initialization. This code might want to go somewhere else as + * it grows */ + uint8_t optionalModules[HWSETTINGS_OPTIONALMODULES_NUMELEM]; + HwSettingsOptionalModulesGet(optionalModules); + if(optionalModules[HWSETTINGS_OPTIONALMODULES_CAMERASTABILIZATION] == HWSETTINGS_OPTIONALMODULES_ENABLED) { + CameraStabInitialize(); + } + + /* swap the stack to use the IRQ stack */ + Stack_Change(); + + /* Start the FreeRTOS scheduler which should never returns.*/ + vTaskStartScheduler(); + + /* If all is well we will never reach here as the scheduler will now be running. */ + + /* Do some indication to user that something bad just happened */ + PIOS_LED_Off(LED1); \ + for(;;) { \ + PIOS_LED_Toggle(LED1); \ + PIOS_DELAY_WaitmS(100); \ + }; + + return 0; +} + +/** + * @} + * @} + */ + diff --git a/flight/CopterControl/System/inc/FreeRTOSConfig.h b/flight/CopterControl/System/inc/FreeRTOSConfig.h index b4677fd8d..8da6a8667 100644 --- a/flight/CopterControl/System/inc/FreeRTOSConfig.h +++ b/flight/CopterControl/System/inc/FreeRTOSConfig.h @@ -9,7 +9,7 @@ * application requirements. * * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE - * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. * * See http://www.freertos.org/a00110.html. *----------------------------------------------------------*/ @@ -29,8 +29,8 @@ #define configCPU_CLOCK_HZ ( ( unsigned long ) 72000000 ) #define configTICK_RATE_HZ ( ( portTickType ) 1000 ) #define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 ) -#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 ) -#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 14 * 1024 ) ) +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 48 ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 54 * 256) ) #define configMAX_TASK_NAME_LEN ( 16 ) #define configUSE_TRACE_FACILITY 0 #define configUSE_16_BIT_TICKS 0 @@ -39,7 +39,6 @@ #define configUSE_RECURSIVE_MUTEXES 1 #define configUSE_COUNTING_SEMAPHORES 0 #define configUSE_ALTERNATIVE_API 0 -#define configCHECK_FOR_STACK_OVERFLOW 2 #define configQUEUE_REGISTRY_SIZE 10 /* Co-routine definitions. */ @@ -71,6 +70,27 @@ configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest NVIC value of 255. */ #define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15 +#if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) +#define CHECK_IRQ_STACK +#endif + +/* Enable run time stats collection */ +#if defined(DIAGNOSTICS) +#define configCHECK_FOR_STACK_OVERFLOW 2 + +#define configGENERATE_RUN_TIME_STATS 1 +#define INCLUDE_uxTaskGetRunTime 1 +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()\ +do {\ +(*(unsigned long *)0xe000edfc) |= (1<<24);/* DEMCR |= DEMCR_TRCENA */\ +(*(unsigned long *)0xe0001000) |= 1; /* DWT_CTRL |= DWT_CYCCNT_ENA */\ +} while(0) +#define portGET_RUN_TIME_COUNTER_VALUE() (*(unsigned long *)0xe0001004)/* DWT_CYCCNT */ +#else +#define configCHECK_FOR_STACK_OVERFLOW 1 +#endif + + /** * @} */ diff --git a/flight/CopterControl/System/inc/pios_config.h b/flight/CopterControl/System/inc/pios_config.h index af1b7d22d..8e09d71ca 100644 --- a/flight/CopterControl/System/inc/pios_config.h +++ b/flight/CopterControl/System/inc/pios_config.h @@ -1,106 +1,113 @@ -/** - ****************************************************************************** - * @addtogroup OpenPilotSystem OpenPilot System - * @{ - * @addtogroup OpenPilotCore OpenPilot Core - * @{ - * - * @file pios_config.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @brief PiOS configuration header. - * Central compile time config for the project. - * In particular, pios_config.h is where you define which PiOS libraries - * and features are included in the firmware. - * @see The GNU Public License (GPL) Version 3 - * - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef PIOS_CONFIG_H -#define PIOS_CONFIG_H - - -/* Enable/Disable PiOS Modules */ -#define PIOS_INCLUDE_ADC -#define PIOS_INCLUDE_DELAY -#if defined(USE_I2C) -#define PIOS_INCLUDE_I2C -#define PIOS_INCLUDE_I2C_ESC -#endif -#define PIOS_INCLUDE_IRQ -#define PIOS_INCLUDE_LED - -#if defined(USE_SPEKTRUM) -#define PIOS_INCLUDE_SPEKTRUM -#else -#define PIOS_INCLUDE_GPS -//#define PIOS_INCLUDE_PPM -#define PIOS_INCLUDE_PWM -#endif - - -#define PIOS_INCLUDE_SERVO -#define PIOS_INCLUDE_SPI -#define PIOS_INCLUDE_SYS -#define PIOS_INCLUDE_USART -#define PIOS_INCLUDE_USB_HID -#define PIOS_INCLUDE_COM -#define PIOS_INCLUDE_SETTINGS -#define PIOS_INCLUDE_FREERTOS -#define PIOS_INCLUDE_GPIO -#define PIOS_INCLUDE_EXTI -#define PIOS_INCLUDE_WDG -#define PIOS_INCLUDE_BL_HELPER - -#define PIOS_INCLUDE_ADXL345 -#define PIOS_INCLUDE_FLASH - -/* A really shitty setting saving implementation */ -#define PIOS_INCLUDE_FLASH_SECTOR_SETTINGS - -/* Defaults for Logging */ -#define LOG_FILENAME "PIOS.LOG" -#define STARTUP_LOG_ENABLED 1 - -/* COM Module */ -#define GPS_BAUDRATE 19200 -#define TELEM_BAUDRATE 19200 -#define AUXUART_ENABLED 0 -#define AUXUART_BAUDRATE 19200 - -/* Alarm Thresholds */ -#define HEAP_LIMIT_WARNING 350 -#define HEAP_LIMIT_CRITICAL 250 -#define CPULOAD_LIMIT_WARNING 80 -#define CPULOAD_LIMIT_CRITICAL 95 - -/* Task stack sizes */ -#define PIOS_ACTUATOR_STACK_SIZE 1020 -#define PIOS_MANUAL_STACK_SIZE 724 -#define PIOS_SYSTEM_STACK_SIZE 504 -#define PIOS_STABILIZATION_STACK_SIZE 524 -#define PIOS_TELEM_STACK_SIZE 500 - -#define IDLE_COUNTS_PER_SEC_AT_NO_LOAD 1995998 -//#define PIOS_QUATERNION_STABILIZATION - -#endif /* PIOS_CONFIG_H */ -/** - * @} - * @} - */ +/** + ****************************************************************************** + * @addtogroup OpenPilotSystem OpenPilot System + * @{ + * @addtogroup OpenPilotCore OpenPilot Core + * @{ + * + * @file pios_config.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief PiOS configuration header. + * Central compile time config for the project. + * In particular, pios_config.h is where you define which PiOS libraries + * and features are included in the firmware. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_CONFIG_H +#define PIOS_CONFIG_H + +/* Enable/Disable PiOS Modules */ +#define PIOS_INCLUDE_ADC +#define PIOS_INCLUDE_DELAY +#if defined(USE_I2C) +#define PIOS_INCLUDE_I2C +#define PIOS_INCLUDE_I2C_ESC +#endif +#define PIOS_INCLUDE_IRQ +#define PIOS_INCLUDE_LED + +#define PIOS_INCLUDE_RCVR + +/* Supported receiver interfaces */ +#define PIOS_INCLUDE_SPEKTRUM +#define PIOS_INCLUDE_SBUS +//#define PIOS_INCLUDE_PPM +#define PIOS_INCLUDE_PWM + +/* Supported USART-based PIOS modules */ +#define PIOS_INCLUDE_TELEMETRY_RF +//#define PIOS_INCLUDE_GPS + +#define PIOS_INCLUDE_SERVO +#define PIOS_INCLUDE_SPI +#define PIOS_INCLUDE_SYS +#define PIOS_INCLUDE_USART +#define PIOS_INCLUDE_USB_HID +#define PIOS_INCLUDE_COM +#define PIOS_INCLUDE_SETTINGS +#define PIOS_INCLUDE_FREERTOS +#define PIOS_INCLUDE_GPIO +#define PIOS_INCLUDE_EXTI +#define PIOS_INCLUDE_RTC +#define PIOS_INCLUDE_WDG +#define PIOS_INCLUDE_BL_HELPER + +#define PIOS_INCLUDE_ADXL345 +#define PIOS_INCLUDE_FLASH + +/* A really shitty setting saving implementation */ +#define PIOS_INCLUDE_FLASH_SECTOR_SETTINGS + +/* Defaults for Logging */ +#define LOG_FILENAME "PIOS.LOG" +#define STARTUP_LOG_ENABLED 1 + +/* COM Module */ +#define GPS_BAUDRATE 19200 +#define TELEM_BAUDRATE 19200 +#define AUXUART_ENABLED 0 +#define AUXUART_BAUDRATE 19200 + +/* Alarm Thresholds */ +#define HEAP_LIMIT_WARNING 220 +#define HEAP_LIMIT_CRITICAL 40 +#define IRQSTACK_LIMIT_WARNING 100 +#define IRQSTACK_LIMIT_CRITICAL 60 +#define CPULOAD_LIMIT_WARNING 85 +#define CPULOAD_LIMIT_CRITICAL 95 + +/* Task stack sizes */ +#define PIOS_ACTUATOR_STACK_SIZE 1020 +#define PIOS_MANUAL_STACK_SIZE 724 +#define PIOS_SYSTEM_STACK_SIZE 460 +#define PIOS_STABILIZATION_STACK_SIZE 524 +#define PIOS_TELEM_STACK_SIZE 500 +#define PIOS_EVENTDISPATCHER_STACK_SIZE 130 +#define IDLE_COUNTS_PER_SEC_AT_NO_LOAD 1995998 +//#define PIOS_QUATERNION_STABILIZATION + +// This can't be too high to stop eventdispatcher thread overflowing +#define PIOS_EVENTDISAPTCHER_QUEUE 10 + +#endif /* PIOS_CONFIG_H */ +/** + * @} + * @} + */ diff --git a/flight/CopterControl/System/pios_board.c b/flight/CopterControl/System/pios_board.c index 45164052f..d512ae989 100644 --- a/flight/CopterControl/System/pios_board.c +++ b/flight/CopterControl/System/pios_board.c @@ -30,10 +30,11 @@ #include #include #include +#include +#include #if defined(PIOS_INCLUDE_SPI) - #include /* Flash/Accel Interface @@ -44,7 +45,7 @@ void PIOS_SPI_flash_accel_irq_handler(void); void DMA1_Channel4_IRQHandler() __attribute__ ((alias ("PIOS_SPI_flash_accel_irq_handler"))); void DMA1_Channel5_IRQHandler() __attribute__ ((alias ("PIOS_SPI_flash_accel_irq_handler"))); -const struct pios_spi_cfg pios_spi_flash_accel_cfg = { +static const struct pios_spi_cfg pios_spi_flash_accel_cfg = { .regs = SPI2, .init = { .SPI_Mode = SPI_Mode_Master, @@ -62,7 +63,6 @@ const struct pios_spi_cfg pios_spi_flash_accel_cfg = { .ahb_clk = RCC_AHBPeriph_DMA1, .irq = { - .handler = PIOS_SPI_flash_accel_irq_handler, .flags = (DMA1_FLAG_TC4 | DMA1_FLAG_TE4 | DMA1_FLAG_HT4 | DMA1_FLAG_GL4), .init = { .NVIC_IRQChannel = DMA1_Channel4_IRQn, @@ -151,11 +151,10 @@ void PIOS_SPI_flash_accel_irq_handler(void) extern void PIOS_ADC_handler(void); void DMA1_Channel1_IRQHandler() __attribute__ ((alias("PIOS_ADC_handler"))); // Remap the ADC DMA handler to this one -const struct pios_adc_cfg pios_adc_cfg = { +static const struct pios_adc_cfg pios_adc_cfg = { .dma = { .ahb_clk = RCC_AHBPeriph_DMA1, .irq = { - .handler = PIOS_ADC_DMA_Handler, .flags = (DMA1_FLAG_TC1 | DMA1_FLAG_TE1 | DMA1_FLAG_HT1 | DMA1_FLAG_GL1), .init = { .NVIC_IRQChannel = DMA1_Channel1_IRQn, @@ -200,19 +199,14 @@ void PIOS_ADC_handler() { #include "pios_usart_priv.h" +#if defined(PIOS_INCLUDE_TELEMETRY_RF) /* * Telemetry USART */ -void PIOS_USART_telem_irq_handler(void); -void USART1_IRQHandler() __attribute__ ((alias ("PIOS_USART_telem_irq_handler"))); -const struct pios_usart_cfg pios_usart_telem_cfg = { +static const struct pios_usart_cfg pios_usart_telem_main_cfg = { .regs = USART1, .init = { - #if defined (PIOS_COM_TELEM_BAUDRATE) - .USART_BaudRate = PIOS_COM_TELEM_BAUDRATE, - #else - .USART_BaudRate = 57600, - #endif + .USART_BaudRate = 57600, .USART_WordLength = USART_WordLength_8b, .USART_Parity = USART_Parity_No, .USART_StopBits = USART_StopBits_1, @@ -220,7 +214,6 @@ const struct pios_usart_cfg pios_usart_telem_cfg = { .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, }, .irq = { - .handler = PIOS_USART_telem_irq_handler, .init = { .NVIC_IRQChannel = USART1_IRQn, .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, @@ -246,20 +239,10 @@ const struct pios_usart_cfg pios_usart_telem_cfg = { }, }; -#if defined(PIOS_INCLUDE_GPS) -/* - * GPS USART - */ -void PIOS_USART_gps_irq_handler(void); -void USART3_IRQHandler() __attribute__ ((alias ("PIOS_USART_gps_irq_handler"))); -const struct pios_usart_cfg pios_usart_gps_cfg = { - .regs = USART3, +static const struct pios_usart_cfg pios_usart_telem_flexi_cfg = { + .regs = USART3, .init = { - #if defined (PIOS_COM_GPS_BAUDRATE) - .USART_BaudRate = PIOS_COM_GPS_BAUDRATE, - #else - .USART_BaudRate = 57600, - #endif + .USART_BaudRate = 57600, .USART_WordLength = USART_WordLength_8b, .USART_Parity = USART_Parity_No, .USART_StopBits = USART_StopBits_1, @@ -267,7 +250,6 @@ const struct pios_usart_cfg pios_usart_gps_cfg = { .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, }, .irq = { - .handler = PIOS_USART_gps_irq_handler, .init = { .NVIC_IRQChannel = USART3_IRQn, .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, @@ -292,22 +274,143 @@ const struct pios_usart_cfg pios_usart_gps_cfg = { }, }, }; -#endif +#endif /* PIOS_INCLUDE_TELEMETRY_RF */ + +#if defined(PIOS_INCLUDE_GPS) +/* + * GPS USART + */ +static const struct pios_usart_cfg pios_usart_gps_main_cfg = { + .regs = USART1, + .init = { + .USART_BaudRate = 57600, + .USART_WordLength = USART_WordLength_8b, + .USART_Parity = USART_Parity_No, + .USART_StopBits = USART_StopBits_1, + .USART_HardwareFlowControl = USART_HardwareFlowControl_None, + .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, + }, + .irq = { + .init = { + .NVIC_IRQChannel = USART1_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .rx = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_10, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_IPU, + }, + }, + .tx = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_9, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_AF_PP, + }, + }, +}; + +static const struct pios_usart_cfg pios_usart_gps_flexi_cfg = { + .regs = USART3, + .init = { + .USART_BaudRate = 57600, + .USART_WordLength = USART_WordLength_8b, + .USART_Parity = USART_Parity_No, + .USART_StopBits = USART_StopBits_1, + .USART_HardwareFlowControl = USART_HardwareFlowControl_None, + .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, + }, + .irq = { + .init = { + .NVIC_IRQChannel = USART3_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .rx = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_11, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_IPU, + }, + }, + .tx = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_10, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_AF_PP, + }, + }, +}; +#endif /* PIOS_INCLUDE_GPS */ #if defined(PIOS_INCLUDE_SPEKTRUM) /* * SPEKTRUM USART */ -void PIOS_USART_spektrum_irq_handler(void); -void USART3_IRQHandler() __attribute__ ((alias ("PIOS_USART_spektrum_irq_handler"))); -const struct pios_usart_cfg pios_usart_spektrum_cfg = { - .regs = USART3, +#include + +static const struct pios_usart_cfg pios_usart_spektrum_main_cfg = { + .regs = USART1, .init = { - #if defined (PIOS_COM_SPEKTRUM_BAUDRATE) - .USART_BaudRate = PIOS_COM_SPEKTRUM_BAUDRATE, - #else - .USART_BaudRate = 115200, - #endif + .USART_BaudRate = 115200, + .USART_WordLength = USART_WordLength_8b, + .USART_Parity = USART_Parity_No, + .USART_StopBits = USART_StopBits_1, + .USART_HardwareFlowControl = USART_HardwareFlowControl_None, + .USART_Mode = USART_Mode_Rx, + }, + .irq = { + .init = { + .NVIC_IRQChannel = USART1_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .rx = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_10, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_IPU, + }, + }, + .tx = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_9, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_IN_FLOATING, + }, + }, +}; + +static const struct pios_spektrum_cfg pios_spektrum_main_cfg = { + .bind = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_10, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_Out_PP, + }, + }, + .remap = 0, +}; + +static const struct pios_usart_cfg pios_usart_spektrum_flexi_cfg = { + .regs = USART3, + .init = { + .USART_BaudRate = 115200, .USART_WordLength = USART_WordLength_8b, .USART_Parity = USART_Parity_No, .USART_StopBits = USART_StopBits_1, @@ -315,7 +418,6 @@ const struct pios_usart_cfg pios_usart_spektrum_cfg = { .USART_Mode = USART_Mode_Rx, }, .irq = { - .handler = PIOS_USART_spektrum_irq_handler, .init = { .NVIC_IRQChannel = USART3_IRQn, .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, @@ -341,76 +443,128 @@ const struct pios_usart_cfg pios_usart_spektrum_cfg = { }, }; -static uint32_t pios_usart_spektrum_id; -void PIOS_USART_spektrum_irq_handler(void) -{ - SPEKTRUM_IRQHandler(pios_usart_spektrum_id); -} - -#include -void TIM2_IRQHandler(); -void TIM2_IRQHandler() __attribute__ ((alias ("PIOS_TIM2_irq_handler"))); -const struct pios_spektrum_cfg pios_spektrum_cfg = { - .pios_usart_spektrum_cfg = &pios_usart_spektrum_cfg, - .tim_base_init = { - .TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1, /* For 1 uS accuracy */ - .TIM_ClockDivision = TIM_CKD_DIV1, - .TIM_CounterMode = TIM_CounterMode_Up, - .TIM_Period = ((1000000 / 120) - 1), //11ms-10*16b/115200bps atleast one interrupt between frames - .TIM_RepetitionCounter = 0x0000, - }, - .gpio_init = { //used for bind feature - .GPIO_Mode = GPIO_Mode_Out_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - .remap = 0, - .irq = { - .handler = TIM2_IRQHandler, - .init = { - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, +static const struct pios_spektrum_cfg pios_spektrum_flexi_cfg = { + .bind = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_11, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_Out_PP, }, }, - .timer = TIM2, - .port = GPIOB, - .ccr = TIM_IT_Update, - .pin = GPIO_Pin_11, + .remap = 0, }; -void PIOS_TIM2_irq_handler() -{ - PIOS_SPEKTRUM_irq_handler(pios_usart_spektrum_id); -} #endif /* PIOS_INCLUDE_SPEKTRUM */ -static uint32_t pios_usart_telem_rf_id; -void PIOS_USART_telem_irq_handler(void) -{ - PIOS_USART_IRQ_Handler(pios_usart_telem_rf_id); -} +#if defined(PIOS_INCLUDE_SBUS) +/* + * SBUS USART + */ +#include -#if defined(PIOS_INCLUDE_GPS) -static uint32_t pios_usart_gps_id; -void PIOS_USART_gps_irq_handler(void) -{ - PIOS_USART_IRQ_Handler(pios_usart_gps_id); -} -#endif /* PIOS_INCLUDE_GPS */ +static const struct pios_usart_cfg pios_usart_sbus_main_cfg = { + .regs = USART1, + .init = { + .USART_BaudRate = 100000, + .USART_WordLength = USART_WordLength_8b, + .USART_Parity = USART_Parity_Even, + .USART_StopBits = USART_StopBits_2, + .USART_HardwareFlowControl = USART_HardwareFlowControl_None, + .USART_Mode = USART_Mode_Rx, + }, + .irq = { + .init = { + .NVIC_IRQChannel = USART1_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .rx = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_10, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_IPU, + }, + }, + .tx = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_9, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_IN_FLOATING, + }, + }, +}; -#endif /* PIOS_INCLUDE_USART */ +static const struct pios_sbus_cfg pios_sbus_cfg = { + /* Inverter configuration */ + .inv = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_2, + .GPIO_Mode = GPIO_Mode_Out_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, + .gpio_clk_func = RCC_APB2PeriphClockCmd, + .gpio_clk_periph = RCC_APB2Periph_GPIOB, + .gpio_inv_enable = Bit_SET, +}; + +#endif /* PIOS_INCLUDE_SBUS */ + +#endif /* PIOS_INCLUDE_USART */ #if defined(PIOS_INCLUDE_COM) #include "pios_com_priv.h" +#define PIOS_COM_TELEM_RF_RX_BUF_LEN 192 +#define PIOS_COM_TELEM_RF_TX_BUF_LEN 192 + +#define PIOS_COM_GPS_RX_BUF_LEN 96 + +#define PIOS_COM_TELEM_USB_RX_BUF_LEN 192 +#define PIOS_COM_TELEM_USB_TX_BUF_LEN 192 + #endif /* PIOS_INCLUDE_COM */ +#if defined(PIOS_INCLUDE_RTC) +/* + * Realtime Clock (RTC) + */ +#include + +void PIOS_RTC_IRQ_Handler (void); +void RTC_IRQHandler() __attribute__ ((alias ("PIOS_RTC_IRQ_Handler"))); +static const struct pios_rtc_cfg pios_rtc_main_cfg = { + .clksrc = RCC_RTCCLKSource_HSE_Div128, + .prescaler = 100, + .irq = { + .init = { + .NVIC_IRQChannel = RTC_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +void PIOS_RTC_IRQ_Handler (void) +{ + PIOS_RTC_irq_handler (); +} + +#endif + /* * Servo outputs */ #include -const struct pios_servo_channel pios_servo_channels[] = { +static const struct pios_servo_channel pios_servo_channels[] = { { .timer = TIM4, .port = GPIOB, @@ -441,14 +595,12 @@ const struct pios_servo_channel pios_servo_channels[] = { .channel = TIM_Channel_1, .pin = GPIO_Pin_4, }, -#ifndef PIOS_INCLUDE_SPEKTRUM { .timer = TIM2, .port = GPIOA, .channel = TIM_Channel_3, .pin = GPIO_Pin_2, }, -#endif }; const struct pios_servo_cfg pios_servo_cfg = { @@ -478,13 +630,64 @@ const struct pios_servo_cfg pios_servo_cfg = { .num_channels = NELEMENTS(pios_servo_channels), }; +#if defined(PIOS_INCLUDE_PWM) && defined(PIOS_INCLUDE_PPM) +#error Cannot define both PIOS_INCLUDE_PWM and PIOS_INCLUDE_PPM at the same time (yet) +#endif + +/* + * PPM Inputs + */ +#if defined(PIOS_INCLUDE_PPM) +#include + +void TIM4_IRQHandler(); +void TIM4_IRQHandler() __attribute__ ((alias ("PIOS_TIM4_irq_handler"))); +const struct pios_ppm_cfg pios_ppm_cfg = { + .tim_base_init = { + .TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1, /* For 1 uS accuracy */ + .TIM_ClockDivision = TIM_CKD_DIV1, + .TIM_CounterMode = TIM_CounterMode_Up, + .TIM_Period = 0xFFFF, /* shared timer, make sure init correctly in outputs */ + .TIM_RepetitionCounter = 0x0000, + }, + .tim_ic_init = { + .TIM_Channel = TIM_Channel_1, + .TIM_ICPolarity = TIM_ICPolarity_Rising, + .TIM_ICSelection = TIM_ICSelection_DirectTI, + .TIM_ICPrescaler = TIM_ICPSC_DIV1, + .TIM_ICFilter = 0x0, + }, + .gpio_init = { + .GPIO_Pin = GPIO_Pin_6, + .GPIO_Mode = GPIO_Mode_IPD, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + .remap = 0, + .irq = { + .init = { + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .timer = TIM4, + .port = GPIOB, + .ccr = TIM_IT_CC1, +}; + +void PIOS_TIM4_irq_handler() +{ + PIOS_PPM_irq_handler(); +} +#endif /* PIOS_INCLUDE_PPM */ /* * PWM Inputs */ #if defined(PIOS_INCLUDE_PWM) #include -const struct pios_pwm_channel pios_pwm_channels[] = { + +static const struct pios_pwm_channel pios_pwm_channels[] = { { .timer = TIM4, .port = GPIOB, @@ -555,7 +758,6 @@ const struct pios_pwm_cfg pios_pwm_cfg = { }, .remap = 0, .irq = { - .handler = TIM2_IRQHandler, .init = { .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, .NVIC_IRQChannelSubPriority = 0, @@ -592,7 +794,7 @@ void PIOS_I2C_main_adapter_er_irq_handler(void); void I2C2_EV_IRQHandler() __attribute__ ((alias ("PIOS_I2C_main_adapter_ev_irq_handler"))); void I2C2_ER_IRQHandler() __attribute__ ((alias ("PIOS_I2C_main_adapter_er_irq_handler"))); -const struct pios_i2c_adapter_cfg pios_i2c_main_adapter_cfg = { +static const struct pios_i2c_adapter_cfg pios_i2c_main_adapter_cfg = { .regs = I2C2, .init = { .I2C_Mode = I2C_Mode_I2C, @@ -620,7 +822,6 @@ const struct pios_i2c_adapter_cfg pios_i2c_main_adapter_cfg = { }, }, .event = { - .handler = PIOS_I2C_main_adapter_ev_irq_handler, .flags = 0, /* FIXME: check this */ .init = { .NVIC_IRQChannel = I2C2_EV_IRQn, @@ -630,7 +831,6 @@ const struct pios_i2c_adapter_cfg pios_i2c_main_adapter_cfg = { }, }, .error = { - .handler = PIOS_I2C_main_adapter_er_irq_handler, .flags = 0, /* FIXME: check this */ .init = { .NVIC_IRQChannel = I2C2_ER_IRQn, @@ -656,12 +856,33 @@ void PIOS_I2C_main_adapter_er_irq_handler(void) #endif /* PIOS_INCLUDE_I2C */ +#if defined(PIOS_INCLUDE_RCVR) +#include "pios_rcvr_priv.h" + +struct pios_rcvr_channel_map pios_rcvr_channel_to_id_map[PIOS_RCVR_MAX_CHANNELS]; +uint32_t pios_rcvr_max_channel; +#endif /* PIOS_INCLUDE_RCVR */ + +#if defined(PIOS_INCLUDE_USB_HID) +#include "pios_usb_hid_priv.h" + +static const struct pios_usb_hid_cfg pios_usb_hid_main_cfg = { + .irq = { + .init = { + .NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; +#endif /* PIOS_INCLUDE_USB_HID */ + extern const struct pios_com_driver pios_usb_com_driver; uint32_t pios_com_telem_rf_id; uint32_t pios_com_telem_usb_id; uint32_t pios_com_gps_id; -uint32_t pios_com_spektrum_id; /** * PIOS_Board_Init() @@ -671,31 +892,29 @@ uint32_t pios_com_spektrum_id; void PIOS_Board_Init(void) { /* Delay system */ - PIOS_DELAY_Init(); - + PIOS_DELAY_Init(); + /* Set up the SPI interface to the serial flash */ if (PIOS_SPI_Init(&pios_spi_flash_accel_id, &pios_spi_flash_accel_cfg)) { - PIOS_DEBUG_Assert(0); + PIOS_Assert(0); } - PIOS_Flash_W25X_Init(pios_spi_flash_accel_id); + PIOS_Flash_W25X_Init(pios_spi_flash_accel_id); PIOS_ADXL345_Attach(pios_spi_flash_accel_id); -#if defined(PIOS_INCLUDE_SPEKTRUM) - /* SPEKTRUM init must come before comms */ - PIOS_SPEKTRUM_Init(); + PIOS_FLASHFS_Init(); - if (PIOS_USART_Init(&pios_usart_spektrum_id, &pios_usart_spektrum_cfg)) { - PIOS_DEBUG_Assert(0); - } - if (PIOS_COM_Init(&pios_com_spektrum_id, &pios_usart_com_driver, pios_usart_spektrum_id)) { - PIOS_DEBUG_Assert(0); - } -#endif /* Initialize UAVObject libraries */ EventDispatcherInitialize(); UAVObjInitialize(); - UAVObjectsInitializeAll(); + + HwSettingsInitialize(); + ManualControlSettingsInitialize(); + +#if defined(PIOS_INCLUDE_RTC) + /* Initialize the real-time clock and its associated tick */ + PIOS_RTC_Init(&pios_rtc_main_cfg); +#endif /* Initialize the alarms library */ AlarmsInitialize(); @@ -703,23 +922,229 @@ void PIOS_Board_Init(void) { /* Initialize the task monitor library */ TaskMonitorInitialize(); - /* Initialize the PiOS library */ -#if defined(PIOS_INCLUDE_COM) - if (PIOS_USART_Init(&pios_usart_telem_rf_id, &pios_usart_telem_cfg)) { - PIOS_DEBUG_Assert(0); - } - if (PIOS_COM_Init(&pios_com_telem_rf_id, &pios_usart_com_driver, pios_usart_telem_rf_id)) { - PIOS_DEBUG_Assert(0); - } + /* Configure the main IO port */ + uint8_t hwsettings_cc_mainport; + HwSettingsCC_MainPortGet(&hwsettings_cc_mainport); + + switch (hwsettings_cc_mainport) { + case HWSETTINGS_CC_MAINPORT_DISABLED: + break; + case HWSETTINGS_CC_MAINPORT_TELEMETRY: +#if defined(PIOS_INCLUDE_TELEMETRY_RF) + { + uint32_t pios_usart_telem_rf_id; + if (PIOS_USART_Init(&pios_usart_telem_rf_id, &pios_usart_telem_main_cfg)) { + PIOS_Assert(0); + } + + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_RX_BUF_LEN); + uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_TX_BUF_LEN); + PIOS_Assert(rx_buffer); + PIOS_Assert(tx_buffer); + if (PIOS_COM_Init(&pios_com_telem_rf_id, &pios_usart_com_driver, pios_usart_telem_rf_id, + rx_buffer, PIOS_COM_TELEM_RF_RX_BUF_LEN, + tx_buffer, PIOS_COM_TELEM_RF_TX_BUF_LEN)) { + PIOS_Assert(0); + } + } +#endif /* PIOS_INCLUDE_TELEMETRY_RF */ + break; + case HWSETTINGS_CC_MAINPORT_SBUS: +#if defined(PIOS_INCLUDE_SBUS) + { + uint32_t pios_usart_sbus_id; + if (PIOS_USART_Init(&pios_usart_sbus_id, &pios_usart_sbus_main_cfg)) { + PIOS_Assert(0); + } + + uint32_t pios_sbus_id; + if (PIOS_SBUS_Init(&pios_sbus_id, &pios_sbus_cfg, &pios_usart_com_driver, pios_usart_sbus_id)) { + PIOS_Assert(0); + } + } +#endif /* PIOS_INCLUDE_SBUS */ + break; + case HWSETTINGS_CC_MAINPORT_GPS: #if defined(PIOS_INCLUDE_GPS) - if (PIOS_USART_Init(&pios_usart_gps_id, &pios_usart_gps_cfg)) { - PIOS_DEBUG_Assert(0); - } - if (PIOS_COM_Init(&pios_com_gps_id, &pios_usart_com_driver, pios_usart_gps_id)) { - PIOS_DEBUG_Assert(0); - } + { + uint32_t pios_usart_gps_id; + if (PIOS_USART_Init(&pios_usart_gps_id, &pios_usart_gps_main_cfg)) { + PIOS_Assert(0); + } + + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_GPS_RX_BUF_LEN); + PIOS_Assert(rx_buffer); + if (PIOS_COM_Init(&pios_com_gps_id, &pios_usart_com_driver, pios_usart_gps_id, + rx_buffer, PIOS_COM_GPS_RX_BUF_LEN, + NULL, 0)) { + PIOS_Assert(0); + } + } #endif /* PIOS_INCLUDE_GPS */ -#endif /* PIOS_INCLUDE_COM */ + break; + case HWSETTINGS_CC_MAINPORT_SPEKTRUM: +#if defined(PIOS_INCLUDE_SPEKTRUM) + { + uint32_t pios_usart_spektrum_id; + if (PIOS_USART_Init(&pios_usart_spektrum_id, &pios_usart_spektrum_main_cfg)) { + PIOS_Assert(0); + } + + uint32_t pios_spektrum_id; + if (PIOS_SPEKTRUM_Init(&pios_spektrum_id, &pios_spektrum_main_cfg, &pios_usart_com_driver, pios_usart_spektrum_id, false)) { + PIOS_Assert(0); + } + } +#endif /* PIOS_INCLUDE_SPEKTRUM */ + break; + case HWSETTINGS_CC_MAINPORT_COMAUX: + break; + } + + /* Configure the flexi port */ + uint8_t hwsettings_cc_flexiport; + HwSettingsCC_FlexiPortGet(&hwsettings_cc_flexiport); + + switch (hwsettings_cc_flexiport) { + case HWSETTINGS_CC_FLEXIPORT_DISABLED: + break; + case HWSETTINGS_CC_FLEXIPORT_TELEMETRY: +#if defined(PIOS_INCLUDE_TELEMETRY_RF) + { + uint32_t pios_usart_telem_rf_id; + if (PIOS_USART_Init(&pios_usart_telem_rf_id, &pios_usart_telem_flexi_cfg)) { + PIOS_Assert(0); + } + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_RX_BUF_LEN); + uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_TX_BUF_LEN); + PIOS_Assert(rx_buffer); + PIOS_Assert(tx_buffer); + if (PIOS_COM_Init(&pios_com_telem_rf_id, &pios_usart_com_driver, pios_usart_telem_rf_id, + rx_buffer, PIOS_COM_TELEM_RF_RX_BUF_LEN, + tx_buffer, PIOS_COM_TELEM_RF_TX_BUF_LEN)) { + PIOS_Assert(0); + } + } +#endif /* PIOS_INCLUDE_TELEMETRY_RF */ + break; + case HWSETTINGS_CC_FLEXIPORT_GPS: +#if defined(PIOS_INCLUDE_GPS) + { + uint32_t pios_usart_gps_id; + if (PIOS_USART_Init(&pios_usart_gps_id, &pios_usart_gps_flexi_cfg)) { + PIOS_Assert(0); + } + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_GPS_RX_BUF_LEN); + PIOS_Assert(rx_buffer); + if (PIOS_COM_Init(&pios_com_gps_id, &pios_usart_com_driver, pios_usart_gps_id, + rx_buffer, PIOS_COM_GPS_RX_BUF_LEN, + NULL, 0)) { + PIOS_Assert(0); + } + } +#endif /* PIOS_INCLUDE_GPS */ + break; + case HWSETTINGS_CC_FLEXIPORT_SPEKTRUM: +#if defined(PIOS_INCLUDE_SPEKTRUM) + { + uint32_t pios_usart_spektrum_id; + if (PIOS_USART_Init(&pios_usart_spektrum_id, &pios_usart_spektrum_flexi_cfg)) { + PIOS_Assert(0); + } + + uint32_t pios_spektrum_id; + if (PIOS_SPEKTRUM_Init(&pios_spektrum_id, &pios_spektrum_flexi_cfg, &pios_usart_com_driver, pios_usart_spektrum_id, false)) { + PIOS_Assert(0); + } + } +#endif /* PIOS_INCLUDE_SPEKTRUM */ + break; + case HWSETTINGS_CC_FLEXIPORT_COMAUX: + break; + case HWSETTINGS_CC_FLEXIPORT_I2C: +#if defined(PIOS_INCLUDE_I2C) + { + if (PIOS_I2C_Init(&pios_i2c_main_adapter_id, &pios_i2c_main_adapter_cfg)) { + PIOS_Assert(0); + } + } +#endif /* PIOS_INCLUDE_I2C */ + break; + } + + /* Configure the selected receiver */ + uint8_t manualcontrolsettings_inputmode; + ManualControlSettingsInputModeGet(&manualcontrolsettings_inputmode); + + switch (manualcontrolsettings_inputmode) { + case MANUALCONTROLSETTINGS_INPUTMODE_PWM: +#if defined(PIOS_INCLUDE_PWM) + PIOS_PWM_Init(); + uint32_t pios_pwm_rcvr_id; + if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, 0)) { + PIOS_Assert(0); + } + for (uint8_t i = 0; + i < PIOS_PWM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); + i++) { + pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_pwm_rcvr_id; + pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; + pios_rcvr_max_channel++; + } +#endif /* PIOS_INCLUDE_PWM */ + break; + case MANUALCONTROLSETTINGS_INPUTMODE_PPM: +#if defined(PIOS_INCLUDE_PPM) + PIOS_PPM_Init(); + uint32_t pios_ppm_rcvr_id; + if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, 0)) { + PIOS_Assert(0); + } + for (uint8_t i = 0; + i < PIOS_PPM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); + i++) { + pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_ppm_rcvr_id; + pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; + pios_rcvr_max_channel++; + } +#endif /* PIOS_INCLUDE_PPM */ + break; + case MANUALCONTROLSETTINGS_INPUTMODE_SPEKTRUM: +#if defined(PIOS_INCLUDE_SPEKTRUM) + if (hwsettings_cc_mainport == HWSETTINGS_CC_MAINPORT_SPEKTRUM || + hwsettings_cc_flexiport == HWSETTINGS_CC_FLEXIPORT_SPEKTRUM) { + uint32_t pios_spektrum_rcvr_id; + if (PIOS_RCVR_Init(&pios_spektrum_rcvr_id, &pios_spektrum_rcvr_driver, 0)) { + PIOS_Assert(0); + } + for (uint8_t i = 0; + i < PIOS_SPEKTRUM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); + i++) { + pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_spektrum_rcvr_id; + pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; + pios_rcvr_max_channel++; + } + } +#endif /* PIOS_INCLUDE_SPEKTRUM */ + break; + case MANUALCONTROLSETTINGS_INPUTMODE_SBUS: +#if defined(PIOS_INCLUDE_SBUS) + if (hwsettings_cc_mainport == HWSETTINGS_CC_MAINPORT_SBUS) { + uint32_t pios_sbus_rcvr_id; + if (PIOS_RCVR_Init(&pios_sbus_rcvr_id, &pios_sbus_rcvr_driver, 0)) { + PIOS_Assert(0); + } + for (uint8_t i = 0; + i < SBUS_NUMBER_OF_CHANNELS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); + i++) { + pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_sbus_rcvr_id; + pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; + pios_rcvr_max_channel++; + } + } +#endif /* PIOS_INCLUDE_SBUS */ + break; + } /* Remap AFIO pin */ GPIO_PinRemapConfig( GPIO_Remap_SWJ_NoJTRST, ENABLE); @@ -728,26 +1153,22 @@ void PIOS_Board_Init(void) { PIOS_ADC_Init(); PIOS_GPIO_Init(); -#if defined(PIOS_INCLUDE_PWM) - PIOS_PWM_Init(); -#endif -#if defined(PIOS_INCLUDE_PPM) - PIOS_PPM_Init(); -#endif #if defined(PIOS_INCLUDE_USB_HID) - PIOS_USB_HID_Init(0); + uint32_t pios_usb_hid_id; + PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_main_cfg); #if defined(PIOS_INCLUDE_COM) - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_com_driver, 0)) { - PIOS_DEBUG_Assert(0); + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); + uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); + PIOS_Assert(rx_buffer); + PIOS_Assert(tx_buffer); + if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_com_driver, pios_usb_hid_id, + rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, + tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { + PIOS_Assert(0); } #endif /* PIOS_INCLUDE_COM */ -#endif +#endif /* PIOS_INCLUDE_USB_HID */ -#if defined(PIOS_INCLUDE_I2C) - if (PIOS_I2C_Init(&pios_i2c_main_adapter_id, &pios_i2c_main_adapter_cfg)) { - PIOS_DEBUG_Assert(0); - } -#endif /* PIOS_INCLUDE_I2C */ PIOS_IAP_Init(); PIOS_WDG_Init(); } diff --git a/flight/CopterControl/System/pios_board_posix.c b/flight/CopterControl/System/pios_board_posix.c index 87d8e7402..30f949830 100644 --- a/flight/CopterControl/System/pios_board_posix.c +++ b/flight/CopterControl/System/pios_board_posix.c @@ -42,7 +42,6 @@ void PIOS_Board_Init(void) { /* Initialize UAVObject libraries */ EventDispatcherInitialize(); UAVObjInitialize(); - UAVObjectsInitializeAll(); /* Initialize the alarms library */ AlarmsInitialize(); diff --git a/flight/CopterControl/System/taskmonitor.c b/flight/CopterControl/System/taskmonitor.c index e13b20515..6ff6299d0 100644 --- a/flight/CopterControl/System/taskmonitor.c +++ b/flight/CopterControl/System/taskmonitor.c @@ -35,21 +35,26 @@ // Private variables static xSemaphoreHandle lock; static xTaskHandle handles[TASKINFO_RUNNING_NUMELEM]; +static uint32_t lastMonitorTime; // Private functions /** - * Initialize library + * Initialize library */ int32_t TaskMonitorInitialize(void) { lock = xSemaphoreCreateRecursiveMutex(); memset(handles, 0, sizeof(xTaskHandle)*TASKINFO_RUNNING_NUMELEM); + lastMonitorTime = 0; +#if defined(DIAGNOSTICS) + lastMonitorTime = portGET_RUN_TIME_COUNTER_VALUE(); +#endif return 0; } /** - * Register a task handle with the library + * Register a task handle with the library */ int32_t TaskMonitorAdd(TaskInfoRunningElem task, xTaskHandle handle) { @@ -67,16 +72,31 @@ int32_t TaskMonitorAdd(TaskInfoRunningElem task, xTaskHandle handle) } /** - * Update the status of all tasks + * Update the status of all tasks */ void TaskMonitorUpdateAll(void) { +#if defined(DIAGNOSTICS) TaskInfoData data; int n; - + // Lock xSemaphoreTakeRecursive(lock, portMAX_DELAY); - + +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + uint32_t currentTime; + uint32_t deltaTime; + + /* + * Calculate the amount of elapsed run time between the last time we + * measured and now. Scale so that we can convert task run times + * directly to percentages. + */ + currentTime = portGET_RUN_TIME_COUNTER_VALUE(); + deltaTime = ((currentTime - lastMonitorTime) / 100) ? : 1; /* avoid divide-by-zero if the interval is too small */ + lastMonitorTime = currentTime; +#endif + // Update all task information for (n = 0; n < TASKINFO_RUNNING_NUMELEM; ++n) { @@ -87,18 +107,25 @@ void TaskMonitorUpdateAll(void) data.StackRemaining[n] = 10000; #else data.StackRemaining[n] = uxTaskGetStackHighWaterMark(handles[n]) * 4; +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + /* Generate run time stats */ + data.RunningTime[n] = uxTaskGetRunTime(handles[n]) / deltaTime; #endif +#endif + } else { data.Running[n] = TASKINFO_RUNNING_FALSE; data.StackRemaining[n] = 0; + data.RunningTime[n] = 0; } } - + // Update object TaskInfoSet(&data); - + // Done xSemaphoreGiveRecursive(lock); +#endif } diff --git a/flight/INS/Makefile b/flight/INS/Makefile index 8e0423a45..bd3bb52a9 100644 --- a/flight/INS/Makefile +++ b/flight/INS/Makefile @@ -25,11 +25,17 @@ WHEREAMI := $(dir $(lastword $(MAKEFILE_LIST))) TOP := $(realpath $(WHEREAMI)/../../) include $(TOP)/make/firmware-defs.mk +include $(TOP)/make/boards/$(BOARD_NAME)/board-info.mk + +# Target file name (without extension). +TARGET := fw_$(BOARD_NAME) + +# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) +OUTDIR := $(TOP)/build/$(TARGET) # Set developer code and compile options # Set to YES for debugging DEBUG ?= YES -USE_BOOTLOADER ?= NO # Set to YES when using Code Sourcery toolchain CODE_SOURCERY ?= YES @@ -42,26 +48,6 @@ endif FLASH_TOOL = OPENOCD -# MCU name, submodel and board -# - MCU used for compiler-option (-mcpu) -# - MODEL used for linker-script name (-T) and passed as define -# - BOARD just passed as define (optional) -MCU = cortex-m3 -CHIP = STM32F103RET -BOARD = STM3210E_INS -MODEL = HD -ifeq ($(USE_BOOTLOADER), YES) -BOOT_MODEL = $(MODEL)_BL -else -BOOT_MODEL = $(MODEL)_NB -endif - -# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) -OUTDIR = $(TOP)/build/ins - -# Target file name (without extension). -TARGET = INS - # Paths INS = ./ INSINC = $(INS)/inc @@ -168,7 +154,7 @@ CPPSRCARM = # Even though the DOS/Win* filesystem matches both .s and .S the same, # it will preserve the spelling of the filenames, and gcc itself does # care about how the name is spelled on its command-line. -ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL).S +ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL)$(MODEL_SUFFIX).S # List Assembler source files here which must be assembled in ARM-Mode.. ASRCARM = @@ -231,9 +217,7 @@ CDEFS = -DSTM32F10X_$(MODEL) CDEFS += -DUSE_STDPERIPH_DRIVER CDEFS += -DUSE_$(BOARD) CDEFS += -DIN_INS -ifeq ($(USE_BOOTLOADER), YES) -CDEFS += -DUSE_BOOTLOADER -endif + # Place project-specific -D and/or -U options for # Assembler with preprocessor here. #ADEFS = -DUSE_IRQ_ASM_WRAPPER @@ -311,22 +295,11 @@ LDFLAGS += $(MATH_LIB) LDFLAGS += -lc -lgcc # Set linker-script name depending on selected submodel name -LDFLAGS +=-T$(LINKERSCRIPTPATH)/link_$(BOARD)_$(BOOT_MODEL).ld - -OOCD_LOADFILE+=$(OUTDIR)/$(TARGET).elf -# Program -OOCD_CL+=-c "flash write_image $(OOCD_LOADFILE)" -# Verify -OOCD_CL+=-c "verify_image $(OOCD_LOADFILE)" -# reset target -OOCD_CL+=-c "reset run" -# # terminate OOCD after programming -OOCD_CL+=-c shutdown +LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_memory.ld +LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_sections.ld # Define programs and commands. REMOVE = $(REMOVE_CMD) -f -###SHELL = sh -###COPY = cp # List of all source files. ALLSRC = $(ASRCARM) $(ASRC) $(SRCARM) $(SRC) $(CPPSRCARM) $(CPPSRC) @@ -358,21 +331,6 @@ endif endif endif -# Program the device. -ifeq ($(USE_BOOTLOADER), YES) -# Program the device with OP Upload Tool". -program: $(OUTDIR)/$(TARGET).bin - @echo ${quote}Programming with OP Upload Tool${quote} - ../../ground/src/experimental/upload-build-desktop/debug/OPUploadTool -d 1 -p $(OUTDIR)/$(TARGET).bin -else -ifeq ($(FLASH_TOOL),OPENOCD) -# Program the device with Dominic Rath's OPENOCD in "batch-mode", needs cfg and "reset-script". -program: $(OUTDIR)/$(TARGET).elf - @echo ${quote}Programming with OPENOCD${quote} - $(OOCD_EXE) $(OOCD_CL) -endif -endif - # Link: create ELF output file from object files. $(eval $(call LINK_TEMPLATE, $(OUTDIR)/$(TARGET).elf, $(ALLOBJ))) @@ -400,22 +358,39 @@ $(eval $(call PARTIAL_COMPILE_TEMPLATE, SRC)) # Compile: create assembler files from C source files. ARM only $(eval $(call PARTIAL_COMPILE_ARM_TEMPLATE, SRCARM)) -.PHONY: elf lss sym hex bin +$(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin + +$(eval $(call OPFW_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BOARD_TYPE),$(BOARD_REVISION))) + +# Add jtag targets (program and wipe) +$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE))) + +.PHONY: elf lss sym hex bin bino opfw elf: $(OUTDIR)/$(TARGET).elf lss: $(OUTDIR)/$(TARGET).lss sym: $(OUTDIR)/$(TARGET).sym hex: $(OUTDIR)/$(TARGET).hex bin: $(OUTDIR)/$(TARGET).bin +bino: $(OUTDIR)/$(TARGET).bin.o +opfw: $(OUTDIR)/$(TARGET).opfw # Display sizes of sections. $(eval $(call SIZE_TEMPLATE, $(OUTDIR)/$(TARGET).elf)) -.PHONY: size -size: $(OUTDIR)/$(TARGET).elf_size # Generate Doxygen documents docs: doxygen $(DOXYGENDIR)/doxygen.cfg +# Install: install binary file with prefix/suffix into install directory +install: $(OUTDIR)/$(TARGET).opfw +ifneq ($(INSTALL_DIR),) + @echo $(MSG_INSTALLING) $(call toprel, $<) + $(V1) mkdir -p $(INSTALL_DIR) + $(V1) $(INSTALL) $< $(INSTALL_DIR)/$(INSTALL_PFX)$(TARGET)$(INSTALL_SFX).opfw +else + $(error INSTALL_DIR must be specified for $@) +endif + # Target: clean project. clean: clean_list @@ -450,6 +425,5 @@ else -include $(shell mkdir $(OUTDIR) 2>/dev/null) $(shell mkdir $(OUTDIR)/dep 2>/dev/null) $(wildcard $(OUTDIR)/dep/*) endif - # Listing of phony targets. -.PHONY : all build clean clean_list program +.PHONY : all build clean clean_list install diff --git a/flight/INS/pios_board.c b/flight/INS/pios_board.c index 524416cb1..ffbf27c45 100644 --- a/flight/INS/pios_board.c +++ b/flight/INS/pios_board.c @@ -61,7 +61,6 @@ static const struct pios_spi_cfg pios_spi_op_mag_cfg = { .ahb_clk = RCC_AHBPeriph_DMA1, .irq = { - .handler = PIOS_SPI_op_mag_irq_handler, .flags = (DMA1_FLAG_TC4 | DMA1_FLAG_TE4 | DMA1_FLAG_HT4 | DMA1_FLAG_GL4), @@ -175,7 +174,6 @@ static const struct pios_spi_cfg pios_spi_accel_cfg = { .ahb_clk = RCC_AHBPeriph_DMA1, .irq = { - .handler = PIOS_SPI_accel_irq_handler, .flags = (DMA1_FLAG_TC2 | DMA1_FLAG_TE2 | DMA1_FLAG_HT2 | DMA1_FLAG_GL2), .init = { .NVIC_IRQChannel = DMA1_Channel2_IRQn, @@ -265,17 +263,10 @@ void PIOS_SPI_accel_irq_handler(void) /* * GPS USART */ -void PIOS_USART_gps_irq_handler(void); -void USART1_IRQHandler() - __attribute__ ((alias("PIOS_USART_gps_irq_handler"))); -const struct pios_usart_cfg pios_usart_gps_cfg = { +static const struct pios_usart_cfg pios_usart_gps_cfg = { .regs = USART1, .init = { -#if defined (PIOS_USART_BAUDRATE) - .USART_BaudRate = PIOS_USART_BAUDRATE, -#else .USART_BaudRate = 57600, -#endif .USART_WordLength = USART_WordLength_8b, .USART_Parity = USART_Parity_No, .USART_StopBits = USART_StopBits_1, @@ -284,7 +275,6 @@ const struct pios_usart_cfg pios_usart_gps_cfg = { .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, }, .irq = { - .handler = PIOS_USART_gps_irq_handler, .init = { .NVIC_IRQChannel = USART1_IRQn, .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, @@ -310,29 +300,16 @@ const struct pios_usart_cfg pios_usart_gps_cfg = { }, }; -static uint32_t pios_usart_gps_id; -void PIOS_USART_gps_irq_handler(void) -{ - PIOS_USART_IRQ_Handler(pios_usart_gps_id); -} - #endif /* PIOS_INCLUDE_GPS */ #ifdef PIOS_COM_AUX /* * AUX USART */ -void PIOS_USART_aux_irq_handler(void); -void USART4_IRQHandler() - __attribute__ ((alias("PIOS_USART_aux_irq_handler"))); -const struct pios_usart_cfg pios_usart_aux_cfg = { +static const struct pios_usart_cfg pios_usart_aux_cfg = { .regs = USART4, .init = { -#if defined (PIOS_USART_BAUDRATE) - .USART_BaudRate = PIOS_USART_BAUDRATE, -#else .USART_BaudRate = 57600, -#endif .USART_WordLength = USART_WordLength_8b, .USART_Parity = USART_Parity_No, .USART_StopBits = USART_StopBits_1, @@ -341,7 +318,6 @@ const struct pios_usart_cfg pios_usart_aux_cfg = { .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, }, .irq = { - .handler = PIOS_USART_aux_irq_handler, .init = { .NVIC_IRQChannel = USART4_IRQn, .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, @@ -367,15 +343,24 @@ const struct pios_usart_cfg pios_usart_aux_cfg = { }, }; -static uint32_t pios_usart_aux_id; -void PIOS_USART_aux_irq_handler(void) -{ - PIOS_USART_IRQ_Handler(pios_usart_aux_id); -} - #endif /* PIOS_COM_AUX */ +#if defined(PIOS_INCLUDE_COM) + +#include + +#if 0 +#define PIOS_COM_AUX_TX_BUF_LEN 192 +static uint8_t pios_com_aux_tx_buffer[PIOS_COM_AUX_TX_BUF_LEN]; +#endif + +#define PIOS_COM_GPS_RX_BUF_LEN 96 +static uint8_t pios_com_gps_rx_buffer[PIOS_COM_GPS_RX_BUF_LEN]; + + +#endif /* PIOS_INCLUDE_COM */ + #if defined(PIOS_INCLUDE_I2C) #include @@ -391,7 +376,7 @@ void I2C1_EV_IRQHandler() void I2C1_ER_IRQHandler() __attribute__ ((alias("PIOS_I2C_pres_mag_adapter_er_irq_handler"))); -const struct pios_i2c_adapter_cfg pios_i2c_pres_mag_adapter_cfg = { +static const struct pios_i2c_adapter_cfg pios_i2c_pres_mag_adapter_cfg = { .regs = I2C1, .init = { .I2C_Mode = I2C_Mode_I2C, @@ -419,7 +404,6 @@ const struct pios_i2c_adapter_cfg pios_i2c_pres_mag_adapter_cfg = { }, }, .event = { - .handler = PIOS_I2C_pres_mag_adapter_ev_irq_handler, .flags = 0, /* FIXME: check this */ .init = { .NVIC_IRQChannel = I2C1_EV_IRQn, @@ -429,7 +413,6 @@ const struct pios_i2c_adapter_cfg pios_i2c_pres_mag_adapter_cfg = { }, }, .error = { - .handler = PIOS_I2C_pres_mag_adapter_er_irq_handler, .flags = 0, /* FIXME: check this */ .init = { .NVIC_IRQChannel = I2C1_ER_IRQn, @@ -459,7 +442,7 @@ void PIOS_I2C_gyro_adapter_er_irq_handler(void); void I2C2_EV_IRQHandler() __attribute__ ((alias ("PIOS_I2C_gyro_adapter_ev_irq_handler"))); void I2C2_ER_IRQHandler() __attribute__ ((alias ("PIOS_I2C_gyro_adapter_er_irq_handler"))); -const struct pios_i2c_adapter_cfg pios_i2c_gyro_adapter_cfg = { +static const struct pios_i2c_adapter_cfg pios_i2c_gyro_adapter_cfg = { .regs = I2C2, .init = { .I2C_Mode = I2C_Mode_I2C, @@ -487,7 +470,6 @@ const struct pios_i2c_adapter_cfg pios_i2c_gyro_adapter_cfg = { }, }, .event = { - .handler = PIOS_I2C_gyro_adapter_ev_irq_handler, .flags = 0, /* FIXME: check this */ .init = { .NVIC_IRQChannel = I2C2_EV_IRQn, @@ -497,7 +479,6 @@ const struct pios_i2c_adapter_cfg pios_i2c_gyro_adapter_cfg = { }, }, .error = { - .handler = PIOS_I2C_gyro_adapter_er_irq_handler, .flags = 0, /* FIXME: check this */ .init = { .NVIC_IRQChannel = I2C2_ER_IRQn, @@ -547,10 +528,13 @@ void PIOS_Board_Init(void) { #if defined(PIOS_INCLUDE_COM) #if defined(PIOS_INCLUDE_GPS) + uint32_t pios_usart_gps_id; if (PIOS_USART_Init(&pios_usart_gps_id, &pios_usart_gps_cfg)) { PIOS_DEBUG_Assert(0); } - if (PIOS_COM_Init(&pios_com_gps_id, &pios_usart_com_driver, pios_usart_gps_id)) { + if (PIOS_COM_Init(&pios_com_gps_id, &pios_usart_com_driver, pios_usart_gps_id, + pios_com_gps_rx_buffer, sizeof(pios_com_gps_rx_buffer), + NULL, 0)) { PIOS_DEBUG_Assert(0); } #endif /* PIOS_INCLUDE_GPS */ diff --git a/flight/Libraries/ahrs_comm_objects.c b/flight/Libraries/ahrs_comm_objects.c index e43c380e4..5fc4f1b20 100644 --- a/flight/Libraries/ahrs_comm_objects.c +++ b/flight/Libraries/ahrs_comm_objects.c @@ -79,6 +79,7 @@ CREATEHANDLE(10, FirmwareIAPObj); static void ObjectUpdatedCb(UAVObjEvent * ev); #define ADDHANDLE(idx,obj) {\ + obj##Initialize();\ int n = idx;\ objectHandles[n].data = &obj;\ objectHandles[n].uavHandle = obj##Handle();\ diff --git a/flight/Libraries/inc/fifo_buffer.h b/flight/Libraries/inc/fifo_buffer.h index 9058d64c6..6e4955f7e 100644 --- a/flight/Libraries/inc/fifo_buffer.h +++ b/flight/Libraries/inc/fifo_buffer.h @@ -26,7 +26,7 @@ #ifndef _FIFO_BUFFER_H_ #define _FIFO_BUFFER_H_ -#include "stm32f10x.h" +#include // ********************* diff --git a/flight/Modules/AHRSComms/ahrs_comms.c b/flight/Modules/AHRSComms/ahrs_comms.c index 76abb1a40..c3fb45fae 100644 --- a/flight/Modules/AHRSComms/ahrs_comms.c +++ b/flight/Modules/AHRSComms/ahrs_comms.c @@ -52,6 +52,8 @@ #include "ahrs_comms.h" #include "ahrs_spi_comm.h" +#include "ahrsstatus.h" +#include "ahrscalibration.h" // Private constants #define STACK_SIZE configMINIMAL_STACK_SIZE-128 @@ -69,9 +71,9 @@ static void ahrscommsTask(void *parameters); * Initialise the module, called on startup * \returns 0 on success or -1 if initialisation failed */ -int32_t AHRSCommsInitialize(void) +int32_t AHRSCommsStart(void) { - // Start main task + // Start main task xTaskCreate(ahrscommsTask, (signed char *)"AHRSComms", STACK_SIZE, NULL, TASK_PRIORITY, &taskHandle); TaskMonitorAdd(TASKINFO_RUNNING_AHRSCOMMS, taskHandle); PIOS_WDG_RegisterFlag(PIOS_WDG_AHRS); @@ -79,6 +81,22 @@ int32_t AHRSCommsInitialize(void) return 0; } +/** + * Initialise the module, called on startup + * \returns 0 on success or -1 if initialisation failed + */ +int32_t AHRSCommsInitialize(void) +{ + AhrsStatusInitialize(); + AHRSCalibrationInitialize(); + AttitudeRawInitialize(); + VelocityActualInitialize(); + PositionActualInitialize(); + + return 0; +} +MODULE_INITCALL(AHRSCommsInitialize, AHRSCommsStart) + /** * Module thread, should not return. */ diff --git a/flight/Modules/Actuator/actuator.c b/flight/Modules/Actuator/actuator.c index b2f143adf..6b353d20f 100644 --- a/flight/Modules/Actuator/actuator.c +++ b/flight/Modules/Actuator/actuator.c @@ -32,6 +32,7 @@ #include "openpilot.h" +#include "accessorydesired.h" #include "actuator.h" #include "actuatorsettings.h" #include "systemsettings.h" @@ -40,6 +41,7 @@ #include "flightstatus.h" #include "mixersettings.h" #include "mixerstatus.h" +#include "cameradesired.h" // Private constants @@ -74,7 +76,6 @@ static int16_t scaleChannel(float value, int16_t max, int16_t min, int16_t neutr static void setFailsafe(); static float MixerCurve(const float throttle, const float* curve); static bool set_channel(uint8_t mixer_channel, uint16_t value); - float ProcessMixer(const int index, const float curve1, const float curve2, MixerSettingsData* mixerSettings, ActuatorDesiredData* desired, const float period); @@ -85,6 +86,19 @@ typedef struct { int8_t matrix[5]; } __attribute__((packed)) Mixer_t; +/** + * @brief Module initialization + * @return 0 + */ +int32_t ActuatorStart() +{ + // Start main task + xTaskCreate(actuatorTask, (signed char*)"Actuator", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &taskHandle); + TaskMonitorAdd(TASKINFO_RUNNING_ACTUATOR, taskHandle); + PIOS_WDG_RegisterFlag(PIOS_WDG_ACTUATOR); + + return 0; +} /** * @brief Module initialization @@ -95,19 +109,23 @@ int32_t ActuatorInitialize() // Create object queue queue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(UAVObjEvent)); + ActuatorSettingsInitialize(); + ActuatorDesiredInitialize(); + MixerSettingsInitialize(); + ActuatorCommandInitialize(); +#if defined(DIAGNOSTICS) + MixerStatusInitialize(); +#endif + // Listen for ExampleObject1 updates ActuatorDesiredConnectQueue(queue); - + // If settings change, update the output rate ActuatorSettingsConnectCallback(actuator_update_rate); - - // Start main task - xTaskCreate(actuatorTask, (signed char*)"Actuator", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &taskHandle); - TaskMonitorAdd(TASKINFO_RUNNING_ACTUATOR, taskHandle); - PIOS_WDG_RegisterFlag(PIOS_WDG_ACTUATOR); - + return 0; } +MODULE_INITCALL(ActuatorInitialize, ActuatorStart) /** * @brief Main Actuator module task @@ -128,17 +146,20 @@ static void actuatorTask(void* parameters) portTickType lastSysTime; portTickType thisSysTime; float dT = 0.0f; - ActuatorCommandData command; - ActuatorSettingsData settings; - SystemSettingsData sysSettings; + ActuatorCommandData command; MixerSettingsData mixerSettings; ActuatorDesiredData desired; MixerStatusData mixerStatus; FlightStatusData flightStatus; - - ActuatorSettingsGet(&settings); - PIOS_Servo_SetHz(&settings.ChannelUpdateFreq[0], ACTUATORSETTINGS_CHANNELUPDATEFREQ_NUMELEM); + + uint8_t MotorsSpinWhileArmed; + int16_t ChannelMax[ACTUATORCOMMAND_CHANNEL_NUMELEM]; + int16_t ChannelMin[ACTUATORCOMMAND_CHANNEL_NUMELEM]; + int16_t ChannelNeutral[ACTUATORCOMMAND_CHANNEL_NUMELEM]; + uint16_t ChannelUpdateFreq[ACTUATORSETTINGS_CHANNELUPDATEFREQ_NUMELEM]; + ActuatorSettingsChannelUpdateFreqGet(ChannelUpdateFreq); + PIOS_Servo_SetHz(&ChannelUpdateFreq[0], ACTUATORSETTINGS_CHANNELUPDATEFREQ_NUMELEM); float * status = (float *)&mixerStatus; //access status objects as an array of floats @@ -148,7 +169,7 @@ static void actuatorTask(void* parameters) // Main task loop lastSysTime = xTaskGetTickCount(); while (1) - { + { PIOS_WDG_UpdateFlag(PIOS_WDG_ACTUATOR); // Wait until the ActuatorDesired object is updated, if a timeout then go to failsafe @@ -164,14 +185,18 @@ static void actuatorTask(void* parameters) dT = (thisSysTime - lastSysTime) / portTICK_RATE_MS / 1000.0f; lastSysTime = thisSysTime; - FlightStatusGet(&flightStatus); - SystemSettingsGet(&sysSettings); - MixerStatusGet(&mixerStatus); MixerSettingsGet (&mixerSettings); ActuatorDesiredGet(&desired); ActuatorCommandGet(&command); - ActuatorSettingsGet(&settings); + +#if defined(DIAGNOSTICS) + MixerStatusGet(&mixerStatus); +#endif + ActuatorSettingsMotorsSpinWhileArmedGet(&MotorsSpinWhileArmed); + ActuatorSettingsChannelMaxGet(ChannelMax); + ActuatorSettingsChannelMinGet(ChannelMin); + ActuatorSettingsChannelNeutralGet(ChannelNeutral); int nMixers = 0; Mixer_t * mixers = (Mixer_t *)&mixerSettings.Mixer1Type; @@ -182,7 +207,7 @@ static void actuatorTask(void* parameters) nMixers ++; } } - if((nMixers < 2) && !ActuatorCommandReadOnly(dummy)) //Nothing can fly with less than two mixers. + if((nMixers < 2) && !ActuatorCommandReadOnly(dummy)) //Nothing can fly with less than two mixers. { setFailsafe(); // So that channels like PWM buzzer keep working continue; @@ -192,10 +217,38 @@ static void actuatorTask(void* parameters) bool armed = flightStatus.Armed == FLIGHTSTATUS_ARMED_ARMED; bool positiveThrottle = desired.Throttle >= 0.00; - bool spinWhileArmed = settings.MotorsSpinWhileArmed == ACTUATORSETTINGS_MOTORSSPINWHILEARMED_TRUE; - + bool spinWhileArmed = MotorsSpinWhileArmed == ACTUATORSETTINGS_MOTORSSPINWHILEARMED_TRUE; + float curve1 = MixerCurve(desired.Throttle,mixerSettings.ThrottleCurve1); - float curve2 = MixerCurve(desired.Throttle,mixerSettings.ThrottleCurve2); + //The source for the secondary curve is selectable + float curve2 = 0; + AccessoryDesiredData accessory; + switch(mixerSettings.Curve2Source) { + case MIXERSETTINGS_CURVE2SOURCE_THROTTLE: + curve2 = MixerCurve(desired.Throttle,mixerSettings.ThrottleCurve2); + break; + case MIXERSETTINGS_CURVE2SOURCE_ROLL: + curve2 = MixerCurve(desired.Roll,mixerSettings.ThrottleCurve2); + break; + case MIXERSETTINGS_CURVE2SOURCE_PITCH: + curve2 = MixerCurve(desired.Pitch,mixerSettings.ThrottleCurve2); + break; + case MIXERSETTINGS_CURVE2SOURCE_YAW: + curve2 = MixerCurve(desired.Yaw,mixerSettings.ThrottleCurve2); + break; + case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY0: + case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY1: + case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY2: + case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY3: + case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY4: + case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY5: + if(AccessoryDesiredInstGet(mixerSettings.Curve2Source - MIXERSETTINGS_CURVE2SOURCE_ACCESSORY0,&accessory) == 0) + curve2 = MixerCurve(accessory.AccessoryVal,mixerSettings.ThrottleCurve2); + else + curve2 = 0; + break; + } + for(int ct=0; ct < MAX_MIX_ACTUATORS; ct++) { if(mixers[ct].type == MIXERSETTINGS_MIXER1TYPE_DISABLED) { @@ -204,38 +257,82 @@ static void actuatorTask(void* parameters) command.Channel[ct] = 0; continue; } - - status[ct] = ProcessMixer(ct, curve1, curve2, &mixerSettings, &desired, dT); - + + if((mixers[ct].type == MIXERSETTINGS_MIXER1TYPE_MOTOR) || (mixers[ct].type == MIXERSETTINGS_MIXER1TYPE_SERVO)) + status[ct] = ProcessMixer(ct, curve1, curve2, &mixerSettings, &desired, dT); + else + status[ct] = -1; + + + // Motors have additional protection for when to be on - if(mixers[ct].type == MIXERSETTINGS_MIXER1TYPE_MOTOR) { + if(mixers[ct].type == MIXERSETTINGS_MIXER1TYPE_MOTOR) { // If not armed or motors aren't meant to spin all the time if( !armed || (!spinWhileArmed && !positiveThrottle)) { filterAccumulator[ct] = 0; - lastResult[ct] = 0; + lastResult[ct] = 0; status[ct] = -1; //force min throttle - } - // If armed meant to keep spinning, + } + // If armed meant to keep spinning, else if ((spinWhileArmed && !positiveThrottle) || (status[ct] < 0) ) - status[ct] = 0; + status[ct] = 0; } - + + // If an accessory channel is selected for direct bypass mode + // In this configuration the accessory channel is scaled and mapped + // directly to output. Note: THERE IS NO SAFETY CHECK HERE FOR ARMING + // these also will not be updated in failsafe mode. I'm not sure what + // the correct behavior is since it seems domain specific. I don't love + // this code + if( (mixers[ct].type >= MIXERSETTINGS_MIXER1TYPE_ACCESSORY0) && + (mixers[ct].type <= MIXERSETTINGS_MIXER1TYPE_ACCESSORY5)) + { + if(AccessoryDesiredInstGet(mixers[ct].type - MIXERSETTINGS_MIXER1TYPE_ACCESSORY0,&accessory) == 0) + status[ct] = accessory.AccessoryVal; + else + status[ct] = -1; + } + if( (mixers[ct].type >= MIXERSETTINGS_MIXER1TYPE_CAMERAROLL) && + (mixers[ct].type <= MIXERSETTINGS_MIXER1TYPE_CAMERAYAW)) + { + CameraDesiredData cameraDesired; + if( CameraDesiredGet(&cameraDesired) == 0 ) { + switch(mixers[ct].type) { + case MIXERSETTINGS_MIXER1TYPE_CAMERAROLL: + status[ct] = cameraDesired.Roll; + break; + case MIXERSETTINGS_MIXER1TYPE_CAMERAPITCH: + status[ct] = cameraDesired.Pitch; + break; + case MIXERSETTINGS_MIXER1TYPE_CAMERAYAW: + status[ct] = cameraDesired.Yaw; + break; + default: + break; + } + } + else + status[ct] = -1; + } + command.Channel[ct] = scaleChannel(status[ct], - settings.ChannelMax[ct], - settings.ChannelMin[ct], - settings.ChannelNeutral[ct]); + ChannelMax[ct], + ChannelMin[ct], + ChannelNeutral[ct]); } +#if defined(DIAGNOSTICS) MixerStatusSet(&mixerStatus); +#endif // Store update time command.UpdateTime = 1000*dT; if(1000*dT > command.MaxUpdateTime) command.MaxUpdateTime = 1000*dT; - + // Update output object ActuatorCommandSet(&command); // Update in case read only (eg. during servo configuration) @@ -243,7 +340,7 @@ static void actuatorTask(void* parameters) // Update servo outputs bool success = true; - + for (int n = 0; n < ACTUATORCOMMAND_CHANNEL_NUMELEM; ++n) { success &= set_channel(n, command.Channel[n]); @@ -252,7 +349,7 @@ static void actuatorTask(void* parameters) if(!success) { command.NumFailedUpdates++; ActuatorCommandSet(&command); - AlarmsSet(SYSTEMALARMS_ALARM_ACTUATOR, SYSTEMALARMS_ALARM_CRITICAL); + AlarmsSet(SYSTEMALARMS_ALARM_ACTUATOR, SYSTEMALARMS_ALARM_CRITICAL); } } @@ -391,11 +488,13 @@ static int16_t scaleChannel(float value, int16_t max, int16_t min, int16_t neutr */ static void setFailsafe() { - ActuatorCommandData command; - ActuatorSettingsData settings; - - ActuatorCommandGet(&command); - ActuatorSettingsGet(&settings); + /* grab only the modules parts that we are going to use */ + int16_t ChannelMin[ACTUATORCOMMAND_CHANNEL_NUMELEM]; + ActuatorSettingsChannelMinGet(ChannelMin); + int16_t ChannelNeutral[ACTUATORCOMMAND_CHANNEL_NUMELEM]; + ActuatorSettingsChannelNeutralGet(ChannelNeutral); + int16_t Channel[ACTUATORCOMMAND_CHANNEL_NUMELEM]; + ActuatorCommandChannelGet(Channel); MixerSettingsData mixerSettings; MixerSettingsGet (&mixerSettings); @@ -404,18 +503,18 @@ static void setFailsafe() // Reset ActuatorCommand to safe values for (int n = 0; n < ACTUATORCOMMAND_CHANNEL_NUMELEM; ++n) { - + if(mixers[n].type == MIXERSETTINGS_MIXER1TYPE_MOTOR) { - command.Channel[n] = settings.ChannelMin[n]; + Channel[n] = ChannelMin[n]; } else if(mixers[n].type == MIXERSETTINGS_MIXER1TYPE_SERVO) { - command.Channel[n] = settings.ChannelNeutral[n]; + Channel[n] = ChannelNeutral[n]; } else { - command.Channel[n] = 0; + Channel[n] = 0; } } @@ -425,11 +524,11 @@ static void setFailsafe() // Update servo outputs for (int n = 0; n < ACTUATORCOMMAND_CHANNEL_NUMELEM; ++n) { - set_channel(n, command.Channel[n]); + set_channel(n, Channel[n]); } - // Update output object - ActuatorCommandSet(&command); + // Update output object's parts that we changed + ActuatorCommandChannelGet(Channel); } @@ -438,25 +537,23 @@ static void setFailsafe() */ static void actuator_update_rate(UAVObjEvent * ev) { - ActuatorSettingsData settings; + uint16_t ChannelUpdateFreq[ACTUATORSETTINGS_CHANNELUPDATEFREQ_NUMELEM]; if ( ev->obj == ActuatorSettingsHandle() ) { - ActuatorSettingsGet(&settings); - PIOS_Servo_SetHz(&settings.ChannelUpdateFreq[0], ACTUATORSETTINGS_CHANNELUPDATEFREQ_NUMELEM); + ActuatorSettingsChannelUpdateFreqGet(ChannelUpdateFreq); + PIOS_Servo_SetHz(&ChannelUpdateFreq[0], ACTUATORSETTINGS_CHANNELUPDATEFREQ_NUMELEM); } } - - #if defined(ARCH_POSIX) || defined(ARCH_WIN32) static bool set_channel(uint8_t mixer_channel, uint16_t value) { return true; } #else static bool set_channel(uint8_t mixer_channel, uint16_t value) { - + ActuatorSettingsData settings; ActuatorSettingsGet(&settings); - + switch(settings.ChannelType[mixer_channel]) { case ACTUATORSETTINGS_CHANNELTYPE_PWMALARMBUZZER: { // This is for buzzers that take a PWM input @@ -508,7 +605,7 @@ static bool set_channel(uint8_t mixer_channel, uint16_t value) { PIOS_Servo_Set(settings.ChannelAddr[mixer_channel], value); return true; #if defined(PIOS_INCLUDE_I2C_ESC) - case ACTUATORSETTINGS_CHANNELTYPE_MK: + case ACTUATORSETTINGS_CHANNELTYPE_MK: return PIOS_SetMKSpeed(settings.ChannelAddr[mixer_channel],value); case ACTUATORSETTINGS_CHANNELTYPE_ASTEC4: return PIOS_SetAstec4Speed(settings.ChannelAddr[mixer_channel],value); @@ -516,10 +613,10 @@ static bool set_channel(uint8_t mixer_channel, uint16_t value) { #endif default: return false; - } - + } + return false; - + } #endif diff --git a/flight/Modules/Altitude/altitude.c b/flight/Modules/Altitude/altitude.c index 705eb061d..d1655aaa8 100644 --- a/flight/Modules/Altitude/altitude.c +++ b/flight/Modules/Altitude/altitude.c @@ -37,6 +37,7 @@ */ #include "openpilot.h" +#include "altitude.h" #include "baroaltitude.h" // object that will be updated by the module #if defined(PIOS_INCLUDE_HCSR04) #include "sonaraltitude.h" // object that will be updated by the module @@ -66,12 +67,28 @@ static void altitudeTask(void *parameters); * Initialise the module, called on startup * \returns 0 on success or -1 if initialisation failed */ -int32_t AltitudeInitialize() +int32_t AltitudeStart() { + + BaroAltitudeInitialize(); +#if defined(PIOS_INCLUDE_HCSR04) + SonarAltitudeInitialze(); +#endif + // Start main task xTaskCreate(altitudeTask, (signed char *)"Altitude", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &taskHandle); TaskMonitorAdd(TASKINFO_RUNNING_ALTITUDE, taskHandle); + return 0; +} + +/** + * Initialise the module, called on startup + * \returns 0 on success or -1 if initialisation failed + */ +int32_t AltitudeInitialize() +{ + // init down-sampling data alt_ds_temp = 0; alt_ds_pres = 0; @@ -79,7 +96,7 @@ int32_t AltitudeInitialize() return 0; } - +MODULE_INITCALL(AltitudeInitialize, AltitudeStart) /** * Module thread, should not return. */ diff --git a/flight/Modules/Attitude/attitude.c b/flight/Modules/Attitude/attitude.c index 599c66b1b..b7b535f18 100644 --- a/flight/Modules/Attitude/attitude.c +++ b/flight/Modules/Attitude/attitude.c @@ -3,7 +3,7 @@ * @addtogroup OpenPilotModules OpenPilot Modules * @{ * @addtogroup Attitude Copter Control Attitude Estimation - * @brief Acquires sensor data and computes attitude estimate + * @brief Acquires sensor data and computes attitude estimate * Specifically updates the the @ref AttitudeActual "AttitudeActual" and @ref AttitudeRaw "AttitudeRaw" settings objects * @{ * @@ -76,7 +76,7 @@ static void AttitudeTask(void *parameters); static float gyro_correct_int[3] = {0,0,0}; static xQueueHandle gyro_queue; -static void updateSensors(AttitudeRawData *); +static int8_t updateSensors(AttitudeRawData *); static void updateAttitude(AttitudeRawData *); static void settingsUpdatedCb(UAVObjEvent * objEv); @@ -89,6 +89,22 @@ static float q[4] = {1,0,0,0}; static float R[3][3]; static int8_t rotate = 0; static bool zero_during_arming = false; +static bool bias_correct_gyro = true; + +/** + * Initialise the module, called on startup + * \returns 0 on success or -1 if initialisation failed + */ +int32_t AttitudeStart(void) +{ + + // Start main task + xTaskCreate(AttitudeTask, (signed char *)"Attitude", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &taskHandle); + TaskMonitorAdd(TASKINFO_RUNNING_ATTITUDE, taskHandle); + PIOS_WDG_RegisterFlag(PIOS_WDG_ATTITUDE); + + return 0; +} /** * Initialise the module, called on startup @@ -96,6 +112,10 @@ static bool zero_during_arming = false; */ int32_t AttitudeInitialize(void) { + AttitudeActualInitialize(); + AttitudeRawInitialize(); + AttitudeSettingsInitialize(); + // Initialize quaternion AttitudeActualData attitude; AttitudeActualGet(&attitude); @@ -104,89 +124,125 @@ int32_t AttitudeInitialize(void) attitude.q3 = 0; attitude.q4 = 0; AttitudeActualSet(&attitude); - + + // Cannot trust the values to init right above if BL runs + gyro_correct_int[0] = 0; + gyro_correct_int[1] = 0; + gyro_correct_int[2] = 0; + + q[0] = 1; + q[1] = 0; + q[2] = 0; + q[3] = 0; + for(uint8_t i = 0; i < 3; i++) + for(uint8_t j = 0; j < 3; j++) + R[i][j] = 0; + // Create queue for passing gyro data, allow 2 back samples in case gyro_queue = xQueueCreate(1, sizeof(float) * 4); - if(gyro_queue == NULL) + if(gyro_queue == NULL) return -1; + + PIOS_ADC_SetQueue(gyro_queue); - + AttitudeSettingsConnectCallback(&settingsUpdatedCb); - - // Start main task - xTaskCreate(AttitudeTask, (signed char *)"Attitude", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &taskHandle); - TaskMonitorAdd(TASKINFO_RUNNING_ATTITUDE, taskHandle); - PIOS_WDG_RegisterFlag(PIOS_WDG_ATTITUDE); + return 0; } +MODULE_INITCALL(AttitudeInitialize, AttitudeStart) + /** * Module thread, should not return. */ static void AttitudeTask(void *parameters) { - uint8_t init = 0; AlarmsClear(SYSTEMALARMS_ALARM_ATTITUDE); PIOS_ADC_Config((PIOS_ADC_RATE / 1000.0f) * UPDATE_RATE); // Keep flash CS pin high while talking accel - PIOS_FLASH_DISABLE; + PIOS_FLASH_DISABLE; PIOS_ADXL345_Init(); - - zero_during_arming = false; + + // Set critical error and wait until the accel is producing data + while(PIOS_ADXL345_FifoElements() == 0) { + AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE, SYSTEMALARMS_ALARM_CRITICAL); + PIOS_WDG_UpdateFlag(PIOS_WDG_ATTITUDE); + } + + // Force settings update to make sure rotation loaded + settingsUpdatedCb(AttitudeSettingsHandle()); + // Main task loop while (1) { - + FlightStatusData flightStatus; FlightStatusGet(&flightStatus); - - if(xTaskGetTickCount() < 10000) { - // For first 5 seconds use accels to get gyro bias + + if((xTaskGetTickCount() < 7000) && (xTaskGetTickCount() > 1000)) { + // For first 7 seconds use accels to get gyro bias accelKp = 1; - // Decrease the rate of gyro learning during init - accelKi = .5 / (1 + xTaskGetTickCount() / 5000); - yawBiasRate = 0.01 / (1 + xTaskGetTickCount() / 5000); + accelKi = 0.9; + yawBiasRate = 0.23; init = 0; - } + } else if (zero_during_arming && (flightStatus.Armed == FLIGHTSTATUS_ARMED_ARMING)) { - accelKi = .01; - yawBiasRate = 0.1; - init = 0; + accelKp = 1; + accelKi = 0.9; + yawBiasRate = 0.23; + init = 0; } else if (init == 0) { - settingsUpdatedCb(AttitudeSettingsHandle()); + // Reload settings (all the rates) + AttitudeSettingsAccelKiGet(&accelKi); + AttitudeSettingsAccelKpGet(&accelKp); + AttitudeSettingsYawBiasRateGet(&yawBiasRate); init = 1; - } - + } + PIOS_WDG_UpdateFlag(PIOS_WDG_ATTITUDE); - + AttitudeRawData attitudeRaw; - AttitudeRawGet(&attitudeRaw); - updateSensors(&attitudeRaw); - updateAttitude(&attitudeRaw); - AttitudeRawSet(&attitudeRaw); + AttitudeRawGet(&attitudeRaw); + if(updateSensors(&attitudeRaw) != 0) + AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE, SYSTEMALARMS_ALARM_ERROR); + else { + // Only update attitude when sensor data is good + updateAttitude(&attitudeRaw); + AttitudeRawSet(&attitudeRaw); + AlarmsClear(SYSTEMALARMS_ALARM_ATTITUDE); + } } } -static void updateSensors(AttitudeRawData * attitudeRaw) -{ +/** + * Get an update from the sensors + * @param[in] attitudeRaw Populate the UAVO instead of saving right here + * @return 0 if successfull, -1 if not + */ +static int8_t updateSensors(AttitudeRawData * attitudeRaw) +{ struct pios_adxl345_data accel_data; float gyro[4]; - + // Only wait the time for two nominal updates before setting an alarm if(xQueueReceive(gyro_queue, (void * const) gyro, UPDATE_RATE * 2) == errQUEUE_EMPTY) { AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE, SYSTEMALARMS_ALARM_ERROR); - return; + return -1; } - - + + // No accel data available + if(PIOS_ADXL345_FifoElements() == 0) + return -1; + // First sample is temperature attitudeRaw->gyros[ATTITUDERAW_GYROS_X] = -(gyro[1] - GYRO_NEUTRAL) * gyroGain; attitudeRaw->gyros[ATTITUDERAW_GYROS_Y] = (gyro[2] - GYRO_NEUTRAL) * gyroGain; attitudeRaw->gyros[ATTITUDERAW_GYROS_Z] = -(gyro[3] - GYRO_NEUTRAL) * gyroGain; - + int32_t x = 0; int32_t y = 0; int32_t z = 0; @@ -201,9 +257,9 @@ static void updateSensors(AttitudeRawData * attitudeRaw) } while ( (i < 32) && (samples_remaining > 0) ); attitudeRaw->gyrotemp[0] = samples_remaining; attitudeRaw->gyrotemp[1] = i; - + float accel[3] = {(float) x / i, (float) y / i, (float) z / i}; - + if(rotate) { // TODO: rotate sensors too so stabilization is well behaved float vec_out[3]; @@ -219,68 +275,71 @@ static void updateSensors(AttitudeRawData * attitudeRaw) attitudeRaw->accels[0] = accel[0]; attitudeRaw->accels[1] = accel[1]; attitudeRaw->accels[2] = accel[2]; - } - + } + // Scale accels and correct bias attitudeRaw->accels[ATTITUDERAW_ACCELS_X] = (attitudeRaw->accels[ATTITUDERAW_ACCELS_X] - accelbias[0]) * 0.004f * 9.81f; attitudeRaw->accels[ATTITUDERAW_ACCELS_Y] = (attitudeRaw->accels[ATTITUDERAW_ACCELS_Y] - accelbias[1]) * 0.004f * 9.81f; attitudeRaw->accels[ATTITUDERAW_ACCELS_Z] = (attitudeRaw->accels[ATTITUDERAW_ACCELS_Z] - accelbias[2]) * 0.004f * 9.81f; + + if(bias_correct_gyro) { + // Applying integral component here so it can be seen on the gyros and correct bias + attitudeRaw->gyros[ATTITUDERAW_GYROS_X] += gyro_correct_int[0]; + attitudeRaw->gyros[ATTITUDERAW_GYROS_Y] += gyro_correct_int[1]; + attitudeRaw->gyros[ATTITUDERAW_GYROS_Z] += gyro_correct_int[2]; + } + + // Because most crafts wont get enough information from gravity to zero yaw gyro, we try + // and make it average zero (weakly) + gyro_correct_int[2] += - attitudeRaw->gyros[ATTITUDERAW_GYROS_Z] * yawBiasRate; - // Applying integral component here so it can be seen on the gyros and correct bias - attitudeRaw->gyros[ATTITUDERAW_GYROS_X] += gyro_correct_int[0]; - attitudeRaw->gyros[ATTITUDERAW_GYROS_Y] += gyro_correct_int[1]; - - // Because most crafts wont get enough information from gravity to zero yaw gyro - attitudeRaw->gyros[ATTITUDERAW_GYROS_Z] += gyro_correct_int[2]; - gyro_correct_int[2] += - attitudeRaw->gyros[ATTITUDERAW_GYROS_Z] * yawBiasRate; + return 0; } static void updateAttitude(AttitudeRawData * attitudeRaw) { + float dT; + portTickType thisSysTime = xTaskGetTickCount(); static portTickType lastSysTime = 0; - static portTickType thisSysTime; - - static float dT = 0; - - thisSysTime = xTaskGetTickCount(); - if(thisSysTime > lastSysTime) // reuse dt in case of wraparound - dT = (thisSysTime - lastSysTime) / portTICK_RATE_MS / 1000.0f; + + dT = (thisSysTime == lastSysTime) ? 0.001 : (portMAX_DELAY & (thisSysTime - lastSysTime)) / portTICK_RATE_MS / 1000.0f; lastSysTime = thisSysTime; - + // Bad practice to assume structure order, but saves memory float gyro[3]; gyro[0] = attitudeRaw->gyros[0]; gyro[1] = attitudeRaw->gyros[1]; gyro[2] = attitudeRaw->gyros[2]; - + { float * accels = attitudeRaw->accels; float grot[3]; float accel_err[3]; - + // Rotate gravity to body frame and cross with accels grot[0] = -(2 * (q[1] * q[3] - q[0] * q[2])); grot[1] = -(2 * (q[2] * q[3] + q[0] * q[1])); grot[2] = -(q[0] * q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3]); CrossProduct((const float *) accels, (const float *) grot, accel_err); - - // Account for accel magnitude + + // Account for accel magnitude float accel_mag = sqrt(accels[0]*accels[0] + accels[1]*accels[1] + accels[2]*accels[2]); accel_err[0] /= accel_mag; accel_err[1] /= accel_mag; accel_err[2] /= accel_mag; - - // Accumulate integral of error. Scale here so that units are (rad/s) but Ki has units of s + + // Accumulate integral of error. Scale here so that units are (deg/s) but Ki has units of s gyro_correct_int[0] += accel_err[0] * accelKi; gyro_correct_int[1] += accel_err[1] * accelKi; + //gyro_correct_int[2] += accel_err[2] * settings.AccelKI * dT; - + // Correct rates based on error, integral component dealt with in updateSensors gyro[0] += accel_err[0] * accelKp / dT; gyro[1] += accel_err[1] * accelKp / dT; gyro[2] += accel_err[2] * accelKp / dT; } - + { // scoping variables to save memory // Work out time derivative from INSAlgo writeup // Also accounts for the fact that gyros are in deg/s @@ -289,28 +348,44 @@ static void updateAttitude(AttitudeRawData * attitudeRaw) qdot[1] = (q[0] * gyro[0] - q[3] * gyro[1] + q[2] * gyro[2]) * dT * M_PI / 180 / 2; qdot[2] = (q[3] * gyro[0] + q[0] * gyro[1] - q[1] * gyro[2]) * dT * M_PI / 180 / 2; qdot[3] = (-q[2] * gyro[0] + q[1] * gyro[1] + q[0] * gyro[2]) * dT * M_PI / 180 / 2; - + // Take a time step q[0] = q[0] + qdot[0]; q[1] = q[1] + qdot[1]; q[2] = q[2] + qdot[2]; q[3] = q[3] + qdot[3]; + + if(q[0] < 0) { + q[0] = -q[0]; + q[1] = -q[1]; + q[2] = -q[2]; + q[3] = -q[3]; + } } - + // Renomalize float qmag = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]); q[0] = q[0] / qmag; q[1] = q[1] / qmag; q[2] = q[2] / qmag; q[3] = q[3] / qmag; - + + // If quaternion has become inappropriately short or is nan reinit. + // THIS SHOULD NEVER ACTUALLY HAPPEN + if((fabs(qmag) < 1e-3) || (qmag != qmag)) { + q[0] = 1; + q[1] = 0; + q[2] = 0; + q[3] = 0; + } + AttitudeActualData attitudeActual; AttitudeActualGet(&attitudeActual); - + quat_copy(q, &attitudeActual.q1); - + // Convert into eueler degrees (makes assumptions about RPY order) - Quaternion2RPY(&attitudeActual.q1,&attitudeActual.Roll); + Quaternion2RPY(&attitudeActual.q1,&attitudeActual.Roll); AttitudeActualSet(&attitudeActual); } @@ -318,36 +393,41 @@ static void updateAttitude(AttitudeRawData * attitudeRaw) static void settingsUpdatedCb(UAVObjEvent * objEv) { AttitudeSettingsData attitudeSettings; AttitudeSettingsGet(&attitudeSettings); - - + + accelKp = attitudeSettings.AccelKp; - accelKi = attitudeSettings.AccelKi; + accelKi = attitudeSettings.AccelKi; yawBiasRate = attitudeSettings.YawBiasRate; gyroGain = attitudeSettings.GyroGain; - + zero_during_arming = attitudeSettings.ZeroDuringArming == ATTITUDESETTINGS_ZERODURINGARMING_TRUE; - + bias_correct_gyro = attitudeSettings.BiasCorrectGyro == ATTITUDESETTINGS_BIASCORRECTGYRO_TRUE; + accelbias[0] = attitudeSettings.AccelBias[ATTITUDESETTINGS_ACCELBIAS_X]; accelbias[1] = attitudeSettings.AccelBias[ATTITUDESETTINGS_ACCELBIAS_Y]; accelbias[2] = attitudeSettings.AccelBias[ATTITUDESETTINGS_ACCELBIAS_Z]; - + + gyro_correct_int[0] = attitudeSettings.GyroBias[ATTITUDESETTINGS_GYROBIAS_X] / 100.0f; + gyro_correct_int[1] = attitudeSettings.GyroBias[ATTITUDESETTINGS_GYROBIAS_Y] / 100.0f; + gyro_correct_int[2] = attitudeSettings.GyroBias[ATTITUDESETTINGS_GYROBIAS_Z] / 100.0f; + // Indicates not to expend cycles on rotation if(attitudeSettings.BoardRotation[0] == 0 && attitudeSettings.BoardRotation[1] == 0 && attitudeSettings.BoardRotation[2] == 0) { rotate = 0; - + // Shouldn't be used but to be safe float rotationQuat[4] = {1,0,0,0}; Quaternion2R(rotationQuat, R); } else { float rotationQuat[4]; - const float rpy[3] = {attitudeSettings.BoardRotation[ATTITUDESETTINGS_BOARDROTATION_ROLL], - attitudeSettings.BoardRotation[ATTITUDESETTINGS_BOARDROTATION_PITCH], + const float rpy[3] = {attitudeSettings.BoardRotation[ATTITUDESETTINGS_BOARDROTATION_ROLL], + attitudeSettings.BoardRotation[ATTITUDESETTINGS_BOARDROTATION_PITCH], attitudeSettings.BoardRotation[ATTITUDESETTINGS_BOARDROTATION_YAW]}; RPY2Quaternion(rpy, rotationQuat); Quaternion2R(rotationQuat, R); rotate = 1; - } + } } /** * @} diff --git a/flight/Modules/Battery/battery.c b/flight/Modules/Battery/battery.c index eabb5f91c..a57efd69a 100644 --- a/flight/Modules/Battery/battery.c +++ b/flight/Modules/Battery/battery.c @@ -75,8 +75,13 @@ static void onTimer(UAVObjEvent* ev); * Initialise the module, called on startup * \returns 0 on success or -1 if initialisation failed */ +MODULE_INITCALL(BatteryInitialize, 0) + int32_t BatteryInitialize(void) { + BatteryStateInitialze(); + BatterySettingsInitialize(); + static UAVObjEvent ev; memset(&ev,0,sizeof(UAVObjEvent)); diff --git a/flight/Modules/CameraStab/camerastab.c b/flight/Modules/CameraStab/camerastab.c new file mode 100644 index 000000000..2e21b8e92 --- /dev/null +++ b/flight/Modules/CameraStab/camerastab.c @@ -0,0 +1,141 @@ +/** + ****************************************************************************** + * @addtogroup OpenPilotModules OpenPilot Modules + * @{ + * @addtogroup CameraStab Camera Stabilization Module + * @brief Camera stabilization module + * Updates accessory outputs with values appropriate for camera stabilization + * @{ + * + * @file camerastab.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Stabilize camera against the roll pitch and yaw of aircraft + * + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * Output object: Accessory + * + * This module will periodically calculate the output values for stabilizing the camera + * + * UAVObjects are automatically generated by the UAVObjectGenerator from + * the object definition XML file. + * + * Modules have no API, all communication to other modules is done through UAVObjects. + * However modules may use the API exposed by shared libraries. + * See the OpenPilot wiki for more details. + * http://www.openpilot.org/OpenPilot_Application_Architecture + * + */ + +#include "openpilot.h" + +#include "accessorydesired.h" +#include "attitudeactual.h" +#include "camerastabsettings.h" +#include "cameradesired.h" + +// +// Configuration +// +#define SAMPLE_PERIOD_MS 10 + +// Private types + +// Private variables + +// Private functions +static void attitudeUpdated(UAVObjEvent* ev); +static float bound(float val); + +/** + * Initialise the module, called on startup + * \returns 0 on success or -1 if initialisation failed + */ +int32_t CameraStabInitialize(void) +{ + static UAVObjEvent ev; + ev.obj = AttitudeActualHandle(); + ev.instId = 0; + ev.event = 0; + + CameraStabSettingsInitialize(); + CameraDesiredInitialize(); + + EventPeriodicCallbackCreate(&ev, attitudeUpdated, SAMPLE_PERIOD_MS / portTICK_RATE_MS); + + return 0; +} + +static void attitudeUpdated(UAVObjEvent* ev) +{ + if (ev->obj != AttitudeActualHandle()) + return; + + float attitude; + float output; + AccessoryDesiredData accessory; + + CameraStabSettingsData cameraStab; + CameraStabSettingsGet(&cameraStab); + + // Read any input channels + float inputs[3] = {0,0,0}; + if(cameraStab.Inputs[CAMERASTABSETTINGS_INPUTS_ROLL] != CAMERASTABSETTINGS_INPUTS_NONE) { + if(AccessoryDesiredInstGet(cameraStab.Inputs[CAMERASTABSETTINGS_INPUTS_ROLL] - CAMERASTABSETTINGS_INPUTS_ACCESSORY0, &accessory) == 0) + inputs[0] = accessory.AccessoryVal * cameraStab.InputRange[CAMERASTABSETTINGS_INPUTRANGE_ROLL]; + } + if(cameraStab.Inputs[CAMERASTABSETTINGS_INPUTS_PITCH] != CAMERASTABSETTINGS_INPUTS_NONE) { + if(AccessoryDesiredInstGet(cameraStab.Inputs[CAMERASTABSETTINGS_INPUTS_PITCH] - CAMERASTABSETTINGS_INPUTS_ACCESSORY0, &accessory) == 0) + inputs[1] = accessory.AccessoryVal * cameraStab.InputRange[CAMERASTABSETTINGS_INPUTRANGE_PITCH]; + } + if(cameraStab.Inputs[CAMERASTABSETTINGS_INPUTS_YAW] != CAMERASTABSETTINGS_INPUTS_NONE) { + if(AccessoryDesiredInstGet(cameraStab.Inputs[CAMERASTABSETTINGS_INPUTS_YAW] - CAMERASTABSETTINGS_INPUTS_ACCESSORY0, &accessory) == 0) + inputs[2] = accessory.AccessoryVal * cameraStab.InputRange[CAMERASTABSETTINGS_INPUTRANGE_YAW]; + } + + // Set output channels + AttitudeActualRollGet(&attitude); + output = bound((attitude + inputs[0]) / cameraStab.OutputRange[CAMERASTABSETTINGS_OUTPUTRANGE_ROLL]); + CameraDesiredRollSet(&output); + + AttitudeActualPitchGet(&attitude); + output = bound((attitude + inputs[1]) / cameraStab.OutputRange[CAMERASTABSETTINGS_OUTPUTRANGE_PITCH]); + CameraDesiredPitchSet(&output); + + AttitudeActualYawGet(&attitude); + output = bound((attitude + inputs[2]) / cameraStab.OutputRange[CAMERASTABSETTINGS_OUTPUTRANGE_YAW]); + CameraDesiredYawSet(&output); + +} + +float bound(float val) +{ + return (val > 1) ? 1 : + (val < -1) ? -1 : + val; +} +/** + * @} + */ + +/** + * @} + */ diff --git a/flight/UAVObjects/uavobjectsinit_linker.c b/flight/Modules/CameraStab/inc/camerastab.h similarity index 62% rename from flight/UAVObjects/uavobjectsinit_linker.c rename to flight/Modules/CameraStab/inc/camerastab.h index 3d4abd7eb..5d7bf9d06 100644 --- a/flight/UAVObjects/uavobjectsinit_linker.c +++ b/flight/Modules/CameraStab/inc/camerastab.h @@ -1,45 +1,42 @@ -/** - ****************************************************************************** - * - * @file uavobjectsinit.c - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @brief Initialize all objects. - * Automatically generated by the UAVObjectGenerator. - * - * @note This is an automatically generated file. - * DO NOT modify manually. - * @see The GNU Public License (GPL) Version 3 - * - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "openpilot.h" - -/** - * Function used to initialize the first instance of each object. - * This file is automatically updated by the UAVObjectGenerator. - */ -extern initcall_t __uavobj_initcall_start[], __uavobj_initcall_end[]; - -void UAVObjectsInitializeAll() -{ - initcall_t *fn; - int32_t ret; - - for (fn = __uavobj_initcall_start; fn < __uavobj_initcall_end; fn++) - ret = (*fn)(); -} +/** + ****************************************************************************** + * @addtogroup OpenPilotModules OpenPilot Modules + * @{ + * @addtogroup BatteryModule Battery Module + * @{ + * + * @file battery.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Module to read the battery Voltage and Current periodically and set alarms appropriately. + * + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef BATTERY_H +#define BATTERY_H + +#include "openpilot.h" + +int32_t CameraStabInitialize(void); + +#endif // BATTERY_H + +/** + * @} + * @} + */ diff --git a/flight/Modules/Example/example.c b/flight/Modules/Example/example.c index add8e3540..d50809415 100644 --- a/flight/Modules/Example/example.c +++ b/flight/Modules/Example/example.c @@ -49,9 +49,14 @@ #include "examplemodperiodic.h" #include "examplemodthread.h" -void ExampleInitialize(void) +void ExampleStart(void) { - ExampleModEventInitialize(); ExampleModPeriodicInitialize(); ExampleModThreadInitialize(); } + +void ExampleInitialize(void) +{ + ExampleModEventInitialize(); +} +MODULE_INITCALL(ExampleInitialize, ExampleStart) diff --git a/flight/Modules/FirmwareIAP/firmwareiap.c b/flight/Modules/FirmwareIAP/firmwareiap.c index 71de8c390..21678397e 100644 --- a/flight/Modules/FirmwareIAP/firmwareiap.c +++ b/flight/Modules/FirmwareIAP/firmwareiap.c @@ -27,9 +27,11 @@ #include #include "pios.h" +#include #include "openpilot.h" #include "firmwareiap.h" #include "firmwareiapobj.h" +#include "flightstatus.h" // Private constants #define IAP_CMD_STEP_1 1122 @@ -86,17 +88,22 @@ static void resetTask(UAVObjEvent *); * \note * */ - +MODULE_INITCALL(FirmwareIAPInitialize, 0) int32_t FirmwareIAPInitialize() { - data.BoardType= BOARD_TYPE; + + FirmwareIAPObjInitialize(); + + const struct pios_board_info * bdinfo = &pios_board_info_blob; + + data.BoardType= bdinfo->board_type; PIOS_BL_HELPER_FLASH_Read_Description(data.Description,FIRMWAREIAPOBJ_DESCRIPTION_NUMELEM); PIOS_SYS_SerialNumberGetBinary(data.CPUSerial); - data.BoardRevision= BOARD_REVISION; + data.BoardRevision= bdinfo->board_rev; data.ArmReset=0; data.crc = 0; FirmwareIAPObjSet( &data ); - FirmwareIAPObjConnectCallback( &FirmwareIAPCallback ); + if(bdinfo->magic==PIOS_BOARD_INFO_BLOB_MAGIC) FirmwareIAPObjConnectCallback( &FirmwareIAPCallback ); return 0; } @@ -111,6 +118,7 @@ int32_t FirmwareIAPInitialize() static uint8_t iap_state = IAP_STATE_READY; static void FirmwareIAPCallback(UAVObjEvent* ev) { + const struct pios_board_info * bdinfo = &pios_board_info_blob; static uint32_t last_time = 0; uint32_t this_time; uint32_t delta; @@ -124,11 +132,11 @@ static void FirmwareIAPCallback(UAVObjEvent* ev) this_time = get_time(); delta = this_time - last_time; last_time = this_time; - if((data.BoardType==BOARD_TYPE)&&(data.crc != PIOS_BL_HELPER_CRC_Memory_Calc())) + if((data.BoardType==bdinfo->board_type)&&(data.crc != PIOS_BL_HELPER_CRC_Memory_Calc())) { PIOS_BL_HELPER_FLASH_Read_Description(data.Description,FIRMWAREIAPOBJ_DESCRIPTION_NUMELEM); PIOS_SYS_SerialNumberGetBinary(data.CPUSerial); - data.BoardRevision=BOARD_REVISION; + data.BoardRevision=bdinfo->board_rev; data.crc = PIOS_BL_HELPER_CRC_Memory_Calc(); FirmwareIAPObjSet( &data ); } @@ -156,6 +164,16 @@ static void FirmwareIAPCallback(UAVObjEvent* ev) case IAP_STATE_STEP_2: if( data.Command == IAP_CMD_STEP_3 ) { if( delta > iap_time_3_low_end && delta < iap_time_3_high_end ) { + + FlightStatusData flightStatus; + FlightStatusGet(&flightStatus); + + if(flightStatus.Armed != FLIGHTSTATUS_ARMED_DISARMED) { + // Abort any attempts if not disarmed + iap_state = IAP_STATE_READY; + break; + } + // we've met the three sequence of command numbers // we've met the time requirements. PIOS_IAP_SetRequest1(); diff --git a/flight/Modules/FlightPlan/flightplan.c b/flight/Modules/FlightPlan/flightplan.c index a76966507..e919dd41e 100644 --- a/flight/Modules/FlightPlan/flightplan.c +++ b/flight/Modules/FlightPlan/flightplan.c @@ -31,6 +31,7 @@ #include "openpilot.h" #include "pm.h" +#include "flightplan.h" #include "flightplanstatus.h" #include "flightplancontrol.h" #include "flightplansettings.h" @@ -56,10 +57,28 @@ extern unsigned char usrlib_img[]; /** * Module initialization */ -int32_t FlightPlanInitialize() +int32_t FlightPlanStart() { taskHandle = NULL; + // Start VM thread + xTaskCreate(flightPlanTask, (signed char *)"FlightPlan", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &taskHandle); + TaskMonitorAdd(TASKINFO_RUNNING_FLIGHTPLAN, taskHandle); + + return 0; +} + +/** + * Module initialization + */ +int32_t FlightPlanInitialize() +{ + taskHandle = NULL; + + FlightPlanStatusInitialize(); + FlightPlanControlInitialize(); + FlightPlanSettingsInitialize(); + // Listen for object updates FlightPlanControlConnectCallback(&objectUpdatedCb); @@ -69,13 +88,9 @@ int32_t FlightPlanInitialize() // Listen for FlightPlanControl updates FlightPlanControlConnectQueue(queue); - // Start VM thread - xTaskCreate(flightPlanTask, (signed char *)"FlightPlan", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &taskHandle); - TaskMonitorAdd(TASKINFO_RUNNING_FLIGHTPLAN, taskHandle); - return 0; } - +MODULE_INITCALL(FlightPlanInitialize, FlightPlanStart) /** * Module task */ diff --git a/flight/Modules/FlightPlan/lib/uavobject.py b/flight/Modules/FlightPlan/lib/uavobject.py index 2ce941bcf..aafe76a43 100644 --- a/flight/Modules/FlightPlan/lib/uavobject.py +++ b/flight/Modules/FlightPlan/lib/uavobject.py @@ -288,7 +288,7 @@ class UAVObject: uint32_t type; uint32_t numElements; uint8_t const *tmpStr; - int8_t tmpInt8; + int8_t tmpInt8 = 0; int16_t tmpInt16; int32_t tmpInt32; float tmpFloat; diff --git a/flight/Modules/GPS/GPS.c b/flight/Modules/GPS/GPS.c index 80fb044d9..60ff80184 100644 --- a/flight/Modules/GPS/GPS.c +++ b/flight/Modules/GPS/GPS.c @@ -63,7 +63,7 @@ static float GravityAccel(float latitude, float longitude, float altitude); // Private constants //#define FULL_COLD_RESTART // uncomment this to tell the GPS to do a FULL COLD restart -//#define DISABLE_GPS_TRESHOLD // +//#define DISABLE_GPS_THRESHOLD // #define GPS_TIMEOUT_MS 500 #define GPS_COMMAND_RESEND_TIMEOUT_MS 2000 @@ -109,19 +109,31 @@ static uint32_t numParsingErrors; * \return 0 on success */ -int32_t GPSInitialize(void) +int32_t GPSStart(void) { - signed portBASE_TYPE xReturn; - - // TODO: Get gps settings object - gpsPort = PIOS_COM_GPS; - // Start gps task - xReturn = xTaskCreate(gpsTask, (signed char *)"GPS", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &gpsTaskHandle); + xTaskCreate(gpsTask, (signed char *)"GPS", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &gpsTaskHandle); TaskMonitorAdd(TASKINFO_RUNNING_GPS, gpsTaskHandle); return 0; } +/** + * Initialise the gps module + * \return -1 if initialisation failed + * \return 0 on success + */ +int32_t GPSInitialize(void) +{ + GPSPositionInitialize(); + GPSTimeInitialize(); + HomeLocationInitialize(); + + // TODO: Get gps settings object + gpsPort = PIOS_COM_GPS; + + return 0; +} +MODULE_INITCALL(GPSInitialize, GPSStart) // **************** /** @@ -154,7 +166,7 @@ static void gpsTask(void *parameters) } #endif -#ifdef DISABLE_GPS_TRESHOLD +#ifdef DISABLE_GPS_THRESHOLD PIOS_COM_SendStringNonBlocking(gpsPort, "$PMTK397,0*23\r\n"); #endif @@ -188,8 +200,10 @@ static void gpsTask(void *parameters) while (PIOS_COM_ReceiveBufferUsed(gpsPort) > 0) { - int res = GTOP_BIN_update_position(PIOS_COM_ReceiveBuffer(gpsPort), &numChecksumErrors, &numParsingErrors); - if (res >= 0) + uint8_t c; + PIOS_COM_ReceiveBuffer(gpsPort, &c, 1, 0); + + if (GTOP_BIN_update_position(c, &numChecksumErrors, &numParsingErrors) >= 0) { numUpdates++; @@ -205,7 +219,8 @@ static void gpsTask(void *parameters) // This blocks the task until there is something on the buffer while (PIOS_COM_ReceiveBufferUsed(gpsPort) > 0) { - char c = PIOS_COM_ReceiveBuffer(gpsPort); + uint8_t c; + PIOS_COM_ReceiveBuffer(gpsPort, &c, 1, 0); // detect start while acquiring stream if (!start_flag && (c == '$')) diff --git a/flight/Modules/Guidance/guidance.c b/flight/Modules/Guidance/guidance.c index d19ef9311..b90303928 100644 --- a/flight/Modules/Guidance/guidance.c +++ b/flight/Modules/Guidance/guidance.c @@ -82,14 +82,8 @@ static void updateVtolDesiredAttitude(); * Initialise the module, called on startup * \returns 0 on success or -1 if initialisation failed */ -int32_t GuidanceInitialize() +int32_t GuidanceStart() { - // Create object queue - queue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(UAVObjEvent)); - - // Listen for updates. - AttitudeRawConnectQueue(queue); - // Start main task xTaskCreate(guidanceTask, (signed char *)"Guidance", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &guidanceTaskHandle); TaskMonitorAdd(TASKINFO_RUNNING_GUIDANCE, guidanceTaskHandle); @@ -97,6 +91,28 @@ int32_t GuidanceInitialize() return 0; } +/** + * Initialise the module, called on startup + * \returns 0 on success or -1 if initialisation failed + */ +int32_t GuidanceInitialize() +{ + + GuidanceSettingsInitialize(); + PositionDesiredInitialize(); + NedAccelInitialize(); + VelocityDesiredInitialize(); + + // Create object queue + queue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(UAVObjEvent)); + + // Listen for updates. + AttitudeRawConnectQueue(queue); + + return 0; +} +MODULE_INITCALL(GuidanceInitialize, GuidanceStart) + static float northVelIntegral = 0; static float eastVelIntegral = 0; static float downVelIntegral = 0; @@ -236,7 +252,7 @@ void updateVtolDesiredVelocity() { static portTickType lastSysTime; portTickType thisSysTime = xTaskGetTickCount();; - float dT; + float dT = 0; GuidanceSettingsData guidanceSettings; PositionActualData positionActual; @@ -304,7 +320,7 @@ static void updateVtolDesiredAttitude() { static portTickType lastSysTime; portTickType thisSysTime = xTaskGetTickCount();; - float dT; + float dT = 0; VelocityDesiredData velocityDesired; VelocityActualData velocityActual; diff --git a/flight/Modules/Guidance/inc/guidance.h b/flight/Modules/Guidance/inc/guidance.h index 8e877edca..86ef46b2d 100644 --- a/flight/Modules/Guidance/inc/guidance.h +++ b/flight/Modules/Guidance/inc/guidance.h @@ -27,5 +27,5 @@ #define EXAMPLEMODPERIODIC_H int32_t ExampleModPeriodicInitialize(); - +int32_t GuidanceInitialize(void); #endif // EXAMPLEMODPERIODIC_H diff --git a/flight/Modules/ManualControl/inc/manualcontrol.h b/flight/Modules/ManualControl/inc/manualcontrol.h index 608c12d1d..5cca1a623 100644 --- a/flight/Modules/ManualControl/inc/manualcontrol.h +++ b/flight/Modules/ManualControl/inc/manualcontrol.h @@ -1,7 +1,7 @@ /** ****************************************************************************** * @addtogroup OpenPilotModules OpenPilot Modules - * @{ + * @{ * @addtogroup ManualControlModule Manual Control Module * @{ * @@ -45,4 +45,64 @@ typedef enum {FLIGHTMODE_UNDEFINED = 0, FLIGHTMODE_MANUAL = 1, FLIGHTMODE_STABIL int32_t ManualControlInitialize(); + +/* + * These are assumptions we make in the flight code about the order of settings and their consistency between + * objects. Please keep this synchronized to the UAVObjects + */ +#define assumptions1 ( \ +((int)MANUALCONTROLSETTINGS_STABILIZATION1SETTINGS_NONE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) && \ +((int)MANUALCONTROLSETTINGS_STABILIZATION1SETTINGS_RATE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) && \ +((int)MANUALCONTROLSETTINGS_STABILIZATION1SETTINGS_AXISLOCK == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) && \ +((int)MANUALCONTROLSETTINGS_STABILIZATION1SETTINGS_WEAKLEVELING == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) && \ +((int)MANUALCONTROLSETTINGS_STABILIZATION1SETTINGS_ATTITUDE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) \ +) + +#define assumptions3 ( \ +((int)MANUALCONTROLSETTINGS_STABILIZATION2SETTINGS_NONE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) && \ +((int)MANUALCONTROLSETTINGS_STABILIZATION2SETTINGS_RATE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) && \ +((int)MANUALCONTROLSETTINGS_STABILIZATION2SETTINGS_AXISLOCK == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) && \ +((int)MANUALCONTROLSETTINGS_STABILIZATION2SETTINGS_WEAKLEVELING == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) && \ +((int)MANUALCONTROLSETTINGS_STABILIZATION2SETTINGS_ATTITUDE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) \ +) + +#define assumptions5 ( \ +((int)MANUALCONTROLSETTINGS_STABILIZATION3SETTINGS_NONE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) && \ +((int)MANUALCONTROLSETTINGS_STABILIZATION3SETTINGS_RATE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) && \ +((int)MANUALCONTROLSETTINGS_STABILIZATION3SETTINGS_AXISLOCK == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) && \ +((int)MANUALCONTROLSETTINGS_STABILIZATION3SETTINGS_WEAKLEVELING == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) && \ +((int)MANUALCONTROLSETTINGS_STABILIZATION3SETTINGS_ATTITUDE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) \ +) + +#define ARMING_CHANNEL_ROLL 0 +#define ARMING_CHANNEL_PITCH 1 +#define ARMING_CHANNEL_YAW 2 + +#define assumptions7 ( \ +( ((int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)/2 == ARMING_CHANNEL_ROLL) && \ +( ((int)MANUALCONTROLSETTINGS_ARMING_ROLLRIGHT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)/2 == ARMING_CHANNEL_ROLL) && \ +( ((int)MANUALCONTROLSETTINGS_ARMING_PITCHFORWARD -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)/2 == ARMING_CHANNEL_PITCH) && \ +( ((int)MANUALCONTROLSETTINGS_ARMING_PITCHAFT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)/2 == ARMING_CHANNEL_PITCH) && \ +( ((int)MANUALCONTROLSETTINGS_ARMING_YAWLEFT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)/2 == ARMING_CHANNEL_YAW) && \ +( ((int)MANUALCONTROLSETTINGS_ARMING_YAWRIGHT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)/2 == ARMING_CHANNEL_YAW) \ +) + +#define assumptions8 ( \ +( ((int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)%2 == 0) && \ +( ((int)MANUALCONTROLSETTINGS_ARMING_ROLLRIGHT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)%2 != 0) && \ +( ((int)MANUALCONTROLSETTINGS_ARMING_PITCHFORWARD -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)%2 == 0) && \ +( ((int)MANUALCONTROLSETTINGS_ARMING_PITCHAFT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)%2 != 0) && \ +( ((int)MANUALCONTROLSETTINGS_ARMING_YAWLEFT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)%2 == 0) && \ +( ((int)MANUALCONTROLSETTINGS_ARMING_YAWRIGHT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)%2 != 0) \ +) + +#define assumptions_flightmode ( \ +( (int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_MANUAL == (int) FLIGHTSTATUS_FLIGHTMODE_MANUAL) && \ +( (int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_STABILIZED1 == (int) FLIGHTSTATUS_FLIGHTMODE_STABILIZED1) && \ +( (int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_STABILIZED2 == (int) FLIGHTSTATUS_FLIGHTMODE_STABILIZED2) && \ +( (int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_STABILIZED3 == (int) FLIGHTSTATUS_FLIGHTMODE_STABILIZED3) && \ +( (int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_VELOCITYCONTROL == (int) FLIGHTSTATUS_FLIGHTMODE_VELOCITYCONTROL) && \ +( (int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_POSITIONHOLD == (int) FLIGHTSTATUS_FLIGHTMODE_POSITIONHOLD) \ +) + #endif // MANUALCONTROL_H diff --git a/flight/Modules/ManualControl/manualcontrol.c b/flight/Modules/ManualControl/manualcontrol.c index 0fccd9759..ba47fd64b 100644 --- a/flight/Modules/ManualControl/manualcontrol.c +++ b/flight/Modules/ManualControl/manualcontrol.c @@ -1,606 +1,595 @@ -/** - ****************************************************************************** - * @addtogroup OpenPilotModules OpenPilot Modules - * @{ - * @addtogroup ManualControlModule Manual Control Module - * @brief Provide manual control or allow it alter flight mode. - * @{ - * - * Reads in the ManualControlCommand FlightMode setting from receiver then either - * pass the settings straght to ActuatorDesired object (manual mode) or to - * AttitudeDesired object (stabilized mode) - * - * @file manualcontrol.c - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @brief ManualControl module. Handles safety R/C link and flight mode. - * - * @see The GNU Public License (GPL) Version 3 - * - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "openpilot.h" -#include "manualcontrol.h" -#include "manualcontrolsettings.h" -#include "stabilizationsettings.h" -#include "manualcontrolcommand.h" -#include "actuatordesired.h" -#include "stabilizationdesired.h" -#include "flighttelemetrystats.h" -#include "flightstatus.h" - -// Private constants -#if defined(PIOS_MANUAL_STACK_SIZE) -#define STACK_SIZE_BYTES PIOS_MANUAL_STACK_SIZE -#else -#define STACK_SIZE_BYTES 824 -#endif - -#define TASK_PRIORITY (tskIDLE_PRIORITY+4) -#define UPDATE_PERIOD_MS 20 -#define THROTTLE_FAILSAFE -0.1 -#define FLIGHT_MODE_LIMIT 1.0/3.0 -#define ARMED_TIME_MS 1000 -#define ARMED_THRESHOLD 0.50 -//safe band to allow a bit of calibration error or trim offset (in microseconds) -#define CONNECTION_OFFSET 150 - -// Private types -typedef enum -{ - ARM_STATE_DISARMED, - ARM_STATE_ARMING_MANUAL, - ARM_STATE_ARMED, - ARM_STATE_DISARMING_MANUAL, - ARM_STATE_DISARMING_TIMEOUT -} ArmState_t; - -// Private variables -static xTaskHandle taskHandle; -static ArmState_t armState; -static portTickType lastSysTime; - -// Private functions -static void updateActuatorDesired(ManualControlCommandData * cmd); -static void updateStabilizationDesired(ManualControlCommandData * cmd, ManualControlSettingsData * settings); -static void processFlightMode(ManualControlSettingsData * settings, float flightMode); -static void processArm(ManualControlCommandData * cmd, ManualControlSettingsData * settings); - -static void manualControlTask(void *parameters); -static float scaleChannel(int16_t value, int16_t max, int16_t min, int16_t neutral); -static uint32_t timeDifferenceMs(portTickType start_time, portTickType end_time); -static bool okToArm(void); -static bool validInputRange(int16_t min, int16_t max, uint16_t value); - -#define assumptions1 ( \ - ((int)MANUALCONTROLSETTINGS_STABILIZATION1SETTINGS_NONE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) && \ - ((int)MANUALCONTROLSETTINGS_STABILIZATION1SETTINGS_RATE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) && \ - ((int)MANUALCONTROLSETTINGS_STABILIZATION1SETTINGS_ATTITUDE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) \ - ) - -#define assumptions3 ( \ - ((int)MANUALCONTROLSETTINGS_STABILIZATION2SETTINGS_NONE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) && \ - ((int)MANUALCONTROLSETTINGS_STABILIZATION2SETTINGS_RATE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) && \ - ((int)MANUALCONTROLSETTINGS_STABILIZATION2SETTINGS_ATTITUDE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) \ - ) - -#define assumptions5 ( \ - ((int)MANUALCONTROLSETTINGS_STABILIZATION3SETTINGS_NONE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) && \ - ((int)MANUALCONTROLSETTINGS_STABILIZATION3SETTINGS_RATE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) && \ - ((int)MANUALCONTROLSETTINGS_STABILIZATION3SETTINGS_ATTITUDE == (int)STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) \ - ) - - - -#define ARMING_CHANNEL_ROLL 0 -#define ARMING_CHANNEL_PITCH 1 -#define ARMING_CHANNEL_YAW 2 - -#define assumptions7 ( \ - ( ((int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)/2 == ARMING_CHANNEL_ROLL) && \ - ( ((int)MANUALCONTROLSETTINGS_ARMING_ROLLRIGHT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)/2 == ARMING_CHANNEL_ROLL) && \ - ( ((int)MANUALCONTROLSETTINGS_ARMING_PITCHFORWARD -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)/2 == ARMING_CHANNEL_PITCH) && \ - ( ((int)MANUALCONTROLSETTINGS_ARMING_PITCHAFT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)/2 == ARMING_CHANNEL_PITCH) && \ - ( ((int)MANUALCONTROLSETTINGS_ARMING_YAWLEFT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)/2 == ARMING_CHANNEL_YAW) && \ - ( ((int)MANUALCONTROLSETTINGS_ARMING_YAWRIGHT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)/2 == ARMING_CHANNEL_YAW) \ - ) - -#define assumptions8 ( \ - ( ((int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)%2 == 0) && \ - ( ((int)MANUALCONTROLSETTINGS_ARMING_ROLLRIGHT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)%2 != 0) && \ - ( ((int)MANUALCONTROLSETTINGS_ARMING_PITCHFORWARD -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)%2 == 0) && \ - ( ((int)MANUALCONTROLSETTINGS_ARMING_PITCHAFT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)%2 != 0) && \ - ( ((int)MANUALCONTROLSETTINGS_ARMING_YAWLEFT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)%2 == 0) && \ - ( ((int)MANUALCONTROLSETTINGS_ARMING_YAWRIGHT -(int)MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)%2 != 0) \ - ) - - -#define assumptions_flightmode ( \ - ( (int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_MANUAL == (int) FLIGHTSTATUS_FLIGHTMODE_MANUAL) && \ - ( (int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_STABILIZED1 == (int) FLIGHTSTATUS_FLIGHTMODE_STABILIZED1) && \ - ( (int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_STABILIZED2 == (int) FLIGHTSTATUS_FLIGHTMODE_STABILIZED2) && \ - ( (int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_STABILIZED3 == (int) FLIGHTSTATUS_FLIGHTMODE_STABILIZED3) && \ - ( (int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_VELOCITYCONTROL == (int) FLIGHTSTATUS_FLIGHTMODE_VELOCITYCONTROL) && \ - ( (int)MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_POSITIONHOLD == (int) FLIGHTSTATUS_FLIGHTMODE_POSITIONHOLD) \ - ) - -#define assumptions (assumptions1 && assumptions3 && assumptions5 && assumptions7 && assumptions8 && assumptions_flightmode) - -/** - * Module initialization - */ -int32_t ManualControlInitialize() -{ - /* Check the assumptions about uavobject enum's are correct */ - if(!assumptions) - return -1; - // Start main task - xTaskCreate(manualControlTask, (signed char *)"ManualControl", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &taskHandle); - TaskMonitorAdd(TASKINFO_RUNNING_MANUALCONTROL, taskHandle); - PIOS_WDG_RegisterFlag(PIOS_WDG_MANUAL); - - - return 0; -} - -/** - * Module task - */ -static void manualControlTask(void *parameters) -{ - ManualControlSettingsData settings; - ManualControlCommandData cmd; - FlightStatusData flightStatus; - float flightMode = 0; - - uint8_t disconnected_count = 0; - uint8_t connected_count = 0; - - // Make sure unarmed on power up - ManualControlCommandGet(&cmd); - FlightStatusGet(&flightStatus); - flightStatus.Armed = FLIGHTSTATUS_ARMED_DISARMED; - armState = ARM_STATE_DISARMED; - - // Main task loop - lastSysTime = xTaskGetTickCount(); - while (1) { - float scaledChannel[MANUALCONTROLCOMMAND_CHANNEL_NUMELEM]; - - // Wait until next update - vTaskDelayUntil(&lastSysTime, UPDATE_PERIOD_MS / portTICK_RATE_MS); - PIOS_WDG_UpdateFlag(PIOS_WDG_MANUAL); - - // Read settings - ManualControlSettingsGet(&settings); - - if (ManualControlCommandReadOnly(&cmd)) { - FlightTelemetryStatsData flightTelemStats; - FlightTelemetryStatsGet(&flightTelemStats); - if(flightTelemStats.Status != FLIGHTTELEMETRYSTATS_STATUS_CONNECTED) { - /* trying to fly via GCS and lost connection. fall back to transmitter */ - UAVObjMetadata metadata; - UAVObjGetMetadata(&cmd, &metadata); - metadata.access = ACCESS_READWRITE; - UAVObjSetMetadata(&cmd, &metadata); - } - } - - if (!ManualControlCommandReadOnly(&cmd)) { - - // Read channel values in us - // TODO: settings.InputMode is currently ignored because PIOS will not allow runtime - // selection of PWM and PPM. The configuration is currently done at compile time in - // the pios_config.h file. - for (int n = 0; n < MANUALCONTROLCOMMAND_CHANNEL_NUMELEM; ++n) { -#if defined(PIOS_INCLUDE_PWM) - cmd.Channel[n] = PIOS_PWM_Get(n); -#elif defined(PIOS_INCLUDE_PPM) - cmd.Channel[n] = PIOS_PPM_Get(n); -#elif defined(PIOS_INCLUDE_SPEKTRUM) - cmd.Channel[n] = PIOS_SPEKTRUM_Get(n); -#endif - scaledChannel[n] = scaleChannel(cmd.Channel[n], settings.ChannelMax[n], settings.ChannelMin[n], settings.ChannelNeutral[n]); - } - - // Check settings, if error raise alarm - if (settings.Roll >= MANUALCONTROLSETTINGS_ROLL_NONE || - settings.Pitch >= MANUALCONTROLSETTINGS_PITCH_NONE || - settings.Yaw >= MANUALCONTROLSETTINGS_YAW_NONE || - settings.Throttle >= MANUALCONTROLSETTINGS_THROTTLE_NONE || - settings.FlightMode >= MANUALCONTROLSETTINGS_FLIGHTMODE_NONE) { - AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_CRITICAL); - cmd.Connected = MANUALCONTROLCOMMAND_CONNECTED_FALSE; - ManualControlCommandSet(&cmd); - continue; - } - - // decide if we have valid manual input or not - bool valid_input_detected = validInputRange(settings.ChannelMin[settings.Throttle], settings.ChannelMax[settings.Throttle], cmd.Channel[settings.Throttle]) && - validInputRange(settings.ChannelMin[settings.Roll], settings.ChannelMax[settings.Roll], cmd.Channel[settings.Roll]) && - validInputRange(settings.ChannelMin[settings.Yaw], settings.ChannelMax[settings.Yaw], cmd.Channel[settings.Yaw]) && - validInputRange(settings.ChannelMin[settings.Pitch], settings.ChannelMax[settings.Pitch], cmd.Channel[settings.Pitch]); - - // Implement hysteresis loop on connection status - if (valid_input_detected && (++connected_count > 10)) { - cmd.Connected = MANUALCONTROLCOMMAND_CONNECTED_TRUE; - connected_count = 0; - disconnected_count = 0; - } else if (!valid_input_detected && (++disconnected_count > 10)) { - cmd.Connected = MANUALCONTROLCOMMAND_CONNECTED_FALSE; - connected_count = 0; - disconnected_count = 0; - } - - if (cmd.Connected == MANUALCONTROLCOMMAND_CONNECTED_FALSE) { - cmd.Throttle = -1; // Shut down engine with no control - cmd.Roll = 0; - cmd.Yaw = 0; - cmd.Pitch = 0; - //cmd.FlightMode = MANUALCONTROLCOMMAND_FLIGHTMODE_AUTO; // don't do until AUTO implemented and functioning - // Important: Throttle < 0 will reset Stabilization coefficients among other things. Either change this, - // or leave throttle at IDLE speed or above when going into AUTO-failsafe. - AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING); - ManualControlCommandSet(&cmd); - } else { - AlarmsClear(SYSTEMALARMS_ALARM_MANUALCONTROL); - - // Scale channels to -1 -> +1 range - cmd.Roll = scaledChannel[settings.Roll]; - cmd.Pitch = scaledChannel[settings.Pitch]; - cmd.Yaw = scaledChannel[settings.Yaw]; - cmd.Throttle = scaledChannel[settings.Throttle]; - flightMode = scaledChannel[settings.FlightMode]; - - // Set accessory channels - cmd.Accessory1 = (settings.Accessory1 != MANUALCONTROLSETTINGS_ACCESSORY1_NONE) ? scaledChannel[settings.Accessory1] : 0; - cmd.Accessory2 = (settings.Accessory1 != MANUALCONTROLSETTINGS_ACCESSORY2_NONE) ? scaledChannel[settings.Accessory2] : 0; - cmd.Accessory3 = (settings.Accessory1 != MANUALCONTROLSETTINGS_ACCESSORY3_NONE) ? scaledChannel[settings.Accessory3] : 0; - - processFlightMode(&settings, flightMode); - processArm(&cmd, &settings); - - // Update cmd object - ManualControlCommandSet(&cmd); - - } - - } else { - ManualControlCommandGet(&cmd); /* Under GCS control */ - } - - - FlightStatusGet(&flightStatus); - - // Depending on the mode update the Stabilization or Actuator objects - switch(PARSE_FLIGHT_MODE(flightStatus.FlightMode)) { - case FLIGHTMODE_UNDEFINED: - // This reflects a bug in the code architecture! - AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_CRITICAL); - break; - case FLIGHTMODE_MANUAL: - updateActuatorDesired(&cmd); - break; - case FLIGHTMODE_STABILIZED: - updateStabilizationDesired(&cmd, &settings); - break; - case FLIGHTMODE_GUIDANCE: - // TODO: Implement - break; - } - } -} - -static void updateActuatorDesired(ManualControlCommandData * cmd) -{ - ActuatorDesiredData actuator; - ActuatorDesiredGet(&actuator); - actuator.Roll = cmd->Roll; - actuator.Pitch = cmd->Pitch; - actuator.Yaw = cmd->Yaw; - actuator.Throttle = (cmd->Throttle < 0) ? -1 : cmd->Throttle; - ActuatorDesiredSet(&actuator); -} - -static void updateStabilizationDesired(ManualControlCommandData * cmd, ManualControlSettingsData * settings) -{ - StabilizationDesiredData stabilization; - StabilizationDesiredGet(&stabilization); - - StabilizationSettingsData stabSettings; - StabilizationSettingsGet(&stabSettings); - - uint8_t * stab_settings; - FlightStatusData flightStatus; - FlightStatusGet(&flightStatus); - switch(flightStatus.FlightMode) { - case FLIGHTSTATUS_FLIGHTMODE_STABILIZED1: - stab_settings = settings->Stabilization1Settings; - break; - case FLIGHTSTATUS_FLIGHTMODE_STABILIZED2: - stab_settings = settings->Stabilization2Settings; - break; - case FLIGHTSTATUS_FLIGHTMODE_STABILIZED3: - stab_settings = settings->Stabilization3Settings; - break; - default: - // Major error, this should not occur because only enter this block when one of these is true - AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_CRITICAL); - return; - } - - // TOOD: Add assumption about order of stabilization desired and manual control stabilization mode fields having same order - stabilization.StabilizationMode[STABILIZATIONDESIRED_STABILIZATIONMODE_ROLL] = stab_settings[0]; - stabilization.StabilizationMode[STABILIZATIONDESIRED_STABILIZATIONMODE_PITCH] = stab_settings[1]; - stabilization.StabilizationMode[STABILIZATIONDESIRED_STABILIZATIONMODE_YAW] = stab_settings[2]; - - stabilization.Roll = (stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) ? cmd->Roll : - (stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) ? cmd->Roll * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_ROLL] : - (stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? cmd->Roll * stabSettings.RollMax : - 0; // this is an invalid mode - ; - stabilization.Pitch = (stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) ? cmd->Pitch : - (stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) ? cmd->Pitch * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_PITCH] : - (stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? cmd->Pitch * stabSettings.PitchMax : - 0; // this is an invalid mode - - stabilization.Yaw = (stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) ? cmd->Yaw : - (stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) ? cmd->Yaw * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_YAW] : - (stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? fmod(cmd->Yaw * 180.0, 360) : - 0; // this is an invalid mode - - stabilization.Throttle = (cmd->Throttle < 0) ? -1 : cmd->Throttle; - StabilizationDesiredSet(&stabilization); -} - -/** - * Convert channel from servo pulse duration (microseconds) to scaled -1/+1 range. - */ -static float scaleChannel(int16_t value, int16_t max, int16_t min, int16_t neutral) -{ - float valueScaled; - - // Scale - if ((max > min && value >= neutral) || (min > max && value <= neutral)) - { - if (max != neutral) - valueScaled = (float)(value - neutral) / (float)(max - neutral); - else - valueScaled = 0; - } - else - { - if (min != neutral) - valueScaled = (float)(value - neutral) / (float)(neutral - min); - else - valueScaled = 0; - } - - // Bound - if (valueScaled > 1.0) valueScaled = 1.0; - else - if (valueScaled < -1.0) valueScaled = -1.0; - - return valueScaled; -} - -static uint32_t timeDifferenceMs(portTickType start_time, portTickType end_time) { - if(end_time > start_time) - return (end_time - start_time) * portTICK_RATE_MS; - return ((((portTICK_RATE_MS) -1) - start_time) + end_time) * portTICK_RATE_MS; -} - -/** - * @brief Determine if the aircraft is safe to arm - * @returns True if safe to arm, false otherwise - */ -static bool okToArm(void) -{ - // read alarms - SystemAlarmsData alarms; - SystemAlarmsGet(&alarms); - - - // Check each alarm - for (int i = 0; i < SYSTEMALARMS_ALARM_NUMELEM; i++) - { - if (alarms.Alarm[i] >= SYSTEMALARMS_ALARM_ERROR) - { // found an alarm thats set - if (i == SYSTEMALARMS_ALARM_GPS || i == SYSTEMALARMS_ALARM_TELEMETRY) - continue; - - return false; - } - } - - return true; -} - -/** - * @brief Update the flightStatus object only if value changed. Reduces callbacks - * @param[in] val The new value - */ -static void setArmedIfChanged(uint8_t val) { - FlightStatusData flightStatus; - FlightStatusGet(&flightStatus); - - if(flightStatus.Armed != val) { - flightStatus.Armed = val; - FlightStatusSet(&flightStatus); - } -} - -/** - * @brief Process the inputs and determine whether to arm or not - * @param[out] cmd The structure to set the armed in - * @param[in] settings Settings indicating the necessary position - */ -static void processArm(ManualControlCommandData * cmd, ManualControlSettingsData * settings) -{ - - bool lowThrottle = cmd->Throttle <= 0; - - if (settings->Arming == MANUALCONTROLSETTINGS_ARMING_ALWAYSDISARMED) { - // In this configuration we always disarm - setArmedIfChanged(FLIGHTSTATUS_ARMED_DISARMED); - } else { - // Not really needed since this function not called when disconnected - if (cmd->Connected == MANUALCONTROLCOMMAND_CONNECTED_FALSE) - return; - - // The throttle is not low, in case we where arming or disarming, abort - if (!lowThrottle) { - switch(armState) { - case ARM_STATE_DISARMING_MANUAL: - case ARM_STATE_DISARMING_TIMEOUT: - armState = ARM_STATE_ARMED; - break; - case ARM_STATE_ARMING_MANUAL: - armState = ARM_STATE_DISARMED; - break; - default: - // Nothing needs to be done in the other states - break; - } - return; - } - - // The rest of these cases throttle is low - if (settings->Arming == MANUALCONTROLSETTINGS_ARMING_ALWAYSARMED) { - // In this configuration, we go into armed state as soon as the throttle is low, never disarm - setArmedIfChanged(FLIGHTSTATUS_ARMED_ARMED); - return; - } - - - // When the configuration is not "Always armed" and no "Always disarmed", - // the state will not be changed when the throttle is not low - static portTickType armedDisarmStart; - float armingInputLevel = 0; - - // Calc channel see assumptions7 - int8_t sign = ((settings->Arming-MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)%2) ? -1 : 1; - switch ( (settings->Arming-MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)/2 ) { - case ARMING_CHANNEL_ROLL: armingInputLevel = sign * cmd->Roll; break; - case ARMING_CHANNEL_PITCH: armingInputLevel = sign * cmd->Pitch; break; - case ARMING_CHANNEL_YAW: armingInputLevel = sign * cmd->Yaw; break; - } - - bool manualArm = false; - bool manualDisarm = false; - - if (armingInputLevel <= -ARMED_THRESHOLD) - manualArm = true; - else if (armingInputLevel >= +ARMED_THRESHOLD) - manualDisarm = true; - - switch(armState) { - case ARM_STATE_DISARMED: - setArmedIfChanged(FLIGHTSTATUS_ARMED_DISARMED); - - // only allow arming if it's OK too - if (manualArm && okToArm()) { - armedDisarmStart = lastSysTime; - armState = ARM_STATE_ARMING_MANUAL; - } - break; - - case ARM_STATE_ARMING_MANUAL: - setArmedIfChanged(FLIGHTSTATUS_ARMED_ARMING); - - if (manualArm && (timeDifferenceMs(armedDisarmStart, lastSysTime) > ARMED_TIME_MS)) - armState = ARM_STATE_ARMED; - else if (!manualArm) - armState = ARM_STATE_DISARMED; - break; - - case ARM_STATE_ARMED: - // When we get here, the throttle is low, - // we go immediately to disarming due to timeout, also when the disarming mechanism is not enabled - armedDisarmStart = lastSysTime; - armState = ARM_STATE_DISARMING_TIMEOUT; - setArmedIfChanged(FLIGHTSTATUS_ARMED_ARMED); - break; - - case ARM_STATE_DISARMING_TIMEOUT: - // We get here when armed while throttle low, even when the arming timeout is not enabled - if ((settings->ArmedTimeout != 0) && (timeDifferenceMs(armedDisarmStart, lastSysTime) > settings->ArmedTimeout)) - armState = ARM_STATE_DISARMED; - - // Switch to disarming due to manual control when needed - if (manualDisarm) { - armedDisarmStart = lastSysTime; - armState = ARM_STATE_DISARMING_MANUAL; - } - break; - - case ARM_STATE_DISARMING_MANUAL: - if (manualDisarm &&(timeDifferenceMs(armedDisarmStart, lastSysTime) > ARMED_TIME_MS)) - armState = ARM_STATE_DISARMED; - else if (!manualDisarm) - armState = ARM_STATE_ARMED; - break; - } // End Switch - } -} - -/** - * @brief Determine which of three positions the flight mode switch is in and set flight mode accordingly - * @param[out] cmd Pointer to the command structure to set the flight mode in - * @param[in] settings The settings which indicate which position is which mode - * @param[in] flightMode the value of the switch position - */ -static void processFlightMode(ManualControlSettingsData * settings, float flightMode) -{ - FlightStatusData flightStatus; - FlightStatusGet(&flightStatus); - - uint8_t newMode; - // Note here the code is ass - if (flightMode < -FLIGHT_MODE_LIMIT) - newMode = settings->FlightModePosition[0]; - else if (flightMode > FLIGHT_MODE_LIMIT) - newMode = settings->FlightModePosition[2]; - else - newMode = settings->FlightModePosition[1]; - - if(flightStatus.FlightMode != newMode) { - flightStatus.FlightMode = newMode; - FlightStatusSet(&flightStatus); - } - -} - -/** - * @brief Determine if the manual input value is within acceptable limits - * @returns return TRUE if so, otherwise return FALSE - */ -bool validInputRange(int16_t min, int16_t max, uint16_t value) -{ - if (min > max) - { - int16_t tmp = min; - min = max; - max = tmp; - } - return (value >= min - CONNECTION_OFFSET && value <= max + CONNECTION_OFFSET); -} - -/** - * @} - * @} - */ +/** + ****************************************************************************** + * @addtogroup OpenPilotModules OpenPilot Modules + * @{ + * @addtogroup ManualControlModule Manual Control Module + * @brief Provide manual control or allow it alter flight mode. + * @{ + * + * Reads in the ManualControlCommand FlightMode setting from receiver then either + * pass the settings straght to ActuatorDesired object (manual mode) or to + * AttitudeDesired object (stabilized mode) + * + * @file manualcontrol.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief ManualControl module. Handles safety R/C link and flight mode. + * + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "openpilot.h" +#include "manualcontrol.h" +#include "manualcontrolsettings.h" +#include "stabilizationsettings.h" +#include "manualcontrolcommand.h" +#include "actuatordesired.h" +#include "stabilizationdesired.h" +#include "flighttelemetrystats.h" +#include "flightstatus.h" +#include "accessorydesired.h" + +// Private constants +#if defined(PIOS_MANUAL_STACK_SIZE) +#define STACK_SIZE_BYTES PIOS_MANUAL_STACK_SIZE +#else +#define STACK_SIZE_BYTES 824 +#endif + +#define TASK_PRIORITY (tskIDLE_PRIORITY+4) +#define UPDATE_PERIOD_MS 20 +#define THROTTLE_FAILSAFE -0.1 +#define FLIGHT_MODE_LIMIT 1.0/3.0 +#define ARMED_TIME_MS 1000 +#define ARMED_THRESHOLD 0.50 +//safe band to allow a bit of calibration error or trim offset (in microseconds) +#define CONNECTION_OFFSET 150 + +// Private types +typedef enum +{ + ARM_STATE_DISARMED, + ARM_STATE_ARMING_MANUAL, + ARM_STATE_ARMED, + ARM_STATE_DISARMING_MANUAL, + ARM_STATE_DISARMING_TIMEOUT +} ArmState_t; + +// Private variables +static xTaskHandle taskHandle; +static ArmState_t armState; +static portTickType lastSysTime; + +// Private functions +static void updateActuatorDesired(ManualControlCommandData * cmd); +static void updateStabilizationDesired(ManualControlCommandData * cmd, ManualControlSettingsData * settings); +static void processFlightMode(ManualControlSettingsData * settings, float flightMode); +static void processArm(ManualControlCommandData * cmd, ManualControlSettingsData * settings); + +static void manualControlTask(void *parameters); +static float scaleChannel(int16_t value, int16_t max, int16_t min, int16_t neutral); +static uint32_t timeDifferenceMs(portTickType start_time, portTickType end_time); +static bool okToArm(void); +static bool validInputRange(int16_t min, int16_t max, uint16_t value); + +#define assumptions (assumptions1 && assumptions3 && assumptions5 && assumptions7 && assumptions8 && assumptions_flightmode) + +/** + * Module starting + */ +int32_t ManualControlStart() +{ + // Start main task + xTaskCreate(manualControlTask, (signed char *)"ManualControl", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &taskHandle); + TaskMonitorAdd(TASKINFO_RUNNING_MANUALCONTROL, taskHandle); + PIOS_WDG_RegisterFlag(PIOS_WDG_MANUAL); + + return 0; +} + +/** + * Module initialization + */ +int32_t ManualControlInitialize() +{ + + /* Check the assumptions about uavobject enum's are correct */ + if(!assumptions) + return -1; + + AccessoryDesiredInitialize(); + ManualControlCommandInitialize(); + FlightStatusInitialize(); + StabilizationDesiredInitialize(); + + ManualControlSettingsInitialize(); + + return 0; +} +MODULE_INITCALL(ManualControlInitialize, ManualControlStart) + +/** + * Module task + */ +static void manualControlTask(void *parameters) +{ + ManualControlSettingsData settings; + ManualControlCommandData cmd; + FlightStatusData flightStatus; + float flightMode = 0; + + uint8_t disconnected_count = 0; + uint8_t connected_count = 0; + + // For now manual instantiate extra instances of Accessory Desired. In future should be done dynamically + // this includes not even registering it if not used + AccessoryDesiredCreateInstance(); + AccessoryDesiredCreateInstance(); + + // Make sure unarmed on power up + ManualControlCommandGet(&cmd); + FlightStatusGet(&flightStatus); + flightStatus.Armed = FLIGHTSTATUS_ARMED_DISARMED; + armState = ARM_STATE_DISARMED; + + // Main task loop + lastSysTime = xTaskGetTickCount(); + while (1) { + float scaledChannel[MANUALCONTROLCOMMAND_CHANNEL_NUMELEM]; + + // Wait until next update + vTaskDelayUntil(&lastSysTime, UPDATE_PERIOD_MS / portTICK_RATE_MS); + PIOS_WDG_UpdateFlag(PIOS_WDG_MANUAL); + + // Read settings + ManualControlSettingsGet(&settings); + + if (ManualControlCommandReadOnly(&cmd)) { + FlightTelemetryStatsData flightTelemStats; + FlightTelemetryStatsGet(&flightTelemStats); + if(flightTelemStats.Status != FLIGHTTELEMETRYSTATS_STATUS_CONNECTED) { + /* trying to fly via GCS and lost connection. fall back to transmitter */ + UAVObjMetadata metadata; + UAVObjGetMetadata(&cmd, &metadata); + metadata.access = ACCESS_READWRITE; + UAVObjSetMetadata(&cmd, &metadata); + } + } + + if (!ManualControlCommandReadOnly(&cmd)) { + + // Read channel values in us + for (int n = 0; n < MANUALCONTROLCOMMAND_CHANNEL_NUMELEM; ++n) { + if (pios_rcvr_channel_to_id_map[n].id) { + cmd.Channel[n] = PIOS_RCVR_Read(pios_rcvr_channel_to_id_map[n].id, + pios_rcvr_channel_to_id_map[n].channel); + } else { + cmd.Channel[n] = -1; + } + scaledChannel[n] = scaleChannel(cmd.Channel[n], settings.ChannelMax[n], settings.ChannelMin[n], settings.ChannelNeutral[n]); + } + + // Check settings, if error raise alarm + if (settings.Roll >= MANUALCONTROLSETTINGS_ROLL_NONE || + settings.Pitch >= MANUALCONTROLSETTINGS_PITCH_NONE || + settings.Yaw >= MANUALCONTROLSETTINGS_YAW_NONE || + settings.Throttle >= MANUALCONTROLSETTINGS_THROTTLE_NONE || + settings.FlightMode >= MANUALCONTROLSETTINGS_FLIGHTMODE_NONE) { + AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_CRITICAL); + cmd.Connected = MANUALCONTROLCOMMAND_CONNECTED_FALSE; + ManualControlCommandSet(&cmd); + continue; + } + + // decide if we have valid manual input or not + bool valid_input_detected = validInputRange(settings.ChannelMin[settings.Throttle], settings.ChannelMax[settings.Throttle], cmd.Channel[settings.Throttle]) && + validInputRange(settings.ChannelMin[settings.Roll], settings.ChannelMax[settings.Roll], cmd.Channel[settings.Roll]) && + validInputRange(settings.ChannelMin[settings.Yaw], settings.ChannelMax[settings.Yaw], cmd.Channel[settings.Yaw]) && + validInputRange(settings.ChannelMin[settings.Pitch], settings.ChannelMax[settings.Pitch], cmd.Channel[settings.Pitch]); + + // Implement hysteresis loop on connection status + if (valid_input_detected && (++connected_count > 10)) { + cmd.Connected = MANUALCONTROLCOMMAND_CONNECTED_TRUE; + connected_count = 0; + disconnected_count = 0; + } else if (!valid_input_detected && (++disconnected_count > 10)) { + cmd.Connected = MANUALCONTROLCOMMAND_CONNECTED_FALSE; + connected_count = 0; + disconnected_count = 0; + } + + if (cmd.Connected == MANUALCONTROLCOMMAND_CONNECTED_FALSE) { + cmd.Throttle = -1; // Shut down engine with no control + cmd.Roll = 0; + cmd.Yaw = 0; + cmd.Pitch = 0; + //cmd.FlightMode = MANUALCONTROLCOMMAND_FLIGHTMODE_AUTO; // don't do until AUTO implemented and functioning + // Important: Throttle < 0 will reset Stabilization coefficients among other things. Either change this, + // or leave throttle at IDLE speed or above when going into AUTO-failsafe. + AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING); + ManualControlCommandSet(&cmd); + } else { + AlarmsClear(SYSTEMALARMS_ALARM_MANUALCONTROL); + + // Scale channels to -1 -> +1 range + cmd.Roll = scaledChannel[settings.Roll]; + cmd.Pitch = scaledChannel[settings.Pitch]; + cmd.Yaw = scaledChannel[settings.Yaw]; + cmd.Throttle = scaledChannel[settings.Throttle]; + flightMode = scaledChannel[settings.FlightMode]; + + AccessoryDesiredData accessory; + // Set Accessory 0 + if(settings.Accessory0 != MANUALCONTROLSETTINGS_ACCESSORY0_NONE) { + accessory.AccessoryVal = scaledChannel[settings.Accessory0]; + if(AccessoryDesiredInstSet(0, &accessory) != 0) + AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING); + } + // Set Accessory 1 + if(settings.Accessory1 != MANUALCONTROLSETTINGS_ACCESSORY1_NONE) { + accessory.AccessoryVal = scaledChannel[settings.Accessory1]; + if(AccessoryDesiredInstSet(1, &accessory) != 0) + AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING); + } + // Set Accsesory 2 + if(settings.Accessory2 != MANUALCONTROLSETTINGS_ACCESSORY2_NONE) { + accessory.AccessoryVal = scaledChannel[settings.Accessory2]; + if(AccessoryDesiredInstSet(2, &accessory) != 0) + AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_WARNING); + } + + + processFlightMode(&settings, flightMode); + processArm(&cmd, &settings); + + // Update cmd object + ManualControlCommandSet(&cmd); + + } + + } else { + ManualControlCommandGet(&cmd); /* Under GCS control */ + } + + + FlightStatusGet(&flightStatus); + + // Depending on the mode update the Stabilization or Actuator objects + switch(PARSE_FLIGHT_MODE(flightStatus.FlightMode)) { + case FLIGHTMODE_UNDEFINED: + // This reflects a bug in the code architecture! + AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_CRITICAL); + break; + case FLIGHTMODE_MANUAL: + updateActuatorDesired(&cmd); + break; + case FLIGHTMODE_STABILIZED: + updateStabilizationDesired(&cmd, &settings); + break; + case FLIGHTMODE_GUIDANCE: + // TODO: Implement + break; + } + } +} + +static void updateActuatorDesired(ManualControlCommandData * cmd) +{ + ActuatorDesiredData actuator; + ActuatorDesiredGet(&actuator); + actuator.Roll = cmd->Roll; + actuator.Pitch = cmd->Pitch; + actuator.Yaw = cmd->Yaw; + actuator.Throttle = (cmd->Throttle < 0) ? -1 : cmd->Throttle; + ActuatorDesiredSet(&actuator); +} + +static void updateStabilizationDesired(ManualControlCommandData * cmd, ManualControlSettingsData * settings) +{ + StabilizationDesiredData stabilization; + StabilizationDesiredGet(&stabilization); + + StabilizationSettingsData stabSettings; + StabilizationSettingsGet(&stabSettings); + + uint8_t * stab_settings; + FlightStatusData flightStatus; + FlightStatusGet(&flightStatus); + switch(flightStatus.FlightMode) { + case FLIGHTSTATUS_FLIGHTMODE_STABILIZED1: + stab_settings = settings->Stabilization1Settings; + break; + case FLIGHTSTATUS_FLIGHTMODE_STABILIZED2: + stab_settings = settings->Stabilization2Settings; + break; + case FLIGHTSTATUS_FLIGHTMODE_STABILIZED3: + stab_settings = settings->Stabilization3Settings; + break; + default: + // Major error, this should not occur because only enter this block when one of these is true + AlarmsSet(SYSTEMALARMS_ALARM_MANUALCONTROL, SYSTEMALARMS_ALARM_CRITICAL); + return; + } + + // TOOD: Add assumption about order of stabilization desired and manual control stabilization mode fields having same order + stabilization.StabilizationMode[STABILIZATIONDESIRED_STABILIZATIONMODE_ROLL] = stab_settings[0]; + stabilization.StabilizationMode[STABILIZATIONDESIRED_STABILIZATIONMODE_PITCH] = stab_settings[1]; + stabilization.StabilizationMode[STABILIZATIONDESIRED_STABILIZATIONMODE_YAW] = stab_settings[2]; + + stabilization.Roll = (stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) ? cmd->Roll : + (stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) ? cmd->Roll * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_ROLL] : + (stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) ? cmd->Roll * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_ROLL] : + (stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? cmd->Roll * stabSettings.RollMax : + (stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) ? cmd->Roll * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_ROLL] : + 0; // this is an invalid mode + ; + stabilization.Pitch = (stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) ? cmd->Pitch : + (stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) ? cmd->Pitch * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_PITCH] : + (stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) ? cmd->Pitch * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_PITCH] : + (stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? cmd->Pitch * stabSettings.PitchMax : + (stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) ? cmd->Pitch * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_PITCH] : + 0; // this is an invalid mode + + stabilization.Yaw = (stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) ? cmd->Yaw : + (stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) ? cmd->Yaw * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_YAW] : + (stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) ? cmd->Yaw * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_YAW] : + (stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? cmd->Yaw * stabSettings.YawMax : + (stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) ? cmd->Yaw * stabSettings.ManualRate[STABILIZATIONSETTINGS_MANUALRATE_YAW] : + 0; // this is an invalid mode + + stabilization.Throttle = (cmd->Throttle < 0) ? -1 : cmd->Throttle; + StabilizationDesiredSet(&stabilization); +} + +/** + * Convert channel from servo pulse duration (microseconds) to scaled -1/+1 range. + */ +static float scaleChannel(int16_t value, int16_t max, int16_t min, int16_t neutral) +{ + float valueScaled; + + // Scale + if ((max > min && value >= neutral) || (min > max && value <= neutral)) + { + if (max != neutral) + valueScaled = (float)(value - neutral) / (float)(max - neutral); + else + valueScaled = 0; + } + else + { + if (min != neutral) + valueScaled = (float)(value - neutral) / (float)(neutral - min); + else + valueScaled = 0; + } + + // Bound + if (valueScaled > 1.0) valueScaled = 1.0; + else + if (valueScaled < -1.0) valueScaled = -1.0; + + return valueScaled; +} + +static uint32_t timeDifferenceMs(portTickType start_time, portTickType end_time) { + if(end_time > start_time) + return (end_time - start_time) * portTICK_RATE_MS; + return ((((portTICK_RATE_MS) -1) - start_time) + end_time) * portTICK_RATE_MS; +} + +/** + * @brief Determine if the aircraft is safe to arm + * @returns True if safe to arm, false otherwise + */ +static bool okToArm(void) +{ + // read alarms + SystemAlarmsData alarms; + SystemAlarmsGet(&alarms); + + + // Check each alarm + for (int i = 0; i < SYSTEMALARMS_ALARM_NUMELEM; i++) + { + if (alarms.Alarm[i] >= SYSTEMALARMS_ALARM_ERROR) + { // found an alarm thats set + if (i == SYSTEMALARMS_ALARM_GPS || i == SYSTEMALARMS_ALARM_TELEMETRY) + continue; + + return false; + } + } + + return true; +} + +/** + * @brief Update the flightStatus object only if value changed. Reduces callbacks + * @param[in] val The new value + */ +static void setArmedIfChanged(uint8_t val) { + FlightStatusData flightStatus; + FlightStatusGet(&flightStatus); + + if(flightStatus.Armed != val) { + flightStatus.Armed = val; + FlightStatusSet(&flightStatus); + } +} + +/** + * @brief Process the inputs and determine whether to arm or not + * @param[out] cmd The structure to set the armed in + * @param[in] settings Settings indicating the necessary position + */ +static void processArm(ManualControlCommandData * cmd, ManualControlSettingsData * settings) +{ + + bool lowThrottle = cmd->Throttle <= 0; + + if (settings->Arming == MANUALCONTROLSETTINGS_ARMING_ALWAYSDISARMED) { + // In this configuration we always disarm + setArmedIfChanged(FLIGHTSTATUS_ARMED_DISARMED); + } else { + // Not really needed since this function not called when disconnected + if (cmd->Connected == MANUALCONTROLCOMMAND_CONNECTED_FALSE) + return; + + // The throttle is not low, in case we where arming or disarming, abort + if (!lowThrottle) { + switch(armState) { + case ARM_STATE_DISARMING_MANUAL: + case ARM_STATE_DISARMING_TIMEOUT: + armState = ARM_STATE_ARMED; + break; + case ARM_STATE_ARMING_MANUAL: + armState = ARM_STATE_DISARMED; + break; + default: + // Nothing needs to be done in the other states + break; + } + return; + } + + // The rest of these cases throttle is low + if (settings->Arming == MANUALCONTROLSETTINGS_ARMING_ALWAYSARMED) { + // In this configuration, we go into armed state as soon as the throttle is low, never disarm + setArmedIfChanged(FLIGHTSTATUS_ARMED_ARMED); + return; + } + + + // When the configuration is not "Always armed" and no "Always disarmed", + // the state will not be changed when the throttle is not low + static portTickType armedDisarmStart; + float armingInputLevel = 0; + + // Calc channel see assumptions7 + int8_t sign = ((settings->Arming-MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)%2) ? -1 : 1; + switch ( (settings->Arming-MANUALCONTROLSETTINGS_ARMING_ROLLLEFT)/2 ) { + case ARMING_CHANNEL_ROLL: armingInputLevel = sign * cmd->Roll; break; + case ARMING_CHANNEL_PITCH: armingInputLevel = sign * cmd->Pitch; break; + case ARMING_CHANNEL_YAW: armingInputLevel = sign * cmd->Yaw; break; + } + + bool manualArm = false; + bool manualDisarm = false; + + if (armingInputLevel <= -ARMED_THRESHOLD) + manualArm = true; + else if (armingInputLevel >= +ARMED_THRESHOLD) + manualDisarm = true; + + switch(armState) { + case ARM_STATE_DISARMED: + setArmedIfChanged(FLIGHTSTATUS_ARMED_DISARMED); + + // only allow arming if it's OK too + if (manualArm && okToArm()) { + armedDisarmStart = lastSysTime; + armState = ARM_STATE_ARMING_MANUAL; + } + break; + + case ARM_STATE_ARMING_MANUAL: + setArmedIfChanged(FLIGHTSTATUS_ARMED_ARMING); + + if (manualArm && (timeDifferenceMs(armedDisarmStart, lastSysTime) > ARMED_TIME_MS)) + armState = ARM_STATE_ARMED; + else if (!manualArm) + armState = ARM_STATE_DISARMED; + break; + + case ARM_STATE_ARMED: + // When we get here, the throttle is low, + // we go immediately to disarming due to timeout, also when the disarming mechanism is not enabled + armedDisarmStart = lastSysTime; + armState = ARM_STATE_DISARMING_TIMEOUT; + setArmedIfChanged(FLIGHTSTATUS_ARMED_ARMED); + break; + + case ARM_STATE_DISARMING_TIMEOUT: + // We get here when armed while throttle low, even when the arming timeout is not enabled + if ((settings->ArmedTimeout != 0) && (timeDifferenceMs(armedDisarmStart, lastSysTime) > settings->ArmedTimeout)) + armState = ARM_STATE_DISARMED; + + // Switch to disarming due to manual control when needed + if (manualDisarm) { + armedDisarmStart = lastSysTime; + armState = ARM_STATE_DISARMING_MANUAL; + } + break; + + case ARM_STATE_DISARMING_MANUAL: + if (manualDisarm &&(timeDifferenceMs(armedDisarmStart, lastSysTime) > ARMED_TIME_MS)) + armState = ARM_STATE_DISARMED; + else if (!manualDisarm) + armState = ARM_STATE_ARMED; + break; + } // End Switch + } +} + +/** + * @brief Determine which of three positions the flight mode switch is in and set flight mode accordingly + * @param[out] cmd Pointer to the command structure to set the flight mode in + * @param[in] settings The settings which indicate which position is which mode + * @param[in] flightMode the value of the switch position + */ +static void processFlightMode(ManualControlSettingsData * settings, float flightMode) +{ + FlightStatusData flightStatus; + FlightStatusGet(&flightStatus); + + uint8_t newMode; + // Note here the code is ass + if (flightMode < -FLIGHT_MODE_LIMIT) + newMode = settings->FlightModePosition[0]; + else if (flightMode > FLIGHT_MODE_LIMIT) + newMode = settings->FlightModePosition[2]; + else + newMode = settings->FlightModePosition[1]; + + if(flightStatus.FlightMode != newMode) { + flightStatus.FlightMode = newMode; + FlightStatusSet(&flightStatus); + } + +} + +/** + * @brief Determine if the manual input value is within acceptable limits + * @returns return TRUE if so, otherwise return FALSE + */ +bool validInputRange(int16_t min, int16_t max, uint16_t value) +{ + if (min > max) + { + int16_t tmp = min; + min = max; + max = tmp; + } + return (value >= min - CONNECTION_OFFSET && value <= max + CONNECTION_OFFSET); +} + +/** + * @} + * @} + */ diff --git a/flight/Modules/Stabilization/stabilization.c b/flight/Modules/Stabilization/stabilization.c index 702020966..7142c9770 100644 --- a/flight/Modules/Stabilization/stabilization.c +++ b/flight/Modules/Stabilization/stabilization.c @@ -40,8 +40,6 @@ #include "attitudeactual.h" #include "attituderaw.h" #include "flightstatus.h" -#include "systemsettings.h" -#include "ahrssettings.h" #include "manualcontrol.h" // Just to get a macro #include "CoordinateConversions.h" @@ -77,6 +75,15 @@ static xTaskHandle taskHandle; static StabilizationSettingsData settings; static xQueueHandle queue; float dT = 1; +float gyro_alpha = 0; +float gyro_filtered[3] = {0,0,0}; +float axis_lock_accum[3] = {0,0,0}; +uint8_t max_axis_lock = 0; +uint8_t max_axislock_rate = 0; +float weak_leveling_kp = 0; +uint8_t weak_leveling_max = 0; +bool lowThrottleZeroIntegral; + pid_type pids[PID_MAX]; // Private functions @@ -89,27 +96,45 @@ static void SettingsUpdatedCb(UAVObjEvent * ev); /** * Module initialization */ -int32_t StabilizationInitialize() +int32_t StabilizationStart() { // Initialize variables - - // Create object queue - queue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(UAVObjEvent)); - - // Listen for updates. - // AttitudeActualConnectQueue(queue); - AttitudeRawConnectQueue(queue); - - StabilizationSettingsConnectCallback(SettingsUpdatedCb); - SettingsUpdatedCb(StabilizationSettingsHandle()); + // Start main task xTaskCreate(stabilizationTask, (signed char*)"Stabilization", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &taskHandle); TaskMonitorAdd(TASKINFO_RUNNING_STABILIZATION, taskHandle); PIOS_WDG_RegisterFlag(PIOS_WDG_STABILIZATION); - return 0; } +/** + * Module initialization + */ +int32_t StabilizationInitialize() +{ + // Initialize variables + StabilizationSettingsInitialize(); + ActuatorDesiredInitialize(); +#if defined(DIAGNOSTICS) + RateDesiredInitialize(); +#endif + + // Create object queue + queue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(UAVObjEvent)); + + // Listen for updates. + // AttitudeActualConnectQueue(queue); + AttitudeRawConnectQueue(queue); + + StabilizationSettingsConnectCallback(SettingsUpdatedCb); + SettingsUpdatedCb(StabilizationSettingsHandle()); + // Start main task + + return 0; +} + +MODULE_INITCALL(StabilizationInitialize, StabilizationStart) + /** * Module task */ @@ -118,43 +143,44 @@ static void stabilizationTask(void* parameters) portTickType lastSysTime; portTickType thisSysTime; UAVObjEvent ev; - - + + ActuatorDesiredData actuatorDesired; StabilizationDesiredData stabDesired; RateDesiredData rateDesired; AttitudeActualData attitudeActual; AttitudeRawData attitudeRaw; - SystemSettingsData systemSettings; FlightStatusData flightStatus; - + SettingsUpdatedCb((UAVObjEvent *) NULL); - + // Main task loop lastSysTime = xTaskGetTickCount(); ZeroPids(); while(1) { PIOS_WDG_UpdateFlag(PIOS_WDG_STABILIZATION); - + // Wait until the AttitudeRaw object is updated, if a timeout then go to failsafe if ( xQueueReceive(queue, &ev, FAILSAFE_TIMEOUT_MS / portTICK_RATE_MS) != pdTRUE ) { AlarmsSet(SYSTEMALARMS_ALARM_STABILIZATION,SYSTEMALARMS_ALARM_WARNING); continue; - } - + } + // Check how long since last update thisSysTime = xTaskGetTickCount(); if(thisSysTime > lastSysTime) // reuse dt in case of wraparound dT = (thisSysTime - lastSysTime) / portTICK_RATE_MS / 1000.0f; lastSysTime = thisSysTime; - + FlightStatusGet(&flightStatus); StabilizationDesiredGet(&stabDesired); AttitudeActualGet(&attitudeActual); AttitudeRawGet(&attitudeRaw); + +#if defined(DIAGNOSTICS) RateDesiredGet(&rateDesired); - SystemSettingsGet(&systemSettings); +#endif #if defined(PIOS_QUATERNION_STABILIZATION) // Quaternion calculation of error in each axis. Uses more memory. @@ -162,11 +188,11 @@ static void stabilizationTask(void* parameters) float q_desired[4]; float q_error[4]; float local_error[3]; - + // Essentially zero errors for anything in rate or none if(stabDesired.StabilizationMode[STABILIZATIONDESIRED_STABILIZATIONMODE_ROLL] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) - rpy_desired[0] = stabDesired.Roll; - else + rpy_desired[0] = stabDesired.Roll; + else rpy_desired[0] = attitudeActual.Roll; if(stabDesired.StabilizationMode[STABILIZATIONDESIRED_STABILIZATIONMODE_PITCH] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) @@ -178,13 +204,13 @@ static void stabilizationTask(void* parameters) rpy_desired[2] = stabDesired.Yaw; else rpy_desired[2] = attitudeActual.Yaw; - + RPY2Quaternion(rpy_desired, q_desired); quat_inverse(q_desired); quat_mult(q_desired, &attitudeActual.q1, q_error); quat_inverse(q_error); Quaternion2RPY(q_error, local_error); - + #else // Simpler algorithm for CC, less memory float local_error[3] = {stabDesired.Roll - attitudeActual.Roll, @@ -192,49 +218,85 @@ static void stabilizationTask(void* parameters) stabDesired.Yaw - attitudeActual.Yaw}; local_error[2] = fmod(local_error[2] + 180, 360) - 180; #endif - + + + for(uint8_t i = 0; i < MAX_AXES; i++) { + gyro_filtered[i] = gyro_filtered[i] * gyro_alpha + attitudeRaw.gyros[i] * (1 - gyro_alpha); + } + float *attitudeDesiredAxis = &stabDesired.Roll; float *actuatorDesiredAxis = &actuatorDesired.Roll; float *rateDesiredAxis = &rateDesired.Roll; - + //Calculate desired rate - for(int8_t ct=0; ct< MAX_AXES; ct++) + for(uint8_t i=0; i< MAX_AXES; i++) { - switch(stabDesired.StabilizationMode[ct]) + switch(stabDesired.StabilizationMode[i]) { case STABILIZATIONDESIRED_STABILIZATIONMODE_RATE: - rateDesiredAxis[ct] = attitudeDesiredAxis[ct]; + rateDesiredAxis[i] = attitudeDesiredAxis[i]; + axis_lock_accum[i] = 0; break; - + + case STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING: + { + float weak_leveling = local_error[i] * weak_leveling_kp; + + if(weak_leveling > weak_leveling_max) + weak_leveling = weak_leveling_max; + if(weak_leveling < -weak_leveling_max) + weak_leveling = -weak_leveling_max; + + rateDesiredAxis[i] = attitudeDesiredAxis[i] + weak_leveling; + + axis_lock_accum[i] = 0; + break; + } case STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE: - rateDesiredAxis[ct] = ApplyPid(&pids[PID_ROLL + ct], local_error[ct]); + rateDesiredAxis[i] = ApplyPid(&pids[PID_ROLL + i], local_error[i]); + axis_lock_accum[i] = 0; + break; + + case STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK: + if(fabs(attitudeDesiredAxis[i]) > max_axislock_rate) { + // While getting strong commands act like rate mode + rateDesiredAxis[i] = attitudeDesiredAxis[i]; + axis_lock_accum[i] = 0; + } else { + // For weaker commands or no command simply attitude lock (almost) on no gyro change + axis_lock_accum[i] += (attitudeDesiredAxis[i] - gyro_filtered[i]) * dT; + if(axis_lock_accum[i] > max_axis_lock) + axis_lock_accum[i] = max_axis_lock; + else if(axis_lock_accum[i] < -max_axis_lock) + axis_lock_accum[i] = -max_axis_lock; + + rateDesiredAxis[i] = ApplyPid(&pids[PID_ROLL + i], axis_lock_accum[i]); + } break; } } - + uint8_t shouldUpdate = 1; +#if defined(DIAGNOSTICS) RateDesiredSet(&rateDesired); +#endif ActuatorDesiredGet(&actuatorDesired); //Calculate desired command for(int8_t ct=0; ct< MAX_AXES; ct++) { - if(fabs(rateDesiredAxis[ct]) > settings.MaximumRate[ct]) - { - if(rateDesiredAxis[ct] > 0) - { - rateDesiredAxis[ct] = settings.MaximumRate[ct]; - }else - { - rateDesiredAxis[ct] = -settings.MaximumRate[ct]; - } - - } + if(rateDesiredAxis[ct] > settings.MaximumRate[ct]) + rateDesiredAxis[ct] = settings.MaximumRate[ct]; + else if(rateDesiredAxis[ct] < -settings.MaximumRate[ct]) + rateDesiredAxis[ct] = -settings.MaximumRate[ct]; + switch(stabDesired.StabilizationMode[ct]) { case STABILIZATIONDESIRED_STABILIZATIONMODE_RATE: case STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE: + case STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK: + case STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING: { - float command = ApplyPid(&pids[PID_RATE_ROLL + ct], rateDesiredAxis[ct]-attitudeRaw.gyros[ct]); + float command = ApplyPid(&pids[PID_RATE_ROLL + ct], rateDesiredAxis[ct] - gyro_filtered[ct]); actuatorDesiredAxis[ct] = bound(command); break; } @@ -255,16 +317,16 @@ static void stabilizationTask(void* parameters) break; } break; - + } } - + // Save dT actuatorDesired.UpdateTime = dT * 1000; - + if(PARSE_FLIGHT_MODE(flightStatus.FlightMode) == FLIGHTMODE_MANUAL) shouldUpdate = 0; - + if(shouldUpdate) { actuatorDesired.Throttle = stabDesired.Throttle; @@ -272,16 +334,17 @@ static void stabilizationTask(void* parameters) actuatorDesired.NumLongUpdates++; ActuatorDesiredSet(&actuatorDesired); } - + if(flightStatus.Armed != FLIGHTSTATUS_ARMED_ARMED || - !shouldUpdate || (stabDesired.Throttle < 0)) + (lowThrottleZeroIntegral && stabDesired.Throttle < 0) || + !shouldUpdate) { ZeroPids(); } - - + + // Clear alarms - AlarmsClear(SYSTEMALARMS_ALARM_STABILIZATION); + AlarmsClear(SYSTEMALARMS_ALARM_STABILIZATION); } } @@ -289,15 +352,15 @@ float ApplyPid(pid_type * pid, const float err) { float diff = (err - pid->lastErr); pid->lastErr = err; - pid->iAccumulator += err * pid->i * dT; - if(fabs(pid->iAccumulator) > pid->iLim) { - if(pid->iAccumulator >0) { - pid->iAccumulator = pid->iLim; - } else { - pid->iAccumulator = -pid->iLim; - } + + // Scale up accumulator by 1000 while computing to avoid losing precision + pid->iAccumulator += err * (pid->i * dT * 1000); + if(pid->iAccumulator > (pid->iLim * 1000)) { + pid->iAccumulator = pid->iLim * 1000; + } else if (pid->iAccumulator < -(pid->iLim * 1000)) { + pid->iAccumulator = -pid->iLim * 1000; } - return ((err * pid->p) + pid->iAccumulator + (diff * pid->d / dT)); + return ((err * pid->p) + pid->iAccumulator / 1000 + (diff * pid->d / dT)); } @@ -307,6 +370,8 @@ static void ZeroPids(void) pids[ct].iAccumulator = 0; pids[ct].lastErr = 0; } + for(uint8_t i = 0; i < 3; i++) + axis_lock_accum[i] = 0; } @@ -328,14 +393,61 @@ static void SettingsUpdatedCb(UAVObjEvent * ev) { memset(pids,0,sizeof (pid_type) * PID_MAX); StabilizationSettingsGet(&settings); - - float * data = settings.RollRatePI; - for(int8_t pid=0; pid < PID_MAX; pid++) - { - pids[pid].p = *data++; - pids[pid].i = *data++; - pids[pid].iLim = *data++; - } + + // Set the roll rate PID constants + pids[0].p = settings.RollRatePID[STABILIZATIONSETTINGS_ROLLRATEPID_KP]; + pids[0].i = settings.RollRatePID[STABILIZATIONSETTINGS_ROLLRATEPID_KI]; + pids[0].d = settings.RollRatePID[STABILIZATIONSETTINGS_ROLLRATEPID_KD]; + pids[0].iLim = settings.RollRatePID[STABILIZATIONSETTINGS_ROLLRATEPID_ILIMIT]; + + // Set the pitch rate PID constants + pids[1].p = settings.PitchRatePID[STABILIZATIONSETTINGS_PITCHRATEPID_KP]; + pids[1].i = settings.PitchRatePID[STABILIZATIONSETTINGS_PITCHRATEPID_KI]; + pids[1].d = settings.PitchRatePID[STABILIZATIONSETTINGS_PITCHRATEPID_KD]; + pids[1].iLim = settings.PitchRatePID[STABILIZATIONSETTINGS_PITCHRATEPID_ILIMIT]; + + // Set the yaw rate PID constants + pids[2].p = settings.YawRatePID[STABILIZATIONSETTINGS_YAWRATEPID_KP]; + pids[2].i = settings.YawRatePID[STABILIZATIONSETTINGS_YAWRATEPID_KI]; + pids[2].d = settings.YawRatePID[STABILIZATIONSETTINGS_YAWRATEPID_KD]; + pids[2].iLim = settings.YawRatePID[STABILIZATIONSETTINGS_YAWRATEPID_ILIMIT]; + + // Set the roll attitude PI constants + pids[3].p = settings.RollPI[STABILIZATIONSETTINGS_ROLLPI_KP]; + pids[3].i = settings.RollPI[STABILIZATIONSETTINGS_ROLLPI_KI]; + pids[3].iLim = settings.RollPI[STABILIZATIONSETTINGS_ROLLPI_ILIMIT]; + + // Set the pitch attitude PI constants + pids[4].p = settings.PitchPI[STABILIZATIONSETTINGS_PITCHPI_KP]; + pids[4].i = settings.PitchPI[STABILIZATIONSETTINGS_PITCHPI_KI]; + pids[4].iLim = settings.PitchPI[STABILIZATIONSETTINGS_PITCHPI_ILIMIT]; + + // Set the yaw attitude PI constants + pids[5].p = settings.YawPI[STABILIZATIONSETTINGS_YAWPI_KP]; + pids[5].i = settings.YawPI[STABILIZATIONSETTINGS_YAWPI_KI]; + pids[5].iLim = settings.YawPI[STABILIZATIONSETTINGS_YAWPI_ILIMIT]; + + // Maximum deviation to accumulate for axis lock + max_axis_lock = settings.MaxAxisLock; + max_axislock_rate = settings.MaxAxisLockRate; + + // Settings for weak leveling + weak_leveling_kp = settings.WeakLevelingKp; + weak_leveling_max = settings.MaxWeakLevelingRate; + + // Whether to zero the PID integrals while throttle is low + lowThrottleZeroIntegral = settings.LowThrottleZeroIntegral == STABILIZATIONSETTINGS_LOWTHROTTLEZEROINTEGRAL_TRUE; + + // The dT has some jitter iteration to iteration that we don't want to + // make thie result unpredictable. Still, it's nicer to specify the constant + // based on a time (in ms) rather than a fixed multiplier. The error between + // update rates on OP (~300 Hz) and CC (~475 Hz) is negligible for this + // calculation + const float fakeDt = 0.0025; + if(settings.GyroTau < 0.0001) + gyro_alpha = 0; // not trusting this to resolve to 0 + else + gyro_alpha = exp(-fakeDt / settings.GyroTau); } diff --git a/flight/Modules/System/systemmod.c b/flight/Modules/System/systemmod.c index c36160a1e..db7d5634c 100644 --- a/flight/Modules/System/systemmod.c +++ b/flight/Modules/System/systemmod.c @@ -43,7 +43,9 @@ #include "objectpersistence.h" #include "flightstatus.h" #include "systemstats.h" +#include "systemsettings.h" #include "i2cstats.h" +#include "taskinfo.h" #include "watchdogstatus.h" #include "taskmonitor.h" #include "pios_config.h" @@ -78,24 +80,51 @@ static int32_t stackOverflow; // Private functions static void objectUpdatedCb(UAVObjEvent * ev); static void updateStats(); -static void updateI2Cstats(); -static void updateWDGstats(); static void updateSystemAlarms(); static void systemTask(void *parameters); - +#if defined(DIAGNOSTICS) +static void updateI2Cstats(); +static void updateWDGstats(); +#endif /** - * Initialise the module, called on startup. - * \returns 0 on success or -1 if initialisation failed + * Create the module task. + * \returns 0 on success or -1 if initialization failed */ -int32_t SystemModInitialize(void) +int32_t SystemModStart(void) { // Initialize vars stackOverflow = 0; // Create system task xTaskCreate(systemTask, (signed char *)"System", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &systemTaskHandle); + // Register task + TaskMonitorAdd(TASKINFO_RUNNING_SYSTEM, systemTaskHandle); + return 0; } +/** + * Initialize the module, called on startup. + * \returns 0 on success or -1 if initialization failed + */ +int32_t SystemModInitialize(void) +{ + + // Must registers objects here for system thread because ObjectManager started in OpenPilotInit + SystemSettingsInitialize(); + SystemStatsInitialize(); + ObjectPersistenceInitialize(); +#if defined(DIAGNOSTICS) + TaskInfoInitialize(); + I2CStatsInitialize(); + WatchdogStatusInitialize(); +#endif + + SystemModStart(); + + return 0; +} + +MODULE_INITCALL(SystemModInitialize, 0) /** * System task, periodically executes every SYSTEM_UPDATE_PERIOD_MS */ @@ -103,11 +132,8 @@ static void systemTask(void *parameters) { portTickType lastSysTime; - // System initialization - OpenPilotInit(); - - // Register task - TaskMonitorAdd(TASKINFO_RUNNING_SYSTEM, systemTaskHandle); + /* create all modules thread */ + MODULE_TASKCREATE_ALL // Initialize vars idleCounter = 0; @@ -118,15 +144,16 @@ static void systemTask(void *parameters) ObjectPersistenceConnectCallback(&objectUpdatedCb); // Main system loop - while (1) { + while (1) { // Update the system statistics updateStats(); // Update the system alarms updateSystemAlarms(); +#if defined(DIAGNOSTICS) updateI2Cstats(); updateWDGstats(); - +#endif // Update the task status object TaskMonitorUpdateAll(); @@ -228,9 +255,7 @@ static void objectUpdatedCb(UAVObjEvent * ev) /** * Called periodically to update the I2C statistics */ -#if defined(ARCH_POSIX) || defined(ARCH_WIN32) -static void updateI2Cstats() {} //Posix and win32 don't have I2C -#else +#if defined(DIAGNOSTICS) static void updateI2Cstats() { #if defined(PIOS_INCLUDE_I2C) @@ -250,7 +275,6 @@ static void updateI2Cstats() I2CStatsSet(&i2cStats); #endif } -#endif static void updateWDGstats() { @@ -259,6 +283,50 @@ static void updateWDGstats() watchdogStatus.ActiveFlags = PIOS_WDG_GetActiveFlags(); WatchdogStatusSet(&watchdogStatus); } +#endif + + +/** + * Called periodically to update the system stats + */ +static uint16_t GetFreeIrqStackSize(void) +{ + uint32_t i = 0x200; + +#if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK) +extern uint32_t _irq_stack_top; +extern uint32_t _irq_stack_end; +uint32_t pattern = 0x0000A5A5; +uint32_t *ptr = &_irq_stack_end; + +#if 1 /* the ugly way accurate but takes more time, useful for debugging */ + uint32_t stack_size = (((uint32_t)&_irq_stack_top - (uint32_t)&_irq_stack_end) & ~3 ) / 4; + + for (i=0; i< stack_size; i++) + { + if (ptr[i] != pattern) + { + i=i*4; + break; + } + } +#else /* faster way but not accurate */ + if (*(volatile uint32_t *)((uint32_t)ptr + IRQSTACK_LIMIT_CRITICAL) != pattern) + { + i = IRQSTACK_LIMIT_CRITICAL - 1; + } + else if (*(volatile uint32_t *)((uint32_t)ptr + IRQSTACK_LIMIT_WARNING) != pattern) + { + i = IRQSTACK_LIMIT_WARNING - 1; + } + else + { + i = IRQSTACK_LIMIT_WARNING; + } +#endif +#endif + return i; +} /** * Called periodically to update the system stats @@ -278,6 +346,9 @@ static void updateStats() stats.HeapRemaining = xPortGetFreeHeapSize(); #endif + // Get Irq stack status + stats.IRQStackRemaining = GetFreeIrqStackSize(); + // When idleCounterClear was not reset by the idle-task, it means the idle-task did not run if (idleCounterClear) { idleCounter = 0; @@ -320,6 +391,17 @@ static void updateSystemAlarms() AlarmsClear(SYSTEMALARMS_ALARM_OUTOFMEMORY); } +#if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK) + // Check IRQ stack + if (stats.IRQStackRemaining < IRQSTACK_LIMIT_CRITICAL) { + AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_CRITICAL); + } else if (stats.IRQStackRemaining < IRQSTACK_LIMIT_WARNING) { + AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_WARNING); + } else { + AlarmsClear(SYSTEMALARMS_ALARM_OUTOFMEMORY); + } +#endif + // Check CPU load if (stats.CPULoad > CPULOAD_LIMIT_CRITICAL) { AlarmsSet(SYSTEMALARMS_ALARM_CPUOVERLOAD, SYSTEMALARMS_ALARM_CRITICAL); diff --git a/flight/Modules/Telemetry/telemetry.c b/flight/Modules/Telemetry/telemetry.c index 07c7dc4dc..25abf2c3a 100644 --- a/flight/Modules/Telemetry/telemetry.c +++ b/flight/Modules/Telemetry/telemetry.c @@ -31,6 +31,7 @@ */ #include "openpilot.h" +#include "telemetry.h" #include "flighttelemetrystats.h" #include "gcstelemetrystats.h" #include "telemetrysettings.h" @@ -66,6 +67,7 @@ static uint32_t txErrors; static uint32_t txRetries; static TelemetrySettingsData settings; static uint32_t timeOfLastObjectUpdate; +static UAVTalkConnection uavTalkCon; // Private functions static void telemetryTxTask(void *parameters); @@ -85,38 +87,15 @@ static void updateSettings(); * \return -1 if initialisation failed * \return 0 on success */ -int32_t TelemetryInitialize(void) +int32_t TelemetryStart(void) { - UAVObjEvent ev; - - // Initialize vars - timeOfLastObjectUpdate = 0; - - // Create object queues - queue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(UAVObjEvent)); -#if defined(PIOS_TELEM_PRIORITY_QUEUE) - priorityQueue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(UAVObjEvent)); -#endif - - // Get telemetry settings object - updateSettings(); - - // Initialise UAVTalk - UAVTalkInitialize(&transmitData); - // Process all registered objects and connect queue for updates UAVObjIterate(®isterObject); - - // Create periodic event that will be used to update the telemetry stats - txErrors = 0; - txRetries = 0; - memset(&ev, 0, sizeof(UAVObjEvent)); - EventPeriodicQueueCreate(&ev, priorityQueue, STATS_UPDATE_PERIOD_MS); - + // Listen to objects of interest GCSTelemetryStatsConnectQueue(priorityQueue); TelemetrySettingsConnectQueue(priorityQueue); - + // Start telemetry tasks xTaskCreate(telemetryTxTask, (signed char *)"TelTx", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY_TX, &telemetryTxTaskHandle); xTaskCreate(telemetryRxTask, (signed char *)"TelRx", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY_RX, &telemetryRxTaskHandle); @@ -127,10 +106,50 @@ int32_t TelemetryInitialize(void) xTaskCreate(telemetryTxPriTask, (signed char *)"TelPriTx", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY_TXPRI, &telemetryTxPriTaskHandle); TaskMonitorAdd(TASKINFO_RUNNING_TELEMETRYTXPRI, telemetryTxPriTaskHandle); #endif - + return 0; } +/** + * Initialise the telemetry module + * \return -1 if initialisation failed + * \return 0 on success + */ +int32_t TelemetryInitialize(void) +{ + UAVObjEvent ev; + + FlightTelemetryStatsInitialize(); + GCSTelemetryStatsInitialize(); + TelemetrySettingsInitialize(); + + // Initialize vars + timeOfLastObjectUpdate = 0; + + // Create object queues + queue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(UAVObjEvent)); +#if defined(PIOS_TELEM_PRIORITY_QUEUE) + priorityQueue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(UAVObjEvent)); +#endif + + // Get telemetry settings object + updateSettings(); + + // Initialise UAVTalk + uavTalkCon = UAVTalkInitialize(&transmitData,256); + + // Create periodic event that will be used to update the telemetry stats + txErrors = 0; + txRetries = 0; + memset(&ev, 0, sizeof(UAVObjEvent)); + EventPeriodicQueueCreate(&ev, priorityQueue, STATS_UPDATE_PERIOD_MS); + + + return 0; +} + +MODULE_INITCALL(TelemetryInitialize, TelemetryStart) + /** * Register a new object, adds object to local list and connects the queue depending on the object's * telemetry settings. @@ -221,7 +240,7 @@ static void processObjEvent(UAVObjEvent * ev) if (ev->event == EV_UPDATED || ev->event == EV_UPDATED_MANUAL) { // Send update to GCS (with retries) while (retries < MAX_RETRIES && success == -1) { - success = UAVTalkSendObject(ev->obj, ev->instId, metadata.telemetryAcked, REQ_TIMEOUT_MS); // call blocks until ack is received or timeout + success = UAVTalkSendObject(uavTalkCon, ev->obj, ev->instId, metadata.telemetryAcked, REQ_TIMEOUT_MS); // call blocks until ack is received or timeout ++retries; } // Update stats @@ -232,7 +251,7 @@ static void processObjEvent(UAVObjEvent * ev) } else if (ev->event == EV_UPDATE_REQ) { // Request object update from GCS (with retries) while (retries < MAX_RETRIES && success == -1) { - success = UAVTalkSendObjectRequest(ev->obj, ev->instId, REQ_TIMEOUT_MS); // call blocks until update is received or timeout + success = UAVTalkSendObjectRequest(uavTalkCon, ev->obj, ev->instId, REQ_TIMEOUT_MS); // call blocks until update is received or timeout ++retries; } // Update stats @@ -291,7 +310,6 @@ static void telemetryTxPriTask(void *parameters) static void telemetryRxTask(void *parameters) { uint32_t inputPort; - int32_t len; // Task loop while (1) { @@ -305,14 +323,20 @@ static void telemetryRxTask(void *parameters) inputPort = telemetryPort; } - // Block until data are available - // TODO: Currently we periodically check the buffer for data, update once the PIOS_COM is made blocking - len = PIOS_COM_ReceiveBufferUsed(inputPort); - for (int32_t n = 0; n < len; ++n) { - UAVTalkProcessInputStream(PIOS_COM_ReceiveBuffer(inputPort)); - } - vTaskDelay(5); // <- remove when blocking calls are implemented + if (inputPort) { + // Block until data are available + uint8_t serial_data[1]; + uint16_t bytes_to_process; + bytes_to_process = PIOS_COM_ReceiveBuffer(inputPort, serial_data, sizeof(serial_data), 500); + if (bytes_to_process > 0) { + for (uint8_t i = 0; i < bytes_to_process; i++) { + UAVTalkProcessInputStream(uavTalkCon,serial_data[i]); + } + } + } else { + vTaskDelay(5); + } } } @@ -336,7 +360,11 @@ static int32_t transmitData(uint8_t * data, int32_t length) outputPort = telemetryPort; } - return PIOS_COM_SendBufferNonBlocking(outputPort, data, length); + if (outputPort) { + return PIOS_COM_SendBufferNonBlocking(outputPort, data, length); + } else { + return -1; + } } /** @@ -403,8 +431,8 @@ static void updateTelemetryStats() uint32_t timeNow; // Get stats - UAVTalkGetStats(&utalkStats); - UAVTalkResetStats(); + UAVTalkGetStats(uavTalkCon, &utalkStats); + UAVTalkResetStats(uavTalkCon); // Get object data FlightTelemetryStatsGet(&flightStats); @@ -492,20 +520,16 @@ static void updateSettings() // Retrieve settings TelemetrySettingsGet(&settings); - // Set port speed - if (settings.Speed == TELEMETRYSETTINGS_SPEED_2400) PIOS_COM_ChangeBaud(telemetryPort, 2400); - else - if (settings.Speed == TELEMETRYSETTINGS_SPEED_4800) PIOS_COM_ChangeBaud(telemetryPort, 4800); - else - if (settings.Speed == TELEMETRYSETTINGS_SPEED_9600) PIOS_COM_ChangeBaud(telemetryPort, 9600); - else - if (settings.Speed == TELEMETRYSETTINGS_SPEED_19200) PIOS_COM_ChangeBaud(telemetryPort, 19200); - else - if (settings.Speed == TELEMETRYSETTINGS_SPEED_38400) PIOS_COM_ChangeBaud(telemetryPort, 38400); - else - if (settings.Speed == TELEMETRYSETTINGS_SPEED_57600) PIOS_COM_ChangeBaud(telemetryPort, 57600); - else - if (settings.Speed == TELEMETRYSETTINGS_SPEED_115200) PIOS_COM_ChangeBaud(telemetryPort, 115200); + if (telemetryPort) { + // Set port speed + if (settings.Speed == TELEMETRYSETTINGS_SPEED_2400) PIOS_COM_ChangeBaud(telemetryPort, 2400); + else if (settings.Speed == TELEMETRYSETTINGS_SPEED_4800) PIOS_COM_ChangeBaud(telemetryPort, 4800); + else if (settings.Speed == TELEMETRYSETTINGS_SPEED_9600) PIOS_COM_ChangeBaud(telemetryPort, 9600); + else if (settings.Speed == TELEMETRYSETTINGS_SPEED_19200) PIOS_COM_ChangeBaud(telemetryPort, 19200); + else if (settings.Speed == TELEMETRYSETTINGS_SPEED_38400) PIOS_COM_ChangeBaud(telemetryPort, 38400); + else if (settings.Speed == TELEMETRYSETTINGS_SPEED_57600) PIOS_COM_ChangeBaud(telemetryPort, 57600); + else if (settings.Speed == TELEMETRYSETTINGS_SPEED_115200) PIOS_COM_ChangeBaud(telemetryPort, 115200); + } } /** diff --git a/flight/OpenPilot/Makefile b/flight/OpenPilot/Makefile index 8bb3ed27c..7d3cdf514 100644 --- a/flight/OpenPilot/Makefile +++ b/flight/OpenPilot/Makefile @@ -25,6 +25,13 @@ WHEREAMI := $(dir $(lastword $(MAKEFILE_LIST))) TOP := $(realpath $(WHEREAMI)/../../) include $(TOP)/make/firmware-defs.mk +include $(TOP)/make/boards/$(BOARD_NAME)/board-info.mk + +# Target file name (without extension). +TARGET := fw_$(BOARD_NAME) + +# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) +OUTDIR := $(TOP)/build/$(TARGET) # Set developer code and compile options # Set to YES to compile for debugging @@ -36,9 +43,6 @@ ENABLE_DEBUG_PINS ?= NO # Set to Yes to enable the AUX UART which is mapped on the S1 (Tx) and S2 (Rx) servo outputs ENABLE_AUX_UART ?= NO -USE_SPEKTRUM ?= NO - - # Set to YES when using Code Sourcery toolchain CODE_SOURCERY ?= YES @@ -52,29 +56,13 @@ endif FLASH_TOOL = OPENOCD # List of modules to include -MODULES = Actuator Telemetry GPS ManualControl Altitude AHRSComms Stabilization Guidance FirmwareIAP FlightPlan - +MODULES = Actuator Telemetry GPS ManualControl Altitude AHRSComms Stabilization Guidance FirmwareIAP +PYMODULES = FlightPlan #MODULES = Telemetry Example #MODULES = Telemetry MK/MKSerial #MODULES = Telemetry #MODULES += Osd/OsdEtStd - -# MCU name, submodel and board -# - MCU used for compiler-option (-mcpu) -# - MODEL used for linker-script name (-T) and passed as define -# - BOARD just passed as define (optional) -MCU = cortex-m3 -CHIP = STM32F103RET -BOARD = STM3210E_OP -MODEL = HD - -# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) -OUTDIR = $(TOP)/build/openpilot - -# Target file name (without extension). -TARGET = OpenPilot - # Paths OPSYSTEM = ./System OPSYSTEMINC = $(OPSYSTEM)/inc @@ -124,21 +112,20 @@ UAVOBJSYNTHDIR = $(OUTDIR)/../uavobject-synthetics/flight # List C source files here. (C dependencies are automatically generated.) # use file-extension c for "c-only"-files -MODNAMES = $(notdir ${MODULES}) - ifndef TESTAPP -## PyMite files +## PyMite files and modules SRC += $(OUTDIR)/pmlib_img.c SRC += $(OUTDIR)/pmlib_nat.c SRC += $(OUTDIR)/pmlibusr_img.c SRC += $(OUTDIR)/pmlibusr_nat.c -SRC += $(wildcard ${PYMITEVM}/*.c) -SRC += $(wildcard ${PYMITEPLAT}/*.c) +PYSRC += $(wildcard ${PYMITEVM}/*.c) +PYSRC += $(wildcard ${PYMITEPLAT}/*.c) +PYSRC += ${foreach MOD, ${PYMODULES}, ${wildcard ${OPMODULEDIR}/${MOD}/*.c}} +SRC += $(PYSRC) ## MODULES SRC += ${foreach MOD, ${MODULES}, ${wildcard ${OPMODULEDIR}/${MOD}/*.c}} -SRC += ${OUTDIR}/InitMods.c ## OPENPILOT CORE: SRC += ${OPMODULEDIR}/System/systemmod.c SRC += $(OPSYSTEM)/openpilot.c @@ -148,7 +135,6 @@ SRC += $(OPSYSTEM)/taskmonitor.c SRC += $(OPUAVTALK)/uavtalk.c SRC += $(OPUAVOBJ)/uavobjectmanager.c SRC += $(OPUAVOBJ)/eventdispatcher.c -SRC += $(OPUAVOBJ)/uavobjectsinit_linker.c else ## TESTCODE SRC += $(OPTESTS)/test_common.c @@ -177,6 +163,7 @@ SRC += $(PIOSSTM32F10X)/pios_spi.c SRC += $(PIOSSTM32F10X)/pios_ppm.c SRC += $(PIOSSTM32F10X)/pios_pwm.c SRC += $(PIOSSTM32F10X)/pios_spektrum.c +SRC += $(PIOSSTM32F10X)/pios_sbus.c SRC += $(PIOSSTM32F10X)/pios_debug.c SRC += $(PIOSSTM32F10X)/pios_gpio.c SRC += $(PIOSSTM32F10X)/pios_exti.c @@ -193,6 +180,7 @@ SRC += $(PIOSSTM32F10X)/pios_usb_hid_prop.c SRC += $(PIOSSTM32F10X)/pios_usb_hid_pwr.c ## PIOS Hardware (Common) +SRC += $(PIOSCOMMON)/pios_crc.c SRC += $(PIOSCOMMON)/pios_sdcard.c SRC += $(PIOSCOMMON)/pios_com.c SRC += $(PIOSCOMMON)/pios_bmp085.c @@ -200,6 +188,7 @@ SRC += $(PIOSCOMMON)/pios_hcsr04.c SRC += $(PIOSCOMMON)/pios_i2c_esc.c SRC += $(PIOSCOMMON)/pios_iap.c SRC += $(PIOSCOMMON)/pios_bl_helper.c +SRC += $(PIOSCOMMON)/pios_rcvr.c SRC += $(PIOSCOMMON)/printf-stdarg.c SRC += $(FLIGHTLIB)/ahrs_spi_comm.c SRC += $(FLIGHTLIB)/ahrs_comm_objects.c @@ -286,7 +275,7 @@ CPPSRCARM = # Even though the DOS/Win* filesystem matches both .s and .S the same, # it will preserve the spelling of the filenames, and gcc itself does # care about how the name is spelled on its command-line. -ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL)_OP.S +ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL)$(MODEL_SUFFIX).S # List Assembler source files here which must be assembled in ARM-Mode.. ASRCARM = @@ -317,7 +306,7 @@ EXTRAINCDIRS += $(RTOSSRCDIR)/portable/GCC/ARM_CM3 EXTRAINCDIRS += $(AHRSBOOTLOADERINC) EXTRAINCDIRS += $(PYMITEINC) -EXTRAINCDIRS += ${foreach MOD, ${MODULES}, $(OPMODULEDIR)/${MOD}/inc} ${OPMODULEDIR}/System/inc +EXTRAINCDIRS += ${foreach MOD, ${MODULES} ${PYMODULES}, $(OPMODULEDIR)/${MOD}/inc} ${OPMODULEDIR}/System/inc # List any extra directories to look for library files here. @@ -368,12 +357,6 @@ endif ifeq ($(ENABLE_AUX_UART), YES) CDEFS += -DPIOS_ENABLE_AUX_UART endif -CDEFS += -DUSE_BOOTLOADER - -ifeq ($(USE_SPEKTRUM), YES) -CDEFS += -DUSE_SPEKTRUM -endif - # Place project-specific -D and/or -U options for # Assembler with preprocessor here. @@ -404,6 +387,9 @@ ifeq ($(DEBUG),YES) CFLAGS = -g$(DEBUGF) -DDEBUG endif +# OP has enough memory to always enable optional objects +CFLAGS += -DDIAGNOSTICS + CFLAGS += -O$(OPT) CFLAGS += -mcpu=$(MCU) CFLAGS += $(CDEFS) @@ -450,22 +436,9 @@ LDFLAGS += -lc -lgcc LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_memory.ld LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_sections.ld -OOCD_LOADFILE+=$(OUTDIR)/$(TARGET).bin -# Program -OOCD_CL+=-c "flash write_image erase $(OOCD_LOADFILE) 0x08005000 bin" -# Verify -OOCD_CL+=-c "verify_image $(OOCD_LOADFILE) 0x08005000 bin" -# reset target -OOCD_CL+=-c "reset run" -# terminate OOCD after programming -OOCD_CL+=-c shutdown - - # Define programs and commands. REMOVE = $(REMOVE_CMD) -f PYTHON = python -###SHELL = sh -###COPY = cp # List of all source files. ALLSRC = $(ASRCARM) $(ASRC) $(SRCARM) $(SRC) $(CPPSRCARM) $(CPPSRC) @@ -481,7 +454,7 @@ LSTFILES = $(addprefix $(OUTDIR)/, $(addsuffix .lst, $(ALLSRCBASE))) DEPFILES = $(addprefix $(OUTDIR)/dep/, $(addsuffix .o.d, $(ALLSRCBASE))) # Default target. -all: gencode gccversion build +all: gccversion build ifeq ($(LOADFORMAT),ihex) build: elf hex lss sym @@ -498,16 +471,9 @@ endif endif # Generate intermediate code -gencode: ${OUTDIR}/InitMods.c ${OUTDIR}/pmlib_img.c ${OUTDIR}/pmlib_nat.c ${OUTDIR}/pmlibusr_img.c ${OUTDIR}/pmlibusr_nat.c ${OUTDIR}/pmfeatures.h +gencode: ${OUTDIR}/pmlib_img.c ${OUTDIR}/pmlib_nat.c ${OUTDIR}/pmlibusr_img.c ${OUTDIR}/pmlibusr_nat.c ${OUTDIR}/pmfeatures.h -# Generate code for module initialization -${OUTDIR}/InitMods.c: Makefile - @echo $(MSG_MODINIT) $(call toprel, $@) - @echo ${quote}// Autogenerated file${quote} > ${OUTDIR}/InitMods.c - @echo ${quote}${foreach MOD, ${MODNAMES}, extern unsigned int ${MOD}Initialize(void);}${quote} >> ${OUTDIR}/InitMods.c - @echo ${quote}void InitModules() {${quote} >> ${OUTDIR}/InitMods.c - @echo ${quote}${foreach MOD, ${MODNAMES}, ${MOD}Initialize();}${quote} >> ${OUTDIR}/InitMods.c - @echo ${quote}}${quote} >> ${OUTDIR}/InitMods.c +$(PYSRC): gencode # Generate code for PyMite ${OUTDIR}/pmlib_img.c ${OUTDIR}/pmlib_nat.c ${OUTDIR}/pmlibusr_img.c ${OUTDIR}/pmlibusr_nat.c ${OUTDIR}/pmfeatures.h: $(wildcard ${PYMITELIB}/*.py) $(wildcard ${PYMITEPLAT}/*.py) $(wildcard ${FLIGHTPLANLIB}/*.py) $(wildcard ${FLIGHTPLANS}/*.py) @@ -516,14 +482,6 @@ ${OUTDIR}/pmlib_img.c ${OUTDIR}/pmlib_nat.c ${OUTDIR}/pmlibusr_img.c ${OUTDIR}/p @$(PYTHON) $(PYMITETOOLS)/pmGenPmFeatures.py $(PYMITEPLAT)/pmfeatures.py > $(OUTDIR)/pmfeatures.h @$(PYTHON) $(PYMITETOOLS)/pmImgCreator.py -f $(PYMITEPLAT)/pmfeatures.py -c -u -o $(OUTDIR)/pmlibusr_img.c --native-file=$(OUTDIR)/pmlibusr_nat.c $(FLIGHTPLANS)/test.py -# Program the device. -ifeq ($(FLASH_TOOL),OPENOCD) -# Program the device with Dominic Rath's OPENOCD in "batch-mode", needs cfg and "reset-script". -program: $(OUTDIR)/$(TARGET).bin - @echo ${quote}Programming with OPENOCD${quote} - $(OOCD_EXE) $(OOCD_CL) -endif - # Link: create ELF output file from object files. $(eval $(call LINK_TEMPLATE, $(OUTDIR)/$(TARGET).elf, $(ALLOBJ))) @@ -553,23 +511,37 @@ $(eval $(call PARTIAL_COMPILE_ARM_TEMPLATE, SRCARM)) $(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin -.PHONY: elf lss sym hex bin bino +$(eval $(call OPFW_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BOARD_TYPE),$(BOARD_REVISION))) + +# Add jtag targets (program and wipe) +$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE))) + +.PHONY: elf lss sym hex bin bino opfw elf: $(OUTDIR)/$(TARGET).elf lss: $(OUTDIR)/$(TARGET).lss sym: $(OUTDIR)/$(TARGET).sym hex: $(OUTDIR)/$(TARGET).hex bin: $(OUTDIR)/$(TARGET).bin bino: $(OUTDIR)/$(TARGET).bin.o +opfw: $(OUTDIR)/$(TARGET).opfw # Display sizes of sections. $(eval $(call SIZE_TEMPLATE, $(OUTDIR)/$(TARGET).elf)) -.PHONY: size -size: $(OUTDIR)/$(TARGET).elf_size # Generate Doxygen documents docs: doxygen $(DOXYGENDIR)/doxygen.cfg +# Install: install binary file with prefix/suffix into install directory +install: $(OUTDIR)/$(TARGET).opfw +ifneq ($(INSTALL_DIR),) + @echo $(MSG_INSTALLING) $(call toprel, $<) + $(V1) mkdir -p $(INSTALL_DIR) + $(V1) $(INSTALL) $< $(INSTALL_DIR)/$(INSTALL_PFX)$(TARGET)$(INSTALL_SFX).opfw +else + $(error INSTALL_DIR must be specified for $@) +endif + # Target: clean project. clean: clean_list @@ -609,5 +581,4 @@ else endif # Listing of phony targets. -.PHONY : all build clean clean_list program gencode - +.PHONY : all build clean clean_list gencode install diff --git a/flight/OpenPilot/Makefile.posix b/flight/OpenPilot/Makefile.posix index 2eff6f933..cfcdbf55f 100644 --- a/flight/OpenPilot/Makefile.posix +++ b/flight/OpenPilot/Makefile.posix @@ -162,8 +162,10 @@ CFLAGS_UAVOBJECTS = $(UAVOBJDEFINE) endif ## PIOS Hardware (posix) +SRC += $(PIOSPOSIX)/pios_crc.c SRC += $(PIOSPOSIX)/pios_sys.c SRC += $(PIOSPOSIX)/pios_led.c +SRC += $(PIOSPOSIX)/pios_irq.c SRC += $(PIOSPOSIX)/pios_delay.c SRC += $(PIOSPOSIX)/pios_sdcard.c SRC += $(PIOSPOSIX)/pios_udp.c @@ -172,8 +174,10 @@ SRC += $(PIOSPOSIX)/pios_servo.c SRC += $(PIOSPOSIX)/pios_wdg.c SRC += $(PIOSPOSIX)/pios_debug.c +SRC += $(PIOSPOSIX)/pios_rcvr.c + ## Libraries for flight calculations -#SRC += $(FLIGHTLIB)/fifo_buffer.c +SRC += $(FLIGHTLIB)/fifo_buffer.c SRC += $(FLIGHTLIB)/WorldMagModel.c SRC += $(FLIGHTLIB)/CoordinateConversions.c ## RTOS and RTOS Portable @@ -440,9 +444,13 @@ ${OUTDIR}/InitMods.c: Makefile.posix @echo ${MSG_MODINIT} @echo ${quote}// Autogenerated file${quote} > ${OUTDIR}/InitMods.c @echo ${quote}${foreach MOD, ${MODNAMES}, extern unsigned int ${MOD}Initialize(void);}${quote} >> ${OUTDIR}/InitMods.c + @echo ${quote}${foreach MOD, ${MODNAMES}, extern unsigned int ${MOD}Start(void);}${quote} >> ${OUTDIR}/InitMods.c @echo ${quote}void InitModules() {${quote} >> ${OUTDIR}/InitMods.c @echo ${quote}${foreach MOD, ${MODNAMES}, ${MOD}Initialize();}${quote} >> ${OUTDIR}/InitMods.c @echo ${quote}}${quote} >> ${OUTDIR}/InitMods.c + @echo ${quote}void StartModules() {${quote} >> ${OUTDIR}/InitMods.c + @echo ${quote}${foreach MOD, ${MODNAMES}, ${MOD}Start();}${quote} >> ${OUTDIR}/InitMods.c + @echo ${quote}}${quote} >> ${OUTDIR}/InitMods.c # Generate code for PyMite ${OUTDIR}/pmlib_img.c ${OUTDIR}/pmlib_nat.c ${OUTDIR}/pmlibusr_img.c ${OUTDIR}/pmlibusr_nat.c ${OUTDIR}/pmfeatures.h: $(wildcard ${PYMITELIB}/*.py) $(wildcard ${PYMITEPLAT}/*.py) $(wildcard ${FLIGHTPLANLIB}/*.py) $(wildcard ${FLIGHTPLANS}/*.py) $(wildcard $(UAVOBJPYTHONSYNTHDIR)/*.py) diff --git a/flight/OpenPilot/Makefile.win32 b/flight/OpenPilot/Makefile.win32 index 1ea309b26..261e4abfb 100644 --- a/flight/OpenPilot/Makefile.win32 +++ b/flight/OpenPilot/Makefile.win32 @@ -166,6 +166,7 @@ SRC += $(PIOSWIN32)/pios_udp.c SRC += $(PIOSWIN32)/pios_com.c SRC += $(PIOSWIN32)/pios_servo.c SRC += $(PIOSWIN32)/pios_wdg.c +SRC += $(PIOSWIN32)/pios_crc.c # ## RTOS SRC += $(RTOSSRCDIR)/list.c diff --git a/flight/OpenPilot/System/alarms.c b/flight/OpenPilot/System/alarms.c index e899be779..e61c7c1ea 100644 --- a/flight/OpenPilot/System/alarms.c +++ b/flight/OpenPilot/System/alarms.c @@ -41,14 +41,12 @@ static xSemaphoreHandle lock; static int32_t hasSeverity(SystemAlarmsAlarmOptions severity); /** - * Initialize the alarms library + * Initialize the alarms library */ int32_t AlarmsInitialize(void) { + SystemAlarmsInitialize(); lock = xSemaphoreCreateRecursiveMutex(); - //do not change the default states of the alarms, let the init code generated by the uavobjectgenerator handle that - //AlarmsClearAll(); - //AlarmsDefaultAll(); return 0; } @@ -56,7 +54,7 @@ int32_t AlarmsInitialize(void) * Set an alarm * @param alarm The system alarm to be modified * @param severity The alarm severity - * @return 0 if success, -1 if an error + * @return 0 if success, -1 if an error */ int32_t AlarmsSet(SystemAlarmsAlarmElem alarm, SystemAlarmsAlarmOptions severity) { @@ -151,7 +149,7 @@ void AlarmsClearAll() /** * Check if there are any alarms with the given or higher severity - * @return 0 if no alarms are found, 1 if at least one alarm is found + * @return 0 if no alarms are found, 1 if at least one alarm is found */ int32_t AlarmsHasWarnings() { @@ -208,5 +206,5 @@ static int32_t hasSeverity(SystemAlarmsAlarmOptions severity) /** * @} * @} - */ + */ diff --git a/flight/OpenPilot/System/inc/FreeRTOSConfig.h b/flight/OpenPilot/System/inc/FreeRTOSConfig.h index c2a07fa67..48b7c1560 100644 --- a/flight/OpenPilot/System/inc/FreeRTOSConfig.h +++ b/flight/OpenPilot/System/inc/FreeRTOSConfig.h @@ -39,7 +39,7 @@ #define configUSE_RECURSIVE_MUTEXES 1 #define configUSE_COUNTING_SEMAPHORES 0 #define configUSE_ALTERNATIVE_API 0 -#define configCHECK_FOR_STACK_OVERFLOW 2 +//#define configCHECK_FOR_STACK_OVERFLOW 2 #define configQUEUE_REGISTRY_SIZE 10 /* Co-routine definitions. */ @@ -72,14 +72,24 @@ NVIC value of 255. */ #define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15 /* Enable run time stats collection */ -#if defined(DEBUG) +#if defined(DIAGNOSTICS) +#define configCHECK_FOR_STACK_OVERFLOW 2 + #define configGENERATE_RUN_TIME_STATS 1 #define INCLUDE_uxTaskGetRunTime 1 -#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() PIOS_RTC_Start() -// Note: Using the tick count defeats the purpose here, need some timer on the scale of 10khz -#define portGET_RUN_TIME_COUNTER_VALUE() PIOS_RTC_Counter() +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()\ +do {\ +(*(unsigned long *)0xe000edfc) |= (1<<24);/* DEMCR |= DEMCR_TRCENA */\ +(*(unsigned long *)0xe0001000) |= 1; /* DWT_CTRL |= DWT_CYCCNT_ENA */\ +} while(0) +#define portGET_RUN_TIME_COUNTER_VALUE() (*(unsigned long *)0xe0001004)/* DWT_CYCCNT */ +#else +#define configCHECK_FOR_STACK_OVERFLOW 1 #endif +#if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) +#define CHECK_IRQ_STACK +#endif /** * @} diff --git a/flight/OpenPilot/System/inc/pios_board_posix.h b/flight/OpenPilot/System/inc/pios_board_posix.h index 741f36ba7..fe6f6ba51 100644 --- a/flight/OpenPilot/System/inc/pios_board_posix.h +++ b/flight/OpenPilot/System/inc/pios_board_posix.h @@ -52,15 +52,22 @@ //------------------------- //#define PIOS_USART_TX_BUFFER_SIZE 256 #define PIOS_COM_BUFFER_SIZE 1024 +#define PIOS_COM_MAX_DEVS 256 #define PIOS_UDP_RX_BUFFER_SIZE PIOS_COM_BUFFER_SIZE -#define PIOS_COM_TELEM_RF 0 -#define PIOS_COM_GPS 1 -#define PIOS_COM_TELEM_USB 2 +extern uint32_t pios_com_telem_rf_id; +extern uint32_t pios_com_telem_usb_id; +extern uint32_t pios_com_gps_id; +extern uint32_t pios_com_aux_id; +extern uint32_t pios_com_spectrum_id; + +#define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) +#define PIOS_COM_TELEM_USB (pios_com_telem_usb_id) +#define PIOS_COM_GPS (pios_com_gps_id) #ifdef PIOS_ENABLE_AUX_UART -#define PIOS_COM_AUX 3 -#define PIOS_COM_DEBUG PIOS_COM_AUX +#define PIOS_COM_AUX (pios_com_aux_id) +#define PIOS_COM_DEBUG (PIOS_COM_AUX #endif /** diff --git a/flight/OpenPilot/System/inc/pios_config.h b/flight/OpenPilot/System/inc/pios_config.h index f3fe8671b..4e6657cef 100644 --- a/flight/OpenPilot/System/inc/pios_config.h +++ b/flight/OpenPilot/System/inc/pios_config.h @@ -42,12 +42,14 @@ #define PIOS_INCLUDE_IRQ #define PIOS_INCLUDE_LED -#if defined(USE_SPEKTRUM) +#define PIOS_INCLUDE_RCVR + #define PIOS_INCLUDE_SPEKTRUM -#else -//#define PIOS_INCLUDE_PPM +//#define PIOS_INCLUDE_SBUS #define PIOS_INCLUDE_PWM -#endif +//#define PIOS_INCLUDE_PPM + +#define PIOS_INCLUDE_TELEMETRY_RF #define PIOS_INCLUDE_SERVO #define PIOS_INCLUDE_SPI @@ -58,6 +60,7 @@ //#define PIOS_INCLUDE_HCSR04 #define PIOS_INCLUDE_OPAHRS #define PIOS_INCLUDE_COM +#define PIOS_INCLUDE_GPS #define PIOS_INCLUDE_SDCARD #define PIOS_INCLUDE_SETTINGS #define PIOS_INCLUDE_FREERTOS @@ -84,6 +87,8 @@ /* Alarm Thresholds */ #define HEAP_LIMIT_WARNING 4000 #define HEAP_LIMIT_CRITICAL 1000 +#define IRQSTACK_LIMIT_WARNING 150 +#define IRQSTACK_LIMIT_CRITICAL 80 #define CPULOAD_LIMIT_WARNING 80 #define CPULOAD_LIMIT_CRITICAL 95 diff --git a/flight/OpenPilot/System/inc/pios_config_posix.h b/flight/OpenPilot/System/inc/pios_config_posix.h index 136e264c3..e8701be90 100644 --- a/flight/OpenPilot/System/inc/pios_config_posix.h +++ b/flight/OpenPilot/System/inc/pios_config_posix.h @@ -36,9 +36,15 @@ #define PIOS_INCLUDE_SDCARD #define PIOS_INCLUDE_FREERTOS #define PIOS_INCLUDE_COM +#define PIOS_INCLUDE_GPS +#define PIOS_INCLUDE_IRQ +#define PIOS_INCLUDE_TELEMETRY_RF #define PIOS_INCLUDE_UDP #define PIOS_INCLUDE_SERVO +#define PIOS_INCLUDE_RCVR +#define PIOS_RCVR_MAX_CHANNELS 12 +#define PIOS_RCVR_MAX_DEVS 3 /* Defaults for Logging */ #define LOG_FILENAME "PIOS.LOG" diff --git a/flight/OpenPilot/System/openpilot.c b/flight/OpenPilot/System/openpilot.c index be50653f7..81a8f17b1 100644 --- a/flight/OpenPilot/System/openpilot.c +++ b/flight/OpenPilot/System/openpilot.c @@ -62,11 +62,10 @@ static void TaskSDCard(void *pvParameters); int32_t CONSOLE_Parse(uint8_t port, char c); void OP_ADC_NotifyChange(uint32_t pin, uint32_t pin_value); -/* Prototype of generated InitModules() function */ -extern void InitModules(void); - /* Prototype of PIOS_Board_Init() function */ extern void PIOS_Board_Init(void); +extern void Stack_Change(void); +static void Stack_Change_Weak () __attribute__ ((weakref ("Stack_Change"))); /** * OpenPilot Main function: @@ -85,48 +84,42 @@ int main() /* Brings up System using CMSIS functions, enables the LEDs. */ PIOS_SYS_Init(); - /* Initialize the system thread */ - SystemModInitialize(); - - /* Start the FreeRTOS scheduler */ - vTaskStartScheduler(); - - /* If all is well we will never reach here as the scheduler will now be running. */ - /* If we do get here, it will most likely be because we ran out of heap space. */ - PIOS_LED_Off(LED1); - PIOS_LED_Off(LED2); - for(;;) { - PIOS_LED_Toggle(LED1); - PIOS_LED_Toggle(LED2); - PIOS_DELAY_WaitmS(100); - } - - return 0; -} - -/** - * Initialize the hardware, libraries and modules (called by the System thread in systemmod.c) - */ -void OpenPilotInit() -{ - /* Architecture dependant Hardware and * core subsystem initialisation * (see pios_board.c for your arch) * */ - PIOS_Board_Init(); /* Initialize modules */ - InitModules(); + MODULE_INITIALISE_ALL +#if INCLUDE_TEST_TASKS /* Create test tasks */ - //xTaskCreate(TaskTesting, (signed portCHAR *)"Testing", configMINIMAL_STACK_SIZE , NULL, 4, NULL); - //xTaskCreate(TaskHIDTest, (signed portCHAR *)"HIDTest", configMINIMAL_STACK_SIZE , NULL, 3, NULL); - //xTaskCreate(TaskServos, (signed portCHAR *)"Servos", configMINIMAL_STACK_SIZE , NULL, 3, NULL); - //xTaskCreate(TaskSDCard, (signed portCHAR *)"SDCard", configMINIMAL_STACK_SIZE, NULL, (tskIDLE_PRIORITY + 2), NULL); + xTaskCreate(TaskTesting, (signed portCHAR *)"Testing", configMINIMAL_STACK_SIZE , NULL, 4, NULL); + xTaskCreate(TaskHIDTest, (signed portCHAR *)"HIDTest", configMINIMAL_STACK_SIZE , NULL, 3, NULL); + xTaskCreate(TaskServos, (signed portCHAR *)"Servos", configMINIMAL_STACK_SIZE , NULL, 3, NULL); + xTaskCreate(TaskSDCard, (signed portCHAR *)"SDCard", configMINIMAL_STACK_SIZE, NULL, (tskIDLE_PRIORITY + 2), NULL); +#endif + + /* swap the stack to use the IRQ stack (does nothing in sim mode) */ + Stack_Change_Weak(); + + /* Start the FreeRTOS scheduler which should never returns.*/ + vTaskStartScheduler(); + + /* If all is well we will never reach here as the scheduler will now be running. */ + + /* Do some indication to user that something bad just happened */ + PIOS_LED_Off(LED1); \ + for(;;) { \ + PIOS_LED_Toggle(LED1); \ + PIOS_DELAY_WaitmS(100); \ + }; + + return 0; } + #if INCLUDE_TEST_TASKS static void TaskTesting(void *pvParameters) { @@ -153,6 +146,9 @@ static void TaskTesting(void *pvParameters) #if defined(PIOS_INCLUDE_SPEKTRUM) PIOS_COM_SendFormattedStringNonBlocking(COM_DEBUG_USART, "%u,%u,%u,%u,%u,%u,%u,%u\r", PIOS_SPEKTRUM_Get(0), PIOS_SPEKTRUM_Get(1), PIOS_SPEKTRUM_Get(2), PIOS_SPEKTRUM_Get(3), PIOS_SPEKTRUM_Get(4), PIOS_SPEKTRUM_Get(5), PIOS_SPEKTRUM_Get(6), PIOS_SPEKTRUM_Get(7)); #endif +#if defined(PIOS_INCLUDE_SBUS) + PIOS_COM_SendFormattedStringNonBlocking(COM_DEBUG_USART, "%u,%u,%u,%u,%u,%u,%u,%u\r", PIOS_SBUS_Get(0), PIOS_SBUS_Get(1), PIOS_SBUS_Get(2), PIOS_SBUS_Get(3), PIOS_SBUS_Get(4), PIOS_SBUS_Get(5), PIOS_SBUS_Get(6), PIOS_SBUS_Get(7)); +#endif #if defined(PIOS_INCLUDE_PWM) PIOS_COM_SendFormattedStringNonBlocking(COM_DEBUG_USART, "%u,%u,%u,%u,%u,%u,%u,%u uS\r", PIOS_PWM_Get(0), PIOS_PWM_Get(1), PIOS_PWM_Get(2), PIOS_PWM_Get(3), PIOS_PWM_Get(4), PIOS_PWM_Get(5), PIOS_PWM_Get(6), PIOS_PWM_Get(7)); #endif @@ -339,5 +335,5 @@ static void TaskSDCard(void *pvParameters) /** * @} * @} - */ + */ diff --git a/flight/OpenPilot/System/pios_board.c b/flight/OpenPilot/System/pios_board.c index ccbf8fced..f4ac5c367 100644 --- a/flight/OpenPilot/System/pios_board.c +++ b/flight/OpenPilot/System/pios_board.c @@ -30,6 +30,7 @@ #include #include #include +#include "manualcontrolsettings.h" //#define I2C_DEBUG_PIN 0 //#define USART_GPS_DEBUG_PIN 1 @@ -46,7 +47,7 @@ void PIOS_SPI_sdcard_irq_handler(void); void DMA1_Channel2_IRQHandler() __attribute__ ((alias ("PIOS_SPI_sdcard_irq_handler"))); void DMA1_Channel3_IRQHandler() __attribute__ ((alias ("PIOS_SPI_sdcard_irq_handler"))); -const struct pios_spi_cfg pios_spi_sdcard_cfg = { +static const struct pios_spi_cfg pios_spi_sdcard_cfg = { .regs = SPI1, .init = { .SPI_Mode = SPI_Mode_Master, @@ -63,7 +64,6 @@ const struct pios_spi_cfg pios_spi_sdcard_cfg = { .ahb_clk = RCC_AHBPeriph_DMA1, .irq = { - .handler = PIOS_SPI_sdcard_irq_handler, .flags = (DMA1_FLAG_TC2 | DMA1_FLAG_TE2 | DMA1_FLAG_HT2 | DMA1_FLAG_GL2), .init = { .NVIC_IRQChannel = DMA1_Channel2_IRQn, @@ -144,7 +144,7 @@ const struct pios_spi_cfg pios_spi_sdcard_cfg = { void PIOS_SPI_ahrs_irq_handler(void); void DMA1_Channel4_IRQHandler() __attribute__ ((alias ("PIOS_SPI_ahrs_irq_handler"))); void DMA1_Channel5_IRQHandler() __attribute__ ((alias ("PIOS_SPI_ahrs_irq_handler"))); -const struct pios_spi_cfg pios_spi_ahrs_cfg = { +static const struct pios_spi_cfg pios_spi_ahrs_cfg = { .regs = SPI2, .init = { .SPI_Mode = SPI_Mode_Master, @@ -162,7 +162,6 @@ const struct pios_spi_cfg pios_spi_ahrs_cfg = { .ahb_clk = RCC_AHBPeriph_DMA1, .irq = { - .handler = PIOS_SPI_ahrs_irq_handler, .flags = (DMA1_FLAG_TC4 | DMA1_FLAG_TE4 | DMA1_FLAG_HT4 | DMA1_FLAG_GL4), .init = { .NVIC_IRQChannel = DMA1_Channel4_IRQn, @@ -258,11 +257,10 @@ void PIOS_SPI_ahrs_irq_handler(void) extern void PIOS_ADC_handler(void); void DMA1_Channel1_IRQHandler() __attribute__ ((alias("PIOS_ADC_handler"))); // Remap the ADC DMA handler to this one -const struct pios_adc_cfg pios_adc_cfg = { +static const struct pios_adc_cfg pios_adc_cfg = { .dma = { .ahb_clk = RCC_AHBPeriph_DMA1, .irq = { - .handler = PIOS_ADC_DMA_Handler, .flags = (DMA1_FLAG_TC1 | DMA1_FLAG_TE1 | DMA1_FLAG_HT1 | DMA1_FLAG_GL1), .init = { .NVIC_IRQChannel = DMA1_Channel1_IRQn, @@ -310,16 +308,10 @@ void PIOS_ADC_handler() { /* * Telemetry USART */ -void PIOS_USART_telem_irq_handler(void); -void USART2_IRQHandler() __attribute__ ((alias ("PIOS_USART_telem_irq_handler"))); -const struct pios_usart_cfg pios_usart_telem_cfg = { +static const struct pios_usart_cfg pios_usart_telem_cfg = { .regs = USART2, .init = { - #if defined (PIOS_COM_TELEM_BAUDRATE) - .USART_BaudRate = PIOS_COM_TELEM_BAUDRATE, - #else - .USART_BaudRate = 57600, - #endif + .USART_BaudRate = 57600, .USART_WordLength = USART_WordLength_8b, .USART_Parity = USART_Parity_No, .USART_StopBits = USART_StopBits_1, @@ -327,7 +319,6 @@ const struct pios_usart_cfg pios_usart_telem_cfg = { .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, }, .irq = { - .handler = PIOS_USART_telem_irq_handler, .init = { .NVIC_IRQChannel = USART2_IRQn, .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, @@ -356,17 +347,11 @@ const struct pios_usart_cfg pios_usart_telem_cfg = { /* * GPS USART */ -void PIOS_USART_gps_irq_handler(void); -void USART3_IRQHandler() __attribute__ ((alias ("PIOS_USART_gps_irq_handler"))); -const struct pios_usart_cfg pios_usart_gps_cfg = { +static const struct pios_usart_cfg pios_usart_gps_cfg = { .regs = USART3, .remap = GPIO_PartialRemap_USART3, .init = { - #if defined (PIOS_COM_GPS_BAUDRATE) - .USART_BaudRate = PIOS_COM_GPS_BAUDRATE, - #else - .USART_BaudRate = 57600, - #endif + .USART_BaudRate = 57600, .USART_WordLength = USART_WordLength_8b, .USART_Parity = USART_Parity_No, .USART_StopBits = USART_StopBits_1, @@ -374,7 +359,6 @@ const struct pios_usart_cfg pios_usart_gps_cfg = { .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, }, .irq = { - .handler = PIOS_USART_gps_irq_handler, .init = { .NVIC_IRQChannel = USART3_IRQn, .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, @@ -404,16 +388,9 @@ const struct pios_usart_cfg pios_usart_gps_cfg = { /* * AUX USART */ -void PIOS_USART_aux_irq_handler(void); -void USART1_IRQHandler() __attribute__ ((alias ("PIOS_USART_aux_irq_handler"))); -const struct pios_usart_cfg pios_usart_aux_cfg = { +static const struct pios_usart_cfg pios_usart_aux_cfg = { .regs = USART1, .init = { - #if defined (PIOS_COM_AUX_BAUDRATE) - .USART_BaudRate = PIOS_COM_AUX_BAUDRATE, - #else - .USART_BaudRate = 57600, - #endif .USART_BaudRate = 57600, .USART_WordLength = USART_WordLength_8b, .USART_Parity = USART_Parity_No, @@ -422,7 +399,6 @@ const struct pios_usart_cfg pios_usart_aux_cfg = { .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, }, .irq = { - .handler = PIOS_USART_aux_irq_handler, .init = { .NVIC_IRQChannel = USART1_IRQn, .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, @@ -450,20 +426,44 @@ const struct pios_usart_cfg pios_usart_aux_cfg = { }; #endif -#ifdef PIOS_COM_SPEKTRUM +#if defined(PIOS_INCLUDE_RTC) +/* + * Realtime Clock (RTC) + */ +#include + +void PIOS_RTC_IRQ_Handler (void); +void RTC_IRQHandler() __attribute__ ((alias ("PIOS_RTC_IRQ_Handler"))); +static const struct pios_rtc_cfg pios_rtc_main_cfg = { + .clksrc = RCC_RTCCLKSource_HSE_Div128, + .prescaler = 100, + .irq = { + .init = { + .NVIC_IRQChannel = RTC_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +void PIOS_RTC_IRQ_Handler (void) +{ + PIOS_RTC_irq_handler (); +} + +#endif + +#if defined(PIOS_INCLUDE_SPEKTRUM) /* * SPEKTRUM USART */ -void PIOS_USART_spektrum_irq_handler(void); -void USART1_IRQHandler() __attribute__ ((alias ("PIOS_USART_spektrum_irq_handler"))); -const struct pios_usart_cfg pios_usart_spektrum_cfg = { +#include + +static const struct pios_usart_cfg pios_usart_spektrum_cfg = { .regs = USART1, .init = { - #if defined (PIOS_COM_SPEKTRUM_BAUDRATE) - .USART_BaudRate = PIOS_COM_SPEKTRUM_BAUDRATE, - #else - .USART_BaudRate = 115200, - #endif + .USART_BaudRate = 115200, .USART_WordLength = USART_WordLength_8b, .USART_Parity = USART_Parity_No, .USART_StopBits = USART_StopBits_1, @@ -471,7 +471,6 @@ const struct pios_usart_cfg pios_usart_spektrum_cfg = { .USART_Mode = USART_Mode_Rx, }, .irq = { - .handler = PIOS_USART_spektrum_irq_handler, .init = { .NVIC_IRQChannel = USART1_IRQn, .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, @@ -497,75 +496,24 @@ const struct pios_usart_cfg pios_usart_spektrum_cfg = { }, }; -static uint32_t pios_usart_spektrum_id; -void PIOS_USART_spektrum_irq_handler(void) -{ - SPEKTRUM_IRQHandler(pios_usart_spektrum_id); -} - #include -void TIM6_IRQHandler(); -void TIM6_IRQHandler() __attribute__ ((alias ("PIOS_TIM6_irq_handler"))); -const struct pios_spektrum_cfg pios_spektrum_cfg = { - .pios_usart_spektrum_cfg = &pios_usart_spektrum_cfg, - .tim_base_init = { - .TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1, /* For 1 uS accuracy */ - .TIM_ClockDivision = TIM_CKD_DIV1, - .TIM_CounterMode = TIM_CounterMode_Up, - .TIM_Period = ((1000000 / 120) - 1), //11ms-10*16b/115200bps, atleast one interrupt between frames - .TIM_RepetitionCounter = 0x0000, - }, - .gpio_init = { //used for bind feature - .GPIO_Mode = GPIO_Mode_Out_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - .remap = 0, - .irq = { - .handler = TIM6_IRQHandler, - .init = { - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, +static const struct pios_spektrum_cfg pios_spektrum_cfg = { + .bind = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_10, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_Out_PP, }, }, - .timer = TIM6, - .port = GPIOA, - .ccr = TIM_IT_Update, - .pin = GPIO_Pin_10, + .remap = 0, }; -void PIOS_TIM6_irq_handler() -{ - PIOS_SPEKTRUM_irq_handler(); -} #endif /* PIOS_COM_SPEKTRUM */ -static uint32_t pios_usart_telem_rf_id; -void PIOS_USART_telem_irq_handler(void) -{ - PIOS_USART_IRQ_Handler(pios_usart_telem_rf_id); -} - -static uint32_t pios_usart_gps_id; -void PIOS_USART_gps_irq_handler(void) -{ -#ifdef USART_GPS_DEBUG_PIN - PIOS_DEBUG_PinHigh(USART_GPS_DEBUG_PIN); -#endif - PIOS_USART_IRQ_Handler(pios_usart_gps_id); -#ifdef USART_GPS_DEBUG_PIN - PIOS_DEBUG_PinLow(USART_GPS_DEBUG_PIN); -#endif - -} - -#ifdef PIOS_COM_AUX -static uint32_t pios_usart_aux_id; -void PIOS_USART_aux_irq_handler(void) -{ - PIOS_USART_IRQ_Handler(pios_usart_aux_id); -} -#endif +#if defined(PIOS_INCLUDE_SBUS) +#error PIOS_INCLUDE_SBUS not implemented +#endif /* PIOS_INCLUDE_SBUS */ #endif /* PIOS_INCLUDE_USART */ @@ -573,13 +521,22 @@ void PIOS_USART_aux_irq_handler(void) #include "pios_com_priv.h" +#define PIOS_COM_TELEM_RF_RX_BUF_LEN 192 +#define PIOS_COM_TELEM_RF_TX_BUF_LEN 192 + +#define PIOS_COM_GPS_RX_BUF_LEN 96 +#define PIOS_COM_GPS_TX_BUF_LEN 96 + +#define PIOS_COM_TELEM_USB_RX_BUF_LEN 192 +#define PIOS_COM_TELEM_USB_TX_BUF_LEN 192 + #endif /* PIOS_INCLUDE_COM */ /** * Pios servo configuration structures */ #include -const struct pios_servo_channel pios_servo_channels[] = { +static const struct pios_servo_channel pios_servo_channels[] = { { .timer = TIM4, .port = GPIOB, @@ -663,7 +620,7 @@ const struct pios_servo_cfg pios_servo_cfg = { */ #if defined(PIOS_INCLUDE_PWM) #include -const struct pios_pwm_channel pios_pwm_channels[] = { +static const struct pios_pwm_channel pios_pwm_channels[] = { { .timer = TIM1, .port = GPIOA, @@ -748,7 +705,6 @@ const struct pios_pwm_cfg pios_pwm_cfg = { }, .remap = GPIO_PartialRemap_TIM3, .irq = { - .handler = TIM1_CC_IRQHandler, .init = { .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, .NVIC_IRQChannelSubPriority = 0, @@ -779,7 +735,7 @@ void PIOS_TIM5_irq_handler() #include void TIM6_IRQHandler(); void TIM6_IRQHandler() __attribute__ ((alias ("PIOS_TIM6_irq_handler"))); -const struct pios_ppmsv_cfg pios_ppmsv_cfg = { +static const struct pios_ppmsv_cfg pios_ppmsv_cfg = { .tim_base_init = { .TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1, /* For 1 uS accuracy */ .TIM_ClockDivision = TIM_CKD_DIV1, @@ -788,7 +744,6 @@ const struct pios_ppmsv_cfg pios_ppmsv_cfg = { .TIM_RepetitionCounter = 0x0000, }, .irq = { - .handler = TIM6_IRQHandler, .init = { .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, .NVIC_IRQChannelSubPriority = 0, @@ -799,14 +754,14 @@ const struct pios_ppmsv_cfg pios_ppmsv_cfg = { .ccr = TIM_IT_Update, }; -void PIOS_TIM6_irq_handler() +void PIOS_TIM6_irq_handler(void) { PIOS_PPMSV_irq_handler(); } void TIM1_CC_IRQHandler(); void TIM1_CC_IRQHandler() __attribute__ ((alias ("PIOS_TIM1_CC_irq_handler"))); -const struct pios_ppm_cfg pios_ppm_cfg = { +static const struct pios_ppm_cfg pios_ppm_cfg = { .tim_base_init = { .TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1, /* For 1 uS accuracy */ .TIM_ClockDivision = TIM_CKD_DIV1, @@ -828,7 +783,6 @@ const struct pios_ppm_cfg pios_ppm_cfg = { }, .remap = 0, .irq = { - .handler = TIM1_CC_IRQHandler, .init = { .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, .NVIC_IRQChannelSubPriority = 0, @@ -841,7 +795,7 @@ const struct pios_ppm_cfg pios_ppm_cfg = { .ccr = TIM_IT_CC2, }; -void PIOS_TIM1_CC_irq_handler() +void PIOS_TIM1_CC_irq_handler(void) { PIOS_PPM_irq_handler(); } @@ -861,7 +815,7 @@ void PIOS_I2C_main_adapter_er_irq_handler(void); void I2C2_EV_IRQHandler() __attribute__ ((alias ("PIOS_I2C_main_adapter_ev_irq_handler"))); void I2C2_ER_IRQHandler() __attribute__ ((alias ("PIOS_I2C_main_adapter_er_irq_handler"))); -const struct pios_i2c_adapter_cfg pios_i2c_main_adapter_cfg = { +static const struct pios_i2c_adapter_cfg pios_i2c_main_adapter_cfg = { .regs = I2C2, .init = { .I2C_Mode = I2C_Mode_I2C, @@ -889,7 +843,6 @@ const struct pios_i2c_adapter_cfg pios_i2c_main_adapter_cfg = { }, }, .event = { - .handler = PIOS_I2C_main_adapter_ev_irq_handler, .flags = 0, /* FIXME: check this */ .init = { .NVIC_IRQChannel = I2C2_EV_IRQn, @@ -899,7 +852,6 @@ const struct pios_i2c_adapter_cfg pios_i2c_main_adapter_cfg = { }, }, .error = { - .handler = PIOS_I2C_main_adapter_er_irq_handler, .flags = 0, /* FIXME: check this */ .init = { .NVIC_IRQChannel = I2C2_ER_IRQn, @@ -1010,6 +962,28 @@ static const struct stm32_gpio pios_debug_pins[] = { #endif /* PIOS_ENABLE_DEBUG_PINS */ +#if defined(PIOS_INCLUDE_RCVR) +#include "pios_rcvr_priv.h" + +struct pios_rcvr_channel_map pios_rcvr_channel_to_id_map[PIOS_RCVR_MAX_CHANNELS]; +uint32_t pios_rcvr_max_channel; +#endif /* PIOS_INCLUDE_RCVR */ + +#if defined(PIOS_INCLUDE_USB_HID) +#include "pios_usb_hid_priv.h" + +static const struct pios_usb_hid_cfg pios_usb_hid_main_cfg = { + .irq = { + .init = { + .NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; +#endif /* PIOS_INCLUDE_USB_HID */ + extern const struct pios_com_driver pios_usb_com_driver; uint32_t pios_com_telem_rf_id; @@ -1039,7 +1013,7 @@ void PIOS_Board_Init(void) { #if defined(PIOS_INCLUDE_SPI) /* Set up the SPI interface to the SD card */ if (PIOS_SPI_Init(&pios_spi_sdcard_id, &pios_spi_sdcard_cfg)) { - PIOS_DEBUG_Assert(0); + PIOS_Assert(0); } /* Enable and mount the SDCard */ @@ -1047,21 +1021,14 @@ void PIOS_Board_Init(void) { PIOS_SDCARD_MountFS(0); #endif /* PIOS_INCLUDE_SPI */ -#if defined(PIOS_INCLUDE_SPEKTRUM) - /* SPEKTRUM init must come before comms */ - PIOS_SPEKTRUM_Init(); - - if (PIOS_USART_Init(&pios_usart_spektrum_id, &pios_usart_spektrum_cfg)) { - PIOS_DEBUG_Assert(0); - } - if (PIOS_COM_Init(&pios_com_spektrum_id, &pios_usart_com_driver, pios_usart_spektrum_id)) { - PIOS_DEBUG_Assert(0); - } -#endif /* Initialize UAVObject libraries */ EventDispatcherInitialize(); UAVObjInitialize(); - UAVObjectsInitializeAll(); + +#if defined(PIOS_INCLUDE_RTC) + /* Initialize the real-time clock and its associated tick */ + PIOS_RTC_Init(&pios_rtc_main_cfg); +#endif /* Initialize the alarms library */ AlarmsInitialize(); @@ -1074,7 +1041,7 @@ void PIOS_Board_Init(void) { /* Set up the SPI interface to the AHRS */ if (PIOS_SPI_Init(&pios_spi_ahrs_id, &pios_spi_ahrs_cfg)) { - PIOS_DEBUG_Assert(0); + PIOS_Assert(0); } /* Bind the AHRS comms layer to the AHRS SPI link */ @@ -1082,43 +1049,147 @@ void PIOS_Board_Init(void) { /* Initialize the PiOS library */ #if defined(PIOS_INCLUDE_COM) - if (PIOS_USART_Init(&pios_usart_telem_rf_id, &pios_usart_telem_cfg)) { - PIOS_DEBUG_Assert(0); - } - if (PIOS_COM_Init(&pios_com_telem_rf_id, &pios_usart_com_driver, pios_usart_telem_rf_id)) { - PIOS_DEBUG_Assert(0); - } +#if defined(PIOS_INCLUDE_TELEMETRY_RF) + { + uint32_t pios_usart_telem_rf_id; + if (PIOS_USART_Init(&pios_usart_telem_rf_id, &pios_usart_telem_cfg)) { + PIOS_Assert(0); + } - if (PIOS_USART_Init(&pios_usart_gps_id, &pios_usart_gps_cfg)) { - PIOS_DEBUG_Assert(0); + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_RX_BUF_LEN); + uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_TX_BUF_LEN); + PIOS_Assert(rx_buffer); + PIOS_Assert(tx_buffer); + if (PIOS_COM_Init(&pios_com_telem_rf_id, &pios_usart_com_driver, pios_usart_telem_rf_id, + rx_buffer, PIOS_COM_TELEM_RF_RX_BUF_LEN, + tx_buffer, PIOS_COM_TELEM_RF_TX_BUF_LEN)) { + PIOS_Assert(0); + } } - if (PIOS_COM_Init(&pios_com_gps_id, &pios_usart_com_driver, pios_usart_gps_id)) { - PIOS_DEBUG_Assert(0); +#endif /* PIOS_INCLUDE_TELEMETRY_RF */ + +#if defined(PIOS_INCLUDE_GPS) + { + uint32_t pios_usart_gps_id; + if (PIOS_USART_Init(&pios_usart_gps_id, &pios_usart_gps_cfg)) { + PIOS_Assert(0); + } + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_GPS_RX_BUF_LEN); + uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_GPS_TX_BUF_LEN); + PIOS_Assert(rx_buffer); + PIOS_Assert(tx_buffer); + if (PIOS_COM_Init(&pios_com_gps_id, &pios_usart_com_driver, pios_usart_gps_id, + rx_buffer, PIOS_COM_GPS_RX_BUF_LEN, + tx_buffer, PIOS_COM_GPS_TX_BUF_LEN)) { + PIOS_Assert(0); + } } +#endif /* PIOS_INCLUDE_GPS */ #endif PIOS_Servo_Init(); PIOS_ADC_Init(); PIOS_GPIO_Init(); + /* Configure the selected receiver */ + uint8_t manualcontrolsettings_inputmode; + ManualControlSettingsInputModeGet(&manualcontrolsettings_inputmode); + + switch (manualcontrolsettings_inputmode) { + case MANUALCONTROLSETTINGS_INPUTMODE_PWM: #if defined(PIOS_INCLUDE_PWM) - PIOS_PWM_Init(); +#if (PIOS_PWM_NUM_INPUTS > PIOS_RCVR_MAX_CHANNELS) +#error More receiver inputs than available devices #endif + PIOS_PWM_Init(); + uint32_t pios_pwm_rcvr_id; + if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, 0)) { + PIOS_Assert(0); + } + for (uint8_t i = 0; + i < PIOS_PWM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); + i++) { + pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_pwm_rcvr_id; + pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; + pios_rcvr_max_channel++; + } +#endif /* PIOS_INCLUDE_PWM */ + break; + case MANUALCONTROLSETTINGS_INPUTMODE_PPM: #if defined(PIOS_INCLUDE_PPM) - PIOS_PPM_Init(); +#if (PIOS_PPM_NUM_INPUTS > PIOS_RCVR_MAX_CHANNELS) +#error More receiver inputs than available devices #endif + PIOS_PPM_Init(); + uint32_t pios_ppm_rcvr_id; + if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, 0)) { + PIOS_Assert(0); + } + for (uint8_t i = 0; + i < PIOS_PPM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); + i++) { + pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_ppm_rcvr_id; + pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; + pios_rcvr_max_channel++; + } +#endif /* PIOS_INCLUDE_PPM */ + break; + case MANUALCONTROLSETTINGS_INPUTMODE_SPEKTRUM: +#if defined(PIOS_INCLUDE_SPEKTRUM) +#if (PIOS_SPEKTRUM_NUM_INPUTS > PIOS_RCVR_MAX_CHANNELS) +#error More receiver inputs than available devices +#endif + { + uint32_t pios_usart_spektrum_id; + if (PIOS_USART_Init(&pios_usart_spektrum_id, &pios_usart_spektrum_cfg)) { + PIOS_Assert(0); + } + + uint32_t pios_spektrum_id; + if (PIOS_SPEKTRUM_Init(&pios_spektrum_id, &pios_spektrum_cfg, &pios_usart_com_driver, pios_usart_spektrum_id, false)) { + PIOS_Assert(0); + } + + uint32_t pios_spektrum_rcvr_id; + if (PIOS_RCVR_Init(&pios_spektrum_rcvr_id, &pios_spektrum_rcvr_driver, 0)) { + PIOS_Assert(0); + } + for (uint8_t i = 0; + i < PIOS_SPEKTRUM_NUM_INPUTS && pios_rcvr_max_channel < NELEMENTS(pios_rcvr_channel_to_id_map); + i++) { + pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].id = pios_spektrum_rcvr_id; + pios_rcvr_channel_to_id_map[pios_rcvr_max_channel].channel = i; + pios_rcvr_max_channel++; + } + } +#endif + break; + case MANUALCONTROLSETTINGS_INPUTMODE_SBUS: +#if defined(PIOS_INCLUDE_SBUS) +#error SBUS NOT ON OP YET +#endif /* PIOS_INCLUDE_SBUS */ + break; + } + #if defined(PIOS_INCLUDE_USB_HID) - PIOS_USB_HID_Init(0); + uint32_t pios_usb_hid_id; + PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_main_cfg); #if defined(PIOS_INCLUDE_COM) - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_com_driver, 0)) { - PIOS_DEBUG_Assert(0); + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); + uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); + PIOS_Assert(rx_buffer); + PIOS_Assert(tx_buffer); + if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_com_driver, pios_usb_hid_id, + rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, + tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { + PIOS_Assert(0); } #endif /* PIOS_INCLUDE_COM */ -#endif /* PIOS_INCLUDE_USB_HID */ +#endif /* PIOS_INCLUDE_USB_HID */ #if defined(PIOS_INCLUDE_I2C) if (PIOS_I2C_Init(&pios_i2c_main_adapter_id, &pios_i2c_main_adapter_cfg)) { - PIOS_DEBUG_Assert(0); + PIOS_Assert(0); } #endif /* PIOS_INCLUDE_I2C */ PIOS_IAP_Init(); diff --git a/flight/OpenPilot/System/pios_board_posix.c b/flight/OpenPilot/System/pios_board_posix.c index 87d8e7402..e1e8dcc54 100644 --- a/flight/OpenPilot/System/pios_board_posix.c +++ b/flight/OpenPilot/System/pios_board_posix.c @@ -29,42 +29,32 @@ #include #include -/** - * PIOS_Board_Init() - * initializes all the core systems on this specific hardware - * called from System/openpilot.c - */ -void PIOS_Board_Init(void) { +#include "attituderaw.h" +#include "attitudeactual.h" +#include "positionactual.h" +#include "velocityactual.h" - /* Delay system */ - PIOS_DELAY_Init(); +#include "pios_rcvr_priv.h" - /* Initialize UAVObject libraries */ - EventDispatcherInitialize(); - UAVObjInitialize(); - UAVObjectsInitializeAll(); +struct pios_rcvr_channel_map pios_rcvr_channel_to_id_map[PIOS_RCVR_MAX_CHANNELS]; +uint32_t pios_rcvr_max_channel; - /* Initialize the alarms library */ - AlarmsInitialize(); - - /* Initialize the task monitor library */ - TaskMonitorInitialize(); - - /* Initialize the PiOS library */ - PIOS_COM_Init(); +void Stack_Change() { +} +void Stack_Change_Weak() { } -const struct pios_udp_cfg pios_udp0_cfg = { +const struct pios_udp_cfg pios_udp_telem_cfg = { .ip = "0.0.0.0", .port = 9000, }; -const struct pios_udp_cfg pios_udp1_cfg = { +const struct pios_udp_cfg pios_udp_gps_cfg = { .ip = "0.0.0.0", .port = 9001, }; -const struct pios_udp_cfg pios_udp2_cfg = { +const struct pios_udp_cfg pios_udp_debug_cfg = { .ip = "0.0.0.0", .port = 9002, }; @@ -73,15 +63,20 @@ const struct pios_udp_cfg pios_udp2_cfg = { /* * AUX USART */ -const struct pios_udp_cfg pios_udp3_cfg = { +const struct pios_udp_cfg pios_udp_aux_cfg = { .ip = "0.0.0.0", .port = 9003, }; #endif +#define PIOS_COM_TELEM_RF_RX_BUF_LEN 192 +#define PIOS_COM_TELEM_RF_TX_BUF_LEN 192 +#define PIOS_COM_GPS_RX_BUF_LEN 192 + /* * Board specific number of devices. */ +/* struct pios_udp_dev pios_udp_devs[] = { #define PIOS_UDP_TELEM 0 { @@ -104,7 +99,7 @@ struct pios_udp_dev pios_udp_devs[] = { }; uint8_t pios_udp_num_devices = NELEMENTS(pios_udp_devs); - +*/ /* * COM devices */ @@ -115,28 +110,79 @@ uint8_t pios_udp_num_devices = NELEMENTS(pios_udp_devs); extern const struct pios_com_driver pios_serial_com_driver; extern const struct pios_com_driver pios_udp_com_driver; -struct pios_com_dev pios_com_devs[] = { - { - .id = PIOS_UDP_TELEM, - .driver = &pios_udp_com_driver, - }, - { - .id = PIOS_UDP_GPS, - .driver = &pios_udp_com_driver, - }, - { - .id = PIOS_UDP_LOCAL, - .driver = &pios_udp_com_driver, - }, -#ifdef PIOS_COM_AUX - { - .id = PIOS_UDP_AUX, - .driver = &pios_udp_com_driver, - }, -#endif -}; +uint32_t pios_com_telem_rf_id; +uint32_t pios_com_telem_usb_id; +uint32_t pios_com_gps_id; +uint32_t pios_com_aux_id; +uint32_t pios_com_spectrum_id; -const uint8_t pios_com_num_devices = NELEMENTS(pios_com_devs); +/** + * PIOS_Board_Init() + * initializes all the core systems on this specific hardware + * called from System/openpilot.c + */ +void PIOS_Board_Init(void) { + + /* Delay system */ + PIOS_DELAY_Init(); + + /* Initialize UAVObject libraries */ + EventDispatcherInitialize(); + UAVObjInitialize(); + UAVObjectsInitializeAll(); + + /* Initialize the alarms library */ + AlarmsInitialize(); + + /* Initialize the task monitor library */ + TaskMonitorInitialize(); + +#if defined(PIOS_INCLUDE_COM) +#if defined(PIOS_INCLUDE_TELEMETRY_RF) + { + uint32_t pios_udp_telem_rf_id; + if (PIOS_UDP_Init(&pios_udp_telem_rf_id, &pios_udp_telem_cfg)) { + PIOS_Assert(0); + } + + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_RX_BUF_LEN); + uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_TELEM_RF_TX_BUF_LEN); + PIOS_Assert(rx_buffer); + PIOS_Assert(tx_buffer); + if (PIOS_COM_Init(&pios_com_telem_rf_id, &pios_udp_com_driver, pios_udp_telem_rf_id, + rx_buffer, PIOS_COM_TELEM_RF_RX_BUF_LEN, + tx_buffer, PIOS_COM_TELEM_RF_TX_BUF_LEN)) { + PIOS_Assert(0); + } + } +#endif /* PIOS_INCLUDE_TELEMETRY_RF */ + +#if defined(PIOS_INCLUDE_GPS) + { + uint32_t pios_udp_gps_id; + if (PIOS_UDP_Init(&pios_udp_gps_id, &pios_udp_gps_cfg)) { + PIOS_Assert(0); + } + uint8_t * rx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_GPS_RX_BUF_LEN); + uint8_t * tx_buffer = (uint8_t *) pvPortMalloc(PIOS_COM_GPS_RX_BUF_LEN); + PIOS_Assert(rx_buffer); + PIOS_Assert(tx_buffer); + if (PIOS_COM_Init(&pios_com_gps_id, &pios_udp_com_driver, pios_udp_gps_id, + rx_buffer, PIOS_COM_GPS_RX_BUF_LEN, + tx_buffer, PIOS_COM_GPS_RX_BUF_LEN)) { + PIOS_Assert(0); + } + } +#endif /* PIOS_INCLUDE_GPS */ +#endif + + // Initialize these here as posix has no AHRSComms + AttitudeRawInitialize(); + AttitudeActualInitialize(); + VelocityActualInitialize(); + PositionActualInitialize(); + +} /** * @} diff --git a/flight/OpenPilot/System/taskmonitor.c b/flight/OpenPilot/System/taskmonitor.c index bc9651982..dcd08945c 100644 --- a/flight/OpenPilot/System/taskmonitor.c +++ b/flight/OpenPilot/System/taskmonitor.c @@ -35,6 +35,7 @@ // Private variables static xSemaphoreHandle lock; static xTaskHandle handles[TASKINFO_RUNNING_NUMELEM]; +static uint32_t lastMonitorTime; // Private functions @@ -45,6 +46,10 @@ int32_t TaskMonitorInitialize(void) { lock = xSemaphoreCreateRecursiveMutex(); memset(handles, 0, sizeof(xTaskHandle)*TASKINFO_RUNNING_NUMELEM); + lastMonitorTime = 0; +#if defined(DIAGNOSTICS) + lastMonitorTime = portGET_RUN_TIME_COUNTER_VALUE(); +#endif return 0; } @@ -89,12 +94,27 @@ int32_t TaskMonitorRemove(TaskInfoRunningElem task) */ void TaskMonitorUpdateAll(void) { +#if defined(DIAGNOSTICS) TaskInfoData data; int n; // Lock xSemaphoreTakeRecursive(lock, portMAX_DELAY); +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + uint32_t currentTime; + uint32_t deltaTime; + + /* + * Calculate the amount of elapsed run time between the last time we + * measured and now. Scale so that we can convert task run times + * directly to percentages. + */ + currentTime = portGET_RUN_TIME_COUNTER_VALUE(); + deltaTime = ((currentTime - lastMonitorTime) / 100) ? : 1; /* avoid divide-by-zero if the interval is too small */ + lastMonitorTime = currentTime; +#endif + // Update all task information for (n = 0; n < TASKINFO_RUNNING_NUMELEM; ++n) { @@ -107,7 +127,8 @@ void TaskMonitorUpdateAll(void) data.StackRemaining[n] = uxTaskGetStackHighWaterMark(handles[n]) * 4; #if ( configGENERATE_RUN_TIME_STATS == 1 ) /* Generate run time stats */ - data.RunningTime[n] = 100 * (float) uxTaskGetRunTime(handles[n]) / portGET_RUN_TIME_COUNTER_VALUE(); + data.RunningTime[n] = uxTaskGetRunTime(handles[n]) / deltaTime; + #endif #endif @@ -125,4 +146,5 @@ void TaskMonitorUpdateAll(void) // Done xSemaphoreGiveRecursive(lock); +#endif } diff --git a/flight/OpenPilot/UAVObjects.inc b/flight/OpenPilot/UAVObjects.inc index 4849367a9..67dd71b97 100644 --- a/flight/OpenPilot/UAVObjects.inc +++ b/flight/OpenPilot/UAVObjects.inc @@ -24,6 +24,7 @@ # (all architectures) UAVOBJSRCFILENAMES = +UAVOBJSRCFILENAMES += accessorydesired UAVOBJSRCFILENAMES += actuatorcommand UAVOBJSRCFILENAMES += actuatordesired UAVOBJSRCFILENAMES += actuatorsettings @@ -68,6 +69,8 @@ UAVOBJSRCFILENAMES += velocityactual UAVOBJSRCFILENAMES += velocitydesired UAVOBJSRCFILENAMES += watchdogstatus UAVOBJSRCFILENAMES += flightstatus +UAVOBJSRCFILENAMES += cameradesired +UAVOBJSRCFILENAMES += camerastabsettings UAVOBJSRC = $(foreach UAVOBJSRCFILE,$(UAVOBJSRCFILENAMES),$(UAVOBJSYNTHDIR)/$(UAVOBJSRCFILE).c ) UAVOBJDEFINE = $(foreach UAVOBJSRCFILE,$(UAVOBJSRCFILENAMES),-DUAVOBJ_INIT_$(UAVOBJSRCFILE) ) diff --git a/flight/PiOS.posix/inc/pios_com.h b/flight/PiOS.posix/inc/pios_com.h index 361e820d5..cbee33735 100644 --- a/flight/PiOS.posix/inc/pios_com.h +++ b/flight/PiOS.posix/inc/pios_com.h @@ -1,55 +1,65 @@ -/** - ****************************************************************************** - * - * @file pios_com.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Thorsten Klose (tk@midibox.org) - * @brief COM layer functions header - * @see The GNU Public License (GPL) Version 3 - * - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef PIOS_COM_H -#define PIOS_COM_H - -/* Public Functions */ -extern int32_t PIOS_COM_Init(void); -extern int32_t PIOS_COM_ChangeBaud(uint8_t port, uint32_t baud); -extern int32_t PIOS_COM_SendCharNonBlocking(uint8_t port, char c); -extern int32_t PIOS_COM_SendChar(uint8_t port, char c); -extern int32_t PIOS_COM_SendBufferNonBlocking(uint8_t port, uint8_t *buffer, uint16_t len); -extern int32_t PIOS_COM_SendBuffer(uint8_t port, uint8_t *buffer, uint16_t len); -extern int32_t PIOS_COM_SendStringNonBlocking(uint8_t port, char *str); -extern int32_t PIOS_COM_SendString(uint8_t port, char *str); -extern int32_t PIOS_COM_SendFormattedStringNonBlocking(uint8_t port, char *format, ...); -extern int32_t PIOS_COM_SendFormattedString(uint8_t port, char *format, ...); -extern uint8_t PIOS_COM_ReceiveBuffer(uint8_t port); -extern int32_t PIOS_COM_ReceiveBufferUsed(uint8_t port); - -extern int32_t PIOS_COM_ReceiveHandler(void); - -struct pios_com_driver { - void (*init)(uint8_t id); - void (*set_baud)(uint8_t id, uint32_t baud); - int32_t (*tx_nb)(uint8_t id, uint8_t *buffer, uint16_t len); - int32_t (*tx)(uint8_t id, uint8_t *buffer, uint16_t len); - int32_t (*rx)(uint8_t id); - int32_t (*rx_avail)(uint8_t id); -}; - -#endif /* PIOS_COM_H */ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_COM COM layer functions + * @brief Hardware communication layer + * @{ + * + * @file pios_com.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Parts by Thorsten Klose (tk@midibox.org) + * @brief COM layer functions header + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_COM_H +#define PIOS_COM_H + +typedef uint16_t (*pios_com_callback)(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * task_woken); + +struct pios_com_driver { + void (*init)(uint32_t id); + void (*set_baud)(uint32_t id, uint32_t baud); + void (*tx_start)(uint32_t id, uint16_t tx_bytes_avail); + void (*rx_start)(uint32_t id, uint16_t rx_bytes_avail); + void (*bind_rx_cb)(uint32_t id, pios_com_callback rx_in_cb, uint32_t context); + void (*bind_tx_cb)(uint32_t id, pios_com_callback tx_out_cb, uint32_t context); +}; + +/* Public Functions */ +extern int32_t PIOS_COM_Init(uint32_t * com_id, const struct pios_com_driver * driver, uint32_t lower_id, uint8_t * rx_buffer, uint16_t rx_buffer_len, uint8_t * tx_buffer, uint16_t tx_buffer_len); +extern int32_t PIOS_COM_ChangeBaud(uint32_t com_id, uint32_t baud); +extern int32_t PIOS_COM_SendCharNonBlocking(uint32_t com_id, char c); +extern int32_t PIOS_COM_SendChar(uint32_t com_id, char c); +extern int32_t PIOS_COM_SendBufferNonBlocking(uint32_t com_id, const uint8_t *buffer, uint16_t len); +extern int32_t PIOS_COM_SendBuffer(uint32_t com_id, const uint8_t *buffer, uint16_t len); +extern int32_t PIOS_COM_SendStringNonBlocking(uint32_t com_id, const char *str); +extern int32_t PIOS_COM_SendString(uint32_t com_id, const char *str); +extern int32_t PIOS_COM_SendFormattedStringNonBlocking(uint32_t com_id, const char *format, ...); +extern int32_t PIOS_COM_SendFormattedString(uint32_t com_id, const char *format, ...); +extern uint16_t PIOS_COM_ReceiveBuffer(uint32_t com_id, uint8_t * buf, uint16_t buf_len, uint32_t timeout_ms); +extern int32_t PIOS_COM_ReceiveBufferUsed(uint32_t com_id); + +#endif /* PIOS_COM_H */ + +/** + * @} + * @} + */ diff --git a/flight/PiOS.posix/inc/pios_com_priv.h b/flight/PiOS.posix/inc/pios_com_priv.h index 5b285edac..54af82bcb 100644 --- a/flight/PiOS.posix/inc/pios_com_priv.h +++ b/flight/PiOS.posix/inc/pios_com_priv.h @@ -1,5 +1,10 @@ /** ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_COM COM layer functions + * @brief Hardware communication layer + * @{ * * @file pios_com_priv.h * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. @@ -29,13 +34,11 @@ #include -struct pios_com_dev { - uint8_t id; - const struct pios_com_driver * const driver; -}; - -extern struct pios_com_dev pios_com_devs[]; -extern const uint8_t pios_com_num_devices; +extern int32_t PIOS_COM_ReceiveHandler(uint32_t com_id); #endif /* PIOS_COM_PRIV_H */ +/** + * @} + * @} + */ diff --git a/flight/PiOS.posix/inc/pios_crc.h b/flight/PiOS.posix/inc/pios_crc.h new file mode 100644 index 000000000..3a64f8bab --- /dev/null +++ b/flight/PiOS.posix/inc/pios_crc.h @@ -0,0 +1,31 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_CRC CRC Functions + * @{ + * + * @file pios_crc.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief CRC functions header. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +uint8_t PIOS_CRC_updateByte(uint8_t crc, const uint8_t data); +uint8_t PIOS_CRC_updateCRC(uint8_t crc, const uint8_t* data, int32_t length); diff --git a/flight/PiOS.posix/inc/pios_initcall.h b/flight/PiOS.posix/inc/pios_initcall.h index c80cd47a8..f88081c33 100644 --- a/flight/PiOS.posix/inc/pios_initcall.h +++ b/flight/PiOS.posix/inc/pios_initcall.h @@ -38,7 +38,31 @@ * and we cannot define a linker script for each of them atm */ -#define uavobj_initcall(fn) + +typedef int32_t (*initcall_t)(void); +typedef struct { + initcall_t fn_minit; + initcall_t fn_tinit; +} initmodule_t; + +/* Init module section */ +extern initmodule_t __module_initcall_start[], __module_initcall_end[]; + +extern void InitModules(); +extern void StartModules(); + +#define MODULE_INITCALL(ifn, sfn) + +#define MODULE_TASKCREATE_ALL { \ + /* Start all module threads */ \ + StartModules(); \ + } + +#define MODULE_INITIALISE_ALL { \ + /* Initialize modules */ \ + InitModules(); \ + /* Initialize the system thread */ \ + SystemModInitialize();} #endif /* PIOS_INITCALL_H */ diff --git a/flight/PiOS.posix/inc/pios_irq.h b/flight/PiOS.posix/inc/pios_irq.h new file mode 100644 index 000000000..f9b9dbb97 --- /dev/null +++ b/flight/PiOS.posix/inc/pios_irq.h @@ -0,0 +1,38 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_IRQ IRQ Setup Functions + * @{ + * + * @file pios_irq.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Parts by Thorsten Klose (tk@midibox.org) + * @brief IRQ functions header. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_IRQ_H +#define PIOS_IRQ_H + +/* Public Functions */ +extern int32_t PIOS_IRQ_Disable(void); +extern int32_t PIOS_IRQ_Enable(void); + +#endif /* PIOS_IRQ_H */ diff --git a/flight/PiOS.posix/inc/pios_rcvr.h b/flight/PiOS.posix/inc/pios_rcvr.h new file mode 100644 index 000000000..a32160894 --- /dev/null +++ b/flight/PiOS.posix/inc/pios_rcvr.h @@ -0,0 +1,54 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_RCVR RCVR layer functions + * @brief Hardware communication layer + * @{ + * + * @file pios_rcvr.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief RCVR layer functions header + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_RCVR_H +#define PIOS_RCVR_H + +struct pios_rcvr_channel_map { + uint32_t id; + uint8_t channel; +}; + +extern struct pios_rcvr_channel_map pios_rcvr_channel_to_id_map[]; + +struct pios_rcvr_driver { + void (*init)(uint32_t id); + int32_t (*read)(uint32_t id, uint8_t channel); +}; + +/* Public Functions */ +extern int32_t PIOS_RCVR_Read(uint32_t rcvr_id, uint8_t channel); + +#endif /* PIOS_RCVR_H */ + +/** + * @} + * @} + */ diff --git a/flight/PiOS.posix/inc/pios_rcvr_priv.h b/flight/PiOS.posix/inc/pios_rcvr_priv.h new file mode 100644 index 000000000..968dc2116 --- /dev/null +++ b/flight/PiOS.posix/inc/pios_rcvr_priv.h @@ -0,0 +1,48 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_RCVR RCVR Functions + * @brief PIOS interface for RCVR drivers + * @{ + * + * @file pios_rcvr_priv.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Parts by Thorsten Klose (tk@midibox.org) + * @brief USART private definitions. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_RCVR_PRIV_H +#define PIOS_RCVR_PRIV_H + +#include + +extern uint32_t pios_rcvr_max_channel; + +extern int32_t PIOS_RCVR_Init(uint32_t * rcvr_id, const struct pios_rcvr_driver * driver, const uint32_t lower_id); + +extern void PIOS_RCVR_IRQ_Handler(uint32_t rcvr_id); + +#endif /* PIOS_RCVR_PRIV_H */ + +/** + * @} + * @} + */ diff --git a/flight/PiOS.posix/inc/pios_udp.h b/flight/PiOS.posix/inc/pios_udp.h index 7376ee6a1..36964a342 100644 --- a/flight/PiOS.posix/inc/pios_udp.h +++ b/flight/PiOS.posix/inc/pios_udp.h @@ -31,21 +31,5 @@ /* Global Types */ /* Public Functions */ -//extern void PIOS_UDP_Init(void); -void PIOS_UDP_Init(void); -extern void PIOS_UDP_ChangeBaud(uint8_t usart, uint32_t baud); - -extern int32_t PIOS_UDP_RxBufferFree(uint8_t usart); -extern int32_t PIOS_UDP_RxBufferUsed(uint8_t usart); -extern int32_t PIOS_UDP_RxBufferGet(uint8_t usart); -extern int32_t PIOS_UDP_RxBufferPeek(uint8_t usart); -extern int32_t PIOS_UDP_RxBufferPut(uint8_t usart, uint8_t b); - -extern int32_t PIOS_UDP_TxBufferFree(uint8_t usart); -extern int32_t PIOS_UDP_TxBufferGet(uint8_t usart); -extern int32_t PIOS_UDP_TxBufferPutMoreNonBlocking(uint8_t usart, uint8_t *buffer, uint16_t len); -extern int32_t PIOS_UDP_TxBufferPutMore(uint8_t usart, uint8_t *buffer, uint16_t len); -extern int32_t PIOS_UDP_TxBufferPutNonBlocking(uint8_t usart, uint8_t b); -extern int32_t PIOS_UDP_TxBufferPut(uint8_t usart, uint8_t b); #endif /* PIOS_UDP_H */ diff --git a/flight/PiOS.posix/inc/pios_udp_priv.h b/flight/PiOS.posix/inc/pios_udp_priv.h index 8f714cc56..999e192e9 100644 --- a/flight/PiOS.posix/inc/pios_udp_priv.h +++ b/flight/PiOS.posix/inc/pios_udp_priv.h @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -37,30 +38,34 @@ #include #include - - struct pios_udp_cfg { const char * ip; uint16_t port; }; -struct pios_udp_buffer { - uint8_t buf[PIOS_UDP_RX_BUFFER_SIZE]; - uint16_t head; - uint16_t tail; - uint16_t size; -}; +typedef struct { + const struct pios_udp_cfg * cfg; + pthread_t rxThread; -struct pios_udp_dev { - const struct pios_udp_cfg * const cfg; - struct pios_udp_buffer rx; int socket; struct sockaddr_in server; struct sockaddr_in client; uint32_t clientLength; -}; -extern struct pios_udp_dev pios_udp_devs[]; -extern uint8_t pios_udp_num_devices; + pthread_cond_t cond; + pthread_mutex_t mutex; + + pios_com_callback tx_out_cb; + uint32_t tx_out_context; + pios_com_callback rx_in_cb; + uint32_t rx_in_context; + + uint8_t rx_buffer[PIOS_UDP_RX_BUFFER_SIZE]; + uint8_t tx_buffer[PIOS_UDP_RX_BUFFER_SIZE]; +} pios_udp_dev; + +extern int32_t PIOS_UDP_Init(uint32_t * udp_id, const struct pios_udp_cfg * cfg); + + #endif /* PIOS_UDP_PRIV_H */ diff --git a/flight/PiOS.posix/pios.h b/flight/PiOS.posix/pios.h index 4f6266aca..9256891b1 100644 --- a/flight/PiOS.posix/pios.h +++ b/flight/PiOS.posix/pios.h @@ -58,12 +58,15 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include #define NELEMENTS(x) (sizeof(x) / sizeof(*(x))) diff --git a/flight/PiOS.posix/posix/pios_com.c b/flight/PiOS.posix/posix/pios_com.c index a70715f24..77c2e2595 100644 --- a/flight/PiOS.posix/posix/pios_com.c +++ b/flight/PiOS.posix/posix/pios_com.c @@ -1,285 +1,522 @@ -/** - ****************************************************************************** - * - * @file pios_com.c - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Thorsten Klose (tk@midibox.org) - * @brief COM layer functions - * @see The GNU Public License (GPL) Version 3 - * @defgroup PIOS_COM COM layer functions - * @{ - * - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -/* Project Includes */ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_COM COM layer functions + * @brief Hardware communication layer + * @{ + * + * @file pios_com.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Parts by Thorsten Klose (tk@midibox.org) + * @brief COM layer functions + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Project Includes */ #include "pios.h" #if defined(PIOS_INCLUDE_COM) +#include "fifo_buffer.h" #include -static struct pios_com_dev * find_com_dev_by_id (uint8_t port) -{ - if (port >= pios_com_num_devices) { - /* Undefined COM port for this board (see pios_board.c) */ - return NULL; - } +#if !defined(PIOS_INCLUDE_FREERTOS) +#include "pios_delay.h" /* PIOS_DELAY_WaitmS */ +#endif - /* Get a handle for the device configuration */ - return &(pios_com_devs[port]); +enum pios_com_dev_magic { + PIOS_COM_DEV_MAGIC = 0xaa55aa55, +}; + +struct pios_com_dev { + enum pios_com_dev_magic magic; + uint32_t lower_id; + const struct pios_com_driver * driver; + +#if defined(PIOS_INCLUDE_FREERTOS) + xSemaphoreHandle tx_sem; + xSemaphoreHandle rx_sem; +#endif + + bool has_rx; + bool has_tx; + + t_fifo_buffer rx; + t_fifo_buffer tx; +}; + +static bool PIOS_COM_validate(struct pios_com_dev * com_dev) +{ + return (com_dev && (com_dev->magic == PIOS_COM_DEV_MAGIC)); } -/** -* Initialises COM layer -* \param[in] mode currently only mode 0 supported -* \return < 0 if initialisation failed -*/ -int32_t PIOS_COM_Init(void) -{ - int32_t ret = 0; - - /* If any COM assignment: */ -#if defined(PIOS_INCLUDE_SERIAL) - PIOS_SERIAL_Init(); -#endif - -#if defined(PIOS_INCLUDE_UDP) - PIOS_UDP_Init(); -#endif - - return ret; -} - -/** -* Change the port speed without re-initializing -* \param[in] port COM port -* \param[in] baud Requested baud rate -* \return -1 if port not available -* \return 0 on success -*/ -int32_t PIOS_COM_ChangeBaud(uint8_t port, uint32_t baud) +#if defined(PIOS_INCLUDE_FREERTOS) && 0 +// static struct pios_com_dev * PIOS_COM_alloc(void) +//{ +// struct pios_com_dev * com_dev; +// +// com_dev = (struct pios_com_dev *)malloc(sizeof(*com_dev)); +// if (!com_dev) return (NULL); +// +// com_dev->magic = PIOS_COM_DEV_MAGIC; +// return(com_dev); +//} +#else +static struct pios_com_dev pios_com_devs[PIOS_COM_MAX_DEVS]; +static uint8_t pios_com_num_devs; +static uint32_t PIOS_COM_create(void) { - struct pios_com_dev * com_dev; + struct pios_com_dev * com_dev; - com_dev = find_com_dev_by_id (port); + if (pios_com_num_devs >= PIOS_COM_MAX_DEVS) { + return (PIOS_COM_MAX_DEVS+1); + } - if (!com_dev) { - /* Undefined COM port for this board (see pios_board.c) */ - return -1; - } + com_dev = &pios_com_devs[pios_com_num_devs++]; + com_dev->magic = PIOS_COM_DEV_MAGIC; - /* Invoke the driver function if it exists */ - if (com_dev->driver->set_baud) { - com_dev->driver->set_baud(com_dev->id, baud); - } - - return 0; + return (pios_com_num_devs); } - -/** -* Sends a package over given port -* \param[in] port COM port -* \param[in] buffer character buffer -* \param[in] len buffer length -* \return -1 if port not available -* \return -2 if non-blocking mode activated: buffer is full -* caller should retry until buffer is free again -* \return 0 on success -*/ -int32_t PIOS_COM_SendBufferNonBlocking(uint8_t port, uint8_t *buffer, uint16_t len) +static struct pios_com_dev * PIOS_COM_find_dev(uint32_t com_dev_id) { - struct pios_com_dev * com_dev; + if (!com_dev_id) return NULL; + if (com_dev_id>pios_com_num_devs+1) return NULL; + return &pios_com_devs[com_dev_id-1]; +} +#endif - com_dev = find_com_dev_by_id (port); +static uint16_t PIOS_COM_TxOutCallback(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * need_yield); +static uint16_t PIOS_COM_RxInCallback(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * need_yield); +static void PIOS_COM_UnblockRx(struct pios_com_dev * com_dev, bool * need_yield); +static void PIOS_COM_UnblockTx(struct pios_com_dev * com_dev, bool * need_yield); - if (!com_dev) { - /* Undefined COM port for this board (see pios_board.c) */ - return -1; - } +/** + * Initialises COM layer + * \param[out] handle + * \param[in] driver + * \param[in] id + * \return < 0 if initialisation failed + */ +int32_t PIOS_COM_Init(uint32_t * com_id, const struct pios_com_driver * driver, uint32_t lower_id, uint8_t * rx_buffer, uint16_t rx_buffer_len, uint8_t * tx_buffer, uint16_t tx_buffer_len) +{ + PIOS_Assert(com_id); + PIOS_Assert(driver); - /* Invoke the driver function if it exists */ - if (com_dev->driver->tx_nb) { - return com_dev->driver->tx_nb(com_dev->id, buffer, len); - } + bool has_rx = (rx_buffer && rx_buffer_len > 0); + bool has_tx = (tx_buffer && tx_buffer_len > 0); + PIOS_Assert(has_rx || has_tx); + PIOS_Assert(driver->bind_tx_cb || !has_tx); + PIOS_Assert(driver->bind_rx_cb || !has_rx); - return 0; + uint32_t com_dev_id; + struct pios_com_dev * com_dev; + + com_dev_id = PIOS_COM_create(); + com_dev = PIOS_COM_find_dev(com_dev_id); + if (!com_dev) goto out_fail; + + com_dev->driver = driver; + com_dev->lower_id = lower_id; + + com_dev->has_rx = has_rx; + com_dev->has_tx = has_tx; + + if (has_rx) { + fifoBuf_init(&com_dev->rx, rx_buffer, rx_buffer_len); +#if defined(PIOS_INCLUDE_FREERTOS) + vSemaphoreCreateBinary(com_dev->rx_sem); +#endif /* PIOS_INCLUDE_FREERTOS */ + (com_dev->driver->bind_rx_cb)(lower_id, PIOS_COM_RxInCallback, com_dev_id); + if (com_dev->driver->rx_start) { + /* Start the receiver */ + (com_dev->driver->rx_start)(com_dev->lower_id, + fifoBuf_getFree(&com_dev->rx)); + } + } + + if (has_tx) { + fifoBuf_init(&com_dev->tx, tx_buffer, tx_buffer_len); +#if defined(PIOS_INCLUDE_FREERTOS) + vSemaphoreCreateBinary(com_dev->tx_sem); +#endif /* PIOS_INCLUDE_FREERTOS */ + (com_dev->driver->bind_tx_cb)(lower_id, PIOS_COM_TxOutCallback, com_dev_id); + } + + *com_id = com_dev_id; + return(0); + +out_fail: + return(-1); } -/** -* Sends a package over given port -* (blocking function) -* \param[in] port COM port -* \param[in] buffer character buffer -* \param[in] len buffer length -* \return -1 if port not available -* \return 0 on success -*/ -int32_t PIOS_COM_SendBuffer(uint8_t port, uint8_t *buffer, uint16_t len) +static void PIOS_COM_UnblockRx(struct pios_com_dev * com_dev, bool * need_yield) { - struct pios_com_dev * com_dev; +#if defined(PIOS_INCLUDE_FREERTOS) + static signed portBASE_TYPE xHigherPriorityTaskWoken; + xSemaphoreGiveFromISR(com_dev->rx_sem, &xHigherPriorityTaskWoken); - com_dev = find_com_dev_by_id (port); - - if (!com_dev) { - /* Undefined COM port for this board (see pios_board.c) */ - return -1; - } - - /* Invoke the driver function if it exists */ - if (com_dev->driver->tx) { - return com_dev->driver->tx(com_dev->id, buffer, len); - } - - return 0; + if (xHigherPriorityTaskWoken != pdFALSE) { + *need_yield = true; + } else { + *need_yield = false; + } +#else + *need_yield = false; +#endif } -/** -* Sends a single character over given port -* \param[in] port COM port -* \param[in] c character -* \return -1 if port not available -* \return -2 buffer is full -* caller should retry until buffer is free again -* \return 0 on success -*/ -int32_t PIOS_COM_SendCharNonBlocking(uint8_t port, char c) -{ - return PIOS_COM_SendBufferNonBlocking(port, (uint8_t *)&c, 1); -} - -/** -* Sends a single character over given port -* (blocking function) -* \param[in] port COM port -* \param[in] c character -* \return -1 if port not available -* \return 0 on success -*/ -int32_t PIOS_COM_SendChar(uint8_t port, char c) -{ - return PIOS_COM_SendBuffer(port, (uint8_t *)&c, 1); -} - -/** -* Sends a string over given port -* \param[in] port COM port -* \param[in] str zero-terminated string -* \return -1 if port not available -* \return -2 buffer is full -* caller should retry until buffer is free again -* \return 0 on success -*/ -int32_t PIOS_COM_SendStringNonBlocking(uint8_t port, char *str) -{ - return PIOS_COM_SendBufferNonBlocking(port, (uint8_t *)str, (uint16_t)strlen(str)); -} - -/** -* Sends a string over given port -* (blocking function) -* \param[in] port COM port -* \param[in] str zero-terminated string -* \return -1 if port not available -* \return 0 on success -*/ -int32_t PIOS_COM_SendString(uint8_t port, char *str) -{ - return PIOS_COM_SendBuffer(port, (uint8_t *)str, strlen(str)); -} - -/** -* Sends a formatted string (-> printf) over given port -* \param[in] port COM port -* \param[in] *format zero-terminated format string - 128 characters supported maximum! -* \param[in] ... optional arguments, -* 128 characters supported maximum! -* \return -2 if non-blocking mode activated: buffer is full -* caller should retry until buffer is free again -* \return 0 on success -*/ -int32_t PIOS_COM_SendFormattedStringNonBlocking(uint8_t port, char *format, ...) -{ - uint8_t buffer[128]; // TODO: tmp!!! Provide a streamed COM method later! - - va_list args; - - va_start(args, format); - vsprintf((char *)buffer, format, args); - return PIOS_COM_SendBufferNonBlocking(port, buffer, (uint16_t)strlen((char *)buffer)); -} - -/** -* Sends a formatted string (-> printf) over given port -* (blocking function) -* \param[in] port COM port -* \param[in] *format zero-terminated format string - 128 characters supported maximum! -* \param[in] ... optional arguments, -* \return -1 if port not available -* \return 0 on success -*/ -int32_t PIOS_COM_SendFormattedString(uint8_t port, char *format, ...) -{ - uint8_t buffer[128]; // TODO: tmp!!! Provide a streamed COM method later! - va_list args; - - va_start(args, format); - vsprintf((char *)buffer, format, args); - return PIOS_COM_SendBuffer(port, buffer, (uint16_t)strlen((char *)buffer)); -} - -/** -* Transfer bytes from port buffers into another buffer -* \param[in] port COM port +static void PIOS_COM_UnblockTx(struct pios_com_dev * com_dev, bool * need_yield) +{ +#if defined(PIOS_INCLUDE_FREERTOS) + static signed portBASE_TYPE xHigherPriorityTaskWoken; + xSemaphoreGiveFromISR(com_dev->tx_sem, &xHigherPriorityTaskWoken); + + if (xHigherPriorityTaskWoken != pdFALSE) { + *need_yield = true; + } else { + *need_yield = false; + } +#else + *need_yield = false; +#endif +} + +static uint16_t PIOS_COM_RxInCallback(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * need_yield) +{ + struct pios_com_dev * com_dev = PIOS_COM_find_dev(context); + + bool valid = PIOS_COM_validate(com_dev); + PIOS_Assert(valid); + PIOS_Assert(com_dev->has_rx); + + PIOS_IRQ_Disable(); + uint16_t bytes_into_fifo = fifoBuf_putData(&com_dev->rx, buf, buf_len); + PIOS_IRQ_Enable(); + + if (bytes_into_fifo > 0) { + /* Data has been added to the buffer */ + PIOS_COM_UnblockRx(com_dev, need_yield); + } + + if (headroom) { + *headroom = fifoBuf_getFree(&com_dev->rx); + } + + return (bytes_into_fifo); +} + +static uint16_t PIOS_COM_TxOutCallback(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * need_yield) +{ + struct pios_com_dev * com_dev = PIOS_COM_find_dev(context); + + bool valid = PIOS_COM_validate(com_dev); + PIOS_Assert(valid); + PIOS_Assert(buf); + PIOS_Assert(buf_len); + PIOS_Assert(com_dev->has_tx); + + PIOS_IRQ_Disable(); + uint16_t bytes_from_fifo = fifoBuf_getData(&com_dev->tx, buf, buf_len); + PIOS_IRQ_Enable(); + + if (bytes_from_fifo > 0) { + /* More space has been made in the buffer */ + PIOS_COM_UnblockTx(com_dev, need_yield); + } + + if (headroom) { + *headroom = fifoBuf_getUsed(&com_dev->tx); + } + + return (bytes_from_fifo); +} + +/** +* Change the port speed without re-initializing +* \param[in] port COM port +* \param[in] baud Requested baud rate +* \return -1 if port not available +* \return 0 on success +*/ +int32_t PIOS_COM_ChangeBaud(uint32_t com_id, uint32_t baud) +{ + struct pios_com_dev * com_dev = PIOS_COM_find_dev(com_id); + + if (!PIOS_COM_validate(com_dev)) { + /* Undefined COM port for this board (see pios_board.c) */ + return -1; + } + + /* Invoke the driver function if it exists */ + if (com_dev->driver->set_baud) { + com_dev->driver->set_baud(com_dev->lower_id, baud); + } + + return 0; +} + +/** +* Sends a package over given port +* \param[in] port COM port +* \param[in] buffer character buffer +* \param[in] len buffer length +* \return -1 if port not available +* \return -2 if non-blocking mode activated: buffer is full +* caller should retry until buffer is free again +* \return 0 on success +*/ +int32_t PIOS_COM_SendBufferNonBlocking(uint32_t com_id, const uint8_t *buffer, uint16_t len) +{ + struct pios_com_dev * com_dev = PIOS_COM_find_dev(com_id); + + if (!PIOS_COM_validate(com_dev)) { + /* Undefined COM port for this board (see pios_board.c) */ + return -1; + } + + PIOS_Assert(com_dev->has_tx); + + if (len >= fifoBuf_getFree(&com_dev->tx)) { + /* Buffer cannot accept all requested bytes (retry) */ + return -2; + } + + PIOS_IRQ_Disable(); + uint16_t bytes_into_fifo = fifoBuf_putData(&com_dev->tx, buffer, len); + PIOS_IRQ_Enable(); + + if (bytes_into_fifo > 0) { + /* More data has been put in the tx buffer, make sure the tx is started */ + if (com_dev->driver->tx_start) { + com_dev->driver->tx_start(com_dev->lower_id, + fifoBuf_getUsed(&com_dev->tx)); + } + } + + return (0); +} + +/** +* Sends a package over given port +* (blocking function) +* \param[in] port COM port +* \param[in] buffer character buffer +* \param[in] len buffer length +* \return -1 if port not available +* \return 0 on success +*/ +int32_t PIOS_COM_SendBuffer(uint32_t com_id, const uint8_t *buffer, uint16_t len) +{ + struct pios_com_dev * com_dev = PIOS_COM_find_dev(com_id); + + if (!PIOS_COM_validate(com_dev)) { + /* Undefined COM port for this board (see pios_board.c) */ + return -1; + } + + PIOS_Assert(com_dev->has_tx); + + int32_t rc; + do { + rc = PIOS_COM_SendBufferNonBlocking(com_id, buffer, len); + +#if defined(PIOS_INCLUDE_FREERTOS) + if (rc == -2) { + /* Make sure the transmitter is running while we wait */ + if (com_dev->driver->tx_start) { + (com_dev->driver->tx_start)(com_dev->lower_id, + fifoBuf_getUsed(&com_dev->tx)); + } + if (xSemaphoreTake(com_dev->tx_sem, portMAX_DELAY) != pdTRUE) { + return -3; + } + } +#endif + } while (rc == -2); + + return rc; +} + +/** +* Sends a single character over given port +* \param[in] port COM port +* \param[in] c character +* \return -1 if port not available +* \return -2 buffer is full +* caller should retry until buffer is free again +* \return 0 on success +*/ +int32_t PIOS_COM_SendCharNonBlocking(uint32_t com_id, char c) +{ + return PIOS_COM_SendBufferNonBlocking(com_id, (uint8_t *)&c, 1); +} + +/** +* Sends a single character over given port +* (blocking function) +* \param[in] port COM port +* \param[in] c character +* \return -1 if port not available +* \return 0 on success +*/ +int32_t PIOS_COM_SendChar(uint32_t com_id, char c) +{ + return PIOS_COM_SendBuffer(com_id, (uint8_t *)&c, 1); +} + +/** +* Sends a string over given port +* \param[in] port COM port +* \param[in] str zero-terminated string +* \return -1 if port not available +* \return -2 buffer is full +* caller should retry until buffer is free again +* \return 0 on success +*/ +int32_t PIOS_COM_SendStringNonBlocking(uint32_t com_id, const char *str) +{ + return PIOS_COM_SendBufferNonBlocking(com_id, (uint8_t *)str, (uint16_t)strlen(str)); +} + +/** +* Sends a string over given port +* (blocking function) +* \param[in] port COM port +* \param[in] str zero-terminated string +* \return -1 if port not available +* \return 0 on success +*/ +int32_t PIOS_COM_SendString(uint32_t com_id, const char *str) +{ + return PIOS_COM_SendBuffer(com_id, (uint8_t *)str, strlen(str)); +} + +/** +* Sends a formatted string (-> printf) over given port +* \param[in] port COM port +* \param[in] *format zero-terminated format string - 128 characters supported maximum! +* \param[in] ... optional arguments, +* 128 characters supported maximum! +* \return -2 if non-blocking mode activated: buffer is full +* caller should retry until buffer is free again +* \return 0 on success +*/ +int32_t PIOS_COM_SendFormattedStringNonBlocking(uint32_t com_id, const char *format, ...) +{ + uint8_t buffer[128]; // TODO: tmp!!! Provide a streamed COM method later! + + va_list args; + + va_start(args, format); + vsprintf((char *)buffer, format, args); + return PIOS_COM_SendBufferNonBlocking(com_id, buffer, (uint16_t)strlen((char *)buffer)); +} + +/** +* Sends a formatted string (-> printf) over given port +* (blocking function) +* \param[in] port COM port +* \param[in] *format zero-terminated format string - 128 characters supported maximum! +* \param[in] ... optional arguments, +* \return -1 if port not available +* \return 0 on success +*/ +int32_t PIOS_COM_SendFormattedString(uint32_t com_id, const char *format, ...) +{ + uint8_t buffer[128]; // TODO: tmp!!! Provide a streamed COM method later! + va_list args; + + va_start(args, format); + vsprintf((char *)buffer, format, args); + return PIOS_COM_SendBuffer(com_id, buffer, (uint16_t)strlen((char *)buffer)); +} + +/** +* Transfer bytes from port buffers into another buffer +* \param[in] port COM port * \returns Byte from buffer -*/ -uint8_t PIOS_COM_ReceiveBuffer(uint8_t port) -{ - struct pios_com_dev * com_dev; - - com_dev = find_com_dev_by_id (port); - //PIOS_DEBUG_Assert(com_dev); - //PIOS_DEBUG_Assert(com_dev->driver->rx); - - return com_dev->driver->rx(com_dev->id); -} - -/** -* Get the number of bytes waiting in the buffer -* \param[in] port COM port -* \return Number of bytes used in buffer -*/ -int32_t PIOS_COM_ReceiveBufferUsed(uint8_t port) +*/ +uint16_t PIOS_COM_ReceiveBuffer(uint32_t com_id, uint8_t * buf, uint16_t buf_len, uint32_t timeout_ms) { - struct pios_com_dev * com_dev; + PIOS_Assert(buf); + PIOS_Assert(buf_len); - com_dev = find_com_dev_by_id (port); + struct pios_com_dev * com_dev = PIOS_COM_find_dev(com_id); - if (!com_dev) { - /* Undefined COM port for this board (see pios_board.c) */ - return 0; - } + if (!PIOS_COM_validate(com_dev)) { + /* Undefined COM port for this board (see pios_board.c) */ + PIOS_Assert(0); + } + PIOS_Assert(com_dev->has_rx); - if (!com_dev->driver->rx_avail) { - return 0; - } + check_again: + PIOS_IRQ_Disable(); + uint16_t bytes_from_fifo = fifoBuf_getData(&com_dev->rx, buf, buf_len); + PIOS_IRQ_Enable(); - return com_dev->driver->rx_avail(com_dev->id); + if (bytes_from_fifo == 0 && timeout_ms > 0) { + /* No more bytes in receive buffer */ + /* Make sure the receiver is running while we wait */ + if (com_dev->driver->rx_start) { + /* Notify the lower layer that there is now room in the rx buffer */ + (com_dev->driver->rx_start)(com_dev->lower_id, + fifoBuf_getFree(&com_dev->rx)); + } +#if defined(PIOS_INCLUDE_FREERTOS) + if (xSemaphoreTake(com_dev->rx_sem, timeout_ms / portTICK_RATE_MS) == pdTRUE) { + /* Make sure we don't come back here again */ + timeout_ms = 0; + goto check_again; + } +#else + PIOS_DELAY_WaitmS(1); + timeout_ms--; + goto check_again; +#endif + } + + /* Return received byte */ + return (bytes_from_fifo); } - -#endif + +/** +* Get the number of bytes waiting in the buffer +* \param[in] port COM port +* \return Number of bytes used in buffer +*/ +int32_t PIOS_COM_ReceiveBufferUsed(uint32_t com_id) +{ + struct pios_com_dev * com_dev = PIOS_COM_find_dev(com_id); + + if (!PIOS_COM_validate(com_dev)) { + /* Undefined COM port for this board (see pios_board.c) */ + PIOS_Assert(0); + } + + PIOS_Assert(com_dev->has_rx); + return (fifoBuf_getUsed(&com_dev->rx)); +} + +#endif + +/** + * @} + * @} + */ diff --git a/flight/PiOS.posix/posix/pios_crc.c b/flight/PiOS.posix/posix/pios_crc.c new file mode 100644 index 000000000..548ba2648 --- /dev/null +++ b/flight/PiOS.posix/posix/pios_crc.c @@ -0,0 +1,74 @@ +/* + * pios_crc.c + * OpenPilotOSX + * + * Created by James Cotton on 6/4/11. + * Copyright 2011 OpenPilot. All rights reserved. + * + */ + +#include "pios.h" + +// CRC lookup table +static const uint8_t crc_table[256] = { + 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 +}; + +/** + * Update the crc value with new data. + * + * Generated by pycrc v0.7.5, http://www.tty1.net/pycrc/ + * using the configuration: + * Width = 8 + * Poly = 0x07 + * XorIn = 0x00 + * ReflectIn = False + * XorOut = 0x00 + * ReflectOut = False + * Algorithm = table-driven + * + * \param crc The current crc value. + * \param data Pointer to a buffer of \a data_len bytes. + * \param length Number of bytes in the \a data buffer. + * \return The updated crc value. + */ +uint8_t PIOS_CRC_updateByte(uint8_t crc, const uint8_t data) +{ + return crc_table[crc ^ data]; +} + +/* + * @brief Update a CRC with a data buffer + * @param[in] crc Starting CRC value + * @param[in] data Data buffer + * @param[in] length Number of bytes to process + * @returns Updated CRC + */ +uint8_t PIOS_CRC_updateCRC(uint8_t crc, const uint8_t* data, int32_t length) +{ + // use registers for speed + register int32_t len = length; + register uint8_t crc8 = crc; + register const uint8_t *p = data; + + while (len--) + crc8 = crc_table[crc8 ^ *p++]; + + return crc8; +} + diff --git a/flight/PiOS.posix/posix/pios_debug.c b/flight/PiOS.posix/posix/pios_debug.c index f79f2e730..5956a9d04 100644 --- a/flight/PiOS.posix/posix/pios_debug.c +++ b/flight/PiOS.posix/posix/pios_debug.c @@ -79,8 +79,15 @@ void PIOS_DEBUG_Panic(const char *msg) PIOS_COM_SendFormattedStringNonBlocking(PIOS_COM_DEBUG, "\r%s @0x%x\r", msg, lr); #endif - // Stay put - while (1) ; + // tell the user whats going on on commandline too + fprintf(stderr,"CRITICAL ERROR: %s\n",msg); + + // this helps debugging: causing a div by zero allows a backtrace + // and/or ends execution + int b = 0; + int a = (2/b); + b=a; + } /** diff --git a/flight/PiOS.posix/posix/pios_delay.c b/flight/PiOS.posix/posix/pios_delay.c index c295b4ac9..cec10467c 100644 --- a/flight/PiOS.posix/posix/pios_delay.c +++ b/flight/PiOS.posix/posix/pios_delay.c @@ -67,10 +67,6 @@ int32_t PIOS_DELAY_WaituS(uint16_t uS) while (!nanosleep(&wait,&rest)) { wait=rest; } - //uint16_t start = PIOS_DELAY_TIMER->CNT; - - /* Note that this event works on 16bit counter wrap-arounds */ - //while((uint16_t)(PIOS_DELAY_TIMER->CNT - start) <= uS); /* No error */ return 0; diff --git a/flight/PiOS.posix/posix/pios_irq.c b/flight/PiOS.posix/posix/pios_irq.c new file mode 100644 index 000000000..b30d09fee --- /dev/null +++ b/flight/PiOS.posix/posix/pios_irq.c @@ -0,0 +1,69 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_IRQ IRQ Setup Functions + * @brief STM32 Hardware code to enable and disable interrupts + * @{ + * + * @file pios_irq.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Parts by Thorsten Klose (tk@midibox.org) (tk@midibox.org) + * @brief IRQ Enable/Disable routines + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Project Includes */ +#include "pios.h" + +#if defined(PIOS_INCLUDE_IRQ) + +/* Private Function Prototypes */ + +/** +* Disables all interrupts (nested) +* \return < 0 On errors +*/ +int32_t PIOS_IRQ_Disable(void) +{ +#if defined(PIOS_INCLUDE_FREERTOS) + taskENTER_CRITICAL(); +#endif + return 0; +} + +/** +* Enables all interrupts (nested) +* \return < 0 on errors +* \return -1 on nesting errors (PIOS_IRQ_Disable() hasn't been called before) +*/ +int32_t PIOS_IRQ_Enable(void) +{ +#if defined(PIOS_INCLUDE_FREERTOS) + taskEXIT_CRITICAL(); +#endif + return 0; +} + +#endif + +/** + * @} + * @} + */ diff --git a/flight/PiOS.posix/posix/pios_rcvr.c b/flight/PiOS.posix/posix/pios_rcvr.c new file mode 100644 index 000000000..652730547 --- /dev/null +++ b/flight/PiOS.posix/posix/pios_rcvr.c @@ -0,0 +1,100 @@ +/* Project Includes */ +#include "pios.h" + +#if defined(PIOS_INCLUDE_RCVR) + +#include + +enum pios_rcvr_dev_magic { + PIOS_RCVR_DEV_MAGIC = 0x99aabbcc, +}; + +struct pios_rcvr_dev { + enum pios_rcvr_dev_magic magic; + uint32_t lower_id; + const struct pios_rcvr_driver * driver; +}; + +static bool PIOS_RCVR_validate(struct pios_rcvr_dev * rcvr_dev) +{ + return (rcvr_dev->magic == PIOS_RCVR_DEV_MAGIC); +} + +#if defined(PIOS_INCLUDE_FREERTOS) && 0 +static struct pios_rcvr_dev * PIOS_RCVR_alloc(void) +{ + struct pios_rcvr_dev * rcvr_dev; + + rcvr_dev = (struct pios_rcvr_dev *)malloc(sizeof(*rcvr_dev)); + if (!rcvr_dev) return (NULL); + + rcvr_dev->magic = PIOS_RCVR_DEV_MAGIC; + return(rcvr_dev); +} +#else +static struct pios_rcvr_dev pios_rcvr_devs[PIOS_RCVR_MAX_DEVS]; +static uint8_t pios_rcvr_num_devs; +static struct pios_rcvr_dev * PIOS_RCVR_alloc(void) +{ + struct pios_rcvr_dev * rcvr_dev; + + if (pios_rcvr_num_devs >= PIOS_RCVR_MAX_DEVS) { + return (NULL); + } + + rcvr_dev = &pios_rcvr_devs[pios_rcvr_num_devs++]; + rcvr_dev->magic = PIOS_RCVR_DEV_MAGIC; + + return (rcvr_dev); +} +#endif + +/** + * Initialises RCVR layer + * \param[out] handle + * \param[in] driver + * \param[in] id + * \return < 0 if initialisation failed + */ +int32_t PIOS_RCVR_Init(uint32_t * rcvr_id, const struct pios_rcvr_driver * driver, const uint32_t lower_id) +{ + PIOS_DEBUG_Assert(rcvr_id); + PIOS_DEBUG_Assert(driver); + + struct pios_rcvr_dev * rcvr_dev; + + rcvr_dev = (struct pios_rcvr_dev *) PIOS_RCVR_alloc(); + if (!rcvr_dev) goto out_fail; + + rcvr_dev->driver = driver; + rcvr_dev->lower_id = lower_id; + + + *rcvr_id = pios_rcvr_num_devs - 1; + + return(0); + +out_fail: + return(-1); +} + +int32_t PIOS_RCVR_Read(uint32_t rcvr_id, uint8_t channel) +{ + struct pios_rcvr_dev * rcvr_dev = &pios_rcvr_devs[rcvr_id]; + + if (!PIOS_RCVR_validate(rcvr_dev)) { + /* Undefined RCVR port for this board (see pios_board.c) */ + PIOS_DEBUG_Assert(0); + } + + PIOS_DEBUG_Assert(rcvr_dev->driver->read); + + return rcvr_dev->driver->read(rcvr_dev->lower_id, channel); +} + +#endif + +/** + * @} + * @} + */ diff --git a/flight/PiOS.posix/posix/pios_udp.c b/flight/PiOS.posix/posix/pios_udp.c index a7ab90841..f7f91f620 100644 --- a/flight/PiOS.posix/posix/pios_udp.c +++ b/flight/PiOS.posix/posix/pios_udp.c @@ -32,429 +32,213 @@ #if defined(PIOS_INCLUDE_UDP) +#include #include +/* We need a list of UDP devices */ + +#define PIOS_UDP_MAX_DEV 256 +static int8_t pios_udp_num_devices = 0; + +static pios_udp_dev pios_udp_devices[PIOS_UDP_MAX_DEV]; + + + /* Provide a COM driver */ +static void PIOS_UDP_ChangeBaud(uint32_t udp_id, uint32_t baud); +static void PIOS_UDP_RegisterRxCallback(uint32_t udp_id, pios_com_callback rx_in_cb, uint32_t context); +static void PIOS_UDP_RegisterTxCallback(uint32_t udp_id, pios_com_callback tx_out_cb, uint32_t context); +static void PIOS_UDP_TxStart(uint32_t udp_id, uint16_t tx_bytes_avail); +static void PIOS_UDP_RxStart(uint32_t udp_id, uint16_t rx_bytes_avail); + const struct pios_com_driver pios_udp_com_driver = { - .set_baud = PIOS_UDP_ChangeBaud, - .tx_nb = PIOS_UDP_TxBufferPutMoreNonBlocking, - .tx = PIOS_UDP_TxBufferPutMore, - .rx = PIOS_UDP_RxBufferGet, - .rx_avail = PIOS_UDP_RxBufferUsed, + .set_baud = PIOS_UDP_ChangeBaud, + .tx_start = PIOS_UDP_TxStart, + .rx_start = PIOS_UDP_RxStart, + .bind_tx_cb = PIOS_UDP_RegisterTxCallback, + .bind_rx_cb = PIOS_UDP_RegisterRxCallback, }; -static struct pios_udp_dev * find_udp_dev_by_id (uint8_t udp) + +static pios_udp_dev * find_udp_dev_by_id (uint8_t udp) { if (udp >= pios_udp_num_devices) { /* Undefined UDP port for this board (see pios_board.c) */ + PIOS_Assert(0); return NULL; } /* Get a handle for the device configuration */ - return &(pios_udp_devs[udp]); + return &(pios_udp_devices[udp]); } /** -* Open some UDP sockets -*/ -void PIOS_UDP_Init(void) -{ - struct pios_udp_dev * udp_dev; - uint8_t i; - - for (i = 0; i < pios_udp_num_devices; i++) { - /* Get a handle for the device configuration */ - udp_dev = find_udp_dev_by_id(i); - //PIOS_DEBUG_Assert(udp_dev); - - /* Clear buffer counters */ - udp_dev->rx.head = udp_dev->rx.tail = udp_dev->rx.size = 0; - - /* assign socket */ - udp_dev->socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - memset(&udp_dev->server,0,sizeof(udp_dev->server)); - memset(&udp_dev->client,0,sizeof(udp_dev->client)); - udp_dev->server.sin_family = AF_INET; - udp_dev->server.sin_addr.s_addr = inet_addr(udp_dev->cfg->ip); - udp_dev->server.sin_port = htons(udp_dev->cfg->port); - int res= bind(udp_dev->socket, (struct sockaddr *)&udp_dev->server,sizeof(udp_dev->server)); - /* use nonblocking IO */ - int flags = fcntl(udp_dev->socket, F_GETFL, 0); - fcntl(udp_dev->socket, F_SETFL, flags | O_NONBLOCK); - printf("udp dev %i - socket %i opened - result %i\n",i,udp_dev->socket,res); - - /* TODO do some error handling - wait no, we can't - we are void anyway ;) */ - } -} - - -/** -* Changes the baud rate of the UDP peripheral without re-initialising. -* \param[in] udp UDP name (GPS, TELEM, AUX) -* \param[in] baud Requested baud rate -*/ -void PIOS_UDP_ChangeBaud(uint8_t udp, uint32_t baud) -{ -} - - -/** -* puts a byte onto the receive buffer -* \param[in] UDP UDP name -* \param[in] b byte which should be put into Rx buffer -* \return 0 if no error -* \return -1 if UDP not available -* \return -2 if buffer full (retry) -* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions -*/ -int32_t PIOS_UDP_RxBufferPut(uint8_t udp, uint8_t b) -{ - struct pios_udp_dev * udp_dev; - - /* Get a handle for the device configuration */ - udp_dev = find_udp_dev_by_id(udp); - - if (!udp_dev) { - /* Undefined UDP port for this board (see pios_board.c) */ - return -1; - } - - if (udp_dev->rx.size >= sizeof(udp_dev->rx.buf)) { - /* Buffer full (retry) */ - return -2; - } - - /* Copy received byte into receive buffer */ - udp_dev->rx.buf[udp_dev->rx.head++] = b; - if (udp_dev->rx.head >= sizeof(udp_dev->rx.buf)) { - udp_dev->rx.head = 0; - } - udp_dev->rx.size++; - - /* No error */ - return 0; -} - -/** - * attempt to receive + * RxThread */ -void PIOS_UDP_RECV(uint8_t udp) { - - struct pios_udp_dev * udp_dev; - unsigned char localbuffer[PIOS_UDP_RX_BUFFER_SIZE]; - - /* Get a handle for the device configuration */ - udp_dev = find_udp_dev_by_id(udp); - - if (!udp_dev) { - /* Undefined UDP port for this board (see pios_board.c) */ - return; - } - - /* use nonblocking IO */ - int flags = fcntl(udp_dev->socket, F_GETFL, 0); - fcntl(udp_dev->socket, F_SETFL, flags | O_NONBLOCK); - - /* receive data */ - int received; - udp_dev->clientLength=sizeof(udp_dev->client); - if ((received = recvfrom(udp_dev->socket, - localbuffer, - (PIOS_UDP_RX_BUFFER_SIZE - udp_dev->rx.size), - 0, - (struct sockaddr *) &udp_dev->client, - (socklen_t*)&udp_dev->clientLength)) < 0) { - - return; - } - /* copy received data to buffer */ - int t; - for (t=0;trx.buf) - udp_dev->rx.size); -} + /** + * receive + */ + int received; + udp_dev->clientLength=sizeof(udp_dev->client); + if ((received = recvfrom(udp_dev->socket, + &udp_dev->rx_buffer, + PIOS_UDP_RX_BUFFER_SIZE, + 0, + (struct sockaddr *) &udp_dev->client, + (socklen_t*)&udp_dev->clientLength)) >= 0) + { -/** -* Returns number of used bytes in receive buffer -* \param[in] UDP UDP name -* \return > 0: number of used bytes -* \return 0 if UDP not available -* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions -*/ -int32_t PIOS_UDP_RxBufferUsed(uint8_t udp) -{ - struct pios_udp_dev * udp_dev; + /* copy received data to buffer if possible */ + /* we do NOT buffer data locally. If the com buffer can't receive, data is discarded! */ + /* (thats what the USART driver does too!) */ + bool rx_need_yield = false; + if (udp_dev->rx_in_cb) { + (void) (udp_dev->rx_in_cb)(udp_dev->rx_in_context, udp_dev->rx_buffer, received, NULL, &rx_need_yield); + } - /* Get a handle for the device configuration */ - udp_dev = find_udp_dev_by_id(udp); +#if defined(PIOS_INCLUDE_FREERTOS) + if (rx_need_yield) { + vPortYieldFromISR(); + } +#endif /* PIOS_INCLUDE_FREERTOS */ - if (!udp_dev) { - /* Undefined UDP port for this board (see pios_board.c) */ - return -2; - } + } - /* fill buffer */ - PIOS_UDP_RECV(udp); - return (udp_dev->rx.size); -} - -/** -* Gets a byte from the receive buffer -* \param[in] UDP UDP name -* \return -1 if UDP not available -* \return -2 if no new byte available -* \return >= 0: number of received bytes -* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions -*/ -int32_t PIOS_UDP_RxBufferGet(uint8_t udp) -{ - struct pios_udp_dev * udp_dev; - - /* Get a handle for the device configuration */ - udp_dev = find_udp_dev_by_id(udp); - - if (!udp_dev) { - /* Undefined UDP port for this board (see pios_board.c) */ - return -2; - } - - /* fill buffer */ - PIOS_UDP_RECV(udp); - - if (!udp_dev->rx.size) { - /* Nothing new in the buffer */ - return -1; - } - - /* get byte */ - uint8_t b = udp_dev->rx.buf[udp_dev->rx.tail++]; - if (udp_dev->rx.tail >= sizeof(udp_dev->rx.buf)) { - udp_dev->rx.tail = 0; - } - udp_dev->rx.size--; - - /* Return received byte */ - return b; -} - -/** -* Returns the next byte of the receive buffer without taking it -* \param[in] UDP UDP name -* \return -1 if UDP not available -* \return -2 if no new byte available -* \return >= 0: number of received bytes -* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions -*/ -int32_t PIOS_UDP_RxBufferPeek(uint8_t udp) -{ - struct pios_udp_dev * udp_dev; - - /* Get a handle for the device configuration */ - udp_dev = find_udp_dev_by_id(udp); - - if (!udp_dev) { - /* Undefined UDP port for this board (see pios_board.c) */ - return -2; - } - - /* fill buffer */ - PIOS_UDP_RECV(udp); - - if (!udp_dev->rx.size) { - /* Nothing new in the buffer */ - return -1; - } - - /* get byte */ - uint8_t b = udp_dev->rx.buf[udp_dev->rx.tail]; - - /* Return received byte */ - return b; -} - -/** -* returns number of free bytes in transmit buffer -* \param[in] UDP UDP name -* \return number of free bytes -* \return 0 if UDP not available -* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions -*/ -int32_t PIOS_UDP_TxBufferFree(uint8_t udp) -{ - struct pios_udp_dev * udp_dev; - - /* Get a handle for the device configuration */ - udp_dev = find_udp_dev_by_id(udp); - - if (!udp_dev) { - /* Undefined UDP port for this board (see pios_board.c) */ - return 0; - } - - return PIOS_UDP_RX_BUFFER_SIZE; -} - -/** -* returns number of used bytes in transmit buffer -* \param[in] UDP UDP name -* \return number of used bytes -* \return 0 if UDP not available -* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions -*/ -int32_t PIOS_UDP_TxBufferUsed(uint8_t udp) -{ - struct pios_udp_dev * udp_dev; - - /* Get a handle for the device configuration */ - udp_dev = find_udp_dev_by_id(udp); - - if (!udp_dev) { - /* Undefined UDP port for this board (see pios_board.c) */ - return 0; - } - - return 0; + } } /** -* puts more than one byte onto the transmit buffer (used for atomic sends) -* \param[in] UDP UDP name -* \param[in] *buffer pointer to buffer to be sent -* \param[in] len number of bytes to be sent -* \return 0 if no error -* \return -1 if UDP not available -* \return -2 if buffer full or cannot get all requested bytes (retry) -* \return -3 if UDP not supported by UDPTxBufferPut Routine -* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions +* Open UDP socket */ -int32_t PIOS_UDP_TxBufferPutMoreNonBlocking(uint8_t udp, uint8_t *buffer, uint16_t len) +int32_t PIOS_UDP_Init(uint32_t * udp_id, const struct pios_udp_cfg * cfg) { - struct pios_udp_dev * udp_dev; - /* Get a handle for the device configuration */ - udp_dev = find_udp_dev_by_id(udp); + pios_udp_dev * udp_dev = &pios_udp_devices[pios_udp_num_devices]; - if (!udp_dev) { - /* Undefined UDP port for this board (see pios_board.c) */ - return -1; - } - - if (len >= PIOS_UDP_RX_BUFFER_SIZE) { - /* Buffer cannot accept all requested bytes (retry) */ - return -2; - } - /* send data to client - non blocking*/ - - /* use nonblocking IO */ - int flags = fcntl(udp_dev->socket, F_GETFL, 0); - fcntl(udp_dev->socket, F_SETFL, flags | O_NONBLOCK); - sendto(udp_dev->socket, buffer, len, 0, - (struct sockaddr *) &udp_dev->client, - (socklen_t)sizeof(udp_dev->client)); + pios_udp_num_devices++; - /* No error */ - return 0; + /* initialize */ + udp_dev->rx_in_cb = NULL; + udp_dev->tx_out_cb = NULL; + udp_dev->cfg=cfg; + + /* assign socket */ + udp_dev->socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + memset(&udp_dev->server,0,sizeof(udp_dev->server)); + memset(&udp_dev->client,0,sizeof(udp_dev->client)); + udp_dev->server.sin_family = AF_INET; + udp_dev->server.sin_addr.s_addr = inet_addr(udp_dev->cfg->ip); + udp_dev->server.sin_port = htons(udp_dev->cfg->port); + int res= bind(udp_dev->socket, (struct sockaddr *)&udp_dev->server,sizeof(udp_dev->server)); + + /* Create transmit thread for this connection */ + pthread_create(&udp_dev->rxThread, NULL, PIOS_UDP_RxThread, (void*)udp_dev); + + printf("udp dev %i - socket %i opened - result %i\n",pios_udp_num_devices-1,udp_dev->socket,res); + + *udp_id = pios_udp_num_devices-1; + + return res; } -/** -* puts more than one byte onto the transmit buffer (used for atomic sends)
-* (blocking function) -* \param[in] UDP UDP name -* \param[in] *buffer pointer to buffer to be sent -* \param[in] len number of bytes to be sent -* \return 0 if no error -* \return -1 if UDP not available -* \return -3 if UDP not supported by UDPTxBufferPut Routine -* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions -*/ -int32_t PIOS_UDP_TxBufferPutMore(uint8_t udp, uint8_t *buffer, uint16_t len) + +void PIOS_UDP_ChangeBaud(uint32_t udp_id, uint32_t baud) { - struct pios_udp_dev * udp_dev; - - /* Get a handle for the device configuration */ - udp_dev = find_udp_dev_by_id(udp); - - if (!udp_dev) { - /* Undefined UDP port for this board (see pios_board.c) */ - return -1; - } - - if (len >= PIOS_UDP_RX_BUFFER_SIZE) { - /* Buffer cannot accept all requested bytes (retry) */ - return -2; - } - - /* send data to client - blocking*/ - /* use blocking IO */ - int flags = fcntl(udp_dev->socket, F_GETFL, 0); - fcntl(udp_dev->socket, F_SETFL, flags & ~O_NONBLOCK); - sendto(udp_dev->socket, buffer, len, 0, - (struct sockaddr *) &udp_dev->client, - sizeof(udp_dev->client)); - - /* No error */ - return 0; + /** + * doesn't apply! + */ } -/** -* puts a byte onto the transmit buffer -* \param[in] UDP UDP name -* \param[in] b byte which should be put into Tx buffer -* \return 0 if no error -* \return -1 if UDP not available -* \return -2 if buffer full (retry) -* \return -3 if UDP not supported by UDPTxBufferPut Routine -* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions -*/ -int32_t PIOS_UDP_TxBufferPut_NonBlocking(uint8_t udp, uint8_t b) + +static void PIOS_UDP_RxStart(uint32_t udp_id, uint16_t rx_bytes_avail) { - return PIOS_UDP_TxBufferPutMoreNonBlocking(udp, &b, 1); + /** + * lazy! + */ } -/** -* puts a byte onto the transmit buffer
-* (blocking function) -* \param[in] UDP UDP name -* \param[in] b byte which should be put into Tx buffer -* \return 0 if no error -* \return -1 if UDP not available -* \return -3 if UDP not supported by UDPTxBufferPut Routine -* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions -*/ -int32_t PIOS_UDP_TxBufferPut(uint8_t udp, uint8_t b) + +static void PIOS_UDP_TxStart(uint32_t udp_id, uint16_t tx_bytes_avail) { - return PIOS_UDP_TxBufferPutMore(udp, &b, 1); + pios_udp_dev * udp_dev = find_udp_dev_by_id(udp_id); + + PIOS_Assert(udp_dev); + + int32_t length,len,rem; + + /** + * we send everything directly whenever notified of data to send (lazy!) + */ + if (udp_dev->tx_out_cb) { + while (tx_bytes_avail>0) { + bool tx_need_yield = false; + length = (udp_dev->tx_out_cb)(udp_dev->tx_out_context, udp_dev->tx_buffer, PIOS_UDP_RX_BUFFER_SIZE, NULL, &tx_need_yield); + rem = length; + while (rem>0) { + len = sendto(udp_dev->socket, udp_dev->tx_buffer, length, 0, + (struct sockaddr *) &udp_dev->client, + sizeof(udp_dev->client)); + if (len<=0) { + rem=0; + } else { + rem -= len; + } + } + tx_bytes_avail -= length; + } + } + } +static void PIOS_UDP_RegisterRxCallback(uint32_t udp_id, pios_com_callback rx_in_cb, uint32_t context) +{ + pios_udp_dev * udp_dev = find_udp_dev_by_id(udp_id); + + PIOS_Assert(udp_dev); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + udp_dev->rx_in_context = context; + udp_dev->rx_in_cb = rx_in_cb; +} + +static void PIOS_UDP_RegisterTxCallback(uint32_t udp_id, pios_com_callback tx_out_cb, uint32_t context) +{ + pios_udp_dev * udp_dev = find_udp_dev_by_id(udp_id); + + PIOS_Assert(udp_dev); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + udp_dev->tx_out_context = context; + udp_dev->tx_out_cb = tx_out_cb; +} + + + + #endif diff --git a/flight/PiOS.win32/inc/pios_crc.h b/flight/PiOS.win32/inc/pios_crc.h new file mode 100644 index 000000000..3a64f8bab --- /dev/null +++ b/flight/PiOS.win32/inc/pios_crc.h @@ -0,0 +1,31 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_CRC CRC Functions + * @{ + * + * @file pios_crc.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief CRC functions header. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +uint8_t PIOS_CRC_updateByte(uint8_t crc, const uint8_t data); +uint8_t PIOS_CRC_updateCRC(uint8_t crc, const uint8_t* data, int32_t length); diff --git a/flight/PiOS.win32/inc/pios_initcall.h b/flight/PiOS.win32/inc/pios_initcall.h index 73d5e72f7..edd9ddc08 100644 --- a/flight/PiOS.win32/inc/pios_initcall.h +++ b/flight/PiOS.win32/inc/pios_initcall.h @@ -38,7 +38,17 @@ * and we cannot define a linker script for each of them atm */ -#define uavobj_initcall(fn) +#define MODULE_INITCALL(ifn, iparam, sfn, sparam, flags) + +#define MODULE_TASKCREATE_ALL + +#define MODULE_INITIALISE_ALL { \ + /* Initialize modules */ \ + InitModules(); \ + /* Start the FreeRTOS scheduler which never returns.*/ \ + /* Initialize the system thread */ \ + SystemModInitialize();} + #endif /* PIOS_INITCALL_H */ diff --git a/flight/PiOS.win32/pios.h b/flight/PiOS.win32/pios.h index 0c908cafc..a4600cee5 100644 --- a/flight/PiOS.win32/pios.h +++ b/flight/PiOS.win32/pios.h @@ -63,6 +63,7 @@ #include #include #include +#include #define NELEMENTS(x) (sizeof(x) / sizeof(*(x))) diff --git a/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/port.c b/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/port.c index 787826afa..94f09de91 100644 --- a/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/port.c +++ b/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/port.c @@ -941,3 +941,8 @@ void vPortExitCritical( void ) } } } + +unsigned long ulPortGetTimerValue( void ) +{ + return (unsigned long) clock(); +} \ No newline at end of file diff --git a/flight/PiOS.win32/win32/pios_crc.c b/flight/PiOS.win32/win32/pios_crc.c new file mode 100644 index 000000000..548ba2648 --- /dev/null +++ b/flight/PiOS.win32/win32/pios_crc.c @@ -0,0 +1,74 @@ +/* + * pios_crc.c + * OpenPilotOSX + * + * Created by James Cotton on 6/4/11. + * Copyright 2011 OpenPilot. All rights reserved. + * + */ + +#include "pios.h" + +// CRC lookup table +static const uint8_t crc_table[256] = { + 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 +}; + +/** + * Update the crc value with new data. + * + * Generated by pycrc v0.7.5, http://www.tty1.net/pycrc/ + * using the configuration: + * Width = 8 + * Poly = 0x07 + * XorIn = 0x00 + * ReflectIn = False + * XorOut = 0x00 + * ReflectOut = False + * Algorithm = table-driven + * + * \param crc The current crc value. + * \param data Pointer to a buffer of \a data_len bytes. + * \param length Number of bytes in the \a data buffer. + * \return The updated crc value. + */ +uint8_t PIOS_CRC_updateByte(uint8_t crc, const uint8_t data) +{ + return crc_table[crc ^ data]; +} + +/* + * @brief Update a CRC with a data buffer + * @param[in] crc Starting CRC value + * @param[in] data Data buffer + * @param[in] length Number of bytes to process + * @returns Updated CRC + */ +uint8_t PIOS_CRC_updateCRC(uint8_t crc, const uint8_t* data, int32_t length) +{ + // use registers for speed + register int32_t len = length; + register uint8_t crc8 = crc; + register const uint8_t *p = data; + + while (len--) + crc8 = crc_table[crc8 ^ *p++]; + + return crc8; +} + diff --git a/flight/PiOS.win32/win32/pios_delay.c b/flight/PiOS.win32/win32/pios_delay.c index 0fed0d8d4..a8d892601 100644 --- a/flight/PiOS.win32/win32/pios_delay.c +++ b/flight/PiOS.win32/win32/pios_delay.c @@ -62,11 +62,7 @@ int32_t PIOS_DELAY_Init(void) int32_t PIOS_DELAY_WaituS(uint16_t uS) { Sleep(uS/1000); - //uint16_t start = PIOS_DELAY_TIMER->CNT; - /* Note that this event works on 16bit counter wrap-arounds */ - //while((uint16_t)(PIOS_DELAY_TIMER->CNT - start) <= uS); - /* No error */ return 0; } diff --git a/flight/PiOS/Boards/STM32103CB_AHRS.h b/flight/PiOS/Boards/STM32103CB_AHRS.h index 8262f9730..26d88fce1 100644 --- a/flight/PiOS/Boards/STM32103CB_AHRS.h +++ b/flight/PiOS/Boards/STM32103CB_AHRS.h @@ -64,25 +64,8 @@ TIM8 | | | | //------------------------ // BOOTLOADER_SETTINGS //------------------------ -//#define FUNC_ID 2 -//#define HW_VERSION 69 - -#define BOOTLOADER_VERSION 0 -#define BOARD_TYPE 0x02 -#define BOARD_REVISION 0x01 -//#define HW_VERSION (BOARD_TYPE << 8) | BOARD_REVISION - -#define MEM_SIZE 0x20000 //128K -#define SIZE_OF_DESCRIPTION 100 -#define START_OF_USER_CODE (uint32_t)0x08002000 -#define SIZE_OF_CODE (uint32_t)(MEM_SIZE-(START_OF_USER_CODE-0x08000000)-SIZE_OF_DESCRIPTION) -#ifdef STM32F10X_HD - #define HW_TYPE 0 //0=high_density 1=medium_density; -#elif STM32F10X_MD - #define HW_TYPE 1 //0=high_density 1=medium_density; -#endif #define BOARD_READABLE TRUE -#define BOARD_WRITABLA TRUE +#define BOARD_WRITABLE TRUE #define MAX_DEL_RETRYS 3 //------------------------ @@ -96,22 +79,11 @@ TIM8 | | | | #define PIOS_LED_PINS { PIOS_LED_LED1_GPIO_PIN } #define PIOS_LED_CLKS { PIOS_LED_LED1_GPIO_CLK } -//------------------------- -// Delay Timer -//------------------------- -#define PIOS_DELAY_TIMER TIM2 -#define PIOS_DELAY_TIMER_RCC_FUNC RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE) - //------------------------- // System Settings //------------------------- #define PIOS_MASTER_CLOCK 72000000 #define PIOS_PERIPHERAL_CLOCK (PIOS_MASTER_CLOCK / 2) -#if defined(USE_BOOTLOADER) -#define PIOS_NVIC_VECTTAB_FLASH (START_OF_USER_CODE) -#else -#define PIOS_NVIC_VECTTAB_FLASH ((uint32_t)0x08000000) -#endif //------------------------- // Interrupt Priorities @@ -140,9 +112,6 @@ extern uint32_t pios_i2c_main_adapter_id; // PIOS_USART //------------------------- #define PIOS_USART_MAX_DEVS 2 -#define PIOS_USART_RX_BUFFER_SIZE 256 -#define PIOS_USART_TX_BUFFER_SIZE 256 -#define PIOS_USART_BAUDRATE 230400 //------------------------- // PIOS_COM @@ -150,6 +119,7 @@ extern uint32_t pios_i2c_main_adapter_id; // See also pios_board.c //------------------------- #define PIOS_COM_MAX_DEVS 2 + extern uint32_t pios_com_aux_id; #define PIOS_COM_AUX (pios_com_aux_id) #define PIOS_COM_DEBUG PIOS_COM_AUX diff --git a/flight/PiOS/Boards/STM32103CB_CC_Rev1.h b/flight/PiOS/Boards/STM32103CB_CC_Rev1.h index a39b8b457..18e0da624 100644 --- a/flight/PiOS/Boards/STM32103CB_CC_Rev1.h +++ b/flight/PiOS/Boards/STM32103CB_CC_Rev1.h @@ -34,7 +34,7 @@ Timer | Channel 1 | Channel 2 | Channel 3 | Channel 4 ------+-----------+-----------+-----------+---------- TIM1 | Servo 4 | | | -TIM2 | RC In 5 | RC In 6 | Servo 6 | +TIM2 | RC In 5 | RC In 6 | Servo 6 | TIM3 | Servo 5 | RC In 2 | RC In 3 | RC In 4 TIM4 | RC In 1 | Servo 3 | Servo 2 | Servo 1 ------+-----------+-----------+-----------+---------- @@ -60,25 +60,8 @@ TIM4 | RC In 1 | Servo 3 | Servo 2 | Servo 1 //------------------------ // BOOTLOADER_SETTINGS //------------------------ -//#define FUNC_ID 2 -//#define HW_VERSION 69 - -#define BOOTLOADER_VERSION 0 -#define BOARD_TYPE 0x04 -#define BOARD_REVISION 0x01 -//#define HW_VERSION (BOARD_TYPE << 8) | BOARD_REVISION - -#define MEM_SIZE 0x20000 //128K -#define SIZE_OF_DESCRIPTION 100 -#define START_OF_USER_CODE (uint32_t)0x08003000 -#define SIZE_OF_CODE (uint32_t)(MEM_SIZE-(START_OF_USER_CODE-0x08000000)-SIZE_OF_DESCRIPTION) -#ifdef STM32F10X_HD - #define HW_TYPE 0 //0=high_density 1=medium_density; -#elif STM32F10X_MD - #define HW_TYPE 1 //0=high_density 1=medium_density; -#endif #define BOARD_READABLE TRUE -#define BOARD_WRITABLA TRUE +#define BOARD_WRITABLE TRUE #define MAX_DEL_RETRYS 3 @@ -93,7 +76,7 @@ TIM4 | RC In 1 | Servo 3 | Servo 2 | Servo 1 #define PIOS_WDG_MANUAL 0x0008 //------------------------ -// TELEMETRY +// TELEMETRY //------------------------ #define TELEM_QUEUE_SIZE 20 @@ -108,22 +91,11 @@ TIM4 | RC In 1 | Servo 3 | Servo 2 | Servo 1 #define PIOS_LED_PINS { PIOS_LED_LED1_GPIO_PIN } #define PIOS_LED_CLKS { PIOS_LED_LED1_GPIO_CLK } -//------------------------- -// Delay Timer -//------------------------- -#define PIOS_DELAY_TIMER TIM3 -#define PIOS_DELAY_TIMER_RCC_FUNC RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE) - //------------------------- // System Settings //------------------------- #define PIOS_MASTER_CLOCK 72000000 #define PIOS_PERIPHERAL_CLOCK (PIOS_MASTER_CLOCK / 2) -#if defined(USE_BOOTLOADER) -#define PIOS_NVIC_VECTTAB_FLASH (START_OF_USER_CODE) -#else -#define PIOS_NVIC_VECTTAB_FLASH ((uint32_t)0x08000000) -#endif //------------------------- // Interrupt Priorities @@ -153,23 +125,18 @@ extern uint32_t pios_i2c_main_adapter_id; //------------------------- #define PIOS_USART_MAX_DEVS 2 -#define PIOS_USART_RX_BUFFER_SIZE 256 -#define PIOS_USART_TX_BUFFER_SIZE 256 - //------------------------- // PIOS_COM // // See also pios_board.c //------------------------- -#define PIOS_COM_MAX_DEVS 4 +#define PIOS_COM_MAX_DEVS 3 -#define PIOS_COM_TELEM_BAUDRATE 57600 extern uint32_t pios_com_telem_rf_id; #define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) #define PIOS_COM_DEBUG PIOS_COM_TELEM_RF #if defined(PIOS_INCLUDE_GPS) -#define PIOS_COM_GPS_BAUDRATE 57600 extern uint32_t pios_com_gps_id; #define PIOS_COM_GPS (pios_com_gps_id) #endif /* PIOS_INCLUDE_GPS */ @@ -177,12 +144,6 @@ extern uint32_t pios_com_gps_id; extern uint32_t pios_com_telem_usb_id; #define PIOS_COM_TELEM_USB (pios_com_telem_usb_id) -#ifdef PIOS_INCLUDE_SPEKTRUM -#define PIOS_COM_SPEKTRUM_BAUDRATE 115200 -extern uint32_t pios_com_spektrum_id; -#define PIOS_COM_SPEKTRUM (pios_com_spektrum_id) -#endif - //------------------------- // ADC // PIOS_ADC_PinGet(0) = Gyro Z @@ -219,7 +180,7 @@ extern uint32_t pios_com_spektrum_id; #define PIOS_ADC_CHANNELS { PIOS_ADC_PIN1_GPIO_CHANNEL, PIOS_ADC_PIN2_GPIO_CHANNEL, PIOS_ADC_PIN3_GPIO_CHANNEL } #define PIOS_ADC_MAPPING { PIOS_ADC_PIN1_ADC, PIOS_ADC_PIN2_ADC, PIOS_ADC_PIN3_ADC } #define PIOS_ADC_CHANNEL_MAPPING { PIOS_ADC_PIN1_ADC_NUMBER, PIOS_ADC_PIN2_ADC_NUMBER, PIOS_ADC_PIN3_ADC_NUMBER } -#define PIOS_ADC_NUM_CHANNELS (PIOS_ADC_NUM_PINS + PIOS_ADC_USE_TEMP_SENSOR) +#define PIOS_ADC_NUM_CHANNELS (PIOS_ADC_NUM_PINS + PIOS_ADC_USE_TEMP_SENSOR) #define PIOS_ADC_NUM_ADC_CHANNELS 2 #define PIOS_ADC_USE_ADC2 1 #define PIOS_ADC_CLOCK_FUNCTION RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE) @@ -241,10 +202,27 @@ extern uint32_t pios_com_spektrum_id; #define PIOS_ADC_RATE (72.0e6 / 1.0 / 8.0 / 252.0 / (PIOS_ADC_NUM_CHANNELS >> PIOS_ADC_USE_ADC2)) #define PIOS_ADC_MAX_OVERSAMPLING 36 +//------------------------ +// PIOS_RCVR +// See also pios_board.c +//------------------------ +#define PIOS_RCVR_MAX_DEVS 1 +#define PIOS_RCVR_MAX_CHANNELS 12 + //------------------------- -// Receiver PWM inputs +// Receiver PPM input //------------------------- -#define PIOS_PWM_MAX_INPUTS 6 +#define PIOS_PPM_NUM_INPUTS 12 + +//------------------------- +// Receiver PWM input +//------------------------- +#define PIOS_PWM_NUM_INPUTS 6 + +//------------------------- +// Receiver SPEKTRUM input +//------------------------- +#define PIOS_SPEKTRUM_NUM_INPUTS 12 //------------------------- // Servo outputs @@ -274,10 +252,9 @@ extern uint32_t pios_com_spektrum_id; // USB //------------------------- #define PIOS_USB_ENABLED 1 +#define PIOS_USB_HID_MAX_DEVS 1 #define PIOS_USB_DETECT_GPIO_PORT GPIOC #define PIOS_USB_DETECT_GPIO_PIN GPIO_Pin_15 #define PIOS_USB_DETECT_EXTI_LINE EXTI_Line15 #define PIOS_IRQ_USB_PRIORITY PIOS_IRQ_PRIO_MID -#define PIOS_USB_RX_BUFFER_SIZE 128 -#define PIOS_USB_TX_BUFFER_SIZE 128 #endif /* STM32103CB_AHRS_H_ */ diff --git a/flight/PiOS/Boards/STM32103CB_PIPXTREME_Rev1.h b/flight/PiOS/Boards/STM32103CB_PIPXTREME_Rev1.h index 3234b8014..7027a42bd 100644 --- a/flight/PiOS/Boards/STM32103CB_PIPXTREME_Rev1.h +++ b/flight/PiOS/Boards/STM32103CB_PIPXTREME_Rev1.h @@ -58,20 +58,8 @@ TIM4 | STOPWATCH | //------------------------ // BOOTLOADER_SETTINGS //------------------------ -#define BOOTLOADER_VERSION 0 -#define BOARD_TYPE 0x03 -#define BOARD_REVISION 0x01 -#define MEM_SIZE ((uint32_t)(*((volatile uint16_t *)(0x1FFFF7E0))) * 1024 - 1024) //128K -#define SIZE_OF_DESCRIPTION 100 -#define START_OF_USER_CODE (uint32_t)0x08003000 -#define SIZE_OF_CODE (uint32_t)(MEM_SIZE-(START_OF_USER_CODE-0x08000000)-SIZE_OF_DESCRIPTION) -#ifdef STM32F10X_HD - #define HW_TYPE 0 //0=high_density 1=medium_density; -#elif STM32F10X_MD - #define HW_TYPE 1 //0=high_density 1=medium_density; -#endif #define BOARD_READABLE TRUE -#define BOARD_WRITABLA TRUE +#define BOARD_WRITABLE TRUE #define MAX_DEL_RETRYS 3 @@ -81,12 +69,6 @@ TIM4 | STOPWATCH | #define PIOS_MASTER_CLOCK 72000000ul #define PIOS_PERIPHERAL_CLOCK (PIOS_MASTER_CLOCK / 2) -#if defined(USE_BOOTLOADER) - #define PIOS_NVIC_VECTTAB_FLASH (START_OF_USER_CODE) -#else - #define PIOS_NVIC_VECTTAB_FLASH ((uint32_t)0x08000000) -#endif - // ***************************************************************** // Interrupt Priorities @@ -135,14 +117,6 @@ TIM4 | STOPWATCH | #define TX_LED_OFF PIOS_LED_Off(LED4) #define TX_LED_TOGGLE PIOS_LED_Toggle(LED4) -// ***************************************************************** -// Delay Timer - -//#define PIOS_DELAY_TIMER TIM2 -//#define PIOS_DELAY_TIMER_RCC_FUNC RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE) -#define PIOS_DELAY_TIMER TIM1 -#define PIOS_DELAY_TIMER_RCC_FUNC RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE) - // ***************************************************************** // Timer interrupt @@ -170,9 +144,6 @@ extern uint32_t pios_spi_port_id; //------------------------- #define PIOS_USART_MAX_DEVS 1 -#define PIOS_USART_RX_BUFFER_SIZE 512 -#define PIOS_USART_TX_BUFFER_SIZE 512 - //------------------------- // PIOS_COM // @@ -422,12 +393,11 @@ extern uint32_t pios_com_telem_usb_id; #if defined(PIOS_INCLUDE_USB_HID) #define PIOS_USB_ENABLED 1 + #define PIOS_USB_HID_MAX_DEVS 1 #define PIOS_USB_DETECT_GPIO_PORT GPIO_IN_2_PORT #define PIOS_USB_DETECT_GPIO_PIN GPIO_IN_2_PIN #define PIOS_USB_DETECT_EXTI_LINE EXTI_Line4 #define PIOS_IRQ_USB_PRIORITY 8 - #define PIOS_USB_RX_BUFFER_SIZE 512 - #define PIOS_USB_TX_BUFFER_SIZE 512 #endif // ***************************************************************** diff --git a/flight/PiOS/Boards/STM3210E_INS.h b/flight/PiOS/Boards/STM3210E_INS.h index 22c94837b..d661e8b96 100644 --- a/flight/PiOS/Boards/STM3210E_INS.h +++ b/flight/PiOS/Boards/STM3210E_INS.h @@ -69,27 +69,8 @@ TIM8 | | | | //------------------------ // BOOTLOADER_SETTINGS //------------------------ - -//#define FUNC_ID 1 -//#define HW_VERSION 01 - -#define BOOTLOADER_VERSION 0 -#define BOARD_TYPE 0x05 // INS board -#define BOARD_REVISION 0x01 // Beta version -//#define HW_VERSION (BOARD_TYPE << 8) | BOARD_REVISION - -#define MEM_SIZE 524288 //512K -#define SIZE_OF_DESCRIPTION (uint8_t) 100 -#define START_OF_USER_CODE (uint32_t)0x08005000//REMEMBER SET ALSO IN link_stm32f10x_HD_BL.ld -#define SIZE_OF_CODE (uint32_t) (MEM_SIZE-(START_OF_USER_CODE-0x08000000)-SIZE_OF_DESCRIPTION) - -#ifdef STM32F10X_HD - #define HW_TYPE 0 //0=high_density 1=medium_density; -#elif STM32F10X_MD - #define HW_TYPE 1 //0=high_density 1=medium_density; -#endif #define BOARD_READABLE TRUE -#define BOARD_WRITABLA TRUE +#define BOARD_WRITABLE TRUE #define MAX_DEL_RETRYS 3 //------------------------ @@ -144,9 +125,6 @@ extern uint32_t pios_i2c_gyro_adapter_id; //------------------------- #define PIOS_USART_MAX_DEVS 2 -#define PIOS_USART_RX_BUFFER_SIZE 256 -#define PIOS_USART_TX_BUFFER_SIZE 256 - //------------------------- // PIOS_COM // @@ -154,33 +132,20 @@ extern uint32_t pios_i2c_gyro_adapter_id; //------------------------- #define PIOS_COM_MAX_DEVS 2 -#define PIOS_COM_GPS_BAUDRATE 57600 extern uint32_t pios_com_gps_id; #define PIOS_COM_GPS (pios_com_gps_id) #ifdef PIOS_ENABLE_AUX_UART -#define PIOS_COM_AUX_BAUDRATE 57600 extern uint32_t pios_com_aux_id; #define PIOS_COM_AUX (pios_com_aux_id) #define PIOS_COM_DEBUG PIOS_COM_AUX #endif -//------------------------- -// Delay Timer -//------------------------- -#define PIOS_DELAY_TIMER TIM2 -#define PIOS_DELAY_TIMER_RCC_FUNC RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE) - //------------------------- // System Settings //------------------------- #define PIOS_MASTER_CLOCK 72000000 #define PIOS_PERIPHERAL_CLOCK (PIOS_MASTER_CLOCK / 2) -#if defined(USE_BOOTLOADER) -#define PIOS_NVIC_VECTTAB_FLASH (START_OF_USER_CODE) -#else -#define PIOS_NVIC_VECTTAB_FLASH ((uint32_t)0x08000000) -#endif //------------------------- // Interrupt Priorities diff --git a/flight/PiOS/Boards/STM3210E_OP.h b/flight/PiOS/Boards/STM3210E_OP.h index 48653179c..3098ee259 100644 --- a/flight/PiOS/Boards/STM3210E_OP.h +++ b/flight/PiOS/Boards/STM3210E_OP.h @@ -68,27 +68,8 @@ TIM8 | Servo 5 | Servo 6 | Servo 7 | Servo 8 //------------------------ // BOOTLOADER_SETTINGS //------------------------ - -//#define FUNC_ID 1 -//#define HW_VERSION 01 - -#define BOOTLOADER_VERSION 0 -#define BOARD_TYPE 0x01 // OpenPilot board -#define BOARD_REVISION 0x01 // Beta version -//#define HW_VERSION (BOARD_TYPE << 8) | BOARD_REVISION - -#define MEM_SIZE 524288 //512K -#define SIZE_OF_DESCRIPTION (uint8_t) 100 -#define START_OF_USER_CODE (uint32_t)0x08005000//REMEMBER SET ALSO IN link_stm32f10x_HD_BL.ld -#define SIZE_OF_CODE (uint32_t) (MEM_SIZE-(START_OF_USER_CODE-0x08000000)-SIZE_OF_DESCRIPTION) - -#ifdef STM32F10X_HD - #define HW_TYPE 0 //0=high_density 1=medium_density; -#elif STM32F10X_MD - #define HW_TYPE 1 //0=high_density 1=medium_density; -#endif #define BOARD_READABLE TRUE -#define BOARD_WRITABLA TRUE +#define BOARD_WRITABLE TRUE #define MAX_DEL_RETRYS 3 //------------------------ @@ -158,9 +139,6 @@ extern uint32_t pios_i2c_main_adapter_id; //------------------------- #define PIOS_USART_MAX_DEVS 3 -#define PIOS_USART_RX_BUFFER_SIZE 512 -#define PIOS_USART_TX_BUFFER_SIZE 512 - //------------------------- // PIOS_COM // @@ -168,11 +146,9 @@ extern uint32_t pios_i2c_main_adapter_id; //------------------------- #define PIOS_COM_MAX_DEVS 4 -#define PIOS_COM_TELEM_BAUDRATE 57600 extern uint32_t pios_com_telem_rf_id; #define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) -#define PIOS_COM_GPS_BAUDRATE 57600 extern uint32_t pios_com_gps_id; #define PIOS_COM_GPS (pios_com_gps_id) @@ -180,34 +156,16 @@ extern uint32_t pios_com_telem_usb_id; #define PIOS_COM_TELEM_USB (pios_com_telem_usb_id) #ifdef PIOS_ENABLE_AUX_UART -#define PIOS_COM_AUX_BAUDRATE 57600 extern uint32_t pios_com_aux_id; #define PIOS_COM_AUX (pios_com_aux_id) #define PIOS_COM_DEBUG PIOS_COM_AUX #endif -#ifdef PIOS_INCLUDE_SPEKTRUM -#define PIOS_COM_SPEKTRUM_BAUDRATE 115200 -extern uint32_t pios_com_spektrum_id; -#define PIOS_COM_SPEKTRUM (pios_com_spektrum_id) -#endif - -//------------------------- -// Delay Timer -//------------------------- -#define PIOS_DELAY_TIMER TIM2 -#define PIOS_DELAY_TIMER_RCC_FUNC RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE) - //------------------------- // System Settings //------------------------- #define PIOS_MASTER_CLOCK 72000000 #define PIOS_PERIPHERAL_CLOCK (PIOS_MASTER_CLOCK / 2) -#if defined(USE_BOOTLOADER) -#define PIOS_NVIC_VECTTAB_FLASH (START_OF_USER_CODE) -#else -#define PIOS_NVIC_VECTTAB_FLASH ((uint32_t)0x08000000) -#endif //------------------------- // Interrupt Priorities @@ -217,37 +175,33 @@ extern uint32_t pios_com_spektrum_id; #define PIOS_IRQ_PRIO_HIGH 5 // for SPI, ADC, I2C etc... #define PIOS_IRQ_PRIO_HIGHEST 4 // for USART etc... -//------------------------- -// Receiver PWM inputs -//------------------------- -/*#define PIOS_PWM_SUPV_ENABLED 1 -#define PIOS_PWM_SUPV_TIMER TIM6 -#define PIOS_PWM_SUPV_TIMER_RCC_FUNC RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE) -#define PIOS_PWM_SUPV_HZ 25 -#define PIOS_PWM_SUPV_IRQ_CHANNEL TIM6_IRQn -#define PIOS_PWM_SUPV_IRQ_FUNC void TIM6_IRQHandler(void)*/ +//------------------------ +// PIOS_RCVR +// See also pios_board.c +//------------------------ +#define PIOS_RCVR_MAX_DEVS 1 +#define PIOS_RCVR_MAX_CHANNELS 12 //------------------------- // Receiver PPM input //------------------------- -#define PIOS_PPM_NUM_INPUTS 8 //Could be more if needed -#define PIOS_PPM_SUPV_ENABLED 1 +#define PIOS_PPM_NUM_INPUTS 12 + //------------------------- -// SPEKTRUM input +// Receiver PWM input //------------------------- -//#define PIOS_SPEKTRUM_SUPV_ENABLED 1 -//#define PIOS_SPEKTRUM_SUPV_TIMER TIM6 -//#define PIOS_SPEKTRUM_SUPV_TIMER_RCC_FUNC RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE) -//#define PIOS_SPEKTRUM_SUPV_HZ 60 // 1/22ms -//#define PIOS_SPEKTRUM_SUPV_IRQ_CHANNEL TIM6_IRQn -//#define PIOS_SPEKTRUM_SUPV_IRQ_FUNC void TIM6_IRQHandler(void) +#define PIOS_PWM_NUM_INPUTS 8 + +//------------------------- +// Receiver SPEKTRUM input +//------------------------- +#define PIOS_SPEKTRUM_NUM_INPUTS 12 //------------------------- // Servo outputs //------------------------- #define PIOS_SERVO_UPDATE_HZ 50 #define PIOS_SERVOS_INITIAL_POSITION 0 /* dont want to start motors, have no pulse till settings loaded */ -#define PIOS_PWM_MAX_INPUTS 8 //------------------------- // ADC @@ -341,12 +295,11 @@ extern uint32_t pios_com_spektrum_id; // USB //------------------------- #define PIOS_USB_ENABLED 1 +#define PIOS_USB_HID_MAX_DEVS 1 #define PIOS_USB_DETECT_GPIO_PORT GPIOC #define PIOS_USB_DETECT_GPIO_PIN GPIO_Pin_4 #define PIOS_USB_DETECT_EXTI_LINE EXTI_Line4 #define PIOS_IRQ_USB_PRIORITY PIOS_IRQ_PRIO_MID -#define PIOS_USB_RX_BUFFER_SIZE 512 -#define PIOS_USB_TX_BUFFER_SIZE 512 /** * glue macros for file IO diff --git a/flight/PiOS/Common/pios_adxl345.c b/flight/PiOS/Common/pios_adxl345.c index e11cadf19..91fb3f91f 100644 --- a/flight/PiOS/Common/pios_adxl345.c +++ b/flight/PiOS/Common/pios_adxl345.c @@ -96,6 +96,22 @@ void PIOS_ADXL345_Init() PIOS_ADXL345_SetMeasure(1); } +/** + * @brief Return number of entries in the fifo + */ +uint8_t PIOS_ADXL345_FifoElements() +{ + uint8_t buf[2] = {0,0}; + uint8_t rec[2] = {0,0}; + buf[0] = ADXL_FIFOSTATUS_ADDR | ADXL_READ_BIT ; // Read fifo status + + PIOS_ADXL345_ClaimBus(); + PIOS_SPI_TransferBlock(PIOS_SPI_ACCEL,&buf[0],&rec[0],sizeof(buf),NULL); + PIOS_ADXL345_ReleaseBus(); + + return rec[1] & 0x3f; +} + /** * @brief Read a single set of values from the x y z channels * @returns The number of samples remaining in the fifo diff --git a/flight/PiOS/Common/pios_bl_helper.c b/flight/PiOS/Common/pios_bl_helper.c index 545a008c6..967c3c7e6 100644 --- a/flight/PiOS/Common/pios_bl_helper.c +++ b/flight/PiOS/Common/pios_bl_helper.c @@ -31,6 +31,7 @@ /* Project Includes */ #include "pios.h" #if defined(PIOS_INCLUDE_BL_HELPER) +#include #include "stm32f10x_flash.h" uint8_t *PIOS_BL_HELPER_FLASH_If_Read(uint32_t SectorAddress) @@ -47,10 +48,10 @@ uint8_t PIOS_BL_HELPER_FLASH_Ini() uint8_t PIOS_BL_HELPER_FLASH_Start() { - uint32_t pageAdress; - pageAdress = START_OF_USER_CODE; + const struct pios_board_info * bdinfo = &pios_board_info_blob; + uint32_t pageAdress = bdinfo->fw_base; uint8_t fail = FALSE; - while ((pageAdress < START_OF_USER_CODE + SIZE_OF_CODE + SIZE_OF_DESCRIPTION) + while ((pageAdress < (bdinfo->fw_base + bdinfo->fw_size + bdinfo->desc_size)) || (fail == TRUE)) { for (int retry = 0; retry < MAX_DEL_RETRYS; ++retry) { if (FLASH_ErasePage(pageAdress) == FLASH_COMPLETE) { @@ -75,17 +76,20 @@ uint8_t PIOS_BL_HELPER_FLASH_Start() uint32_t PIOS_BL_HELPER_CRC_Memory_Calc() { + const struct pios_board_info * bdinfo = &pios_board_info_blob; + PIOS_BL_HELPER_CRC_Ini(); CRC_ResetDR(); - CRC_CalcBlockCRC((uint32_t *) START_OF_USER_CODE, (SIZE_OF_CODE) >> 2); + CRC_CalcBlockCRC((uint32_t *) bdinfo->fw_base, (bdinfo->fw_size) >> 2); return CRC_GetCRC(); } void PIOS_BL_HELPER_FLASH_Read_Description(uint8_t * array, uint8_t size) { + const struct pios_board_info * bdinfo = &pios_board_info_blob; uint8_t x = 0; - if (size>SIZE_OF_DESCRIPTION) size = SIZE_OF_DESCRIPTION; - for (uint32_t i = START_OF_USER_CODE + SIZE_OF_CODE; i < START_OF_USER_CODE + SIZE_OF_CODE + size; ++i) { + if (size > bdinfo->desc_size) size = bdinfo->desc_size; + for (uint32_t i = bdinfo->fw_base + bdinfo->fw_size; i < bdinfo->fw_base + bdinfo->fw_size + size; ++i) { array[x] = *PIOS_BL_HELPER_FLASH_If_Read(i); ++x; } diff --git a/flight/PiOS/Common/pios_board_info.c b/flight/PiOS/Common/pios_board_info.c new file mode 100644 index 000000000..8905a5c08 --- /dev/null +++ b/flight/PiOS/Common/pios_board_info.c @@ -0,0 +1,20 @@ +#include +#include + +#include "pios_board_info.h" + +const struct pios_board_info __attribute__((__used__)) __attribute__((__section__(".boardinfo"))) pios_board_info_blob = { + .magic = PIOS_BOARD_INFO_BLOB_MAGIC, + .board_type = BOARD_TYPE, + .board_rev = BOARD_REVISION, + .bl_rev = BOOTLOADER_VERSION, + .hw_type = HW_TYPE, + .fw_base = FW_BANK_BASE, + .fw_size = FW_BANK_SIZE - FW_DESC_SIZE, + .desc_base = FW_BANK_BASE + FW_BANK_SIZE - FW_DESC_SIZE, + .desc_size = FW_DESC_SIZE, +#ifdef EE_BANK_BASE + .ee_base = EE_BANK_BASE, + .ee_size = EE_BANK_SIZE, +#endif +}; diff --git a/flight/PiOS/Common/pios_com.c b/flight/PiOS/Common/pios_com.c index 0d2c21d30..b7a9a67e5 100644 --- a/flight/PiOS/Common/pios_com.c +++ b/flight/PiOS/Common/pios_com.c @@ -34,11 +34,37 @@ #if defined(PIOS_INCLUDE_COM) +#include "fifo_buffer.h" #include +#if !defined(PIOS_INCLUDE_FREERTOS) +#include "pios_delay.h" /* PIOS_DELAY_WaitmS */ +#endif + +enum pios_com_dev_magic { + PIOS_COM_DEV_MAGIC = 0xaa55aa55, +}; + +struct pios_com_dev { + enum pios_com_dev_magic magic; + uint32_t lower_id; + const struct pios_com_driver * driver; + +#if defined(PIOS_INCLUDE_FREERTOS) + xSemaphoreHandle tx_sem; + xSemaphoreHandle rx_sem; +#endif + + bool has_rx; + bool has_tx; + + t_fifo_buffer rx; + t_fifo_buffer tx; +}; + static bool PIOS_COM_validate(struct pios_com_dev * com_dev) { - return (com_dev->magic == PIOS_COM_DEV_MAGIC); + return (com_dev && (com_dev->magic == PIOS_COM_DEV_MAGIC)); } #if defined(PIOS_INCLUDE_FREERTOS) && 0 @@ -70,6 +96,11 @@ static struct pios_com_dev * PIOS_COM_alloc(void) } #endif +static uint16_t PIOS_COM_TxOutCallback(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * need_yield); +static uint16_t PIOS_COM_RxInCallback(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * need_yield); +static void PIOS_COM_UnblockRx(struct pios_com_dev * com_dev, bool * need_yield); +static void PIOS_COM_UnblockTx(struct pios_com_dev * com_dev, bool * need_yield); + /** * Initialises COM layer * \param[out] handle @@ -77,18 +108,48 @@ static struct pios_com_dev * PIOS_COM_alloc(void) * \param[in] id * \return < 0 if initialisation failed */ -int32_t PIOS_COM_Init(uint32_t * com_id, const struct pios_com_driver * driver, const uint32_t lower_id) +int32_t PIOS_COM_Init(uint32_t * com_id, const struct pios_com_driver * driver, uint32_t lower_id, uint8_t * rx_buffer, uint16_t rx_buffer_len, uint8_t * tx_buffer, uint16_t tx_buffer_len) { - PIOS_DEBUG_Assert(com_id); - PIOS_DEBUG_Assert(driver); + PIOS_Assert(com_id); + PIOS_Assert(driver); + + bool has_rx = (rx_buffer && rx_buffer_len > 0); + bool has_tx = (tx_buffer && tx_buffer_len > 0); + PIOS_Assert(has_rx || has_tx); + PIOS_Assert(driver->bind_tx_cb || !has_tx); + PIOS_Assert(driver->bind_rx_cb || !has_rx); struct pios_com_dev * com_dev; com_dev = (struct pios_com_dev *) PIOS_COM_alloc(); if (!com_dev) goto out_fail; - com_dev->driver = driver; - com_dev->id = lower_id; + com_dev->driver = driver; + com_dev->lower_id = lower_id; + + com_dev->has_rx = has_rx; + com_dev->has_tx = has_tx; + + if (has_rx) { + fifoBuf_init(&com_dev->rx, rx_buffer, rx_buffer_len); +#if defined(PIOS_INCLUDE_FREERTOS) + vSemaphoreCreateBinary(com_dev->rx_sem); +#endif /* PIOS_INCLUDE_FREERTOS */ + (com_dev->driver->bind_rx_cb)(lower_id, PIOS_COM_RxInCallback, (uint32_t)com_dev); + if (com_dev->driver->rx_start) { + /* Start the receiver */ + (com_dev->driver->rx_start)(com_dev->lower_id, + fifoBuf_getFree(&com_dev->rx)); + } + } + + if (has_tx) { + fifoBuf_init(&com_dev->tx, tx_buffer, tx_buffer_len); +#if defined(PIOS_INCLUDE_FREERTOS) + vSemaphoreCreateBinary(com_dev->tx_sem); +#endif /* PIOS_INCLUDE_FREERTOS */ + (com_dev->driver->bind_tx_cb)(lower_id, PIOS_COM_TxOutCallback, (uint32_t)com_dev); + } *com_id = (uint32_t)com_dev; return(0); @@ -97,6 +158,88 @@ out_fail: return(-1); } +static void PIOS_COM_UnblockRx(struct pios_com_dev * com_dev, bool * need_yield) +{ +#if defined(PIOS_INCLUDE_FREERTOS) + static signed portBASE_TYPE xHigherPriorityTaskWoken; + xSemaphoreGiveFromISR(com_dev->rx_sem, &xHigherPriorityTaskWoken); + + if (xHigherPriorityTaskWoken != pdFALSE) { + *need_yield = true; + } else { + *need_yield = false; + } +#else + *need_yield = false; +#endif +} + +static void PIOS_COM_UnblockTx(struct pios_com_dev * com_dev, bool * need_yield) +{ +#if defined(PIOS_INCLUDE_FREERTOS) + static signed portBASE_TYPE xHigherPriorityTaskWoken; + xSemaphoreGiveFromISR(com_dev->tx_sem, &xHigherPriorityTaskWoken); + + if (xHigherPriorityTaskWoken != pdFALSE) { + *need_yield = true; + } else { + *need_yield = false; + } +#else + *need_yield = false; +#endif +} + +static uint16_t PIOS_COM_RxInCallback(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * need_yield) +{ + struct pios_com_dev * com_dev = (struct pios_com_dev *)context; + + bool valid = PIOS_COM_validate(com_dev); + PIOS_Assert(valid); + PIOS_Assert(com_dev->has_rx); + + PIOS_IRQ_Disable(); + uint16_t bytes_into_fifo = fifoBuf_putData(&com_dev->rx, buf, buf_len); + PIOS_IRQ_Enable(); + + if (bytes_into_fifo > 0) { + /* Data has been added to the buffer */ + PIOS_COM_UnblockRx(com_dev, need_yield); + } + + if (headroom) { + *headroom = fifoBuf_getFree(&com_dev->rx); + } + + return (bytes_into_fifo); +} + +static uint16_t PIOS_COM_TxOutCallback(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * need_yield) +{ + struct pios_com_dev * com_dev = (struct pios_com_dev *)context; + + bool valid = PIOS_COM_validate(com_dev); + PIOS_Assert(valid); + PIOS_Assert(buf); + PIOS_Assert(buf_len); + PIOS_Assert(com_dev->has_tx); + + PIOS_IRQ_Disable(); + uint16_t bytes_from_fifo = fifoBuf_getData(&com_dev->tx, buf, buf_len); + PIOS_IRQ_Enable(); + + if (bytes_from_fifo > 0) { + /* More space has been made in the buffer */ + PIOS_COM_UnblockTx(com_dev, need_yield); + } + + if (headroom) { + *headroom = fifoBuf_getUsed(&com_dev->tx); + } + + return (bytes_from_fifo); +} + /** * Change the port speed without re-initializing * \param[in] port COM port @@ -115,7 +258,7 @@ int32_t PIOS_COM_ChangeBaud(uint32_t com_id, uint32_t baud) /* Invoke the driver function if it exists */ if (com_dev->driver->set_baud) { - com_dev->driver->set_baud(com_dev->id, baud); + com_dev->driver->set_baud(com_dev->lower_id, baud); } return 0; @@ -140,12 +283,26 @@ int32_t PIOS_COM_SendBufferNonBlocking(uint32_t com_id, const uint8_t *buffer, u return -1; } - /* Invoke the driver function if it exists */ - if (com_dev->driver->tx_nb) { - return com_dev->driver->tx_nb(com_dev->id, buffer, len); + PIOS_Assert(com_dev->has_tx); + + if (len >= fifoBuf_getFree(&com_dev->tx)) { + /* Buffer cannot accept all requested bytes (retry) */ + return -2; } - return 0; + PIOS_IRQ_Disable(); + uint16_t bytes_into_fifo = fifoBuf_putData(&com_dev->tx, buffer, len); + PIOS_IRQ_Enable(); + + if (bytes_into_fifo > 0) { + /* More data has been put in the tx buffer, make sure the tx is started */ + if (com_dev->driver->tx_start) { + com_dev->driver->tx_start(com_dev->lower_id, + fifoBuf_getUsed(&com_dev->tx)); + } + } + + return (0); } /** @@ -166,12 +323,27 @@ int32_t PIOS_COM_SendBuffer(uint32_t com_id, const uint8_t *buffer, uint16_t len return -1; } - /* Invoke the driver function if it exists */ - if (com_dev->driver->tx) { - return com_dev->driver->tx(com_dev->id, buffer, len); - } + PIOS_Assert(com_dev->has_tx); - return 0; + int32_t rc; + do { + rc = PIOS_COM_SendBufferNonBlocking(com_id, buffer, len); + +#if defined(PIOS_INCLUDE_FREERTOS) + if (rc == -2) { + /* Make sure the transmitter is running while we wait */ + if (com_dev->driver->tx_start) { + (com_dev->driver->tx_start)(com_dev->lower_id, + fifoBuf_getUsed(&com_dev->tx)); + } + if (xSemaphoreTake(com_dev->tx_sem, portMAX_DELAY) != pdTRUE) { + return -3; + } + } +#endif + } while (rc == -2); + + return rc; } /** @@ -273,18 +445,47 @@ int32_t PIOS_COM_SendFormattedString(uint32_t com_id, const char *format, ...) * \param[in] port COM port * \returns Byte from buffer */ -uint8_t PIOS_COM_ReceiveBuffer(uint32_t com_id) +uint16_t PIOS_COM_ReceiveBuffer(uint32_t com_id, uint8_t * buf, uint16_t buf_len, uint32_t timeout_ms) { + PIOS_Assert(buf); + PIOS_Assert(buf_len); + struct pios_com_dev * com_dev = (struct pios_com_dev *)com_id; if (!PIOS_COM_validate(com_dev)) { /* Undefined COM port for this board (see pios_board.c) */ - PIOS_DEBUG_Assert(0); + PIOS_Assert(0); + } + PIOS_Assert(com_dev->has_rx); + + check_again: + PIOS_IRQ_Disable(); + uint16_t bytes_from_fifo = fifoBuf_getData(&com_dev->rx, buf, buf_len); + PIOS_IRQ_Enable(); + + if (bytes_from_fifo == 0 && timeout_ms > 0) { + /* No more bytes in receive buffer */ + /* Make sure the receiver is running while we wait */ + if (com_dev->driver->rx_start) { + /* Notify the lower layer that there is now room in the rx buffer */ + (com_dev->driver->rx_start)(com_dev->lower_id, + fifoBuf_getFree(&com_dev->rx)); + } +#if defined(PIOS_INCLUDE_FREERTOS) + if (xSemaphoreTake(com_dev->rx_sem, timeout_ms / portTICK_RATE_MS) == pdTRUE) { + /* Make sure we don't come back here again */ + timeout_ms = 0; + goto check_again; + } +#else + PIOS_DELAY_WaitmS(1); + timeout_ms--; + goto check_again; +#endif } - PIOS_DEBUG_Assert(com_dev->driver->rx); - - return com_dev->driver->rx(com_dev->id); + /* Return received byte */ + return (bytes_from_fifo); } /** @@ -298,14 +499,11 @@ int32_t PIOS_COM_ReceiveBufferUsed(uint32_t com_id) if (!PIOS_COM_validate(com_dev)) { /* Undefined COM port for this board (see pios_board.c) */ - PIOS_DEBUG_Assert(0); + PIOS_Assert(0); } - if (!com_dev->driver->rx_avail) { - return 0; - } - - return com_dev->driver->rx_avail(com_dev->id); + PIOS_Assert(com_dev->has_rx); + return (fifoBuf_getUsed(&com_dev->rx)); } #endif diff --git a/flight/PiOS/Common/pios_crc.c b/flight/PiOS/Common/pios_crc.c new file mode 100644 index 000000000..548ba2648 --- /dev/null +++ b/flight/PiOS/Common/pios_crc.c @@ -0,0 +1,74 @@ +/* + * pios_crc.c + * OpenPilotOSX + * + * Created by James Cotton on 6/4/11. + * Copyright 2011 OpenPilot. All rights reserved. + * + */ + +#include "pios.h" + +// CRC lookup table +static const uint8_t crc_table[256] = { + 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 +}; + +/** + * Update the crc value with new data. + * + * Generated by pycrc v0.7.5, http://www.tty1.net/pycrc/ + * using the configuration: + * Width = 8 + * Poly = 0x07 + * XorIn = 0x00 + * ReflectIn = False + * XorOut = 0x00 + * ReflectOut = False + * Algorithm = table-driven + * + * \param crc The current crc value. + * \param data Pointer to a buffer of \a data_len bytes. + * \param length Number of bytes in the \a data buffer. + * \return The updated crc value. + */ +uint8_t PIOS_CRC_updateByte(uint8_t crc, const uint8_t data) +{ + return crc_table[crc ^ data]; +} + +/* + * @brief Update a CRC with a data buffer + * @param[in] crc Starting CRC value + * @param[in] data Data buffer + * @param[in] length Number of bytes to process + * @returns Updated CRC + */ +uint8_t PIOS_CRC_updateCRC(uint8_t crc, const uint8_t* data, int32_t length) +{ + // use registers for speed + register int32_t len = length; + register uint8_t crc8 = crc; + register const uint8_t *p = data; + + while (len--) + crc8 = crc_table[crc8 ^ *p++]; + + return crc8; +} + diff --git a/flight/PiOS/Common/pios_flash_w25x.c b/flight/PiOS/Common/pios_flash_w25x.c index b1c602422..f474beb3f 100644 --- a/flight/PiOS/Common/pios_flash_w25x.c +++ b/flight/PiOS/Common/pios_flash_w25x.c @@ -41,11 +41,11 @@ static uint8_t PIOS_Flash_W25X_Busy() ; static uint32_t PIOS_SPI_FLASH; -/** +/** * @brief Claim the SPI bus for flash use and assert CS pin * @return 0 for sucess, -1 for failure to get semaphore */ -static int8_t PIOS_Flash_W25X_ClaimBus() +static int8_t PIOS_Flash_W25X_ClaimBus() { int8_t ret = PIOS_SPI_ClaimBus(PIOS_SPI_FLASH); PIOS_FLASH_ENABLE; @@ -55,7 +55,7 @@ static int8_t PIOS_Flash_W25X_ClaimBus() /** * @brief Release the SPI bus sempahore and ensure flash chip not using bus */ -static void PIOS_Flash_W25X_ReleaseBus() +static void PIOS_Flash_W25X_ReleaseBus() { PIOS_FLASH_DISABLE; PIOS_SPI_ReleaseBus(PIOS_SPI_FLASH); @@ -64,8 +64,8 @@ static void PIOS_Flash_W25X_ReleaseBus() /** * @brief Returns if the flash chip is busy */ -static uint8_t PIOS_Flash_W25X_Busy() -{ +static uint8_t PIOS_Flash_W25X_Busy() +{ return PIOS_Flash_W25X_ReadStatus() & W25X_STATUS_BUSY; } @@ -73,12 +73,12 @@ static uint8_t PIOS_Flash_W25X_Busy() * @brief Execute the write enable instruction and returns the status * @returns 0 if successful, -1 if unable to claim bus */ -static uint8_t PIOS_Flash_W25X_WriteEnable() +static uint8_t PIOS_Flash_W25X_WriteEnable() { uint8_t out[] = {W25X_WRITE_ENABLE}; if(PIOS_Flash_W25X_ClaimBus() != 0) return -1; - PIOS_SPI_TransferBlock(PIOS_SPI_FLASH,out,NULL,sizeof(out),NULL); + PIOS_SPI_TransferBlock(PIOS_SPI_FLASH,out,NULL,sizeof(out),NULL); PIOS_Flash_W25X_ReleaseBus(); return 0; } @@ -97,27 +97,27 @@ int8_t PIOS_Flash_W25X_Init(uint32_t spi_id) /** - * @brief Read the status register from flash chip and return it + * @brief Read the status register from flash chip and return it */ -uint8_t PIOS_Flash_W25X_ReadStatus() +uint8_t PIOS_Flash_W25X_ReadStatus() { uint8_t out[2] = {W25X_READ_STATUS, 0}; uint8_t in[2] = {0,0}; PIOS_Flash_W25X_ClaimBus(); - PIOS_SPI_TransferBlock(PIOS_SPI_FLASH,out,in,sizeof(out),NULL); + PIOS_SPI_TransferBlock(PIOS_SPI_FLASH,out,in,sizeof(out),NULL); PIOS_Flash_W25X_ReleaseBus(); return in[1]; } /** - * @brief Read the status register from flash chip and return it + * @brief Read the status register from flash chip and return it */ -uint8_t PIOS_Flash_W25X_ReadID() +uint8_t PIOS_Flash_W25X_ReadID() { uint8_t out[] = {W25X_DEVICE_ID, 0, 0, 0, 0, 0}; uint8_t in[6]; PIOS_Flash_W25X_ClaimBus(); - PIOS_SPI_TransferBlock(PIOS_SPI_FLASH,out,in,sizeof(out),NULL); + PIOS_SPI_TransferBlock(PIOS_SPI_FLASH,out,in,sizeof(out),NULL); PIOS_Flash_W25X_ReleaseBus(); return in[5]; } @@ -127,28 +127,27 @@ uint8_t PIOS_Flash_W25X_ReadID() * @param[in] add Address of flash to erase * @returns 0 if successful * @retval -1 if unable to claim bus - * @retval + * @retval */ int8_t PIOS_Flash_W25X_EraseSector(uint32_t addr) { uint8_t ret; uint8_t out[] = {W25X_SECTOR_ERASE, (addr >> 16) & 0xff, (addr >> 8) & 0xff , addr & 0xff}; - + if((ret = PIOS_Flash_W25X_WriteEnable()) != 0) return ret; - + if(PIOS_Flash_W25X_ClaimBus() != 0) - return -1; + return -1; PIOS_SPI_TransferBlock(PIOS_SPI_FLASH,out,NULL,sizeof(out),NULL); PIOS_Flash_W25X_ReleaseBus(); + uint32_t i = 1; while(PIOS_Flash_W25X_Busy()) { - //TODO: Fail on timeout -#if defined(PIOS_INCLUDE_FREERTOS) - vTaskDelay(1); -#endif + if(++i == 0) + return -1; } - + return 0; } @@ -160,25 +159,26 @@ int8_t PIOS_Flash_W25X_EraseChip() { uint8_t ret; uint8_t out[] = {W25X_CHIP_ERASE}; - + if((ret = PIOS_Flash_W25X_WriteEnable()) != 0) return ret; - + if(PIOS_Flash_W25X_ClaimBus() != 0) return -1; - PIOS_SPI_TransferBlock(PIOS_SPI_FLASH,out,NULL,sizeof(out),NULL); + PIOS_SPI_TransferBlock(PIOS_SPI_FLASH,out,NULL,sizeof(out),NULL); PIOS_Flash_W25X_ReleaseBus(); + + uint32_t i = 1; while(PIOS_Flash_W25X_Busy()) { - //TODO: Fail on timeout -#if defined(PIOS_INCLUDE_FREERTOS) - vTaskDelay(1); -#endif + if(++i == 0) + return -1; } + return 0; } -/** +/** * @brief Write one page of data (up to 256 bytes) aligned to a page start * @param[in] addr Address in flash to write to * @param[in] data Pointer to data to write to flash @@ -192,36 +192,45 @@ int8_t PIOS_Flash_W25X_WriteData(uint32_t addr, uint8_t * data, uint16_t len) { uint8_t ret; uint8_t out[4] = {W25X_PAGE_WRITE, (addr >> 16) & 0xff, (addr >> 8) & 0xff , addr & 0xff}; - + /* Can only write one page at a time */ - if(len > 0x100) + if(len > 0x100) return -2; - + /* Ensure number of bytes fits after starting address before end of page */ - if(((addr & 0xff) + len) > 0x100) + if(((addr & 0xff) + len) > 0x100) return -3; - + if((ret = PIOS_Flash_W25X_WriteEnable()) != 0) return ret; - + /* Execute write page command and clock in address. Keep CS asserted */ if(PIOS_Flash_W25X_ClaimBus() != 0) return -1; PIOS_SPI_TransferBlock(PIOS_SPI_FLASH,out,NULL,sizeof(out),NULL); - + /* Clock out data to flash */ PIOS_SPI_TransferBlock(PIOS_SPI_FLASH,data,NULL,len,NULL); PIOS_Flash_W25X_ReleaseBus(); + uint32_t i = 1; while(PIOS_Flash_W25X_Busy()) { -#if defined(PIOS_INCLUDE_FREERTOS) - vTaskDelay(1); -#endif + if(++i == 0) + return -1; } + return 0; } +/** + * @brief Read data from a location in flash memory + * @param[in] addr Address in flash to write to + * @param[in] data Pointer to data to write from flash + * @param[in] len Length of data to write (max 256 bytes) + * @return Zero if success or error code + * @retval -1 Unable to claim SPI bus + */ int8_t PIOS_Flash_W25X_ReadData(uint32_t addr, uint8_t * data, uint16_t len) { if(PIOS_Flash_W25X_ClaimBus() == -1) @@ -235,6 +244,6 @@ int8_t PIOS_Flash_W25X_ReadData(uint32_t addr, uint8_t * data, uint16_t len) PIOS_SPI_TransferBlock(PIOS_SPI_FLASH,NULL,data,len,NULL); PIOS_Flash_W25X_ReleaseBus(); - + return 0; } diff --git a/flight/PiOS/Common/pios_flashfs_objlist.c b/flight/PiOS/Common/pios_flashfs_objlist.c new file mode 100644 index 000000000..08fe640c9 --- /dev/null +++ b/flight/PiOS/Common/pios_flashfs_objlist.c @@ -0,0 +1,346 @@ +/** + ****************************************************************************** + * + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_FLASHFS_OBJLIST Object list based flash filesystem (low ram) + * @{ + * + * @file pios_flashfs_objlist.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief A file system for storing UAVObject in flash chip + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "openpilot.h" +#include "uavobjectmanager.h" + +// Private functions +static int32_t PIOS_FLASHFS_ClearObjectTableHeader(); +static int32_t PIOS_FLASHFS_GetObjAddress(uint32_t objId, uint16_t instId); +static int32_t PIOS_FLASHFS_GetNewAddress(uint32_t objId, uint16_t instId); + +// Private variables +static int32_t numObjects = -1; + +// Private structures +// Header for objects in the file system table +struct objectHeader { + uint32_t objMagic; + uint32_t objId; + uint32_t instId; + uint32_t address; +} __attribute__((packed));; + +struct fileHeader { + uint32_t id; + uint16_t instId; + uint16_t size; +} __attribute__((packed)); + + +#define OBJECT_TABLE_MAGIC 0x85FB3C35 +#define OBJ_MAGIC 0x3015AE71 +#define OBJECT_TABLE_START 0x00000010 +#define OBJECT_TABLE_END 0x00001000 +#define SECTOR_SIZE 0x00001000 +#define MAX_BADMAGIC 4 + +/** + * @brief Initialize the flash object setting FS + * @return 0 if success, -1 if failure + */ +int32_t PIOS_FLASHFS_Init() +{ + + // Check for valid object table or create one + uint32_t object_table_magic; + uint8_t magic_fail_count = 0; + bool magic_good = false; + + while(!magic_good) { + if (PIOS_Flash_W25X_ReadData(0, (uint8_t *)&object_table_magic, sizeof(object_table_magic)) != 0) + return -1; + if(object_table_magic != OBJECT_TABLE_MAGIC) { + if(magic_fail_count++ > MAX_BADMAGIC) { + PIOS_FLASHFS_ClearObjectTableHeader(); + PIOS_LED_Toggle(LED1); + magic_fail_count = 0; + magic_good = true; + } else { + PIOS_DELAY_WaituS(100); + } + + } + else { + magic_good = true; + } + + } + + int32_t addr = OBJECT_TABLE_START; + struct objectHeader header; + numObjects = 0; + + // Loop through header area while objects detect to count how many saved + while(addr < OBJECT_TABLE_END) { + // Read the instance data + if (PIOS_Flash_W25X_ReadData(addr, (uint8_t *)&header, sizeof(header)) != 0) + return -1; + + // Counting number of valid headers + if(header.objMagic != OBJ_MAGIC) + break; + + numObjects++; + addr += sizeof(header); + } + + return 0; +} + +/** + * @brief Erase the headers for all objects in the flash chip + * @return 0 if successful, -1 if not + */ +static int32_t PIOS_FLASHFS_ClearObjectTableHeader() +{ + if(PIOS_Flash_W25X_EraseSector(0) != 0) + return -1; + + uint32_t object_table_magic = OBJECT_TABLE_MAGIC; + if (PIOS_Flash_W25X_WriteData(0, (uint8_t *)&object_table_magic, sizeof(object_table_magic)) != 0) + return -1; + + return 0; +} + +/** + * @brief Get the address of an object + * @param obj UAVObjHandle for that object + * @parma instId Instance id for that object + * @return address if successful, -1 if not found + */ +static int32_t PIOS_FLASHFS_GetObjAddress(uint32_t objId, uint16_t instId) +{ + int32_t addr = OBJECT_TABLE_START; + struct objectHeader header; + + // Loop through header area while objects detect to count how many saved + while(addr < OBJECT_TABLE_END) { + // Read the instance data + if (PIOS_Flash_W25X_ReadData(addr, (uint8_t *) &header, sizeof(header)) != 0) + return -1; + if(header.objMagic != OBJ_MAGIC) + break; // stop searching once hit first non-object header + else if (header.objId == objId && header.instId == instId) + break; + addr += sizeof(header); + } + + if (header.objId == objId && header.instId == instId) + return header.address; + + return -1; +} + +/** + * @brief Returns an address for a new object and creates entry into object table + * @param[in] obj Object handle for object to be saved + * @param[in] instId The instance id of object to be saved + * @return 0 if success or error code + * @retval -1 Object not found + * @retval -2 No room in object table + * @retval -3 Unable to write entry into object table + * @retval -4 FS not initialized + */ +int32_t PIOS_FLASHFS_GetNewAddress(uint32_t objId, uint16_t instId) +{ + struct objectHeader header; + + if(numObjects < 0) + return -4; + + // Don't worry about max size of flash chip here, other code will catch that + header.objMagic = OBJ_MAGIC; + header.objId = objId; + header.instId = instId; + header.address = OBJECT_TABLE_END + SECTOR_SIZE * numObjects; + + int32_t addr = OBJECT_TABLE_START + sizeof(header) * numObjects; + + // No room for this header in object table + if((addr + sizeof(header)) > OBJECT_TABLE_END) + return -2; + + if(PIOS_Flash_W25X_WriteData(addr, (uint8_t *) &header, sizeof(header)) != 0) + return -3; + + // This numObejcts value must stay consistent or there will be a break in the table + // and later the table will have bad values in it + numObjects++; + return header.address; +} + + +/** + * @brief Saves one object instance per sector + * @param[in] obj UAVObjHandle the object to save + * @param[in] instId The instance of the object to save + * @return 0 if success or -1 if failure + * @note This uses one sector on the flash chip per object so that no buffering in ram + * must be done when erasing the sector before a save + */ +int32_t PIOS_FLASHFS_ObjSave(UAVObjHandle obj, uint16_t instId, uint8_t * data) +{ + uint32_t objId = UAVObjGetID(obj); + uint8_t crc = 0; + + int32_t addr = PIOS_FLASHFS_GetObjAddress(objId, instId); + + // Object currently not saved + if(addr < 0) + addr = PIOS_FLASHFS_GetNewAddress(objId, instId); + + // Could not allocate a sector + if(addr < 0) + return -1; + + struct fileHeader header = { + .id = objId, + .instId = instId, + .size = UAVObjGetNumBytes(obj) + }; + + if(PIOS_Flash_W25X_EraseSector(addr) != 0) + return -2; + + // Save header + // This information IS redundant with the object table id. Oh well. Better safe than sorry. + if(PIOS_Flash_W25X_WriteData(addr, (uint8_t *) &header, sizeof(header)) != 0) + return -3; + + // Update CRC + crc = PIOS_CRC_updateCRC(0, (uint8_t *) &header, sizeof(header)); + + // Save data + if(PIOS_Flash_W25X_WriteData(addr + sizeof(header), data, UAVObjGetNumBytes(obj)) != 0) + return -4; + + // Update CRC + crc = PIOS_CRC_updateCRC(crc, (uint8_t *) data, UAVObjGetNumBytes(obj)); + + // Save CRC (written so will work when CRC changes to uint16) + if(PIOS_Flash_W25X_WriteData(addr + sizeof(header) + UAVObjGetNumBytes(obj), (uint8_t *) &crc, sizeof(crc)) != 0) + return -4; + + return 0; +} + +/** + * @brief Load one object instance per sector + * @param[in] obj UAVObjHandle the object to save + * @param[in] instId The instance of the object to save + * @return 0 if success or error code + * @retval -1 if object not in file table + * @retval -2 if unable to retrieve object header + * @retval -3 if loaded data instId or objId don't match + * @retval -4 if unable to retrieve instance data + * @retval -5 if unable to read CRC + * @retval -6 if CRC doesn't match + * @note This uses one sector on the flash chip per object so that no buffering in ram + * must be done when erasing the sector before a save + */ +int32_t PIOS_FLASHFS_ObjLoad(UAVObjHandle obj, uint16_t instId, uint8_t * data) +{ + uint32_t objId = UAVObjGetID(obj); + uint16_t objSize = UAVObjGetNumBytes(obj); + uint8_t crc = 0; + uint8_t crcFlash = 0; + const uint8_t crc_read_step = 8; + uint8_t crc_read_buffer[crc_read_step]; + + int32_t addr = PIOS_FLASHFS_GetObjAddress(objId, instId); + + // Object currently not saved + if(addr < 0) + return -1; + + struct fileHeader header; + + // Load header + // This information IS redundant with the object table id. Oh well. Better safe than sorry. + if(PIOS_Flash_W25X_ReadData(addr, (uint8_t *) &header, sizeof(header)) != 0) + return -2; + + // Update CRC + crc = PIOS_CRC_updateCRC(0, (uint8_t *) &header, sizeof(header)); + + if((header.id != objId) || (header.instId != instId)) + return -3; + + // To avoid having to allocate the RAM for a copy of the object, we read by chunks + // and compute the CRC + for(uint32_t i = 0; i < objSize; i += crc_read_step) { + PIOS_Flash_W25X_ReadData(addr + sizeof(header) + i, crc_read_buffer, crc_read_step); + uint8_t valid_bytes = ((i + crc_read_step) >= objSize) ? objSize - i : crc_read_step; + crc = PIOS_CRC_updateCRC(crc, crc_read_buffer, valid_bytes); + } + + // Read CRC (written so will work when CRC changes to uint16) + if(PIOS_Flash_W25X_ReadData(addr + sizeof(header) + objSize, (uint8_t *) &crcFlash, sizeof(crcFlash)) != 0) + return -5; + + if(crc != crcFlash) + return -6; + + // Read the instance data + if (PIOS_Flash_W25X_ReadData(addr + sizeof(header), data, objSize) != 0) + return -4; + + return 0; +} + +/** + * @brief Delete object from flash + * @param[in] obj UAVObjHandle the object to save + * @param[in] instId The instance of the object to save + * @return 0 if success or error code + * @retval -1 if object not in file table + * @retval -2 Erase failed + * @note To avoid buffering the file table (1k ram!) the entry in the file table + * remains but destination sector is erased. This will make the load fail as the + * file header won't match the object. At next save it goes back there. + */ +int32_t PIOS_FLASHFS_ObjDelete(UAVObjHandle obj, uint16_t instId) +{ + uint32_t objId = UAVObjGetID(obj); + + int32_t addr = PIOS_FLASHFS_GetObjAddress(objId, instId); + + // Object currently not saved + if(addr < 0) + return -1; + + if(PIOS_Flash_W25X_EraseSector(addr) != 0) + return -2; + + return 0; +} diff --git a/flight/PiOS/Common/pios_hcsr04.c b/flight/PiOS/Common/pios_hcsr04.c index aa6dece83..6db1bc401 100644 --- a/flight/PiOS/Common/pios_hcsr04.c +++ b/flight/PiOS/Common/pios_hcsr04.c @@ -32,8 +32,8 @@ #include "pios.h" #if defined(PIOS_INCLUDE_HCSR04) -#if !defined(PIOS_INCLUDE_SPEKTRUM) -#error Only supported with spektrum interface! +#if !(defined(PIOS_INCLUDE_SPEKTRUM) || defined(PIOS_INCLUDE_SBUS)) +#error Only supported with Spektrum or S.Bus interface! #endif /* Local Variables */ diff --git a/flight/PiOS/Common/pios_rcvr.c b/flight/PiOS/Common/pios_rcvr.c new file mode 100644 index 000000000..29acb2594 --- /dev/null +++ b/flight/PiOS/Common/pios_rcvr.c @@ -0,0 +1,98 @@ +/* Project Includes */ +#include "pios.h" + +#if defined(PIOS_INCLUDE_RCVR) + +#include + +enum pios_rcvr_dev_magic { + PIOS_RCVR_DEV_MAGIC = 0x99aabbcc, +}; + +struct pios_rcvr_dev { + enum pios_rcvr_dev_magic magic; + uint32_t lower_id; + const struct pios_rcvr_driver * driver; +}; + +static bool PIOS_RCVR_validate(struct pios_rcvr_dev * rcvr_dev) +{ + return (rcvr_dev->magic == PIOS_RCVR_DEV_MAGIC); +} + +#if defined(PIOS_INCLUDE_FREERTOS) && 0 +static struct pios_rcvr_dev * PIOS_RCVR_alloc(void) +{ + struct pios_rcvr_dev * rcvr_dev; + + rcvr_dev = (struct pios_rcvr_dev *)malloc(sizeof(*rcvr_dev)); + if (!rcvr_dev) return (NULL); + + rcvr_dev->magic = PIOS_RCVR_DEV_MAGIC; + return(rcvr_dev); +} +#else +static struct pios_rcvr_dev pios_rcvr_devs[PIOS_RCVR_MAX_DEVS]; +static uint8_t pios_rcvr_num_devs; +static struct pios_rcvr_dev * PIOS_RCVR_alloc(void) +{ + struct pios_rcvr_dev * rcvr_dev; + + if (pios_rcvr_num_devs >= PIOS_RCVR_MAX_DEVS) { + return (NULL); + } + + rcvr_dev = &pios_rcvr_devs[pios_rcvr_num_devs++]; + rcvr_dev->magic = PIOS_RCVR_DEV_MAGIC; + + return (rcvr_dev); +} +#endif + +/** + * Initialises RCVR layer + * \param[out] handle + * \param[in] driver + * \param[in] id + * \return < 0 if initialisation failed + */ +int32_t PIOS_RCVR_Init(uint32_t * rcvr_id, const struct pios_rcvr_driver * driver, uint32_t lower_id) +{ + PIOS_DEBUG_Assert(rcvr_id); + PIOS_DEBUG_Assert(driver); + + struct pios_rcvr_dev * rcvr_dev; + + rcvr_dev = (struct pios_rcvr_dev *) PIOS_RCVR_alloc(); + if (!rcvr_dev) goto out_fail; + + rcvr_dev->driver = driver; + rcvr_dev->lower_id = lower_id; + + *rcvr_id = (uint32_t)rcvr_dev; + return(0); + +out_fail: + return(-1); +} + +int32_t PIOS_RCVR_Read(uint32_t rcvr_id, uint8_t channel) +{ + struct pios_rcvr_dev * rcvr_dev = (struct pios_rcvr_dev *)rcvr_id; + + if (!PIOS_RCVR_validate(rcvr_dev)) { + /* Undefined RCVR port for this board (see pios_board.c) */ + PIOS_Assert(0); + } + + PIOS_DEBUG_Assert(rcvr_dev->driver->read); + + return rcvr_dev->driver->read(rcvr_dev->lower_id, channel); +} + +#endif + +/** + * @} + * @} + */ diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/croutine.c b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/croutine.c old mode 100755 new mode 100644 index f180a8774..58fb1bf4b --- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/croutine.c +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/croutine.c @@ -1,41 +1,47 @@ /* - FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd. + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + + + FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by: + Atollic AB - Atollic provides professional embedded systems development + tools for C/C++ development, code analysis and test automation. + See http://www.atollic.com + *************************************************************************** - * * - * If you are: * - * * - * + New to FreeRTOS, * - * + Wanting to learn FreeRTOS or multitasking in general quickly * - * + Looking for basic training, * - * + Wanting to improve your FreeRTOS skills and productivity * - * * - * then take a look at the FreeRTOS books - available as PDF or paperback * - * * - * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * - * http://www.FreeRTOS.org/Documentation * - * * - * A pdf reference manual is also available. Both are usually delivered * - * to your inbox within 20 minutes to two hours when purchased between 8am * - * and 8pm GMT (although please allow up to 24 hours in case of * - * exceptional circumstances). Thank you for your support! * - * * + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * *************************************************************************** + This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - ***NOTE*** The exception to the GPL is included to allow you to distribute - a combined work that includes FreeRTOS without being obliged to provide the - source code for proprietary components outside of the FreeRTOS kernel. - FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it - can be viewed here: http://www.freertos.org/a00114.html and also obtained + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained by writing to Richard Barry, contact details for whom are available on the FreeRTOS WEB site. @@ -222,7 +228,7 @@ static void prvCheckPendingReadyList( void ) /* Are there any co-routines waiting to get moved to the ready list? These are co-routines that have been readied by an ISR. The ISR cannot access the ready lists itself. */ - while( !listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) ) + while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE ) { corCRCB *pxUnblockedCRCB; @@ -263,8 +269,10 @@ corCRCB *pxCRCB; } /* See if this tick has made a timeout expire. */ - while( ( pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList ) ) != NULL ) - { + while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE ) + { + pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList ); + if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) ) { /* Timeout not yet expired. */ @@ -352,7 +360,8 @@ corCRCB *pxUnblockedCRCB; signed portBASE_TYPE xReturn; /* This function is called from within an interrupt. It can only access - event lists and the pending ready list. */ + event lists and the pending ready list. This function assumes that a + check has already been made to ensure pxEventList is not empty. */ pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); vListRemove( &( pxUnblockedCRCB->xEventListItem ) ); vListInsertEnd( ( xList * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) ); diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/FreeRTOS.h b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/FreeRTOS.h old mode 100755 new mode 100644 index f440a16d1..e5eb39abb --- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/FreeRTOS.h +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/FreeRTOS.h @@ -1,38 +1,44 @@ /* - FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd. + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + + + FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by: + Atollic AB - Atollic provides professional embedded systems development + tools for C/C++ development, code analysis and test automation. + See http://www.atollic.com + *************************************************************************** - * * - * If you are: * - * * - * + New to FreeRTOS, * - * + Wanting to learn FreeRTOS or multitasking in general quickly * - * + Looking for basic training, * - * + Wanting to improve your FreeRTOS skills and productivity * - * * - * then take a look at the FreeRTOS books - available as PDF or paperback * - * * - * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * - * http://www.FreeRTOS.org/Documentation * - * * - * A pdf reference manual is also available. Both are usually delivered * - * to your inbox within 20 minutes to two hours when purchased between 8am * - * and 8pm GMT (although please allow up to 24 hours in case of * - * exceptional circumstances). Thank you for your support! * - * * + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * *************************************************************************** + This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - ***NOTE*** The exception to the GPL is included to allow you to distribute - a combined work that includes FreeRTOS without being obliged to provide the - source code for proprietary components outside of the FreeRTOS kernel. - FreeRTOS 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 + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it can be viewed here: http://www.freertos.org/a00114.html and also obtained @@ -148,6 +154,10 @@ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * ); #define configUSE_MUTEXES 0 #endif +#ifndef configUSE_TIMERS + #define configUSE_TIMERS 0 +#endif + #ifndef configUSE_COUNTING_SEMAPHORES #define configUSE_COUNTING_SEMAPHORES 0 #endif @@ -169,27 +179,40 @@ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * ); #endif #if configMAX_TASK_NAME_LEN < 1 - #undef configMAX_TASK_NAME_LEN - #define configMAX_TASK_NAME_LEN 1 + #error configMAX_TASK_NAME_LEN must be set to a minimum of 1 in FreeRTOSConfig.h #endif #ifndef INCLUDE_xTaskResumeFromISR #define INCLUDE_xTaskResumeFromISR 1 #endif +#ifndef configASSERT + #define configASSERT( x ) +#endif + +/* The timers module relies on xTaskGetSchedulerState(). */ +#if configUSE_TIMERS == 1 + + #ifndef configTIMER_TASK_PRIORITY + #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_PRIORITY must also be defined. + #endif /* configTIMER_TASK_PRIORITY */ + + #ifndef configTIMER_QUEUE_LENGTH + #error If configUSE_TIMERS is set to 1 then configTIMER_QUEUE_LENGTH must also be defined. + #endif /* configTIMER_QUEUE_LENGTH */ + + #ifndef configTIMER_TASK_STACK_DEPTH + #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_STACK_DEPTH must also be defined. + #endif /* configTIMER_TASK_STACK_DEPTH */ + +#endif /* configUSE_TIMERS */ + #ifndef INCLUDE_xTaskGetSchedulerState #define INCLUDE_xTaskGetSchedulerState 0 #endif -#if ( configUSE_MUTEXES == 1 ) - /* xTaskGetCurrentTaskHandle is used by the priority inheritance mechanism - within the mutex implementation so must be available if mutexes are used. */ - #undef INCLUDE_xTaskGetCurrentTaskHandle - #define INCLUDE_xTaskGetCurrentTaskHandle 1 -#else - #ifndef INCLUDE_xTaskGetCurrentTaskHandle - #define INCLUDE_xTaskGetCurrentTaskHandle 0 - #endif +#ifndef INCLUDE_xTaskGetCurrentTaskHandle + #define INCLUDE_xTaskGetCurrentTaskHandle 0 #endif @@ -203,11 +226,10 @@ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * ); #ifndef configQUEUE_REGISTRY_SIZE - #define configQUEUE_REGISTRY_SIZE 0 + #define configQUEUE_REGISTRY_SIZE 0U #endif -#if configQUEUE_REGISTRY_SIZE < 1 - #define configQUEUE_REGISTRY_SIZE 0 +#if ( configQUEUE_REGISTRY_SIZE < 1U ) #define vQueueAddToRegistry( xQueue, pcName ) #define vQueueUnregisterQueue( xQueue ) #endif @@ -380,6 +402,26 @@ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * ); #define traceTASK_INCREMENT_TICK( xTickCount ) #endif +#ifndef traceTIMER_CREATE + #define traceTIMER_CREATE( pxNewTimer ) +#endif + +#ifndef traceTIMER_CREATE_FAILED + #define traceTIMER_CREATE_FAILED() +#endif + +#ifndef traceTIMER_COMMAND_SEND + #define traceTIMER_COMMAND_SEND( xTimer, xMessageID, xMessageValueValue, xReturn ) +#endif + +#ifndef traceTIMER_EXPIRED + #define traceTIMER_EXPIRED( pxTimer ) +#endif + +#ifndef traceTIMER_COMMAND_RECEIVED + #define traceTIMER_COMMAND_RECEIVED( pxTimer, xMessageID, xMessageValue ) +#endif + #ifndef configGENERATE_RUN_TIME_STATS #define configGENERATE_RUN_TIME_STATS 0 #endif @@ -415,7 +457,7 @@ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * ); #endif #ifndef pvPortMallocAligned - #define pvPortMallocAligned( x, puxStackBuffer ) ( ( puxStackBuffer == NULL ) ? ( pvPortMalloc( x ) ) : ( puxStackBuffer ) ) + #define pvPortMallocAligned( x, puxStackBuffer ) ( ( ( puxStackBuffer ) == NULL ) ? ( pvPortMalloc( ( x ) ) ) : ( puxStackBuffer ) ) #endif #ifndef vPortFreeAligned diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/StackMacros.h b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/StackMacros.h old mode 100755 new mode 100644 index 00645e895..1114b6d29 --- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/StackMacros.h +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/StackMacros.h @@ -1,38 +1,44 @@ /* - FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd. + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + + + FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by: + Atollic AB - Atollic provides professional embedded systems development + tools for C/C++ development, code analysis and test automation. + See http://www.atollic.com + *************************************************************************** - * * - * If you are: * - * * - * + New to FreeRTOS, * - * + Wanting to learn FreeRTOS or multitasking in general quickly * - * + Looking for basic training, * - * + Wanting to improve your FreeRTOS skills and productivity * - * * - * then take a look at the FreeRTOS books - available as PDF or paperback * - * * - * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * - * http://www.FreeRTOS.org/Documentation * - * * - * A pdf reference manual is also available. Both are usually delivered * - * to your inbox within 20 minutes to two hours when purchased between 8am * - * and 8pm GMT (although please allow up to 24 hours in case of * - * exceptional circumstances). Thank you for your support! * - * * + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * *************************************************************************** + This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - ***NOTE*** The exception to the GPL is included to allow you to distribute - a combined work that includes FreeRTOS without being obliged to provide the - source code for proprietary components outside of the FreeRTOS kernel. - FreeRTOS 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 + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it can be viewed here: http://www.freertos.org/a00114.html and also obtained @@ -93,8 +99,6 @@ /* Only the current stack state is to be checked. */ #define taskFIRST_CHECK_FOR_STACK_OVERFLOW() \ { \ - extern void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName ); \ - \ /* Is the currently saved stack pointer within the stack limit? */ \ if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \ { \ @@ -110,7 +114,6 @@ /* Only the current stack state is to be checked. */ #define taskFIRST_CHECK_FOR_STACK_OVERFLOW() \ { \ - extern void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName ); \ \ /* Is the currently saved stack pointer within the stack limit? */ \ if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \ @@ -124,21 +127,20 @@ #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) ) - #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() \ - { \ - extern void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName ); \ - static const unsigned char ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ - tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ - tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ - tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ - tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \ - \ - \ - /* Has the extremity of the task stack ever been written over? */ \ - if( memcmp( ( void * ) pxCurrentTCB->pxStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \ - { \ - vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ - } \ + #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() \ + { \ + static const unsigned char ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \ + \ + \ + /* Has the extremity of the task stack ever been written over? */ \ + if( memcmp( ( void * ) pxCurrentTCB->pxStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \ + { \ + vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ } #endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ @@ -146,24 +148,23 @@ #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) ) - #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() \ - { \ - extern void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName ); \ - char *pcEndOfStack = ( char * ) pxCurrentTCB->pxEndOfStack; \ - static const unsigned char ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ - tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ - tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ - tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ - tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \ - \ - \ - pcEndOfStack -= sizeof( ucExpectedStackBytes ); \ - \ - /* Has the extremity of the task stack ever been written over? */ \ - if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \ - { \ - vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ - } \ + #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() \ + { \ + char *pcEndOfStack = ( char * ) pxCurrentTCB->pxEndOfStack; \ + static const unsigned char ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \ + \ + \ + pcEndOfStack -= sizeof( ucExpectedStackBytes ); \ + \ + /* Has the extremity of the task stack ever been written over? */ \ + if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \ + { \ + vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ } #endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/croutine.h b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/croutine.h old mode 100755 new mode 100644 index 64c64a754..65fdc48e0 --- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/croutine.h +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/croutine.h @@ -1,41 +1,47 @@ /* - FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd. + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + + + FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by: + Atollic AB - Atollic provides professional embedded systems development + tools for C/C++ development, code analysis and test automation. + See http://www.atollic.com + *************************************************************************** - * * - * If you are: * - * * - * + New to FreeRTOS, * - * + Wanting to learn FreeRTOS or multitasking in general quickly * - * + Looking for basic training, * - * + Wanting to improve your FreeRTOS skills and productivity * - * * - * then take a look at the FreeRTOS books - available as PDF or paperback * - * * - * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * - * http://www.FreeRTOS.org/Documentation * - * * - * A pdf reference manual is also available. Both are usually delivered * - * to your inbox within 20 minutes to two hours when purchased between 8am * - * and 8pm GMT (although please allow up to 24 hours in case of * - * exceptional circumstances). Thank you for your support! * - * * + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * *************************************************************************** + This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - ***NOTE*** The exception to the GPL is included to allow you to distribute - a combined work that includes FreeRTOS without being obliged to provide the - source code for proprietary components outside of the FreeRTOS kernel. - FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it - can be viewed here: http://www.freertos.org/a00114.html and also obtained + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained by writing to Richard Barry, contact details for whom are available on the FreeRTOS WEB site. @@ -51,16 +57,13 @@ licensing and training services. */ +#ifndef CO_ROUTINE_H +#define CO_ROUTINE_H + #ifndef INC_FREERTOS_H #error "include FreeRTOS.h must appear in source files before include croutine.h" #endif - - - -#ifndef CO_ROUTINE_H -#define CO_ROUTINE_H - #include "list.h" #ifdef __cplusplus @@ -230,7 +233,7 @@ void vCoRoutineSchedule( void ); * \defgroup crSTART crSTART * \ingroup Tasks */ -#define crSTART( pxCRCB ) switch( ( ( corCRCB * )pxCRCB )->uxState ) { case 0: +#define crSTART( pxCRCB ) switch( ( ( corCRCB * )( pxCRCB ) )->uxState ) { case 0: /** * croutine. h @@ -267,8 +270,8 @@ void vCoRoutineSchedule( void ); * These macros are intended for internal use by the co-routine implementation * only. The macros should not be used directly by application writers. */ -#define crSET_STATE0( xHandle ) ( ( corCRCB * )xHandle)->uxState = (__LINE__ * 2); return; case (__LINE__ * 2): -#define crSET_STATE1( xHandle ) ( ( corCRCB * )xHandle)->uxState = ((__LINE__ * 2)+1); return; case ((__LINE__ * 2)+1): +#define crSET_STATE0( xHandle ) ( ( corCRCB * )( xHandle ) )->uxState = (__LINE__ * 2); return; case (__LINE__ * 2): +#define crSET_STATE1( xHandle ) ( ( corCRCB * )( xHandle ) )->uxState = ((__LINE__ * 2)+1); return; case ((__LINE__ * 2)+1): /** * croutine. h @@ -317,11 +320,11 @@ void vCoRoutineSchedule( void ); * \ingroup Tasks */ #define crDELAY( xHandle, xTicksToDelay ) \ - if( xTicksToDelay > 0 ) \ + if( ( xTicksToDelay ) > 0 ) \ { \ - vCoRoutineAddToDelayedList( xTicksToDelay, NULL ); \ + vCoRoutineAddToDelayedList( ( xTicksToDelay ), NULL ); \ } \ - crSET_STATE0( xHandle ); + crSET_STATE0( ( xHandle ) ); /** *
@@ -408,15 +411,15 @@ void vCoRoutineSchedule( void );
  */
 #define crQUEUE_SEND( xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult )			\
 {																						\
-	*pxResult = xQueueCRSend( pxQueue, pvItemToQueue, xTicksToWait );					\
-	if( *pxResult == errQUEUE_BLOCKED )													\
+	*( pxResult ) = xQueueCRSend( ( pxQueue) , ( pvItemToQueue) , ( xTicksToWait ) );	\
+	if( *( pxResult ) == errQUEUE_BLOCKED )												\
 	{																					\
-		crSET_STATE0( xHandle );														\
-		*pxResult = xQueueCRSend( pxQueue, pvItemToQueue, 0 );							\
+		crSET_STATE0( ( xHandle ) );													\
+		*pxResult = xQueueCRSend( ( pxQueue ), ( pvItemToQueue ), 0 );					\
 	}																					\
 	if( *pxResult == errQUEUE_YIELD )													\
 	{																					\
-		crSET_STATE1( xHandle );														\
+		crSET_STATE1( ( xHandle ) );													\
 		*pxResult = pdPASS;																\
 	}																					\
 }
@@ -500,16 +503,16 @@ void vCoRoutineSchedule( void );
  */
 #define crQUEUE_RECEIVE( xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult )			\
 {																						\
-	*pxResult = xQueueCRReceive( pxQueue, pvBuffer, xTicksToWait );						\
-	if( *pxResult == errQUEUE_BLOCKED ) 												\
+	*( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), ( xTicksToWait ) );		\
+	if( *( pxResult ) == errQUEUE_BLOCKED ) 											\
 	{																					\
-		crSET_STATE0( xHandle );														\
-		*pxResult = xQueueCRReceive( pxQueue, pvBuffer, 0 );							\
+		crSET_STATE0( ( xHandle ) );													\
+		*( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), 0 );				\
 	}																					\
-	if( *pxResult == errQUEUE_YIELD )													\
+	if( *( pxResult ) == errQUEUE_YIELD )												\
 	{																					\
-		crSET_STATE1( xHandle );														\
-		*pxResult = pdPASS;																\
+		crSET_STATE1( ( xHandle ) );													\
+		*( pxResult ) = pdPASS;															\
 	}																					\
 }
 
@@ -607,7 +610,7 @@ void vCoRoutineSchedule( void );
  * \defgroup crQUEUE_SEND_FROM_ISR crQUEUE_SEND_FROM_ISR
  * \ingroup Tasks
  */
-#define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) xQueueCRSendFromISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken )
+#define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) xQueueCRSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( xCoRoutinePreviouslyWoken ) )
 
 
 /**
@@ -720,7 +723,7 @@ void vCoRoutineSchedule( void );
  * \defgroup crQUEUE_RECEIVE_FROM_ISR crQUEUE_RECEIVE_FROM_ISR
  * \ingroup Tasks
  */
-#define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) xQueueCRReceiveFromISR( pxQueue, pvBuffer, pxCoRoutineWoken )
+#define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) xQueueCRReceiveFromISR( ( pxQueue ), ( pvBuffer ), ( pxCoRoutineWoken ) )
 
 /*
  * This function is intended for internal use by the co-routine macros only.
diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/list.h b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/list.h
old mode 100755
new mode 100644
index 5a09fd1d6..e8b47c439
--- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/list.h
+++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/list.h
@@ -1,41 +1,47 @@
 /*
-    FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+    FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+	
+
+	FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+	Atollic AB - Atollic provides professional embedded systems development 
+	tools for C/C++ development, code analysis and test automation.  
+	See http://www.atollic.com
+	
 
     ***************************************************************************
-    *                                                                         *
-    * If you are:                                                             *
-    *                                                                         *
-    *    + New to FreeRTOS,                                                   *
-    *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
-    *    + Looking for basic training,                                        *
-    *    + Wanting to improve your FreeRTOS skills and productivity           *
-    *                                                                         *
-    * then take a look at the FreeRTOS books - available as PDF or paperback  *
-    *                                                                         *
-    *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
-    *                  http://www.FreeRTOS.org/Documentation                  *
-    *                                                                         *
-    * A pdf reference manual is also available.  Both are usually delivered   *
-    * to your inbox within 20 minutes to two hours when purchased between 8am *
-    * and 8pm GMT (although please allow up to 24 hours in case of            *
-    * exceptional circumstances).  Thank you for your support!                *
-    *                                                                         *
+     *                                                                       *
+     *    FreeRTOS tutorial books are available in pdf and paperback.        *
+     *    Complete, revised, and edited pdf reference manuals are also       *
+     *    available.                                                         *
+     *                                                                       *
+     *    Purchasing FreeRTOS documentation will not only help you, by       *
+     *    ensuring you get running as quickly as possible and with an        *
+     *    in-depth knowledge of how to use FreeRTOS, it will also help       *
+     *    the FreeRTOS project to continue with its mission of providing     *
+     *    professional grade, cross platform, de facto standard solutions    *
+     *    for microcontrollers - completely free of charge!                  *
+     *                                                                       *
+     *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *
+     *                                                                       *
+     *    Thank you for using FreeRTOS, and thank you for your support!      *
+     *                                                                       *
     ***************************************************************************
 
+
     This file is part of the FreeRTOS distribution.
 
     FreeRTOS is free software; you can redistribute it and/or modify it under
     the terms of the GNU General Public License (version 2) as published by the
     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
-    ***NOTE*** The exception to the GPL is included to allow you to distribute
-    a combined work that includes FreeRTOS without being obliged to provide the
-    source code for proprietary components outside of the FreeRTOS kernel.
-    FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it 
-    can be viewed here: http://www.freertos.org/a00114.html and also obtained 
+    >>>NOTE<<< The modification to the GPL is included to allow you to
+    distribute a combined work that includes FreeRTOS without being obliged to
+    provide the source code for proprietary components outside of the FreeRTOS
+    kernel.  FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it
+    can be viewed here: http://www.freertos.org/a00114.html and also obtained
     by writing to Richard Barry, contact details for whom are available on the
     FreeRTOS WEB site.
 
@@ -79,12 +85,6 @@
  * \ingroup FreeRTOSIntro
  */
 
-/*
-	Changes from V4.3.1
-
-	+ Included local const within listGET_OWNER_OF_NEXT_ENTRY() to assist
-	  compiler with optimisation.  Thanks B.R.
-*/
 
 #ifndef LIST_H
 #define LIST_H
@@ -130,7 +130,7 @@ typedef struct xLIST
  * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
  * \ingroup LinkedList
  */
-#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )		( pxListItem )->pvOwner = ( void * ) pxOwner
+#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )		( pxListItem )->pvOwner = ( void * ) ( pxOwner )
 
 /*
  * Access macro to set the value of the list item.  In most cases the value is
@@ -139,7 +139,7 @@ typedef struct xLIST
  * \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE
  * \ingroup LinkedList
  */
-#define listSET_LIST_ITEM_VALUE( pxListItem, xValue )		( pxListItem )->xItemValue = xValue
+#define listSET_LIST_ITEM_VALUE( pxListItem, xValue )		( pxListItem )->xItemValue = ( xValue )
 
 /*
  * Access macro the retrieve the value of the list item.  The value can
@@ -151,6 +151,15 @@ typedef struct xLIST
  */
 #define listGET_LIST_ITEM_VALUE( pxListItem )				( ( pxListItem )->xItemValue )
 
+/*
+ * Access macro the retrieve the value of the list item at the head of a given
+ * list.
+ *
+ * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
+ * \ingroup LinkedList
+ */
+#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )			( (&( ( pxList )->xListEnd ))->pxNext->xItemValue )
+
 /*
  * Access macro to determine if a list contains any items.  The macro will
  * only have the value true if the list is empty.
@@ -186,7 +195,7 @@ typedef struct xLIST
  */
 #define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )									\
 {																						\
-xList * const pxConstList = pxList;														\
+xList * const pxConstList = ( pxList );													\
 	/* Increment the index to the next item and return the item, ensuring */			\
 	/* we don't return the marker used at the end of the list.  */						\
 	( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;						\
@@ -194,7 +203,7 @@ xList * const pxConstList = pxList;														\
 	{																					\
 		( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;					\
 	}																					\
-	pxTCB = ( pxConstList )->pxIndex->pvOwner;											\
+	( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;										\
 }
 
 
@@ -214,7 +223,7 @@ xList * const pxConstList = pxList;														\
  * \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY
  * \ingroup LinkedList
  */
-#define listGET_OWNER_OF_HEAD_ENTRY( pxList )  ( ( pxList->uxNumberOfItems != ( unsigned portBASE_TYPE ) 0 ) ? ( (&( pxList->xListEnd ))->pxNext->pvOwner ) : ( NULL ) )
+#define listGET_OWNER_OF_HEAD_ENTRY( pxList )  ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner )
 
 /*
  * Check to see if a list item is within a list.  The list item maintains a
@@ -226,7 +235,7 @@ xList * const pxConstList = pxList;														\
  * @return pdTRUE is the list item is in the list, otherwise pdFALSE.
  * pointer against
  */
-#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( pxListItem )->pvContainer == ( void * ) pxList )
+#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) )
 
 /*
  * Must be called before a list is used!  This initialises all the members
diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/mpu_wrappers.h b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/mpu_wrappers.h
old mode 100755
new mode 100644
index 6f5287fd2..b7371b9ba
--- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/mpu_wrappers.h
+++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/mpu_wrappers.h
@@ -1,41 +1,47 @@
 /*
-    FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+    FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+	
+
+	FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+	Atollic AB - Atollic provides professional embedded systems development 
+	tools for C/C++ development, code analysis and test automation.  
+	See http://www.atollic.com
+	
 
     ***************************************************************************
-    *                                                                         *
-    * If you are:                                                             *
-    *                                                                         *
-    *    + New to FreeRTOS,                                                   *
-    *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
-    *    + Looking for basic training,                                        *
-    *    + Wanting to improve your FreeRTOS skills and productivity           *
-    *                                                                         *
-    * then take a look at the FreeRTOS books - available as PDF or paperback  *
-    *                                                                         *
-    *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
-    *                  http://www.FreeRTOS.org/Documentation                  *
-    *                                                                         *
-    * A pdf reference manual is also available.  Both are usually delivered   *
-    * to your inbox within 20 minutes to two hours when purchased between 8am *
-    * and 8pm GMT (although please allow up to 24 hours in case of            *
-    * exceptional circumstances).  Thank you for your support!                *
-    *                                                                         *
+     *                                                                       *
+     *    FreeRTOS tutorial books are available in pdf and paperback.        *
+     *    Complete, revised, and edited pdf reference manuals are also       *
+     *    available.                                                         *
+     *                                                                       *
+     *    Purchasing FreeRTOS documentation will not only help you, by       *
+     *    ensuring you get running as quickly as possible and with an        *
+     *    in-depth knowledge of how to use FreeRTOS, it will also help       *
+     *    the FreeRTOS project to continue with its mission of providing     *
+     *    professional grade, cross platform, de facto standard solutions    *
+     *    for microcontrollers - completely free of charge!                  *
+     *                                                                       *
+     *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *
+     *                                                                       *
+     *    Thank you for using FreeRTOS, and thank you for your support!      *
+     *                                                                       *
     ***************************************************************************
 
+
     This file is part of the FreeRTOS distribution.
 
     FreeRTOS is free software; you can redistribute it and/or modify it under
     the terms of the GNU General Public License (version 2) as published by the
     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
-    ***NOTE*** The exception to the GPL is included to allow you to distribute
-    a combined work that includes FreeRTOS without being obliged to provide the
-    source code for proprietary components outside of the FreeRTOS kernel.
-    FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it 
-    can be viewed here: http://www.freertos.org/a00114.html and also obtained 
+    >>>NOTE<<< The modification to the GPL is included to allow you to
+    distribute a combined work that includes FreeRTOS without being obliged to
+    provide the source code for proprietary components outside of the FreeRTOS
+    kernel.  FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it
+    can be viewed here: http://www.freertos.org/a00114.html and also obtained
     by writing to Richard Barry, contact details for whom are available on the
     FreeRTOS WEB site.
 
diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/portable.h b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/portable.h
old mode 100755
new mode 100644
index b4f37f336..288320033
--- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/portable.h
+++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/portable.h
@@ -1,41 +1,47 @@
 /*
-    FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+    FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+	
+
+	FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+	Atollic AB - Atollic provides professional embedded systems development 
+	tools for C/C++ development, code analysis and test automation.  
+	See http://www.atollic.com
+	
 
     ***************************************************************************
-    *                                                                         *
-    * If you are:                                                             *
-    *                                                                         *
-    *    + New to FreeRTOS,                                                   *
-    *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
-    *    + Looking for basic training,                                        *
-    *    + Wanting to improve your FreeRTOS skills and productivity           *
-    *                                                                         *
-    * then take a look at the FreeRTOS books - available as PDF or paperback  *
-    *                                                                         *
-    *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
-    *                  http://www.FreeRTOS.org/Documentation                  *
-    *                                                                         *
-    * A pdf reference manual is also available.  Both are usually delivered   *
-    * to your inbox within 20 minutes to two hours when purchased between 8am *
-    * and 8pm GMT (although please allow up to 24 hours in case of            *
-    * exceptional circumstances).  Thank you for your support!                *
-    *                                                                         *
+     *                                                                       *
+     *    FreeRTOS tutorial books are available in pdf and paperback.        *
+     *    Complete, revised, and edited pdf reference manuals are also       *
+     *    available.                                                         *
+     *                                                                       *
+     *    Purchasing FreeRTOS documentation will not only help you, by       *
+     *    ensuring you get running as quickly as possible and with an        *
+     *    in-depth knowledge of how to use FreeRTOS, it will also help       *
+     *    the FreeRTOS project to continue with its mission of providing     *
+     *    professional grade, cross platform, de facto standard solutions    *
+     *    for microcontrollers - completely free of charge!                  *
+     *                                                                       *
+     *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *
+     *                                                                       *
+     *    Thank you for using FreeRTOS, and thank you for your support!      *
+     *                                                                       *
     ***************************************************************************
 
+
     This file is part of the FreeRTOS distribution.
 
     FreeRTOS is free software; you can redistribute it and/or modify it under
     the terms of the GNU General Public License (version 2) as published by the
     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
-    ***NOTE*** The exception to the GPL is included to allow you to distribute
-    a combined work that includes FreeRTOS without being obliged to provide the
-    source code for proprietary components outside of the FreeRTOS kernel.
-    FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it 
-    can be viewed here: http://www.freertos.org/a00114.html and also obtained 
+    >>>NOTE<<< The modification to the GPL is included to allow you to
+    distribute a combined work that includes FreeRTOS without being obliged to
+    provide the source code for proprietary components outside of the FreeRTOS
+    kernel.  FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it
+    can be viewed here: http://www.freertos.org/a00114.html and also obtained
     by writing to Richard Barry, contact details for whom are available on the
     FreeRTOS WEB site.
 
diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/projdefs.h b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/projdefs.h
old mode 100755
new mode 100644
index 00835ed20..37e432fec
--- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/projdefs.h
+++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/projdefs.h
@@ -1,41 +1,47 @@
 /*
-    FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+    FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+	
+
+	FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+	Atollic AB - Atollic provides professional embedded systems development 
+	tools for C/C++ development, code analysis and test automation.  
+	See http://www.atollic.com
+	
 
     ***************************************************************************
-    *                                                                         *
-    * If you are:                                                             *
-    *                                                                         *
-    *    + New to FreeRTOS,                                                   *
-    *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
-    *    + Looking for basic training,                                        *
-    *    + Wanting to improve your FreeRTOS skills and productivity           *
-    *                                                                         *
-    * then take a look at the FreeRTOS books - available as PDF or paperback  *
-    *                                                                         *
-    *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
-    *                  http://www.FreeRTOS.org/Documentation                  *
-    *                                                                         *
-    * A pdf reference manual is also available.  Both are usually delivered   *
-    * to your inbox within 20 minutes to two hours when purchased between 8am *
-    * and 8pm GMT (although please allow up to 24 hours in case of            *
-    * exceptional circumstances).  Thank you for your support!                *
-    *                                                                         *
+     *                                                                       *
+     *    FreeRTOS tutorial books are available in pdf and paperback.        *
+     *    Complete, revised, and edited pdf reference manuals are also       *
+     *    available.                                                         *
+     *                                                                       *
+     *    Purchasing FreeRTOS documentation will not only help you, by       *
+     *    ensuring you get running as quickly as possible and with an        *
+     *    in-depth knowledge of how to use FreeRTOS, it will also help       *
+     *    the FreeRTOS project to continue with its mission of providing     *
+     *    professional grade, cross platform, de facto standard solutions    *
+     *    for microcontrollers - completely free of charge!                  *
+     *                                                                       *
+     *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *
+     *                                                                       *
+     *    Thank you for using FreeRTOS, and thank you for your support!      *
+     *                                                                       *
     ***************************************************************************
 
+
     This file is part of the FreeRTOS distribution.
 
     FreeRTOS is free software; you can redistribute it and/or modify it under
     the terms of the GNU General Public License (version 2) as published by the
     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
-    ***NOTE*** The exception to the GPL is included to allow you to distribute
-    a combined work that includes FreeRTOS without being obliged to provide the
-    source code for proprietary components outside of the FreeRTOS kernel.
-    FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it 
-    can be viewed here: http://www.freertos.org/a00114.html and also obtained 
+    >>>NOTE<<< The modification to the GPL is included to allow you to
+    distribute a combined work that includes FreeRTOS without being obliged to
+    provide the source code for proprietary components outside of the FreeRTOS
+    kernel.  FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it
+    can be viewed here: http://www.freertos.org/a00114.html and also obtained
     by writing to Richard Barry, contact details for whom are available on the
     FreeRTOS WEB site.
 
diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/queue.h b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/queue.h
old mode 100755
new mode 100644
index 53790f676..47add266f
--- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/queue.h
+++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/queue.h
@@ -1,41 +1,47 @@
 /*
-    FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+    FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+	
+
+	FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
+	Atollic AB - Atollic provides professional embedded systems development 
+	tools for C/C++ development, code analysis and test automation.  
+	See http://www.atollic.com
+	
 
     ***************************************************************************
-    *                                                                         *
-    * If you are:                                                             *
-    *                                                                         *
-    *    + New to FreeRTOS,                                                   *
-    *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
-    *    + Looking for basic training,                                        *
-    *    + Wanting to improve your FreeRTOS skills and productivity           *
-    *                                                                         *
-    * then take a look at the FreeRTOS books - available as PDF or paperback  *
-    *                                                                         *
-    *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
-    *                  http://www.FreeRTOS.org/Documentation                  *
-    *                                                                         *
-    * A pdf reference manual is also available.  Both are usually delivered   *
-    * to your inbox within 20 minutes to two hours when purchased between 8am *
-    * and 8pm GMT (although please allow up to 24 hours in case of            *
-    * exceptional circumstances).  Thank you for your support!                *
-    *                                                                         *
+     *                                                                       *
+     *    FreeRTOS tutorial books are available in pdf and paperback.        *
+     *    Complete, revised, and edited pdf reference manuals are also       *
+     *    available.                                                         *
+     *                                                                       *
+     *    Purchasing FreeRTOS documentation will not only help you, by       *
+     *    ensuring you get running as quickly as possible and with an        *
+     *    in-depth knowledge of how to use FreeRTOS, it will also help       *
+     *    the FreeRTOS project to continue with its mission of providing     *
+     *    professional grade, cross platform, de facto standard solutions    *
+     *    for microcontrollers - completely free of charge!                  *
+     *                                                                       *
+     *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *
+     *                                                                       *
+     *    Thank you for using FreeRTOS, and thank you for your support!      *
+     *                                                                       *
     ***************************************************************************
 
+
     This file is part of the FreeRTOS distribution.
 
     FreeRTOS is free software; you can redistribute it and/or modify it under
     the terms of the GNU General Public License (version 2) as published by the
     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
-    ***NOTE*** The exception to the GPL is included to allow you to distribute
-    a combined work that includes FreeRTOS without being obliged to provide the
-    source code for proprietary components outside of the FreeRTOS kernel.
-    FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it 
-    can be viewed here: http://www.freertos.org/a00114.html and also obtained 
+    >>>NOTE<<< The modification to the GPL is included to allow you to
+    distribute a combined work that includes FreeRTOS without being obliged to
+    provide the source code for proprietary components outside of the FreeRTOS
+    kernel.  FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it
+    can be viewed here: http://www.freertos.org/a00114.html and also obtained
     by writing to Richard Barry, contact details for whom are available on the
     FreeRTOS WEB site.
 
@@ -51,16 +57,14 @@
     licensing and training services.
 */
 
-#ifndef INC_FREERTOS_H
-	#error "#include FreeRTOS.h" must appear in source files before "#include queue.h"
-#endif
-
-
-
 
 #ifndef QUEUE_H
 #define QUEUE_H
 
+#ifndef INC_FREERTOS_H
+	#error "#include FreeRTOS.h" must appear in source files before "#include queue.h"
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -68,7 +72,11 @@ extern "C" {
 
 #include "mpu_wrappers.h"
 
-
+/**
+ * Type by which queues are referenced.  For example, a call to xQueueCreate
+ * returns (via a pointer parameter) an xQueueHandle variable that can then
+ * be used as a parameter to xQueueSend(), xQueueReceive(), etc.
+ */
 typedef void * xQueueHandle;
 
 
@@ -140,7 +148,7 @@ xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBA
  * 
  portBASE_TYPE xQueueSendToToFront(
 								   xQueueHandle	xQueue,
-								   const	void	*	pvItemToQueue,
+								   const void	*	pvItemToQueue,
 								   portTickType	xTicksToWait
 							   );
  * 
@@ -215,7 +223,7 @@ xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBA * \defgroup xQueueSend xQueueSend * \ingroup QueueManagement */ -#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, queueSEND_TO_FRONT ) +#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT ) /** * queue. h @@ -297,7 +305,7 @@ xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBA * \defgroup xQueueSend xQueueSend * \ingroup QueueManagement */ -#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, queueSEND_TO_BACK ) +#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK ) /** * queue. h @@ -381,7 +389,7 @@ xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBA * \defgroup xQueueSend xQueueSend * \ingroup QueueManagement */ -#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, queueSEND_TO_BACK ) +#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK ) /** @@ -469,7 +477,7 @@ xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBA * \defgroup xQueueSend xQueueSend * \ingroup QueueManagement */ -signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ); +signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ); /** * queue. h @@ -563,7 +571,7 @@ signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const * \defgroup xQueueReceive xQueueReceive * \ingroup QueueManagement */ -#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( xQueue, pvBuffer, xTicksToWait, pdTRUE ) +#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE ) /** * queue. h @@ -656,7 +664,7 @@ signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const * \defgroup xQueueReceive xQueueReceive * \ingroup QueueManagement */ -#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( xQueue, pvBuffer, xTicksToWait, pdFALSE ) +#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE ) /** @@ -784,7 +792,7 @@ unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle xQueue ); * \page vQueueDelete vQueueDelete * \ingroup QueueManagement */ -void vQueueDelete( xQueueHandle xQueue ); +void vQueueDelete( xQueueHandle pxQueue ); /** * queue. h @@ -854,7 +862,7 @@ void vQueueDelete( xQueueHandle xQueue ); * \defgroup xQueueSendFromISR xQueueSendFromISR * \ingroup QueueManagement */ -#define xQueueSendToFrontFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken, queueSEND_TO_FRONT ) +#define xQueueSendToFrontFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_FRONT ) /** @@ -925,7 +933,7 @@ void vQueueDelete( xQueueHandle xQueue ); * \defgroup xQueueSendFromISR xQueueSendFromISR * \ingroup QueueManagement */ -#define xQueueSendToBackFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken, queueSEND_TO_BACK ) +#define xQueueSendToBackFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) /** * queue. h @@ -999,7 +1007,7 @@ void vQueueDelete( xQueueHandle xQueue ); * \defgroup xQueueSendFromISR xQueueSendFromISR * \ingroup QueueManagement */ -#define xQueueSendFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken, queueSEND_TO_BACK ) +#define xQueueSendFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) /** * queue. h @@ -1193,10 +1201,10 @@ unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue */ signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ); signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ); -#define xQueueAltSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( xQueue, pvItemToQueue, xTicksToWait, queueSEND_TO_FRONT ) -#define xQueueAltSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( xQueue, pvItemToQueue, xTicksToWait, queueSEND_TO_BACK ) -#define xQueueAltReceive( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( xQueue, pvBuffer, xTicksToWait, pdFALSE ) -#define xQueueAltPeek( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( xQueue, pvBuffer, xTicksToWait, pdTRUE ) +#define xQueueAltSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT ) +#define xQueueAltSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK ) +#define xQueueAltReceive( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE ) +#define xQueueAltPeek( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE ) /* * The functions defined above are for passing data to and from tasks. The @@ -1223,8 +1231,8 @@ xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, * For internal use only. Use xSemaphoreTakeMutexRecursive() or * xSemaphoreGiveMutexRecursive() instead of calling these functions directly. */ -portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle xMutex, portTickType xBlockTime ); -portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle xMutex ); +portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime ); +portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex ); /* * The registry is provided as a means for kernel aware debuggers to @@ -1246,11 +1254,12 @@ portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle xMutex ); * @param pcName The name to be associated with the handle. This is the * name that the kernel aware debugger will display. */ -#if configQUEUE_REGISTRY_SIZE > 0 +#if configQUEUE_REGISTRY_SIZE > 0U void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcName ); #endif - +/* Not a public API function, hence the 'Restricted' in the name. */ +void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait ); #ifdef __cplusplus diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/semphr.h b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/semphr.h old mode 100755 new mode 100644 index 8674096ad..0130f1d79 --- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/semphr.h +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/semphr.h @@ -1,41 +1,47 @@ /* - FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd. + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + + + FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by: + Atollic AB - Atollic provides professional embedded systems development + tools for C/C++ development, code analysis and test automation. + See http://www.atollic.com + *************************************************************************** - * * - * If you are: * - * * - * + New to FreeRTOS, * - * + Wanting to learn FreeRTOS or multitasking in general quickly * - * + Looking for basic training, * - * + Wanting to improve your FreeRTOS skills and productivity * - * * - * then take a look at the FreeRTOS books - available as PDF or paperback * - * * - * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * - * http://www.FreeRTOS.org/Documentation * - * * - * A pdf reference manual is also available. Both are usually delivered * - * to your inbox within 20 minutes to two hours when purchased between 8am * - * and 8pm GMT (although please allow up to 24 hours in case of * - * exceptional circumstances). Thank you for your support! * - * * + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * *************************************************************************** + This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - ***NOTE*** The exception to the GPL is included to allow you to distribute - a combined work that includes FreeRTOS without being obliged to provide the - source code for proprietary components outside of the FreeRTOS kernel. - FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it - can be viewed here: http://www.freertos.org/a00114.html and also obtained + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained by writing to Richard Barry, contact details for whom are available on the FreeRTOS WEB site. @@ -51,20 +57,20 @@ licensing and training services. */ +#ifndef SEMAPHORE_H +#define SEMAPHORE_H + #ifndef INC_FREERTOS_H #error "#include FreeRTOS.h" must appear in source files before "#include semphr.h" #endif -#ifndef SEMAPHORE_H -#define SEMAPHORE_H - #include "queue.h" typedef xQueueHandle xSemaphoreHandle; -#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( unsigned char ) 1 ) -#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( unsigned char ) 0 ) -#define semGIVE_BLOCK_TIME ( ( portTickType ) 0 ) +#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( unsigned char ) 1U ) +#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( unsigned char ) 0U ) +#define semGIVE_BLOCK_TIME ( ( portTickType ) 0U ) /** @@ -105,12 +111,12 @@ typedef xQueueHandle xSemaphoreHandle; * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary * \ingroup Semaphores */ -#define vSemaphoreCreateBinary( xSemaphore ) { \ - xSemaphore = xQueueCreate( ( unsigned portBASE_TYPE ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH ); \ - if( xSemaphore != NULL ) \ - { \ - xSemaphoreGive( xSemaphore ); \ - } \ +#define vSemaphoreCreateBinary( xSemaphore ) { \ + ( xSemaphore ) = xQueueCreate( ( unsigned portBASE_TYPE ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH ); \ + if( ( xSemaphore ) != NULL ) \ + { \ + xSemaphoreGive( ( xSemaphore ) ); \ + } \ } /** @@ -178,7 +184,7 @@ typedef xQueueHandle xSemaphoreHandle; * \defgroup xSemaphoreTake xSemaphoreTake * \ingroup Semaphores */ -#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( xQueueHandle ) xSemaphore, NULL, xBlockTime, pdFALSE ) +#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( xQueueHandle ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE ) /** * semphr. h @@ -271,7 +277,7 @@ typedef xQueueHandle xSemaphoreHandle; * \defgroup xSemaphoreTakeRecursive xSemaphoreTakeRecursive * \ingroup Semaphores */ -#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( xMutex, xBlockTime ) +#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) ) /* @@ -286,7 +292,7 @@ typedef xQueueHandle xSemaphoreHandle; * responsiveness to gain execution speed, whereas the fully featured API * sacrifices execution speed to ensure better interrupt responsiveness. */ -#define xSemaphoreAltTake( xSemaphore, xBlockTime ) xQueueAltGenericReceive( ( xQueueHandle ) xSemaphore, NULL, xBlockTime, pdFALSE ) +#define xSemaphoreAltTake( xSemaphore, xBlockTime ) xQueueAltGenericReceive( ( xQueueHandle ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE ) /** * semphr. h @@ -349,7 +355,7 @@ typedef xQueueHandle xSemaphoreHandle; * \defgroup xSemaphoreGive xSemaphoreGive * \ingroup Semaphores */ -#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( xQueueHandle ) xSemaphore, NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK ) +#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( xQueueHandle ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK ) /** * semphr. h @@ -433,7 +439,7 @@ typedef xQueueHandle xSemaphoreHandle; * \defgroup xSemaphoreGiveRecursive xSemaphoreGiveRecursive * \ingroup Semaphores */ -#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( xMutex ) +#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) ) /* * xSemaphoreAltGive() is an alternative version of xSemaphoreGive(). @@ -447,7 +453,7 @@ typedef xQueueHandle xSemaphoreHandle; * responsiveness to gain execution speed, whereas the fully featured API * sacrifices execution speed to ensure better interrupt responsiveness. */ -#define xSemaphoreAltGive( xSemaphore ) xQueueAltGenericSend( ( xQueueHandle ) xSemaphore, NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK ) +#define xSemaphoreAltGive( xSemaphore ) xQueueAltGenericSend( ( xQueueHandle ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK ) /** * semphr. h @@ -538,7 +544,7 @@ typedef xQueueHandle xSemaphoreHandle; * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR * \ingroup Semaphores */ -#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueueHandle ) xSemaphore, NULL, pxHigherPriorityTaskWoken, queueSEND_TO_BACK ) +#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueueHandle ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) /** * semphr. h @@ -703,7 +709,7 @@ typedef xQueueHandle xSemaphoreHandle; * \defgroup xSemaphoreCreateCounting xSemaphoreCreateCounting * \ingroup Semaphores */ -#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( uxMaxCount, uxInitialCount ) +#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) ) #endif /* SEMAPHORE_H */ diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/task.h b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/task.h old mode 100755 new mode 100644 index cfc1b3d2f..6c476ee00 --- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/task.h +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/task.h @@ -1,38 +1,44 @@ /* - FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd. + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + + + FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by: + Atollic AB - Atollic provides professional embedded systems development + tools for C/C++ development, code analysis and test automation. + See http://www.atollic.com + *************************************************************************** - * * - * If you are: * - * * - * + New to FreeRTOS, * - * + Wanting to learn FreeRTOS or multitasking in general quickly * - * + Looking for basic training, * - * + Wanting to improve your FreeRTOS skills and productivity * - * * - * then take a look at the FreeRTOS books - available as PDF or paperback * - * * - * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * - * http://www.FreeRTOS.org/Documentation * - * * - * A pdf reference manual is also available. Both are usually delivered * - * to your inbox within 20 minutes to two hours when purchased between 8am * - * and 8pm GMT (although please allow up to 24 hours in case of * - * exceptional circumstances). Thank you for your support! * - * * + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * *************************************************************************** + This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - ***NOTE*** The exception to the GPL is included to allow you to distribute - a combined work that includes FreeRTOS without being obliged to provide the - source code for proprietary components outside of the FreeRTOS kernel. - FreeRTOS 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 + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it can be viewed here: http://www.freertos.org/a00114.html and also obtained @@ -52,15 +58,13 @@ */ +#ifndef TASK_H +#define TASK_H + #ifndef INC_FREERTOS_H #error "include FreeRTOS.h must appear in source files before include task.h" #endif - - -#ifndef TASK_H -#define TASK_H - #include "portable.h" #include "list.h" @@ -72,7 +76,7 @@ extern "C" { * MACROS AND DEFINITIONS *----------------------------------------------------------*/ -#define tskKERNEL_VERSION_NUMBER "V6.1.1" +#define tskKERNEL_VERSION_NUMBER "V7.0.1" /** * task. h @@ -124,7 +128,7 @@ typedef struct xTASK_PARAMTERS * * \ingroup TaskUtils */ -#define tskIDLE_PRIORITY ( ( unsigned portBASE_TYPE ) 0 ) +#define tskIDLE_PRIORITY ( ( unsigned portBASE_TYPE ) 0U ) /** * task. h @@ -427,8 +431,7 @@ void vTaskAllocateMPURegions( xTaskHandle xTask, const xMemoryRegion * const pxR * \defgroup vTaskDelete vTaskDelete * \ingroup Tasks */ -void vTaskDelete( xTaskHandle pxTask ) PRIVILEGED_FUNCTION; - +void vTaskDelete( xTaskHandle pxTaskToDelete ) PRIVILEGED_FUNCTION; /*----------------------------------------------------------- * TASK CONTROL API @@ -1103,7 +1106,7 @@ unsigned long ulTaskEndTrace( void ) PRIVILEGED_FUNCTION; * * Returns the high water mark of the stack associated with xTask. That is, * the minimum free stack space there has been (in words, so on a 32 bit machine - * a value of 1 means 4 bytes) since the task started. The smaller the returned + * a value of 1 means 4 bytes) since the task started. The smaller the returned * number the closer the task has come to overflowing its stack. * * @param xTask Handle of the task associated with the stack to be checked. @@ -1126,7 +1129,7 @@ unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask ) PRIVILEG * @return The run time of selected task */ unsigned portBASE_TYPE uxTaskGetRunTime( xTaskHandle xTask ); - + /* When using trace macros it is sometimes necessary to include tasks.h before FreeRTOS.h. When this is done pdTASK_HOOK_CODE will not yet have been defined, so the following two prototypes will cause a compilation error. This can be @@ -1207,6 +1210,21 @@ void vTaskIncrementTick( void ) PRIVILEGED_FUNCTION; */ void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION; +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN + * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED. + * + * This function performs nearly the same function as vTaskPlaceOnEventList(). + * The difference being that this function does not permit tasks to block + * indefinitely, whereas vTaskPlaceOnEventList() does. + * + * @return pdTRUE if the task being removed has a higher priority than the task + * making the call, otherwise pdFALSE. + */ +void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION; + /* * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. @@ -1291,7 +1309,7 @@ void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder ) PRIVILEGED_FUN * Generic version of the task creation function which is in turn called by the * xTaskCreate() and xTaskCreateRestricted() macros. */ -signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pvTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions ) PRIVILEGED_FUNCTION; +signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions ) PRIVILEGED_FUNCTION; #ifdef __cplusplus } diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/timers.h b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/timers.h new file mode 100644 index 000000000..3d78c0ae0 --- /dev/null +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/include/timers.h @@ -0,0 +1,936 @@ +/* + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + + + FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by: + Atollic AB - Atollic provides professional embedded systems development + tools for C/C++ development, code analysis and test automation. + See http://www.atollic.com + + + *************************************************************************** + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * + *************************************************************************** + + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation AND MODIFIED BY the FreeRTOS exception. + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained + by writing to Richard Barry, contact details for whom are available on the + FreeRTOS WEB site. + + 1 tab == 4 spaces! + + http://www.FreeRTOS.org - Documentation, latest information, license and + contact details. + + http://www.SafeRTOS.com - A version that is certified for use in safety + critical systems. + + http://www.OpenRTOS.com - Commercial support, development, porting, + licensing and training services. +*/ + + +#ifndef TIMERS_H +#define TIMERS_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include timers.h" +#endif + +#include "portable.h" +#include "list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* IDs for commands that can be sent/received on the timer queue. These are to +be used solely through the macros that make up the public software timer API, +as defined below. */ +#define tmrCOMMAND_START 0 +#define tmrCOMMAND_STOP 1 +#define tmrCOMMAND_CHANGE_PERIOD 2 +#define tmrCOMMAND_DELETE 3 + +/*----------------------------------------------------------- + * MACROS AND DEFINITIONS + *----------------------------------------------------------*/ + + /** + * Type by which software timers are referenced. For example, a call to + * xTimerCreate() returns an xTimerHandle variable that can then be used to + * reference the subject timer in calls to other software timer API functions + * (for example, xTimerStart(), xTimerReset(), etc.). + */ +typedef void * xTimerHandle; + +/* Define the prototype to which timer callback functions must conform. */ +typedef void (*tmrTIMER_CALLBACK)( xTimerHandle xTimer ); + +/** + * xTimerHandle xTimerCreate( const signed char *pcTimerName, + * portTickType xTimerPeriod, + * unsigned portBASE_TYPE uxAutoReload, + * void * pvTimerID, + * tmrTIMER_CALLBACK pxCallbackFunction ); + * + * Creates a new software timer instance. This allocates the storage required + * by the new timer, initialises the new timers internal state, and returns a + * handle by which the new timer can be referenced. + * + * Timers are created in the dormant state. The xTimerStart(), xTimerReset(), + * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and + * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the + * active state. + * + * @param pcTimerName A text name that is assigned to the timer. This is done + * purely to assist debugging. The kernel itself only ever references a timer by + * its handle, and never by its name. + * + * @param xTimerPeriod The timer period. The time is defined in tick periods so + * the constant portTICK_RATE_MS can be used to convert a time that has been + * specified in milliseconds. For example, if the timer must expire after 100 + * ticks, then xTimerPeriod should be set to 100. Alternatively, if the timer + * must expire after 500ms, then xPeriod can be set to ( 500 / portTICK_RATE_MS ) + * provided configTICK_RATE_HZ is less than or equal to 1000. + * + * @param uxAutoReload If uxAutoReload is set to pdTRUE then the timer will + * expire repeatedly with a frequency set by the xTimerPeriod parameter. If + * uxAutoReload is set to pdFALSE then the timer will be a one-shot timer and + * enter the dormant state after it expires. + * + * @param pvTimerID An identifier that is assigned to the timer being created. + * Typically this would be used in the timer callback function to identify which + * timer expired when the same callback function is assigned to more than one + * timer. + * + * @param pxCallbackFunction The function to call when the timer expires. + * Callback functions must have the prototype defined by tmrTIMER_CALLBACK, + * which is "void vCallbackFunction( xTIMER *xTimer );". + * + * @return If the timer is successfully create then a handle to the newly + * created timer is returned. If the timer cannot be created (because either + * there is insufficient FreeRTOS heap remaining to allocate the timer + * structures, or the timer period was set to 0) then 0 is returned. + * + * Example usage: + * + * + * #define NUM_TIMERS 5 + * + * // An array to hold handles to the created timers. + * xTimerHandle xTimers[ NUM_TIMERS ]; + * + * // An array to hold a count of the number of times each timer expires. + * long lExpireCounters[ NUM_TIMERS ] = { 0 }; + * + * // Define a callback function that will be used by multiple timer instances. + * // The callback function does nothing but count the number of times the + * // associated timer expires, and stop the timer once the timer has expired + * // 10 times. + * void vTimerCallback( xTIMER *pxTimer ) + * { + * long lArrayIndex; + * const long xMaxExpiryCountBeforeStopping = 10; + * + * // Optionally do something if the pxTimer parameter is NULL. + * configASSERT( pxTimer ); + * + * // Which timer expired? + * lArrayIndex = ( long ) pvTimerGetTimerID( pxTimer ); + * + * // Increment the number of times that pxTimer has expired. + * lExpireCounters[ lArrayIndex ] += 1; + * + * // If the timer has expired 10 times then stop it from running. + * if( lExpireCounters[ lArrayIndex ] == xMaxExpiryCountBeforeStopping ) + * { + * // Do not use a block time if calling a timer API function from a + * // timer callback function, as doing so could cause a deadlock! + * xTimerStop( pxTimer, 0 ); + * } + * } + * + * void main( void ) + * { + * long x; + * + * // Create then start some timers. Starting the timers before the scheduler + * // has been started means the timers will start running immediately that + * // the scheduler starts. + * for( x = 0; x < NUM_TIMERS; x++ ) + * { + * xTimers[ x ] = xTimerCreate( "Timer", // Just a text name, not used by the kernel. + * ( 100 * x ), // The timer period in ticks. + * pdTRUE, // The timers will auto-reload themselves when they expire. + * ( void * ) x, // Assign each timer a unique id equal to its array index. + * vTimerCallback // Each timer calls the same callback when it expires. + * ); + * + * if( xTimers[ x ] == NULL ) + * { + * // The timer was not created. + * } + * else + * { + * // Start the timer. No block time is specified, and even if one was + * // it would be ignored because the scheduler has not yet been + * // started. + * if( xTimerStart( xTimers[ x ], 0 ) != pdPASS ) + * { + * // The timer could not be set into the Active state. + * } + * } + * } + * + * // ... + * // Create tasks here. + * // ... + * + * // Starting the scheduler will start the timers running as they have already + * // been set into the active state. + * xTaskStartScheduler(); + * + * // Should not reach here. + * for( ;; ); + * } + */ +xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void * pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction ) PRIVILEGED_FUNCTION; + +/** + * void *pvTimerGetTimerID( xTimerHandle xTimer ); + * + * Returns the ID assigned to the timer. + * + * IDs are assigned to timers using the pvTimerID parameter of the call to + * xTimerCreated() that was used to create the timer. + * + * If the same callback function is assigned to multiple timers then the timer + * ID can be used within the callback function to identify which timer actually + * expired. + * + * @param xTimer The timer being queried. + * + * @return The ID assigned to the timer being queried. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + */ +void *pvTimerGetTimerID( xTimerHandle xTimer ) PRIVILEGED_FUNCTION; + +/** + * portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer ); + * + * Queries a timer to see if it is active or dormant. + * + * A timer will be dormant if: + * 1) It has been created but not started, or + * 2) It is an expired on-shot timer that has not been restarted. + * + * Timers are created in the dormant state. The xTimerStart(), xTimerReset(), + * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and + * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the + * active state. + * + * @param xTimer The timer being queried. + * + * @return pdFALSE will be returned if the timer is dormant. A value other than + * pdFALSE will be returned if the timer is active. + * + * Example usage: + * + * // This function assumes xTimer has already been created. + * void vAFunction( xTimerHandle xTimer ) + * { + * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )" + * { + * // xTimer is active, do something. + * } + * else + * { + * // xTimer is not active, do something else. + * } + * } + */ +portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer ) PRIVILEGED_FUNCTION; + +/** + * portBASE_TYPE xTimerStart( xTimerHandle xTimer, portTickType xBlockTime ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * though a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerStart() starts a timer that was previously created using the + * xTimerCreate() API function. If the timer had already been started and was + * already in the active state, then xTimerStart() has equivalent functionality + * to the xTimerReset() API function. + * + * Starting a timer ensures the timer is in the active state. If the timer + * is not stopped, deleted, or reset in the mean time, the callback function + * associated with the timer will get called 'n' ticks after xTimerStart() was + * called, where 'n' is the timers defined period. + * + * It is valid to call xTimerStart() before the scheduler has been started, but + * when this is done the timer will not actually start until the scheduler is + * started, and the timers expiry time will be relative to when the scheduler is + * started, not relative to when xTimerStart() was called. + * + * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStart() + * to be available. + * + * @param xTimer The handle of the timer being started/restarted. + * + * @param xBlockTime Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the start command to be successfully + * sent to the timer command queue, should the queue already be full when + * xTimerStart() was called. xBlockTime is ignored if xTimerStart() is called + * before the scheduler is started. + * + * @return pdFAIL will be returned if the start command could not be sent to + * the timer command queue even after xBlockTime ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system, although the + * timers expiry time is relative to when xTimerStart() is actually called. The + * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + * + */ +#define xTimerStart( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xBlockTime ) ) + +/** + * portBASE_TYPE xTimerStop( xTimerHandle xTimer, portTickType xBlockTime ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * though a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerStop() stops a timer that was previously started using either of the + * The xTimerStart(), xTimerReset(), xTimerStartFromISR(), xTimerResetFromISR(), + * xTimerChangePeriod() or xTimerChangePeriodFromISR() API functions. + * + * Stopping a timer ensures the timer is not in the active state. + * + * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStop() + * to be available. + * + * @param xTimer The handle of the timer being stopped. + * + * @param xBlockTime Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the stop command to be successfully + * sent to the timer command queue, should the queue already be full when + * xTimerStop() was called. xBlockTime is ignored if xTimerStop() is called + * before the scheduler is started. + * + * @return pdFAIL will be returned if the stop command could not be sent to + * the timer command queue even after xBlockTime ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system. The timer + * service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + * + */ +#define xTimerStop( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0U, NULL, ( xBlockTime ) ) + +/** + * portBASE_TYPE xTimerChangePeriod( xTimerHandle xTimer, + * portTickType xNewPeriod, + * portTickType xBlockTime ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * though a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerChangePeriod() changes the period of a timer that was previously + * created using the xTimerCreate() API function. + * + * xTimerChangePeriod() can be called to change the period of an active or + * dormant state timer. + * + * The configUSE_TIMERS configuration constant must be set to 1 for + * xTimerChangePeriod() to be available. + * + * @param xTimer The handle of the timer that is having its period changed. + * + * @param xNewPeriod The new period for xTimer. Timer periods are specified in + * tick periods, so the constant portTICK_RATE_MS can be used to convert a time + * that has been specified in milliseconds. For example, if the timer must + * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively, + * if the timer must expire after 500ms, then xNewPeriod can be set to + * ( 500 / portTICK_RATE_MS ) provided configTICK_RATE_HZ is less than + * or equal to 1000. + * + * @param xBlockTime Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the change period command to be + * successfully sent to the timer command queue, should the queue already be + * full when xTimerChangePeriod() was called. xBlockTime is ignored if + * xTimerChangePeriod() is called before the scheduler is started. + * + * @return pdFAIL will be returned if the change period command could not be + * sent to the timer command queue even after xBlockTime ticks had passed. + * pdPASS will be returned if the command was successfully sent to the timer + * command queue. When the command is actually processed will depend on the + * priority of the timer service/daemon task relative to other tasks in the + * system. The timer service/daemon task priority is set by the + * configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * + * // This function assumes xTimer has already been created. If the timer + * // referenced by xTimer is already active when it is called, then the timer + * // is deleted. If the timer referenced by xTimer is not active when it is + * // called, then the period of the timer is set to 500ms and the timer is + * // started. + * void vAFunction( xTimerHandle xTimer ) + * { + * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )" + * { + * // xTimer is already active - delete it. + * xTimerDelete( xTimer ); + * } + * else + * { + * // xTimer is not active, change its period to 500ms. This will also + * // cause the timer to start. Block for a maximum of 100 ticks if the + * // change period command cannot immediately be sent to the timer + * // command queue. + * if( xTimerChangePeriod( xTimer, 500 / portTICK_RATE_MS, 100 ) == pdPASS ) + * { + * // The command was successfully sent. + * } + * else + * { + * // The command could not be sent, even after waiting for 100 ticks + * // to pass. Take appropriate action here. + * } + * } + * } + */ + #define xTimerChangePeriod( xTimer, xNewPeriod, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), NULL, ( xBlockTime ) ) + +/** + * portBASE_TYPE xTimerDelete( xTimerHandle xTimer, portTickType xBlockTime ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * though a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerDelete() deletes a timer that was previously created using the + * xTimerCreate() API function. + * + * The configUSE_TIMERS configuration constant must be set to 1 for + * xTimerDelete() to be available. + * + * @param xTimer The handle of the timer being deleted. + * + * @param xBlockTime Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the delete command to be + * successfully sent to the timer command queue, should the queue already be + * full when xTimerDelete() was called. xBlockTime is ignored if xTimerDelete() + * is called before the scheduler is started. + * + * @return pdFAIL will be returned if the delete command could not be sent to + * the timer command queue even after xBlockTime ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system. The timer + * service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * + * See the xTimerChangePeriod() API function example usage scenario. + */ +#define xTimerDelete( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_DELETE, 0U, NULL, ( xBlockTime ) ) + +/** + * portBASE_TYPE xTimerReset( xTimerHandle xTimer, portTickType xBlockTime ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * though a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerReset() re-starts a timer that was previously created using the + * xTimerCreate() API function. If the timer had already been started and was + * already in the active state, then xTimerReset() will cause the timer to + * re-evaluate its expiry time so that it is relative to when xTimerReset() was + * called. If the timer was in the dormant state then xTimerReset() has + * equivalent functionality to the xTimerStart() API function. + * + * Resetting a timer ensures the timer is in the active state. If the timer + * is not stopped, deleted, or reset in the mean time, the callback function + * associated with the timer will get called 'n' ticks after xTimerReset() was + * called, where 'n' is the timers defined period. + * + * It is valid to call xTimerReset() before the scheduler has been started, but + * when this is done the timer will not actually start until the scheduler is + * started, and the timers expiry time will be relative to when the scheduler is + * started, not relative to when xTimerReset() was called. + * + * The configUSE_TIMERS configuration constant must be set to 1 for xTimerReset() + * to be available. + * + * @param xTimer The handle of the timer being reset/started/restarted. + * + * @param xBlockTime Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the reset command to be successfully + * sent to the timer command queue, should the queue already be full when + * xTimerReset() was called. xBlockTime is ignored if xTimerReset() is called + * before the scheduler is started. + * + * @return pdFAIL will be returned if the reset command could not be sent to + * the timer command queue even after xBlockTime ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system, although the + * timers expiry time is relative to when xTimerStart() is actually called. The + * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * + * // When a key is pressed, an LCD back-light is switched on. If 5 seconds pass + * // without a key being pressed, then the LCD back-light is switched off. In + * // this case, the timer is a one-shot timer. + * + * xTimerHandle xBacklightTimer = NULL; + * + * // The callback function assigned to the one-shot timer. In this case the + * // parameter is not used. + * void vBacklightTimerCallback( xTIMER *pxTimer ) + * { + * // The timer expired, therefore 5 seconds must have passed since a key + * // was pressed. Switch off the LCD back-light. + * vSetBacklightState( BACKLIGHT_OFF ); + * } + * + * // The key press event handler. + * void vKeyPressEventHandler( char cKey ) + * { + * // Ensure the LCD back-light is on, then reset the timer that is + * // responsible for turning the back-light off after 5 seconds of + * // key inactivity. Wait 10 ticks for the command to be successfully sent + * // if it cannot be sent immediately. + * vSetBacklightState( BACKLIGHT_ON ); + * if( xTimerReset( xBacklightTimer, 100 ) != pdPASS ) + * { + * // The reset command was not executed successfully. Take appropriate + * // action here. + * } + * + * // Perform the rest of the key processing here. + * } + * + * void main( void ) + * { + * long x; + * + * // Create then start the one-shot timer that is responsible for turning + * // the back-light off if no keys are pressed within a 5 second period. + * xBacklightTimer = xTimerCreate( "BacklightTimer", // Just a text name, not used by the kernel. + * ( 5000 / portTICK_RATE_MS), // The timer period in ticks. + * pdFALSE, // The timer is a one-shot timer. + * 0, // The id is not used by the callback so can take any value. + * vBacklightTimerCallback // The callback function that switches the LCD back-light off. + * ); + * + * if( xBacklightTimer == NULL ) + * { + * // The timer was not created. + * } + * else + * { + * // Start the timer. No block time is specified, and even if one was + * // it would be ignored because the scheduler has not yet been + * // started. + * if( xTimerStart( xBacklightTimer, 0 ) != pdPASS ) + * { + * // The timer could not be set into the Active state. + * } + * } + * + * // ... + * // Create tasks here. + * // ... + * + * // Starting the scheduler will start the timer running as it has already + * // been set into the active state. + * xTaskStartScheduler(); + * + * // Should not reach here. + * for( ;; ); + * } + */ +#define xTimerReset( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xBlockTime ) ) + +/** + * portBASE_TYPE xTimerStartFromISR( xTimerHandle xTimer, + * portBASE_TYPE *pxHigherPriorityTaskWoken ); + * + * A version of xTimerStart() that can be called from an interrupt service + * routine. + * + * @param xTimer The handle of the timer being started/restarted. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerStartFromISR() writes a message to the timer + * command queue, so has the potential to transition the timer service/daemon + * task out of the Blocked state. If calling xTimerStartFromISR() causes the + * timer service/daemon task to leave the Blocked state, and the timer service/ + * daemon task has a priority equal to or greater than the currently executing + * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will + * get set to pdTRUE internally within the xTimerStartFromISR() function. If + * xTimerStartFromISR() sets this value to pdTRUE then a context switch should + * be performed before the interrupt exits. + * + * @return pdFAIL will be returned if the start command could not be sent to + * the timer command queue. pdPASS will be returned if the command was + * successfully sent to the timer command queue. When the command is actually + * processed will depend on the priority of the timer service/daemon task + * relative to other tasks in the system, although the timers expiry time is + * relative to when xTimerStartFromISR() is actually called. The timer service/daemon + * task priority is set by the configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * + * // This scenario assumes xBacklightTimer has already been created. When a + * // key is pressed, an LCD back-light is switched on. If 5 seconds pass + * // without a key being pressed, then the LCD back-light is switched off. In + * // this case, the timer is a one-shot timer, and unlike the example given for + * // the xTimerReset() function, the key press event handler is an interrupt + * // service routine. + * + * // The callback function assigned to the one-shot timer. In this case the + * // parameter is not used. + * void vBacklightTimerCallback( xTIMER *pxTimer ) + * { + * // The timer expired, therefore 5 seconds must have passed since a key + * // was pressed. Switch off the LCD back-light. + * vSetBacklightState( BACKLIGHT_OFF ); + * } + * + * // The key press interrupt service routine. + * void vKeyPressEventInterruptHandler( void ) + * { + * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + * + * // Ensure the LCD back-light is on, then restart the timer that is + * // responsible for turning the back-light off after 5 seconds of + * // key inactivity. This is an interrupt service routine so can only + * // call FreeRTOS API functions that end in "FromISR". + * vSetBacklightState( BACKLIGHT_ON ); + * + * // xTimerStartFromISR() or xTimerResetFromISR() could be called here + * // as both cause the timer to re-calculate its expiry time. + * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was + * // declared (in this function). + * if( xTimerStartFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The start command was not executed successfully. Take appropriate + * // action here. + * } + * + * // Perform the rest of the key processing here. + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used. + * } + * } + */ +#define xTimerStartFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U ) + +/** + * portBASE_TYPE xTimerStopFromISR( xTimerHandle xTimer, + * portBASE_TYPE *pxHigherPriorityTaskWoken ); + * + * A version of xTimerStop() that can be called from an interrupt service + * routine. + * + * @param xTimer The handle of the timer being stopped. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerStopFromISR() writes a message to the timer + * command queue, so has the potential to transition the timer service/daemon + * task out of the Blocked state. If calling xTimerStopFromISR() causes the + * timer service/daemon task to leave the Blocked state, and the timer service/ + * daemon task has a priority equal to or greater than the currently executing + * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will + * get set to pdTRUE internally within the xTimerStopFromISR() function. If + * xTimerStopFromISR() sets this value to pdTRUE then a context switch should + * be performed before the interrupt exits. + * + * @return pdFAIL will be returned if the stop command could not be sent to + * the timer command queue. pdPASS will be returned if the command was + * successfully sent to the timer command queue. When the command is actually + * processed will depend on the priority of the timer service/daemon task + * relative to other tasks in the system. The timer service/daemon task + * priority is set by the configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * + * // This scenario assumes xTimer has already been created and started. When + * // an interrupt occurs, the timer should be simply stopped. + * + * // The interrupt service routine that stops the timer. + * void vAnExampleInterruptServiceRoutine( void ) + * { + * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + * + * // The interrupt has occurred - simply stop the timer. + * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined + * // (within this function). As this is an interrupt service routine, only + * // FreeRTOS API functions that end in "FromISR" can be used. + * if( xTimerStopFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The stop command was not executed successfully. Take appropriate + * // action here. + * } + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used. + * } + * } + */ +#define xTimerStopFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0, ( pxHigherPriorityTaskWoken ), 0U ) + +/** + * portBASE_TYPE xTimerChangePeriodFromISR( xTimerHandle xTimer, + * portTickType xNewPeriod, + * portBASE_TYPE *pxHigherPriorityTaskWoken ); + * + * A version of xTimerChangePeriod() that can be called from an interrupt + * service routine. + * + * @param xTimer The handle of the timer that is having its period changed. + * + * @param xNewPeriod The new period for xTimer. Timer periods are specified in + * tick periods, so the constant portTICK_RATE_MS can be used to convert a time + * that has been specified in milliseconds. For example, if the timer must + * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively, + * if the timer must expire after 500ms, then xNewPeriod can be set to + * ( 500 / portTICK_RATE_MS ) provided configTICK_RATE_HZ is less than + * or equal to 1000. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerChangePeriodFromISR() writes a message to the + * timer command queue, so has the potential to transition the timer service/ + * daemon task out of the Blocked state. If calling xTimerChangePeriodFromISR() + * causes the timer service/daemon task to leave the Blocked state, and the + * timer service/daemon task has a priority equal to or greater than the + * currently executing task (the task that was interrupted), then + * *pxHigherPriorityTaskWoken will get set to pdTRUE internally within the + * xTimerChangePeriodFromISR() function. If xTimerChangePeriodFromISR() sets + * this value to pdTRUE then a context switch should be performed before the + * interrupt exits. + * + * @return pdFAIL will be returned if the command to change the timers period + * could not be sent to the timer command queue. pdPASS will be returned if the + * command was successfully sent to the timer command queue. When the command + * is actually processed will depend on the priority of the timer service/daemon + * task relative to other tasks in the system. The timer service/daemon task + * priority is set by the configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * + * // This scenario assumes xTimer has already been created and started. When + * // an interrupt occurs, the period of xTimer should be changed to 500ms. + * + * // The interrupt service routine that changes the period of xTimer. + * void vAnExampleInterruptServiceRoutine( void ) + * { + * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + * + * // The interrupt has occurred - change the period of xTimer to 500ms. + * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined + * // (within this function). As this is an interrupt service routine, only + * // FreeRTOS API functions that end in "FromISR" can be used. + * if( xTimerChangePeriodFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The command to change the timers period was not executed + * // successfully. Take appropriate action here. + * } + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used. + * } + * } + */ +#define xTimerChangePeriodFromISR( xTimer, xNewPeriod, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), ( pxHigherPriorityTaskWoken ), 0U ) + +/** + * portBASE_TYPE xTimerResetFromISR( xTimerHandle xTimer, + * portBASE_TYPE *pxHigherPriorityTaskWoken ); + * + * A version of xTimerReset() that can be called from an interrupt service + * routine. + * + * @param xTimer The handle of the timer that is to be started, reset, or + * restarted. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerResetFromISR() writes a message to the timer + * command queue, so has the potential to transition the timer service/daemon + * task out of the Blocked state. If calling xTimerResetFromISR() causes the + * timer service/daemon task to leave the Blocked state, and the timer service/ + * daemon task has a priority equal to or greater than the currently executing + * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will + * get set to pdTRUE internally within the xTimerResetFromISR() function. If + * xTimerResetFromISR() sets this value to pdTRUE then a context switch should + * be performed before the interrupt exits. + * + * @return pdFAIL will be returned if the reset command could not be sent to + * the timer command queue. pdPASS will be returned if the command was + * successfully sent to the timer command queue. When the command is actually + * processed will depend on the priority of the timer service/daemon task + * relative to other tasks in the system, although the timers expiry time is + * relative to when xTimerResetFromISR() is actually called. The timer service/daemon + * task priority is set by the configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * + * // This scenario assumes xBacklightTimer has already been created. When a + * // key is pressed, an LCD back-light is switched on. If 5 seconds pass + * // without a key being pressed, then the LCD back-light is switched off. In + * // this case, the timer is a one-shot timer, and unlike the example given for + * // the xTimerReset() function, the key press event handler is an interrupt + * // service routine. + * + * // The callback function assigned to the one-shot timer. In this case the + * // parameter is not used. + * void vBacklightTimerCallback( xTIMER *pxTimer ) + * { + * // The timer expired, therefore 5 seconds must have passed since a key + * // was pressed. Switch off the LCD back-light. + * vSetBacklightState( BACKLIGHT_OFF ); + * } + * + * // The key press interrupt service routine. + * void vKeyPressEventInterruptHandler( void ) + * { + * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + * + * // Ensure the LCD back-light is on, then reset the timer that is + * // responsible for turning the back-light off after 5 seconds of + * // key inactivity. This is an interrupt service routine so can only + * // call FreeRTOS API functions that end in "FromISR". + * vSetBacklightState( BACKLIGHT_ON ); + * + * // xTimerStartFromISR() or xTimerResetFromISR() could be called here + * // as both cause the timer to re-calculate its expiry time. + * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was + * // declared (in this function). + * if( xTimerResetFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The reset command was not executed successfully. Take appropriate + * // action here. + * } + * + * // Perform the rest of the key processing here. + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used. + * } + * } + */ +#define xTimerResetFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U ) + +/* + * Functions beyond this part are not part of the public API and are intended + * for use by the kernel only. + */ +portBASE_TYPE xTimerCreateTimerTask( void ) PRIVILEGED_FUNCTION; +portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime ) PRIVILEGED_FUNCTION; + +#ifdef __cplusplus +} +#endif +#endif /* TIMERS_H */ + + + diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/list.c b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/list.c old mode 100755 new mode 100644 index a800c030a..c3ef2a89d --- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/list.c +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/list.c @@ -1,41 +1,47 @@ /* - FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd. + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + + + FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by: + Atollic AB - Atollic provides professional embedded systems development + tools for C/C++ development, code analysis and test automation. + See http://www.atollic.com + *************************************************************************** - * * - * If you are: * - * * - * + New to FreeRTOS, * - * + Wanting to learn FreeRTOS or multitasking in general quickly * - * + Looking for basic training, * - * + Wanting to improve your FreeRTOS skills and productivity * - * * - * then take a look at the FreeRTOS books - available as PDF or paperback * - * * - * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * - * http://www.FreeRTOS.org/Documentation * - * * - * A pdf reference manual is also available. Both are usually delivered * - * to your inbox within 20 minutes to two hours when purchased between 8am * - * and 8pm GMT (although please allow up to 24 hours in case of * - * exceptional circumstances). Thank you for your support! * - * * + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * *************************************************************************** + This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - ***NOTE*** The exception to the GPL is included to allow you to distribute - a combined work that includes FreeRTOS without being obliged to provide the - source code for proprietary components outside of the FreeRTOS kernel. - FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it - can be viewed here: http://www.freertos.org/a00114.html and also obtained + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained by writing to Richard Barry, contact details for whom are available on the FreeRTOS WEB site. @@ -76,7 +82,7 @@ void vListInitialise( xList *pxList ) pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd ); pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd ); - pxList->uxNumberOfItems = 0; + pxList->uxNumberOfItems = ( unsigned portBASE_TYPE ) 0U; } /*-----------------------------------------------------------*/ @@ -121,9 +127,9 @@ portTickType xValueOfInsertion; /* If the list already contains a list item with the same item value then the new list item should be placed after it. This ensures that TCB's which are stored in ready lists (all of which have the same ulListItem value) - get an equal share of the CPU. However, if the xItemValue is the same as + get an equal share of the CPU. However, if the xItemValue is the same as the back marker the iteration loop below will not end. This means we need - to guard against this by checking the value first and modifying the + to guard against this by checking the value first and modifying the algorithm slightly if necessary. */ if( xValueOfInsertion == portMAX_DELAY ) { @@ -133,18 +139,18 @@ portTickType xValueOfInsertion; { /* *** NOTE *********************************************************** If you find your application is crashing here then likely causes are: - 1) Stack overflow - + 1) Stack overflow - see http://www.freertos.org/Stacks-and-stack-overflow-checking.html - 2) Incorrect interrupt priority assignment, especially on Cortex M3 - parts where numerically high priority values denote low actual - interrupt priories, which can seem counter intuitive. See + 2) Incorrect interrupt priority assignment, especially on Cortex-M3 + parts where numerically high priority values denote low actual + interrupt priories, which can seem counter intuitive. See configMAX_SYSCALL_INTERRUPT_PRIORITY on http://www.freertos.org/a00110.html 3) Calling an API function from within a critical section or when the scheduler is suspended. 4) Using a queue or semaphore before it has been initialised or before the scheduler has been started (are interrupts firing before vTaskStartScheduler() has been called?). - See http://www.freertos.org/FAQHelp.html for more tips. + See http://www.freertos.org/FAQHelp.html for more tips. **********************************************************************/ for( pxIterator = ( xListItem * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c old mode 100755 new mode 100644 index fa24c7ff5..70c74912a --- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c @@ -1,41 +1,41 @@ /* - FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd. + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + *************************************************************************** - * * - * If you are: * - * * - * + New to FreeRTOS, * - * + Wanting to learn FreeRTOS or multitasking in general quickly * - * + Looking for basic training, * - * + Wanting to improve your FreeRTOS skills and productivity * - * * - * then take a look at the FreeRTOS books - available as PDF or paperback * - * * - * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * - * http://www.FreeRTOS.org/Documentation * - * * - * A pdf reference manual is also available. Both are usually delivered * - * to your inbox within 20 minutes to two hours when purchased between 8am * - * and 8pm GMT (although please allow up to 24 hours in case of * - * exceptional circumstances). Thank you for your support! * - * * + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * *************************************************************************** + This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - ***NOTE*** The exception to the GPL is included to allow you to distribute - a combined work that includes FreeRTOS without being obliged to provide the - source code for proprietary components outside of the FreeRTOS kernel. - FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it - can be viewed here: http://www.freertos.org/a00114.html and also obtained + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained by writing to Richard Barry, contact details for whom are available on the FreeRTOS WEB site. diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h old mode 100755 new mode 100644 index 81839c07f..c2860d1e9 --- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h @@ -1,41 +1,41 @@ /* - FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd. + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + *************************************************************************** - * * - * If you are: * - * * - * + New to FreeRTOS, * - * + Wanting to learn FreeRTOS or multitasking in general quickly * - * + Looking for basic training, * - * + Wanting to improve your FreeRTOS skills and productivity * - * * - * then take a look at the FreeRTOS books - available as PDF or paperback * - * * - * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * - * http://www.FreeRTOS.org/Documentation * - * * - * A pdf reference manual is also available. Both are usually delivered * - * to your inbox within 20 minutes to two hours when purchased between 8am * - * and 8pm GMT (although please allow up to 24 hours in case of * - * exceptional circumstances). Thank you for your support! * - * * + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * *************************************************************************** + This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - ***NOTE*** The exception to the GPL is included to allow you to distribute - a combined work that includes FreeRTOS without being obliged to provide the - source code for proprietary components outside of the FreeRTOS kernel. - FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it - can be viewed here: http://www.freertos.org/a00114.html and also obtained + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained by writing to Richard Barry, contact details for whom are available on the FreeRTOS WEB site. @@ -138,9 +138,9 @@ extern void vPortYieldFromISR( void ); extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); -void PIOS_RTC_Start(); +void PIOS_RTC_Init(); uint32_t PIOS_RTC_Counter(); - + #define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK() #define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK() #define portENTER_CRITICAL() vPortEnterCritical() diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/MemMang/heap_1.c b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/MemMang/heap_1.c old mode 100755 new mode 100644 index 70a6bb172..f3abbb52c --- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/MemMang/heap_1.c +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/MemMang/heap_1.c @@ -1,41 +1,41 @@ /* - FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd. + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + *************************************************************************** - * * - * If you are: * - * * - * + New to FreeRTOS, * - * + Wanting to learn FreeRTOS or multitasking in general quickly * - * + Looking for basic training, * - * + Wanting to improve your FreeRTOS skills and productivity * - * * - * then take a look at the FreeRTOS books - available as PDF or paperback * - * * - * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * - * http://www.FreeRTOS.org/Documentation * - * * - * A pdf reference manual is also available. Both are usually delivered * - * to your inbox within 20 minutes to two hours when purchased between 8am * - * and 8pm GMT (although please allow up to 24 hours in case of * - * exceptional circumstances). Thank you for your support! * - * * + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * *************************************************************************** + This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - ***NOTE*** The exception to the GPL is included to allow you to distribute - a combined work that includes FreeRTOS without being obliged to provide the - source code for proprietary components outside of the FreeRTOS kernel. - FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it - can be viewed here: http://www.freertos.org/a00114.html and also obtained + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained by writing to Richard Barry, contact details for whom are available on the FreeRTOS WEB site. @@ -79,16 +79,18 @@ static union xRTOS_HEAP volatile portDOUBLE dDummy; #else volatile unsigned long ulDummy; - #endif + #endif unsigned char ucHeap[ configTOTAL_HEAP_SIZE ]; -} xHeap; +} xHeap __attribute__ ((section (".heap"))); static size_t xNextFreeByte = ( size_t ) 0; +static size_t currentTOTAL_HEAP_SIZE = configTOTAL_HEAP_SIZE; + /*-----------------------------------------------------------*/ void *pvPortMalloc( size_t xWantedSize ) { -void *pvReturn = NULL; +void *pvReturn = NULL; /* Ensure that blocks are always aligned to the required number of bytes. */ #if portBYTE_ALIGNMENT != 1 @@ -102,17 +104,17 @@ void *pvReturn = NULL; vTaskSuspendAll(); { /* Check there is enough room left for the allocation. */ - if( ( ( xNextFreeByte + xWantedSize ) < configTOTAL_HEAP_SIZE ) && + if( ( ( xNextFreeByte + xWantedSize ) < currentTOTAL_HEAP_SIZE ) && ( ( xNextFreeByte + xWantedSize ) > xNextFreeByte ) )/* Check for overflow. */ { /* Return the next free byte then increment the index past this block. */ pvReturn = &( xHeap.ucHeap[ xNextFreeByte ] ); - xNextFreeByte += xWantedSize; - } + xNextFreeByte += xWantedSize; + } } xTaskResumeAll(); - + #if( configUSE_MALLOC_FAILED_HOOK == 1 ) { if( pvReturn == NULL ) @@ -121,7 +123,7 @@ void *pvReturn = NULL; vApplicationMallocFailedHook(); } } - #endif + #endif return pvReturn; } @@ -129,8 +131,8 @@ void *pvReturn = NULL; void vPortFree( void *pv ) { - /* Memory cannot be freed using this scheme. See heap_2.c and heap_3.c - for alternative implementations, and the memory management pages of + /* Memory cannot be freed using this scheme. See heap_2.c and heap_3.c + for alternative implementations, and the memory management pages of http://www.FreeRTOS.org for more information. */ ( void ) pv; } @@ -145,8 +147,14 @@ void vPortInitialiseBlocks( void ) size_t xPortGetFreeHeapSize( void ) { - return ( configTOTAL_HEAP_SIZE - xNextFreeByte ); + return ( currentTOTAL_HEAP_SIZE - xNextFreeByte ); } +/*-----------------------------------------------------------*/ - - +void xPortIncreaseHeapSize( size_t bytes ) +{ + vTaskSuspendAll(); + currentTOTAL_HEAP_SIZE = configTOTAL_HEAP_SIZE + bytes; + xTaskResumeAll(); +} +/*-----------------------------------------------------------*/ diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/MemMang/heap_2.c b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/MemMang/heap_2.c old mode 100755 new mode 100644 index 9f8de5cd2..91258edd6 --- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/MemMang/heap_2.c +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/MemMang/heap_2.c @@ -1,41 +1,41 @@ /* - FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd. + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + *************************************************************************** - * * - * If you are: * - * * - * + New to FreeRTOS, * - * + Wanting to learn FreeRTOS or multitasking in general quickly * - * + Looking for basic training, * - * + Wanting to improve your FreeRTOS skills and productivity * - * * - * then take a look at the FreeRTOS books - available as PDF or paperback * - * * - * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * - * http://www.FreeRTOS.org/Documentation * - * * - * A pdf reference manual is also available. Both are usually delivered * - * to your inbox within 20 minutes to two hours when purchased between 8am * - * and 8pm GMT (although please allow up to 24 hours in case of * - * exceptional circumstances). Thank you for your support! * - * * + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * *************************************************************************** + This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - ***NOTE*** The exception to the GPL is included to allow you to distribute - a combined work that includes FreeRTOS without being obliged to provide the - source code for proprietary components outside of the FreeRTOS kernel. - FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it - can be viewed here: http://www.freertos.org/a00114.html and also obtained + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained by writing to Richard Barry, contact details for whom are available on the FreeRTOS WEB site. @@ -81,7 +81,7 @@ static union xRTOS_HEAP volatile unsigned long ulDummy; #endif unsigned char ucHeap[ configTOTAL_HEAP_SIZE ]; -} xHeap; +} xHeap __attribute__ ((section (".heap"))); /* Define the linked list structure. This is used to link free blocks in order of their size. */ @@ -101,6 +101,7 @@ static xBlockLink xStart, xEnd; /* Keeps track of the number of free bytes remaining, but says nothing about fragmentation. */ static size_t xFreeBytesRemaining = configTOTAL_HEAP_SIZE; +static size_t currentTOTAL_HEAP_SIZE = configTOTAL_HEAP_SIZE; /* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */ @@ -140,13 +141,13 @@ xBlockLink *pxFirstFreeBlock; \ xStart.xBlockSize = ( size_t ) 0; \ \ /* xEnd is used to mark the end of the list of free blocks. */ \ - xEnd.xBlockSize = configTOTAL_HEAP_SIZE; \ + xEnd.xBlockSize = currentTOTAL_HEAP_SIZE; \ xEnd.pxNextFreeBlock = NULL; \ \ /* To start with there is a single free block that is sized to take up the \ entire heap space. */ \ pxFirstFreeBlock = ( void * ) xHeap.ucHeap; \ - pxFirstFreeBlock->xBlockSize = configTOTAL_HEAP_SIZE; \ + pxFirstFreeBlock->xBlockSize = currentTOTAL_HEAP_SIZE; \ pxFirstFreeBlock->pxNextFreeBlock = &xEnd; \ } /*-----------------------------------------------------------*/ @@ -181,7 +182,7 @@ void *pvReturn = NULL; } } - if( ( xWantedSize > 0 ) && ( xWantedSize < configTOTAL_HEAP_SIZE ) ) + if( ( xWantedSize > 0 ) && ( xWantedSize < currentTOTAL_HEAP_SIZE ) ) { /* Blocks are stored in byte order - traverse the list from the start (smallest) block until one of adequate size is found. */ @@ -220,7 +221,7 @@ void *pvReturn = NULL; /* Insert the new block into the list of free blocks. */ prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); } - + xFreeBytesRemaining -= pxBlock->xBlockSize; } } @@ -276,3 +277,18 @@ void vPortInitialiseBlocks( void ) { /* This just exists to keep the linker quiet. */ } + +void xPortIncreaseHeapSize( size_t bytes ) +{ + xBlockLink *pxNewBlockLink; + vTaskSuspendAll(); + currentTOTAL_HEAP_SIZE = configTOTAL_HEAP_SIZE + bytes; + xEnd.xBlockSize = currentTOTAL_HEAP_SIZE; + xFreeBytesRemaining += bytes; + /* Insert the new block into the list of free blocks. */ + pxNewBlockLink = ( void * ) &xHeap.ucHeap[ configTOTAL_HEAP_SIZE ]; + pxNewBlockLink->xBlockSize = bytes; + prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); + xTaskResumeAll(); +} +/*-----------------------------------------------------------*/ diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/MemMang/heap_3.c b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/MemMang/heap_3.c old mode 100755 new mode 100644 index 7ff9bb515..fa799a0c2 --- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/MemMang/heap_3.c +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/portable/MemMang/heap_3.c @@ -1,41 +1,41 @@ /* - FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd. + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + *************************************************************************** - * * - * If you are: * - * * - * + New to FreeRTOS, * - * + Wanting to learn FreeRTOS or multitasking in general quickly * - * + Looking for basic training, * - * + Wanting to improve your FreeRTOS skills and productivity * - * * - * then take a look at the FreeRTOS books - available as PDF or paperback * - * * - * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * - * http://www.FreeRTOS.org/Documentation * - * * - * A pdf reference manual is also available. Both are usually delivered * - * to your inbox within 20 minutes to two hours when purchased between 8am * - * and 8pm GMT (although please allow up to 24 hours in case of * - * exceptional circumstances). Thank you for your support! * - * * + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * *************************************************************************** + This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - ***NOTE*** The exception to the GPL is included to allow you to distribute - a combined work that includes FreeRTOS without being obliged to provide the - source code for proprietary components outside of the FreeRTOS kernel. - FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it - can be viewed here: http://www.freertos.org/a00114.html and also obtained + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained by writing to Richard Barry, contact details for whom are available on the FreeRTOS WEB site. diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/queue.c b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/queue.c old mode 100755 new mode 100644 index a62d179e9..2ae7c7030 --- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/queue.c +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/queue.c @@ -1,41 +1,47 @@ /* - FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd. + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + + + FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by: + Atollic AB - Atollic provides professional embedded systems development + tools for C/C++ development, code analysis and test automation. + See http://www.atollic.com + *************************************************************************** - * * - * If you are: * - * * - * + New to FreeRTOS, * - * + Wanting to learn FreeRTOS or multitasking in general quickly * - * + Looking for basic training, * - * + Wanting to improve your FreeRTOS skills and productivity * - * * - * then take a look at the FreeRTOS books - available as PDF or paperback * - * * - * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * - * http://www.FreeRTOS.org/Documentation * - * * - * A pdf reference manual is also available. Both are usually delivered * - * to your inbox within 20 minutes to two hours when purchased between 8am * - * and 8pm GMT (although please allow up to 24 hours in case of * - * exceptional circumstances). Thank you for your support! * - * * + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * *************************************************************************** + This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - ***NOTE*** The exception to the GPL is included to allow you to distribute - a combined work that includes FreeRTOS without being obliged to provide the - source code for proprietary components outside of the FreeRTOS kernel. - FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it - can be viewed here: http://www.freertos.org/a00114.html and also obtained + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained by writing to Richard Barry, contact details for whom are available on the FreeRTOS WEB site. @@ -144,6 +150,7 @@ signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; +void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION; /* * Co-routine queue functions differ from task queue functions. Co-routines are @@ -222,21 +229,19 @@ static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer ) * Macro to mark a queue as locked. Locking a queue prevents an ISR from * accessing the queue event lists. */ -#define prvLockQueue( pxQueue ) \ -{ \ - taskENTER_CRITICAL(); \ - { \ - if( pxQueue->xRxLock == queueUNLOCKED ) \ - { \ - pxQueue->xRxLock = queueLOCKED_UNMODIFIED; \ - } \ - if( pxQueue->xTxLock == queueUNLOCKED ) \ - { \ - pxQueue->xTxLock = queueLOCKED_UNMODIFIED; \ - } \ - } \ - taskEXIT_CRITICAL(); \ -} +#define prvLockQueue( pxQueue ) \ + taskENTER_CRITICAL(); \ + { \ + if( ( pxQueue )->xRxLock == queueUNLOCKED ) \ + { \ + ( pxQueue )->xRxLock = queueLOCKED_UNMODIFIED; \ + } \ + if( ( pxQueue )->xTxLock == queueUNLOCKED ) \ + { \ + ( pxQueue )->xTxLock = queueLOCKED_UNMODIFIED; \ + } \ + } \ + taskEXIT_CRITICAL() /*-----------------------------------------------------------*/ @@ -248,6 +253,7 @@ xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBA { xQUEUE *pxNewQueue; size_t xQueueSizeInBytes; +xQueueHandle xReturn = NULL; /* Allocate the new queue structure. */ if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 ) @@ -265,9 +271,9 @@ size_t xQueueSizeInBytes; /* Initialise the queue members as described above where the queue type is defined. */ pxNewQueue->pcTail = pxNewQueue->pcHead + ( uxQueueLength * uxItemSize ); - pxNewQueue->uxMessagesWaiting = 0; + pxNewQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U; pxNewQueue->pcWriteTo = pxNewQueue->pcHead; - pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - 1 ) * uxItemSize ); + pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - ( unsigned portBASE_TYPE ) 1U ) * uxItemSize ); pxNewQueue->uxLength = uxQueueLength; pxNewQueue->uxItemSize = uxItemSize; pxNewQueue->xRxLock = queueUNLOCKED; @@ -278,7 +284,7 @@ size_t xQueueSizeInBytes; vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) ); traceQUEUE_CREATE( pxNewQueue ); - return pxNewQueue; + xReturn = pxNewQueue; } else { @@ -288,9 +294,9 @@ size_t xQueueSizeInBytes; } } - /* Will only reach here if we could not allocate enough memory or no memory - was required. */ - return NULL; + configASSERT( xReturn ); + + return xReturn; } /*-----------------------------------------------------------*/ @@ -316,9 +322,9 @@ size_t xQueueSizeInBytes; /* Each mutex has a length of 1 (like a binary semaphore) and an item size of 0 as nothing is actually copied into or out of the mutex. */ - pxNewQueue->uxMessagesWaiting = 0; - pxNewQueue->uxLength = 1; - pxNewQueue->uxItemSize = 0; + pxNewQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U; + pxNewQueue->uxLength = ( unsigned portBASE_TYPE ) 1U; + pxNewQueue->uxItemSize = ( unsigned portBASE_TYPE ) 0U; pxNewQueue->xRxLock = queueUNLOCKED; pxNewQueue->xTxLock = queueUNLOCKED; @@ -327,7 +333,7 @@ size_t xQueueSizeInBytes; vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) ); /* Start with the semaphore in the expected state. */ - xQueueGenericSend( pxNewQueue, NULL, 0, queueSEND_TO_BACK ); + xQueueGenericSend( pxNewQueue, NULL, ( portTickType ) 0U, queueSEND_TO_BACK ); traceCREATE_MUTEX( pxNewQueue ); } @@ -336,6 +342,7 @@ size_t xQueueSizeInBytes; traceCREATE_MUTEX_FAILED(); } + configASSERT( pxNewQueue ); return pxNewQueue; } @@ -348,6 +355,8 @@ size_t xQueueSizeInBytes; { portBASE_TYPE xReturn; + configASSERT( pxMutex ); + /* If this is the task that holds the mutex then pxMutexHolder will not change outside of this task. If this task does not hold the mutex then pxMutexHolder can never coincidentally equal the tasks handle, and as @@ -395,6 +404,8 @@ size_t xQueueSizeInBytes; { portBASE_TYPE xReturn; + configASSERT( pxMutex ); + /* Comments regarding mutual exclusion as per those within xQueueGiveMutexRecursive(). */ @@ -446,6 +457,7 @@ size_t xQueueSizeInBytes; traceCREATE_COUNTING_SEMAPHORE_FAILED(); } + configASSERT( pxHandle ); return pxHandle; } @@ -457,6 +469,9 @@ signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const signed portBASE_TYPE xEntryTimeSet = pdFALSE; xTimeOutType xTimeOut; + configASSERT( pxQueue ); + configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); + /* This function relaxes the coding standard somewhat to allow return statements within the function itself. This is done in the interest of execution time efficiency. */ @@ -575,6 +590,9 @@ xTimeOutType xTimeOut; signed portBASE_TYPE xEntryTimeSet = pdFALSE; xTimeOutType xTimeOut; + configASSERT( pxQueue ); + configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); + for( ;; ) { taskENTER_CRITICAL(); @@ -650,6 +668,9 @@ xTimeOutType xTimeOut; xTimeOutType xTimeOut; signed char *pcOriginalReadPosition; + configASSERT( pxQueue ); + configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); + for( ;; ) { taskENTER_CRITICAL(); @@ -697,7 +718,7 @@ xTimeOutType xTimeOut; /* The data is being left in the queue, so see if there are any other tasks waiting for the data. */ - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { /* Tasks that are removed from the event list will get added to the pending ready list as the scheduler is still suspended. */ @@ -773,6 +794,10 @@ signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void signed portBASE_TYPE xReturn; unsigned portBASE_TYPE uxSavedInterruptStatus; + configASSERT( pxQueue ); + configASSERT( pxHigherPriorityTaskWoken ); + configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); + /* Similar to xQueueGenericSend, except we don't block if there is no room in the queue. Also we don't directly wake a task that was blocked on a queue read, instead we return a flag to say whether a context switch is @@ -790,7 +815,7 @@ unsigned portBASE_TYPE uxSavedInterruptStatus; be done when the queue is unlocked later. */ if( pxQueue->xTxLock == queueUNLOCKED ) { - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { @@ -827,6 +852,9 @@ signed portBASE_TYPE xEntryTimeSet = pdFALSE; xTimeOutType xTimeOut; signed char *pcOriginalReadPosition; + configASSERT( pxQueue ); + configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); + /* This function relaxes the coding standard somewhat to allow return statements within the function itself. This is done in the interest of execution time efficiency. */ @@ -880,7 +908,7 @@ signed char *pcOriginalReadPosition; /* The data is being left in the queue, so see if there are any other tasks waiting for the data. */ - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { /* Tasks that are removed from the event list will get added to the pending ready list as the scheduler is still suspended. */ @@ -973,6 +1001,10 @@ signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pv signed portBASE_TYPE xReturn; unsigned portBASE_TYPE uxSavedInterruptStatus; + configASSERT( pxQueue ); + configASSERT( pxTaskWoken ); + configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) ); + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); { /* We cannot block from an ISR, so check there is data available. */ @@ -988,7 +1020,7 @@ unsigned portBASE_TYPE uxSavedInterruptStatus; that an ISR has removed data while the queue was locked. */ if( pxQueue->xRxLock == queueUNLOCKED ) { - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { @@ -1023,6 +1055,8 @@ unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue ) { unsigned portBASE_TYPE uxReturn; + configASSERT( pxQueue ); + taskENTER_CRITICAL(); uxReturn = pxQueue->uxMessagesWaiting; taskEXIT_CRITICAL(); @@ -1035,6 +1069,8 @@ unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue { unsigned portBASE_TYPE uxReturn; + configASSERT( pxQueue ); + uxReturn = pxQueue->uxMessagesWaiting; return uxReturn; @@ -1043,6 +1079,8 @@ unsigned portBASE_TYPE uxReturn; void vQueueDelete( xQueueHandle pxQueue ) { + configASSERT( pxQueue ); + traceQUEUE_DELETE( pxQueue ); vQueueUnregisterQueue( pxQueue ); vPortFree( pxQueue->pcHead ); @@ -1117,7 +1155,7 @@ static void prvUnlockQueue( xQueueHandle pxQueue ) { /* Data was posted while the queue was locked. Are any tasks blocked waiting for data to become available? */ - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { /* Tasks that are removed from the event list will get added to the pending ready list as the scheduler is still suspended. */ @@ -1145,7 +1183,7 @@ static void prvUnlockQueue( xQueueHandle pxQueue ) { while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED ) { - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { @@ -1182,6 +1220,7 @@ signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue ) { signed portBASE_TYPE xReturn; + configASSERT( pxQueue ); xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 ); return xReturn; @@ -1204,6 +1243,7 @@ signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue ) { signed portBASE_TYPE xReturn; + configASSERT( pxQueue ); xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength ); return xReturn; @@ -1252,7 +1292,7 @@ signed portBASE_TYPE xReturn; xReturn = pdPASS; /* Were any co-routines waiting for data to become available? */ - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { /* In this instance the co-routine could be placed directly into the ready list as we are within a critical section. @@ -1327,7 +1367,7 @@ signed portBASE_TYPE xReturn; xReturn = pdPASS; /* Were any co-routines waiting for space to become available? */ - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { /* In this instance the co-routine could be placed directly into the ready list as we are within a critical section. @@ -1366,7 +1406,7 @@ signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvIt co-routine has not already been woken. */ if( !xCoRoutinePreviouslyWoken ) { - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { @@ -1401,7 +1441,7 @@ signed portBASE_TYPE xReturn; if( !( *pxCoRoutineWoken ) ) { - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { @@ -1430,7 +1470,7 @@ signed portBASE_TYPE xReturn; /* See if there is an empty space in the registry. A NULL name denotes a free slot. */ - for( ux = 0; ux < configQUEUE_REGISTRY_SIZE; ux++ ) + for( ux = ( unsigned portBASE_TYPE ) 0U; ux < configQUEUE_REGISTRY_SIZE; ux++ ) { if( xQueueRegistry[ ux ].pcQueueName == NULL ) { @@ -1443,7 +1483,7 @@ signed portBASE_TYPE xReturn; } #endif - /*-----------------------------------------------------------*/ +/*-----------------------------------------------------------*/ #if configQUEUE_REGISTRY_SIZE > 0 @@ -1453,7 +1493,7 @@ signed portBASE_TYPE xReturn; /* See if the handle of the queue being unregistered in actually in the registry. */ - for( ux = 0; ux < configQUEUE_REGISTRY_SIZE; ux++ ) + for( ux = ( unsigned portBASE_TYPE ) 0U; ux < configQUEUE_REGISTRY_SIZE; ux++ ) { if( xQueueRegistry[ ux ].xHandle == xQueue ) { @@ -1466,4 +1506,34 @@ signed portBASE_TYPE xReturn; } #endif +/*-----------------------------------------------------------*/ + +#if configUSE_TIMERS == 1 + + void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait ) + { + /* This function should not be called by application code hence the + 'Restricted' in its name. It is not part of the public API. It is + designed for use by kernel code, and has special calling requirements. + It can result in vListInsert() being called on a list that can only + possibly ever have one item in it, so the list will be fast, but even + so it should be called with the scheduler locked and not from a critical + section. */ + + /* Only do anything if there are no messages in the queue. This function + will not actually cause the task to block, just place it on a blocked + list. It will not block until the scheduler is unlocked - at which + time a yield will be performed. If an item is added to the queue while + the queue is locked, and the calling task blocks on the queue, then the + calling task will be immediately unblocked when the queue is unlocked. */ + prvLockQueue( pxQueue ); + if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0U ) + { + /* There is nothing in the queue, block for the specified period. */ + vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); + } + prvUnlockQueue( pxQueue ); + } + +#endif diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/tasks.c b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/tasks.c old mode 100755 new mode 100644 index 85089740a..865d5e9db --- a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/tasks.c +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/tasks.c @@ -1,38 +1,44 @@ /* - FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd. + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + + + FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by: + Atollic AB - Atollic provides professional embedded systems development + tools for C/C++ development, code analysis and test automation. + See http://www.atollic.com + *************************************************************************** - * * - * If you are: * - * * - * + New to FreeRTOS, * - * + Wanting to learn FreeRTOS or multitasking in general quickly * - * + Looking for basic training, * - * + Wanting to improve your FreeRTOS skills and productivity * - * * - * then take a look at the FreeRTOS books - available as PDF or paperback * - * * - * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * - * http://www.FreeRTOS.org/Documentation * - * * - * A pdf reference manual is also available. Both are usually delivered * - * to your inbox within 20 minutes to two hours when purchased between 8am * - * and 8pm GMT (although please allow up to 24 hours in case of * - * exceptional circumstances). Thank you for your support! * - * * + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * *************************************************************************** + This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. - ***NOTE*** The exception to the GPL is included to allow you to distribute - a combined work that includes FreeRTOS without being obliged to provide the - source code for proprietary components outside of the FreeRTOS kernel. - FreeRTOS 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 + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it can be viewed here: http://www.freertos.org/a00114.html and also obtained @@ -63,6 +69,7 @@ task.h is included from an application file. */ #include "FreeRTOS.h" #include "task.h" +#include "timers.h" #include "StackMacros.h" #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE @@ -161,6 +168,7 @@ PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxMissedTicks = ( unsi PRIVILEGED_DATA static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE; PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0; PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0; +PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType ) portMAX_DELAY; #if ( configGENERATE_RUN_TIME_STATS == 1 ) @@ -176,7 +184,7 @@ PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned po * The value used to fill the stack of a task when the task is created. This * is used purely for checking the high water mark for tasks. */ -#define tskSTACK_FILL_BYTE ( 0xa5 ) +#define tskSTACK_FILL_BYTE ( 0xa5U ) /* * Macros used by vListTask to indicate which state a task is in. @@ -196,7 +204,7 @@ PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned po PRIVILEGED_DATA static signed char *pcTraceBufferStart; PRIVILEGED_DATA static signed char *pcTraceBufferEnd; PRIVILEGED_DATA static signed portBASE_TYPE xTracing = pdFALSE; - static unsigned portBASE_TYPE uxPreviousTask = 255; + static unsigned portBASE_TYPE uxPreviousTask = 255U; PRIVILEGED_DATA static char pcStatusString[ 50 ]; #endif @@ -220,10 +228,10 @@ PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned po if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \ { \ uxPreviousTask = pxCurrentTCB->uxTCBNumber; \ - *( unsigned long * ) pcTraceBuffer = ( unsigned long ) xTickCount; \ - pcTraceBuffer += sizeof( unsigned long ); \ - *( unsigned long * ) pcTraceBuffer = ( unsigned long ) uxPreviousTask; \ - pcTraceBuffer += sizeof( unsigned long ); \ + *( unsigned long * ) pcTraceBuffer = ( unsigned long ) xTickCount; \ + pcTraceBuffer += sizeof( unsigned long ); \ + *( unsigned long * ) pcTraceBuffer = ( unsigned long ) uxPreviousTask; \ + pcTraceBuffer += sizeof( unsigned long ); \ } \ else \ { \ @@ -247,14 +255,12 @@ PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned po * executing task, then it will only be rescheduled after the currently * executing task has been rescheduled. */ -#define prvAddTaskToReadyQueue( pxTCB ) \ -{ \ - if( pxTCB->uxPriority > uxTopReadyPriority ) \ - { \ - uxTopReadyPriority = pxTCB->uxPriority; \ - } \ - vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ); \ -} +#define prvAddTaskToReadyQueue( pxTCB ) \ + if( ( pxTCB )->uxPriority > uxTopReadyPriority ) \ + { \ + uxTopReadyPriority = ( pxTCB )->uxPriority; \ + } \ + vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) ) /*-----------------------------------------------------------*/ /* @@ -265,24 +271,56 @@ PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned po * once one tasks has been found whose timer has not expired we need not look * any further down the list. */ -#define prvCheckDelayedTasks() \ -{ \ -register tskTCB *pxTCB; \ - \ - while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL ) \ - { \ - if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) ) \ - { \ - break; \ - } \ - vListRemove( &( pxTCB->xGenericListItem ) ); \ - /* Is the task waiting on an event also? */ \ - if( pxTCB->xEventListItem.pvContainer ) \ - { \ - vListRemove( &( pxTCB->xEventListItem ) ); \ - } \ - prvAddTaskToReadyQueue( pxTCB ); \ - } \ +#define prvCheckDelayedTasks() \ +{ \ +portTickType xItemValue; \ + \ + /* Is the tick count greater than or equal to the wake time of the first \ + task referenced from the delayed tasks list? */ \ + if( xTickCount >= xNextTaskUnblockTime ) \ + { \ + for( ;; ) \ + { \ + if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) \ + { \ + /* The delayed list is empty. Set xNextTaskUnblockTime to the \ + maximum possible value so it is extremely unlikely that the \ + if( xTickCount >= xNextTaskUnblockTime ) test will pass next \ + time through. */ \ + xNextTaskUnblockTime = portMAX_DELAY; \ + break; \ + } \ + else \ + { \ + /* The delayed list is not empty, get the value of the item at \ + the head of the delayed list. This is the time at which the \ + task at the head of the delayed list should be removed from \ + the Blocked state. */ \ + pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); \ + xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); \ + \ + if( xTickCount < xItemValue ) \ + { \ + /* It is not time to unblock this item yet, but the item \ + value is the time at which the task at the head of the \ + blocked list should be removed from the Blocked state - \ + so record the item value in xNextTaskUnblockTime. */ \ + xNextTaskUnblockTime = xItemValue; \ + break; \ + } \ + \ + /* It is time to remove the item from the Blocked state. */ \ + vListRemove( &( pxTCB->xGenericListItem ) ); \ + \ + /* Is the task waiting on an event also? */ \ + if( pxTCB->xEventListItem.pvContainer ) \ + { \ + vListRemove( &( pxTCB->xEventListItem ) ); \ + } \ + prvAddTaskToReadyQueue( pxTCB ); \ + } \ + } \ + } \ } /*-----------------------------------------------------------*/ @@ -292,9 +330,12 @@ register tskTCB *pxTCB; \ * task should be used in place of the parameter. This macro simply checks to * see if the parameter is NULL and returns a pointer to the appropriate TCB. */ -#define prvGetTCBFromHandle( pxHandle ) ( ( pxHandle == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) pxHandle ) - +#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) ( pxHandle ) ) +/* Callback function prototypes. --------------------------*/ +extern void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName ); +extern void vApplicationTickHook( void ); + /* File private functions. --------------------------------*/ /* @@ -342,6 +383,12 @@ static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ); */ static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION; +/* + * The currently executing task is entering the Blocked state. Add the task to + * either the current or the overflow delayed task list. + */ +static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) PRIVILEGED_FUNCTION; + /* * Allocates memory from the heap for a TCB and associated stack. Checks the * allocation was successful. @@ -388,6 +435,9 @@ signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed ch signed portBASE_TYPE xReturn; tskTCB * pxNewTCB; + configASSERT( pxTaskCode ); + configASSERT( ( uxPriority < configMAX_PRIORITIES ) ); + /* Allocate the memory required by the TCB and stack for the new task, checking that the allocation was successful. */ pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer ); @@ -416,12 +466,18 @@ tskTCB * pxNewTCB; required by the port. */ #if( portSTACK_GROWTH < 0 ) { - pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 ); + pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 ); pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( unsigned long ) pxTopOfStack ) & ( ( unsigned long ) ~portBYTE_ALIGNMENT_MASK ) ); + + /* Check the alignment of the calculated top of stack is correct. */ + configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); } #else { pxTopOfStack = pxNewTCB->pxStack; + + /* Check the alignment of the stack buffer is correct. */ + configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); /* If we want to use stack checking on architectures that use a positive stack growth direction then we also need to store the @@ -447,6 +503,9 @@ tskTCB * pxNewTCB; } #endif + /* Check the alignment of the initialised stack. */ + configASSERT( ( ( ( unsigned long ) pxNewTCB->pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + if( ( void * ) pxCreatedTask != NULL ) { /* Pass the TCB out - in an anonymous way. The calling function/ @@ -457,7 +516,7 @@ tskTCB * pxNewTCB; /* We are going to manipulate the task queues to add this task to a ready list, so must make sure no interrupts occur. */ - portENTER_CRITICAL(); + taskENTER_CRITICAL(); { uxCurrentNumberOfTasks++; if( pxCurrentTCB == NULL ) @@ -508,7 +567,7 @@ tskTCB * pxNewTCB; xReturn = pdPASS; traceTASK_CREATE( pxNewTCB ); } - portEXIT_CRITICAL(); + taskEXIT_CRITICAL(); } else { @@ -539,7 +598,7 @@ tskTCB * pxNewTCB; { tskTCB *pxTCB; - portENTER_CRITICAL(); + taskENTER_CRITICAL(); { /* Ensure a yield is performed if the current task is being deleted. */ @@ -576,7 +635,7 @@ tskTCB * pxNewTCB; traceTASK_DELETE( pxTCB ); } - portEXIT_CRITICAL(); + taskEXIT_CRITICAL(); /* Force a reschedule if we have just deleted the current task. */ if( xSchedulerRunning != pdFALSE ) @@ -606,6 +665,9 @@ tskTCB * pxNewTCB; portTickType xTimeToWake; portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE; + configASSERT( pxPreviousWakeTime ); + configASSERT( ( xTimeIncrement > 0 ) ); + vTaskSuspendAll(); { /* Generate the tick time at which the task wants to wake. */ @@ -637,7 +699,7 @@ tskTCB * pxNewTCB; /* Update the wake time ready for the next call. */ *pxPreviousWakeTime = xTimeToWake; - if( xShouldDelay ) + if( xShouldDelay != pdFALSE ) { traceTASK_DELAY_UNTIL(); @@ -645,22 +707,7 @@ tskTCB * pxNewTCB; ourselves to the blocked list as the same list item is used for both lists. */ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - - /* The list item will be inserted in wake time order. */ - listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake ); - - if( xTimeToWake < xTickCount ) - { - /* Wake time has overflowed. Place this item in the - overflow list. */ - vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } - else - { - /* The wake time has not overflowed, so we can use the - current block list. */ - vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } + prvAddCurrentTaskToDelayedList( xTimeToWake ); } } xAlreadyYielded = xTaskResumeAll(); @@ -706,22 +753,7 @@ tskTCB * pxNewTCB; ourselves to the blocked list as the same list item is used for both lists. */ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - - /* The list item will be inserted in wake time order. */ - listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake ); - - if( xTimeToWake < xTickCount ) - { - /* Wake time has overflowed. Place this item in the - overflow list. */ - vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } - else - { - /* The wake time has not overflowed, so we can use the - current block list. */ - vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } + prvAddCurrentTaskToDelayedList( xTimeToWake ); } xAlreadyYielded = xTaskResumeAll(); } @@ -744,14 +776,14 @@ tskTCB * pxNewTCB; tskTCB *pxTCB; unsigned portBASE_TYPE uxReturn; - portENTER_CRITICAL(); + taskENTER_CRITICAL(); { /* If null is passed in here then we are changing the priority of the calling function. */ pxTCB = prvGetTCBFromHandle( pxTask ); uxReturn = pxTCB->uxPriority; } - portEXIT_CRITICAL(); + taskEXIT_CRITICAL(); return uxReturn; } @@ -764,15 +796,18 @@ tskTCB * pxNewTCB; void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority ) { tskTCB *pxTCB; - unsigned portBASE_TYPE uxCurrentPriority, xYieldRequired = pdFALSE; + unsigned portBASE_TYPE uxCurrentPriority; + portBASE_TYPE xYieldRequired = pdFALSE; + + configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) ); /* Ensure the new priority is valid. */ if( uxNewPriority >= configMAX_PRIORITIES ) { - uxNewPriority = configMAX_PRIORITIES - 1; + uxNewPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U; } - portENTER_CRITICAL(); + taskENTER_CRITICAL(); { if( pxTask == pxCurrentTCB ) { @@ -858,7 +893,7 @@ tskTCB * pxNewTCB; } } } - portEXIT_CRITICAL(); + taskEXIT_CRITICAL(); } #endif @@ -870,7 +905,7 @@ tskTCB * pxNewTCB; { tskTCB *pxTCB; - portENTER_CRITICAL(); + taskENTER_CRITICAL(); { /* Ensure a yield is performed if the current task is being suspended. */ @@ -895,7 +930,7 @@ tskTCB * pxNewTCB; vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ); } - portEXIT_CRITICAL(); + taskEXIT_CRITICAL(); if( ( void * ) pxTaskToSuspend == NULL ) { @@ -909,9 +944,9 @@ tskTCB * pxNewTCB; /* The scheduler is not running, but the task that was pointed to by pxCurrentTCB has just been suspended and pxCurrentTCB must be adjusted to point to a different task. */ - if( uxCurrentNumberOfTasks == 1 ) + if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) { - /* No other tasks are defined, so set pxCurrentTCB back to + /* No other tasks are ready, so set pxCurrentTCB back to NULL so when the next task is created pxCurrentTCB will be set to point to it no matter what its relative priority is. */ @@ -935,6 +970,9 @@ tskTCB * pxNewTCB; portBASE_TYPE xReturn = pdFALSE; const tskTCB * const pxTCB = ( tskTCB * ) xTask; + /* It does not make sense to check if the calling task is suspended. */ + configASSERT( xTask ); + /* Is the task we are attempting to resume actually in the suspended list? */ if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE ) @@ -965,6 +1003,9 @@ tskTCB * pxNewTCB; { tskTCB *pxTCB; + /* It does not make sense to resume the calling task. */ + configASSERT( pxTaskToResume ); + /* Remove the task from whichever list it is currently in, and place it in the ready list. */ pxTCB = ( tskTCB * ) pxTaskToResume; @@ -973,7 +1014,7 @@ tskTCB * pxNewTCB; currently executing task. */ if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) ) { - portENTER_CRITICAL(); + taskENTER_CRITICAL(); { if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE ) { @@ -993,7 +1034,7 @@ tskTCB * pxNewTCB; } } } - portEXIT_CRITICAL(); + taskEXIT_CRITICAL(); } } @@ -1008,6 +1049,8 @@ tskTCB * pxNewTCB; portBASE_TYPE xYieldRequired = pdFALSE; tskTCB *pxTCB; + configASSERT( pxTaskToResume ); + pxTCB = ( tskTCB * ) pxTaskToResume; if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE ) @@ -1049,6 +1092,15 @@ portBASE_TYPE xReturn; /* Add the idle task at the lowest priority. */ xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), ( xTaskHandle * ) NULL ); + #if ( configUSE_TIMERS == 1 ) + { + if( xReturn == pdPASS ) + { + xReturn = xTimerCreateTimerTask(); + } + } + #endif + if( xReturn == pdPASS ) { /* Interrupts are turned off here, to ensure a tick does not occur @@ -1081,6 +1133,9 @@ portBASE_TYPE xReturn; /* Should only reach here if a task calls xTaskEndScheduler(). */ } } + + /* This line will only be reached if the kernel could not be started. */ + configASSERT( xReturn ); } /*-----------------------------------------------------------*/ @@ -1108,12 +1163,16 @@ signed portBASE_TYPE xTaskResumeAll( void ) register tskTCB *pxTCB; signed portBASE_TYPE xAlreadyYielded = pdFALSE; + /* If uxSchedulerSuspended is zero then this function does not match a + previous call to vTaskSuspendAll(). */ + configASSERT( uxSchedulerSuspended ); + /* It is possible that an ISR caused a task to be removed from an event list while the scheduler was suspended. If this was the case then the removed task will have been added to the xPendingReadyList. Once the scheduler has been resumed it is safe to move all the pending ready tasks from this list into their appropriate ready list. */ - portENTER_CRITICAL(); + taskENTER_CRITICAL(); { --uxSchedulerSuspended; @@ -1125,8 +1184,9 @@ signed portBASE_TYPE xAlreadyYielded = pdFALSE; /* Move any readied tasks from the pending list into the appropriate ready list. */ - while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) ) ) != NULL ) + while( listLIST_IS_EMPTY( ( xList * ) &xPendingReadyList ) == pdFALSE ) { + pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) ); vListRemove( &( pxTCB->xEventListItem ) ); vListRemove( &( pxTCB->xGenericListItem ) ); prvAddTaskToReadyQueue( pxTCB ); @@ -1169,7 +1229,7 @@ signed portBASE_TYPE xAlreadyYielded = pdFALSE; } } } - portEXIT_CRITICAL(); + taskEXIT_CRITICAL(); return xAlreadyYielded; } @@ -1190,11 +1250,11 @@ portTickType xTaskGetTickCount( void ) portTickType xTicks; /* Critical section required if running on a 16 bit processor. */ - portENTER_CRITICAL(); + taskENTER_CRITICAL(); { xTicks = xTickCount; } - portEXIT_CRITICAL(); + taskEXIT_CRITICAL(); return xTicks; } @@ -1202,7 +1262,14 @@ portTickType xTicks; portTickType xTaskGetTickCountFromISR( void ) { - return xTickCount; +portTickType xReturn; +unsigned portBASE_TYPE uxSavedInterruptStatus; + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + xReturn = xTickCount; + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; } /*-----------------------------------------------------------*/ @@ -1228,34 +1295,34 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) /* Run through all the lists that could potentially contain a TCB and report the task name, state and stack high water mark. */ - pcWriteBuffer[ 0 ] = ( signed char ) 0x00; + *pcWriteBuffer = ( signed char ) 0x00; strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" ); - uxQueue = uxTopUsedPriority + 1; + uxQueue = uxTopUsedPriority + ( unsigned portBASE_TYPE ) 1U; do { uxQueue--; - if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) ) + if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) == pdFALSE ) { prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR ); } }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY ); - if( !listLIST_IS_EMPTY( pxDelayedTaskList ) ) + if( listLIST_IS_EMPTY( pxDelayedTaskList ) == pdFALSE ) { prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR ); } - if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) ) + if( listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) == pdFALSE ) { prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR ); } #if( INCLUDE_vTaskDelete == 1 ) { - if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) ) + if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE ) { prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR ); } @@ -1264,7 +1331,7 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) #if ( INCLUDE_vTaskSuspend == 1 ) { - if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) ) + if( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE ) { prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR ); } @@ -1303,34 +1370,34 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) generating a table of run timer percentages in the provided buffer. */ - pcWriteBuffer[ 0 ] = ( signed char ) 0x00; + *pcWriteBuffer = ( signed char ) 0x00; strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" ); - uxQueue = uxTopUsedPriority + 1; + uxQueue = uxTopUsedPriority + ( unsigned portBASE_TYPE ) 1U; do { uxQueue--; - if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) ) + if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) == pdFALSE ) { prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTime ); } }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY ); - if( !listLIST_IS_EMPTY( pxDelayedTaskList ) ) + if( listLIST_IS_EMPTY( pxDelayedTaskList ) == pdFALSE ) { prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTime ); } - if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) ) + if( listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) == pdFALSE ) { prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTime ); } #if ( INCLUDE_vTaskDelete == 1 ) { - if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) ) + if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE ) { prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, ulTotalRunTime ); } @@ -1339,7 +1406,7 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) #if ( INCLUDE_vTaskSuspend == 1 ) { - if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) ) + if( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE ) { prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, ulTotalRunTime ); } @@ -1356,14 +1423,17 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) void vTaskStartTrace( signed char * pcBuffer, unsigned long ulBufferSize ) { - portENTER_CRITICAL(); + configASSERT( pcBuffer ); + configASSERT( ulBufferSize ); + + taskENTER_CRITICAL(); { pcTraceBuffer = ( signed char * )pcBuffer; pcTraceBufferStart = pcBuffer; pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE ); xTracing = pdTRUE; } - portEXIT_CRITICAL(); + taskEXIT_CRITICAL(); } #endif @@ -1375,9 +1445,9 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) { unsigned long ulBufferLength; - portENTER_CRITICAL(); + taskENTER_CRITICAL(); xTracing = pdFALSE; - portEXIT_CRITICAL(); + taskEXIT_CRITICAL(); ulBufferLength = ( unsigned long ) ( pcTraceBuffer - pcTraceBufferStart ); @@ -1396,6 +1466,8 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) void vTaskIncrementTick( void ) { +tskTCB * pxTCB; + /* Called by the portable layer each time a tick interrupt occurs. Increments the tick then checks to see if the new tick value will cause any tasks to be unblocked. */ @@ -1409,10 +1481,31 @@ void vTaskIncrementTick( void ) /* Tick count has overflowed so we need to swap the delay lists. If there are any items in pxDelayedTaskList here then there is an error! */ + configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); + pxTemp = pxDelayedTaskList; pxDelayedTaskList = pxOverflowDelayedTaskList; pxOverflowDelayedTaskList = pxTemp; xNumOfOverflows++; + + if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) + { + /* The new current delayed list is empty. Set + xNextTaskUnblockTime to the maximum possible value so it is + extremely unlikely that the + if( xTickCount >= xNextTaskUnblockTime ) test will pass until + there is an item in the delayed list. */ + xNextTaskUnblockTime = portMAX_DELAY; + } + else + { + /* The new current delayed list is not empty, get the value of + the item at the head of the delayed list. This is the time at + which the task at the head of the delayed list should be removed + from the Blocked state. */ + pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); + xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); + } } /* See if this tick has made a timeout expire. */ @@ -1426,8 +1519,6 @@ void vTaskIncrementTick( void ) scheduler is locked. */ #if ( configUSE_TICK_HOOK == 1 ) { - extern void vApplicationTickHook( void ); - vApplicationTickHook(); } #endif @@ -1435,11 +1526,9 @@ void vTaskIncrementTick( void ) #if ( configUSE_TICK_HOOK == 1 ) { - extern void vApplicationTickHook( void ); - /* Guard against the tick hook being called when the missed tick count is being unwound (when the scheduler is being unlocked. */ - if( uxMissedTicks == 0 ) + if( uxMissedTicks == ( unsigned portBASE_TYPE ) 0U ) { vApplicationTickHook(); } @@ -1464,7 +1553,7 @@ void vTaskIncrementTick( void ) { usQueue--; - while( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) ) + while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) == pdFALSE ) { listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) ); vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ); @@ -1474,7 +1563,7 @@ void vTaskIncrementTick( void ) }while( usQueue > ( unsigned short ) tskIDLE_PRIORITY ); /* Remove any TCB's from the delayed queue. */ - while( !listLIST_IS_EMPTY( &xDelayedTaskList1 ) ) + while( listLIST_IS_EMPTY( &xDelayedTaskList1 ) == pdFALSE ) { listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 ); vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ); @@ -1483,7 +1572,7 @@ void vTaskIncrementTick( void ) } /* Remove any TCB's from the overflow delayed queue. */ - while( !listLIST_IS_EMPTY( &xDelayedTaskList2 ) ) + while( listLIST_IS_EMPTY( &xDelayedTaskList2 ) == pdFALSE ) { listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 ); vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ); @@ -1491,7 +1580,7 @@ void vTaskIncrementTick( void ) prvDeleteTCB( ( tskTCB * ) pxTCB ); } - while( !listLIST_IS_EMPTY( &xSuspendedTaskList ) ) + while( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE ) { listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList ); vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ); @@ -1505,7 +1594,7 @@ void vTaskIncrementTick( void ) #if ( configUSE_APPLICATION_TASK_TAG == 1 ) - void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxTagValue ) + void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction ) { tskTCB *xTCB; @@ -1521,9 +1610,9 @@ void vTaskIncrementTick( void ) /* Save the hook function in the TCB. A critical section is required as the value can be accessed from an interrupt. */ - portENTER_CRITICAL(); - xTCB->pxTaskTag = pxTagValue; - portEXIT_CRITICAL(); + taskENTER_CRITICAL(); + xTCB->pxTaskTag = pxHookFunction; + taskEXIT_CRITICAL(); } #endif @@ -1548,9 +1637,9 @@ void vTaskIncrementTick( void ) /* Save the hook function in the TCB. A critical section is required as the value can be accessed from an interrupt. */ - portENTER_CRITICAL(); + taskENTER_CRITICAL(); xReturn = xTCB->pxTaskTag; - portEXIT_CRITICAL(); + taskEXIT_CRITICAL(); return xReturn; } @@ -1597,46 +1686,48 @@ void vTaskSwitchContext( void ) /* The scheduler is currently suspended - do not allow a context switch. */ xMissedYield = pdTRUE; - return; } - - traceTASK_SWITCHED_OUT(); - - #if ( configGENERATE_RUN_TIME_STATS == 1 ) + else { - unsigned long ulTempCounter; - - #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE - portALT_GET_RUN_TIME_COUNTER_VALUE( ulTempCounter ); - #else - ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE(); - #endif - - /* Add the amount of time the task has been running to the accumulated - time so far. The time the task started running was stored in - ulTaskSwitchedInTime. Note that there is no overflow protection here - so count values are only valid until the timer overflows. Generally - this will be about 1 hour assuming a 1uS timer increment. */ - pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime ); - ulTaskSwitchedInTime = ulTempCounter; + traceTASK_SWITCHED_OUT(); + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + unsigned long ulTempCounter; + + #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE + portALT_GET_RUN_TIME_COUNTER_VALUE( ulTempCounter ); + #else + ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE(); + #endif + + /* Add the amount of time the task has been running to the accumulated + time so far. The time the task started running was stored in + ulTaskSwitchedInTime. Note that there is no overflow protection here + so count values are only valid until the timer overflows. Generally + this will be about 1 hour assuming a 1uS timer increment. */ + pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime ); + ulTaskSwitchedInTime = ulTempCounter; + } + #endif + + taskFIRST_CHECK_FOR_STACK_OVERFLOW(); + taskSECOND_CHECK_FOR_STACK_OVERFLOW(); + + /* Find the highest priority queue that contains ready tasks. */ + while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) + { + configASSERT( uxTopReadyPriority ); + --uxTopReadyPriority; + } + + /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the + same priority get an equal share of the processor time. */ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); + + traceTASK_SWITCHED_IN(); + vWriteTraceToBuffer(); } - #endif - - taskFIRST_CHECK_FOR_STACK_OVERFLOW(); - taskSECOND_CHECK_FOR_STACK_OVERFLOW(); - - /* Find the highest priority queue that contains ready tasks. */ - while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) - { - --uxTopReadyPriority; - } - - /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the - same priority get an equal share of the processor time. */ - listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); - - traceTASK_SWITCHED_IN(); - vWriteTraceToBuffer(); } /*-----------------------------------------------------------*/ @@ -1644,6 +1735,8 @@ void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicks { portTickType xTimeToWake; + configASSERT( pxEventList ); + /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE SCHEDULER SUSPENDED. */ @@ -1672,19 +1765,7 @@ portTickType xTimeToWake; /* Calculate the time at which the task should be woken if the event does not occur. This may overflow but this doesn't matter. */ xTimeToWake = xTickCount + xTicksToWait; - - listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake ); - - if( xTimeToWake < xTickCount ) - { - /* Wake time has overflowed. Place this item in the overflow list. */ - vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } - else - { - /* The wake time has not overflowed, so we can use the current block list. */ - vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } + prvAddCurrentTaskToDelayedList( xTimeToWake ); } } #else @@ -1692,24 +1773,46 @@ portTickType xTimeToWake; /* Calculate the time at which the task should be woken if the event does not occur. This may overflow but this doesn't matter. */ xTimeToWake = xTickCount + xTicksToWait; - - listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake ); - - if( xTimeToWake < xTickCount ) - { - /* Wake time has overflowed. Place this item in the overflow list. */ - vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } - else - { - /* The wake time has not overflowed, so we can use the current block list. */ - vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } + prvAddCurrentTaskToDelayedList( xTimeToWake ); } #endif } /*-----------------------------------------------------------*/ +#if configUSE_TIMERS == 1 + + void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait ) + { + portTickType xTimeToWake; + + configASSERT( pxEventList ); + + /* This function should not be called by application code hence the + 'Restricted' in its name. It is not part of the public API. It is + designed for use by kernel code, and has special calling requirements - + it should be called from a critical section. */ + + + /* Place the event list item of the TCB in the appropriate event list. + In this case it is assume that this is the only task that is going to + be waiting on this event list, so the faster vListInsertEnd() function + can be used in place of vListInsert. */ + vListInsertEnd( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) ); + + /* We must remove this task from the ready list before adding it to the + blocked list as the same list item is used for both lists. This + function is called form a critical section. */ + vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); + + /* Calculate the time at which the task should be woken if the event does + not occur. This may overflow but this doesn't matter. */ + xTimeToWake = xTickCount + xTicksToWait; + prvAddCurrentTaskToDelayedList( xTimeToWake ); + } + +#endif /* configUSE_TIMERS */ +/*-----------------------------------------------------------*/ + signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList ) { tskTCB *pxUnblockedTCB; @@ -1724,8 +1827,12 @@ portBASE_TYPE xReturn; If an event is for a queue that is locked then this function will never get called - the lock count on the queue will get modified instead. This - means we can always expect exclusive access to the event list here. */ + means we can always expect exclusive access to the event list here. + + This function assumes that a check has already been made to ensure that + pxEventList is not empty. */ pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); + configASSERT( pxUnblockedTCB ); vListRemove( &( pxUnblockedTCB->xEventListItem ) ); if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE ) @@ -1759,6 +1866,7 @@ portBASE_TYPE xReturn; void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut ) { + configASSERT( pxTimeOut ); pxTimeOut->xOverflowCount = xNumOfOverflows; pxTimeOut->xTimeOnEntering = xTickCount; } @@ -1768,7 +1876,10 @@ portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType { portBASE_TYPE xReturn; - portENTER_CRITICAL(); + configASSERT( pxTimeOut ); + configASSERT( pxTicksToWait ); + + taskENTER_CRITICAL(); { #if ( INCLUDE_vTaskSuspend == 1 ) /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is @@ -1801,7 +1912,7 @@ portBASE_TYPE xReturn; xReturn = pdTRUE; } } - portEXIT_CRITICAL(); + taskEXIT_CRITICAL(); return xReturn; } @@ -1897,13 +2008,13 @@ static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned short ) configMAX_TASK_NAME_LEN ); } #endif - pxTCB->pcTaskName[ ( unsigned short ) configMAX_TASK_NAME_LEN - ( unsigned short ) 1 ] = '\0'; + pxTCB->pcTaskName[ ( unsigned short ) configMAX_TASK_NAME_LEN - ( unsigned short ) 1 ] = ( signed char ) '\0'; /* This is used as an array index so must ensure it's not too large. First remove the privilege bit if one is present. */ if( uxPriority >= configMAX_PRIORITIES ) { - uxPriority = configMAX_PRIORITIES - 1; + uxPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U; } pxTCB->uxPriority = uxPriority; @@ -1978,7 +2089,7 @@ static void prvInitialiseTaskLists( void ) { unsigned portBASE_TYPE uxPriority; - for( uxPriority = 0; uxPriority < configMAX_PRIORITIES; uxPriority++ ) + for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < configMAX_PRIORITIES; uxPriority++ ) { vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) ); } @@ -2020,18 +2131,18 @@ static void prvCheckTasksWaitingTermination( void ) xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination ); xTaskResumeAll(); - if( !xListIsEmpty ) + if( xListIsEmpty == pdFALSE ) { tskTCB *pxTCB; - portENTER_CRITICAL(); + taskENTER_CRITICAL(); { pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) ); vListRemove( &( pxTCB->xGenericListItem ) ); --uxCurrentNumberOfTasks; --uxTasksDeleted; } - portEXIT_CRITICAL(); + taskEXIT_CRITICAL(); prvDeleteTCB( pxTCB ); } @@ -2041,6 +2152,32 @@ static void prvCheckTasksWaitingTermination( void ) } /*-----------------------------------------------------------*/ +static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) +{ + /* The list item will be inserted in wake time order. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake ); + + if( xTimeToWake < xTickCount ) + { + /* Wake time has overflowed. Place this item in the overflow list. */ + vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); + } + else + { + /* The wake time has not overflowed, so we can use the current block list. */ + vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); + + /* If the task entering the blocked state was placed at the head of the + list of blocked tasks then xNextTaskUnblockTime needs to be updated + too. */ + if( xTimeToWake < xNextTaskUnblockTime ) + { + xNextTaskUnblockTime = xTimeToWake; + } + } +} +/*-----------------------------------------------------------*/ + static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) { tskTCB *pxNewTCB; @@ -2130,7 +2267,7 @@ tskTCB *pxNewTCB; else { /* What percentage of the total run time has the task used? - This will always be rounded down to the nearest integer. + This will always be rounded down to the nearest integer. ulTotalRunTime has already been divided by 100. */ ulStatsAsPercentage = pxNextTCB->ulRunTimeCounter / ulTotalRunTime; @@ -2178,13 +2315,16 @@ tskTCB *pxNewTCB; #if ( INCLUDE_uxTaskGetRunTime == 1 ) unsigned portBASE_TYPE uxTaskGetRunTime( xTaskHandle xTask ) { + unsigned long runTime; + tskTCB *pxTCB; pxTCB = prvGetTCBFromHandle( xTask ); - return pxTCB->ulRunTimeCounter; + runTime = pxTCB->ulRunTimeCounter; + pxTCB->ulRunTimeCounter = 0; + return runTime; } #endif - /*-----------------------------------------------------------*/ #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) @@ -2250,7 +2390,7 @@ unsigned portBASE_TYPE uxTaskGetRunTime( xTaskHandle xTask ) /*-----------------------------------------------------------*/ -#if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) +#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) xTaskHandle xTaskGetCurrentTaskHandle( void ) { @@ -2268,7 +2408,7 @@ unsigned portBASE_TYPE uxTaskGetRunTime( xTaskHandle xTask ) /*-----------------------------------------------------------*/ -#if ( INCLUDE_xTaskGetSchedulerState == 1 ) +#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) portBASE_TYPE xTaskGetSchedulerState( void ) { @@ -2302,6 +2442,8 @@ unsigned portBASE_TYPE uxTaskGetRunTime( xTaskHandle xTask ) { tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder; + configASSERT( pxMutexHolder ); + if( pxTCB->uxPriority < pxCurrentTCB->uxPriority ) { /* Adjust the mutex holder state to account for its new priority. */ diff --git a/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/timers.c b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/timers.c new file mode 100644 index 000000000..7e5ef22ad --- /dev/null +++ b/flight/PiOS/STM32F10x/Libraries/FreeRTOS/Source/timers.c @@ -0,0 +1,649 @@ +/* + FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd. + + + FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by: + Atollic AB - Atollic provides professional embedded systems development + tools for C/C++ development, code analysis and test automation. + See http://www.atollic.com + + + *************************************************************************** + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * + *************************************************************************** + + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation AND MODIFIED BY the FreeRTOS exception. + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained + by writing to Richard Barry, contact details for whom are available on the + FreeRTOS WEB site. + + 1 tab == 4 spaces! + + http://www.FreeRTOS.org - Documentation, latest information, license and + contact details. + + http://www.SafeRTOS.com - A version that is certified for use in safety + critical systems. + + http://www.OpenRTOS.com - Commercial support, development, porting, + licensing and training services. +*/ + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "timers.h" + +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* This entire source file will be skipped if the application is not configured +to include software timer functionality. This #if is closed at the very bottom +of this file. If you want to include software timer functionality then ensure +configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ +#if ( configUSE_TIMERS == 1 ) + +/* Misc definitions. */ +#define tmrNO_DELAY ( portTickType ) 0U + +/* The definition of the timers themselves. */ +typedef struct tmrTimerControl +{ + const signed char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */ + xListItem xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */ + portTickType xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */ + unsigned portBASE_TYPE uxAutoReload; /*<< Set to pdTRUE if the timer should be automatically restarted once expired. Set to pdFALSE if the timer is, in effect, a one shot timer. */ + void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */ + tmrTIMER_CALLBACK pxCallbackFunction; /*<< The function that will be called when the timer expires. */ +} xTIMER; + +/* The definition of messages that can be sent and received on the timer +queue. */ +typedef struct tmrTimerQueueMessage +{ + portBASE_TYPE xMessageID; /*<< The command being sent to the timer service task. */ + portTickType xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */ + xTIMER * pxTimer; /*<< The timer to which the command will be applied. */ +} xTIMER_MESSAGE; + + +/* The list in which active timers are stored. Timers are referenced in expire +time order, with the nearest expiry time at the front of the list. Only the +timer service task is allowed to access xActiveTimerList. */ +PRIVILEGED_DATA static xList xActiveTimerList1; +PRIVILEGED_DATA static xList xActiveTimerList2; +PRIVILEGED_DATA static xList *pxCurrentTimerList; +PRIVILEGED_DATA static xList *pxOverflowTimerList; + +/* A queue that is used to send commands to the timer service task. */ +PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL; + +/*-----------------------------------------------------------*/ + +/* + * Initialise the infrastructure used by the timer service task if it has not + * been initialised already. + */ +static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION; + +/* + * The timer service task (daemon). Timer functionality is controlled by this + * task. Other tasks communicate with the timer service task using the + * xTimerQueue queue. + */ +static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION; + +/* + * Called by the timer service task to interpret and process a command it + * received on the timer queue. + */ +static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION; + +/* + * Insert the timer into either xActiveTimerList1, or xActiveTimerList2, + * depending on if the expire time causes a timer counter overflow. + */ +static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime ) PRIVILEGED_FUNCTION; + +/* + * An active timer has reached its expire time. Reload the timer if it is an + * auto reload timer, then call its callback. + */ +static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow ) PRIVILEGED_FUNCTION; + +/* + * The tick count has overflowed. Switch the timer lists after ensuring the + * current timer list does not still reference some timers. + */ +static void prvSwitchTimerLists( portTickType xLastTime ) PRIVILEGED_FUNCTION; + +/* + * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE + * if a tick count overflow occurred since prvSampleTimeNow() was last called. + */ +static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION; + +/* + * If the timer list contains any active timers then return the expire time of + * the timer that will expire first and set *pxListWasEmpty to false. If the + * timer list does not contain any timers then return 0 and set *pxListWasEmpty + * to pdTRUE. + */ +static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty ) PRIVILEGED_FUNCTION; + +/* + * If a timer has expired, process it. Otherwise, block the timer service task + * until either a timer does expire or a command is received. + */ +static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty ) PRIVILEGED_FUNCTION; + +/*-----------------------------------------------------------*/ + +portBASE_TYPE xTimerCreateTimerTask( void ) +{ +portBASE_TYPE xReturn = pdFAIL; + + /* This function is called when the scheduler is started if + configUSE_TIMERS is set to 1. Check that the infrastructure used by the + timer service task has been created/initialised. If timers have already + been created then the initialisation will already have been performed. */ + prvCheckForValidListAndQueue(); + + if( xTimerQueue != NULL ) + { + xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY, NULL); + } + + configASSERT( xReturn ); + return xReturn; +} +/*-----------------------------------------------------------*/ + +xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void *pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction ) +{ +xTIMER *pxNewTimer; + + /* Allocate the timer structure. */ + if( xTimerPeriodInTicks == ( portTickType ) 0U ) + { + pxNewTimer = NULL; + configASSERT( ( xTimerPeriodInTicks > 0 ) ); + } + else + { + pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) ); + if( pxNewTimer != NULL ) + { + /* Ensure the infrastructure used by the timer service task has been + created/initialised. */ + prvCheckForValidListAndQueue(); + + /* Initialise the timer structure members using the function parameters. */ + pxNewTimer->pcTimerName = pcTimerName; + pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks; + pxNewTimer->uxAutoReload = uxAutoReload; + pxNewTimer->pvTimerID = pvTimerID; + pxNewTimer->pxCallbackFunction = pxCallbackFunction; + vListInitialiseItem( &( pxNewTimer->xTimerListItem ) ); + + traceTIMER_CREATE( pxNewTimer ); + } + else + { + traceTIMER_CREATE_FAILED(); + } + } + + return ( xTimerHandle ) pxNewTimer; +} +/*-----------------------------------------------------------*/ + +portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime ) +{ +portBASE_TYPE xReturn = pdFAIL; +xTIMER_MESSAGE xMessage; + + /* Send a message to the timer service task to perform a particular action + on a particular timer definition. */ + if( xTimerQueue != NULL ) + { + /* Send a command to the timer service task to start the xTimer timer. */ + xMessage.xMessageID = xCommandID; + xMessage.xMessageValue = xOptionalValue; + xMessage.pxTimer = ( xTIMER * ) xTimer; + + if( pxHigherPriorityTaskWoken == NULL ) + { + if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING ) + { + xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime ); + } + else + { + xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY ); + } + } + else + { + xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken ); + } + + traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow ) +{ +xTIMER *pxTimer; +portBASE_TYPE xResult; + + /* Remove the timer from the list of active timers. A check has already + been performed to ensure the list is not empty. */ + pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); + vListRemove( &( pxTimer->xTimerListItem ) ); + traceTIMER_EXPIRED( pxTimer ); + + /* If the timer is an auto reload timer then calculate the next + expiry time and re-insert the timer in the list of active timers. */ + if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE ) + { + /* This is the only time a timer is inserted into a list using + a time relative to anything other than the current time. It + will therefore be inserted into the correct list relative to + the time this task thinks it is now, even if a command to + switch lists due to a tick count overflow is already waiting in + the timer queue. */ + if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE ) + { + /* The timer expired before it was added to the active timer + list. Reload it now. */ + xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY ); + configASSERT( xResult ); + ( void ) xResult; + } + } + + /* Call the timer callback. */ + pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer ); +} +/*-----------------------------------------------------------*/ + +static void prvTimerTask( void *pvParameters ) +{ +portTickType xNextExpireTime; +portBASE_TYPE xListWasEmpty; + + /* Just to avoid compiler warnings. */ + ( void ) pvParameters; + + for( ;; ) + { + /* Query the timers list to see if it contains any timers, and if so, + obtain the time at which the next timer will expire. */ + xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty ); + + /* If a timer has expired, process it. Otherwise, block this task + until either a timer does expire, or a command is received. */ + prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty ); + + /* Empty the command queue. */ + prvProcessReceivedCommands(); + } +} +/*-----------------------------------------------------------*/ + +static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty ) +{ +portTickType xTimeNow; +portBASE_TYPE xTimerListsWereSwitched; + + vTaskSuspendAll(); + { + /* Obtain the time now to make an assessment as to whether the timer + has expired or not. If obtaining the time causes the lists to switch + then don't process this timer as any timers that remained in the list + when the lists were switched will have been processed within the + prvSampelTimeNow() function. */ + xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched ); + if( xTimerListsWereSwitched == pdFALSE ) + { + /* The tick count has not overflowed, has the timer expired? */ + if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) ) + { + xTaskResumeAll(); + prvProcessExpiredTimer( xNextExpireTime, xTimeNow ); + } + else + { + /* The tick count has not overflowed, and the next expire + time has not been reached yet. This task should therefore + block to wait for the next expire time or a command to be + received - whichever comes first. The following line cannot + be reached unless xNextExpireTime > xTimeNow, except in the + case when the current timer list is empty. */ + vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) ); + + if( xTaskResumeAll() == pdFALSE ) + { + /* Yield to wait for either a command to arrive, or the block time + to expire. If a command arrived between the critical section being + exited and this yield then the yield will not cause the task + to block. */ + portYIELD_WITHIN_API(); + } + } + } + else + { + xTaskResumeAll(); + } + } +} +/*-----------------------------------------------------------*/ + +static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty ) +{ +portTickType xNextExpireTime; + + /* Timers are listed in expiry time order, with the head of the list + referencing the task that will expire first. Obtain the time at which + the timer with the nearest expiry time will expire. If there are no + active timers then just set the next expire time to 0. That will cause + this task to unblock when the tick count overflows, at which point the + timer lists will be switched and the next expiry time can be + re-assessed. */ + *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList ); + if( *pxListWasEmpty == pdFALSE ) + { + xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); + } + else + { + /* Ensure the task unblocks when the tick count rolls over. */ + xNextExpireTime = ( portTickType ) 0U; + } + + return xNextExpireTime; +} +/*-----------------------------------------------------------*/ + +static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched ) +{ +portTickType xTimeNow; +static portTickType xLastTime = ( portTickType ) 0U; + + xTimeNow = xTaskGetTickCount(); + + if( xTimeNow < xLastTime ) + { + prvSwitchTimerLists( xLastTime ); + *pxTimerListsWereSwitched = pdTRUE; + } + else + { + *pxTimerListsWereSwitched = pdFALSE; + } + + xLastTime = xTimeNow; + + return xTimeNow; +} +/*-----------------------------------------------------------*/ + +static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime ) +{ +portBASE_TYPE xProcessTimerNow = pdFALSE; + + listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime ); + listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer ); + + if( xNextExpiryTime <= xTimeNow ) + { + /* Has the expiry time elapsed between the command to start/reset a + timer was issued, and the time the command was processed? */ + if( ( ( portTickType ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks ) + { + /* The time between a command being issued and the command being + processed actually exceeds the timers period. */ + xProcessTimerNow = pdTRUE; + } + else + { + vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) ); + } + } + else + { + if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) ) + { + /* If, since the command was issued, the tick count has overflowed + but the expiry time has not, then the timer must have already passed + its expiry time and should be processed immediately. */ + xProcessTimerNow = pdTRUE; + } + else + { + vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) ); + } + } + + return xProcessTimerNow; +} +/*-----------------------------------------------------------*/ + +static void prvProcessReceivedCommands( void ) +{ +xTIMER_MESSAGE xMessage; +xTIMER *pxTimer; +portBASE_TYPE xTimerListsWereSwitched, xResult; +portTickType xTimeNow; + + /* In this case the xTimerListsWereSwitched parameter is not used, but it + must be present in the function call. */ + xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched ); + + while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) + { + pxTimer = xMessage.pxTimer; + + /* Is the timer already in a list of active timers? When the command + is trmCOMMAND_PROCESS_TIMER_OVERFLOW, the timer will be NULL as the + command is to the task rather than to an individual timer. */ + if( pxTimer != NULL ) + { + if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) + { + /* The timer is in a list, remove it. */ + vListRemove( &( pxTimer->xTimerListItem ) ); + } + } + + traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.xMessageValue ); + + switch( xMessage.xMessageID ) + { + case tmrCOMMAND_START : + /* Start or restart a timer. */ + if( prvInsertTimerInActiveList( pxTimer, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.xMessageValue ) == pdTRUE ) + { + /* The timer expired before it was added to the active timer + list. Process it now. */ + pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer ); + + if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE ) + { + xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY ); + configASSERT( xResult ); + ( void ) xResult; + } + } + break; + + case tmrCOMMAND_STOP : + /* The timer has already been removed from the active list. + There is nothing to do here. */ + break; + + case tmrCOMMAND_CHANGE_PERIOD : + pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue; + configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) ); + prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow ); + break; + + case tmrCOMMAND_DELETE : + /* The timer has already been removed from the active list, + just free up the memory. */ + vPortFree( pxTimer ); + break; + + default : + /* Don't expect to get here. */ + break; + } + } +} +/*-----------------------------------------------------------*/ + +static void prvSwitchTimerLists( portTickType xLastTime ) +{ +portTickType xNextExpireTime, xReloadTime; +xList *pxTemp; +xTIMER *pxTimer; +portBASE_TYPE xResult; + + /* Remove compiler warnings if configASSERT() is not defined. */ + ( void ) xLastTime; + + /* The tick count has overflowed. The timer lists must be switched. + If there are any timers still referenced from the current timer list + then they must have expired and should be processed before the lists + are switched. */ + while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE ) + { + xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); + + /* Remove the timer from the list. */ + pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); + vListRemove( &( pxTimer->xTimerListItem ) ); + + /* Execute its callback, then send a command to restart the timer if + it is an auto-reload timer. It cannot be restarted here as the lists + have not yet been switched. */ + pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer ); + + if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE ) + { + /* Calculate the reload value, and if the reload value results in + the timer going into the same timer list then it has already expired + and the timer should be re-inserted into the current list so it is + processed again within this loop. Otherwise a command should be sent + to restart the timer to ensure it is only inserted into a list after + the lists have been swapped. */ + xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ); + if( xReloadTime > xNextExpireTime ) + { + listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime ); + listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer ); + vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) ); + } + else + { + xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY ); + configASSERT( xResult ); + ( void ) xResult; + } + } + } + + pxTemp = pxCurrentTimerList; + pxCurrentTimerList = pxOverflowTimerList; + pxOverflowTimerList = pxTemp; +} +/*-----------------------------------------------------------*/ + +static void prvCheckForValidListAndQueue( void ) +{ + /* Check that the list from which active timers are referenced, and the + queue used to communicate with the timer service, have been + initialised. */ + taskENTER_CRITICAL(); + { + if( xTimerQueue == NULL ) + { + vListInitialise( &xActiveTimerList1 ); + vListInitialise( &xActiveTimerList2 ); + pxCurrentTimerList = &xActiveTimerList1; + pxOverflowTimerList = &xActiveTimerList2; + xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) ); + } + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer ) +{ +portBASE_TYPE xTimerIsInActiveList; +xTIMER *pxTimer = ( xTIMER * ) xTimer; + + /* Is the timer in the list of active timers? */ + taskENTER_CRITICAL(); + { + /* Checking to see if it is in the NULL list in effect checks to see if + it is referenced from either the current or the overflow timer lists in + one go, but the logic has to be reversed, hence the '!'. */ + xTimerIsInActiveList = !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) ); + } + taskEXIT_CRITICAL(); + + return xTimerIsInActiveList; +} +/*-----------------------------------------------------------*/ + +void *pvTimerGetTimerID( xTimerHandle xTimer ) +{ +xTIMER *pxTimer = ( xTIMER * ) xTimer; + + return pxTimer->pvTimerID; +} +/*-----------------------------------------------------------*/ + +/* This entire source file will be skipped if the application is not configured +to include software timer functionality. If you want to include software timer +functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ +#endif /* configUSE_TIMERS == 1 */ diff --git a/flight/PiOS/STM32F10x/link_STM32103CB_AHRS_BL_sections.ld b/flight/PiOS/STM32F10x/link_STM32103CB_AHRS_BL_sections.ld index ccc2cfe7a..d411c3e4f 100644 --- a/flight/PiOS/STM32F10x/link_STM32103CB_AHRS_BL_sections.ld +++ b/flight/PiOS/STM32F10x/link_STM32103CB_AHRS_BL_sections.ld @@ -5,6 +5,7 @@ SECTIONS { .text : { + PROVIDE (pios_isr_vector_table_base = .); KEEP(*(.isr_vector .isr_vector.*)) *(.text .text.* .gnu.linkonce.t.*) *(.glue_7t) *(.glue_7) @@ -45,4 +46,11 @@ SECTIONS . = ALIGN(4); _end = . ; + + .boardinfo : + { + . = ALIGN(4); + KEEP(*(.boardinfo)) + . = ALIGN(4); + } > BD_INFO } diff --git a/flight/PiOS/STM32F10x/link_STM32103CB_AHRS_memory.ld b/flight/PiOS/STM32F10x/link_STM32103CB_AHRS_memory.ld index 50823e432..9f7bf0f19 100644 --- a/flight/PiOS/STM32F10x/link_STM32103CB_AHRS_memory.ld +++ b/flight/PiOS/STM32F10x/link_STM32103CB_AHRS_memory.ld @@ -1,6 +1,7 @@ MEMORY { - BL_FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 8K - FLASH (rx) : ORIGIN = 0x08000000 + 8K, LENGTH = 128K - 8K - SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K + BL_FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x02000 - 0x00080 + BD_INFO (r) : ORIGIN = 0x08002000 - 0x80, LENGTH = 0x00080 + FLASH (rx) : ORIGIN = 0x08002000, LENGTH = 0x20000 - 0x02000 + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x05000 } diff --git a/flight/PiOS/STM32F10x/link_STM32103CB_AHRS_sections.ld b/flight/PiOS/STM32F10x/link_STM32103CB_AHRS_sections.ld index 207956b53..dd814f561 100644 --- a/flight/PiOS/STM32F10x/link_STM32103CB_AHRS_sections.ld +++ b/flight/PiOS/STM32F10x/link_STM32103CB_AHRS_sections.ld @@ -1,3 +1,5 @@ +PROVIDE(pios_board_info_blob = ORIGIN(BD_INFO)); + _estack = 0x20004FF0; /* Section Definitions */ @@ -5,6 +7,7 @@ SECTIONS { .text : { + PROVIDE (pios_isr_vector_table_base = .); KEEP(*(.isr_vector .isr_vector.*)) *(.text .text.* .gnu.linkonce.t.*) *(.glue_7t) *(.glue_7) diff --git a/flight/PiOS/STM32F10x/link_STM32103CB_CC_Rev1_BL_sections.ld b/flight/PiOS/STM32F10x/link_STM32103CB_CC_Rev1_BL_sections.ld index b5b4e07d0..777e09aa6 100644 --- a/flight/PiOS/STM32F10x/link_STM32103CB_CC_Rev1_BL_sections.ld +++ b/flight/PiOS/STM32F10x/link_STM32103CB_CC_Rev1_BL_sections.ld @@ -3,29 +3,21 @@ PROVIDE ( vPortSVCHandler = 0 ) ; PROVIDE ( xPortPendSVHandler = 0 ) ; PROVIDE ( xPortSysTickHandler = 0 ) ; -_estack = 0x20004FF0; +/* This is the size of the stack for early init and for all FreeRTOS IRQs */ +_irq_stack_size = 0x400; /* Section Definitions */ SECTIONS { .text : { + PROVIDE (pios_isr_vector_table_base = .); KEEP(*(.isr_vector .isr_vector.*)) *(.text .text.* .gnu.linkonce.t.*) *(.glue_7t) *(.glue_7) *(.rodata .rodata* .gnu.linkonce.r.*) } > BL_FLASH - /* init sections */ - .initcalluavobj.init : - { - . = ALIGN(4); - __uavobj_initcall_start = .; - KEEP(*(.initcalluavobj.init)) - . = ALIGN(4); - __uavobj_initcall_end = .; - } > BL_FLASH - .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) @@ -58,9 +50,33 @@ SECTIONS _ebss = . ; } > SRAM + /* + * This stack is used both as the initial sp during early init as well as ultimately + * being used as the STM32's MSP (Main Stack Pointer) which is the same stack that + * is used for _all_ interrupt handlers. The end of this stack should be placed + * against the lowest address in RAM so that a stack overrun results in a hard fault + * at the first access beyond the end of the stack. + */ + .irq_stack : + { + . = ALIGN(4); + _irq_stack_end = . ; + . = . + _irq_stack_size ; + . = ALIGN(4); + _irq_stack_top = . - 4 ; + _init_stack_top = _irq_stack_top; + . = ALIGN(4); + } > SRAM + . = ALIGN(4); _end = . ; + .boardinfo : + { + . = ALIGN(4); + KEEP(*(.boardinfo)) + } > BD_INFO + /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } diff --git a/flight/PiOS/STM32F10x/link_STM32103CB_CC_Rev1_memory.ld b/flight/PiOS/STM32F10x/link_STM32103CB_CC_Rev1_memory.ld index 57146d7d6..fd36c31ba 100644 --- a/flight/PiOS/STM32F10x/link_STM32103CB_CC_Rev1_memory.ld +++ b/flight/PiOS/STM32F10x/link_STM32103CB_CC_Rev1_memory.ld @@ -1,6 +1,7 @@ MEMORY { - BL_FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 12K - FLASH (rx) : ORIGIN = 0x08000000 + 12K, LENGTH = 128K - 12K - SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K + BL_FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x03000 - 0x00080 + BD_INFO (r) : ORIGIN = 0x08003000 - 0x80, LENGTH = 0x00080 + FLASH (rx) : ORIGIN = 0x08003000, LENGTH = 0x20000 - 0x03000 + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x05000 } diff --git a/flight/PiOS/STM32F10x/link_STM32103CB_CC_Rev1_sections.ld b/flight/PiOS/STM32F10x/link_STM32103CB_CC_Rev1_sections.ld index 17534b780..57530d320 100644 --- a/flight/PiOS/STM32F10x/link_STM32103CB_CC_Rev1_sections.ld +++ b/flight/PiOS/STM32F10x/link_STM32103CB_CC_Rev1_sections.ld @@ -1,29 +1,35 @@ +/* This is the size of the stack for all FreeRTOS IRQs */ +_irq_stack_size = 0x180; +/* This is the size of the stack for early init: life span is until scheduler starts */ +_init_stack_size = 0x100; + /* Stub out these functions since we don't use them anyway */ PROVIDE ( vPortSVCHandler = 0 ) ; PROVIDE ( xPortPendSVHandler = 0 ) ; PROVIDE ( xPortSysTickHandler = 0 ) ; -_estack = 0x20004FF0; +PROVIDE(pios_board_info_blob = ORIGIN(BD_INFO)); /* Section Definitions */ SECTIONS { .text : { + PROVIDE (pios_isr_vector_table_base = .); KEEP(*(.isr_vector .isr_vector.*)) *(.text .text.* .gnu.linkonce.t.*) *(.glue_7t) *(.glue_7) *(.rodata .rodata* .gnu.linkonce.r.*) } > FLASH - /* init sections */ - .initcalluavobj.init : + /* module sections */ + .initcallmodule.init : { . = ALIGN(4); - __uavobj_initcall_start = .; - KEEP(*(.initcalluavobj.init)) + __module_initcall_start = .; + KEEP(*(.initcallmodule.init)) . = ALIGN(4); - __uavobj_initcall_end = .; + __module_initcall_end = .; } >FLASH .ARM.extab : @@ -40,6 +46,23 @@ SECTIONS _etext = .; _sidata = .; + /* + * This stack is used both as the initial sp during early init as well as ultimately + * being used as the STM32's MSP (Main Stack Pointer) which is the same stack that + * is used for _all_ interrupt handlers. The end of this stack should be placed + * against the lowest address in RAM so that a stack overrun results in a hard fault + * at the first access beyond the end of the stack. + */ + .irq_stack : + { + . = ALIGN(4); + _irq_stack_end = . ; + . = . + _irq_stack_size ; + . = ALIGN(4); + _irq_stack_top = . - 4 ; + . = ALIGN(4); + } > SRAM + .data : AT (_etext) { _sdata = .; @@ -48,18 +71,49 @@ SECTIONS _edata = . ; } > SRAM + + /* .bss section which is used for uninitialized data */ .bss (NOLOAD) : { _sbss = . ; *(.bss .bss.*) *(COMMON) - . = ALIGN(4); - _ebss = . ; } > SRAM - . = ALIGN(4); - _end = . ; + .heap (NOLOAD) : + { + . = ALIGN(4); + _sheap = . ; + _sheap_pre_rtos = . ; + *(.heap) + . = ALIGN(4); + _eheap = . ; + _eheap_pre_rtos = . ; + _init_stack_end = . ; + _sheap_post_rtos = . ; + . = . + _init_stack_size ; + . = ALIGN(4); + _eheap_post_rtos = . ; + _init_stack_top = . - 4 ; + } > SRAM + + + _free_ram = . ; + .free_ram (NOLOAD) : + { + . = ORIGIN(SRAM) + LENGTH(SRAM) - _free_ram ; + /* This is used by the startup in order to initialize the .bss section */ + _ebss = . ; + _eram = . ; + } > SRAM + + /* keep the heap section at the end of the SRAM + * this will allow to claim the remaining bytes not used + * at run time! (done by the reset vector). + */ + + PROVIDE ( _end = _ebss ) ; /* Stabs debugging sections. */ .stab 0 : { *(.stab) } diff --git a/flight/PiOS/STM32F10x/link_STM32103CB_PIPXTREME_BL_sections.ld b/flight/PiOS/STM32F10x/link_STM32103CB_PIPXTREME_BL_sections.ld index de9efa6fc..69eaadb8c 100644 --- a/flight/PiOS/STM32F10x/link_STM32103CB_PIPXTREME_BL_sections.ld +++ b/flight/PiOS/STM32F10x/link_STM32103CB_PIPXTREME_BL_sections.ld @@ -10,6 +10,7 @@ SECTIONS { .text : { + PROVIDE (pios_isr_vector_table_base = .); KEEP(*(.isr_vector .isr_vector.*)) *(.text .text.* .gnu.linkonce.t.*) *(.glue_7t) *(.glue_7) @@ -50,4 +51,11 @@ SECTIONS . = ALIGN(4); _end = . ; + + .boardinfo : + { + . = ALIGN(4); + KEEP(*(.boardinfo)) + . = ALIGN(4); + } > BD_INFO } diff --git a/flight/PiOS/STM32F10x/link_STM32103CB_PIPXTREME_memory.ld b/flight/PiOS/STM32F10x/link_STM32103CB_PIPXTREME_memory.ld index 57146d7d6..04aa69ccb 100644 --- a/flight/PiOS/STM32F10x/link_STM32103CB_PIPXTREME_memory.ld +++ b/flight/PiOS/STM32F10x/link_STM32103CB_PIPXTREME_memory.ld @@ -1,6 +1,8 @@ MEMORY { - BL_FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 12K - FLASH (rx) : ORIGIN = 0x08000000 + 12K, LENGTH = 128K - 12K - SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K + BL_FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x03000 - 0x00080 + BD_INFO (r) : ORIGIN = 0x08003000 - 0x80, LENGTH = 0x00080 + FLASH (rx) : ORIGIN = 0x08003000, LENGTH = 0x20000 - 0x03000 - 0x00400 + EE_FLASH (rw) : ORIGIN = 0x0801FC00, LENGTH = 0x00400 + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x05000 } diff --git a/flight/PiOS/STM32F10x/link_STM32103CB_PIPXTREME_sections.ld b/flight/PiOS/STM32F10x/link_STM32103CB_PIPXTREME_sections.ld index 678f164c8..badf5f986 100644 --- a/flight/PiOS/STM32F10x/link_STM32103CB_PIPXTREME_sections.ld +++ b/flight/PiOS/STM32F10x/link_STM32103CB_PIPXTREME_sections.ld @@ -3,6 +3,8 @@ PROVIDE ( vPortSVCHandler = 0 ) ; PROVIDE ( xPortPendSVHandler = 0 ) ; PROVIDE ( xPortSysTickHandler = 0 ) ; +PROVIDE(pios_board_info_blob = ORIGIN(BD_INFO)); + _estack = 0x20004FF0; /* Section Definitions */ @@ -10,6 +12,7 @@ SECTIONS { .text : { + PROVIDE (pios_isr_vector_table_base = .); KEEP(*(.isr_vector .isr_vector.*)) *(.text .text.* .gnu.linkonce.t.*) *(.glue_7t) *(.glue_7) diff --git a/flight/PiOS/STM32F10x/link_STM3210E_INS_HD_NB.ld b/flight/PiOS/STM32F10x/link_STM3210E_INS_BL_sections.ld similarity index 91% rename from flight/PiOS/STM32F10x/link_STM3210E_INS_HD_NB.ld rename to flight/PiOS/STM32F10x/link_STM3210E_INS_BL_sections.ld index 99a82b1e4..3420c385e 100644 --- a/flight/PiOS/STM32F10x/link_STM3210E_INS_HD_NB.ld +++ b/flight/PiOS/STM32F10x/link_STM3210E_INS_BL_sections.ld @@ -24,26 +24,11 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Memory Spaces Definitions */ -MEMORY -{ - RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K - FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K - FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 - EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0 - EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 - EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0 - EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0 -} - -_estack = 0x20004FF0; - /* This is the size of the stack for early init and for all FreeRTOS IRQs */ _irq_stack_size = 0x400; /* Check valid alignment for VTOR */ -ASSERT(ORIGIN(FLASH) == ALIGN(ORIGIN(FLASH), 0x80), "Start of memory region flash not aligned for startup vector table"); +ASSERT(ORIGIN(BL_FLASH) == ALIGN(ORIGIN(BL_FLASH), 0x80), "Start of memory region flash not aligned for startup vector table"); /* this sends all unreferenced IRQHandlers to reset @@ -208,9 +193,10 @@ SECTIONS /* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */ .isr_vector : { + PROVIDE (pios_isr_vector_table_base = .); KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); - } >FLASH + } > BL_FLASH /* for some STRx devices, the beginning of the startup code is stored in the .flashtext section, which goes to FLASH */ .flashtext : @@ -218,19 +204,9 @@ SECTIONS . = ALIGN(4); *(.flashtext) /* Startup code */ . = ALIGN(4); - } >FLASH + } > BL_FLASH - /* init sections */ - .initcalluavobj.init : - { - . = ALIGN(4); - __uavobj_initcall_start = .; - KEEP(*(.initcalluavobj.init)) - . = ALIGN(4); - __uavobj_initcall_end = .; - } >FLASH - /* the program code is stored in the .text section, which goes to Flash */ .text : { @@ -247,7 +223,7 @@ SECTIONS _etext = .; /* This is used by the startup in order to initialize the .data secion */ _sidata = _etext; - } >FLASH + } > BL_FLASH /* @@ -354,6 +330,13 @@ SECTIONS __exidx_start = .; __exidx_end = .; + .boardinfo : + { + . = ALIGN(4); + KEEP(*(.boardinfo)) + . = ALIGN(4); + } > BD_INFO + /* after that it's only debugging information. */ /* remove the debugging information from the standard libraries */ diff --git a/flight/PiOS/STM32F10x/link_STM3210E_INS_memory.ld b/flight/PiOS/STM32F10x/link_STM3210E_INS_memory.ld new file mode 100644 index 000000000..7ecb0f65d --- /dev/null +++ b/flight/PiOS/STM32F10x/link_STM3210E_INS_memory.ld @@ -0,0 +1,13 @@ +/* Memory Spaces Definitions */ +MEMORY +{ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x10000 + BL_FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x05000 - 0x00080 + BD_INFO (r) : ORIGIN = 0x08005000 - 0x80, LENGTH = 0x00080 + FLASH (rx) : ORIGIN = 0x08005000, LENGTH = 0x80000 - 0x05000 + FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 + EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0 + EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 + EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0 + EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0 +} diff --git a/flight/PiOS/STM32F10x/link_STM3210E_INS_HD_BL.ld b/flight/PiOS/STM32F10x/link_STM3210E_INS_sections.ld similarity index 91% rename from flight/PiOS/STM32F10x/link_STM3210E_INS_HD_BL.ld rename to flight/PiOS/STM32F10x/link_STM3210E_INS_sections.ld index ab897621c..bcf498dd0 100644 --- a/flight/PiOS/STM32F10x/link_STM3210E_INS_HD_BL.ld +++ b/flight/PiOS/STM32F10x/link_STM3210E_INS_sections.ld @@ -1,9 +1,9 @@ /** ****************************************************************************** * - * @file link_STM3210E_INS_HD_BL.ld + * @file link_STM3210E_INS_HD_NB.ld * @author David "Buzz" Carlson (buzz@chebuzz.com) - * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. * @brief PiOS linker for the OpenPilot INS board * @see The GNU Public License (GPL) Version 3 * @@ -24,21 +24,6 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Memory Spaces Definitions */ -MEMORY -{ - RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K - FLASH (rx) : ORIGIN = 0x08005000, LENGTH = 492K - FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 - EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0 - EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 - EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0 - EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0 -} - -_estack = 0x20004FF0; - /* This is the size of the stack for early init and for all FreeRTOS IRQs */ _irq_stack_size = 0x400; @@ -62,10 +47,10 @@ PROVIDE ( HardFault_Handler = 0 ) ; PROVIDE ( MemManage_Handler = 0 ) ; PROVIDE ( BusFault_Handler = 0 ) ; PROVIDE ( UsageFault_Handler = 0 ) ; -PROVIDE ( SVC_Handler = 0 ) ; +PROVIDE ( vPortSVCHandler = 0 ) ; PROVIDE ( DebugMon_Handler = 0 ) ; -PROVIDE ( PendSV_Handler = 0 ) ; -PROVIDE ( SysTick_Handler = 0 ) ; +PROVIDE ( xPortPendSVHandler = 0 ) ; +PROVIDE ( xPortSysTickHandler = 0 ) ; PROVIDE ( WWDG_IRQHandler = 0 ) ; PROVIDE ( PVD_IRQHandler = 0 ) ; @@ -199,18 +184,19 @@ PROVIDE ( SysTick = (SCS_BASE + 0x0010) ) ; PROVIDE ( NVIC = (SCS_BASE + 0x0100) ) ; PROVIDE ( SCB = (SCS_BASE + 0x0D00) ) ; +PROVIDE(pios_board_info_blob = ORIGIN(BD_INFO)); /* Sections Definitions */ SECTIONS { - /* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */ .isr_vector : { + PROVIDE (pios_isr_vector_table_base = .); KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); - } >FLASH + } > FLASH /* for some STRx devices, the beginning of the startup code is stored in the .flashtext section, which goes to FLASH */ .flashtext : @@ -218,18 +204,8 @@ SECTIONS . = ALIGN(4); *(.flashtext) /* Startup code */ . = ALIGN(4); - } >FLASH + } > FLASH - - /* init sections */ - .initcalluavobj.init : - { - . = ALIGN(4); - __uavobj_initcall_start = .; - KEEP(*(.initcalluavobj.init)) - . = ALIGN(4); - __uavobj_initcall_end = .; - } >FLASH /* the program code is stored in the .text section, which goes to Flash */ .text : @@ -247,7 +223,7 @@ SECTIONS _etext = .; /* This is used by the startup in order to initialize the .data secion */ _sidata = _etext; - } >FLASH + } > FLASH /* @@ -264,6 +240,7 @@ SECTIONS . = . + _irq_stack_size ; . = ALIGN(4); _irq_stack_top = . - 4 ; + _init_stack_top = _irq_stack_top; . = ALIGN(4); } >RAM diff --git a/flight/PiOS/STM32F10x/link_STM3210E_OP_BL_sections.ld b/flight/PiOS/STM32F10x/link_STM3210E_OP_BL_sections.ld index 120a2ba1b..9cd7c8b4b 100644 --- a/flight/PiOS/STM32F10x/link_STM3210E_OP_BL_sections.ld +++ b/flight/PiOS/STM32F10x/link_STM3210E_OP_BL_sections.ld @@ -2,7 +2,7 @@ _irq_stack_size = 0x400; /* Check valid alignment for VTOR */ -ASSERT(ORIGIN(FLASH) == ALIGN(ORIGIN(FLASH), 0x80), "Start of memory region flash not aligned for startup vector table"); +ASSERT(ORIGIN(BL_FLASH) == ALIGN(ORIGIN(BL_FLASH), 0x80), "Start of memory region flash not aligned for startup vector table"); /* this sends all unreferenced IRQHandlers to reset @@ -163,10 +163,10 @@ PROVIDE ( SCB = (SCS_BASE + 0x0D00) ) ; SECTIONS { - /* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */ .isr_vector : { + PROVIDE (pios_isr_vector_table_base = .); KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); } > BL_FLASH @@ -179,17 +179,6 @@ SECTIONS . = ALIGN(4); } > BL_FLASH - - /* init sections */ - .initcalluavobj.init : - { - . = ALIGN(4); - __uavobj_initcall_start = .; - KEEP(*(.initcalluavobj.init)) - . = ALIGN(4); - __uavobj_initcall_end = .; - } > BL_FLASH - /* the program code is stored in the .text section, which goes to Flash */ .text : { @@ -223,6 +212,7 @@ SECTIONS . = . + _irq_stack_size ; . = ALIGN(4); _irq_stack_top = . - 4 ; + _init_stack_top = _irq_stack_top; . = ALIGN(4); } >RAM @@ -313,6 +303,13 @@ SECTIONS __exidx_start = .; __exidx_end = .; + .boardinfo : + { + . = ALIGN(4); + KEEP(*(.boardinfo)) + . = ALIGN(4); + } > BD_INFO + /* after that it's only debugging information. */ /* remove the debugging information from the standard libraries */ @@ -357,5 +354,3 @@ SECTIONS .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } } - - diff --git a/flight/PiOS/STM32F10x/link_STM3210E_OP_memory.ld b/flight/PiOS/STM32F10x/link_STM3210E_OP_memory.ld index 72ed542d2..ce70e2e5c 100644 --- a/flight/PiOS/STM32F10x/link_STM3210E_OP_memory.ld +++ b/flight/PiOS/STM32F10x/link_STM3210E_OP_memory.ld @@ -1,11 +1,12 @@ MEMORY { - RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K - BL_FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 20K - FLASH (rx) : ORIGIN = 0x08000000 + 20K, LENGTH = 512K - 20K - FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 - EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0 - EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 - EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0 - EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0 + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x10000 + BL_FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x05000 - 0x00080 + BD_INFO (r) : ORIGIN = 0x08005000 - 0x80, LENGTH = 0x00080 + FLASH (rx) : ORIGIN = 0x08005000, LENGTH = 0x80000 - 0x05000 + FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 + EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0 + EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 + EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0 + EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0 } diff --git a/flight/PiOS/STM32F10x/link_STM3210E_OP_sections.ld b/flight/PiOS/STM32F10x/link_STM3210E_OP_sections.ld index 97e60b135..5d504bfdd 100644 --- a/flight/PiOS/STM32F10x/link_STM3210E_OP_sections.ld +++ b/flight/PiOS/STM32F10x/link_STM3210E_OP_sections.ld @@ -1,5 +1,7 @@ /* This is the size of the stack for early init and for all FreeRTOS IRQs */ _irq_stack_size = 0x400; +/* This is the size of the stack for early init: life span is until scheduler starts */ +_init_stack_size = 0x400; /* Check valid alignment for VTOR */ ASSERT(ORIGIN(FLASH) == ALIGN(ORIGIN(FLASH), 0x80), "Start of memory region flash not aligned for startup vector table"); @@ -158,15 +160,16 @@ PROVIDE ( SysTick = (SCS_BASE + 0x0010) ) ; PROVIDE ( NVIC = (SCS_BASE + 0x0100) ) ; PROVIDE ( SCB = (SCS_BASE + 0x0D00) ) ; +PROVIDE(pios_board_info_blob = ORIGIN(BD_INFO)); /* Sections Definitions */ SECTIONS { - /* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */ .isr_vector : { + PROVIDE (pios_isr_vector_table_base = .); KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); } >FLASH @@ -178,16 +181,15 @@ SECTIONS *(.flashtext) /* Startup code */ . = ALIGN(4); } >FLASH - - - /* init sections */ - .initcalluavobj.init : + + /* module sections */ + .initcallmodule.init : { . = ALIGN(4); - __uavobj_initcall_start = .; - KEEP(*(.initcalluavobj.init)) + __module_initcall_start = .; + KEEP(*(.initcallmodule.init)) . = ALIGN(4); - __uavobj_initcall_end = .; + __module_initcall_end = .; } >FLASH /* the program code is stored in the .text section, which goes to Flash */ @@ -208,7 +210,6 @@ SECTIONS _sidata = _etext; } >FLASH - /* * This stack is used both as the initial sp during early init as well as ultimately * being used as the STM32's MSP (Main Stack Pointer) which is the same stack that @@ -250,17 +251,44 @@ SECTIONS .bss : { . = ALIGN(4); - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; *(.bss) *(COMMON) - - . = ALIGN(4); - /* This is used by the startup in order to initialize the .bss secion */ - _ebss = . ; } >RAM + .heap (NOLOAD) : + { + . = ALIGN(4); + _sheap = . ; + _sheap_pre_rtos = . ; + *(.heap) + . = ALIGN(4); + _eheap = . ; + _eheap_pre_rtos = . ; + _init_stack_end = . ; + _sheap_post_rtos = . ; + . = . + _init_stack_size ; + . = ALIGN(4); + _eheap_post_rtos = . ; + _init_stack_top = . - 4 ; + } > RAM + + _free_ram = . ; + .free_ram (NOLOAD) : + { + . = ORIGIN(RAM) + LENGTH(RAM) - _free_ram ; + /* This is used by the startup in order to initialize the .bss section */ + _ebss = . ; + _eram = . ; + } > RAM + + /* keep the heap section at the end of the SRAM + * this will allow to claim the remaining bytes not used + * at run time! (done by the reset vector). + */ + PROVIDE ( end = _ebss ); PROVIDE ( _end = _ebss ); diff --git a/flight/PiOS/STM32F10x/pios_delay.c b/flight/PiOS/STM32F10x/pios_delay.c index 933fb8e7e..c4e74717b 100644 --- a/flight/PiOS/STM32F10x/pios_delay.c +++ b/flight/PiOS/STM32F10x/pios_delay.c @@ -7,10 +7,10 @@ * @{ * * @file pios_delay.c - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Thorsten Klose (tk@midibox.org) (tk@midibox.org) + * @author Michael Smith Copyright (C) 2011 * @brief Delay Functions - * - Provides a micro-second granular delay using a TIM + * - Provides a micro-second granular delay using the CPU + * cycle counter. * @see The GNU Public License (GPL) Version 3 * *****************************************************************************/ @@ -31,72 +31,97 @@ */ /* Project Includes */ -#include "pios.h" +#include #if defined(PIOS_INCLUDE_DELAY) +/* these should be defined by CMSIS, but they aren't */ +#define DWT_CTRL (*(volatile uint32_t *)0xe0001000) +#define CYCCNTENA (1<<0) +#define DWT_CYCCNT (*(volatile uint32_t *)0xe0001004) + + +/* cycles per microsecond */ +static uint32_t us_ticks; + /** -* Initialises the Timer used by PIOS_DELAY functions
-* This is called from pios.c as part of the main() function -* at system start up. -* \return < 0 if initialisation failed -*/ + * Initialises the Timer used by PIOS_DELAY functions. + * + * \return always zero (success) + */ int32_t PIOS_DELAY_Init(void) { - /* Enable timer clock */ - PIOS_DELAY_TIMER_RCC_FUNC; + RCC_ClocksTypeDef clocks; - /* Time base configuration */ - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; - TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); - TIM_TimeBaseStructure.TIM_Period = 65535; // maximum value - TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; // for 1 uS accuracy fixed to 72Mhz - TIM_TimeBaseStructure.TIM_ClockDivision = 0; - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; - TIM_TimeBaseInit(PIOS_DELAY_TIMER, &TIM_TimeBaseStructure); + /* compute the number of system clocks per microsecond */ + RCC_GetClocksFreq(&clocks); + us_ticks = clocks.SYSCLK_Frequency / 1000000; + PIOS_DEBUG_Assert(us_ticks > 1); - /* Enable counter */ - TIM_Cmd(PIOS_DELAY_TIMER, ENABLE); + /* turn on access to the DWT registers */ + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + + /* enable the CPU cycle counter */ + DWT_CTRL |= CYCCNTENA; + + return 0; +} + +/** + * Waits for a specific number of uS + * + * Example:
+ * \code + * // Wait for 500 uS + * PIOS_DELAY_Wait_uS(500); + * \endcode + * \param[in] uS delay + * \return < 0 on errors + */ +int32_t PIOS_DELAY_WaituS(uint32_t uS) +{ + uint32_t elapsed = 0; + uint32_t last_count = DWT_CYCCNT; + + for (;;) { + uint32_t current_count = DWT_CYCCNT; + uint32_t elapsed_uS; + + /* measure the time elapsed since the last time we checked */ + elapsed += current_count - last_count; + last_count = current_count; + + /* convert to microseconds */ + elapsed_uS = elapsed / us_ticks; + if (elapsed_uS >= uS) + break; + + /* reduce the delay by the elapsed time */ + uS -= elapsed_uS; + + /* keep fractional microseconds for the next iteration */ + elapsed %= us_ticks; + } /* No error */ return 0; } /** -* Waits for a specific number of uS
-* Example:
-* \code -* // Wait for 500 uS -* PIOS_DELAY_Wait_uS(500); -* \endcode -* \param[in] uS delay (1..65535 microseconds) -* \return < 0 on errors -*/ -int32_t PIOS_DELAY_WaituS(uint16_t uS) + * Waits for a specific number of mS + * + * Example:
+ * \code + * // Wait for 500 mS + * PIOS_DELAY_Wait_mS(500); + * \endcode + * \param[in] mS delay + * \return < 0 on errors + */ +int32_t PIOS_DELAY_WaitmS(uint32_t mS) { - uint16_t start = PIOS_DELAY_TIMER->CNT; - - /* Note that this event works on 16bit counter wrap-arounds */ - while ((uint16_t) (PIOS_DELAY_TIMER->CNT - start) <= uS) ; - - /* No error */ - return 0; -} - -/** -* Waits for a specific number of mS
-* Example:
-* \code -* // Wait for 500 mS -* PIOS_DELAY_Wait_mS(500); -* \endcode -* \param[in] mS delay (1..65535 milliseconds) -* \return < 0 on errors -*/ -int32_t PIOS_DELAY_WaitmS(uint16_t mS) -{ - for (int i = 0; i < mS; i++) { + while (mS--) { PIOS_DELAY_WaituS(1000); } @@ -104,6 +129,25 @@ int32_t PIOS_DELAY_WaitmS(uint16_t mS) return 0; } +/** + * @brief Query the Delay timer for the current uS + * @return A microsecond value + */ +uint32_t PIOS_DELAY_GetuS(void) +{ + return DWT_CYCCNT / us_ticks; +} + +/** + * @brief Calculate time in microseconds since a previous time + * @param[in] t previous time + * @return time in us since previous time t. + */ +uint32_t PIOS_DELAY_GetuSSince(uint32_t t) +{ + return (PIOS_DELAY_GetuS() - t); +} + #endif /** diff --git a/flight/PiOS/STM32F10x/pios_ppm.c b/flight/PiOS/STM32F10x/pios_ppm.c index 885b3e27d..fe7421a17 100644 --- a/flight/PiOS/STM32F10x/pios_ppm.c +++ b/flight/PiOS/STM32F10x/pios_ppm.c @@ -34,34 +34,59 @@ #if defined(PIOS_INCLUDE_PPM) -/* Local Variables */ +/* Provide a RCVR driver */ +static int32_t PIOS_PPM_Get(uint32_t rcvr_id, uint8_t channel); +const struct pios_rcvr_driver pios_ppm_rcvr_driver = { + .read = PIOS_PPM_Get, +}; + +#define PIOS_PPM_IN_MIN_NUM_CHANNELS 4 +#define PIOS_PPM_IN_MAX_NUM_CHANNELS PIOS_PPM_NUM_INPUTS +#define PIOS_PPM_STABLE_CHANNEL_COUNT 25 // frames +#define PIOS_PPM_IN_MIN_SYNC_PULSE_US 3800 // microseconds +#define PIOS_PPM_IN_MIN_CHANNEL_PULSE_US 750 // microseconds +#define PIOS_PPM_IN_MAX_CHANNEL_PULSE_US 2250 // microseconds +#define PIOS_PPM_INPUT_INVALID 0 + +/* Local Variables */ static TIM_ICInitTypeDef TIM_ICInitStructure; static uint8_t PulseIndex; -static uint32_t PreviousValue; -static uint32_t CurrentValue; -static uint32_t CapturedValue; -static uint32_t CaptureValue[PIOS_PPM_NUM_INPUTS]; +static uint32_t PreviousTime; +static uint32_t CurrentTime; +static uint32_t DeltaTime; +static uint32_t CaptureValue[PIOS_PPM_IN_MAX_NUM_CHANNELS]; +static uint32_t CaptureValueNewFrame[PIOS_PPM_IN_MAX_NUM_CHANNELS]; +static uint32_t LargeCounter; +static int8_t NumChannels; +static int8_t NumChannelsPrevFrame; +static uint8_t NumChannelCounter; -static uint8_t SupervisorState = 0; -static uint32_t CapCounter[PIOS_PPM_NUM_INPUTS]; -static uint32_t CapCounterPrev[PIOS_PPM_NUM_INPUTS]; +static uint8_t supv_timer = 0; +static bool Tracking; +static bool Fresh; + +static void PIOS_PPM_Supervisor(uint32_t ppm_id); -/** -* Initialises all the LED's -*/ void PIOS_PPM_Init(void) { /* Flush counter variables */ int32_t i; PulseIndex = 0; - PreviousValue = 0; - CurrentValue = 0; - CapturedValue = 0; + PreviousTime = 0; + CurrentTime = 0; + DeltaTime = 0; + LargeCounter = 0; + NumChannels = -1; + NumChannelsPrevFrame = -1; + NumChannelCounter = 0; + Tracking = FALSE; + Fresh = FALSE; - for (i = 0; i < PIOS_PPM_NUM_INPUTS; i++) { + for (i = 0; i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) { CaptureValue[i] = 0; + CaptureValueNewFrame[i] = 0; } NVIC_InitTypeDef NVIC_InitStructure = pios_ppm_cfg.irq.init; @@ -85,7 +110,6 @@ void PIOS_PPM_Init(void) RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); break; #ifdef STM32F10X_HD - case (int32_t)TIM5: NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); @@ -121,85 +145,20 @@ void PIOS_PPM_Init(void) TIM_TimeBaseInit(pios_ppm_cfg.timer, &TIM_TimeBaseStructure); /* Enable the Capture Compare Interrupt Request */ - TIM_ITConfig(pios_ppm_cfg.timer, pios_ppm_cfg.ccr, ENABLE); + TIM_ITConfig(pios_ppm_cfg.timer, pios_ppm_cfg.ccr | TIM_IT_Update, ENABLE); /* Enable timers */ TIM_Cmd(pios_ppm_cfg.timer, ENABLE); - /* Supervisor Setup */ -#if (PIOS_PPM_SUPV_ENABLED) - /* Flush counter variables */ - for (i = 0; i < PIOS_PPM_NUM_INPUTS; i++) { - CapCounter[i] = 0; - } - for (i = 0; i < PIOS_PPM_NUM_INPUTS; i++) { - CapCounterPrev[i] = 0; - } - - NVIC_InitStructure = pios_ppmsv_cfg.irq.init; - - /* Enable appropriate clock to timer module */ - switch((int32_t) pios_ppmsv_cfg.timer) { - case (int32_t)TIM1: - NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn; - RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); - break; - case (int32_t)TIM2: - NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); - break; - case (int32_t)TIM3: - NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); - break; - case (int32_t)TIM4: - NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); - break; -#ifdef STM32F10X_HD - - case (int32_t)TIM5: - NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); - break; - case (int32_t)TIM6: - NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); - break; - case (int32_t)TIM7: - NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn; - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); - break; - case (int32_t)TIM8: - NVIC_InitStructure.NVIC_IRQChannel = TIM8_CC_IRQn; - RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE); - break; -#endif - } - - /* Configure interrupts */ - NVIC_Init(&NVIC_InitStructure); - - /* Time base configuration */ - TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); - TIM_TimeBaseStructure = pios_ppmsv_cfg.tim_base_init; - TIM_TimeBaseInit(pios_ppmsv_cfg.timer, &TIM_TimeBaseStructure); - - /* Enable the CCx Interrupt Request */ - TIM_ITConfig(pios_ppmsv_cfg.timer, pios_ppmsv_cfg.ccr, ENABLE); - - /* Clear update pending flag */ - TIM_ClearFlag(pios_ppmsv_cfg.timer, TIM_FLAG_Update); - - /* Enable counter */ - TIM_Cmd(pios_ppmsv_cfg.timer, ENABLE); -#endif - /* Setup local variable which stays in this scope */ /* Doing this here and using a local variable saves doing it in the ISR */ TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICInitStructure.TIM_ICFilter = 0x0; + + if (!PIOS_RTC_RegisterTickCallback(PIOS_PPM_Supervisor, 0)) { + PIOS_DEBUG_Assert(0); + } } /** @@ -208,13 +167,13 @@ void PIOS_PPM_Init(void) * \output -1 Channel not available * \output >0 Channel value */ -int32_t PIOS_PPM_Get(int8_t Channel) +static int32_t PIOS_PPM_Get(uint32_t rcvr_id, uint8_t channel) { /* Return error if channel not available */ - if (Channel >= PIOS_PPM_NUM_INPUTS) { + if (channel >= PIOS_PPM_IN_MAX_NUM_CHANNELS) { return -1; } - return CaptureValue[Channel]; + return CaptureValue[channel]; } /** @@ -224,75 +183,128 @@ int32_t PIOS_PPM_Get(int8_t Channel) */ void PIOS_PPM_irq_handler(void) { - /* Do this as it's more efficient */ + /* Timer Overflow Interrupt + * The time between timer overflows must be greater than the PPM + * frame period. If a full frame has not decoded in the between timer + * overflows then capture values should be cleared. + */ + + if (TIM_GetITStatus(pios_ppm_cfg.timer, TIM_IT_Update) == SET) { + /* Clear TIMx overflow interrupt pending bit */ + TIM_ClearITPendingBit(pios_ppm_cfg.timer, TIM_IT_Update); + + /* If sharing a timer with a servo output the ARR register will + be set according to the PWM period. When timer reaches the + ARR value a timer overflow interrupt will fire. We use the + interrupt accumulate a 32-bit timer. */ + LargeCounter = LargeCounter + pios_ppm_cfg.timer->ARR; + } + + /* Signal edge interrupt */ if (TIM_GetITStatus(pios_ppm_cfg.timer, pios_ppm_cfg.ccr) == SET) { - PreviousValue = CurrentValue; + PreviousTime = CurrentTime; + switch((int32_t) pios_ppm_cfg.ccr) { case (int32_t)TIM_IT_CC1: - CurrentValue = TIM_GetCapture1(pios_ppm_cfg.timer); + CurrentTime = TIM_GetCapture1(pios_ppm_cfg.timer); break; case (int32_t)TIM_IT_CC2: - CurrentValue = TIM_GetCapture2(pios_ppm_cfg.timer); + CurrentTime = TIM_GetCapture2(pios_ppm_cfg.timer); break; case (int32_t)TIM_IT_CC3: - CurrentValue = TIM_GetCapture3(pios_ppm_cfg.timer); + CurrentTime = TIM_GetCapture3(pios_ppm_cfg.timer); break; case (int32_t)TIM_IT_CC4: - CurrentValue = TIM_GetCapture4(pios_ppm_cfg.timer); + CurrentTime = TIM_GetCapture4(pios_ppm_cfg.timer); break; } - } - /* Clear TIMx Capture compare interrupt pending bit */ - TIM_ClearITPendingBit(pios_ppm_cfg.timer, pios_ppm_cfg.ccr); + /* Clear TIMx Capture compare interrupt pending bit */ + TIM_ClearITPendingBit(pios_ppm_cfg.timer, pios_ppm_cfg.ccr); - /* Capture computation */ - if (CurrentValue > PreviousValue) { - CapturedValue = (CurrentValue - PreviousValue); - } else { - CapturedValue = ((0xFFFF - PreviousValue) + CurrentValue); - } + /* Convert to 32-bit timer result */ + CurrentTime = CurrentTime + LargeCounter; - /* sync pulse */ - if (CapturedValue > 8000) { - PulseIndex = 0; - /* trying to detect bad pulses, not sure this is working correctly yet. I need a scope :P */ - } else if (CapturedValue > 750 && CapturedValue < 2500) { - if (PulseIndex < PIOS_PPM_NUM_INPUTS) { - CaptureValue[PulseIndex] = CapturedValue; - CapCounter[PulseIndex]++; - PulseIndex++; + /* Capture computation */ + DeltaTime = CurrentTime - PreviousTime; + + PreviousTime = CurrentTime; + + /* Sync pulse detection */ + if (DeltaTime > PIOS_PPM_IN_MIN_SYNC_PULSE_US) { + if (PulseIndex == NumChannelsPrevFrame + && PulseIndex >= PIOS_PPM_IN_MIN_NUM_CHANNELS + && PulseIndex <= PIOS_PPM_IN_MAX_NUM_CHANNELS) + { + /* If we see n simultaneous frames of the same + number of channels we save it as our frame size */ + if (NumChannelCounter < PIOS_PPM_STABLE_CHANNEL_COUNT) + NumChannelCounter++; + else + NumChannels = PulseIndex; + } else { + NumChannelCounter = 0; + } + + /* Check if the last frame was well formed */ + if (PulseIndex == NumChannels && Tracking) { + /* The last frame was well formed */ + for (uint32_t i = 0; i < NumChannels; i++) { + CaptureValue[i] = CaptureValueNewFrame[i]; + } + for (uint32_t i = NumChannels; + i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) { + CaptureValue[i] = PIOS_PPM_INPUT_INVALID; + } + } + + Fresh = TRUE; + Tracking = TRUE; + NumChannelsPrevFrame = PulseIndex; + PulseIndex = 0; + + /* We rely on the supervisor to set CaptureValue to invalid + if no valid frame is found otherwise we ride over it */ + + } else if (Tracking) { + /* Valid pulse duration 0.75 to 2.5 ms*/ + if (DeltaTime > PIOS_PPM_IN_MIN_CHANNEL_PULSE_US + && DeltaTime < PIOS_PPM_IN_MAX_CHANNEL_PULSE_US + && PulseIndex < PIOS_PPM_IN_MAX_NUM_CHANNELS) { + + CaptureValueNewFrame[PulseIndex] = DeltaTime; + PulseIndex++; + } else { + /* Not a valid pulse duration */ + Tracking = FALSE; + for (uint32_t i = 0; i < PIOS_PPM_IN_MAX_NUM_CHANNELS ; i++) { + CaptureValueNewFrame[i] = PIOS_PPM_INPUT_INVALID; + } + } } } } -/** -* This function handles TIM3 global interrupt request. -*/ -void PIOS_PPMSV_irq_handler(void) { - /* Clear timer interrupt pending bit */ - TIM_ClearITPendingBit(pios_ppmsv_cfg.timer, pios_ppmsv_cfg.ccr); - - /* Simple state machine */ - if (SupervisorState == 0) { - /* Save this states values */ - for (int32_t i = 0; i < PIOS_PPM_NUM_INPUTS; i++) { - CapCounterPrev[i] = CapCounter[i]; - } - - /* Move to next state */ - SupervisorState = 1; - } else { - /* See what channels have been updated */ - for (int32_t i = 0; i < PIOS_PPM_NUM_INPUTS; i++) { - if (CapCounter[i] == CapCounterPrev[i]) { - CaptureValue[i] = 0; - } - } - - /* Move to next state */ - SupervisorState = 0; +static void PIOS_PPM_Supervisor(uint32_t ppm_id) { + /* + * RTC runs at 625Hz so divide down the base rate so + * that this loop runs at 25Hz. + */ + if(++supv_timer < 25) { + return; } + supv_timer = 0; + + if (!Fresh) { + Tracking = FALSE; + + for (int32_t i = 0; i < PIOS_PPM_IN_MAX_NUM_CHANNELS ; i++) { + CaptureValue[i] = PIOS_PPM_INPUT_INVALID; + CaptureValueNewFrame[i] = PIOS_PPM_INPUT_INVALID; + } + } + + Fresh = FALSE; } #endif diff --git a/flight/PiOS/STM32F10x/pios_pwm.c b/flight/PiOS/STM32F10x/pios_pwm.c index c524b3d9f..433c272bb 100644 --- a/flight/PiOS/STM32F10x/pios_pwm.c +++ b/flight/PiOS/STM32F10x/pios_pwm.c @@ -34,15 +34,20 @@ #if defined(PIOS_INCLUDE_PWM) -/* Local Variables */ -static uint8_t CaptureState[PIOS_PWM_MAX_INPUTS]; -static uint16_t RiseValue[PIOS_PWM_MAX_INPUTS]; -static uint16_t FallValue[PIOS_PWM_MAX_INPUTS]; -static uint32_t CaptureValue[PIOS_PWM_MAX_INPUTS]; +/* Provide a RCVR driver */ +static int32_t PIOS_PWM_Get(uint32_t rcvr_id, uint8_t channel); -//static uint8_t SupervisorState = 0; -static uint32_t CapCounter[PIOS_PWM_MAX_INPUTS]; -//static uint32_t CapCounterPrev[MAX_CHANNELS]; +const struct pios_rcvr_driver pios_pwm_rcvr_driver = { + .read = PIOS_PWM_Get, +}; + +/* Local Variables */ +static uint8_t CaptureState[PIOS_PWM_NUM_INPUTS]; +static uint16_t RiseValue[PIOS_PWM_NUM_INPUTS]; +static uint16_t FallValue[PIOS_PWM_NUM_INPUTS]; +static uint32_t CaptureValue[PIOS_PWM_NUM_INPUTS]; + +static uint32_t CapCounter[PIOS_PWM_NUM_INPUTS]; /** * Initialises all the pins @@ -127,52 +132,6 @@ void PIOS_PWM_Init(void) /* Warning, I don't think this will work for multiple remaps at once */ GPIO_PinRemapConfig(pios_pwm_cfg.remap, ENABLE); } - -#if 0 - /* Supervisor Setup */ -#if (PIOS_PWM_SUPV_ENABLED) - /* Flush counter variables */ - for (i = 0; i < PIOS_PWM_NUM_INPUTS; i++) { - CapCounter[i] = 0; - } - for (i = 0; i < PIOS_PWM_NUM_INPUTS; i++) { - CapCounterPrev[i] = 0; - } - - /* Enable timer clock */ - PIOS_PWM_SUPV_TIMER_RCC_FUNC; - - /* Configure interrupts */ - NVIC_InitStructure.NVIC_IRQChannel = PIOS_PWM_SUPV_IRQ_CHANNEL; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); - - /* Time base configuration */ - TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); - TIM_TimeBaseStructure.TIM_Period = ((1000000 / PIOS_PWM_SUPV_HZ) - 1); - TIM_TimeBaseStructure.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1; /* For 1 uS accuracy */ - TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; - TIM_TimeBaseInit(PIOS_PWM_SUPV_TIMER, &TIM_TimeBaseStructure); - - /* Enable the CC2 Interrupt Request */ - TIM_ITConfig(PIOS_PWM_SUPV_TIMER, TIM_IT_Update, ENABLE); - - /* Clear update pending flag */ - TIM_ClearFlag(TIM2, TIM_FLAG_Update); - - /* Enable counter */ - TIM_Cmd(PIOS_PWM_SUPV_TIMER, ENABLE); -#endif - - /* Setup local variable which stays in this scope */ - /* Doing this here and using a local variable saves doing it in the ISR */ - TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; - TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; - TIM_ICInitStructure.TIM_ICFilter = 0x0; -#endif } /** @@ -181,13 +140,13 @@ void PIOS_PWM_Init(void) * \output -1 Channel not available * \output >0 Channel value */ -int32_t PIOS_PWM_Get(int8_t Channel) +static int32_t PIOS_PWM_Get(uint32_t rcvr_id, uint8_t channel) { /* Return error if channel not available */ - if (Channel >= pios_pwm_cfg.num_channels) { + if (channel >= pios_pwm_cfg.num_channels) { return -1; } - return CaptureValue[Channel]; + return CaptureValue[channel]; } void PIOS_PWM_irq_handler(TIM_TypeDef * timer) @@ -254,84 +213,6 @@ void PIOS_PWM_irq_handler(TIM_TypeDef * timer) } } -#if 0 -/** -* Handle TIM5 global interrupt request -*/ -void TIM5_IRQHandler(void) -{ - /* Do this as it's more efficient */ - if (TIM_GetITStatus(PIOS_PWM_TIM_PORT[2], PIOS_PWM_TIM_CCR[2]) == SET) { - if (CaptureState[2] == 0) { - RiseValue[2] = TIM_GetCapture1(PIOS_PWM_TIM_PORT[2]); - } else { - FallValue[2] = TIM_GetCapture1(PIOS_PWM_TIM_PORT[2]); - } - - /* Clear TIM3 Capture compare interrupt pending bit */ - TIM_ClearITPendingBit(PIOS_PWM_TIM_PORT[2], PIOS_PWM_TIM_CCR[2]); - - /* Simple rise or fall state machine */ - if (CaptureState[2] == 0) { - /* Switch states */ - CaptureState[2] = 1; - - /* Switch polarity of input capture */ - TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; - TIM_ICInitStructure.TIM_Channel = PIOS_PWM_TIM_CHANNEL[2]; - TIM_ICInit(PIOS_PWM_TIM_PORT[2], &TIM_ICInitStructure); - - } else { - /* Capture computation */ - if (FallValue[2] > RiseValue[2]) { - CaptureValue[2] = (FallValue[2] - RiseValue[2]); - } else { - CaptureValue[2] = ((0xFFFF - RiseValue[2]) + FallValue[2]); - } - - /* Switch states */ - CaptureState[2] = 0; - - /* Increase supervisor counter */ - CapCounter[2]++; - - /* Switch polarity of input capture */ - TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; - TIM_ICInitStructure.TIM_Channel = PIOS_PWM_TIM_CHANNEL[2]; - TIM_ICInit(PIOS_PWM_TIM_PORT[2], &TIM_ICInitStructure); - } - } -} - -/** -* This function handles TIM3 global interrupt request. -*/ -PIOS_PWM_SUPV_IRQ_FUNC { - /* Clear timer interrupt pending bit */ - TIM_ClearITPendingBit(PIOS_PWM_SUPV_TIMER, TIM_IT_Update); - - /* Simple state machine */ - if (SupervisorState == 0) { - /* Save this states values */ - for (int32_t i = 0; i < PIOS_PWM_NUM_INPUTS; i++) { - CapCounterPrev[i] = CapCounter[i]; - } - - /* Move to next state */ - SupervisorState = 1; - } else { - /* See what channels have been updated */ - for (int32_t i = 0; i < PIOS_PWM_NUM_INPUTS; i++) { - if (CapCounter[i] == CapCounterPrev[i]) { - CaptureValue[i] = 0; - } - } - - /* Move to next state */ - SupervisorState = 0; - } -} -#endif #endif /** diff --git a/flight/PiOS/STM32F10x/pios_rtc.c b/flight/PiOS/STM32F10x/pios_rtc.c index 0a950e913..b80a9e0d1 100644 --- a/flight/PiOS/STM32F10x/pios_rtc.c +++ b/flight/PiOS/STM32F10x/pios_rtc.c @@ -32,19 +32,39 @@ #include "pios.h" #if defined(PIOS_INCLUDE_RTC) +#include -void PIOS_RTC_Start() +#ifndef PIOS_RTC_PRESCALER +#define PIOS_RTC_PRESCALER 100 +#endif + +struct rtc_callback_entry { + void (*fn)(uint32_t); + uint32_t data; +}; + +#define PIOS_RTC_MAX_CALLBACKS 3 +struct rtc_callback_entry rtc_callback_list[PIOS_RTC_MAX_CALLBACKS]; +static uint8_t rtc_callback_next = 0; + +void PIOS_RTC_Init(const struct pios_rtc_cfg * cfg) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE); PWR_BackupAccessCmd(ENABLE); - RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128); + RCC_RTCCLKConfig(cfg->clksrc); RCC_RTCCLKCmd(ENABLE); RTC_WaitForLastTask(); RTC_WaitForSynchro(); RTC_WaitForLastTask(); - RTC_SetPrescaler(0); // counting at 8e6 / 128 + + /* Configure and enable the RTC Second interrupt */ + NVIC_Init(&cfg->irq.init); + RTC_ITConfig( RTC_IT_SEC, ENABLE ); + RTC_WaitForLastTask(); + + RTC_SetPrescaler(cfg->prescaler); RTC_WaitForLastTask(); RTC_SetCounter(0); RTC_WaitForLastTask(); @@ -55,7 +75,52 @@ uint32_t PIOS_RTC_Counter() return RTC_GetCounter(); } +/* FIXME: This shouldn't use hard-coded clock rates, dividers or prescalers. + * Should get these from the cfg struct passed to init. + */ +float PIOS_RTC_Rate() +{ + return (float) (8e6 / 128) / (1 + PIOS_RTC_PRESCALER); +} +float PIOS_RTC_MsPerTick() +{ + return 1000.0f / PIOS_RTC_Rate(); +} + +/* TODO: This needs a mutex around rtc_callbacks[] */ +bool PIOS_RTC_RegisterTickCallback(void (*fn)(uint32_t id), uint32_t data) +{ + struct rtc_callback_entry * cb; + if (rtc_callback_next >= PIOS_RTC_MAX_CALLBACKS) { + return false; + } + + cb = &rtc_callback_list[rtc_callback_next++]; + + cb->fn = fn; + cb->data = data; + return true; +} + +void PIOS_RTC_irq_handler (void) +{ + if (RTC_GetITStatus(RTC_IT_SEC)) + { + /* Call all registered callbacks */ + for (uint8_t i = 0; i < rtc_callback_next; i++) { + struct rtc_callback_entry * cb = &rtc_callback_list[i]; + if (cb->fn) { + (cb->fn)(cb->data); + } + } + + /* Wait until last write operation on RTC registers has finished */ + RTC_WaitForLastTask(); + /* Clear the RTC Second interrupt */ + RTC_ClearITPendingBit(RTC_IT_SEC); + } +} #endif /** diff --git a/flight/PiOS/STM32F10x/pios_sbus.c b/flight/PiOS/STM32F10x/pios_sbus.c new file mode 100644 index 000000000..a80fe8fe3 --- /dev/null +++ b/flight/PiOS/STM32F10x/pios_sbus.c @@ -0,0 +1,223 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_SBUS Futaba S.Bus receiver functions + * @brief Code to read Futaba S.Bus input + * @{ + * + * @file pios_sbus.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. + * @brief USART commands. Inits USARTs, controls USARTs & Interrupt handlers. (STM32 dependent) + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Project Includes */ +#include "pios.h" +#include "pios_sbus_priv.h" + +#if defined(PIOS_INCLUDE_SBUS) + +/* Global Variables */ + +/* Provide a RCVR driver */ +static int32_t PIOS_SBUS_Get(uint32_t rcvr_id, uint8_t channel); + +const struct pios_rcvr_driver pios_sbus_rcvr_driver = { + .read = PIOS_SBUS_Get, +}; + +/* Local Variables */ +static uint16_t channel_data[SBUS_NUMBER_OF_CHANNELS]; +static uint8_t received_data[SBUS_FRAME_LENGTH - 2]; +static uint8_t receive_timer; +static uint8_t failsafe_timer; +static uint8_t frame_found; + +static void PIOS_SBUS_Supervisor(uint32_t sbus_id); + +/** + * reset_channels() function clears all channel data in case of + * lost signal or explicit failsafe flag from the S.Bus data stream + */ +static void reset_channels(void) +{ + for (int i = 0; i < SBUS_NUMBER_OF_CHANNELS; i++) { + channel_data[i] = 0; + } +} + +/** + * unroll_channels() function computes channel_data[] from received_data[] + * For efficiency it unrolls first 8 channels without loops. If other + * 8 channels are needed they can be unrolled using the same code + * starting from s[11] instead of s[0]. Two extra digital channels are + * accessible using (s[22] & SBUS_FLAG_DGx) logical expressions. + */ +static void unroll_channels(void) +{ + uint8_t *s = received_data; + uint16_t *d = channel_data; + +#if (SBUS_NUMBER_OF_CHANNELS != 8) +#error Current S.Bus code unrolls only first 8 channels +#endif + +#define F(v,s) ((v) >> s) & 0x7ff + *d++ = F(s[0] | s[1] << 8, 0); + *d++ = F(s[1] | s[2] << 8, 3); + *d++ = F(s[2] | s[3] << 8 | s[4] << 16, 6); + *d++ = F(s[4] | s[5] << 8, 1); + *d++ = F(s[5] | s[6] << 8, 4); + *d++ = F(s[6] | s[7] << 8 | s[8] << 16, 7); + *d++ = F(s[8] | s[9] << 8, 2); + *d++ = F(s[9] | s[10] << 8, 5); +} + +/** + * process_byte() function processes incoming byte from S.Bus stream + */ +static void process_byte(uint8_t b) +{ + static uint8_t byte_count; + + if (frame_found == 0) { + /* no frame found yet, waiting for start byte */ + if (b == SBUS_SOF_BYTE) { + byte_count = 0; + frame_found = 1; + } + } else { + /* do not store start and end of frame bytes */ + if (byte_count < SBUS_FRAME_LENGTH - 2) { + /* store next byte */ + received_data[byte_count++] = b; + } else { + if (b == SBUS_EOF_BYTE) { + /* full frame received */ + uint8_t flags = received_data[SBUS_FRAME_LENGTH - 3]; + if (flags & SBUS_FLAG_FL) { + /* frame lost, do not update */ + } else if (flags & SBUS_FLAG_FS) { + /* failsafe flag active */ + reset_channels(); + } else { + /* data looking good */ + unroll_channels(); + failsafe_timer = 0; + } + } else { + /* discard whole frame */ + } + + /* prepare for the next frame */ + frame_found = 0; + } + } +} + +static uint16_t PIOS_SBUS_RxInCallback(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * need_yield) +{ + /* process byte(s) and clear receive timer */ + for (uint8_t i = 0; i < buf_len; i++) { + process_byte(buf[i]); + receive_timer = 0; + } + + /* Always signal that we can accept another byte */ + if (headroom) { + *headroom = SBUS_FRAME_LENGTH; + } + + /* We never need a yield */ + *need_yield = false; + + /* Always indicate that all bytes were consumed */ + return (buf_len); +} + +/** + * Initialise S.Bus receiver interface + */ +int32_t PIOS_SBUS_Init(uint32_t * sbus_id, const struct pios_sbus_cfg *cfg, const struct pios_com_driver * driver, uint32_t lower_id) +{ + /* Enable inverter clock and enable the inverter */ + (*cfg->gpio_clk_func)(cfg->gpio_clk_periph, ENABLE); + GPIO_Init(cfg->inv.gpio, &cfg->inv.init); + GPIO_WriteBit(cfg->inv.gpio, + cfg->inv.init.GPIO_Pin, + cfg->gpio_inv_enable); + + (driver->bind_rx_cb)(lower_id, PIOS_SBUS_RxInCallback, 0); + + if (!PIOS_RTC_RegisterTickCallback(PIOS_SBUS_Supervisor, 0)) { + PIOS_Assert(0); + } + + return (0); +} + +/** + * Get the value of an input channel + * \param[in] channel Number of the channel desired (zero based) + * \output -1 channel not available + * \output >0 channel value + */ +static int32_t PIOS_SBUS_Get(uint32_t rcvr_id, uint8_t channel) +{ + /* return error if channel is not available */ + if (channel >= SBUS_NUMBER_OF_CHANNELS) { + return -1; + } + return channel_data[channel]; +} + +/** + * Input data supervisor is called periodically and provides + * two functions: frame syncing and failsafe triggering. + * + * S.Bus frames come at 7ms (HS) or 14ms (FS) rate at 100000bps. RTC + * timer is running at 625Hz (1.6ms). So with divider 2 it gives + * 3.2ms pause between frames which is good for both S.Bus data rates. + * + * Data receive function must clear the receive_timer to confirm new + * data reception. If no new data received in 100ms, we must call the + * failsafe function which clears all channels. + */ +static void PIOS_SBUS_Supervisor(uint32_t sbus_id) +{ + /* waiting for new frame if no bytes were received in 3.2ms */ + if (++receive_timer > 2) { + receive_timer = 0; + frame_found = 0; + } + + /* activate failsafe if no frames have arrived in 102.4ms */ + if (++failsafe_timer > 64) { + reset_channels(); + failsafe_timer = 0; + } +} + +#endif + +/** + * @} + * @} + */ diff --git a/flight/PiOS/STM32F10x/pios_servo.c b/flight/PiOS/STM32F10x/pios_servo.c index 04c731a5d..229f371ce 100644 --- a/flight/PiOS/STM32F10x/pios_servo.c +++ b/flight/PiOS/STM32F10x/pios_servo.c @@ -6,25 +6,25 @@ * @brief Code to do set RC servo output * @{ * - * @file pios_servo.c + * @file pios_servo.c * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @brief RC Servo routines (STM32 dependent) * @see The GNU Public License (GPL) Version 3 - * + * *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -34,7 +34,6 @@ /* Private Function Prototypes */ -uint16_t servo_positions[8]; /** * Initialise Servos */ @@ -42,15 +41,15 @@ void PIOS_Servo_Init(void) { #ifndef PIOS_ENABLE_DEBUG_PINS #if defined(PIOS_INCLUDE_SERVO) - - + + for (uint8_t i = 0; i < pios_servo_cfg.num_channels; i++) { GPIO_InitTypeDef GPIO_InitStructure = pios_servo_cfg.gpio_init; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = pios_servo_cfg.tim_base_init; TIM_OCInitTypeDef TIM_OCInitStructure = pios_servo_cfg.tim_oc_init; struct pios_servo_channel channel = pios_servo_cfg.channels[i]; - + /* Enable appropriate clock to timer module */ switch((int32_t) channel.timer) { case (int32_t)TIM1: @@ -82,12 +81,12 @@ void PIOS_Servo_Init(void) /* Enable GPIO */ GPIO_InitStructure.GPIO_Pin = channel.pin; GPIO_Init(channel.port, &GPIO_InitStructure); - + /* Enable time base */ TIM_TimeBaseInit(channel.timer, &TIM_TimeBaseStructure); - + channel.timer->PSC = (PIOS_MASTER_CLOCK / 1000000) - 1; - + /* Set up for output compare function */ switch(channel.channel) { case TIM_Channel_1: @@ -107,19 +106,19 @@ void PIOS_Servo_Init(void) TIM_OC4PreloadConfig(channel.timer, TIM_OCPreload_Enable); break; } - + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); TIM_ARRPreloadConfig(channel.timer, ENABLE); TIM_CtrlPWMOutputs(channel.timer, ENABLE); - TIM_Cmd(channel.timer, ENABLE); - - } - + TIM_Cmd(channel.timer, ENABLE); + + } + if(pios_servo_cfg.remap) { /* Warning, I don't think this will work for multiple remaps at once */ GPIO_PinRemapConfig(pios_servo_cfg.remap, ENABLE); } - + #endif // PIOS_INCLUDE_SERVO #endif // PIOS_ENABLE_DEBUG_PINS @@ -138,19 +137,19 @@ void PIOS_Servo_SetHz(uint16_t * speeds, uint8_t banks) TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1; - + uint8_t set = 0; - - for(uint8_t i = 0; (i < pios_servo_cfg.num_channels) && (set < banks); i++) { + + for(uint8_t i = 0; (i < pios_servo_cfg.num_channels) && (set < banks); i++) { bool new = true; struct pios_servo_channel channel = pios_servo_cfg.channels[i]; - + /* See if any previous channels use that same timer */ - for(uint8_t j = 0; (j < i) && new; j++) + for(uint8_t j = 0; (j < i) && new; j++) new &= channel.timer != pios_servo_cfg.channels[j].timer; - + if(new) { - TIM_TimeBaseStructure.TIM_Period = ((1000000 / speeds[set]) - 1); + TIM_TimeBaseStructure.TIM_Period = ((1000000 / speeds[set]) - 1); TIM_TimeBaseInit(channel.timer, &TIM_TimeBaseStructure); set++; } @@ -162,7 +161,7 @@ void PIOS_Servo_SetHz(uint16_t * speeds, uint8_t banks) /** * Set servo position * \param[in] Servo Servo number (0-7) -* \param[in] Position Servo position in milliseconds +* \param[in] Position Servo position in microseconds */ void PIOS_Servo_Set(uint8_t Servo, uint16_t Position) { @@ -174,22 +173,18 @@ void PIOS_Servo_Set(uint8_t Servo, uint16_t Position) switch(pios_servo_cfg.channels[Servo].channel) { case TIM_Channel_1: - servo_positions[Servo] = Position; TIM_SetCompare1(pios_servo_cfg.channels[Servo].timer, Position); break; case TIM_Channel_2: - servo_positions[Servo] = Position; TIM_SetCompare2(pios_servo_cfg.channels[Servo].timer, Position); break; case TIM_Channel_3: - servo_positions[Servo] = Position; TIM_SetCompare3(pios_servo_cfg.channels[Servo].timer, Position); break; case TIM_Channel_4: - servo_positions[Servo] = Position; TIM_SetCompare4(pios_servo_cfg.channels[Servo].timer, Position); break; - } + } } #endif // PIOS_INCLUDE_SERVO #endif // PIOS_ENABLE_DEBUG_PINS diff --git a/flight/PiOS/STM32F10x/pios_spektrum.c b/flight/PiOS/STM32F10x/pios_spektrum.c index 16b9b9883..8b0f38c6b 100644 --- a/flight/PiOS/STM32F10x/pios_spektrum.c +++ b/flight/PiOS/STM32F10x/pios_spektrum.c @@ -34,87 +34,71 @@ #include "pios_spektrum_priv.h" #if defined(PIOS_INCLUDE_SPEKTRUM) -#if defined(PIOS_INCLUDE_PWM) -#error "Both PWM and SPEKTRUM input defined, choose only one" -#endif -#if defined(PIOS_COM_AUX) -#error "AUX com cannot be used with SPEKTRUM" -#endif + +/** + * @Note Framesyncing: + * The code resets the watchdog timer whenever a single byte is received, so what watchdog code + * is never called if regularly getting bytes. + * RTC timer is running @625Hz, supervisor timer has divider 5 so frame sync comes every 1/125Hz=8ms. + * Good for both 11ms and 22ms framecycles + */ /* Global Variables */ -/* Local Variables, use pios_usart */ -static uint16_t CaptureValue[12],CaptureValueTemp[12]; -static uint8_t prev_byte = 0xFF, sync = 0, bytecount = 0, datalength=0, frame_error=0, byte_array[20] = { 0 }; +/* Provide a RCVR driver */ +static int32_t PIOS_SPEKTRUM_Get(uint32_t rcvr_id, uint8_t channel); +const struct pios_rcvr_driver pios_spektrum_rcvr_driver = { + .read = PIOS_SPEKTRUM_Get, +}; + +/* Local Variables */ +static uint16_t CaptureValue[PIOS_SPEKTRUM_NUM_INPUTS],CaptureValueTemp[PIOS_SPEKTRUM_NUM_INPUTS]; +static uint8_t prev_byte = 0xFF, sync = 0, bytecount = 0, datalength=0, frame_error=0, byte_array[20] = { 0 }; uint8_t sync_of = 0; +uint16_t supv_timer=0; + +static void PIOS_SPEKTRUM_Supervisor(uint32_t spektrum_id); +static bool PIOS_SPEKTRUM_Bind(const struct pios_spektrum_cfg * cfg); +static int32_t PIOS_SPEKTRUM_Decode(uint8_t b); + +static uint16_t PIOS_SPEKTRUM_RxInCallback(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * need_yield) +{ + /* process byte(s) and clear receive timer */ + for (uint8_t i = 0; i < buf_len; i++) { + PIOS_SPEKTRUM_Decode(buf[i]); + supv_timer = 0; + } + + /* Always signal that we can accept another byte */ + if (headroom) { + *headroom = 1; + } + + /* We never need a yield */ + *need_yield = false; + + /* Always indicate that all bytes were consumed */ + return (buf_len); +} /** -* Initialise the onboard USARTs +* Bind and Initialise Spektrum satellite receiver */ -void PIOS_SPEKTRUM_Init(void) +int32_t PIOS_SPEKTRUM_Init(uint32_t * spektrum_id, const struct pios_spektrum_cfg *cfg, const struct pios_com_driver * driver, uint32_t lower_id, bool bind) { // TODO: need setting flag for bind on next powerup - if (0) { - PIOS_SPEKTRUM_Bind(); + if (bind) { + PIOS_SPEKTRUM_Bind(cfg); } - NVIC_InitTypeDef NVIC_InitStructure = pios_spektrum_cfg.irq.init; - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = pios_spektrum_cfg.tim_base_init; + (driver->bind_rx_cb)(lower_id, PIOS_SPEKTRUM_RxInCallback, 0); - - /* Enable appropriate clock to timer module */ - switch((int32_t) pios_spektrum_cfg.timer) { - case (int32_t)TIM1: - NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn; - RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); - break; - case (int32_t)TIM2: - NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); - break; - case (int32_t)TIM3: - NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); - break; - case (int32_t)TIM4: - NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); - break; -#ifdef STM32F10X_HD - - case (int32_t)TIM5: - NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); - break; - case (int32_t)TIM6: - NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); - break; - case (int32_t)TIM7: - NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn; - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); - break; - case (int32_t)TIM8: - NVIC_InitStructure.NVIC_IRQChannel = TIM8_CC_IRQn; - RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE); - break; -#endif + if (!PIOS_RTC_RegisterTickCallback(PIOS_SPEKTRUM_Supervisor, 0)) { + PIOS_DEBUG_Assert(0); } - NVIC_Init(&NVIC_InitStructure); - /* Configure timer clocks */ - TIM_InternalClockConfig(pios_spektrum_cfg.timer); - TIM_TimeBaseInit(pios_spektrum_cfg.timer, &TIM_TimeBaseStructure); - - /* Enable the Capture Compare Interrupt Request */ - TIM_ITConfig(pios_spektrum_cfg.timer, pios_spektrum_cfg.ccr, ENABLE); - - /* Clear update pending flag */ - TIM_ClearFlag(pios_spektrum_cfg.timer, TIM_FLAG_Update); - - /* Enable timers */ - TIM_Cmd(pios_spektrum_cfg.timer, ENABLE); + return (0); } /** @@ -123,59 +107,42 @@ void PIOS_SPEKTRUM_Init(void) * \output -1 Channel not available * \output >0 Channel value */ -int16_t PIOS_SPEKTRUM_Get(int8_t Channel) +static int32_t PIOS_SPEKTRUM_Get(uint32_t rcvr_id, uint8_t channel) { /* Return error if channel not available */ - if (Channel >= 12) { + if (channel >= PIOS_SPEKTRUM_NUM_INPUTS) { return -1; } - return CaptureValue[Channel]; + return CaptureValue[channel]; } /** * Spektrum bind function -* \output 1 Successful bind -* \output 0 Bind failed -* \note Applications shouldn't call these functions directly +* \output true Successful bind +* \output false Bind failed */ -uint8_t PIOS_SPEKTRUM_Bind(void) +static bool PIOS_SPEKTRUM_Bind(const struct pios_spektrum_cfg * cfg) { - GPIO_InitTypeDef GPIO_InitStructure = pios_spektrum_cfg.gpio_init; - GPIO_InitStructure.GPIO_Pin = pios_spektrum_cfg.pin; - GPIO_Init(pios_spektrum_cfg.port, &GPIO_InitStructure); +#define BIND_PULSES 5 - pios_spektrum_cfg.port->BRR = pios_spektrum_cfg.pin; - //PIOS_DELAY_WaitmS(75); - /* RX line, drive high for 10us */ - pios_spektrum_cfg.port->BSRR = pios_spektrum_cfg.pin; - PIOS_DELAY_WaituS(10); - /* RX line, drive low for 120us */ - pios_spektrum_cfg.port->BRR = pios_spektrum_cfg.pin; - PIOS_DELAY_WaituS(120); - /* RX line, drive high for 120us */ - pios_spektrum_cfg.port->BSRR = pios_spektrum_cfg.pin; - PIOS_DELAY_WaituS(120); - /* RX line, drive low for 120us */ - pios_spektrum_cfg.port->BRR = pios_spektrum_cfg.pin; - PIOS_DELAY_WaituS(120); - /* RX line, drive high for 120us */ - pios_spektrum_cfg.port->BSRR = pios_spektrum_cfg.pin; - PIOS_DELAY_WaituS(120); - /* RX line, drive low for 120us */ - pios_spektrum_cfg.port->BRR = pios_spektrum_cfg.pin; - PIOS_DELAY_WaituS(120); - /* RX line, drive high for 120us */ - pios_spektrum_cfg.port->BSRR = pios_spektrum_cfg.pin; - PIOS_DELAY_WaituS(120); - /* RX line, drive low for 120us */ - pios_spektrum_cfg.port->BRR = pios_spektrum_cfg.pin; - PIOS_DELAY_WaituS(120); - /* RX line, drive high for 120us */ - pios_spektrum_cfg.port->BSRR = pios_spektrum_cfg.pin; - PIOS_DELAY_WaituS(120); + GPIO_Init(cfg->bind.gpio, &cfg->bind.init); + /* RX line, set high */ + GPIO_SetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); + + /* on CC works upto 140ms, I guess bind window is around 20-140ms after powerup */ + PIOS_DELAY_WaitmS(60); + + for (int i = 0; i < BIND_PULSES ; i++) { + /* RX line, drive low for 120us */ + GPIO_ResetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); + PIOS_DELAY_WaituS(120); + /* RX line, drive high for 120us */ + GPIO_SetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); + PIOS_DELAY_WaituS(120); + } /* RX line, set input and wait for data, PIOS_SPEKTRUM_Init */ - return 1; + return true; } /** @@ -186,7 +153,7 @@ uint8_t PIOS_SPEKTRUM_Bind(void) * \return -2 if buffer full (retry) * \note Applications shouldn't call these functions directly */ -int32_t PIOS_SPEKTRUM_Decode(uint8_t b) +static int32_t PIOS_SPEKTRUM_Decode(uint8_t b) { static uint16_t channel = 0; /*, sync_word = 0;*/ uint8_t channeln = 0, frame = 0; @@ -240,7 +207,7 @@ int32_t PIOS_SPEKTRUM_Decode(uint8_t b) { frame_error=1; } - if (channeln < 12 && !frame_error) + if (channeln < PIOS_SPEKTRUM_NUM_INPUTS && !frame_error) CaptureValueTemp[channeln] = data; } } @@ -251,7 +218,7 @@ int32_t PIOS_SPEKTRUM_Decode(uint8_t b) sync_of = 0; if (!frame_error) { - for(int i=0;i<12;i++) + for(int i=0;iregs->SR; - volatile uint8_t b = pios_spektrum_cfg.pios_usart_spektrum_cfg->regs->DR; - - /* check if RXNE flag is set */ - if (sr & USART_SR_RXNE) { - if (PIOS_SPEKTRUM_Decode(b) < 0) { - /* Here we could add some error handling */ - } - } - - if (sr & USART_SR_TXE) { // check if TXE flag is set - /* Disable TXE interrupt (TXEIE=0) */ - USART_ITConfig(pios_spektrum_cfg.pios_usart_spektrum_cfg->regs, USART_IT_TXE, DISABLE); - } - /* clear "watchdog" timer */ - TIM_SetCounter(pios_spektrum_cfg.timer, 0); -} - /** -* This function handles TIM6 global interrupt request. -*/ -void PIOS_SPEKTRUM_irq_handler() { -//PIOS_SPEKTRUM_SUPV_IRQ_FUNC { - /* Clear timer interrupt pending bit */ - TIM_ClearITPendingBit(pios_spektrum_cfg.timer, TIM_IT_Update); - - /* sync between frames */ - sync = 0; - bytecount = 0; - prev_byte = 0xFF; - frame_error=0; - sync_of++; - /* watchdog activated */ - if (sync_of > 12) { - /* signal lost */ - sync_of = 0; - for (int i = 0; i < 12; i++) - { - CaptureValue[i] = 0; - CaptureValueTemp[i] = 0; + *@brief This function is called between frames and when a spektrum word hasnt been decoded for too long + *@brief clears the channel values + */ +static void PIOS_SPEKTRUM_Supervisor(uint32_t spektrum_id) { + /* 125hz */ + supv_timer++; + if(supv_timer > 5) { + /* sync between frames */ + sync = 0; + bytecount = 0; + prev_byte = 0xFF; + frame_error = 0; + sync_of++; + /* watchdog activated after 100ms silence */ + if (sync_of > 12) { + /* signal lost */ + sync_of = 0; + for (int i = 0; i < PIOS_SPEKTRUM_NUM_INPUTS; i++) { + CaptureValue[i] = 0; + CaptureValueTemp[i] = 0; + } } + supv_timer = 0; } } diff --git a/flight/PiOS/STM32F10x/pios_sys.c b/flight/PiOS/STM32F10x/pios_sys.c index 2170c7811..cc35194e7 100644 --- a/flight/PiOS/STM32F10x/pios_sys.c +++ b/flight/PiOS/STM32F10x/pios_sys.c @@ -186,7 +186,8 @@ int32_t PIOS_SYS_SerialNumberGet(char *str) void NVIC_Configuration(void) { /* Set the Vector Table base address as specified in .ld file */ - NVIC_SetVectorTable(PIOS_NVIC_VECTTAB_FLASH, 0x0); + extern void *pios_isr_vector_table_base; + NVIC_SetVectorTable((uint32_t)&pios_isr_vector_table_base, 0x0); /* 4 bits for Interrupt priorities so no sub priorities */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); diff --git a/flight/PiOS/STM32F10x/pios_usart.c b/flight/PiOS/STM32F10x/pios_usart.c index 36b1b0c7a..8582344b5 100644 --- a/flight/PiOS/STM32F10x/pios_usart.c +++ b/flight/PiOS/STM32F10x/pios_usart.c @@ -38,17 +38,31 @@ /* Provide a COM driver */ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud); -static int32_t PIOS_USART_TxBufferPutMoreNonBlocking(uint32_t usart_id, const uint8_t *buffer, uint16_t len); -static int32_t PIOS_USART_TxBufferPutMore(uint32_t usart_id, const uint8_t *buffer, uint16_t len); -static int32_t PIOS_USART_RxBufferGet(uint32_t usart_id); -static int32_t PIOS_USART_RxBufferUsed(uint32_t usart_id); +static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context); +static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context); +static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail); +static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail); const struct pios_com_driver pios_usart_com_driver = { - .set_baud = PIOS_USART_ChangeBaud, - .tx_nb = PIOS_USART_TxBufferPutMoreNonBlocking, - .tx = PIOS_USART_TxBufferPutMore, - .rx = PIOS_USART_RxBufferGet, - .rx_avail = PIOS_USART_RxBufferUsed, + .set_baud = PIOS_USART_ChangeBaud, + .tx_start = PIOS_USART_TxStart, + .rx_start = PIOS_USART_RxStart, + .bind_tx_cb = PIOS_USART_RegisterTxCallback, + .bind_rx_cb = PIOS_USART_RegisterRxCallback, +}; + +enum pios_usart_dev_magic { + PIOS_USART_DEV_MAGIC = 0x11223344, +}; + +struct pios_usart_dev { + enum pios_usart_dev_magic magic; + const struct pios_usart_cfg * cfg; + + pios_com_callback rx_in_cb; + uint32_t rx_in_context; + pios_com_callback tx_out_cb; + uint32_t tx_out_context; }; static bool PIOS_USART_validate(struct pios_usart_dev * usart_dev) @@ -85,6 +99,34 @@ static struct pios_usart_dev * PIOS_USART_alloc(void) } #endif +/* Bind Interrupt Handlers + * + * Map all valid USART IRQs to the common interrupt handler + * and provide storage for a 32-bit device id IRQ to map + * each physical IRQ to a specific registered device instance. + */ +static void PIOS_USART_generic_irq_handler(uint32_t usart_id); + +static uint32_t PIOS_USART_1_id; +void USART1_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_1_irq_handler"))); +static void PIOS_USART_1_irq_handler (void) +{ + PIOS_USART_generic_irq_handler (PIOS_USART_1_id); +} + +static uint32_t PIOS_USART_2_id; +void USART2_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_2_irq_handler"))); +static void PIOS_USART_2_irq_handler (void) +{ + PIOS_USART_generic_irq_handler (PIOS_USART_2_id); +} + +static uint32_t PIOS_USART_3_id; +void USART3_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_3_irq_handler"))); +static void PIOS_USART_3_irq_handler (void) +{ + PIOS_USART_generic_irq_handler (PIOS_USART_3_id); +} /** * Initialise a single USART device @@ -102,10 +144,6 @@ int32_t PIOS_USART_Init(uint32_t * usart_id, const struct pios_usart_cfg * cfg) /* Bind the configuration to the device instance */ usart_dev->cfg = cfg; - /* Clear buffer counters */ - fifoBuf_init(&usart_dev->rx, usart_dev->rx_buffer, sizeof(usart_dev->rx_buffer)); - fifoBuf_init(&usart_dev->tx, usart_dev->tx_buffer, sizeof(usart_dev->tx_buffer)); - /* Enable the USART Pins Software Remapping */ if (usart_dev->cfg->remap) { GPIO_PinRemapConfig(usart_dev->cfg->remap, ENABLE); @@ -134,6 +172,17 @@ int32_t PIOS_USART_Init(uint32_t * usart_id, const struct pios_usart_cfg * cfg) *usart_id = (uint32_t)usart_dev; /* Configure USART Interrupts */ + switch ((uint32_t)usart_dev->cfg->regs) { + case (uint32_t)USART1: + PIOS_USART_1_id = (uint32_t)usart_dev; + break; + case (uint32_t)USART2: + PIOS_USART_2_id = (uint32_t)usart_dev; + break; + case (uint32_t)USART3: + PIOS_USART_3_id = (uint32_t)usart_dev; + break; + } NVIC_Init(&usart_dev->cfg->irq.init); USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE); USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE); @@ -147,6 +196,25 @@ out_fail: return(-1); } +static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail) +{ + struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + PIOS_Assert(valid); + + USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE); +} +static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail) +{ + struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + PIOS_Assert(valid); + + USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE); +} + /** * Changes the baud rate of the USART peripheral without re-initialising. * \param[in] usart_id USART name (GPS, TELEM, AUX) @@ -157,7 +225,7 @@ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud) struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; bool valid = PIOS_USART_validate(usart_dev); - PIOS_Assert(valid) + PIOS_Assert(valid); USART_InitTypeDef USART_InitStructure; @@ -171,206 +239,83 @@ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud) USART_Init(usart_dev->cfg->regs, &USART_InitStructure); } -/** -* Returns number of used bytes in receive buffer -* \param[in] USART USART name -* \return > 0: number of used bytes -* \return 0 if USART not available -*/ -static int32_t PIOS_USART_RxBufferUsed(uint32_t usart_id) +static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context) { struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; bool valid = PIOS_USART_validate(usart_dev); - PIOS_Assert(valid) + PIOS_Assert(valid); - return (fifoBuf_getUsed(&usart_dev->rx)); + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usart_dev->rx_in_context = context; + usart_dev->rx_in_cb = rx_in_cb; } -/** -* Gets a byte from the receive buffer -* \param[in] USART USART name -* \return -1 if no new byte available -* \return >= 0: actual byte received -*/ -static int32_t PIOS_USART_RxBufferGet(uint32_t usart_id) +static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context) { struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; bool valid = PIOS_USART_validate(usart_dev); - PIOS_Assert(valid) + PIOS_Assert(valid); - if (fifoBuf_getUsed(&usart_dev->rx) == 0) { - /* Nothing new in the buffer */ - return -1; - } - - /* get byte - this operation should be atomic! */ - uint8_t b = fifoBuf_getByte(&usart_dev->rx); - - /* Return received byte */ - return b; + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usart_dev->tx_out_context = context; + usart_dev->tx_out_cb = tx_out_cb; } -/** -* puts a byte onto the receive buffer -* \param[in] USART USART name -* \param[in] b byte which should be put into Rx buffer -* \return 0 if no error -* \return -1 if buffer full (retry) -*/ -static int32_t PIOS_USART_RxBufferPut(uint32_t usart_id, uint8_t b) +static void PIOS_USART_generic_irq_handler(uint32_t usart_id) { struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; bool valid = PIOS_USART_validate(usart_dev); - PIOS_Assert(valid) - - if (fifoBuf_getFree(&usart_dev->rx) < 1) { - /* Buffer full (retry) */ - return -1; - } - - /* Copy received byte into receive buffer */ - /* This operation should be atomic! */ - fifoBuf_putByte(&usart_dev->rx, b); - - /* No error */ - return 0; -} - -/** -* returns number of used bytes in transmit buffer -* \param[in] USART USART name -* \return number of used bytes -* \return 0 if USART not available -*/ -static int32_t PIOS_USART_TxBufferUsed(uint32_t usart_id) -{ - struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; - - bool valid = PIOS_USART_validate(usart_dev); - PIOS_Assert(valid) - - return (fifoBuf_getUsed(&usart_dev->tx)); -} - -/** -* gets a byte from the transmit buffer -* \param[in] USART USART name -* \return -1 if no new byte available -* \return >= 0: transmitted byte -*/ -static int32_t PIOS_USART_TxBufferGet(uint32_t usart_id) -{ - struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; - - bool valid = PIOS_USART_validate(usart_dev); - PIOS_Assert(valid) - - if (fifoBuf_getUsed(&usart_dev->tx) == 0) { - /* Nothing new in the buffer */ - return -1; - } - - /* get byte - this operation should be atomic! */ - PIOS_IRQ_Disable(); - uint8_t b = fifoBuf_getByte(&usart_dev->tx); - PIOS_IRQ_Enable(); - - /* Return received byte */ - return b; -} - -/** -* puts more than one byte onto the transmit buffer (used for atomic sends) -* \param[in] USART USART name -* \param[in] *buffer pointer to buffer to be sent -* \param[in] len number of bytes to be sent -* \return 0 if no error -* \return -1 if buffer full or cannot get all requested bytes (retry) -*/ -static int32_t PIOS_USART_TxBufferPutMoreNonBlocking(uint32_t usart_id, const uint8_t *buffer, uint16_t len) -{ - struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; - - bool valid = PIOS_USART_validate(usart_dev); - PIOS_Assert(valid) - - if (len >= fifoBuf_getFree(&usart_dev->tx)) { - /* Buffer cannot accept all requested bytes (retry) */ - return -1; - } - - /* Copy bytes to be transmitted into transmit buffer */ - /* This operation should be atomic! */ - PIOS_IRQ_Disable(); - - uint16_t used = fifoBuf_getUsed(&usart_dev->tx); - fifoBuf_putData(&usart_dev->tx,buffer,len); - - if (used == 0) { - /* enable sending when buffer was previously empty */ - USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE); - } - - PIOS_IRQ_Enable(); - - /* No error */ - return 0; -} - -/** -* puts more than one byte onto the transmit buffer (used for atomic sends)
-* (blocking function) -* \param[in] USART USART name -* \param[in] *buffer pointer to buffer to be sent -* \param[in] len number of bytes to be sent -* \return 0 if no error -*/ -static int32_t PIOS_USART_TxBufferPutMore(uint32_t usart_id, const uint8_t *buffer, uint16_t len) -{ - int32_t rc; - - while ((rc = PIOS_USART_TxBufferPutMoreNonBlocking(usart_id, buffer, len)) == -1); - - return rc; -} - -void PIOS_USART_IRQ_Handler(uint32_t usart_id) -{ - struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; - - bool valid = PIOS_USART_validate(usart_dev); - PIOS_Assert(valid) + PIOS_Assert(valid); /* Force read of dr after sr to make sure to clear error flags */ volatile uint16_t sr = usart_dev->cfg->regs->SR; volatile uint8_t dr = usart_dev->cfg->regs->DR; /* Check if RXNE flag is set */ + bool rx_need_yield = false; if (sr & USART_SR_RXNE) { - if (PIOS_USART_RxBufferPut(usart_id, dr) < 0) { - /* Here we could add some error handling */ + uint8_t byte = dr; + if (usart_dev->rx_in_cb) { + (void) (usart_dev->rx_in_cb)(usart_dev->rx_in_context, &byte, 1, NULL, &rx_need_yield); } } /* Check if TXE flag is set */ + bool tx_need_yield = false; if (sr & USART_SR_TXE) { - if (PIOS_USART_TxBufferUsed(usart_id) > 0) { - int32_t b = PIOS_USART_TxBufferGet(usart_id); + if (usart_dev->tx_out_cb) { + uint8_t b; + uint16_t bytes_to_send; - if (b < 0) { - /* Here we could add some error handling */ - usart_dev->cfg->regs->DR = 0xff; + bytes_to_send = (usart_dev->tx_out_cb)(usart_dev->tx_out_context, &b, 1, NULL, &tx_need_yield); + + if (bytes_to_send > 0) { + /* Send the byte we've been given */ + usart_dev->cfg->regs->DR = b; } else { - usart_dev->cfg->regs->DR = b & 0xff; + /* No bytes to send, disable TXE interrupt */ + USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE); } } else { - /* Disable TXE interrupt (TXEIE=0) */ + /* No bytes to send, disable TXE interrupt */ USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE); } } + +#if defined(PIOS_INCLUDE_FREERTOS) + if (rx_need_yield || tx_need_yield) { + vPortYieldFromISR(); + } +#endif /* PIOS_INCLUDE_FREERTOS */ } #endif diff --git a/flight/PiOS/STM32F10x/pios_usb_hid.c b/flight/PiOS/STM32F10x/pios_usb_hid.c index d66b92598..0ebca1320 100644 --- a/flight/PiOS/STM32F10x/pios_usb_hid.c +++ b/flight/PiOS/STM32F10x/pios_usb_hid.c @@ -36,76 +36,106 @@ #include "usb_lib.h" #include "pios_usb_hid_desc.h" #include "stm32f10x.h" -#include "fifo_buffer.h" + +#include "pios_usb_hid_priv.h" #if defined(PIOS_INCLUDE_USB_HID) -#if defined(PIOS_INCLUDE_FREERTOS) -#define USE_FREERTOS -#endif - -static int32_t PIOS_USB_HID_TxBufferPutMoreNonBlocking(uint32_t usbcom_id, const uint8_t *buffer, uint16_t len); -static int32_t PIOS_USB_HID_TxBufferPutMore(uint32_t usbcom_id, const uint8_t *buffer, uint16_t len); -static int32_t PIOS_USB_HID_RxBufferGet(uint32_t usbcom_id); -static int32_t PIOS_USB_HID_RxBufferUsed(uint32_t usbcom_id); +static void PIOS_USB_HID_TxStart(uint32_t usbcom_id, uint16_t tx_bytes_avail); +static void PIOS_USB_HID_RxStart(uint32_t usbcom_id, uint16_t rx_bytes_avail); +static void PIOS_USB_HID_RegisterTxCallback(uint32_t usbcom_id, pios_com_callback tx_out_cb, uint32_t context); +static void PIOS_USB_HID_RegisterRxCallback(uint32_t usbcom_id, pios_com_callback rx_in_cb, uint32_t context); const struct pios_com_driver pios_usb_com_driver = { - .tx_nb = PIOS_USB_HID_TxBufferPutMoreNonBlocking, - .tx = PIOS_USB_HID_TxBufferPutMore, - .rx = PIOS_USB_HID_RxBufferGet, - .rx_avail = PIOS_USB_HID_RxBufferUsed, + .tx_start = PIOS_USB_HID_TxStart, + .rx_start = PIOS_USB_HID_RxStart, + .bind_tx_cb = PIOS_USB_HID_RegisterTxCallback, + .bind_rx_cb = PIOS_USB_HID_RegisterRxCallback, }; -// TODO: Eventually replace the transmit and receive buffers with bigger ring bufers -// so there isn't hte 64 byte cap in place by the USB interrupt packet definition +enum pios_usb_hid_dev_magic { + PIOS_USB_HID_DEV_MAGIC = 0xAABBCCDD, +}; + +struct pios_usb_hid_dev { + enum pios_usb_hid_dev_magic magic; + const struct pios_usb_hid_cfg * cfg; + + pios_com_callback rx_in_cb; + uint32_t rx_in_context; + pios_com_callback tx_out_cb; + uint32_t tx_out_context; + + uint8_t rx_packet_buffer[PIOS_USB_HID_DATA_LENGTH + 2]; + uint8_t tx_packet_buffer[PIOS_USB_HID_DATA_LENGTH + 2]; +}; + +static bool PIOS_USB_HID_validate(struct pios_usb_hid_dev * usb_hid_dev) +{ + return (usb_hid_dev->magic == PIOS_USB_HID_DEV_MAGIC); +} + +#if defined(PIOS_INCLUDE_FREERTOS) && 0 +static struct pios_usb_hid_dev * PIOS_USB_HID_alloc(void) +{ + struct pios_usb_hid_dev * usb_hid_dev; + + usb_hid_dev = (struct pios_usb_hid_dev *)malloc(sizeof(*usb_hid_dev)); + if (!usb_hid_dev) return(NULL); + + usb_hid_dev->magic = PIOS_USB_HID_DEV_MAGIC; + return(usb_hid_dev); +} +#else +static struct pios_usb_hid_dev pios_usb_hid_devs[PIOS_USB_HID_MAX_DEVS]; +static uint8_t pios_usb_hid_num_devs; +static struct pios_usb_hid_dev * PIOS_USB_HID_alloc(void) +{ + struct pios_usb_hid_dev * usb_hid_dev; + + if (pios_usb_hid_num_devs >= PIOS_USB_HID_MAX_DEVS) { + return (NULL); + } + + usb_hid_dev = &pios_usb_hid_devs[pios_usb_hid_num_devs++]; + usb_hid_dev->magic = PIOS_USB_HID_DEV_MAGIC; + + return (usb_hid_dev); +} +#endif /* Rx/Tx status */ static uint8_t transfer_possible = 0; -static uint8_t rx_packet_buffer[PIOS_USB_HID_DATA_LENGTH + 2] = { 0 }; -static uint8_t tx_packet_buffer[PIOS_USB_HID_DATA_LENGTH + 2] = { 0 }; - -uint8_t rx_pios_fifo_buf[PIOS_USB_RX_BUFFER_SIZE] __attribute__ ((aligned(4))); // align to 32-bit to try and provide speed improvement -t_fifo_buffer rx_pios_fifo_buffer; - -uint8_t tx_pios_fifo_buf[PIOS_USB_TX_BUFFER_SIZE] __attribute__ ((aligned(4))); // align to 32-bit to try and provide speed improvement -t_fifo_buffer tx_pios_fifo_buffer; - -#if defined(USE_FREERTOS) -xSemaphoreHandle pios_usb_tx_semaphore; -#endif /** * Initialises USB COM layer - * \param[in] mode currently only mode 0 supported * \return < 0 if initialisation failed * \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions */ -int32_t PIOS_USB_HID_Init(uint32_t mode) +static uint32_t pios_usb_hid_id; +int32_t PIOS_USB_HID_Init(uint32_t * usb_hid_id, const struct pios_usb_hid_cfg * cfg) { - /* Currently only mode 0 supported */ - if (mode != 0) { - /* Unsupported mode */ - return -1; - } + PIOS_Assert(usb_hid_id); + PIOS_Assert(cfg); - fifoBuf_init(&rx_pios_fifo_buffer, rx_pios_fifo_buf, sizeof(rx_pios_fifo_buf)); - fifoBuf_init(&tx_pios_fifo_buffer, tx_pios_fifo_buf, sizeof(tx_pios_fifo_buf)); + struct pios_usb_hid_dev * usb_hid_dev; + + usb_hid_dev = (struct pios_usb_hid_dev *) PIOS_USB_HID_alloc(); + if (!usb_hid_dev) goto out_fail; + + /* Bind the configuration to the device instance */ + usb_hid_dev->cfg = cfg; PIOS_USB_HID_Reenumerate(); - /* Create semaphore before enabling interrupts */ -#if defined(USE_FREERTOS) - vSemaphoreCreateBinary(pios_usb_tx_semaphore); -#endif - + /* + * This is a horrible hack to make this available to + * the interrupt callbacks. This should go away ASAP. + */ + pios_usb_hid_id = (uint32_t) usb_hid_dev; + /* Enable the USB Interrupts */ - /* 2 bit for pre-emption priority, 2 bits for subpriority */ - NVIC_InitTypeDef NVIC_InitStructure; - NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); + NVIC_Init(&usb_hid_dev->cfg->irq.init); /* Select USBCLK source */ RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5); @@ -122,7 +152,12 @@ int32_t PIOS_USB_HID_Init(uint32_t mode) USB_Init(); USB_SIL_Init(); + *usb_hid_id = (uint32_t) usb_hid_dev; + return 0; /* No error */ + +out_fail: + return(-1); } /** @@ -201,127 +236,118 @@ int32_t PIOS_USB_HID_CheckAvailable(uint8_t id) return (PIOS_USB_DETECT_GPIO_PORT->IDR & PIOS_USB_DETECT_GPIO_PIN) != 0 && transfer_possible ? 1 : 0; } -void sendChunk() +static void PIOS_USB_HID_SendReport(struct pios_usb_hid_dev * usb_hid_dev) { + uint16_t bytes_to_tx; - uint32_t size = fifoBuf_getUsed(&tx_pios_fifo_buffer); - if ((size > 0) && (GetEPTxStatus(ENDP1) != EP_TX_VALID)) { - if (size > PIOS_USB_HID_DATA_LENGTH) - size = PIOS_USB_HID_DATA_LENGTH; + if (!usb_hid_dev->tx_out_cb) { + return; + } + + bool need_yield = false; #ifdef USB_HID - fifoBuf_getData(&tx_pios_fifo_buffer, &tx_packet_buffer[1], size + 1); - tx_packet_buffer[0] = 1; /* report ID */ + bytes_to_tx = (usb_hid_dev->tx_out_cb)(usb_hid_dev->tx_out_context, + &usb_hid_dev->tx_packet_buffer[1], + sizeof(usb_hid_dev->tx_packet_buffer)-1, + NULL, + &need_yield); #else - fifoBuf_getData(&tx_pios_fifo_buffer, &tx_packet_buffer[2], size); - tx_packet_buffer[0] = 1; /* report ID */ - tx_packet_buffer[1] = size; /* valid data length */ - + bytes_to_tx = (usb_hid_dev->tx_out_cb)(usb_hid_dev->tx_out_context, + &usb_hid_dev->tx_packet_buffer[2], + sizeof(usb_hid_dev->tx_packet_buffer)-2, + NULL, + &need_yield); #endif - - UserToPMABufferCopy((uint8_t *) tx_packet_buffer, GetEPTxAddr(EP1_IN & 0x7F), size + 2); - SetEPTxCount((EP1_IN & 0x7F), PIOS_USB_HID_DATA_LENGTH + 2); - - /* Send Buffer */ - SetEPTxValid(ENDP1); + if (bytes_to_tx == 0) { + return; } -} + /* Always set type as report ID */ + usb_hid_dev->tx_packet_buffer[0] = 1; -/** - * Puts more than one byte onto the transmit buffer (used for atomic sends) - * \param[in] *buffer pointer to buffer which should be transmitted - * \param[in] len number of bytes which should be transmitted - * \return 0 if no error - * \return -1 if port unavailable (disconnected) - * \return -2 if too many bytes to be send - * \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions - */ -static int32_t PIOS_USB_HID_TxBufferPutMoreNonBlocking(uint32_t usbcom_id, const uint8_t * buffer, uint16_t len) -{ - uint16_t ret; - - if(!transfer_possible) - return -1; - - if (len > fifoBuf_getFree(&tx_pios_fifo_buffer)) { - sendChunk(); /* Try and send what's in the buffer though */ - return -2; /* Cannot send all requested bytes */ - } - - /* don't check returned bytes because it should always succeed */ - /* after previous thread and no meaningful way to deal with the */ - /* case it only buffers half the bytes */ -#if defined(USE_FREERTOS) - if(!xSemaphoreTake(pios_usb_tx_semaphore,10 / portTICK_RATE_MS)) - return -3; +#ifdef USB_HID + UserToPMABufferCopy(usb_hid_dev->tx_packet_buffer, GetEPTxAddr(EP1_IN & 0x7F), bytes_to_tx + 1); +#else + usb_hid_dev->tx_packet_buffer[1] = bytes_to_tx; + UserToPMABufferCopy(usb_hid_dev->tx_packet_buffer, GetEPTxAddr(EP1_IN & 0x7F), bytes_to_tx + 2); #endif + /* Is this correct? Why do we always send the whole buffer? */ + SetEPTxCount((EP1_IN & 0x7F), sizeof(usb_hid_dev->tx_packet_buffer)); + SetEPTxValid(ENDP1); - ret = fifoBuf_putData(&tx_pios_fifo_buffer, buffer, len); - -#if defined(USE_FREERTOS) - xSemaphoreGive(pios_usb_tx_semaphore); -#endif - - sendChunk(); - - return 0; -} - -/** - * Puts more than one byte onto the transmit buffer (used for atomic sends)
- * (Blocking Function) - * \param[in] *buffer pointer to buffer which should be transmitted - * \param[in] len number of bytes which should be transmitted - * \return 0 if no error - * \return -1 if too many bytes to be send - * \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions - */ -static int32_t PIOS_USB_HID_TxBufferPutMore(uint32_t usbcom_id, const uint8_t *buffer, uint16_t len) -{ - if(len > (fifoBuf_getUsed(&tx_pios_fifo_buffer) + fifoBuf_getFree(&tx_pios_fifo_buffer))) - return -1; - - uint32_t error; - while ((error = PIOS_USB_HID_TxBufferPutMoreNonBlocking(usbcom_id, buffer, len)) == -2) { #if defined(PIOS_INCLUDE_FREERTOS) - taskYIELD(); -#endif + if (need_yield) { + vPortYieldFromISR(); } - - return error; +#endif /* PIOS_INCLUDE_FREERTOS */ } -/** - * Gets a byte from the receive buffer - * \return -1 if no new byte available - * \return >= 0: received byte - * \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions - */ -static int32_t PIOS_USB_HID_RxBufferGet(uint32_t usbcom_id) -{ - uint8_t read; +static void PIOS_USB_HID_RxStart(uint32_t usbcom_id, uint16_t rx_bytes_avail) { + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)usbcom_id; - if(fifoBuf_getUsed(&rx_pios_fifo_buffer) == 0) - return -1; + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + PIOS_Assert(valid); - read = fifoBuf_getByte(&rx_pios_fifo_buffer); + if (!transfer_possible) { + return; + } // If endpoint was stalled and there is now space make it valid - if ((GetEPRxStatus(ENDP1) != EP_RX_VALID) && (fifoBuf_getFree(&rx_pios_fifo_buffer) > 62)) { + PIOS_IRQ_Disable(); + if ((GetEPRxStatus(ENDP1) != EP_RX_VALID) && + (rx_bytes_avail > PIOS_USB_HID_DATA_LENGTH)) { SetEPRxStatus(ENDP1, EP_RX_VALID); } - return read; + PIOS_IRQ_Enable(); } -/** - * Returns number of used bytes in receive buffer - * \return > 0: number of used bytes - * \return 0 nothing available - * \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions - */ -static int32_t PIOS_USB_HID_RxBufferUsed(uint32_t usbcom_id) +static void PIOS_USB_HID_TxStart(uint32_t usbcom_id, uint16_t tx_bytes_avail) { - return fifoBuf_getUsed(&rx_pios_fifo_buffer); + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)usbcom_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + PIOS_Assert(valid); + + if (!transfer_possible) { + return; + } + + if (GetEPTxStatus(ENDP1) == EP_TX_VALID) { + /* Endpoint is already transmitting */ + return; + } + + PIOS_USB_HID_SendReport(usb_hid_dev); +} + +static void PIOS_USB_HID_RegisterRxCallback(uint32_t usbcom_id, pios_com_callback rx_in_cb, uint32_t context) +{ + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)usbcom_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usb_hid_dev->rx_in_context = context; + usb_hid_dev->rx_in_cb = rx_in_cb; +} + +static void PIOS_USB_HID_RegisterTxCallback(uint32_t usbcom_id, pios_com_callback tx_out_cb, uint32_t context) +{ + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)usbcom_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usb_hid_dev->tx_out_context = context; + usb_hid_dev->tx_out_cb = tx_out_cb; } /** @@ -330,7 +356,16 @@ static int32_t PIOS_USB_HID_RxBufferUsed(uint32_t usbcom_id) */ void PIOS_USB_HID_EP1_IN_Callback(void) { - sendChunk(); + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)pios_usb_hid_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + PIOS_Assert(valid); + + if (!transfer_possible) { + return; + } + + PIOS_USB_HID_SendReport(usb_hid_dev); } /** @@ -338,28 +373,58 @@ void PIOS_USB_HID_EP1_IN_Callback(void) */ void PIOS_USB_HID_EP1_OUT_Callback(void) { + struct pios_usb_hid_dev * usb_hid_dev = (struct pios_usb_hid_dev *)pios_usb_hid_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + PIOS_Assert(valid); + uint32_t DataLength = 0; /* Read received data (63 bytes) */ /* Get the number of received data on the selected Endpoint */ DataLength = GetEPRxCount(ENDP1 & 0x7F); + if (DataLength > sizeof(usb_hid_dev->rx_packet_buffer)) { + DataLength = sizeof(usb_hid_dev->rx_packet_buffer); + } /* Use the memory interface function to write to the selected endpoint */ - PMAToUserBufferCopy((uint8_t *) &rx_packet_buffer[0], GetEPRxAddr(ENDP1 & 0x7F), DataLength); + PMAToUserBufferCopy((uint8_t *) usb_hid_dev->rx_packet_buffer, GetEPRxAddr(ENDP1 & 0x7F), DataLength); + + if (!usb_hid_dev->rx_in_cb) { + /* No Rx call back registered, disable the receiver */ + SetEPRxStatus(ENDP1, EP_RX_NAK); + return; + } /* The first byte is report ID (not checked), the second byte is the valid data length */ + uint16_t headroom; + bool need_yield = false; #ifdef USB_HID - fifoBuf_putData(&rx_pios_fifo_buffer, &rx_packet_buffer[1], PIOS_USB_HID_DATA_LENGTH + 1); + (usb_hid_dev->rx_in_cb)(usb_hid_dev->rx_in_context, + &usb_hid_dev->rx_packet_buffer[1], + sizeof(usb_hid_dev->rx_packet_buffer)-1, + &headroom, + &need_yield); #else - fifoBuf_putData(&rx_pios_fifo_buffer, &rx_packet_buffer[2], rx_packet_buffer[1]); + (usb_hid_dev->rx_in_cb)(usb_hid_dev->rx_in_context, + &usb_hid_dev->rx_packet_buffer[2], + usb_hid_dev->rx_packet_buffer[1], + &headroom, + &need_yield); #endif - - // Only reactivate endpoint if available space in buffer - if (fifoBuf_getFree(&rx_pios_fifo_buffer) > 62) { + if (headroom > PIOS_USB_HID_DATA_LENGTH) { + /* We have room for a maximum length message */ SetEPRxStatus(ENDP1, EP_RX_VALID); } else { + /* Not enough room left for a message, apply backpressure */ SetEPRxStatus(ENDP1, EP_RX_NAK); } + +#if defined(PIOS_INCLUDE_FREERTOS) + if (need_yield) { + vPortYieldFromISR(); + } +#endif /* PIOS_INCLUDE_FREERTOS */ } #endif diff --git a/flight/PiOS/STM32F10x/startup_stm32f10x_HD_OP.S b/flight/PiOS/STM32F10x/startup_stm32f10x_HD_OP.S index a252adf76..159a9dd66 100644 --- a/flight/PiOS/STM32F10x/startup_stm32f10x_HD_OP.S +++ b/flight/PiOS/STM32F10x/startup_stm32f10x_HD_OP.S @@ -36,6 +36,8 @@ .global g_pfnVectors .global SystemInit_ExtMemCtl_Dummy .global Default_Handler +.global xPortIncreaseHeapSize +.global Stack_Change /* start address for the initialization values of the .data section. defined in linker script */ @@ -71,6 +73,35 @@ Reset_Handler: /* restore original stack pointer */ LDR r0, =_irq_stack_top MSR msp, r0 + LDR r2, =_init_stack_top + MSR psp, r2 + /* check if irq and init stack are the same */ + /* if they are, we don't do stack swap */ + /* and lets bypass the monitoring as well for now */ + cmp r0, r2 + beq SectionBssInit +/* DO + * - stay in thread process mode + * - stay in privilege level + * - use process stack + */ + movs r0, #2 + MSR control, r0 + ISB +/* Fill IRQ stack for watermark monitoring */ + ldr r2, =_irq_stack_end + b LoopFillIRQStack + +FillIRQStack: + movw r3, #0xA5A5 + str r3, [r2], #4 + +LoopFillIRQStack: + ldr r3, = _irq_stack_top + cmp r2, r3 + bcc FillIRQStack + +SectionBssInit: /* Copy the data segment initializers from flash to SRAM */ movs r1, #0 b LoopCopyDataInit @@ -100,9 +131,37 @@ LoopFillZerobss: bcc FillZerobss /* Call the application's entry point.*/ bl main - bx lr +/* will never return here */ + bx lr .size Reset_Handler, .-Reset_Handler +/** + * @brief This is the code that swaps stack (from end of heap to irq_stack). + * Also reclaim the heap that was used as a stack. + * @param None + * @retval : None +*/ + .section .text.Stack_Change + .weak Stack_Change + .type Stack_Change, %function +Stack_Change: + mov r4, lr +/* Switches stack back momentarily to MSP */ + movs r0, #0 + msr control, r0 +Heap_Reclaim: +/* add heap_post_rtos to the heap (if the capability/function exist) */ +/* Also claim the unused memory (between end of heap to end of memory */ +/* CAREFULL: the heap section must be the last section in RAM in order this to work */ + ldr r0, = _init_stack_size + ldr r1, = _eheap_post_rtos + ldr r2, = _eram + subs r2, r2, r1 + adds r0, r0, r2 + bl xPortIncreaseHeapSize + bx r4 + .size Stack_Change, .-Stack_Change + /** * @brief Dummy SystemInit_ExtMemCtl function * @param None @@ -114,12 +173,12 @@ SystemInit_ExtMemCtl_Dummy: .size SystemInit_ExtMemCtl_Dummy, .-SystemInit_ExtMemCtl_Dummy /** - * @brief This is the code that gets called when the processor receives an + * @brief This is the code that gets called when the processor receives an * unexpected interrupt. This simply enters an infinite loop, preserving * the system state for examination by a debugger. * - * @param None - * @retval : None + * @param None + * @retval : None */ .section .text.Default_Handler,"ax",%progbits Default_Handler: @@ -272,13 +331,13 @@ g_pfnVectors: .weak NMI_Handler .thumb_set NMI_Handler,Default_Handler - + .weak HardFault_Handler .thumb_set HardFault_Handler,Default_Handler - + .weak MemManage_Handler .thumb_set MemManage_Handler,Default_Handler - + .weak BusFault_Handler .thumb_set BusFault_Handler,Default_Handler diff --git a/flight/PiOS/STM32F10x/startup_stm32f10x_MD_CC.S b/flight/PiOS/STM32F10x/startup_stm32f10x_MD_CC.S index 21c7c7b29..828462ab6 100644 --- a/flight/PiOS/STM32F10x/startup_stm32f10x_MD_CC.S +++ b/flight/PiOS/STM32F10x/startup_stm32f10x_MD_CC.S @@ -33,6 +33,8 @@ .global g_pfnVectors .global Default_Handler +.global xPortIncreaseHeapSize +.global Stack_Change /* start address for the initialization values of the .data section. defined in linker script */ @@ -61,6 +63,47 @@ defined in linker script */ .type Reset_Handler, %function Reset_Handler: +/* + * From COrtex-M3 reference manual: + * - Handler IRQ always use SP_main + * - Process use SP_main or SP_process + * Here, we will use beginning of SRAM for IRQ (SP_main) + * and end of heap for initialization (SP_process). + * Once the schedule starts, all threads will use their own stack + * from heap and NOBOBY should use SP_process again. + */ + /* Do set/reset the stack pointers */ + LDR r0, =_irq_stack_top + MSR msp, r0 + LDR r2, =_init_stack_top + MSR psp, r2 + /* check if irq and init stack are the same */ + /* if they are, we don't do stack swap */ + /* and lets bypass the monitoring as well for now */ + cmp r0, r2 + beq SectionBssInit +/* DO + * - stay in thread process mode + * - stay in privilege level + * - use process stack + */ + movs r0, #2 + MSR control, r0 + ISB +/* Fill IRQ stack for watermark monitoring */ + ldr r2, =_irq_stack_end + b LoopFillIRQStack + +FillIRQStack: + movw r3, #0xA5A5 + str r3, [r2], #4 + +LoopFillIRQStack: + ldr r3, = _irq_stack_top + cmp r2, r3 + bcc FillIRQStack + +SectionBssInit: /* Copy the data segment initializers from flash to SRAM */ movs r1, #0 b LoopCopyDataInit @@ -90,16 +133,45 @@ LoopFillZerobss: bcc FillZerobss /* Call the application's entry point.*/ bl main +/* will never return here */ bx lr .size Reset_Handler, .-Reset_Handler /** - * @brief This is the code that gets called when the processor receives an + * @brief This is the code that swaps stack (from end of heap to irq_stack). + * Also reclaim the heap that was used as a stack. + * @param None + * @retval : None +*/ + .section .text.Stack_Change + .weak Stack_Change + .type Stack_Change, %function +Stack_Change: + mov r4, lr +/* Switches stack back momentarily to MSP */ + movs r0, #0 + msr control, r0 +Heap_Reclaim: +/* add heap_post_rtos to the heap (if the capability/function exist) */ +/* Also claim the unused memory (between end of heap to end of memory */ +/* CAREFULL: the heap section must be the last section in RAM in order this to work */ + ldr r0, = _init_stack_size + ldr r1, = _eheap_post_rtos + ldr r2, = _eram + subs r2, r2, r1 + adds r0, r0, r2 + bl xPortIncreaseHeapSize + bx r4 + .size Stack_Change, .-Stack_Change + + +/** + * @brief This is the code that gets called when the processor receives an * unexpected interrupt. This simply enters an infinite loop, preserving * the system state for examination by a debugger. * - * @param None - * @retval : None + * @param None + * @retval : None */ .section .text.Default_Handler,"ax",%progbits Default_Handler: @@ -119,7 +191,7 @@ Infinite_Loop: g_pfnVectors: - .word _estack + .word _irq_stack_top .word Reset_Handler .word NMI_Handler .word HardFault_Handler diff --git a/flight/PiOS/inc/pios_adxl345.h b/flight/PiOS/inc/pios_adxl345.h index 1e5c83274..1e0b89f6d 100644 --- a/flight/PiOS/inc/pios_adxl345.h +++ b/flight/PiOS/inc/pios_adxl345.h @@ -16,6 +16,7 @@ #define ADXL_MULTI_BIT 0x40 #define ADXL_X0_ADDR 0x32 +#define ADXL_FIFOSTATUS_ADDR 0x39 #define ADXL_RATE_ADDR 0x2C #define ADXL_RATE_100 0x0A @@ -52,5 +53,6 @@ void PIOS_ADXL345_FifoDepth(uint8_t depth); void PIOS_ADXL345_Attach(uint32_t spi_id); void PIOS_ADXL345_Init(); uint8_t PIOS_ADXL345_Read(struct pios_adxl345_data * data); +uint8_t PIOS_ADXL345_FifoElements(); #endif diff --git a/flight/PiOS/inc/pios_board_info.h b/flight/PiOS/inc/pios_board_info.h new file mode 100644 index 000000000..f2ff58fb4 --- /dev/null +++ b/flight/PiOS/inc/pios_board_info.h @@ -0,0 +1,17 @@ +#define PIOS_BOARD_INFO_BLOB_MAGIC 0xBDBDBDBD + +struct pios_board_info { + uint32_t magic; + uint8_t board_type; + uint8_t board_rev; + uint8_t bl_rev; + uint8_t hw_type; + uint32_t fw_base; + uint32_t fw_size; + uint32_t desc_base; + uint32_t desc_size; + uint32_t ee_base; + uint32_t ee_size; +} __attribute__((packed)); + +extern const struct pios_board_info pios_board_info_blob; diff --git a/flight/PiOS/inc/pios_com.h b/flight/PiOS/inc/pios_com.h index 0af333d7b..cbee33735 100644 --- a/flight/PiOS/inc/pios_com.h +++ b/flight/PiOS/inc/pios_com.h @@ -32,17 +32,19 @@ #ifndef PIOS_COM_H #define PIOS_COM_H +typedef uint16_t (*pios_com_callback)(uint32_t context, uint8_t * buf, uint16_t buf_len, uint16_t * headroom, bool * task_woken); + struct pios_com_driver { - void (*init)(uint32_t id); - void (*set_baud)(uint32_t id, uint32_t baud); - int32_t (*tx_nb)(uint32_t id, const uint8_t *buffer, uint16_t len); - int32_t (*tx)(uint32_t id, const uint8_t *buffer, uint16_t len); - int32_t (*rx)(uint32_t id); - int32_t (*rx_avail)(uint32_t id); + void (*init)(uint32_t id); + void (*set_baud)(uint32_t id, uint32_t baud); + void (*tx_start)(uint32_t id, uint16_t tx_bytes_avail); + void (*rx_start)(uint32_t id, uint16_t rx_bytes_avail); + void (*bind_rx_cb)(uint32_t id, pios_com_callback rx_in_cb, uint32_t context); + void (*bind_tx_cb)(uint32_t id, pios_com_callback tx_out_cb, uint32_t context); }; /* Public Functions */ -extern int32_t PIOS_COM_Init(uint32_t * com_id, const struct pios_com_driver * driver, const uint32_t lower_id); +extern int32_t PIOS_COM_Init(uint32_t * com_id, const struct pios_com_driver * driver, uint32_t lower_id, uint8_t * rx_buffer, uint16_t rx_buffer_len, uint8_t * tx_buffer, uint16_t tx_buffer_len); extern int32_t PIOS_COM_ChangeBaud(uint32_t com_id, uint32_t baud); extern int32_t PIOS_COM_SendCharNonBlocking(uint32_t com_id, char c); extern int32_t PIOS_COM_SendChar(uint32_t com_id, char c); @@ -52,7 +54,7 @@ extern int32_t PIOS_COM_SendStringNonBlocking(uint32_t com_id, const char *str); extern int32_t PIOS_COM_SendString(uint32_t com_id, const char *str); extern int32_t PIOS_COM_SendFormattedStringNonBlocking(uint32_t com_id, const char *format, ...); extern int32_t PIOS_COM_SendFormattedString(uint32_t com_id, const char *format, ...); -extern uint8_t PIOS_COM_ReceiveBuffer(uint32_t com_id); +extern uint16_t PIOS_COM_ReceiveBuffer(uint32_t com_id, uint8_t * buf, uint16_t buf_len, uint32_t timeout_ms); extern int32_t PIOS_COM_ReceiveBufferUsed(uint32_t com_id); #endif /* PIOS_COM_H */ diff --git a/flight/PiOS/inc/pios_com_priv.h b/flight/PiOS/inc/pios_com_priv.h index 2bf58a300..54af82bcb 100644 --- a/flight/PiOS/inc/pios_com_priv.h +++ b/flight/PiOS/inc/pios_com_priv.h @@ -34,16 +34,6 @@ #include -enum pios_com_dev_magic { - PIOS_COM_DEV_MAGIC = 0xaa55aa55, -}; - -struct pios_com_dev { - enum pios_com_dev_magic magic; - uint32_t id; - const struct pios_com_driver * driver; -}; - extern int32_t PIOS_COM_ReceiveHandler(uint32_t com_id); #endif /* PIOS_COM_PRIV_H */ diff --git a/flight/PiOS/inc/pios_crc.h b/flight/PiOS/inc/pios_crc.h new file mode 100644 index 000000000..3a64f8bab --- /dev/null +++ b/flight/PiOS/inc/pios_crc.h @@ -0,0 +1,31 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_CRC CRC Functions + * @{ + * + * @file pios_crc.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief CRC functions header. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +uint8_t PIOS_CRC_updateByte(uint8_t crc, const uint8_t data); +uint8_t PIOS_CRC_updateCRC(uint8_t crc, const uint8_t* data, int32_t length); diff --git a/flight/PiOS/inc/pios_delay.h b/flight/PiOS/inc/pios_delay.h index 51a8755a2..17e6d0452 100644 --- a/flight/PiOS/inc/pios_delay.h +++ b/flight/PiOS/inc/pios_delay.h @@ -34,8 +34,10 @@ /* Public Functions */ extern int32_t PIOS_DELAY_Init(void); -extern int32_t PIOS_DELAY_WaituS(uint16_t uS); -extern int32_t PIOS_DELAY_WaitmS(uint16_t mS); +extern int32_t PIOS_DELAY_WaituS(uint32_t uS); +extern int32_t PIOS_DELAY_WaitmS(uint32_t mS); +extern uint32_t PIOS_DELAY_GetuS(); +extern uint32_t PIOS_DELAY_GetuSSince(uint32_t t); #endif /* PIOS_DELAY_H */ diff --git a/flight/PiOS/inc/pios_flashfs_objlist.h b/flight/PiOS/inc/pios_flashfs_objlist.h new file mode 100644 index 000000000..945df4068 --- /dev/null +++ b/flight/PiOS/inc/pios_flashfs_objlist.h @@ -0,0 +1,37 @@ +/** + ****************************************************************************** + * + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_FLASHFS_OBJLIST Object list based flash filesystem (low ram) + * @{ + * + * @file pios_flashfs_objlist.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief A file system for storing UAVObject in flash chip + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "openpilot.h" +#include "uavobjectmanager.h" + +int32_t PIOS_FLASHFS_Init(); +int32_t PIOS_FLASHFS_ObjSave(UAVObjHandle obj, uint16_t instId, uint8_t * data); +int32_t PIOS_FLASHFS_ObjLoad(UAVObjHandle obj, uint16_t instId, uint8_t * data); +int32_t PIOS_FLASHFS_ObjDelete(UAVObjHandle obj, uint16_t instId); \ No newline at end of file diff --git a/flight/PiOS/inc/pios_initcall.h b/flight/PiOS/inc/pios_initcall.h index 7edad6283..e242989c0 100644 --- a/flight/PiOS/inc/pios_initcall.h +++ b/flight/PiOS/inc/pios_initcall.h @@ -41,7 +41,15 @@ /* * Used for initialization calls.. */ + typedef int32_t (*initcall_t)(void); +typedef struct { + initcall_t fn_minit; + initcall_t fn_tinit; +} initmodule_t; + +/* Init module section */ +extern initmodule_t __module_initcall_start[], __module_initcall_end[]; /* initcalls are now grouped by functionality into separate * subsections. Ordering inside the subsections is determined @@ -55,7 +63,19 @@ typedef int32_t (*initcall_t)(void); static initcall_t __initcall_##fn##id __attribute__((__used__)) \ __attribute__((__section__(".initcall" level ".init"))) = fn -#define uavobj_initcall(fn) __define_initcall("uavobj",fn,1) +#define __define_module_initcall(level, ifn, sfn) \ + static initmodule_t __initcall_##fn __attribute__((__used__)) \ + __attribute__((__section__(".initcall" level ".init"))) = { .fn_minit = ifn, .fn_tinit = sfn }; + +#define MODULE_INITCALL(ifn, sfn) __define_module_initcall("module", ifn, sfn) + +#define MODULE_INITIALISE_ALL { for (initmodule_t *fn = __module_initcall_start; fn < __module_initcall_end; fn++) \ + if (fn->fn_minit) \ + (fn->fn_minit)(); } + +#define MODULE_TASKCREATE_ALL { for (initmodule_t *fn = __module_initcall_start; fn < __module_initcall_end; fn++) \ + if (fn->fn_tinit) \ + (fn->fn_tinit)(); } #endif /* PIOS_INITCALL_H */ diff --git a/flight/PiOS/inc/pios_ppm.h b/flight/PiOS/inc/pios_ppm.h index a7c809f70..d75868f4e 100644 --- a/flight/PiOS/inc/pios_ppm.h +++ b/flight/PiOS/inc/pios_ppm.h @@ -30,8 +30,4 @@ #ifndef PIOS_PPM_H #define PIOS_PPM_H -/* Public Functions */ -extern void PIOS_PPM_Init(void); -extern int32_t PIOS_PPM_Get(int8_t Channel); - #endif /* PIOS_PPM_H */ diff --git a/flight/PiOS/inc/pios_ppm_priv.h b/flight/PiOS/inc/pios_ppm_priv.h index 5fdcd73e1..fd863fc50 100644 --- a/flight/PiOS/inc/pios_ppm_priv.h +++ b/flight/PiOS/inc/pios_ppm_priv.h @@ -34,13 +34,6 @@ #include #include -struct pios_ppmsv_cfg { - TIM_TimeBaseInitTypeDef tim_base_init; - struct stm32_irq irq; - TIM_TypeDef * timer; - uint16_t ccr; -}; - struct pios_ppm_cfg { TIM_TimeBaseInitTypeDef tim_base_init; TIM_ICInitTypeDef tim_ic_init; @@ -53,11 +46,13 @@ struct pios_ppm_cfg { }; extern void PIOS_PPM_irq_handler(); -extern void PIOS_PPMSV_irq_handler(); extern uint8_t pios_ppm_num_channels; extern const struct pios_ppm_cfg pios_ppm_cfg; -extern const struct pios_ppmsv_cfg pios_ppmsv_cfg; + +extern const struct pios_rcvr_driver pios_ppm_rcvr_driver; + +extern void PIOS_PPM_Init(void); #endif /* PIOS_PPM_PRIV_H */ diff --git a/flight/PiOS/inc/pios_pwm.h b/flight/PiOS/inc/pios_pwm.h index 32635c8b8..3552319c9 100644 --- a/flight/PiOS/inc/pios_pwm.h +++ b/flight/PiOS/inc/pios_pwm.h @@ -30,9 +30,4 @@ #ifndef PIOS_PWM_H #define PIOS_PWM_H -/* Public Functions */ -extern void PIOS_PWM_Init(void); -extern int32_t PIOS_PWM_Get(int8_t Channel); -//extern void PIOS_PWM_irq_handler(TIM_TypeDef * timer); - #endif /* PIOS_PWM_H */ diff --git a/flight/PiOS/inc/pios_pwm_priv.h b/flight/PiOS/inc/pios_pwm_priv.h index f2119e63c..23d7d4818 100644 --- a/flight/PiOS/inc/pios_pwm_priv.h +++ b/flight/PiOS/inc/pios_pwm_priv.h @@ -57,6 +57,10 @@ extern void PIOS_PWM_irq_handler(TIM_TypeDef * timer); extern uint8_t pios_pwm_num_channels; extern const struct pios_pwm_cfg pios_pwm_cfg; +extern const struct pios_rcvr_driver pios_pwm_rcvr_driver; + +extern void PIOS_PWM_Init(void); + #endif /* PIOS_PWM_PRIV_H */ /** diff --git a/flight/PiOS/inc/pios_rcvr.h b/flight/PiOS/inc/pios_rcvr.h new file mode 100644 index 000000000..dfec004f5 --- /dev/null +++ b/flight/PiOS/inc/pios_rcvr.h @@ -0,0 +1,54 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_RCVR RCVR layer functions + * @brief Hardware communication layer + * @{ + * + * @file pios_rcvr.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief RCVR layer functions header + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_RCVR_H +#define PIOS_RCVR_H + +struct pios_rcvr_channel_map { + uint32_t id; + uint8_t channel; +}; + +extern struct pios_rcvr_channel_map pios_rcvr_channel_to_id_map[]; + +struct pios_rcvr_driver { + void (*init)(uint32_t id); + int32_t (*read)(uint32_t id, uint8_t channel); +}; + +/* Public Functions */ +extern int32_t PIOS_RCVR_Read(uint32_t rcvr_id, uint8_t channel); + +#endif /* PIOS_RCVR_H */ + +/** + * @} + * @} + */ diff --git a/flight/PiOS/inc/pios_rcvr_priv.h b/flight/PiOS/inc/pios_rcvr_priv.h new file mode 100644 index 000000000..968dc2116 --- /dev/null +++ b/flight/PiOS/inc/pios_rcvr_priv.h @@ -0,0 +1,48 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_RCVR RCVR Functions + * @brief PIOS interface for RCVR drivers + * @{ + * + * @file pios_rcvr_priv.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Parts by Thorsten Klose (tk@midibox.org) + * @brief USART private definitions. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_RCVR_PRIV_H +#define PIOS_RCVR_PRIV_H + +#include + +extern uint32_t pios_rcvr_max_channel; + +extern int32_t PIOS_RCVR_Init(uint32_t * rcvr_id, const struct pios_rcvr_driver * driver, const uint32_t lower_id); + +extern void PIOS_RCVR_IRQ_Handler(uint32_t rcvr_id); + +#endif /* PIOS_RCVR_PRIV_H */ + +/** + * @} + * @} + */ diff --git a/flight/PiOS/inc/pios_rtc.h b/flight/PiOS/inc/pios_rtc.h index c9ad5661f..2e01912b9 100644 --- a/flight/PiOS/inc/pios_rtc.h +++ b/flight/PiOS/inc/pios_rtc.h @@ -27,14 +27,18 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef PIOS_SERVO_H -#define PIOS_SERVO_H +#ifndef PIOS_RTC_H +#define PIOS_RTC_H + +#include /* Public Functions */ -extern void PIOS_RTC_Start(); extern uint32_t PIOS_RTC_Counter(); +extern float PIOS_RTC_Rate(); +extern float PIOS_RTC_MsPerTick(); +extern bool PIOS_RTC_RegisterTickCallback(void (*fn)(uint32_t id), uint32_t data); -#endif /* PIOS_SERVO_H */ +#endif /* PIOS_RTC_H */ /** * @} diff --git a/flight/PiOS/inc/pios_rtc_priv.h b/flight/PiOS/inc/pios_rtc_priv.h new file mode 100644 index 000000000..0a8c1c9b1 --- /dev/null +++ b/flight/PiOS/inc/pios_rtc_priv.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_RTC RTC Functions + * @brief PIOS interface for RTC tick + * @{ + * + * @file pios_rtc_priv.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief ADC private definitions. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_RTC_PRIV_H +#define PIOS_RTC_PRIV_H + +#include +#include + +struct pios_rtc_cfg { + uint32_t clksrc; + uint32_t prescaler; + struct stm32_irq irq; +}; + +extern void PIOS_RTC_Init(const struct pios_rtc_cfg * cfg); + +extern void PIOS_RTC_irq_handler(void); +#endif /* PIOS_RTC_PRIV_H */ + +/** + * @} + * @} + */ + diff --git a/flight/PiOS/inc/pios_sbus.h b/flight/PiOS/inc/pios_sbus.h new file mode 100644 index 000000000..868fedd70 --- /dev/null +++ b/flight/PiOS/inc/pios_sbus.h @@ -0,0 +1,42 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_SBUS Futaba S.Bus receiver functions + * @{ + * + * @file pios_sbus.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. + * @brief Futaba S.Bus functions header. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_SBUS_H +#define PIOS_SBUS_H + +/* Global Types */ + +/* Public Functions */ + +#endif /* PIOS_SBUS_H */ + +/** + * @} + * @} + */ diff --git a/flight/PiOS/inc/pios_sbus_priv.h b/flight/PiOS/inc/pios_sbus_priv.h new file mode 100644 index 000000000..4e46b2089 --- /dev/null +++ b/flight/PiOS/inc/pios_sbus_priv.h @@ -0,0 +1,87 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_SBUS S.Bus Functions + * @brief PIOS interface to read and write from Futaba S.Bus port + * @{ + * + * @file pios_sbus_priv.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. + * @brief Futaba S.Bus Private structures. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_SBUS_PRIV_H +#define PIOS_SBUS_PRIV_H + +#include +#include +#include + +/* + * S.Bus serial port settings: + * 100000bps inverted serial stream, 8 bits, even parity, 2 stop bits + * frame period is 7ms (HS) or 14ms (FS) + * + * Frame structure: + * 1 byte - 0x0f (start of frame byte) + * 22 bytes - channel data (11 bit/channel, 16 channels, LSB first) + * 1 byte - bit flags: + * 0x01 - digital channel 1, + * 0x02 - digital channel 2, + * 0x04 - lost frame flag, + * 0x08 - failsafe flag, + * 0xf0 - reserved + * 1 byte - 0x00 (end of frame byte) + */ +#define SBUS_FRAME_LENGTH (1+22+1+1) +#define SBUS_SOF_BYTE 0x0f +#define SBUS_EOF_BYTE 0x00 +#define SBUS_FLAG_DG1 0x01 +#define SBUS_FLAG_DG2 0x02 +#define SBUS_FLAG_FL 0x04 +#define SBUS_FLAG_FS 0x08 + +/* + * S.Bus protocol provides up to 16 analog and 2 digital channels. + * Only 8 channels are currently supported by the OpenPilot. + */ +#define SBUS_NUMBER_OF_CHANNELS 8 + +/* + * S.Bus configuration programmable invertor + */ +struct pios_sbus_cfg { + struct stm32_gpio inv; + void (*gpio_clk_func)(uint32_t periph, FunctionalState state); + uint32_t gpio_clk_periph; + BitAction gpio_inv_enable; +}; + +extern const struct pios_rcvr_driver pios_sbus_rcvr_driver; + +extern int32_t PIOS_SBUS_Init(uint32_t * sbus_id, const struct pios_sbus_cfg *cfg, const struct pios_com_driver * driver, uint32_t lower_id); + +#endif /* PIOS_SBUS_PRIV_H */ + +/** + * @} + * @} + */ diff --git a/flight/PiOS/inc/pios_spektrum.h b/flight/PiOS/inc/pios_spektrum.h index 241782e9d..765d2c8a5 100644 --- a/flight/PiOS/inc/pios_spektrum.h +++ b/flight/PiOS/inc/pios_spektrum.h @@ -34,11 +34,6 @@ /* Global Types */ /* Public Functions */ -extern void PIOS_SPEKTRUM_Init(void); -extern uint8_t PIOS_SPEKTRUM_Bind(void); -extern int32_t PIOS_SPEKTRUM_Decode(uint8_t b); -extern int16_t PIOS_SPEKTRUM_Get(int8_t Channel); -extern void SPEKTRUM_IRQHandler(uint32_t usart_id); #endif /* PIOS_SPEKTRUM_H */ diff --git a/flight/PiOS/inc/pios_spektrum_priv.h b/flight/PiOS/inc/pios_spektrum_priv.h index 19a1db20b..2d31a8027 100644 --- a/flight/PiOS/inc/pios_spektrum_priv.h +++ b/flight/PiOS/inc/pios_spektrum_priv.h @@ -36,21 +36,13 @@ #include struct pios_spektrum_cfg { - const struct pios_usart_cfg * pios_usart_spektrum_cfg; - TIM_TimeBaseInitTypeDef tim_base_init; - GPIO_InitTypeDef gpio_init; + struct stm32_gpio bind; uint32_t remap; /* GPIO_Remap_* */ - struct stm32_irq irq; - TIM_TypeDef * timer; - GPIO_TypeDef * port; - uint16_t ccr; - uint16_t pin; }; -extern void PIOS_SPEKTRUM_irq_handler(); +extern const struct pios_rcvr_driver pios_spektrum_rcvr_driver; -extern uint8_t pios_spektrum_num_channels; -extern const struct pios_spektrum_cfg pios_spektrum_cfg; +extern int32_t PIOS_SPEKTRUM_Init(uint32_t * spektrum_id, const struct pios_spektrum_cfg *cfg, const struct pios_com_driver * driver, uint32_t lower_id, bool bind); #endif /* PIOS_PWM_PRIV_H */ diff --git a/flight/PiOS/inc/pios_stm32.h b/flight/PiOS/inc/pios_stm32.h index 1433d460b..fb9163208 100644 --- a/flight/PiOS/inc/pios_stm32.h +++ b/flight/PiOS/inc/pios_stm32.h @@ -32,7 +32,6 @@ #define PIOS_STM32_H struct stm32_irq { - void (*handler) (void); uint32_t flags; NVIC_InitTypeDef init; }; diff --git a/flight/PiOS/inc/pios_usart_priv.h b/flight/PiOS/inc/pios_usart_priv.h index 772e6f4d2..edca829aa 100644 --- a/flight/PiOS/inc/pios_usart_priv.h +++ b/flight/PiOS/inc/pios_usart_priv.h @@ -48,26 +48,8 @@ struct pios_usart_cfg { struct stm32_irq irq; }; -enum pios_usart_dev_magic { - PIOS_USART_DEV_MAGIC = 0x11223344, -}; - -struct pios_usart_dev { - enum pios_usart_dev_magic magic; - const struct pios_usart_cfg * cfg; - - // align to 32-bit to try and provide speed improvement; - uint8_t rx_buffer[PIOS_USART_RX_BUFFER_SIZE] __attribute__ ((aligned(4))); - t_fifo_buffer rx; - - // align to 32-bit to try and provide speed improvement; - uint8_t tx_buffer[PIOS_USART_TX_BUFFER_SIZE] __attribute__ ((aligned(4))); - t_fifo_buffer tx; -}; - extern int32_t PIOS_USART_Init(uint32_t * usart_id, const struct pios_usart_cfg * cfg); - -extern void PIOS_USART_IRQ_Handler(uint32_t usart_id); +extern const struct pios_usart_cfg * PIOS_USART_GetConfig(uint32_t usart_id); #endif /* PIOS_USART_PRIV_H */ diff --git a/flight/PiOS/inc/pios_usb_hid.h b/flight/PiOS/inc/pios_usb_hid.h index 06f4deca1..67067ba72 100644 --- a/flight/PiOS/inc/pios_usb_hid.h +++ b/flight/PiOS/inc/pios_usb_hid.h @@ -41,7 +41,6 @@ #define PIOS_USB_HID_DATA_LENGTH 62 /* Global functions */ -extern int32_t PIOS_USB_HID_Init(uint32_t mode); extern int32_t PIOS_USB_HID_Reenumerate(); extern int32_t PIOS_USB_HID_ChangeConnectionState(uint32_t Connected); extern int32_t PIOS_USB_HID_CheckAvailable(uint8_t id); diff --git a/flight/PiOS/inc/pios_usb_hid_priv.h b/flight/PiOS/inc/pios_usb_hid_priv.h new file mode 100644 index 000000000..5a8652762 --- /dev/null +++ b/flight/PiOS/inc/pios_usb_hid_priv.h @@ -0,0 +1,49 @@ + /** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_HID USB_HID Functions + * @brief PIOS interface for USB_HID port + * @{ + * + * @file pios_usb_hid_priv.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief USB_HID private definitions. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PIOS_USB_HID_PRIV_H +#define PIOS_USB_HID_PRIV_H + +#include +#include + +struct pios_usb_hid_cfg { + struct stm32_irq irq; +}; + +extern int32_t PIOS_USB_HID_Init(uint32_t * usb_hid_id, const struct pios_usb_hid_cfg * cfg); + +#endif /* PIOS_USB_HID_PRIV_H */ + +/** + * @} + * @} + */ + diff --git a/flight/PiOS/pios.h b/flight/PiOS/pios.h index cbf2a2249..a675f93b1 100644 --- a/flight/PiOS/pios.h +++ b/flight/PiOS/pios.h @@ -1,135 +1,141 @@ -/** - ****************************************************************************** - * - * @file pios.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @brief Main PiOS header. - * - Central header for the project. - * @see The GNU Public License (GPL) Version 3 - * - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef PIOS_H -#define PIOS_H - -/* PIOS Feature Selection */ -#include "pios_config.h" - -#if defined(PIOS_INCLUDE_FREERTOS) -/* FreeRTOS Includes */ -#include "FreeRTOS.h" -#include "task.h" -#include "queue.h" -#include "semphr.h" -#endif - -/* C Lib Includes */ -#include -#include -#include -#include -#include - -/* STM32 Std Perf Lib */ -#include -#include - -#if defined(PIOS_INCLUDE_SDCARD) -/* Dosfs Includes */ -#include - -/* Mass Storage Device Includes */ -#include -#endif - -/* Generic initcall infrastructure */ -#include "pios_initcall.h" - -/* PIOS Board Specific Device Configuration */ -#include "pios_board.h" - -/* PIOS Hardware Includes (STM32F10x) */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(PIOS_INCLUDE_EXTI) -#include -#endif -#include - -/* PIOS Hardware Includes (Common) */ -#include -#include -#if defined(PIOS_INCLUDE_BMP085) -#include -#endif -#if defined(PIOS_INCLUDE_HCSR04) -#include -#endif -#if defined(PIOS_INCLUDE_HMC5843) -#include -#endif -#if defined(PIOS_INCLUDE_HMC5883) -#include -#endif -#if defined(PIOS_INCLUDE_I2C_ESC) -#include -#endif -#if defined(PIOS_INCLUDE_IMU3000) -#include -#endif -#include - -#if defined(PIOS_INCLUDE_ADXL345) -#include -#endif - -#if defined(PIOS_INCLUDE_BMA180) -#include -#endif - -#if defined(PIOS_INCLUDE_FLASH) -#include -#endif - -#if defined(PIOS_INCLUDE_BL_HELPER) -#include -#endif - -#if defined(PIOS_INCLUDE_USB) -/* USB Libs */ -#include -#endif - -#define NELEMENTS(x) (sizeof(x) / sizeof(*(x))) - -#endif /* PIOS_H */ +/** + ****************************************************************************** + * + * @file pios.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Main PiOS header. + * - Central header for the project. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef PIOS_H +#define PIOS_H + +/* PIOS Feature Selection */ +#include "pios_config.h" + +#if defined(PIOS_INCLUDE_FREERTOS) +/* FreeRTOS Includes */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" +#endif + +/* C Lib Includes */ +#include +#include +#include +#include +#include + +/* STM32 Std Perf Lib */ +#include +#include + +#if defined(PIOS_INCLUDE_SDCARD) +/* Dosfs Includes */ +#include + +/* Mass Storage Device Includes */ +#include +#endif + +/* Generic initcall infrastructure */ +#include "pios_initcall.h" + +/* PIOS Board Specific Device Configuration */ +#include "pios_board.h" + +/* PIOS Hardware Includes (STM32F10x) */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(PIOS_INCLUDE_EXTI) +#include +#endif +#include + +/* PIOS Hardware Includes (Common) */ +#include +#include +#if defined(PIOS_INCLUDE_BMP085) +#include +#endif +#if defined(PIOS_INCLUDE_HCSR04) +#include +#endif +#if defined(PIOS_INCLUDE_HMC5843) +#include +#endif +#if defined(PIOS_INCLUDE_HMC5883) +#include +#endif +#if defined(PIOS_INCLUDE_I2C_ESC) +#include +#endif +#if defined(PIOS_INCLUDE_IMU3000) +#include +#endif +#include + +#if defined(PIOS_INCLUDE_ADXL345) +#include +#endif + +#if defined(PIOS_INCLUDE_BMA180) +#include +#endif + +#if defined(PIOS_INCLUDE_FLASH) +#include +#include +#endif + +#if defined(PIOS_INCLUDE_BL_HELPER) +#include +#endif + +#if defined(PIOS_INCLUDE_USB) +/* USB Libs */ +#include +#endif + +#include + +#define NELEMENTS(x) (sizeof(x) / sizeof(*(x))) + +#endif /* PIOS_H */ diff --git a/flight/PipXtreme/Makefile b/flight/PipXtreme/Makefile index 21d1c3d5a..9a70ac417 100644 --- a/flight/PipXtreme/Makefile +++ b/flight/PipXtreme/Makefile @@ -25,6 +25,13 @@ WHEREAMI := $(dir $(lastword $(MAKEFILE_LIST))) TOP := $(realpath $(WHEREAMI)/../../) include $(TOP)/make/firmware-defs.mk +include $(TOP)/make/boards/$(BOARD_NAME)/board-info.mk + +# Target file name (without extension). +TARGET := fw_$(BOARD_NAME) + +# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) +OUTDIR := $(TOP)/build/$(TARGET) # Debugging (YES/NO) ? DEBUG ?= NO @@ -43,23 +50,6 @@ FLASH_TOOL = OPENOCD # Include the USB files (YES/NO) ? USE_USB = YES -# MCU name, submodel and board -# - MCU used for compiler-option (-mcpu) -# - MODEL used for linker-script name (-T) and passed as define -# - BOARD just passed as define (optional) -MCU = cortex-m3 -CHIP = STM32F103CBT -BOARD = STM32103CB_PIPXTREME -#CHIP = STM32F103C8T -#BOARD = STM32103C8_PIPXTREME -MODEL = MD - -# Directory for output files (lst, obj, dep, elf, sym, map, hex, bin etc.) -OUTDIR = $(TOP)/build/pipxtreme - -# Target file name (without extension). -TARGET = PipXtreme - # Paths HOME_DIR = ./ HOME_DIR_INC = $(HOME_DIR)/inc @@ -192,7 +182,7 @@ CPPSRCARM = # Even though the DOS/Win* filesystem matches both .s and .S the same, # it will preserve the spelling of the filenames, and gcc itself does # care about how the name is spelled on its command-line. -ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL).S +ASRC = $(PIOSSTM32F10X)/startup_stm32f10x_$(MODEL)$(MODEL_SUFFIX).S # List Assembler source files here which must be assembled in ARM-Mode.. ASRCARM = @@ -257,7 +247,6 @@ DEBUGF = dwarf-2 CDEFS = -DSTM32F10X_$(MODEL) CDEFS += -DUSE_STDPERIPH_DRIVER CDEFS += -DUSE_$(BOARD) -CDEFS += -DUSE_BOOTLOADER # Place project-specific -D and/or -U options for # Assembler with preprocessor here. @@ -340,20 +329,8 @@ LDFLAGS += -lc -lgcc LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_memory.ld LDFLAGS += -T$(LINKERSCRIPTPATH)/link_$(BOARD)_sections.ld -OOCD_LOADFILE+=$(OUTDIR)/$(TARGET).bin -# Program -OOCD_CL+=-c "flash write_image erase $(OOCD_LOADFILE) 0x08003000 bin" -# Verify -OOCD_CL+=-c "verify_image $(OOCD_LOADFILE) 0x08003000 bin" -# reset target -OOCD_CL+=-c "reset run" -# terminate OOCD after programming -OOCD_CL+=-c shutdown - # Define programs and commands. REMOVE = $(REMOVE_CMD) -f -###SHELL = sh -###COPY = cp # List of all source files. ALLSRC = $(ASRCARM) $(ASRC) $(SRCARM) $(SRC) $(CPPSRCARM) $(CPPSRC) @@ -385,14 +362,6 @@ endif endif endif -# Program the device. -ifeq ($(FLASH_TOOL),OPENOCD) -# Program the device with Dominic Rath's OPENOCD in "batch-mode", needs cfg and "reset-script". -program: $(OUTDIR)/$(TARGET).bin - @echo ${quote}Programming with OPENOCD${quote} - $(OOCD_EXE) $(OOCD_CL) -endif - # Link: create ELF output file from object files. $(eval $(call LINK_TEMPLATE, $(OUTDIR)/$(TARGET).elf, $(ALLOBJ))) @@ -422,23 +391,37 @@ $(eval $(call PARTIAL_COMPILE_ARM_TEMPLATE, SRCARM)) $(OUTDIR)/$(TARGET).bin.o: $(OUTDIR)/$(TARGET).bin -.PHONY: elf lss sym hex bin bino +$(eval $(call OPFW_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BOARD_TYPE),$(BOARD_REVISION))) + +# Add jtag targets (program and wipe) +$(eval $(call JTAG_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(FW_BANK_BASE),$(FW_BANK_SIZE))) + +.PHONY: elf lss sym hex bin bino opfw elf: $(OUTDIR)/$(TARGET).elf lss: $(OUTDIR)/$(TARGET).lss sym: $(OUTDIR)/$(TARGET).sym hex: $(OUTDIR)/$(TARGET).hex bin: $(OUTDIR)/$(TARGET).bin bino: $(OUTDIR)/$(TARGET).bin.o +opfw: $(OUTDIR)/$(TARGET).opfw # Display sizes of sections. $(eval $(call SIZE_TEMPLATE, $(OUTDIR)/$(TARGET).elf)) -.PHONY: size -size: $(OUTDIR)/$(TARGET).elf_size # Generate Doxygen documents docs: doxygen $(DOXYGENDIR)/doxygen.cfg +# Install: install binary file with prefix/suffix into install directory +install: $(OUTDIR)/$(TARGET).opfw +ifneq ($(INSTALL_DIR),) + @echo $(MSG_INSTALLING) $(call toprel, $<) + $(V1) mkdir -p $(INSTALL_DIR) + $(V1) $(INSTALL) $< $(INSTALL_DIR)/$(INSTALL_PFX)$(TARGET)$(INSTALL_SFX).opfw +else + $(error INSTALL_DIR must be specified for $@) +endif + # Target: clean project. clean: clean_list @@ -476,4 +459,4 @@ else endif # Listing of phony targets. -.PHONY : all build clean clean_list program +.PHONY : all build clean clean_list install diff --git a/flight/PipXtreme/api_config.c b/flight/PipXtreme/api_config.c index bf10a13b3..2cecfc65e 100644 --- a/flight/PipXtreme/api_config.c +++ b/flight/PipXtreme/api_config.c @@ -794,7 +794,8 @@ void apiconfig_process(void) int32_t bytes = PIOS_COM_ReceiveBufferUsed(PIOS_COM_SERIAL); while (bytes > 0) { - PIOS_COM_ReceiveBuffer(PIOS_COM_SERIAL); + uint8_t c; + PIOS_COM_ReceiveBuffer(PIOS_COM_SERIAL, &c, 1, 0); bytes--; } } @@ -812,9 +813,12 @@ void apiconfig_process(void) if (com_num > sizeof(apiconfig_rx_buffer) - apiconfig_rx_buffer_wr) com_num = sizeof(apiconfig_rx_buffer) - apiconfig_rx_buffer_wr; + while (com_num > 0) { // fetch a byte from the comm-port RX buffer and save it into our RX buffer - apiconfig_rx_buffer[apiconfig_rx_buffer_wr++] = PIOS_COM_ReceiveBuffer(apiconfig_comm_port); + uint8_t c; + PIOS_COM_ReceiveBuffer(apiconfig_comm_port, &c, 1, 0); + apiconfig_rx_buffer[apiconfig_rx_buffer_wr++] = c; com_num--; } diff --git a/flight/PipXtreme/main.c b/flight/PipXtreme/main.c index f30a355a8..46b9073ea 100644 --- a/flight/PipXtreme/main.c +++ b/flight/PipXtreme/main.c @@ -163,8 +163,8 @@ void TIMER_INT_FUNC(void) // Clear timer interrupt pending bit TIM_ClearITPendingBit(TIMER_INT_TIMER, TIM_IT_Update); -// random32 = UpdateCRC32(random32, PIOS_DELAY_TIMER->CNT >> 8); -// random32 = UpdateCRC32(random32, PIOS_DELAY_TIMER->CNT); +// random32 = UpdateCRC32(random32, PIOS_DELAY_GetuS() >> 8); +// random32 = UpdateCRC32(random32, PIOS_DELAY_GetuS()); uptime_ms++; @@ -785,8 +785,8 @@ int main() for (;;) { - random32 = updateCRC32(random32, PIOS_DELAY_TIMER->CNT >> 8); - random32 = updateCRC32(random32, PIOS_DELAY_TIMER->CNT); + random32 = updateCRC32(random32, PIOS_DELAY_GetuS() >> 8); + random32 = updateCRC32(random32, PIOS_DELAY_GetuS()); if (second_tick) { diff --git a/flight/PipXtreme/pios_board.c b/flight/PipXtreme/pios_board.c index a0b85915a..0a69808ad 100644 --- a/flight/PipXtreme/pios_board.c +++ b/flight/PipXtreme/pios_board.c @@ -90,7 +90,6 @@ static const struct pios_spi_cfg pios_spi_port_cfg = .ahb_clk = RCC_AHBPeriph_DMA1, .irq = { - .handler = PIOS_SPI_port_irq_handler, .flags = (DMA1_FLAG_TC2 | DMA1_FLAG_TE2 | DMA1_FLAG_HT2 | DMA1_FLAG_GL2), .init = { .NVIC_IRQChannel = DMA1_Channel2_IRQn, @@ -189,11 +188,10 @@ void PIOS_SPI_port_irq_handler(void) extern void PIOS_ADC_handler(void); void DMA1_Channel1_IRQHandler() __attribute__ ((alias("PIOS_ADC_handler"))); // Remap the ADC DMA handler to this one -const struct pios_adc_cfg pios_adc_cfg = { +static const struct pios_adc_cfg pios_adc_cfg = { .dma = { .ahb_clk = RCC_AHBPeriph_DMA1, .irq = { - .handler = PIOS_ADC_DMA_Handler, .flags = (DMA1_FLAG_TC1 | DMA1_FLAG_TE1 | DMA1_FLAG_HT1 | DMA1_FLAG_GL1), .init = { .NVIC_IRQChannel = DMA1_Channel1_IRQn, @@ -245,10 +243,7 @@ void PIOS_ADC_handler() { /* * SERIAL USART */ -void PIOS_USART_serial_irq_handler(void); -void USART1_IRQHandler() __attribute__ ((alias ("PIOS_USART_serial_irq_handler"))); - -const struct pios_usart_cfg pios_usart_serial_cfg = +static const struct pios_usart_cfg pios_usart_serial_cfg = { .regs = USART1, .init = @@ -262,7 +257,6 @@ const struct pios_usart_cfg pios_usart_serial_cfg = }, .irq = { - .handler = PIOS_USART_serial_irq_handler, .init = { .NVIC_IRQChannel = USART1_IRQn, @@ -293,12 +287,6 @@ const struct pios_usart_cfg pios_usart_serial_cfg = }, }; -static uint32_t pios_usart_serial_id; -void PIOS_USART_serial_irq_handler(void) -{ - PIOS_USART_IRQ_Handler(pios_usart_serial_id); -} - #endif /* PIOS_INCLUDE_USART */ // *********************************************************************************** @@ -307,10 +295,37 @@ void PIOS_USART_serial_irq_handler(void) #include +#define PIOS_COM_TELEM_USB_RX_BUF_LEN 192 +#define PIOS_COM_TELEM_USB_TX_BUF_LEN 192 + +static uint8_t pios_com_telem_usb_rx_buffer[PIOS_COM_TELEM_USB_RX_BUF_LEN]; +static uint8_t pios_com_telem_usb_tx_buffer[PIOS_COM_TELEM_USB_TX_BUF_LEN]; + +#define PIOS_COM_SERIAL_RX_BUF_LEN 192 +#define PIOS_COM_SERIAL_TX_BUF_LEN 192 + +static uint8_t pios_com_serial_rx_buffer[PIOS_COM_SERIAL_RX_BUF_LEN]; +static uint8_t pios_com_serial_tx_buffer[PIOS_COM_SERIAL_TX_BUF_LEN]; + #endif /* PIOS_INCLUDE_COM */ // *********************************************************************************** +#if defined(PIOS_INCLUDE_USB_HID) +#include "pios_usb_hid_priv.h" + +static const struct pios_usb_hid_cfg pios_usb_hid_main_cfg = { + .irq = { + .init = { + .NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; +#endif /* PIOS_INCLUDE_USB_HID */ + extern const struct pios_com_driver pios_usb_com_driver; uint32_t pios_com_serial_id; @@ -334,21 +349,27 @@ void PIOS_Board_Init(void) { // Delay system PIOS_DELAY_Init(); + uint32_t pios_usart_serial_id; if (PIOS_USART_Init(&pios_usart_serial_id, &pios_usart_serial_cfg)) { PIOS_DEBUG_Assert(0); } - if (PIOS_COM_Init(&pios_com_serial_id, &pios_usart_com_driver, pios_usart_serial_id)) { + if (PIOS_COM_Init(&pios_com_serial_id, &pios_usart_com_driver, pios_usart_serial_id, + pios_com_serial_rx_buffer, sizeof(pios_com_serial_rx_buffer), + pios_com_serial_tx_buffer, sizeof(pios_com_serial_tx_buffer))) { PIOS_DEBUG_Assert(0); } #if defined(PIOS_INCLUDE_USB_HID) - PIOS_USB_HID_Init(0); + uint32_t pios_usb_hid_id; + PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_main_cfg); #if defined(PIOS_INCLUDE_COM) - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_com_driver, 0)) { - PIOS_DEBUG_Assert(0); + if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_com_driver, pios_usb_hid_id, + pios_com_telem_usb_rx_buffer, sizeof(pios_com_telem_usb_rx_buffer), + pios_com_telem_usb_tx_buffer, sizeof(pios_com_telem_usb_tx_buffer))) { + PIOS_Assert(0); } #endif /* PIOS_INCLUDE_COM */ -#endif /* PIOS_INCLUDE_USB_HID */ +#endif /* PIOS_INCLUDE_USB_HID */ // ADC system // PIOS_ADC_Init(); diff --git a/flight/PipXtreme/transparent_comms.c b/flight/PipXtreme/transparent_comms.c index a04ca17ee..b30f5f581 100644 --- a/flight/PipXtreme/transparent_comms.c +++ b/flight/PipXtreme/transparent_comms.c @@ -91,7 +91,8 @@ void trans_process(void) int32_t bytes = PIOS_COM_ReceiveBufferUsed(PIOS_COM_SERIAL); while (bytes > 0) { - PIOS_COM_ReceiveBuffer(PIOS_COM_SERIAL); + uint8_t c; + PIOS_COM_ReceiveBuffer(PIOS_COM_SERIAL, &c, 1, 0); bytes--; } } @@ -134,8 +135,7 @@ void trans_process(void) // copy data received down the comm-port into our temp buffer register uint16_t bytes_saved = 0; - while (bytes_saved < com_num) - trans_temp_buffer1[bytes_saved++] = PIOS_COM_ReceiveBuffer(comm_port); + bytes_saved = PIOS_COM_ReceiveBuffer(comm_port, trans_temp_buffer1, com_num, 0); // put the received comm-port data bytes into the RF packet handler TX buffer if (bytes_saved > 0) @@ -147,8 +147,11 @@ void trans_process(void) else { // empty the comm-ports rx buffer int32_t com_num = PIOS_COM_ReceiveBufferUsed(comm_port); - while (com_num > 0) - PIOS_COM_ReceiveBuffer(comm_port); + while (com_num > 0) { + uint8_t c; + PIOS_COM_ReceiveBuffer(comm_port, &c, 1, 0); + com_num--; + } } // ******************** diff --git a/flight/Project/Eclipse/eclipseWindowsWsp.zip b/flight/Project/Eclipse/eclipseWindowsWsp.zip new file mode 100644 index 000000000..e79d0fc76 Binary files /dev/null and b/flight/Project/Eclipse/eclipseWindowsWsp.zip differ diff --git a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj index 5dd95349b..ceca7eafb 100644 --- a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj +++ b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj @@ -85,10 +85,14 @@ 6549E0D21279B3C800C5476F /* fifo_buffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fifo_buffer.c; sourceTree = ""; }; 6549E0D31279B3CF00C5476F /* fifo_buffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fifo_buffer.h; sourceTree = ""; }; 655268BC121FBD2900410C6E /* ahrscalibration.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = ahrscalibration.xml; sourceTree = ""; }; + 655B1A8E13B2FC0900B0E48D /* camerastabsettings.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = camerastabsettings.xml; sourceTree = ""; }; 656268C612DC1923007B0A0F /* nedaccel.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = nedaccel.xml; sourceTree = ""; }; + 6562BE1713CCAD0600C823E8 /* pios_rcvr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pios_rcvr.c; sourceTree = ""; }; 65632DF51251650300469B77 /* pios_board.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_board.h; sourceTree = ""; }; 65632DF61251650300469B77 /* STM32103CB_AHRS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STM32103CB_AHRS.h; sourceTree = ""; }; 65632DF71251650300469B77 /* STM3210E_OP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STM3210E_OP.h; sourceTree = ""; }; + 6572CB1613D0F2B200FC2972 /* link_STM32103CB_CC_Rev1_memory.ld */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = link_STM32103CB_CC_Rev1_memory.ld; path = ../../PiOS/STM32F10x/link_STM32103CB_CC_Rev1_memory.ld; sourceTree = SOURCE_ROOT; }; + 6572CB1713D0F2B200FC2972 /* link_STM32103CB_CC_Rev1_sections.ld */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = link_STM32103CB_CC_Rev1_sections.ld; path = ../../PiOS/STM32F10x/link_STM32103CB_CC_Rev1_sections.ld; sourceTree = SOURCE_ROOT; }; 657CEEAD121DB6C8007A1FBE /* homelocation.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = homelocation.xml; sourceTree = ""; }; 657CEEB7121DBC63007A1FBE /* CoordinateConversions.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CoordinateConversions.c; sourceTree = ""; }; 657CEEB9121DBC63007A1FBE /* CoordinateConversions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoordinateConversions.h; sourceTree = ""; }; @@ -2677,7 +2681,6 @@ 65C35E7912EFB2F3004811C2 /* watchdogstatus.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = watchdogstatus.xml; sourceTree = ""; }; 65C35E9E12F0A834004811C2 /* uavobjecttemplate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uavobjecttemplate.c; sourceTree = ""; }; 65C35E9F12F0A834004811C2 /* uavobjectsinittemplate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uavobjectsinittemplate.c; sourceTree = ""; }; - 65C35EA012F0A834004811C2 /* uavobjectsinit_cc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uavobjectsinit_cc.c; sourceTree = ""; }; 65C35EA112F0A834004811C2 /* uavobjectmanager.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uavobjectmanager.c; sourceTree = ""; }; 65C35EA312F0A834004811C2 /* eventdispatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eventdispatcher.h; sourceTree = ""; }; 65C35EA412F0A834004811C2 /* uavobjectmanager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uavobjectmanager.h; sourceTree = ""; }; @@ -2687,9 +2690,13 @@ 65C35EA812F0A834004811C2 /* eventdispatcher.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eventdispatcher.c; sourceTree = ""; }; 65C35F6612F0DC2D004811C2 /* attitude.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = attitude.c; sourceTree = ""; }; 65C35F6812F0DC2D004811C2 /* attitude.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = attitude.h; sourceTree = ""; }; + 65C9903C13A871B90082BD60 /* camerastab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = camerastab.c; sourceTree = ""; }; + 65C9903E13A871B90082BD60 /* camerastab.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = camerastab.h; sourceTree = ""; }; 65D2CA841248F9A400B1E7D6 /* mixersettings.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = mixersettings.xml; sourceTree = ""; }; 65D2CA851248F9A400B1E7D6 /* mixerstatus.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = mixerstatus.xml; sourceTree = ""; }; + 65DEA79113F2143B00095B06 /* cameradesired.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = cameradesired.xml; sourceTree = ""; }; 65E410AE12F65AEA00725888 /* attitudesettings.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = attitudesettings.xml; sourceTree = ""; }; + 65E6D80713E3A4D0002A557A /* hwsettings.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = hwsettings.xml; sourceTree = ""; }; 65E6DF7112E02E8E00058553 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; 65E6DF7312E02E8E00058553 /* alarms.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alarms.c; sourceTree = ""; }; 65E6DF7412E02E8E00058553 /* coptercontrol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = coptercontrol.c; sourceTree = ""; }; @@ -2736,6 +2743,9 @@ 65E6E06112E031E300058553 /* STM32103CB_CC_Rev1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STM32103CB_CC_Rev1.h; sourceTree = ""; }; 65E6E06212E031E300058553 /* STM32103CB_PIPXTREME_Rev1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STM32103CB_PIPXTREME_Rev1.h; sourceTree = ""; }; 65E6E09912E037C800058553 /* pios_adc_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_adc_priv.h; sourceTree = ""; }; + 65E8C743139A6D0900E1F979 /* pios_crc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pios_crc.c; sourceTree = ""; }; + 65E8C745139A6D1A00E1F979 /* pios_crc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_crc.h; sourceTree = ""; }; + 65E8C788139AA2A800E1F979 /* accessorydesired.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = accessorydesired.xml; sourceTree = ""; }; 65E8EF1F11EEA61E00BBF654 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = ../../OpenPilot/Makefile; sourceTree = SOURCE_ROOT; }; 65E8EF2011EEA61E00BBF654 /* Makefile.posix */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Makefile.posix; path = ../../OpenPilot/Makefile.posix; sourceTree = SOURCE_ROOT; }; 65E8EF5C11EEA61E00BBF654 /* alarms.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = alarms.c; path = ../../OpenPilot/System/alarms.c; sourceTree = SOURCE_ROOT; }; @@ -3171,6 +3181,8 @@ 65FF4BE913791C3300146BE4 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; 65FF4BEA13791C3300146BE4 /* op_dfu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = op_dfu.c; sourceTree = ""; }; 65FF4BEB13791C3300146BE4 /* pios_board.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pios_board.c; sourceTree = ""; }; + 65FF4D5E137EDEC100146BE4 /* pios_flashfs_objlist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pios_flashfs_objlist.c; sourceTree = ""; }; + 65FF4D61137EFA4F00146BE4 /* pios_flashfs_objlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_flashfs_objlist.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXGroup section */ @@ -3200,6 +3212,7 @@ 650D8E2812DFE16400D05CC9 /* Altitude */, 65C35F6512F0DC2D004811C2 /* Attitude */, 650D8E2E12DFE16400D05CC9 /* Battery */, + 65C9903B13A871B90082BD60 /* CameraStab */, 650D8E3212DFE16400D05CC9 /* Example */, 650D8E3B12DFE16400D05CC9 /* FirmwareIAP */, 650D8E3F12DFE16400D05CC9 /* FlightPlan */, @@ -3509,7 +3522,6 @@ children = ( 65C35E9E12F0A834004811C2 /* uavobjecttemplate.c */, 65C35E9F12F0A834004811C2 /* uavobjectsinittemplate.c */, - 65C35EA012F0A834004811C2 /* uavobjectsinit_cc.c */, 65C35EA112F0A834004811C2 /* uavobjectmanager.c */, 65C35EA212F0A834004811C2 /* inc */, 65C35EA812F0A834004811C2 /* eventdispatcher.c */, @@ -7414,6 +7426,8 @@ 65C35E4F12EFB2F3004811C2 /* uavobjectdefinition */ = { isa = PBXGroup; children = ( + 65E6D80713E3A4D0002A557A /* hwsettings.xml */, + 65E8C788139AA2A800E1F979 /* accessorydesired.xml */, 65C35E5012EFB2F3004811C2 /* actuatorcommand.xml */, 65C35E5112EFB2F3004811C2 /* actuatordesired.xml */, 65C35E5212EFB2F3004811C2 /* actuatorsettings.xml */, @@ -7425,6 +7439,7 @@ 65E410AE12F65AEA00725888 /* attitudesettings.xml */, 65C35E5912EFB2F3004811C2 /* baroaltitude.xml */, 65C35E5A12EFB2F3004811C2 /* batterysettings.xml */, + 655B1A8E13B2FC0900B0E48D /* camerastabsettings.xml */, 652C8568132B632A00BFCC70 /* firmwareiapobj.xml */, 65C35E5C12EFB2F3004811C2 /* flightbatterystate.xml */, 65C35E5D12EFB2F3004811C2 /* flightplancontrol.xml */, @@ -7459,6 +7474,7 @@ 65C35E7712EFB2F3004811C2 /* velocityactual.xml */, 65C35E7812EFB2F3004811C2 /* velocitydesired.xml */, 65C35E7912EFB2F3004811C2 /* watchdogstatus.xml */, + 65DEA79113F2143B00095B06 /* cameradesired.xml */, ); path = uavobjectdefinition; sourceTree = ""; @@ -7492,6 +7508,23 @@ path = inc; sourceTree = ""; }; + 65C9903B13A871B90082BD60 /* CameraStab */ = { + isa = PBXGroup; + children = ( + 65C9903C13A871B90082BD60 /* camerastab.c */, + 65C9903D13A871B90082BD60 /* inc */, + ); + path = CameraStab; + sourceTree = ""; + }; + 65C9903D13A871B90082BD60 /* inc */ = { + isa = PBXGroup; + children = ( + 65C9903E13A871B90082BD60 /* camerastab.h */, + ); + path = inc; + sourceTree = ""; + }; 65E6DF7012E02E8E00058553 /* CopterControl */ = { isa = PBXGroup; children = ( @@ -7657,6 +7690,9 @@ 65E8F03711EFF25C00BBF654 /* printf-stdarg.c */, 6528CCB412E406B800CF5144 /* pios_adxl345.c */, 6512D60712ED4CB8008175E5 /* pios_flash_w25x.c */, + 65FF4D5E137EDEC100146BE4 /* pios_flashfs_objlist.c */, + 6562BE1713CCAD0600C823E8 /* pios_rcvr.c */, + 65E8C743139A6D0900E1F979 /* pios_crc.c */, ); name = Common; path = ../../PiOS/Common; @@ -7666,13 +7702,7 @@ isa = PBXGroup; children = ( 6528CCE212E40F6700CF5144 /* pios_adxl345.h */, - 6512D60512ED4CA2008175E5 /* pios_flash_w25x.h */, - 6526645B122DF972006F9A3C /* pios_wdg.h */, - 651CF9EF120B700D00EEFD70 /* pios_usb_hid_desc.h */, - 651CF9F0120B700D00EEFD70 /* pios_usb_hid_istr.h */, - 651CF9F1120B700D00EEFD70 /* pios_usb_hid_prop.h */, - 651CF9F2120B700D00EEFD70 /* pios_usb_hid_pwr.h */, - 651CF9F3120B700D00EEFD70 /* usb_conf.h */, + 65E8C745139A6D1A00E1F979 /* pios_crc.h */, 65E8F03A11EFF25C00BBF654 /* pios_adc.h */, 65E6E09912E037C800058553 /* pios_adc_priv.h */, 65E8F03B11EFF25C00BBF654 /* pios_bmp085.h */, @@ -7681,6 +7711,8 @@ 65E8F03E11EFF25C00BBF654 /* pios_debug.h */, 65E8F03F11EFF25C00BBF654 /* pios_delay.h */, 65E8F04011EFF25C00BBF654 /* pios_exti.h */, + 6512D60512ED4CA2008175E5 /* pios_flash_w25x.h */, + 65FF4D61137EFA4F00146BE4 /* pios_flashfs_objlist.h */, 65E8F04111EFF25C00BBF654 /* pios_gpio.h */, 65E8F04211EFF25C00BBF654 /* pios_hmc5843.h */, 65E8F04311EFF25C00BBF654 /* pios_i2c.h */, @@ -7705,6 +7737,12 @@ 65E8F05211EFF25C00BBF654 /* pios_usart_priv.h */, 65E8F05311EFF25C00BBF654 /* pios_usb.h */, 65E8F05511EFF25C00BBF654 /* pios_usb_hid.h */, + 651CF9EF120B700D00EEFD70 /* pios_usb_hid_desc.h */, + 651CF9F0120B700D00EEFD70 /* pios_usb_hid_istr.h */, + 651CF9F1120B700D00EEFD70 /* pios_usb_hid_prop.h */, + 651CF9F2120B700D00EEFD70 /* pios_usb_hid_pwr.h */, + 6526645B122DF972006F9A3C /* pios_wdg.h */, + 651CF9F3120B700D00EEFD70 /* usb_conf.h */, 65E8F05611EFF25C00BBF654 /* stm32f10x_conf.h */, ); name = inc; @@ -7749,6 +7787,8 @@ 65E8F05911EFF25C00BBF654 /* Libraries */ = { isa = PBXGroup; children = ( + 6572CB1613D0F2B200FC2972 /* link_STM32103CB_CC_Rev1_memory.ld */, + 6572CB1713D0F2B200FC2972 /* link_STM32103CB_CC_Rev1_sections.ld */, 65E8F05A11EFF25C00BBF654 /* CMSIS */, 65E8F06B11EFF25C00BBF654 /* dosfs */, 65E8F07111EFF25C00BBF654 /* FreeRTOS */, @@ -8453,6 +8493,7 @@ }; buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "OpenPilotOSX" */; compatibilityVersion = "Xcode 3.1"; + developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, diff --git a/flight/Project/gdb/bl_coptercontrol b/flight/Project/gdb/bl_coptercontrol index 52411d9bd..45bb50412 100644 --- a/flight/Project/gdb/bl_coptercontrol +++ b/flight/Project/gdb/bl_coptercontrol @@ -1,7 +1,7 @@ define connect target remote localhost:3333 monitor cortex_m3 vector_catch all - file ./build/bl_coptercontrol/CopterControl_BL.elf + file ./build/bl_coptercontrol/bl_coptercontrol.elf end #monitor reset halt diff --git a/flight/Project/gdb/coptercontrol b/flight/Project/gdb/coptercontrol index d08282e50..7e7b53453 100644 --- a/flight/Project/gdb/coptercontrol +++ b/flight/Project/gdb/coptercontrol @@ -1,7 +1,7 @@ define connect target remote localhost:3333 monitor cortex_m3 vector_catch all - file ./build/coptercontrol/CopterControl.elf + file ./build/fw_coptercontrol/fw_coptercontrol.elf end #monitor reset halt diff --git a/flight/Project/gdb/openpilot b/flight/Project/gdb/openpilot index 28ae59b1c..7c02a7a0b 100644 --- a/flight/Project/gdb/openpilot +++ b/flight/Project/gdb/openpilot @@ -1,7 +1,7 @@ define connect target remote localhost:3333 monitor cortex_m3 vector_catch all - file ./build/openpilot/OpenPilot.elf + file ./build/fw_openpilot/fw_openpilot.elf end #monitor reset halt diff --git a/flight/UAVObjects/eventdispatcher.c b/flight/UAVObjects/eventdispatcher.c index 353739468..53a6e039d 100644 --- a/flight/UAVObjects/eventdispatcher.c +++ b/flight/UAVObjects/eventdispatcher.c @@ -1,377 +1,387 @@ -/** - ****************************************************************************** - * - * @file eventdispatcher.c - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @brief Event dispatcher, distributes object events as callbacks. Alternative - * to using tasks and queues. All callbacks are invoked from the event task. - * @see The GNU Public License (GPL) Version 3 - * - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "openpilot.h" - -// Private constants -#define MAX_QUEUE_SIZE 20 -#define STACK_SIZE configMINIMAL_STACK_SIZE -#define TASK_PRIORITY (tskIDLE_PRIORITY + 3) -#define MAX_UPDATE_PERIOD_MS 1000 - -// Private types - - -/** - * Event callback information - */ -typedef struct { - UAVObjEvent ev; /** The actual event */ - UAVObjEventCallback cb; /** The callback function, or zero if none */ - xQueueHandle queue; /** The queue or zero if none */ -} EventCallbackInfo; - -/** - * List of object properties that are needed for the periodic updates. - */ -struct PeriodicObjectListStruct { - EventCallbackInfo evInfo; /** Event callback information */ - int32_t updatePeriodMs; /** Update period in ms or 0 if no periodic updates are needed */ - int32_t timeToNextUpdateMs; /** Time delay to the next update */ - struct PeriodicObjectListStruct* next; /** Needed by linked list library (utlist.h) */ -}; -typedef struct PeriodicObjectListStruct PeriodicObjectList; - -// Private variables -static PeriodicObjectList* objList; -static xQueueHandle queue; -static xTaskHandle eventTaskHandle; -static xSemaphoreHandle mutex; -static EventStats stats; - -// Private functions -static int32_t processPeriodicUpdates(); -static void eventTask(); -static int32_t eventPeriodicCreate(UAVObjEvent* ev, UAVObjEventCallback cb, xQueueHandle queue, int32_t periodMs); -static int32_t eventPeriodicUpdate(UAVObjEvent* ev, UAVObjEventCallback cb, xQueueHandle queue, int32_t periodMs); -static uint32_t randomizePeriod(uint32_t periodMs); - - -/** - * Initialize the dispatcher - * \return Success (0), failure (-1) - */ -int32_t EventDispatcherInitialize() -{ - // Initialize variables - objList = NULL; - memset(&stats, 0, sizeof(EventStats)); - - // Create mutex - mutex = xSemaphoreCreateRecursiveMutex(); - if (mutex == NULL) - return -1; - - // Create event queue - queue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(EventCallbackInfo)); - - // Create task - xTaskCreate( eventTask, (signed char*)"Event", STACK_SIZE, NULL, TASK_PRIORITY, &eventTaskHandle ); - - // Done - return 0; -} - -/** - * Get the statistics counters - * @param[out] statsOut The statistics counters will be copied there - */ -void EventGetStats(EventStats* statsOut) -{ - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - memcpy(statsOut, &stats, sizeof(EventStats)); - xSemaphoreGiveRecursive(mutex); -} - -/** - * Clear the statistics counters - */ -void EventClearStats() -{ - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - memset(&stats, 0, sizeof(EventStats)); - xSemaphoreGiveRecursive(mutex); -} - -/** - * Dispatch an event by invoking the supplied callback. The function - * returns imidiatelly, the callback is invoked from the event task. - * \param[in] ev The event to be dispatched - * \param[in] cb The callback function - * \return Success (0), failure (-1) - */ -int32_t EventCallbackDispatch(UAVObjEvent* ev, UAVObjEventCallback cb) -{ - EventCallbackInfo evInfo; - // Initialize event callback information - memcpy(&evInfo.ev, ev, sizeof(UAVObjEvent)); - evInfo.cb = cb; - evInfo.queue = 0; - // Push to queue - return xQueueSend(queue, &evInfo, 0); // will not block if queue is full -} - -/** - * Dispatch an event at periodic intervals. - * \param[in] ev The event to be dispatched - * \param[in] cb The callback to be invoked - * \param[in] periodMs The period the event is generated - * \return Success (0), failure (-1) - */ -int32_t EventPeriodicCallbackCreate(UAVObjEvent* ev, UAVObjEventCallback cb, int32_t periodMs) -{ - return eventPeriodicCreate(ev, cb, 0, periodMs); -} - -/** - * Update the period of a periodic event. - * \param[in] ev The event to be dispatched - * \param[in] cb The callback to be invoked - * \param[in] periodMs The period the event is generated - * \return Success (0), failure (-1) - */ -int32_t EventPeriodicCallbackUpdate(UAVObjEvent* ev, UAVObjEventCallback cb, int32_t periodMs) -{ - return eventPeriodicUpdate(ev, cb, 0, periodMs); -} - -/** - * Dispatch an event at periodic intervals. - * \param[in] ev The event to be dispatched - * \param[in] queue The queue that the event will be pushed in - * \param[in] periodMs The period the event is generated - * \return Success (0), failure (-1) - */ -int32_t EventPeriodicQueueCreate(UAVObjEvent* ev, xQueueHandle queue, int32_t periodMs) -{ - return eventPeriodicCreate(ev, 0, queue, periodMs); -} - -/** - * Update the period of a periodic event. - * \param[in] ev The event to be dispatched - * \param[in] queue The queue - * \param[in] periodMs The period the event is generated - * \return Success (0), failure (-1) - */ -int32_t EventPeriodicQueueUpdate(UAVObjEvent* ev, xQueueHandle queue, int32_t periodMs) -{ - return eventPeriodicUpdate(ev, 0, queue, periodMs); -} - -/** - * Dispatch an event through a callback at periodic intervals. - * \param[in] ev The event to be dispatched - * \param[in] cb The callback to be invoked or zero if none - * \param[in] queue The queue or zero if none - * \param[in] periodMs The period the event is generated - * \return Success (0), failure (-1) - */ -static int32_t eventPeriodicCreate(UAVObjEvent* ev, UAVObjEventCallback cb, xQueueHandle queue, int32_t periodMs) -{ - PeriodicObjectList* objEntry; - // Get lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - // Check that the object is not already connected - LL_FOREACH(objList, objEntry) - { - if (objEntry->evInfo.cb == cb && - objEntry->evInfo.queue == queue && - objEntry->evInfo.ev.obj == ev->obj && - objEntry->evInfo.ev.instId == ev->instId && - objEntry->evInfo.ev.event == ev->event) - { - // Already registered, do nothing - xSemaphoreGiveRecursive(mutex); - return -1; - } - } - // Create handle - objEntry = (PeriodicObjectList*)pvPortMalloc(sizeof(PeriodicObjectList)); - if (objEntry == NULL) return -1; - objEntry->evInfo.ev.obj = ev->obj; - objEntry->evInfo.ev.instId = ev->instId; - objEntry->evInfo.ev.event = ev->event; - objEntry->evInfo.cb = cb; - objEntry->evInfo.queue = queue; - objEntry->updatePeriodMs = periodMs; - objEntry->timeToNextUpdateMs = randomizePeriod(periodMs); // avoid bunching of updates - // Add to list - LL_APPEND(objList, objEntry); - // Release lock - xSemaphoreGiveRecursive(mutex); - return 0; -} - -/** - * Update the period of a periodic event. - * \param[in] ev The event to be dispatched - * \param[in] cb The callback to be invoked or zero if none - * \param[in] queue The queue or zero if none - * \param[in] periodMs The period the event is generated - * \return Success (0), failure (-1) - */ -static int32_t eventPeriodicUpdate(UAVObjEvent* ev, UAVObjEventCallback cb, xQueueHandle queue, int32_t periodMs) -{ - PeriodicObjectList* objEntry; - // Get lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - // Find object - LL_FOREACH(objList, objEntry) - { - if (objEntry->evInfo.cb == cb && - objEntry->evInfo.queue == queue && - objEntry->evInfo.ev.obj == ev->obj && - objEntry->evInfo.ev.instId == ev->instId && - objEntry->evInfo.ev.event == ev->event) - { - // Object found, update period - objEntry->updatePeriodMs = periodMs; - objEntry->timeToNextUpdateMs = randomizePeriod(periodMs); // avoid bunching of updates - // Release lock - xSemaphoreGiveRecursive(mutex); - return 0; - } - } - // If this point is reached the object was not found - xSemaphoreGiveRecursive(mutex); - return -1; -} - -/** - * Event task, responsible of invoking callbacks. - */ -static void eventTask() -{ - int32_t timeToNextUpdateMs; - int32_t delayMs; - EventCallbackInfo evInfo; - - // Initialize time - timeToNextUpdateMs = xTaskGetTickCount()*portTICK_RATE_MS; - - // Loop forever - while (1) - { - // Calculate delay time - delayMs = timeToNextUpdateMs-(xTaskGetTickCount()*portTICK_RATE_MS); - if (delayMs < 0) - { - delayMs = 0; - } - - // Wait for queue message - if ( xQueueReceive(queue, &evInfo, delayMs/portTICK_RATE_MS) == pdTRUE ) - { - // Invoke callback, if one - if ( evInfo.cb != 0) - { - evInfo.cb(&evInfo.ev); // the function is expected to copy the event information - } - } - - // Process periodic updates - if ((xTaskGetTickCount()*portTICK_RATE_MS) >= timeToNextUpdateMs ) - { - timeToNextUpdateMs = processPeriodicUpdates(); - } - } -} - -/** - * Handle periodic updates for all objects. - * \return The system time until the next update (in ms) or -1 if failed - */ -static int32_t processPeriodicUpdates() -{ - PeriodicObjectList* objEntry; - int32_t timeNow; - int32_t timeToNextUpdate; - int32_t offset; - - // Get lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Iterate through each object and update its timer, if zero then transmit object. - // Also calculate smallest delay to next update. - timeToNextUpdate = xTaskGetTickCount()*portTICK_RATE_MS + MAX_UPDATE_PERIOD_MS; - LL_FOREACH(objList, objEntry) - { - // If object is configured for periodic updates - if (objEntry->updatePeriodMs > 0) - { - // Check if time for the next update - timeNow = xTaskGetTickCount()*portTICK_RATE_MS; - if (objEntry->timeToNextUpdateMs <= timeNow) - { - // Reset timer - offset = ( timeNow - objEntry->timeToNextUpdateMs ) % objEntry->updatePeriodMs; - objEntry->timeToNextUpdateMs = timeNow + objEntry->updatePeriodMs - offset; - // Invoke callback, if one - if ( objEntry->evInfo.cb != 0) - { - objEntry->evInfo.cb(&objEntry->evInfo.ev); // the function is expected to copy the event information - } - // Push event to queue, if one - if ( objEntry->evInfo.queue != 0) - { - if ( xQueueSend(objEntry->evInfo.queue, &objEntry->evInfo.ev, 0) != pdTRUE ) // do not block if queue is full - { - ++stats.eventErrors; - } - } - } - // Update minimum delay - if (objEntry->timeToNextUpdateMs < timeToNextUpdate) - { - timeToNextUpdate = objEntry->timeToNextUpdateMs; - } - } - } - - // Done - xSemaphoreGiveRecursive(mutex); - return timeToNextUpdate; -} - -/** - * Return a psedorandom integer from 0 to periodMs - * Based on the Park-Miller-Carta Pseudo-Random Number Generator - * http://www.firstpr.com.au/dsp/rand31/ - */ -static uint32_t randomizePeriod(uint32_t periodMs) -{ - static uint32_t seed = 1; - uint32_t hi, lo; - lo = 16807 * (seed & 0xFFFF); - hi = 16807 * (seed >> 16); - lo += (hi & 0x7FFF) << 16; - lo += hi >> 15; - if (lo > 0x7FFFFFFF) lo -= 0x7FFFFFFF; - seed = lo; - return (uint32_t)( ((float)periodMs * (float)lo) / (float)0x7FFFFFFF ); -} - +/** + ****************************************************************************** + * + * @file eventdispatcher.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Event dispatcher, distributes object events as callbacks. Alternative + * to using tasks and queues. All callbacks are invoked from the event task. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "openpilot.h" + +// Private constants +#if defined(PIOS_EVENTDISAPTCHER_QUEUE) +#define MAX_QUEUE_SIZE PIOS_EVENTDISAPTCHER_QUEUE +#else +#define MAX_QUEUE_SIZE 20 +#endif + +#if defined(PIOS_EVENTDISPATCHER_STACK_SIZE) +#define STACK_SIZE PIOS_EVENTDISPATCHER_STACK_SIZE +#else +#define STACK_SIZE configMINIMAL_STACK_SIZE +#endif /* PIOS_EVENTDISPATCHER_STACK_SIZE */ + +#define TASK_PRIORITY (tskIDLE_PRIORITY + 3) +#define MAX_UPDATE_PERIOD_MS 1000 + +// Private types + + +/** + * Event callback information + */ +typedef struct { + UAVObjEvent ev; /** The actual event */ + UAVObjEventCallback cb; /** The callback function, or zero if none */ + xQueueHandle queue; /** The queue or zero if none */ +} EventCallbackInfo; + +/** + * List of object properties that are needed for the periodic updates. + */ +struct PeriodicObjectListStruct { + EventCallbackInfo evInfo; /** Event callback information */ + int32_t updatePeriodMs; /** Update period in ms or 0 if no periodic updates are needed */ + int32_t timeToNextUpdateMs; /** Time delay to the next update */ + struct PeriodicObjectListStruct* next; /** Needed by linked list library (utlist.h) */ +}; +typedef struct PeriodicObjectListStruct PeriodicObjectList; + +// Private variables +static PeriodicObjectList* objList; +static xQueueHandle queue; +static xTaskHandle eventTaskHandle; +static xSemaphoreHandle mutex; +static EventStats stats; + +// Private functions +static int32_t processPeriodicUpdates(); +static void eventTask(); +static int32_t eventPeriodicCreate(UAVObjEvent* ev, UAVObjEventCallback cb, xQueueHandle queue, int32_t periodMs); +static int32_t eventPeriodicUpdate(UAVObjEvent* ev, UAVObjEventCallback cb, xQueueHandle queue, int32_t periodMs); +static uint32_t randomizePeriod(uint32_t periodMs); + + +/** + * Initialize the dispatcher + * \return Success (0), failure (-1) + */ +int32_t EventDispatcherInitialize() +{ + // Initialize variables + objList = NULL; + memset(&stats, 0, sizeof(EventStats)); + + // Create mutex + mutex = xSemaphoreCreateRecursiveMutex(); + if (mutex == NULL) + return -1; + + // Create event queue + queue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(EventCallbackInfo)); + + // Create task + xTaskCreate( eventTask, (signed char*)"Event", STACK_SIZE, NULL, TASK_PRIORITY, &eventTaskHandle ); + + // Done + return 0; +} + +/** + * Get the statistics counters + * @param[out] statsOut The statistics counters will be copied there + */ +void EventGetStats(EventStats* statsOut) +{ + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + memcpy(statsOut, &stats, sizeof(EventStats)); + xSemaphoreGiveRecursive(mutex); +} + +/** + * Clear the statistics counters + */ +void EventClearStats() +{ + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + memset(&stats, 0, sizeof(EventStats)); + xSemaphoreGiveRecursive(mutex); +} + +/** + * Dispatch an event by invoking the supplied callback. The function + * returns imidiatelly, the callback is invoked from the event task. + * \param[in] ev The event to be dispatched + * \param[in] cb The callback function + * \return Success (0), failure (-1) + */ +int32_t EventCallbackDispatch(UAVObjEvent* ev, UAVObjEventCallback cb) +{ + EventCallbackInfo evInfo; + // Initialize event callback information + memcpy(&evInfo.ev, ev, sizeof(UAVObjEvent)); + evInfo.cb = cb; + evInfo.queue = 0; + // Push to queue + return xQueueSend(queue, &evInfo, 0); // will not block if queue is full +} + +/** + * Dispatch an event at periodic intervals. + * \param[in] ev The event to be dispatched + * \param[in] cb The callback to be invoked + * \param[in] periodMs The period the event is generated + * \return Success (0), failure (-1) + */ +int32_t EventPeriodicCallbackCreate(UAVObjEvent* ev, UAVObjEventCallback cb, int32_t periodMs) +{ + return eventPeriodicCreate(ev, cb, 0, periodMs); +} + +/** + * Update the period of a periodic event. + * \param[in] ev The event to be dispatched + * \param[in] cb The callback to be invoked + * \param[in] periodMs The period the event is generated + * \return Success (0), failure (-1) + */ +int32_t EventPeriodicCallbackUpdate(UAVObjEvent* ev, UAVObjEventCallback cb, int32_t periodMs) +{ + return eventPeriodicUpdate(ev, cb, 0, periodMs); +} + +/** + * Dispatch an event at periodic intervals. + * \param[in] ev The event to be dispatched + * \param[in] queue The queue that the event will be pushed in + * \param[in] periodMs The period the event is generated + * \return Success (0), failure (-1) + */ +int32_t EventPeriodicQueueCreate(UAVObjEvent* ev, xQueueHandle queue, int32_t periodMs) +{ + return eventPeriodicCreate(ev, 0, queue, periodMs); +} + +/** + * Update the period of a periodic event. + * \param[in] ev The event to be dispatched + * \param[in] queue The queue + * \param[in] periodMs The period the event is generated + * \return Success (0), failure (-1) + */ +int32_t EventPeriodicQueueUpdate(UAVObjEvent* ev, xQueueHandle queue, int32_t periodMs) +{ + return eventPeriodicUpdate(ev, 0, queue, periodMs); +} + +/** + * Dispatch an event through a callback at periodic intervals. + * \param[in] ev The event to be dispatched + * \param[in] cb The callback to be invoked or zero if none + * \param[in] queue The queue or zero if none + * \param[in] periodMs The period the event is generated + * \return Success (0), failure (-1) + */ +static int32_t eventPeriodicCreate(UAVObjEvent* ev, UAVObjEventCallback cb, xQueueHandle queue, int32_t periodMs) +{ + PeriodicObjectList* objEntry; + // Get lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + // Check that the object is not already connected + LL_FOREACH(objList, objEntry) + { + if (objEntry->evInfo.cb == cb && + objEntry->evInfo.queue == queue && + objEntry->evInfo.ev.obj == ev->obj && + objEntry->evInfo.ev.instId == ev->instId && + objEntry->evInfo.ev.event == ev->event) + { + // Already registered, do nothing + xSemaphoreGiveRecursive(mutex); + return -1; + } + } + // Create handle + objEntry = (PeriodicObjectList*)pvPortMalloc(sizeof(PeriodicObjectList)); + if (objEntry == NULL) return -1; + objEntry->evInfo.ev.obj = ev->obj; + objEntry->evInfo.ev.instId = ev->instId; + objEntry->evInfo.ev.event = ev->event; + objEntry->evInfo.cb = cb; + objEntry->evInfo.queue = queue; + objEntry->updatePeriodMs = periodMs; + objEntry->timeToNextUpdateMs = randomizePeriod(periodMs); // avoid bunching of updates + // Add to list + LL_APPEND(objList, objEntry); + // Release lock + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Update the period of a periodic event. + * \param[in] ev The event to be dispatched + * \param[in] cb The callback to be invoked or zero if none + * \param[in] queue The queue or zero if none + * \param[in] periodMs The period the event is generated + * \return Success (0), failure (-1) + */ +static int32_t eventPeriodicUpdate(UAVObjEvent* ev, UAVObjEventCallback cb, xQueueHandle queue, int32_t periodMs) +{ + PeriodicObjectList* objEntry; + // Get lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + // Find object + LL_FOREACH(objList, objEntry) + { + if (objEntry->evInfo.cb == cb && + objEntry->evInfo.queue == queue && + objEntry->evInfo.ev.obj == ev->obj && + objEntry->evInfo.ev.instId == ev->instId && + objEntry->evInfo.ev.event == ev->event) + { + // Object found, update period + objEntry->updatePeriodMs = periodMs; + objEntry->timeToNextUpdateMs = randomizePeriod(periodMs); // avoid bunching of updates + // Release lock + xSemaphoreGiveRecursive(mutex); + return 0; + } + } + // If this point is reached the object was not found + xSemaphoreGiveRecursive(mutex); + return -1; +} + +/** + * Event task, responsible of invoking callbacks. + */ +static void eventTask() +{ + int32_t timeToNextUpdateMs; + int32_t delayMs; + EventCallbackInfo evInfo; + + // Initialize time + timeToNextUpdateMs = xTaskGetTickCount()*portTICK_RATE_MS; + + // Loop forever + while (1) + { + // Calculate delay time + delayMs = timeToNextUpdateMs-(xTaskGetTickCount()*portTICK_RATE_MS); + if (delayMs < 0) + { + delayMs = 0; + } + + // Wait for queue message + if ( xQueueReceive(queue, &evInfo, delayMs/portTICK_RATE_MS) == pdTRUE ) + { + // Invoke callback, if one + if ( evInfo.cb != 0) + { + evInfo.cb(&evInfo.ev); // the function is expected to copy the event information + } + } + + // Process periodic updates + if ((xTaskGetTickCount()*portTICK_RATE_MS) >= timeToNextUpdateMs ) + { + timeToNextUpdateMs = processPeriodicUpdates(); + } + } +} + +/** + * Handle periodic updates for all objects. + * \return The system time until the next update (in ms) or -1 if failed + */ +static int32_t processPeriodicUpdates() +{ + PeriodicObjectList* objEntry; + int32_t timeNow; + int32_t timeToNextUpdate; + int32_t offset; + + // Get lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Iterate through each object and update its timer, if zero then transmit object. + // Also calculate smallest delay to next update. + timeToNextUpdate = xTaskGetTickCount()*portTICK_RATE_MS + MAX_UPDATE_PERIOD_MS; + LL_FOREACH(objList, objEntry) + { + // If object is configured for periodic updates + if (objEntry->updatePeriodMs > 0) + { + // Check if time for the next update + timeNow = xTaskGetTickCount()*portTICK_RATE_MS; + if (objEntry->timeToNextUpdateMs <= timeNow) + { + // Reset timer + offset = ( timeNow - objEntry->timeToNextUpdateMs ) % objEntry->updatePeriodMs; + objEntry->timeToNextUpdateMs = timeNow + objEntry->updatePeriodMs - offset; + // Invoke callback, if one + if ( objEntry->evInfo.cb != 0) + { + objEntry->evInfo.cb(&objEntry->evInfo.ev); // the function is expected to copy the event information + } + // Push event to queue, if one + if ( objEntry->evInfo.queue != 0) + { + if ( xQueueSend(objEntry->evInfo.queue, &objEntry->evInfo.ev, 0) != pdTRUE ) // do not block if queue is full + { + ++stats.eventErrors; + } + } + } + // Update minimum delay + if (objEntry->timeToNextUpdateMs < timeToNextUpdate) + { + timeToNextUpdate = objEntry->timeToNextUpdateMs; + } + } + } + + // Done + xSemaphoreGiveRecursive(mutex); + return timeToNextUpdate; +} + +/** + * Return a psedorandom integer from 0 to periodMs + * Based on the Park-Miller-Carta Pseudo-Random Number Generator + * http://www.firstpr.com.au/dsp/rand31/ + */ +static uint32_t randomizePeriod(uint32_t periodMs) +{ + static uint32_t seed = 1; + uint32_t hi, lo; + lo = 16807 * (seed & 0xFFFF); + hi = 16807 * (seed >> 16); + lo += (hi & 0x7FFF) << 16; + lo += hi >> 15; + if (lo > 0x7FFFFFFF) lo -= 0x7FFFFFFF; + seed = lo; + return (uint32_t)( ((float)periodMs * (float)lo) / (float)0x7FFFFFFF ); +} + diff --git a/flight/UAVObjects/inc/uavobjectmanager.h b/flight/UAVObjects/inc/uavobjectmanager.h index e7bb8b9c7..ac5d34b5c 100644 --- a/flight/UAVObjects/inc/uavobjectmanager.h +++ b/flight/UAVObjects/inc/uavobjectmanager.h @@ -153,9 +153,13 @@ int32_t UAVObjSaveMetaobjects(); int32_t UAVObjLoadMetaobjects(); int32_t UAVObjDeleteMetaobjects(); int32_t UAVObjSetData(UAVObjHandle obj, const void* dataIn); +int32_t UAVObjSetDataField(UAVObjHandle obj, const void* dataIn, uint32_t offset, uint32_t size); int32_t UAVObjGetData(UAVObjHandle obj, void* dataOut); +int32_t UAVObjGetDataField(UAVObjHandle obj, void* dataOut, uint32_t offset, uint32_t size); int32_t UAVObjSetInstanceData(UAVObjHandle obj, uint16_t instId, const void* dataIn); +int32_t UAVObjSetInstanceDataField(UAVObjHandle obj, uint16_t instId, const void* dataIn, uint32_t offset, uint32_t size); int32_t UAVObjGetInstanceData(UAVObjHandle obj, uint16_t instId, void* dataOut); +int32_t UAVObjGetInstanceDataField(UAVObjHandle obj, uint16_t instId, void* dataOut, uint32_t offset, uint32_t size); int32_t UAVObjSetMetadata(UAVObjHandle obj, const UAVObjMetadata* dataIn); int32_t UAVObjGetMetadata(UAVObjHandle obj, UAVObjMetadata* dataOut); int8_t UAVObjReadOnly(UAVObjHandle obj); diff --git a/flight/UAVObjects/inc/uavobjectsinit.h b/flight/UAVObjects/inc/uavobjectsinittemplate.h similarity index 93% rename from flight/UAVObjects/inc/uavobjectsinit.h rename to flight/UAVObjects/inc/uavobjectsinittemplate.h index ec946ba92..ec11c47ad 100644 --- a/flight/UAVObjects/inc/uavobjectsinit.h +++ b/flight/UAVObjects/inc/uavobjectsinittemplate.h @@ -29,4 +29,6 @@ void UAVObjectsInitializeAll(); +#define UAVOBJECTS_LARGEST $(SIZECALCULATION) + #endif // UAVOBJECTSINIT_H diff --git a/flight/UAVObjects/inc/uavobjecttemplate.h b/flight/UAVObjects/inc/uavobjecttemplate.h index 938c8ebf7..9564d05d2 100644 --- a/flight/UAVObjects/inc/uavobjecttemplate.h +++ b/flight/UAVObjects/inc/uavobjecttemplate.h @@ -82,6 +82,9 @@ int32_t $(NAME)Initialize(); UAVObjHandle $(NAME)Handle(); void $(NAME)SetDefaults(UAVObjHandle obj, uint16_t instId); +// set/Get functions +$(SETGETFIELDSEXTERN) + #endif // $(NAMEUC)_H /** diff --git a/flight/UAVObjects/uavobjectmanager.c b/flight/UAVObjects/uavobjectmanager.c index 50558d411..7d30bee7b 100644 --- a/flight/UAVObjects/uavobjectmanager.c +++ b/flight/UAVObjects/uavobjectmanager.c @@ -1,1607 +1,1620 @@ -/** - ****************************************************************************** - * @addtogroup UAVObjects OpenPilot UAVObjects - * @{ - * @addtogroup UAV Object Manager - * @brief The core UAV Objects functions, most of which are wrappered by - * autogenerated defines - * @{ - * - * - * @file uavobjectmanager.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @brief Object manager library. This library holds a collection of all objects. - * It can be used by all modules/libraries to find an object reference. - * @see The GNU Public License (GPL) Version 3 - * - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "openpilot.h" - -// Constants - -// Private types - -/** - * List of event queues and the eventmask associated with the queue. - */ -struct ObjectEventListStruct { - xQueueHandle queue; - UAVObjEventCallback cb; - int32_t eventMask; - struct ObjectEventListStruct* next; -}; -typedef struct ObjectEventListStruct ObjectEventList; - -/** - * List of object instances, holds the actual data structure and instance ID - */ -struct ObjectInstListStruct { - void* data; - uint16_t instId; - struct ObjectInstListStruct* next; -}; -typedef struct ObjectInstListStruct ObjectInstList; - -/** - * List of objects registered in the object manager - */ -struct ObjectListStruct { - uint32_t id; /** The object ID */ - const char* name; /** The object name */ - int8_t isMetaobject; /** Set to 1 if this is a metaobject */ - int8_t isSingleInstance; /** Set to 1 if this object has a single instance */ - int8_t isSettings; /** Set to 1 if this object is a settings object */ - uint16_t numBytes; /** Number of data bytes contained in the object (for a single instance) */ - uint16_t numInstances; /** Number of instances */ - struct ObjectListStruct* linkedObj; /** Linked object, for regular objects this is the metaobject and for metaobjects it is the parent object */ - ObjectInstList instances; /** List of object instances, instance 0 always exists */ - ObjectEventList* events; /** Event queues registered on the object */ - struct ObjectListStruct* next; /** Needed by linked list library (utlist.h) */ -}; -typedef struct ObjectListStruct ObjectList; - -// Private functions -static int32_t sendEvent(ObjectList* obj, uint16_t instId, UAVObjEventType event); -static ObjectInstList* createInstance(ObjectList* obj, uint16_t instId); -static ObjectInstList* getInstance(ObjectList* obj, uint16_t instId); -static int32_t connectObj(UAVObjHandle obj, xQueueHandle queue, UAVObjEventCallback cb, int32_t eventMask); -static int32_t disconnectObj(UAVObjHandle obj, xQueueHandle queue, UAVObjEventCallback cb); - -#if defined(PIOS_INCLUDE_SDCARD) -static void objectFilename(ObjectList* obj, uint8_t* filename); -static void customSPrintf(uint8_t* buffer, uint8_t* format, ...); -#endif - -// Private variables -static ObjectList* objList; -static xSemaphoreHandle mutex; -static UAVObjMetadata defMetadata; -static UAVObjStats stats; - -/** - * Initialize the object manager - * \return 0 Success - * \return -1 Failure - */ -int32_t UAVObjInitialize() -{ - // Initialize variables - objList = NULL; - memset(&stats, 0, sizeof(UAVObjStats)); - - // Create mutex - mutex = xSemaphoreCreateRecursiveMutex(); - if (mutex == NULL) - return -1; - - // Initialize default metadata structure (metadata of metaobjects) - defMetadata.access = ACCESS_READWRITE; - defMetadata.gcsAccess = ACCESS_READWRITE; - defMetadata.telemetryAcked = 1; - defMetadata.telemetryUpdateMode = UPDATEMODE_ONCHANGE; - defMetadata.telemetryUpdatePeriod = 0; - defMetadata.gcsTelemetryAcked = 1; - defMetadata.gcsTelemetryUpdateMode = UPDATEMODE_ONCHANGE; - defMetadata.gcsTelemetryUpdatePeriod = 0; - defMetadata.loggingUpdateMode = UPDATEMODE_ONCHANGE; - defMetadata.loggingUpdatePeriod = 0; - - // Done - return 0; -} - -/** - * Get the statistics counters - * @param[out] statsOut The statistics counters will be copied there - */ -void UAVObjGetStats(UAVObjStats* statsOut) -{ - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - memcpy(statsOut, &stats, sizeof(UAVObjStats)); - xSemaphoreGiveRecursive(mutex); -} - -/** - * Clear the statistics counters - */ -void UAVObjClearStats() -{ - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - memset(&stats, 0, sizeof(UAVObjStats)); - xSemaphoreGiveRecursive(mutex); -} - -/** - * Register and new object in the object manager. - * \param[in] id Unique object ID - * \param[in] name Object name - * \param[in] nameName Metaobject name - * \param[in] isMetaobject Is this a metaobject (1:true, 0:false) - * \param[in] isSingleInstance Is this a single instance or multi-instance object - * \param[in] isSettings Is this a settings object - * \param[in] numBytes Number of bytes of object data (for one instance) - * \param[in] initCb Default field and metadata initialization function - * \return Object handle, or NULL if failure. - * \return - */ -UAVObjHandle UAVObjRegister(uint32_t id, const char* name, const char* metaName, int32_t isMetaobject, - int32_t isSingleInstance, int32_t isSettings, uint32_t numBytes, UAVObjInitializeCallback initCb) -{ - ObjectList* objEntry; - ObjectInstList* instEntry; - ObjectList* metaObj; - - // Get lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Check that the object is not already registered - LL_FOREACH(objList, objEntry) - { - if (objEntry->id == id) - { - // Already registered, ignore - xSemaphoreGiveRecursive(mutex); - return NULL; - } - } - - // Create and append entry - objEntry = (ObjectList*)pvPortMalloc(sizeof(ObjectList)); - if (objEntry == NULL) - { - xSemaphoreGiveRecursive(mutex); - return NULL; - } - objEntry->id = id; - objEntry->name = name; - objEntry->isMetaobject = (int8_t)isMetaobject; - objEntry->isSingleInstance = (int8_t)isSingleInstance; - objEntry->isSettings = (int8_t)isSettings; - objEntry->numBytes = numBytes; - objEntry->events = NULL; - objEntry->numInstances = 0; - objEntry->instances.data = NULL; - objEntry->instances.instId = 0xFFFF; - objEntry->instances.next = NULL; - objEntry->linkedObj = NULL; // will be set later - LL_APPEND(objList, objEntry); - - // Create instance zero - instEntry = createInstance(objEntry, 0); - if ( instEntry == NULL ) - { - xSemaphoreGiveRecursive(mutex); - return NULL; - } - - // Create metaobject and update linkedObj - if (isMetaobject) - { - objEntry->linkedObj = NULL; // will be set later - } - else - { - // Create metaobject - metaObj = (ObjectList*)UAVObjRegister(id+1, metaName, NULL, 1, 1, 0, sizeof(UAVObjMetadata), NULL); - // Link two objects - objEntry->linkedObj = metaObj; - metaObj->linkedObj = objEntry; - } - - // Initialize object fields and metadata to default values - if ( initCb != NULL ) - { - initCb((UAVObjHandle)objEntry, 0); - } - - // Attempt to load object's metadata from the SD card (not done directly on the metaobject, but through the object) - if ( !objEntry->isMetaobject ) - { - UAVObjLoad( (UAVObjHandle)objEntry->linkedObj, 0 ); - } - - // If this is a settings object, attempt to load from SD card - if ( objEntry->isSettings ) - { - UAVObjLoad( (UAVObjHandle)objEntry, 0 ); - } - - // Release lock - xSemaphoreGiveRecursive(mutex); - return (UAVObjHandle)objEntry; -} - -/** - * Retrieve an object from the list given its id - * \param[in] The object ID - * \return The object or NULL if not found. - */ -UAVObjHandle UAVObjGetByID(uint32_t id) -{ - ObjectList* objEntry; - - // Get lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Look for object - LL_FOREACH(objList, objEntry) - { - if (objEntry->id == id) - { - // Release lock - xSemaphoreGiveRecursive(mutex); - // Done, object found - return (UAVObjHandle)objEntry; - } - } - - // Object not found, release lock and return error - xSemaphoreGiveRecursive(mutex); - return NULL; -} - -/** - * Retrieve an object from the list given its name - * \param[in] name The name of the object - * \return The object or NULL if not found. - */ -UAVObjHandle UAVObjGetByName(char* name) -{ - ObjectList* objEntry; - - // Get lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Look for object - LL_FOREACH(objList, objEntry) - { - if (objEntry->name != NULL && strcmp(objEntry->name, name) == 0) - { - // Release lock - xSemaphoreGiveRecursive(mutex); - // Done, object found - return (UAVObjHandle)objEntry; - } - } - - // Object not found, release lock and return error - xSemaphoreGiveRecursive(mutex); - return NULL; -} - -/** - * Get the object's ID - * \param[in] obj The object handle - * \return The object ID - */ -uint32_t UAVObjGetID(UAVObjHandle obj) -{ - return ((ObjectList*)obj)->id; -} - -/** - * Get the object's name - * \param[in] obj The object handle - * \return The object's name - */ -const char* UAVObjGetName(UAVObjHandle obj) -{ - return ((ObjectList*)obj)->name; -} - -/** - * Get the number of bytes of the object's data (for one instance) - * \param[in] obj The object handle - * \return The number of bytes - */ -uint32_t UAVObjGetNumBytes(UAVObjHandle obj) -{ - return ((ObjectList*)obj)->numBytes; -} - -/** - * Get the object this object is linked to. For regular objects, the linked object - * is the metaobject. For metaobjects the linked object is the parent object. - * This function is normally only needed by the telemetry module. - * \param[in] obj The object handle - * \return The object linked object handle - */ -UAVObjHandle UAVObjGetLinkedObj(UAVObjHandle obj) -{ - return (UAVObjHandle)(((ObjectList*)obj)->linkedObj); -} - -/** - * Get the number of instances contained in the object. - * \param[in] obj The object handle - * \return The number of instances - */ -uint16_t UAVObjGetNumInstances(UAVObjHandle obj) -{ - uint32_t numInstances; - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - numInstances = ((ObjectList*)obj)->numInstances; - xSemaphoreGiveRecursive(mutex); - return numInstances; -} - -/** - * Create a new instance in the object. - * \param[in] obj The object handle - * \return The instance ID or 0 if an error - */ -uint16_t UAVObjCreateInstance(UAVObjHandle obj, UAVObjInitializeCallback initCb) -{ - ObjectList* objEntry; - ObjectInstList* instEntry; - - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Create new instance - objEntry = (ObjectList*)obj; - instEntry = createInstance(objEntry, objEntry->numInstances); - if ( instEntry == NULL ) - { - xSemaphoreGiveRecursive(mutex); - return -1; - } - - // Initialize instance data - if ( initCb != NULL ) - { - initCb(obj, instEntry->instId); - } - - // Unlock - xSemaphoreGiveRecursive(mutex); - return instEntry->instId; -} - -/** - * Does this object contains a single instance or multiple instances? - * \param[in] obj The object handle - * \return True (1) if this is a single instance object - */ -int32_t UAVObjIsSingleInstance(UAVObjHandle obj) -{ - return ((ObjectList*)obj)->isSingleInstance; -} - -/** - * Is this a metaobject? - * \param[in] obj The object handle - * \return True (1) if this is metaobject - */ -int32_t UAVObjIsMetaobject(UAVObjHandle obj) -{ - return ((ObjectList*)obj)->isMetaobject; -} - -/** - * Is this a settings object? - * \param[in] obj The object handle - * \return True (1) if this is a settings object - */ -int32_t UAVObjIsSettings(UAVObjHandle obj) -{ - return ((ObjectList*)obj)->isSettings; -} - -/** - * Unpack an object from a byte array - * \param[in] obj The object handle - * \param[in] instId The instance ID - * \param[in] dataIn The byte array - * \return 0 if success or -1 if failure - */ -int32_t UAVObjUnpack(UAVObjHandle obj, uint16_t instId, const uint8_t* dataIn) -{ - ObjectList* objEntry; - ObjectInstList* instEntry; - - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Cast handle to object - objEntry = (ObjectList*)obj; - - // Get the instance - instEntry = getInstance(objEntry, instId); - - // If the instance does not exist create it and any other instances before it - if ( instEntry == NULL ) - { - instEntry = createInstance(objEntry, instId); - if ( instEntry == NULL ) - { - // Error, unlock and return - xSemaphoreGiveRecursive(mutex); - return -1; - } - } - - // Set the data - memcpy(instEntry->data, dataIn, objEntry->numBytes); - - // Fire event - sendEvent(objEntry, instId, EV_UNPACKED); - - // Unlock - xSemaphoreGiveRecursive(mutex); - return 0; -} - -/** - * Pack an object to a byte array - * \param[in] obj The object handle - * \param[in] instId The instance ID - * \param[out] dataOut The byte array - * \return 0 if success or -1 if failure - */ -int32_t UAVObjPack(UAVObjHandle obj, uint16_t instId, uint8_t* dataOut) -{ - ObjectList* objEntry; - ObjectInstList* instEntry; - - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Cast handle to object - objEntry = (ObjectList*)obj; - - // Get the instance - instEntry = getInstance(objEntry, instId); - if ( instEntry == NULL ) - { - // Error, unlock and return - xSemaphoreGiveRecursive(mutex); - return -1; - } - - // Pack data - memcpy(dataOut, instEntry->data, objEntry->numBytes); - - // Unlock - xSemaphoreGiveRecursive(mutex); - return 0; -} - -/** - * Save the data of the specified object instance to the file system (SD card). - * The object will be appended and the file will not be closed. - * The object data can be restored using the UAVObjLoad function. - * @param[in] obj The object handle. - * @param[in] instId The instance ID - * @param[in] file File to append to - * @return 0 if success or -1 if failure - */ -int32_t UAVObjSaveToFile(UAVObjHandle obj, uint16_t instId, FILEINFO* file) -{ -#if defined(PIOS_INCLUDE_SDCARD) - uint32_t bytesWritten; - ObjectList* objEntry; - ObjectInstList* instEntry; - - // Check for file system availability - if ( PIOS_SDCARD_IsMounted() == 0 ) - { - return -1; - } - - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Cast to object - objEntry = (ObjectList*)obj; - - // Get the instance information - instEntry = getInstance(objEntry, instId); - if ( instEntry == NULL ) - { - xSemaphoreGiveRecursive(mutex); - return -1; - } - - // Write the object ID - PIOS_FWRITE(file,&objEntry->id,sizeof(objEntry->id),&bytesWritten); - - // Write the instance ID - if (!objEntry->isSingleInstance) - { - PIOS_FWRITE(file,&instEntry->instId,sizeof(instEntry->instId),&bytesWritten); - } - - // Write the data and check that the write was successful - PIOS_FWRITE(file,instEntry->data,objEntry->numBytes,&bytesWritten); - if ( bytesWritten != objEntry->numBytes ) - { - xSemaphoreGiveRecursive(mutex); - return -1; - } - - // Done - xSemaphoreGiveRecursive(mutex); -#endif /* PIOS_INCLUDE_SDCARD */ - return 0; -} - -struct fileHeader { - uint32_t id; - uint16_t instId; - uint16_t size; -} __attribute__((packed)); - -#define FLASH_MASK 0x001ff000 /* Select a sector */ - -/** - * Save the data of the specified object to the file system (SD card). - * If the object contains multiple instances, all of them will be saved. - * A new file with the name of the object will be created. - * The object data can be restored using the UAVObjLoad function. - * @param[in] obj The object handle. - * @param[in] instId The instance ID - * @param[in] file File to append to - * @return 0 if success or -1 if failure - */ -int32_t UAVObjSave(UAVObjHandle obj, uint16_t instId) -{ -#if defined(PIOS_INCLUDE_FLASH_SECTOR_SETTINGS) - ObjectList* objEntry = (ObjectList*)obj; - - if(objEntry == NULL) - return -1; - - ObjectInstList* instEntry = getInstance(objEntry, instId); - - if(instEntry == NULL) - return -1; - - if(instEntry->data == NULL) - return -1; - - - struct fileHeader header = { - .id = objEntry->id, - .instId = instId, - .size = objEntry->numBytes - }; - - uint32_t addr = (objEntry->id & FLASH_MASK); - PIOS_Flash_W25X_EraseSector(addr); - PIOS_Flash_W25X_WriteData(addr, (uint8_t *) &header, sizeof(header)); - PIOS_Flash_W25X_WriteData(addr + sizeof(header), instEntry->data,objEntry->numBytes); -#endif -#if defined(PIOS_INCLUDE_SDCARD) - FILEINFO file; - ObjectList* objEntry; - uint8_t filename[14]; - - // Check for file system availability - if ( PIOS_SDCARD_IsMounted() == 0 ) - { - return -1; - } - - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Cast to object - objEntry = (ObjectList*)obj; - - // Get filename - objectFilename(objEntry, filename); - - // Open file - if ( PIOS_FOPEN_WRITE(filename,file) ) - { - xSemaphoreGiveRecursive(mutex); - return -1; - } - - // Append object - if ( UAVObjSaveToFile(obj, instId, &file) == -1 ) - { - PIOS_FCLOSE(file); - xSemaphoreGiveRecursive(mutex); - return -1; - } - - // Done, close file and unlock - PIOS_FCLOSE(file); - xSemaphoreGiveRecursive(mutex); -#endif /* PIOS_INCLUDE_SDCARD */ - return 0; -} - -/** - * Load an object from the file system (SD card). - * @param[in] file File to read from - * @return The handle of the object loaded or NULL if a failure - */ -UAVObjHandle UAVObjLoadFromFile(FILEINFO* file) -{ -#if defined(PIOS_INCLUDE_SDCARD) - uint32_t bytesRead; - ObjectList* objEntry; - ObjectInstList* instEntry; - uint32_t objId; - uint16_t instId; - UAVObjHandle obj; - - // Check for file system availability - if ( PIOS_SDCARD_IsMounted() == 0 ) - { - return NULL; - } - - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Read the object ID - if ( PIOS_FREAD(file,&objId,sizeof(objId),&bytesRead) ) - { - xSemaphoreGiveRecursive(mutex); - return NULL; - } - - // Get the object - obj = UAVObjGetByID(objId); - if ( obj == 0 ) - { - xSemaphoreGiveRecursive(mutex); - return NULL; - } - objEntry = (ObjectList*)obj; - - // Get the instance ID - instId = 0; - if ( !objEntry->isSingleInstance ) - { - if ( PIOS_FREAD(file,&instId,sizeof(instId),&bytesRead) ) - { - xSemaphoreGiveRecursive(mutex); - return NULL; - } - } - - // Get the instance information - instEntry = getInstance(objEntry, instId); - - // If the instance does not exist create it and any other instances before it - if ( instEntry == NULL ) - { - instEntry = createInstance(objEntry, instId); - if ( instEntry == NULL ) - { - // Error, unlock and return - xSemaphoreGiveRecursive(mutex); - return NULL; - } - } - - // Read the instance data - if ( PIOS_FREAD(file,instEntry->data,objEntry->numBytes,&bytesRead) ) - { - xSemaphoreGiveRecursive(mutex); - return NULL; - } - - // Fire event - sendEvent(objEntry, instId, EV_UNPACKED); - - // Unlock - xSemaphoreGiveRecursive(mutex); - return obj; -#else /* PIOS_INCLUDE_SDCARD */ - return NULL; -#endif -} - -/** - * Load an object from the file system (SD card). - * A file with the name of the object will be opened. - * The object data can be saved using the UAVObjSave function. - * @param[in] obj The object handle. - * @param[in] instId The object instance - * @return 0 if success or -1 if failure - */ -int32_t UAVObjLoad(UAVObjHandle obj, uint16_t instId) -{ -#if defined(PIOS_INCLUDE_FLASH_SECTOR_SETTINGS) - ObjectList* objEntry = (ObjectList*)obj; - - if(objEntry == NULL) - return -1; - - ObjectInstList* instEntry = getInstance(objEntry, instId); - - if(instEntry == NULL) - return -1; - - if(instEntry->data == NULL) - return -1; - - struct fileHeader header; - uint32_t addr = (objEntry->id & FLASH_MASK); - - PIOS_Flash_W25X_ReadData(addr, (uint8_t *) &header, sizeof(header)); - - if(header.id != objEntry->id) - return -1; - - // Read the instance data - if (PIOS_Flash_W25X_ReadData(addr + sizeof(header) ,instEntry->data, objEntry->numBytes) != 0) - return -1; - - // Fire event - sendEvent(objEntry, instId, EV_UNPACKED); -#endif - -#if defined(PIOS_INCLUDE_SDCARD) - FILEINFO file; - ObjectList* objEntry; - UAVObjHandle loadedObj; - ObjectList* loadedObjEntry; - uint8_t filename[14]; - - // Check for file system availability - if ( PIOS_SDCARD_IsMounted() == 0 ) - { - return -1; - } - - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Cast to object - objEntry = (ObjectList*)obj; - - // Get filename - objectFilename(objEntry, filename); - - // Open file - if ( PIOS_FOPEN_READ(filename,file) ) - { - xSemaphoreGiveRecursive(mutex); - return -1; - } - - // Load object - loadedObj = UAVObjLoadFromFile(&file); - if (loadedObj == 0) - { - PIOS_FCLOSE(file); - xSemaphoreGiveRecursive(mutex); - return -1; - } - - // Check that the IDs match - loadedObjEntry = (ObjectList*)loadedObj; - if ( loadedObjEntry->id != objEntry->id ) - { - PIOS_FCLOSE(file); - xSemaphoreGiveRecursive(mutex); - return -1; - } - - // Done, close file and unlock - PIOS_FCLOSE(file); - xSemaphoreGiveRecursive(mutex); -#endif /* PIOS_INCLUDE_SDCARD */ - return 0; -} - -/** - * Delete an object from the file system (SD card). - * @param[in] obj The object handle. - * @param[in] instId The object instance - * @return 0 if success or -1 if failure - */ -int32_t UAVObjDelete(UAVObjHandle obj, uint16_t instId) -{ -#if defined(PIOS_INCLUDE_FLASH_SECTOR_SETTINGS) - ObjectList* objEntry = (ObjectList*)obj; - - if(objEntry == NULL) - return -1; - - uint32_t addr = (objEntry->id & FLASH_MASK); - PIOS_Flash_W25X_EraseSector(addr); -#endif -#if defined(PIOS_INCLUDE_SDCARD) - ObjectList* objEntry; - uint8_t filename[14]; - - // Check for file system availability - if ( PIOS_SDCARD_IsMounted() == 0 ) - { - return -1; - } - - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Cast to object - objEntry = (ObjectList*)obj; - - // Get filename - objectFilename(objEntry, filename); - - // Delete file - PIOS_FUNLINK(filename); - - // Done - xSemaphoreGiveRecursive(mutex); -#endif /* PIOS_INCLUDE_SDCARD */ - return 0; -} - -/** - * Save all settings objects to the SD card. - * @return 0 if success or -1 if failure - */ -int32_t UAVObjSaveSettings() -{ - ObjectList* objEntry; - - // Get lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Save all settings objects - LL_FOREACH(objList, objEntry) - { - // Check if this is a settings object - if ( objEntry->isSettings ) - { - // Save object - if ( UAVObjSave( (UAVObjHandle)objEntry, 0 ) == -1 ) - { - xSemaphoreGiveRecursive(mutex); - return -1; - } - } - } - - // Done - xSemaphoreGiveRecursive(mutex); - return 0; -} - -/** - * Load all settings objects from the SD card. - * @return 0 if success or -1 if failure - */ -int32_t UAVObjLoadSettings() -{ - ObjectList* objEntry; - - // Get lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Load all settings objects - LL_FOREACH(objList, objEntry) - { - // Check if this is a settings object - if ( objEntry->isSettings ) - { - // Load object - if ( UAVObjLoad( (UAVObjHandle)objEntry, 0 ) == -1 ) - { - xSemaphoreGiveRecursive(mutex); - return -1; - } - } - } - - // Done - xSemaphoreGiveRecursive(mutex); - return 0; -} - -/** - * Delete all settings objects from the SD card. - * @return 0 if success or -1 if failure - */ -int32_t UAVObjDeleteSettings() -{ - ObjectList* objEntry; - - // Get lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Save all settings objects - LL_FOREACH(objList, objEntry) - { - // Check if this is a settings object - if ( objEntry->isSettings ) - { - // Save object - if ( UAVObjDelete( (UAVObjHandle)objEntry, 0 ) == -1 ) - { - xSemaphoreGiveRecursive(mutex); - return -1; - } - } - } - - // Done - xSemaphoreGiveRecursive(mutex); - return 0; -} - -/** - * Save all metaobjects to the SD card. - * @return 0 if success or -1 if failure - */ -int32_t UAVObjSaveMetaobjects() -{ - ObjectList* objEntry; - - // Get lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Save all settings objects - LL_FOREACH(objList, objEntry) - { - // Check if this is a settings object - if ( objEntry->isMetaobject ) - { - // Save object - if ( UAVObjSave( (UAVObjHandle)objEntry, 0 ) == -1 ) - { - xSemaphoreGiveRecursive(mutex); - return -1; - } - } - } - - // Done - xSemaphoreGiveRecursive(mutex); - return 0; -} - -/** - * Load all metaobjects from the SD card. - * @return 0 if success or -1 if failure - */ -int32_t UAVObjLoadMetaobjects() -{ - ObjectList* objEntry; - - // Get lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Load all settings objects - LL_FOREACH(objList, objEntry) - { - // Check if this is a settings object - if ( objEntry->isMetaobject ) - { - // Load object - if ( UAVObjLoad( (UAVObjHandle)objEntry, 0 ) == -1 ) - { - xSemaphoreGiveRecursive(mutex); - return -1; - } - } - } - - // Done - xSemaphoreGiveRecursive(mutex); - return 0; -} - -/** - * Delete all metaobjects from the SD card. - * @return 0 if success or -1 if failure - */ -int32_t UAVObjDeleteMetaobjects() -{ - ObjectList* objEntry; - - // Get lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Load all settings objects - LL_FOREACH(objList, objEntry) - { - // Check if this is a settings object - if ( objEntry->isMetaobject ) - { - // Load object - if ( UAVObjDelete( (UAVObjHandle)objEntry, 0 ) == -1 ) - { - xSemaphoreGiveRecursive(mutex); - return -1; - } - } - } - - // Done - xSemaphoreGiveRecursive(mutex); - return 0; -} - -/** - * Set the object data - * \param[in] obj The object handle - * \param[in] dataIn The object's data structure - * \return 0 if success or -1 if failure - */ -int32_t UAVObjSetData(UAVObjHandle obj, const void* dataIn) -{ - return UAVObjSetInstanceData(obj, 0, dataIn); -} - -/** - * Get the object data - * \param[in] obj The object handle - * \param[out] dataOut The object's data structure - * \return 0 if success or -1 if failure - */ -int32_t UAVObjGetData(UAVObjHandle obj, void* dataOut) -{ - return UAVObjGetInstanceData(obj, 0, dataOut); -} - -/** - * Set the data of a specific object instance - * \param[in] obj The object handle - * \param[in] instId The object instance ID - * \param[in] dataIn The object's data structure - * \return 0 if success or -1 if failure - */ -int32_t UAVObjSetInstanceData(UAVObjHandle obj, uint16_t instId, const void* dataIn) -{ - ObjectList* objEntry; - ObjectInstList* instEntry; - UAVObjMetadata* mdata; - - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Cast to object info - objEntry = (ObjectList*)obj; - - // Check access level - if ( !objEntry->isMetaobject ) - { - mdata = (UAVObjMetadata*)(objEntry->linkedObj->instances.data); - if ( mdata->access == ACCESS_READONLY ) - { - xSemaphoreGiveRecursive(mutex); - return -1; - } - } - - // Get instance information - instEntry = getInstance(objEntry, instId); - if ( instEntry == NULL ) - { - // Error, unlock and return - xSemaphoreGiveRecursive(mutex); - return -1; - } - - // Set data - memcpy(instEntry->data, dataIn, objEntry->numBytes); - - // Fire event - sendEvent(objEntry, instId, EV_UPDATED); - - // Unlock - xSemaphoreGiveRecursive(mutex); - return 0; -} - -/** - * Get the data of a specific object instance - * \param[in] obj The object handle - * \param[in] instId The object instance ID - * \param[out] dataOut The object's data structure - * \return 0 if success or -1 if failure - */ -int32_t UAVObjGetInstanceData(UAVObjHandle obj, uint16_t instId, void* dataOut) -{ - ObjectList* objEntry; - ObjectInstList* instEntry; - - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Cast to object info - objEntry = (ObjectList*)obj; - - // Get instance information - instEntry = getInstance(objEntry, instId); - if ( instEntry == NULL ) - { - // Error, unlock and return - xSemaphoreGiveRecursive(mutex); - return -1; - } - - // Set data - memcpy(dataOut, instEntry->data, objEntry->numBytes); - - // Unlock - xSemaphoreGiveRecursive(mutex); - return 0; -} - -/** - * Set the object metadata - * \param[in] obj The object handle - * \param[in] dataIn The object's metadata structure - * \return 0 if success or -1 if failure - */ -int32_t UAVObjSetMetadata(UAVObjHandle obj, const UAVObjMetadata* dataIn) -{ - ObjectList* objEntry; - - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Set metadata (metadata of metaobjects can not be modified) - objEntry = (ObjectList*)obj; - if (!objEntry->isMetaobject) - { - UAVObjSetData((UAVObjHandle)objEntry->linkedObj, dataIn); - } - else - { - return -1; - } - - // Unlock - xSemaphoreGiveRecursive(mutex); - return 0; -} - -/** - * Get the object metadata - * \param[in] obj The object handle - * \param[out] dataOut The object's metadata structure - * \return 0 if success or -1 if failure - */ -int32_t UAVObjGetMetadata(UAVObjHandle obj, UAVObjMetadata* dataOut) -{ - ObjectList* objEntry; - - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Get metadata - objEntry = (ObjectList*)obj; - if (objEntry->isMetaobject) - { - memcpy(dataOut, &defMetadata, sizeof(UAVObjMetadata)); - } - else - { - UAVObjGetData((UAVObjHandle)objEntry->linkedObj, dataOut); - } - - // Unlock - xSemaphoreGiveRecursive(mutex); - return 0; -} - -/** - * Check if an object is read only - * \param[in] obj The object handle - * \return - * \arg 0 if not read only - * \arg 1 if read only - * \arg -1 if unable to get meta data - */ -int8_t UAVObjReadOnly(UAVObjHandle obj) -{ - ObjectList* objEntry; - UAVObjMetadata* mdata; - - // Cast to object info - objEntry = (ObjectList*)obj; - - // Check access level - if ( !objEntry->isMetaobject ) - { - mdata = (UAVObjMetadata*)(objEntry->linkedObj->instances.data); - return mdata->access == ACCESS_READONLY; - } - return -1; -} - -/** - * Connect an event queue to the object, if the queue is already connected then the event mask is only updated. - * All events matching the event mask will be pushed to the event queue. - * \param[in] obj The object handle - * \param[in] queue The event queue - * \param[in] eventMask The event mask, if EV_MASK_ALL then all events are enabled (e.g. EV_UPDATED | EV_UPDATED_MANUAL) - * \return 0 if success or -1 if failure - */ -int32_t UAVObjConnectQueue(UAVObjHandle obj, xQueueHandle queue, int32_t eventMask) -{ - int32_t res; - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - res = connectObj(obj, queue, 0, eventMask); - xSemaphoreGiveRecursive(mutex); - return res; -} - -/** - * Disconnect an event queue from the object. - * \param[in] obj The object handle - * \param[in] queue The event queue - * \return 0 if success or -1 if failure - */ -int32_t UAVObjDisconnectQueue(UAVObjHandle obj, xQueueHandle queue) -{ - int32_t res; - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - res = disconnectObj(obj, queue, 0); - xSemaphoreGiveRecursive(mutex); - return res; -} - -/** - * Connect an event callback to the object, if the callback is already connected then the event mask is only updated. - * The supplied callback will be invoked on all events matching the event mask. - * \param[in] obj The object handle - * \param[in] cb The event callback - * \param[in] eventMask The event mask, if EV_MASK_ALL then all events are enabled (e.g. EV_UPDATED | EV_UPDATED_MANUAL) - * \return 0 if success or -1 if failure - */ -int32_t UAVObjConnectCallback(UAVObjHandle obj, UAVObjEventCallback cb, int32_t eventMask) -{ - int32_t res; - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - res = connectObj(obj, 0, cb, eventMask); - xSemaphoreGiveRecursive(mutex); - return res; -} - -/** - * Disconnect an event callback from the object. - * \param[in] obj The object handle - * \param[in] cb The event callback - * \return 0 if success or -1 if failure - */ -int32_t UAVObjDisconnectCallback(UAVObjHandle obj, UAVObjEventCallback cb) -{ - int32_t res; - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - res = disconnectObj(obj, 0, cb); - xSemaphoreGiveRecursive(mutex); - return res; -} - - -/** - * Request an update of the object's data from the GCS. The call will not wait for the response, a EV_UPDATED event - * will be generated as soon as the object is updated. - * \param[in] obj The object handle - */ -void UAVObjRequestUpdate(UAVObjHandle obj) -{ - UAVObjRequestInstanceUpdate(obj, UAVOBJ_ALL_INSTANCES); -} - -/** - * Request an update of the object's data from the GCS. The call will not wait for the response, a EV_UPDATED event - * will be generated as soon as the object is updated. - * \param[in] obj The object handle - * \param[in] instId Object instance ID to update - */ -void UAVObjRequestInstanceUpdate(UAVObjHandle obj, uint16_t instId) -{ - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - sendEvent((ObjectList*)obj, instId, EV_UPDATE_REQ); - xSemaphoreGiveRecursive(mutex); -} - -/** - * Send the object's data to the GCS (triggers a EV_UPDATED_MANUAL event on this object). - * \param[in] obj The object handle - */ -void UAVObjUpdated(UAVObjHandle obj) -{ - UAVObjInstanceUpdated(obj, UAVOBJ_ALL_INSTANCES); -} - -/** - * Send the object's data to the GCS (triggers a EV_UPDATED_MANUAL event on this object). - * \param[in] obj The object handle - * \param[in] instId The object instance ID - */ -void UAVObjInstanceUpdated(UAVObjHandle obj, uint16_t instId) -{ - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - sendEvent((ObjectList*)obj, instId, EV_UPDATED_MANUAL); - xSemaphoreGiveRecursive(mutex); -} - -/** - * Iterate through all objects in the list. - * \param iterator This function will be called once for each object, - * the object will be passed as a parameter - */ -void UAVObjIterate(void (*iterator)(UAVObjHandle obj)) -{ - ObjectList* objEntry; - - // Get lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Iterate through the list and invoke iterator for each object - LL_FOREACH(objList, objEntry) - { - (*iterator)((UAVObjHandle)objEntry); - } - - // Release lock - xSemaphoreGiveRecursive(mutex); -} - -/** - * Send an event to all event queues registered on the object. - */ -static int32_t sendEvent(ObjectList* obj, uint16_t instId, UAVObjEventType event) -{ - ObjectEventList* eventEntry; - UAVObjEvent msg; - - // Setup event - msg.obj = (UAVObjHandle)obj; - msg.event = event; - msg.instId = instId; - - // Go through each object and push the event message in the queue (if event is activated for the queue) - LL_FOREACH(obj->events, eventEntry) - { - if ( eventEntry->eventMask == 0 || (eventEntry->eventMask & event) != 0 ) - { - // Send to queue if a valid queue is registered - if (eventEntry->queue != 0) - { - if ( xQueueSend(eventEntry->queue, &msg, 0) != pdTRUE ) // will not block - { - ++stats.eventErrors; - } - } - // Invoke callback (from event task) if a valid one is registered - if (eventEntry->cb != 0) - { - if ( EventCallbackDispatch(&msg, eventEntry->cb) != pdTRUE ) // invoke callback from the event task, will not block - { - ++stats.eventErrors; - } - } - } - } - - // Done - return 0; -} - -/** - * Create a new object instance, return the instance info or NULL if failure. - */ -static ObjectInstList* createInstance(ObjectList* obj, uint16_t instId) -{ - ObjectInstList* instEntry; - int32_t n; - - // For single instance objects, only instance zero is allowed - if (obj->isSingleInstance && instId != 0) - { - return NULL; - } - - // Make sure that the instance ID is within limits - if (instId >= UAVOBJ_MAX_INSTANCES) - { - return NULL; - } - - // Check if the instance already exists - if ( getInstance(obj, instId) != NULL ) - { - return NULL; - } - - // Create any missing instances (all instance IDs must be sequential) - for (n = obj->numInstances; n < instId; ++n) - { - if ( createInstance(obj, n) == NULL ) - { - return NULL; - } - } - - if(instId == 0) /* Instance 0 ObjectInstList allocated with ObjectList element */ - { - instEntry = &obj->instances; - instEntry->data = pvPortMalloc(obj->numBytes); - if (instEntry->data == NULL) return NULL; - memset(instEntry->data, 0, obj->numBytes); - instEntry->instId = instId; - } else - { - // Create the actual instance - instEntry = (ObjectInstList*)pvPortMalloc(sizeof(ObjectInstList)); - if (instEntry == NULL) return NULL; - instEntry->data = pvPortMalloc(obj->numBytes); - if (instEntry->data == NULL) return NULL; - memset(instEntry->data, 0, obj->numBytes); - instEntry->instId = instId; - LL_APPEND(obj->instances.next, instEntry); - } - ++obj->numInstances; - - // Fire event - UAVObjInstanceUpdated((UAVObjHandle)obj, instId); - - // Done - return instEntry; -} - -/** - * Get the instance information or NULL if the instance does not exist - */ -static ObjectInstList* getInstance(ObjectList* obj, uint16_t instId) -{ - ObjectInstList* instEntry; - - // Look for specified instance ID - LL_FOREACH(&(obj->instances), instEntry) - { - if (instEntry->instId == instId) - { - return instEntry; - } - } - // If this point is reached then instance id was not found - return NULL; -} - -/** - * Connect an event queue to the object, if the queue is already connected then the event mask is only updated. - * \param[in] obj The object handle - * \param[in] queue The event queue - * \param[in] cb The event callback - * \param[in] eventMask The event mask, if EV_MASK_ALL then all events are enabled (e.g. EV_UPDATED | EV_UPDATED_MANUAL) - * \return 0 if success or -1 if failure - */ -static int32_t connectObj(UAVObjHandle obj, xQueueHandle queue, UAVObjEventCallback cb, int32_t eventMask) -{ - ObjectEventList* eventEntry; - ObjectList* objEntry; - - // Check that the queue is not already connected, if it is simply update event mask - objEntry = (ObjectList*)obj; - LL_FOREACH(objEntry->events, eventEntry) - { - if ( eventEntry->queue == queue && eventEntry->cb == cb ) - { - // Already connected, update event mask and return - eventEntry->eventMask = eventMask; - return 0; - } - } - - // Add queue to list - eventEntry = (ObjectEventList*)pvPortMalloc(sizeof(ObjectEventList)); - if (eventEntry == NULL) - { - return -1; - } - eventEntry->queue = queue; - eventEntry->cb = cb; - eventEntry->eventMask = eventMask; - LL_APPEND(objEntry->events, eventEntry); - - // Done - return 0; -} - -/** - * Disconnect an event queue from the object - * \param[in] obj The object handle - * \param[in] queue The event queue - * \param[in] cb The event callback - * \return 0 if success or -1 if failure - */ -static int32_t disconnectObj(UAVObjHandle obj, xQueueHandle queue, UAVObjEventCallback cb) -{ - ObjectEventList* eventEntry; - ObjectList* objEntry; - - // Find queue and remove it - objEntry = (ObjectList*)obj; - LL_FOREACH(objEntry->events, eventEntry) - { - if ( ( eventEntry->queue == queue && eventEntry->cb == cb ) ) - { - LL_DELETE(objEntry->events, eventEntry); - vPortFree(eventEntry); - return 0; - } - } - - // If this point is reached the queue was not found - return -1; -} - -#if defined(PIOS_INCLUDE_SDCARD) -/** - * Wrapper for the sprintf function - */ -static void customSPrintf(uint8_t* buffer, uint8_t* format, ...) -{ - va_list args; - va_start(args, format); - vsprintf((char *)buffer, (char *)format, args); -} - -/** - * Get an 8 character (plus extension) filename for the object. - */ -static void objectFilename(ObjectList* obj, uint8_t* filename) -{ - customSPrintf(filename, (uint8_t*)"%X.obj", obj->id); -} -#endif /* PIOS_INCLUDE_SDCARD */ - - - - - - - - - - - - - - - - +/** + ****************************************************************************** + * @addtogroup UAVObjects OpenPilot UAVObjects + * @{ + * @addtogroup UAV Object Manager + * @brief The core UAV Objects functions, most of which are wrappered by + * autogenerated defines + * @{ + * + * + * @file uavobjectmanager.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Object manager library. This library holds a collection of all objects. + * It can be used by all modules/libraries to find an object reference. + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "openpilot.h" + +// Constants + +// Private types + +/** + * List of event queues and the eventmask associated with the queue. + */ +struct ObjectEventListStruct { + xQueueHandle queue; + UAVObjEventCallback cb; + int32_t eventMask; + struct ObjectEventListStruct *next; +}; +typedef struct ObjectEventListStruct ObjectEventList; + +/** + * List of object instances, holds the actual data structure and instance ID + */ +struct ObjectInstListStruct { + void *data; + uint16_t instId; + struct ObjectInstListStruct *next; +}; +typedef struct ObjectInstListStruct ObjectInstList; + +/** + * List of objects registered in the object manager + */ +struct ObjectListStruct { + uint32_t id; + /** The object ID */ + const char *name; + /** The object name */ + int8_t isMetaobject; + /** Set to 1 if this is a metaobject */ + int8_t isSingleInstance; + /** Set to 1 if this object has a single instance */ + int8_t isSettings; + /** Set to 1 if this object is a settings object */ + uint16_t numBytes; + /** Number of data bytes contained in the object (for a single instance) */ + uint16_t numInstances; + /** Number of instances */ + struct ObjectListStruct *linkedObj; + /** Linked object, for regular objects this is the metaobject and for metaobjects it is the parent object */ + ObjectInstList instances; + /** List of object instances, instance 0 always exists */ + ObjectEventList *events; + /** Event queues registered on the object */ + struct ObjectListStruct *next; + /** Needed by linked list library (utlist.h) */ +}; +typedef struct ObjectListStruct ObjectList; + +// Private functions +static int32_t sendEvent(ObjectList * obj, uint16_t instId, + UAVObjEventType event); +static ObjectInstList *createInstance(ObjectList * obj, uint16_t instId); +static ObjectInstList *getInstance(ObjectList * obj, uint16_t instId); +static int32_t connectObj(UAVObjHandle obj, xQueueHandle queue, + UAVObjEventCallback cb, int32_t eventMask); +static int32_t disconnectObj(UAVObjHandle obj, xQueueHandle queue, + UAVObjEventCallback cb); + +#if defined(PIOS_INCLUDE_SDCARD) +static void objectFilename(ObjectList * obj, uint8_t * filename); +static void customSPrintf(uint8_t * buffer, uint8_t * format, ...); +#endif + +// Private variables +static ObjectList *objList; +static xSemaphoreHandle mutex; +static UAVObjMetadata defMetadata; +static UAVObjStats stats; + +/** + * Initialize the object manager + * \return 0 Success + * \return -1 Failure + */ +int32_t UAVObjInitialize() +{ + // Initialize variables + objList = NULL; + memset(&stats, 0, sizeof(UAVObjStats)); + + // Create mutex + mutex = xSemaphoreCreateRecursiveMutex(); + if (mutex == NULL) + return -1; + + // Initialize default metadata structure (metadata of metaobjects) + defMetadata.access = ACCESS_READWRITE; + defMetadata.gcsAccess = ACCESS_READWRITE; + defMetadata.telemetryAcked = 1; + defMetadata.telemetryUpdateMode = UPDATEMODE_ONCHANGE; + defMetadata.telemetryUpdatePeriod = 0; + defMetadata.gcsTelemetryAcked = 1; + defMetadata.gcsTelemetryUpdateMode = UPDATEMODE_ONCHANGE; + defMetadata.gcsTelemetryUpdatePeriod = 0; + defMetadata.loggingUpdateMode = UPDATEMODE_ONCHANGE; + defMetadata.loggingUpdatePeriod = 0; + + // Done + return 0; +} + +/** + * Get the statistics counters + * @param[out] statsOut The statistics counters will be copied there + */ +void UAVObjGetStats(UAVObjStats * statsOut) +{ + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + memcpy(statsOut, &stats, sizeof(UAVObjStats)); + xSemaphoreGiveRecursive(mutex); +} + +/** + * Clear the statistics counters + */ +void UAVObjClearStats() +{ + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + memset(&stats, 0, sizeof(UAVObjStats)); + xSemaphoreGiveRecursive(mutex); +} + +/** + * Register and new object in the object manager. + * \param[in] id Unique object ID + * \param[in] name Object name + * \param[in] nameName Metaobject name + * \param[in] isMetaobject Is this a metaobject (1:true, 0:false) + * \param[in] isSingleInstance Is this a single instance or multi-instance object + * \param[in] isSettings Is this a settings object + * \param[in] numBytes Number of bytes of object data (for one instance) + * \param[in] initCb Default field and metadata initialization function + * \return Object handle, or NULL if failure. + * \return + */ +UAVObjHandle UAVObjRegister(uint32_t id, const char *name, + const char *metaName, int32_t isMetaobject, + int32_t isSingleInstance, int32_t isSettings, + uint32_t numBytes, + UAVObjInitializeCallback initCb) +{ + ObjectList *objEntry; + ObjectInstList *instEntry; + ObjectList *metaObj; + + // Get lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Check that the object is not already registered + LL_FOREACH(objList, objEntry) { + if (objEntry->id == id) { + // Already registered, ignore + xSemaphoreGiveRecursive(mutex); + return NULL; + } + } + + // Create and append entry + objEntry = (ObjectList *) pvPortMalloc(sizeof(ObjectList)); + if (objEntry == NULL) { + xSemaphoreGiveRecursive(mutex); + return NULL; + } + objEntry->id = id; + objEntry->name = name; + objEntry->isMetaobject = (int8_t) isMetaobject; + objEntry->isSingleInstance = (int8_t) isSingleInstance; + objEntry->isSettings = (int8_t) isSettings; + objEntry->numBytes = numBytes; + objEntry->events = NULL; + objEntry->numInstances = 0; + objEntry->instances.data = NULL; + objEntry->instances.instId = 0xFFFF; + objEntry->instances.next = NULL; + objEntry->linkedObj = NULL; // will be set later + LL_APPEND(objList, objEntry); + + // Create instance zero + instEntry = createInstance(objEntry, 0); + if (instEntry == NULL) { + xSemaphoreGiveRecursive(mutex); + return NULL; + } + // Create metaobject and update linkedObj + if (isMetaobject) { + objEntry->linkedObj = NULL; // will be set later + } else { + // Create metaobject + metaObj = + (ObjectList *) UAVObjRegister(id + 1, metaName, + NULL, 1, 1, 0, + sizeof + (UAVObjMetadata), + NULL); + // Link two objects + objEntry->linkedObj = metaObj; + metaObj->linkedObj = objEntry; + } + + // Initialize object fields and metadata to default values + if (initCb != NULL) { + initCb((UAVObjHandle) objEntry, 0); + } + // Attempt to load object's metadata from the SD card (not done directly on the metaobject, but through the object) + if (!objEntry->isMetaobject) { + UAVObjLoad((UAVObjHandle) objEntry->linkedObj, 0); + } + // If this is a settings object, attempt to load from SD card + if (objEntry->isSettings) { + UAVObjLoad((UAVObjHandle) objEntry, 0); + } + // Release lock + xSemaphoreGiveRecursive(mutex); + return (UAVObjHandle) objEntry; +} + +/** + * Retrieve an object from the list given its id + * \param[in] The object ID + * \return The object or NULL if not found. + */ +UAVObjHandle UAVObjGetByID(uint32_t id) +{ + ObjectList *objEntry; + + // Get lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Look for object + LL_FOREACH(objList, objEntry) { + if (objEntry->id == id) { + // Release lock + xSemaphoreGiveRecursive(mutex); + // Done, object found + return (UAVObjHandle) objEntry; + } + } + + // Object not found, release lock and return error + xSemaphoreGiveRecursive(mutex); + return NULL; +} + +/** + * Retrieve an object from the list given its name + * \param[in] name The name of the object + * \return The object or NULL if not found. + */ +UAVObjHandle UAVObjGetByName(char *name) +{ + ObjectList *objEntry; + + // Get lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Look for object + LL_FOREACH(objList, objEntry) { + if (objEntry->name != NULL + && strcmp(objEntry->name, name) == 0) { + // Release lock + xSemaphoreGiveRecursive(mutex); + // Done, object found + return (UAVObjHandle) objEntry; + } + } + + // Object not found, release lock and return error + xSemaphoreGiveRecursive(mutex); + return NULL; +} + +/** + * Get the object's ID + * \param[in] obj The object handle + * \return The object ID + */ +uint32_t UAVObjGetID(UAVObjHandle obj) +{ + return ((ObjectList *) obj)->id; +} + +/** + * Get the object's name + * \param[in] obj The object handle + * \return The object's name + */ +const char *UAVObjGetName(UAVObjHandle obj) +{ + return ((ObjectList *) obj)->name; +} + +/** + * Get the number of bytes of the object's data (for one instance) + * \param[in] obj The object handle + * \return The number of bytes + */ +uint32_t UAVObjGetNumBytes(UAVObjHandle obj) +{ + return ((ObjectList *) obj)->numBytes; +} + +/** + * Get the object this object is linked to. For regular objects, the linked object + * is the metaobject. For metaobjects the linked object is the parent object. + * This function is normally only needed by the telemetry module. + * \param[in] obj The object handle + * \return The object linked object handle + */ +UAVObjHandle UAVObjGetLinkedObj(UAVObjHandle obj) +{ + return (UAVObjHandle) (((ObjectList *) obj)->linkedObj); +} + +/** + * Get the number of instances contained in the object. + * \param[in] obj The object handle + * \return The number of instances + */ +uint16_t UAVObjGetNumInstances(UAVObjHandle obj) +{ + uint32_t numInstances; + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + numInstances = ((ObjectList *) obj)->numInstances; + xSemaphoreGiveRecursive(mutex); + return numInstances; +} + +/** + * Create a new instance in the object. + * \param[in] obj The object handle + * \return The instance ID or 0 if an error + */ +uint16_t UAVObjCreateInstance(UAVObjHandle obj, + UAVObjInitializeCallback initCb) +{ + ObjectList *objEntry; + ObjectInstList *instEntry; + + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Create new instance + objEntry = (ObjectList *) obj; + instEntry = createInstance(objEntry, objEntry->numInstances); + if (instEntry == NULL) { + xSemaphoreGiveRecursive(mutex); + return -1; + } + // Initialize instance data + if (initCb != NULL) { + initCb(obj, instEntry->instId); + } + // Unlock + xSemaphoreGiveRecursive(mutex); + return instEntry->instId; +} + +/** + * Does this object contains a single instance or multiple instances? + * \param[in] obj The object handle + * \return True (1) if this is a single instance object + */ +int32_t UAVObjIsSingleInstance(UAVObjHandle obj) +{ + return ((ObjectList *) obj)->isSingleInstance; +} + +/** + * Is this a metaobject? + * \param[in] obj The object handle + * \return True (1) if this is metaobject + */ +int32_t UAVObjIsMetaobject(UAVObjHandle obj) +{ + return ((ObjectList *) obj)->isMetaobject; +} + +/** + * Is this a settings object? + * \param[in] obj The object handle + * \return True (1) if this is a settings object + */ +int32_t UAVObjIsSettings(UAVObjHandle obj) +{ + return ((ObjectList *) obj)->isSettings; +} + +/** + * Unpack an object from a byte array + * \param[in] obj The object handle + * \param[in] instId The instance ID + * \param[in] dataIn The byte array + * \return 0 if success or -1 if failure + */ +int32_t UAVObjUnpack(UAVObjHandle obj, uint16_t instId, + const uint8_t * dataIn) +{ + ObjectList *objEntry; + ObjectInstList *instEntry; + + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Cast handle to object + objEntry = (ObjectList *) obj; + + // Get the instance + instEntry = getInstance(objEntry, instId); + + // If the instance does not exist create it and any other instances before it + if (instEntry == NULL) { + instEntry = createInstance(objEntry, instId); + if (instEntry == NULL) { + // Error, unlock and return + xSemaphoreGiveRecursive(mutex); + return -1; + } + } + // Set the data + memcpy(instEntry->data, dataIn, objEntry->numBytes); + + // Fire event + sendEvent(objEntry, instId, EV_UNPACKED); + + // Unlock + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Pack an object to a byte array + * \param[in] obj The object handle + * \param[in] instId The instance ID + * \param[out] dataOut The byte array + * \return 0 if success or -1 if failure + */ +int32_t UAVObjPack(UAVObjHandle obj, uint16_t instId, uint8_t * dataOut) +{ + ObjectList *objEntry; + ObjectInstList *instEntry; + + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Cast handle to object + objEntry = (ObjectList *) obj; + + // Get the instance + instEntry = getInstance(objEntry, instId); + if (instEntry == NULL) { + // Error, unlock and return + xSemaphoreGiveRecursive(mutex); + return -1; + } + // Pack data + memcpy(dataOut, instEntry->data, objEntry->numBytes); + + // Unlock + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Save the data of the specified object instance to the file system (SD card). + * The object will be appended and the file will not be closed. + * The object data can be restored using the UAVObjLoad function. + * @param[in] obj The object handle. + * @param[in] instId The instance ID + * @param[in] file File to append to + * @return 0 if success or -1 if failure + */ +int32_t UAVObjSaveToFile(UAVObjHandle obj, uint16_t instId, + FILEINFO * file) +{ +#if defined(PIOS_INCLUDE_SDCARD) + uint32_t bytesWritten; + ObjectList *objEntry; + ObjectInstList *instEntry; + + // Check for file system availability + if (PIOS_SDCARD_IsMounted() == 0) { + return -1; + } + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Cast to object + objEntry = (ObjectList *) obj; + + // Get the instance information + instEntry = getInstance(objEntry, instId); + if (instEntry == NULL) { + xSemaphoreGiveRecursive(mutex); + return -1; + } + // Write the object ID + PIOS_FWRITE(file, &objEntry->id, sizeof(objEntry->id), + &bytesWritten); + + // Write the instance ID + if (!objEntry->isSingleInstance) { + PIOS_FWRITE(file, &instEntry->instId, + sizeof(instEntry->instId), &bytesWritten); + } + // Write the data and check that the write was successful + PIOS_FWRITE(file, instEntry->data, objEntry->numBytes, + &bytesWritten); + if (bytesWritten != objEntry->numBytes) { + xSemaphoreGiveRecursive(mutex); + return -1; + } + // Done + xSemaphoreGiveRecursive(mutex); +#endif /* PIOS_INCLUDE_SDCARD */ + return 0; +} + +/** + * Save the data of the specified object to the file system (SD card). + * If the object contains multiple instances, all of them will be saved. + * A new file with the name of the object will be created. + * The object data can be restored using the UAVObjLoad function. + * @param[in] obj The object handle. + * @param[in] instId The instance ID + * @param[in] file File to append to + * @return 0 if success or -1 if failure + */ +int32_t UAVObjSave(UAVObjHandle obj, uint16_t instId) +{ +#if defined(PIOS_INCLUDE_FLASH_SECTOR_SETTINGS) + ObjectList *objEntry = (ObjectList *) obj; + + if (objEntry == NULL) + return -1; + + ObjectInstList *instEntry = getInstance(objEntry, instId); + + if (instEntry == NULL) + return -1; + + if (instEntry->data == NULL) + return -1; + + if (PIOS_FLASHFS_ObjSave(obj, instId, instEntry->data) != 0) + return -1; +#endif +#if defined(PIOS_INCLUDE_SDCARD) + FILEINFO file; + ObjectList *objEntry; + uint8_t filename[14]; + + // Check for file system availability + if (PIOS_SDCARD_IsMounted() == 0) { + return -1; + } + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Cast to object + objEntry = (ObjectList *) obj; + + // Get filename + objectFilename(objEntry, filename); + + // Open file + if (PIOS_FOPEN_WRITE(filename, file)) { + xSemaphoreGiveRecursive(mutex); + return -1; + } + // Append object + if (UAVObjSaveToFile(obj, instId, &file) == -1) { + PIOS_FCLOSE(file); + xSemaphoreGiveRecursive(mutex); + return -1; + } + // Done, close file and unlock + PIOS_FCLOSE(file); + xSemaphoreGiveRecursive(mutex); +#endif /* PIOS_INCLUDE_SDCARD */ + return 0; +} + +/** + * Load an object from the file system (SD card). + * @param[in] file File to read from + * @return The handle of the object loaded or NULL if a failure + */ +UAVObjHandle UAVObjLoadFromFile(FILEINFO * file) +{ +#if defined(PIOS_INCLUDE_SDCARD) + uint32_t bytesRead; + ObjectList *objEntry; + ObjectInstList *instEntry; + uint32_t objId; + uint16_t instId; + UAVObjHandle obj; + + // Check for file system availability + if (PIOS_SDCARD_IsMounted() == 0) { + return NULL; + } + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Read the object ID + if (PIOS_FREAD(file, &objId, sizeof(objId), &bytesRead)) { + xSemaphoreGiveRecursive(mutex); + return NULL; + } + // Get the object + obj = UAVObjGetByID(objId); + if (obj == 0) { + xSemaphoreGiveRecursive(mutex); + return NULL; + } + objEntry = (ObjectList *) obj; + + // Get the instance ID + instId = 0; + if (!objEntry->isSingleInstance) { + if (PIOS_FREAD + (file, &instId, sizeof(instId), &bytesRead)) { + xSemaphoreGiveRecursive(mutex); + return NULL; + } + } + // Get the instance information + instEntry = getInstance(objEntry, instId); + + // If the instance does not exist create it and any other instances before it + if (instEntry == NULL) { + instEntry = createInstance(objEntry, instId); + if (instEntry == NULL) { + // Error, unlock and return + xSemaphoreGiveRecursive(mutex); + return NULL; + } + } + // Read the instance data + if (PIOS_FREAD + (file, instEntry->data, objEntry->numBytes, &bytesRead)) { + xSemaphoreGiveRecursive(mutex); + return NULL; + } + // Fire event + sendEvent(objEntry, instId, EV_UNPACKED); + + // Unlock + xSemaphoreGiveRecursive(mutex); + return obj; +#else /* PIOS_INCLUDE_SDCARD */ + return NULL; +#endif +} + +/** + * Load an object from the file system (SD card). + * A file with the name of the object will be opened. + * The object data can be saved using the UAVObjSave function. + * @param[in] obj The object handle. + * @param[in] instId The object instance + * @return 0 if success or -1 if failure + */ +int32_t UAVObjLoad(UAVObjHandle obj, uint16_t instId) +{ +#if defined(PIOS_INCLUDE_FLASH_SECTOR_SETTINGS) + ObjectList *objEntry = (ObjectList *) obj; + + if (objEntry == NULL) + return -1; + + ObjectInstList *instEntry = getInstance(objEntry, instId); + + if (instEntry == NULL) + return -1; + + if (instEntry->data == NULL) + return -1; + + // Fire event on success + if (PIOS_FLASHFS_ObjLoad(obj, instId, instEntry->data) == 0) + sendEvent(objEntry, instId, EV_UNPACKED); + else + return -1; +#endif + +#if defined(PIOS_INCLUDE_SDCARD) + FILEINFO file; + ObjectList *objEntry; + UAVObjHandle loadedObj; + ObjectList *loadedObjEntry; + uint8_t filename[14]; + + // Check for file system availability + if (PIOS_SDCARD_IsMounted() == 0) { + return -1; + } + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Cast to object + objEntry = (ObjectList *) obj; + + // Get filename + objectFilename(objEntry, filename); + + // Open file + if (PIOS_FOPEN_READ(filename, file)) { + xSemaphoreGiveRecursive(mutex); + return -1; + } + // Load object + loadedObj = UAVObjLoadFromFile(&file); + if (loadedObj == 0) { + PIOS_FCLOSE(file); + xSemaphoreGiveRecursive(mutex); + return -1; + } + // Check that the IDs match + loadedObjEntry = (ObjectList *) loadedObj; + if (loadedObjEntry->id != objEntry->id) { + PIOS_FCLOSE(file); + xSemaphoreGiveRecursive(mutex); + return -1; + } + // Done, close file and unlock + PIOS_FCLOSE(file); + xSemaphoreGiveRecursive(mutex); +#endif /* PIOS_INCLUDE_SDCARD */ + return 0; +} + +/** + * Delete an object from the file system (SD card). + * @param[in] obj The object handle. + * @param[in] instId The object instance + * @return 0 if success or -1 if failure + */ +int32_t UAVObjDelete(UAVObjHandle obj, uint16_t instId) +{ +#if defined(PIOS_INCLUDE_FLASH_SECTOR_SETTINGS) + PIOS_FLASHFS_ObjDelete(obj, instId); +#endif +#if defined(PIOS_INCLUDE_SDCARD) + ObjectList *objEntry; + uint8_t filename[14]; + + // Check for file system availability + if (PIOS_SDCARD_IsMounted() == 0) { + return -1; + } + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Cast to object + objEntry = (ObjectList *) obj; + + // Get filename + objectFilename(objEntry, filename); + + // Delete file + PIOS_FUNLINK(filename); + + // Done + xSemaphoreGiveRecursive(mutex); +#endif /* PIOS_INCLUDE_SDCARD */ + return 0; +} + +/** + * Save all settings objects to the SD card. + * @return 0 if success or -1 if failure + */ +int32_t UAVObjSaveSettings() +{ + ObjectList *objEntry; + + // Get lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Save all settings objects + LL_FOREACH(objList, objEntry) { + // Check if this is a settings object + if (objEntry->isSettings) { + // Save object + if (UAVObjSave((UAVObjHandle) objEntry, 0) == + -1) { + xSemaphoreGiveRecursive(mutex); + return -1; + } + } + } + + // Done + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Load all settings objects from the SD card. + * @return 0 if success or -1 if failure + */ +int32_t UAVObjLoadSettings() +{ + ObjectList *objEntry; + + // Get lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Load all settings objects + LL_FOREACH(objList, objEntry) { + // Check if this is a settings object + if (objEntry->isSettings) { + // Load object + if (UAVObjLoad((UAVObjHandle) objEntry, 0) == + -1) { + xSemaphoreGiveRecursive(mutex); + return -1; + } + } + } + + // Done + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Delete all settings objects from the SD card. + * @return 0 if success or -1 if failure + */ +int32_t UAVObjDeleteSettings() +{ + ObjectList *objEntry; + + // Get lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Save all settings objects + LL_FOREACH(objList, objEntry) { + // Check if this is a settings object + if (objEntry->isSettings) { + // Save object + if (UAVObjDelete((UAVObjHandle) objEntry, 0) + == -1) { + xSemaphoreGiveRecursive(mutex); + return -1; + } + } + } + + // Done + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Save all metaobjects to the SD card. + * @return 0 if success or -1 if failure + */ +int32_t UAVObjSaveMetaobjects() +{ + ObjectList *objEntry; + + // Get lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Save all settings objects + LL_FOREACH(objList, objEntry) { + // Check if this is a settings object + if (objEntry->isMetaobject) { + // Save object + if (UAVObjSave((UAVObjHandle) objEntry, 0) == + -1) { + xSemaphoreGiveRecursive(mutex); + return -1; + } + } + } + + // Done + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Load all metaobjects from the SD card. + * @return 0 if success or -1 if failure + */ +int32_t UAVObjLoadMetaobjects() +{ + ObjectList *objEntry; + + // Get lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Load all settings objects + LL_FOREACH(objList, objEntry) { + // Check if this is a settings object + if (objEntry->isMetaobject) { + // Load object + if (UAVObjLoad((UAVObjHandle) objEntry, 0) == + -1) { + xSemaphoreGiveRecursive(mutex); + return -1; + } + } + } + + // Done + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Delete all metaobjects from the SD card. + * @return 0 if success or -1 if failure + */ +int32_t UAVObjDeleteMetaobjects() +{ + ObjectList *objEntry; + + // Get lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Load all settings objects + LL_FOREACH(objList, objEntry) { + // Check if this is a settings object + if (objEntry->isMetaobject) { + // Load object + if (UAVObjDelete((UAVObjHandle) objEntry, 0) + == -1) { + xSemaphoreGiveRecursive(mutex); + return -1; + } + } + } + + // Done + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Set the object data + * \param[in] obj The object handle + * \param[in] dataIn The object's data structure + * \return 0 if success or -1 if failure + */ +int32_t UAVObjSetData(UAVObjHandle obj, const void *dataIn) +{ + return UAVObjSetInstanceData(obj, 0, dataIn); +} + +/** + * Set the object data + * \param[in] obj The object handle + * \param[in] dataIn The object's data structure + * \return 0 if success or -1 if failure + */ +int32_t UAVObjSetDataField(UAVObjHandle obj, const void* dataIn, uint32_t offset, uint32_t size) +{ + return UAVObjSetInstanceDataField(obj, 0, dataIn, offset, size); +} + +/** + * Get the object data + * \param[in] obj The object handle + * \param[out] dataOut The object's data structure + * \return 0 if success or -1 if failure + */ +int32_t UAVObjGetData(UAVObjHandle obj, void *dataOut) +{ + return UAVObjGetInstanceData(obj, 0, dataOut); +} + +/** + * Get the object data + * \param[in] obj The object handle + * \param[out] dataOut The object's data structure + * \return 0 if success or -1 if failure + */ +int32_t UAVObjGetDataField(UAVObjHandle obj, void* dataOut, uint32_t offset, uint32_t size) +{ + return UAVObjGetInstanceDataField(obj, 0, dataOut, offset, size); +} + +/** + * Set the data of a specific object instance + * \param[in] obj The object handle + * \param[in] instId The object instance ID + * \param[in] dataIn The object's data structure + * \return 0 if success or -1 if failure + */ +int32_t UAVObjSetInstanceData(UAVObjHandle obj, uint16_t instId, + const void *dataIn) +{ + ObjectList *objEntry; + ObjectInstList *instEntry; + UAVObjMetadata *mdata; + + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Cast to object info + objEntry = (ObjectList *) obj; + + // Check access level + if (!objEntry->isMetaobject) { + mdata = + (UAVObjMetadata *) (objEntry->linkedObj->instances. + data); + if (mdata->access == ACCESS_READONLY) { + xSemaphoreGiveRecursive(mutex); + return -1; + } + } + // Get instance information + instEntry = getInstance(objEntry, instId); + if (instEntry == NULL) { + // Error, unlock and return + xSemaphoreGiveRecursive(mutex); + return -1; + } + // Set data + memcpy(instEntry->data, dataIn, objEntry->numBytes); + + // Fire event + sendEvent(objEntry, instId, EV_UPDATED); + + // Unlock + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Set the data of a specific object instance + * \param[in] obj The object handle + * \param[in] instId The object instance ID + * \param[in] dataIn The object's data structure + * \return 0 if success or -1 if failure + */ +int32_t UAVObjSetInstanceDataField(UAVObjHandle obj, uint16_t instId, const void* dataIn, uint32_t offset, uint32_t size) +{ + ObjectList* objEntry; + ObjectInstList* instEntry; + UAVObjMetadata* mdata; + + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Cast to object info + objEntry = (ObjectList*)obj; + + // Check access level + if ( !objEntry->isMetaobject ) + { + mdata = (UAVObjMetadata*)(objEntry->linkedObj->instances.data); + if ( mdata->access == ACCESS_READONLY ) + { + xSemaphoreGiveRecursive(mutex); + return -1; + } + } + + // Get instance information + instEntry = getInstance(objEntry, instId); + if ( instEntry == NULL ) + { + // Error, unlock and return + xSemaphoreGiveRecursive(mutex); + return -1; + } + + // return if we set too much of what we have + if ( (size + offset) > objEntry->numBytes) { + // Error, unlock and return + xSemaphoreGiveRecursive(mutex); + return -1; + } + + // Set data + memcpy(instEntry->data + offset, dataIn, size); + + // Fire event + sendEvent(objEntry, instId, EV_UPDATED); + + // Unlock + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Get the data of a specific object instance + * \param[in] obj The object handle + * \param[in] instId The object instance ID + * \param[out] dataOut The object's data structure + * \return 0 if success or -1 if failure + */ +int32_t UAVObjGetInstanceData(UAVObjHandle obj, uint16_t instId, + void *dataOut) +{ + ObjectList *objEntry; + ObjectInstList *instEntry; + + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Cast to object info + objEntry = (ObjectList *) obj; + + // Get instance information + instEntry = getInstance(objEntry, instId); + if (instEntry == NULL) { + // Error, unlock and return + xSemaphoreGiveRecursive(mutex); + return -1; + } + // Set data + memcpy(dataOut, instEntry->data, objEntry->numBytes); + + // Unlock + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Get the data of a specific object instance + * \param[in] obj The object handle + * \param[in] instId The object instance ID + * \param[out] dataOut The object's data structure + * \return 0 if success or -1 if failure + */ +int32_t UAVObjGetInstanceDataField(UAVObjHandle obj, uint16_t instId, void* dataOut, uint32_t offset, uint32_t size) +{ + ObjectList* objEntry; + ObjectInstList* instEntry; + + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Cast to object info + objEntry = (ObjectList*)obj; + + // Get instance information + instEntry = getInstance(objEntry, instId); + if ( instEntry == NULL ) + { + // Error, unlock and return + xSemaphoreGiveRecursive(mutex); + return -1; + } + + // return if we request too much of what we can give + if ( (size + offset) > objEntry->numBytes) + { + // Error, unlock and return + xSemaphoreGiveRecursive(mutex); + return -1; + } + + // Set data + memcpy(dataOut, instEntry->data + offset, size); + + // Unlock + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Set the object metadata + * \param[in] obj The object handle + * \param[in] dataIn The object's metadata structure + * \return 0 if success or -1 if failure + */ +int32_t UAVObjSetMetadata(UAVObjHandle obj, const UAVObjMetadata * dataIn) +{ + ObjectList *objEntry; + + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Set metadata (metadata of metaobjects can not be modified) + objEntry = (ObjectList *) obj; + if (!objEntry->isMetaobject) { + UAVObjSetData((UAVObjHandle) objEntry->linkedObj, + dataIn); + } else { + return -1; + } + + // Unlock + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Get the object metadata + * \param[in] obj The object handle + * \param[out] dataOut The object's metadata structure + * \return 0 if success or -1 if failure + */ +int32_t UAVObjGetMetadata(UAVObjHandle obj, UAVObjMetadata * dataOut) +{ + ObjectList *objEntry; + + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Get metadata + objEntry = (ObjectList *) obj; + if (objEntry->isMetaobject) { + memcpy(dataOut, &defMetadata, sizeof(UAVObjMetadata)); + } else { + UAVObjGetData((UAVObjHandle) objEntry->linkedObj, + dataOut); + } + + // Unlock + xSemaphoreGiveRecursive(mutex); + return 0; +} + +/** + * Check if an object is read only + * \param[in] obj The object handle + * \return + * \arg 0 if not read only + * \arg 1 if read only + * \arg -1 if unable to get meta data + */ +int8_t UAVObjReadOnly(UAVObjHandle obj) +{ + ObjectList *objEntry; + UAVObjMetadata *mdata; + + // Cast to object info + objEntry = (ObjectList *) obj; + + // Check access level + if (!objEntry->isMetaobject) { + mdata = + (UAVObjMetadata *) (objEntry->linkedObj->instances. + data); + return mdata->access == ACCESS_READONLY; + } + return -1; +} + +/** + * Connect an event queue to the object, if the queue is already connected then the event mask is only updated. + * All events matching the event mask will be pushed to the event queue. + * \param[in] obj The object handle + * \param[in] queue The event queue + * \param[in] eventMask The event mask, if EV_MASK_ALL then all events are enabled (e.g. EV_UPDATED | EV_UPDATED_MANUAL) + * \return 0 if success or -1 if failure + */ +int32_t UAVObjConnectQueue(UAVObjHandle obj, xQueueHandle queue, + int32_t eventMask) +{ + int32_t res; + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + res = connectObj(obj, queue, 0, eventMask); + xSemaphoreGiveRecursive(mutex); + return res; +} + +/** + * Disconnect an event queue from the object. + * \param[in] obj The object handle + * \param[in] queue The event queue + * \return 0 if success or -1 if failure + */ +int32_t UAVObjDisconnectQueue(UAVObjHandle obj, xQueueHandle queue) +{ + int32_t res; + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + res = disconnectObj(obj, queue, 0); + xSemaphoreGiveRecursive(mutex); + return res; +} + +/** + * Connect an event callback to the object, if the callback is already connected then the event mask is only updated. + * The supplied callback will be invoked on all events matching the event mask. + * \param[in] obj The object handle + * \param[in] cb The event callback + * \param[in] eventMask The event mask, if EV_MASK_ALL then all events are enabled (e.g. EV_UPDATED | EV_UPDATED_MANUAL) + * \return 0 if success or -1 if failure + */ +int32_t UAVObjConnectCallback(UAVObjHandle obj, UAVObjEventCallback cb, + int32_t eventMask) +{ + int32_t res; + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + res = connectObj(obj, 0, cb, eventMask); + xSemaphoreGiveRecursive(mutex); + return res; +} + +/** + * Disconnect an event callback from the object. + * \param[in] obj The object handle + * \param[in] cb The event callback + * \return 0 if success or -1 if failure + */ +int32_t UAVObjDisconnectCallback(UAVObjHandle obj, UAVObjEventCallback cb) +{ + int32_t res; + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + res = disconnectObj(obj, 0, cb); + xSemaphoreGiveRecursive(mutex); + return res; +} + +/** + * Request an update of the object's data from the GCS. The call will not wait for the response, a EV_UPDATED event + * will be generated as soon as the object is updated. + * \param[in] obj The object handle + */ +void UAVObjRequestUpdate(UAVObjHandle obj) +{ + UAVObjRequestInstanceUpdate(obj, UAVOBJ_ALL_INSTANCES); +} + +/** + * Request an update of the object's data from the GCS. The call will not wait for the response, a EV_UPDATED event + * will be generated as soon as the object is updated. + * \param[in] obj The object handle + * \param[in] instId Object instance ID to update + */ +void UAVObjRequestInstanceUpdate(UAVObjHandle obj, uint16_t instId) +{ + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + sendEvent((ObjectList *) obj, instId, EV_UPDATE_REQ); + xSemaphoreGiveRecursive(mutex); +} + +/** + * Send the object's data to the GCS (triggers a EV_UPDATED_MANUAL event on this object). + * \param[in] obj The object handle + */ +void UAVObjUpdated(UAVObjHandle obj) +{ + UAVObjInstanceUpdated(obj, UAVOBJ_ALL_INSTANCES); +} + +/** + * Send the object's data to the GCS (triggers a EV_UPDATED_MANUAL event on this object). + * \param[in] obj The object handle + * \param[in] instId The object instance ID + */ +void UAVObjInstanceUpdated(UAVObjHandle obj, uint16_t instId) +{ + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + sendEvent((ObjectList *) obj, instId, EV_UPDATED_MANUAL); + xSemaphoreGiveRecursive(mutex); +} + +/** + * Iterate through all objects in the list. + * \param iterator This function will be called once for each object, + * the object will be passed as a parameter + */ +void UAVObjIterate(void (*iterator) (UAVObjHandle obj)) +{ + ObjectList *objEntry; + + // Get lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + // Iterate through the list and invoke iterator for each object + LL_FOREACH(objList, objEntry) { + (*iterator) ((UAVObjHandle) objEntry); + } + + // Release lock + xSemaphoreGiveRecursive(mutex); +} + +/** + * Send an event to all event queues registered on the object. + */ +static int32_t sendEvent(ObjectList * obj, uint16_t instId, + UAVObjEventType event) +{ + ObjectEventList *eventEntry; + UAVObjEvent msg; + + // Setup event + msg.obj = (UAVObjHandle) obj; + msg.event = event; + msg.instId = instId; + + // Go through each object and push the event message in the queue (if event is activated for the queue) + LL_FOREACH(obj->events, eventEntry) { + if (eventEntry->eventMask == 0 + || (eventEntry->eventMask & event) != 0) { + // Send to queue if a valid queue is registered + if (eventEntry->queue != 0) { + if (xQueueSend(eventEntry->queue, &msg, 0) != pdTRUE) // will not block + { + ++stats.eventErrors; + } + } + // Invoke callback (from event task) if a valid one is registered + if (eventEntry->cb != 0) { + if (EventCallbackDispatch(&msg, eventEntry->cb) != pdTRUE) // invoke callback from the event task, will not block + { + ++stats.eventErrors; + } + } + } + } + + // Done + return 0; +} + +/** + * Create a new object instance, return the instance info or NULL if failure. + */ +static ObjectInstList *createInstance(ObjectList * obj, uint16_t instId) +{ + ObjectInstList *instEntry; + int32_t n; + + // For single instance objects, only instance zero is allowed + if (obj->isSingleInstance && instId != 0) { + return NULL; + } + // Make sure that the instance ID is within limits + if (instId >= UAVOBJ_MAX_INSTANCES) { + return NULL; + } + // Check if the instance already exists + if (getInstance(obj, instId) != NULL) { + return NULL; + } + // Create any missing instances (all instance IDs must be sequential) + for (n = obj->numInstances; n < instId; ++n) { + if (createInstance(obj, n) == NULL) { + return NULL; + } + } + + if (instId == 0) { /* Instance 0 ObjectInstList allocated with ObjectList element */ + instEntry = &obj->instances; + instEntry->data = pvPortMalloc(obj->numBytes); + if (instEntry->data == NULL) + return NULL; + memset(instEntry->data, 0, obj->numBytes); + instEntry->instId = instId; + } else { + // Create the actual instance + instEntry = + (ObjectInstList *) + pvPortMalloc(sizeof(ObjectInstList)); + if (instEntry == NULL) + return NULL; + instEntry->data = pvPortMalloc(obj->numBytes); + if (instEntry->data == NULL) + return NULL; + memset(instEntry->data, 0, obj->numBytes); + instEntry->instId = instId; + LL_APPEND(obj->instances.next, instEntry); + } + ++obj->numInstances; + + // Fire event + UAVObjInstanceUpdated((UAVObjHandle) obj, instId); + + // Done + return instEntry; +} + +/** + * Get the instance information or NULL if the instance does not exist + */ +static ObjectInstList *getInstance(ObjectList * obj, uint16_t instId) +{ + ObjectInstList *instEntry; + + // Look for specified instance ID + LL_FOREACH(&(obj->instances), instEntry) { + if (instEntry->instId == instId) { + return instEntry; + } + } + // If this point is reached then instance id was not found + return NULL; +} + +/** + * Connect an event queue to the object, if the queue is already connected then the event mask is only updated. + * \param[in] obj The object handle + * \param[in] queue The event queue + * \param[in] cb The event callback + * \param[in] eventMask The event mask, if EV_MASK_ALL then all events are enabled (e.g. EV_UPDATED | EV_UPDATED_MANUAL) + * \return 0 if success or -1 if failure + */ +static int32_t connectObj(UAVObjHandle obj, xQueueHandle queue, + UAVObjEventCallback cb, int32_t eventMask) +{ + ObjectEventList *eventEntry; + ObjectList *objEntry; + + // Check that the queue is not already connected, if it is simply update event mask + objEntry = (ObjectList *) obj; + LL_FOREACH(objEntry->events, eventEntry) { + if (eventEntry->queue == queue && eventEntry->cb == cb) { + // Already connected, update event mask and return + eventEntry->eventMask = eventMask; + return 0; + } + } + + // Add queue to list + eventEntry = + (ObjectEventList *) pvPortMalloc(sizeof(ObjectEventList)); + if (eventEntry == NULL) { + return -1; + } + eventEntry->queue = queue; + eventEntry->cb = cb; + eventEntry->eventMask = eventMask; + LL_APPEND(objEntry->events, eventEntry); + + // Done + return 0; +} + +/** + * Disconnect an event queue from the object + * \param[in] obj The object handle + * \param[in] queue The event queue + * \param[in] cb The event callback + * \return 0 if success or -1 if failure + */ +static int32_t disconnectObj(UAVObjHandle obj, xQueueHandle queue, + UAVObjEventCallback cb) +{ + ObjectEventList *eventEntry; + ObjectList *objEntry; + + // Find queue and remove it + objEntry = (ObjectList *) obj; + LL_FOREACH(objEntry->events, eventEntry) { + if ((eventEntry->queue == queue + && eventEntry->cb == cb)) { + LL_DELETE(objEntry->events, eventEntry); + vPortFree(eventEntry); + return 0; + } + } + + // If this point is reached the queue was not found + return -1; +} + +#if defined(PIOS_INCLUDE_SDCARD) +/** + * Wrapper for the sprintf function + */ +static void customSPrintf(uint8_t * buffer, uint8_t * format, ...) +{ + va_list args; + va_start(args, format); + vsprintf((char *)buffer, (char *)format, args); +} + +/** + * Get an 8 character (plus extension) filename for the object. + */ +static void objectFilename(ObjectList * obj, uint8_t * filename) +{ + customSPrintf(filename, (uint8_t *) "%X.obj", obj->id); +} +#endif /* PIOS_INCLUDE_SDCARD */ diff --git a/flight/UAVObjects/uavobjectsinittemplate.c b/flight/UAVObjects/uavobjectsinittemplate.c index 75a104d18..97a1525a4 100644 --- a/flight/UAVObjects/uavobjectsinittemplate.c +++ b/flight/UAVObjects/uavobjectsinittemplate.c @@ -36,5 +36,7 @@ $(OBJINC) */ void UAVObjectsInitializeAll() { +return; +// This function is no longer used anyway $(OBJINIT) } diff --git a/flight/UAVObjects/uavobjecttemplate.c b/flight/UAVObjects/uavobjecttemplate.c index 4ee7cc9b1..6d572dbcb 100644 --- a/flight/UAVObjects/uavobjecttemplate.c +++ b/flight/UAVObjects/uavobjecttemplate.c @@ -40,15 +40,19 @@ #include "$(NAMELC).h" // Private variables -static UAVObjHandle handle; +static UAVObjHandle handle = NULL; /** * Initialize object. * \return 0 Success - * \return -1 Failure + * \return -1 Failure to initialize or -2 for already initialized */ int32_t $(NAME)Initialize(void) { + // Don't set the handle to null if already registered + if(UAVObjGetByID($(NAMEUC)_OBJID) != NULL) + return -2; + // Register object with the object manager handle = UAVObjRegister($(NAMEUC)_OBJID, $(NAMEUC)_NAME, $(NAMEUC)_METANAME, 0, $(NAMEUC)_ISSINGLEINST, $(NAMEUC)_ISSETTINGS, $(NAMEUC)_NUMBYTES, &$(NAME)SetDefaults); @@ -64,8 +68,6 @@ int32_t $(NAME)Initialize(void) } } -uavobj_initcall($(NAME)Initialize); - /** * Initialize object fields and metadata with the default values. * If a default value is not specified the object fields @@ -104,6 +106,11 @@ UAVObjHandle $(NAME)Handle() return handle; } +/** + * Get/Set object Functions + */ +$(SETGETFIELDS) + /** * @} */ diff --git a/flight/UAVTalk/inc/uavtalk.h b/flight/UAVTalk/inc/uavtalk.h index 7a257620d..71114ce74 100644 --- a/flight/UAVTalk/inc/uavtalk.h +++ b/flight/UAVTalk/inc/uavtalk.h @@ -29,10 +29,6 @@ #ifndef UAVTALK_H #define UAVTALK_H -// Public constants -#define UAVTALK_WAITFOREVER -1 -#define UAVTALK_NOWAIT 0 - // Public types typedef int32_t (*UAVTalkOutputStream)(uint8_t* data, int32_t length); @@ -47,14 +43,17 @@ typedef struct { uint32_t rxErrors; } UAVTalkStats; +typedef void* UAVTalkConnection; + // Public functions -int32_t UAVTalkInitialize(UAVTalkOutputStream outputStream); -int32_t UAVTalkSetOutputStream(UAVTalkOutputStream outputStream); -int32_t UAVTalkSendObject(UAVObjHandle obj, uint16_t instId, uint8_t acked, int32_t timeoutMs); -int32_t UAVTalkSendObjectRequest(UAVObjHandle obj, uint16_t instId, int32_t timeoutMs); -int32_t UAVTalkProcessInputStream(uint8_t rxbyte); -void UAVTalkGetStats(UAVTalkStats* stats); -void UAVTalkResetStats(); +UAVTalkConnection UAVTalkInitialize(UAVTalkOutputStream outputStream, uint32_t maxPacketSize); +int32_t UAVTalkSetOutputStream(UAVTalkConnection connection, UAVTalkOutputStream outputStream); +UAVTalkOutputStream UAVTalkGetOutputStream(UAVTalkConnection connection); +int32_t UAVTalkSendObject(UAVTalkConnection connection, UAVObjHandle obj, uint16_t instId, uint8_t acked, int32_t timeoutMs); +int32_t UAVTalkSendObjectRequest(UAVTalkConnection connection, UAVObjHandle obj, uint16_t instId, int32_t timeoutMs); +int32_t UAVTalkProcessInputStream(UAVTalkConnection connection, uint8_t rxbyte); +void UAVTalkGetStats(UAVTalkConnection connection, UAVTalkStats *stats); +void UAVTalkResetStats(UAVTalkConnection connection); #endif // UAVTALK_H /** diff --git a/flight/UAVTalk/inc/uavtalk_priv.h b/flight/UAVTalk/inc/uavtalk_priv.h new file mode 100644 index 000000000..1bcf01fd9 --- /dev/null +++ b/flight/UAVTalk/inc/uavtalk_priv.h @@ -0,0 +1,111 @@ +/** + ****************************************************************************** + * @addtogroup OpenPilotSystem OpenPilot System + * @{ + * @addtogroup OpenPilotLibraries OpenPilot System Libraries + * @{ + * @file uavtalk.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Private include file of the UAVTalk library + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef UAVTALK_PRIV_H +#define UAVTALK_PRIV_H + +#include "uavobjectsinit.h" + +// Private types and constants +typedef struct { + uint8_t sync; + uint8_t type; + uint16_t size; + uint32_t objId; +} uavtalk_min_header; +#define UAVTALK_MIN_HEADER_LENGTH sizeof(uavtalk_min_header) + +typedef struct { + uint8_t sync; + uint8_t type; + uint16_t size; + uint32_t objId; + uint16_t instId; +} uavtalk_max_header; +#define UAVTALK_MAX_HEADER_LENGTH sizeof(uavtalk_max_header) + +typedef uint8_t uavtalk_checksum; +#define UAVTALK_CHECKSUM_LENGTH sizeof(uavtalk_checksum) +#define UAVTALK_MAX_PAYLOAD_LENGTH UAVOBJECTS_LARGEST +#define UAVTALK_MIN_PACKET_LENGTH UAVTALK_MAX_HEADER_LENGTH + UAVTALK_CHECKSUM_LENGTH +#define UAVTALK_MAX_PACKET_LENGTH UAVTALK_MIN_PACKET_LENGTH + UAVTALK_MAX_PAYLOAD_LENGTH + +typedef enum {UAVTALK_STATE_SYNC, UAVTALK_STATE_TYPE, UAVTALK_STATE_SIZE, UAVTALK_STATE_OBJID, UAVTALK_STATE_INSTID, UAVTALK_STATE_DATA, UAVTALK_STATE_CS} UAVTalkRxState; + +typedef struct { + UAVObjHandle obj; + uint8_t type; + uint16_t packet_size; + uint32_t objId; + uint16_t instId; + uint32_t length; + uint8_t cs; + int32_t rxCount; + UAVTalkRxState state; + uint16_t rxPacketLength; +} UAVTalkInputProcessor; + +typedef struct { + uint8_t canari; + UAVTalkOutputStream outStream; + xSemaphoreHandle lock; + xSemaphoreHandle transLock; + xSemaphoreHandle respSema; + UAVObjHandle respObj; + uint16_t respInstId; + UAVTalkStats stats; + UAVTalkInputProcessor iproc; + uint8_t *rxBuffer; + uint32_t txSize; + uint8_t *txBuffer; +} UAVTalkConnectionData; + +#define UAVTALK_CANARI 0xCA +#define UAVTALK_WAITFOREVER -1 +#define UAVTALK_NOWAIT 0 +#define UAVTALK_SYNC_VAL 0x3C +#define UAVTALK_TYPE_MASK 0xF8 +#define UAVTALK_TYPE_VER 0x20 +#define UAVTALK_TYPE_OBJ (UAVTALK_TYPE_VER | 0x00) +#define UAVTALK_TYPE_OBJ_REQ (UAVTALK_TYPE_VER | 0x01) +#define UAVTALK_TYPE_OBJ_ACK (UAVTALK_TYPE_VER | 0x02) +#define UAVTALK_TYPE_ACK (UAVTALK_TYPE_VER | 0x03) +#define UAVTALK_TYPE_NACK (UAVTALK_TYPE_VER | 0x04) + +//macros +#define CHECKCONHANDLE(handle,variable,failcommand) \ + variable = (UAVTalkConnectionData*) handle; \ + if (variable == NULL || variable->canari != UAVTALK_CANARI) { \ + failcommand; \ + } + +#endif // UAVTALK__PRIV_H +/** + * @} + * @} + */ diff --git a/flight/UAVTalk/uavtalk.c b/flight/UAVTalk/uavtalk.c index 57136db90..236915b28 100644 --- a/flight/UAVTalk/uavtalk.c +++ b/flight/UAVTalk/uavtalk.c @@ -30,134 +30,145 @@ */ #include "openpilot.h" +#include "uavtalk_priv.h" -// Private constants -#define SYNC_VAL 0x3C -#define TYPE_MASK 0xF8 -#define TYPE_VER 0x20 -#define TYPE_OBJ (TYPE_VER | 0x00) -#define TYPE_OBJ_REQ (TYPE_VER | 0x01) -#define TYPE_OBJ_ACK (TYPE_VER | 0x02) -#define TYPE_ACK (TYPE_VER | 0x03) -#define TYPE_NACK (TYPE_VER | 0x04) - -#define MIN_HEADER_LENGTH 8 // sync(1), type (1), size (2), object ID (4) -#define MAX_HEADER_LENGTH 10 // sync(1), type (1), size (2), object ID (4), instance ID (2, not used in single objects) - -#define CHECKSUM_LENGTH 1 - -#define MAX_PAYLOAD_LENGTH 256 - -#define MAX_PACKET_LENGTH (MAX_HEADER_LENGTH + MAX_PAYLOAD_LENGTH + CHECKSUM_LENGTH) - -// CRC lookup table -static const uint8_t crc_table[256] = { - 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 -}; - -// Private types -typedef enum {STATE_SYNC, STATE_TYPE, STATE_SIZE, STATE_OBJID, STATE_INSTID, STATE_DATA, STATE_CS} RxState; - -// Private variables -static UAVTalkOutputStream outStream; -static xSemaphoreHandle lock; -static xSemaphoreHandle transLock; -static xSemaphoreHandle respSema; -static UAVObjHandle respObj; -static uint16_t respInstId; -static uint8_t rxBuffer[MAX_PACKET_LENGTH]; -static uint8_t txBuffer[MAX_PACKET_LENGTH]; -static UAVTalkStats stats; // Private functions -static uint8_t updateCRCbyte(uint8_t crc, const uint8_t data); -static uint8_t updateCRC(uint8_t crc, const uint8_t* data, int32_t length); -static int32_t objectTransaction(UAVObjHandle objectId, uint16_t instId, uint8_t type, int32_t timeout); -static int32_t sendObject(UAVObjHandle obj, uint16_t instId, uint8_t type); -static int32_t sendSingleObject(UAVObjHandle obj, uint16_t instId, uint8_t type); -static int32_t sendNack(uint32_t objId); -static int32_t receiveObject(uint8_t type, uint32_t objId, uint16_t instId, uint8_t* data, int32_t length); -static void updateAck(UAVObjHandle obj, uint16_t instId); +static int32_t objectTransaction(UAVTalkConnectionData *connection, UAVObjHandle objectId, uint16_t instId, uint8_t type, int32_t timeout); +static int32_t sendObject(UAVTalkConnectionData *connection, UAVObjHandle obj, uint16_t instId, uint8_t type); +static int32_t sendSingleObject(UAVTalkConnectionData *connection, UAVObjHandle obj, uint16_t instId, uint8_t type); +static int32_t sendNack(UAVTalkConnectionData *connection, uint32_t objId); +static int32_t receiveObject(UAVTalkConnectionData *connection, uint8_t type, uint32_t objId, uint16_t instId, uint8_t* data, int32_t length); +static void updateAck(UAVTalkConnectionData *connection, UAVObjHandle obj, uint16_t instId); /** * Initialize the UAVTalk library + * \param[in] connection UAVTalkConnection to be used * \param[in] outputStream Function pointer that is called to send a data buffer * \return 0 Success * \return -1 Failure */ -int32_t UAVTalkInitialize(UAVTalkOutputStream outputStream) +UAVTalkConnection UAVTalkInitialize(UAVTalkOutputStream outputStream, uint32_t maxPacketSize) { - outStream = outputStream; - lock = xSemaphoreCreateRecursiveMutex(); - transLock = xSemaphoreCreateRecursiveMutex(); - vSemaphoreCreateBinary(respSema); - xSemaphoreTake(respSema, 0); // reset to zero - UAVTalkResetStats(); + if (maxPacketSize<1) return 0; + // allocate object + UAVTalkConnectionData * connection = pvPortMalloc(sizeof(UAVTalkConnectionData)); + if (!connection) return 0; + connection->canari = UAVTALK_CANARI; + connection->iproc.rxPacketLength = 0; + connection->iproc.state = UAVTALK_STATE_SYNC; + connection->outStream = outputStream; + connection->lock = xSemaphoreCreateRecursiveMutex(); + connection->transLock = xSemaphoreCreateRecursiveMutex(); + connection->txSize = maxPacketSize; + // allocate buffers + connection->rxBuffer = pvPortMalloc(UAVTALK_MAX_PACKET_LENGTH); + if (!connection->rxBuffer) return 0; + connection->txBuffer = pvPortMalloc(UAVTALK_MAX_PACKET_LENGTH); + if (!connection->txBuffer) return 0; + vSemaphoreCreateBinary(connection->respSema); + xSemaphoreTake(connection->respSema, 0); // reset to zero + UAVTalkResetStats( (UAVTalkConnection) connection ); + return (UAVTalkConnection) connection; +} + +/** + * Set the communication output stream + * \param[in] connection UAVTalkConnection to be used + * \param[in] outputStream Function pointer that is called to send a data buffer + * \return 0 Success + * \return -1 Failure + */ +int32_t UAVTalkSetOutputStream(UAVTalkConnection connectionHandle, UAVTalkOutputStream outputStream) +{ + + UAVTalkConnectionData *connection; + CHECKCONHANDLE(connectionHandle,connection,return -1); + + // Lock + xSemaphoreTakeRecursive(connection->lock, portMAX_DELAY); + + // set output stream + connection->outStream = outputStream; + + // Release lock + xSemaphoreGiveRecursive(connection->lock); + return 0; + +} + +/** + * Get current output stream + * \param[in] connection UAVTalkConnection to be used + * @return UAVTarlkOutputStream the output stream used + */ +UAVTalkOutputStream UAVTalkGetOutputStream(UAVTalkConnection connectionHandle) +{ + UAVTalkConnectionData *connection; + CHECKCONHANDLE(connectionHandle,connection,return NULL); + return connection->outStream; } /** * Get communication statistics counters + * \param[in] connection UAVTalkConnection to be used * @param[out] statsOut Statistics counters */ -void UAVTalkGetStats(UAVTalkStats* statsOut) +void UAVTalkGetStats(UAVTalkConnection connectionHandle, UAVTalkStats* statsOut) { + UAVTalkConnectionData *connection; + CHECKCONHANDLE(connectionHandle,connection,return ); + // Lock - xSemaphoreTakeRecursive(lock, portMAX_DELAY); + xSemaphoreTakeRecursive(connection->lock, portMAX_DELAY); // Copy stats - memcpy(statsOut, &stats, sizeof(UAVTalkStats)); + memcpy(statsOut, &connection->stats, sizeof(UAVTalkStats)); // Release lock - xSemaphoreGiveRecursive(lock); + xSemaphoreGiveRecursive(connection->lock); } /** * Reset the statistics counters. + * \param[in] connection UAVTalkConnection to be used */ -void UAVTalkResetStats() +void UAVTalkResetStats(UAVTalkConnection connectionHandle) { + UAVTalkConnectionData *connection; + CHECKCONHANDLE(connectionHandle,connection,return); + // Lock - xSemaphoreTakeRecursive(lock, portMAX_DELAY); + xSemaphoreTakeRecursive(connection->lock, portMAX_DELAY); // Clear stats - memset(&stats, 0, sizeof(UAVTalkStats)); + memset(&connection->stats, 0, sizeof(UAVTalkStats)); // Release lock - xSemaphoreGiveRecursive(lock); + xSemaphoreGiveRecursive(connection->lock); } /** * Request an update for the specified object, on success the object data would have been * updated by the GCS. + * \param[in] connection UAVTalkConnection to be used * \param[in] obj Object to update * \param[in] instId The instance ID or UAVOBJ_ALL_INSTANCES for all instances. * \param[in] timeout Time to wait for the response, when zero it will return immediately * \return 0 Success * \return -1 Failure */ -int32_t UAVTalkSendObjectRequest(UAVObjHandle obj, uint16_t instId, int32_t timeout) +int32_t UAVTalkSendObjectRequest(UAVTalkConnection connectionHandle, UAVObjHandle obj, uint16_t instId, int32_t timeout) { - return objectTransaction(obj, instId, TYPE_OBJ_REQ, timeout); + UAVTalkConnectionData *connection; + CHECKCONHANDLE(connectionHandle,connection,return -1); + return objectTransaction(connection, obj, instId, UAVTALK_TYPE_OBJ_REQ, timeout); } /** * Send the specified object through the telemetry link. + * \param[in] connection UAVTalkConnection to be used * \param[in] obj Object to send * \param[in] instId The instance ID or UAVOBJ_ALL_INSTANCES for all instances. * \param[in] acked Selects if an ack is required (1:ack required, 0: ack not required) @@ -165,69 +176,72 @@ int32_t UAVTalkSendObjectRequest(UAVObjHandle obj, uint16_t instId, int32_t time * \return 0 Success * \return -1 Failure */ -int32_t UAVTalkSendObject(UAVObjHandle obj, uint16_t instId, uint8_t acked, int32_t timeoutMs) +int32_t UAVTalkSendObject(UAVTalkConnection connectionHandle, UAVObjHandle obj, uint16_t instId, uint8_t acked, int32_t timeoutMs) { + UAVTalkConnectionData *connection; + CHECKCONHANDLE(connectionHandle,connection,return -1); // Send object if (acked == 1) { - return objectTransaction(obj, instId, TYPE_OBJ_ACK, timeoutMs); + return objectTransaction(connection, obj, instId, UAVTALK_TYPE_OBJ_ACK, timeoutMs); } else { - return objectTransaction(obj, instId, TYPE_OBJ, timeoutMs); + return objectTransaction(connection, obj, instId, UAVTALK_TYPE_OBJ, timeoutMs); } } /** * Execute the requested transaction on an object. + * \param[in] connection UAVTalkConnection to be used * \param[in] obj Object * \param[in] instId The instance ID of UAVOBJ_ALL_INSTANCES for all instances. * \param[in] type Transaction type - * TYPE_OBJ: send object, - * TYPE_OBJ_REQ: request object update - * TYPE_OBJ_ACK: send object with an ack + * UAVTALK_TYPE_OBJ: send object, + * UAVTALK_TYPE_OBJ_REQ: request object update + * UAVTALK_TYPE_OBJ_ACK: send object with an ack * \return 0 Success * \return -1 Failure */ -static int32_t objectTransaction(UAVObjHandle obj, uint16_t instId, uint8_t type, int32_t timeoutMs) +static int32_t objectTransaction(UAVTalkConnectionData *connection, UAVObjHandle obj, uint16_t instId, uint8_t type, int32_t timeoutMs) { int32_t respReceived; // Send object depending on if a response is needed - if (type == TYPE_OBJ_ACK || type == TYPE_OBJ_REQ) + if (type == UAVTALK_TYPE_OBJ_ACK || type == UAVTALK_TYPE_OBJ_REQ) { // Get transaction lock (will block if a transaction is pending) - xSemaphoreTakeRecursive(transLock, portMAX_DELAY); + xSemaphoreTakeRecursive(connection->transLock, portMAX_DELAY); // Send object - xSemaphoreTakeRecursive(lock, portMAX_DELAY); - respObj = obj; - respInstId = instId; - sendObject(obj, instId, type); - xSemaphoreGiveRecursive(lock); + xSemaphoreTakeRecursive(connection->lock, portMAX_DELAY); + connection->respObj = obj; + connection->respInstId = instId; + sendObject(connection, obj, instId, type); + xSemaphoreGiveRecursive(connection->lock); // Wait for response (or timeout) - respReceived = xSemaphoreTake(respSema, timeoutMs/portTICK_RATE_MS); + respReceived = xSemaphoreTake(connection->respSema, timeoutMs/portTICK_RATE_MS); // Check if a response was received if (respReceived == pdFALSE) { // Cancel transaction - xSemaphoreTakeRecursive(lock, portMAX_DELAY); - xSemaphoreTake(respSema, 0); // non blocking call to make sure the value is reset to zero (binary sema) - respObj = 0; - xSemaphoreGiveRecursive(lock); - xSemaphoreGiveRecursive(transLock); + xSemaphoreTakeRecursive(connection->lock, portMAX_DELAY); + xSemaphoreTake(connection->respSema, 0); // non blocking call to make sure the value is reset to zero (binary sema) + connection->respObj = 0; + xSemaphoreGiveRecursive(connection->lock); + xSemaphoreGiveRecursive(connection->transLock); return -1; } else { - xSemaphoreGiveRecursive(transLock); + xSemaphoreGiveRecursive(connection->transLock); return 0; } } - else if (type == TYPE_OBJ) + else if (type == UAVTALK_TYPE_OBJ) { - xSemaphoreTakeRecursive(lock, portMAX_DELAY); - sendObject(obj, instId, TYPE_OBJ); - xSemaphoreGiveRecursive(lock); + xSemaphoreTakeRecursive(connection->lock, portMAX_DELAY); + sendObject(connection, obj, instId, UAVTALK_TYPE_OBJ); + xSemaphoreGiveRecursive(connection->lock); return 0; } else @@ -238,222 +252,214 @@ static int32_t objectTransaction(UAVObjHandle obj, uint16_t instId, uint8_t type /** * Process an byte from the telemetry stream. + * \param[in] connection UAVTalkConnection to be used * \param[in] rxbyte Received byte * \return 0 Success * \return -1 Failure */ -int32_t UAVTalkProcessInputStream(uint8_t rxbyte) +int32_t UAVTalkProcessInputStream(UAVTalkConnection connectionHandle, uint8_t rxbyte) { - static UAVObjHandle obj; - static uint8_t type; - static uint16_t packet_size; - static uint32_t objId; - static uint16_t instId; - static uint32_t length; - static uint8_t cs, csRx; - static int32_t rxCount; - static RxState state = STATE_SYNC; - static uint16_t rxPacketLength = 0; + UAVTalkConnectionData *connection; + CHECKCONHANDLE(connectionHandle,connection,return -1); + + UAVTalkInputProcessor *iproc = &connection->iproc; + ++connection->stats.rxBytes; - ++stats.rxBytes; - - if (rxPacketLength < 0xffff) - rxPacketLength++; // update packet byte count + if (iproc->rxPacketLength < 0xffff) + iproc->rxPacketLength++; // update packet byte count // Receive state machine - switch (state) + switch (iproc->state) { - case STATE_SYNC: - if (rxbyte != SYNC_VAL) + case UAVTALK_STATE_SYNC: + if (rxbyte != UAVTALK_SYNC_VAL) break; // Initialize and update the CRC - cs = updateCRCbyte(0, rxbyte); + iproc->cs = PIOS_CRC_updateByte(0, rxbyte); - rxPacketLength = 1; + iproc->rxPacketLength = 1; - state = STATE_TYPE; + iproc->state = UAVTALK_STATE_TYPE; break; - case STATE_TYPE: + case UAVTALK_STATE_TYPE: // update the CRC - cs = updateCRCbyte(cs, rxbyte); + iproc->cs = PIOS_CRC_updateByte(iproc->cs, rxbyte); - if ((rxbyte & TYPE_MASK) != TYPE_VER) + if ((rxbyte & UAVTALK_TYPE_MASK) != UAVTALK_TYPE_VER) { - state = STATE_SYNC; + iproc->state = UAVTALK_STATE_SYNC; break; } - type = rxbyte; + iproc->type = rxbyte; - packet_size = 0; + iproc->packet_size = 0; - state = STATE_SIZE; - rxCount = 0; + iproc->state = UAVTALK_STATE_SIZE; + iproc->rxCount = 0; break; - case STATE_SIZE: + case UAVTALK_STATE_SIZE: // update the CRC - cs = updateCRCbyte(cs, rxbyte); + iproc->cs = PIOS_CRC_updateByte(iproc->cs, rxbyte); - if (rxCount == 0) + if (iproc->rxCount == 0) { - packet_size += rxbyte; - rxCount++; + iproc->packet_size += rxbyte; + iproc->rxCount++; break; } - packet_size += rxbyte << 8; + iproc->packet_size += rxbyte << 8; - if (packet_size < MIN_HEADER_LENGTH || packet_size > MAX_HEADER_LENGTH + MAX_PAYLOAD_LENGTH) + if (iproc->packet_size < UAVTALK_MIN_HEADER_LENGTH || iproc->packet_size > UAVTALK_MAX_HEADER_LENGTH + UAVTALK_MAX_PAYLOAD_LENGTH) { // incorrect packet size - state = STATE_SYNC; + iproc->state = UAVTALK_STATE_SYNC; break; } - rxCount = 0; - objId = 0; - state = STATE_OBJID; + iproc->rxCount = 0; + iproc->objId = 0; + iproc->state = UAVTALK_STATE_OBJID; break; - case STATE_OBJID: + case UAVTALK_STATE_OBJID: // update the CRC - cs = updateCRCbyte(cs, rxbyte); + iproc->cs = PIOS_CRC_updateByte(iproc->cs, rxbyte); - objId += rxbyte << (8*(rxCount++)); + iproc->objId += rxbyte << (8*(iproc->rxCount++)); - if (rxCount < 4) + if (iproc->rxCount < 4) break; // Search for object, if not found reset state machine // except if we got a OBJ_REQ for an object which does not // exist, in which case we'll send a NACK - obj = UAVObjGetByID(objId); - if (obj == 0 && type != TYPE_OBJ_REQ) + iproc->obj = UAVObjGetByID(iproc->objId); + if (iproc->obj == 0 && iproc->type != UAVTALK_TYPE_OBJ_REQ) { - stats.rxErrors++; - state = STATE_SYNC; + connection->stats.rxErrors++; + iproc->state = UAVTALK_STATE_SYNC; break; } // Determine data length - if (type == TYPE_OBJ_REQ || type == TYPE_ACK || type == TYPE_NACK) - length = 0; + if (iproc->type == UAVTALK_TYPE_OBJ_REQ || iproc->type == UAVTALK_TYPE_ACK || iproc->type == UAVTALK_TYPE_NACK) + iproc->length = 0; else - length = UAVObjGetNumBytes(obj); + iproc->length = UAVObjGetNumBytes(iproc->obj); // Check length and determine next state - if (length >= MAX_PAYLOAD_LENGTH) + if (iproc->length >= UAVTALK_MAX_PAYLOAD_LENGTH) { - stats.rxErrors++; - state = STATE_SYNC; + connection->stats.rxErrors++; + iproc->state = UAVTALK_STATE_SYNC; break; } // Check the lengths match - if ((rxPacketLength + length) != packet_size) + if ((iproc->rxPacketLength + iproc->length) != iproc->packet_size) { // packet error - mismatched packet size - stats.rxErrors++; - state = STATE_SYNC; + connection->stats.rxErrors++; + iproc->state = UAVTALK_STATE_SYNC; break; } - instId = 0; - if (obj == 0) + iproc->instId = 0; + if (iproc->obj == 0) { // If this is a NACK, we skip to Checksum - state = STATE_CS; - rxCount = 0; + iproc->state = UAVTALK_STATE_CS; + iproc->rxCount = 0; } // Check if this is a single instance object (i.e. if the instance ID field is coming next) - else if (UAVObjIsSingleInstance(obj)) + else if (UAVObjIsSingleInstance(iproc->obj)) { // If there is a payload get it, otherwise receive checksum - if (length > 0) - state = STATE_DATA; + if (iproc->length > 0) + iproc->state = UAVTALK_STATE_DATA; else - state = STATE_CS; + iproc->state = UAVTALK_STATE_CS; - rxCount = 0; + iproc->rxCount = 0; } else { - state = STATE_INSTID; - rxCount = 0; + iproc->state = UAVTALK_STATE_INSTID; + iproc->rxCount = 0; } break; - case STATE_INSTID: + case UAVTALK_STATE_INSTID: // update the CRC - cs = updateCRCbyte(cs, rxbyte); + iproc->cs = PIOS_CRC_updateByte(iproc->cs, rxbyte); - instId += rxbyte << (8*(rxCount++)); + iproc->instId += rxbyte << (8*(iproc->rxCount++)); - if (rxCount < 2) + if (iproc->rxCount < 2) break; - rxCount = 0; + iproc->rxCount = 0; // If there is a payload get it, otherwise receive checksum - if (length > 0) - state = STATE_DATA; + if (iproc->length > 0) + iproc->state = UAVTALK_STATE_DATA; else - state = STATE_CS; + iproc->state = UAVTALK_STATE_CS; break; - case STATE_DATA: + case UAVTALK_STATE_DATA: // update the CRC - cs = updateCRCbyte(cs, rxbyte); + iproc->cs = PIOS_CRC_updateByte(iproc->cs, rxbyte); - rxBuffer[rxCount++] = rxbyte; - if (rxCount < length) + connection->rxBuffer[iproc->rxCount++] = rxbyte; + if (iproc->rxCount < iproc->length) break; - state = STATE_CS; - rxCount = 0; + iproc->state = UAVTALK_STATE_CS; + iproc->rxCount = 0; break; - case STATE_CS: + case UAVTALK_STATE_CS: // the CRC byte - csRx = rxbyte; - - if (csRx != cs) + if (rxbyte != iproc->cs) { // packet error - faulty CRC - stats.rxErrors++; - state = STATE_SYNC; + connection->stats.rxErrors++; + iproc->state = UAVTALK_STATE_SYNC; break; } - if (rxPacketLength != (packet_size + 1)) + if (iproc->rxPacketLength != (iproc->packet_size + 1)) { // packet error - mismatched packet size - stats.rxErrors++; - state = STATE_SYNC; + connection->stats.rxErrors++; + iproc->state = UAVTALK_STATE_SYNC; break; } - xSemaphoreTakeRecursive(lock, portMAX_DELAY); - receiveObject(type, objId, instId, rxBuffer, length); - stats.rxObjectBytes += length; - stats.rxObjects++; - xSemaphoreGiveRecursive(lock); + xSemaphoreTakeRecursive(connection->lock, portMAX_DELAY); + receiveObject(connection, iproc->type, iproc->objId, iproc->instId, connection->rxBuffer, iproc->length); + connection->stats.rxObjectBytes += iproc->length; + connection->stats.rxObjects++; + xSemaphoreGiveRecursive(connection->lock); - state = STATE_SYNC; + iproc->state = UAVTALK_STATE_SYNC; break; default: - stats.rxErrors++; - state = STATE_SYNC; + connection->stats.rxErrors++; + iproc->state = UAVTALK_STATE_SYNC; } // Done @@ -462,7 +468,8 @@ int32_t UAVTalkProcessInputStream(uint8_t rxbyte) /** * Receive an object. This function process objects received through the telemetry stream. - * \param[in] type Type of received message (TYPE_OBJ, TYPE_OBJ_REQ, TYPE_OBJ_ACK, TYPE_ACK, TYPE_NACK) + * \param[in] connection UAVTalkConnection to be used + * \param[in] type Type of received message (UAVTALK_TYPE_OBJ, UAVTALK_TYPE_OBJ_REQ, UAVTALK_TYPE_OBJ_ACK, UAVTALK_TYPE_ACK, UAVTALK_TYPE_NACK) * \param[in] objId ID of the object to work on * \param[in] instId The instance ID of UAVOBJ_ALL_INSTANCES for all instances. * \param[in] data Data buffer @@ -470,9 +477,9 @@ int32_t UAVTalkProcessInputStream(uint8_t rxbyte) * \return 0 Success * \return -1 Failure */ -static int32_t receiveObject(uint8_t type, uint32_t objId, uint16_t instId, uint8_t* data, int32_t length) +static int32_t receiveObject(UAVTalkConnectionData *connection, uint8_t type, uint32_t objId, uint16_t instId, uint8_t* data, int32_t length) { - static UAVObjHandle obj; + UAVObjHandle obj; int32_t ret = 0; // Get the handle to the Object. Will be zero @@ -481,21 +488,21 @@ static int32_t receiveObject(uint8_t type, uint32_t objId, uint16_t instId, uint // Process message type switch (type) { - case TYPE_OBJ: + case UAVTALK_TYPE_OBJ: // All instances, not allowed for OBJ messages if (instId != UAVOBJ_ALL_INSTANCES) { // Unpack object, if the instance does not exist it will be created! UAVObjUnpack(obj, instId, data); // Check if an ack is pending - updateAck(obj, instId); + updateAck(connection, obj, instId); } else { ret = -1; } break; - case TYPE_OBJ_ACK: + case UAVTALK_TYPE_OBJ_ACK: // All instances, not allowed for OBJ_ACK messages if (instId != UAVOBJ_ALL_INSTANCES) { @@ -503,7 +510,7 @@ static int32_t receiveObject(uint8_t type, uint32_t objId, uint16_t instId, uint if ( UAVObjUnpack(obj, instId, data) == 0 ) { // Transmit ACK - sendObject(obj, instId, TYPE_ACK); + sendObject(connection, obj, instId, UAVTALK_TYPE_ACK); } else { @@ -515,22 +522,22 @@ static int32_t receiveObject(uint8_t type, uint32_t objId, uint16_t instId, uint ret = -1; } break; - case TYPE_OBJ_REQ: + case UAVTALK_TYPE_OBJ_REQ: // Send requested object if message is of type OBJ_REQ if (obj == 0) - sendNack(objId); + sendNack(connection, objId); else - sendObject(obj, instId, TYPE_OBJ); + sendObject(connection, obj, instId, UAVTALK_TYPE_OBJ); break; - case TYPE_NACK: + case UAVTALK_TYPE_NACK: // Do nothing on flight side, let it time out. break; - case TYPE_ACK: + case UAVTALK_TYPE_ACK: // All instances, not allowed for ACK messages if (instId != UAVOBJ_ALL_INSTANCES) { // Check if an ack is pending - updateAck(obj, instId); + updateAck(connection, obj, instId); } else { @@ -546,25 +553,29 @@ static int32_t receiveObject(uint8_t type, uint32_t objId, uint16_t instId, uint /** * Check if an ack is pending on an object and give response semaphore + * \param[in] connection UAVTalkConnection to be used + * \param[in] obj Object + * \param[in] instId The instance ID of UAVOBJ_ALL_INSTANCES for all instances. */ -static void updateAck(UAVObjHandle obj, uint16_t instId) +static void updateAck(UAVTalkConnectionData *connection, UAVObjHandle obj, uint16_t instId) { - if (respObj == obj && (respInstId == instId || respInstId == UAVOBJ_ALL_INSTANCES)) + if (connection->respObj == obj && (connection->respInstId == instId || connection->respInstId == UAVOBJ_ALL_INSTANCES)) { - xSemaphoreGive(respSema); - respObj = 0; + xSemaphoreGive(connection->respSema); + connection->respObj = 0; } } /** * Send an object through the telemetry link. + * \param[in] connection UAVTalkConnection to be used * \param[in] obj Object handle to send * \param[in] instId The instance ID or UAVOBJ_ALL_INSTANCES for all instances * \param[in] type Transaction type * \return 0 Success * \return -1 Failure */ -static int32_t sendObject(UAVObjHandle obj, uint16_t instId, uint8_t type) +static int32_t sendObject(UAVTalkConnectionData *connection, UAVObjHandle obj, uint16_t instId, uint8_t type) { uint32_t numInst; uint32_t n; @@ -576,7 +587,7 @@ static int32_t sendObject(UAVObjHandle obj, uint16_t instId, uint8_t type) } // Process message type - if ( type == TYPE_OBJ || type == TYPE_OBJ_ACK ) + if ( type == UAVTALK_TYPE_OBJ || type == UAVTALK_TYPE_OBJ_ACK ) { if (instId == UAVOBJ_ALL_INSTANCES) { @@ -585,24 +596,24 @@ static int32_t sendObject(UAVObjHandle obj, uint16_t instId, uint8_t type) // Send all instances for (n = 0; n < numInst; ++n) { - sendSingleObject(obj, n, type); + sendSingleObject(connection, obj, n, type); } return 0; } else { - return sendSingleObject(obj, instId, type); + return sendSingleObject(connection, obj, instId, type); } } - else if (type == TYPE_OBJ_REQ) + else if (type == UAVTALK_TYPE_OBJ_REQ) { - return sendSingleObject(obj, instId, TYPE_OBJ_REQ); + return sendSingleObject(connection, obj, instId, UAVTALK_TYPE_OBJ_REQ); } - else if (type == TYPE_ACK) + else if (type == UAVTALK_TYPE_ACK) { if ( instId != UAVOBJ_ALL_INSTANCES ) { - return sendSingleObject(obj, instId, TYPE_ACK); + return sendSingleObject(connection, obj, instId, UAVTALK_TYPE_ACK); } else { @@ -617,13 +628,14 @@ static int32_t sendObject(UAVObjHandle obj, uint16_t instId, uint8_t type) /** * Send an object through the telemetry link. + * \param[in] connection UAVTalkConnection to be used * \param[in] obj Object handle to send * \param[in] instId The instance ID (can NOT be UAVOBJ_ALL_INSTANCES, use sendObject() instead) * \param[in] type Transaction type * \return 0 Success * \return -1 Failure */ -static int32_t sendSingleObject(UAVObjHandle obj, uint16_t instId, uint8_t type) +static int32_t sendSingleObject(UAVTalkConnectionData *connection, UAVObjHandle obj, uint16_t instId, uint8_t type) { int32_t length; int32_t dataOffset; @@ -631,13 +643,13 @@ static int32_t sendSingleObject(UAVObjHandle obj, uint16_t instId, uint8_t type) // Setup type and object id fields objId = UAVObjGetID(obj); - txBuffer[0] = SYNC_VAL; // sync byte - txBuffer[1] = type; + connection->txBuffer[0] = UAVTALK_SYNC_VAL; // sync byte + connection->txBuffer[1] = type; // data length inserted here below - txBuffer[4] = (uint8_t)(objId & 0xFF); - txBuffer[5] = (uint8_t)((objId >> 8) & 0xFF); - txBuffer[6] = (uint8_t)((objId >> 16) & 0xFF); - txBuffer[7] = (uint8_t)((objId >> 24) & 0xFF); + connection->txBuffer[4] = (uint8_t)(objId & 0xFF); + connection->txBuffer[5] = (uint8_t)((objId >> 8) & 0xFF); + connection->txBuffer[6] = (uint8_t)((objId >> 16) & 0xFF); + connection->txBuffer[7] = (uint8_t)((objId >> 24) & 0xFF); // Setup instance ID if one is required if (UAVObjIsSingleInstance(obj)) @@ -646,13 +658,13 @@ static int32_t sendSingleObject(UAVObjHandle obj, uint16_t instId, uint8_t type) } else { - txBuffer[8] = (uint8_t)(instId & 0xFF); - txBuffer[9] = (uint8_t)((instId >> 8) & 0xFF); + connection->txBuffer[8] = (uint8_t)(instId & 0xFF); + connection->txBuffer[9] = (uint8_t)((instId >> 8) & 0xFF); dataOffset = 10; } // Determine data length - if (type == TYPE_OBJ_REQ || type == TYPE_ACK) + if (type == UAVTALK_TYPE_OBJ_REQ || type == UAVTALK_TYPE_ACK) { length = 0; } @@ -662,7 +674,7 @@ static int32_t sendSingleObject(UAVObjHandle obj, uint16_t instId, uint8_t type) } // Check length - if (length >= MAX_PAYLOAD_LENGTH) + if (length >= UAVTALK_MAX_PAYLOAD_LENGTH) { return -1; } @@ -670,26 +682,34 @@ static int32_t sendSingleObject(UAVObjHandle obj, uint16_t instId, uint8_t type) // Copy data (if any) if (length > 0) { - if ( UAVObjPack(obj, instId, &txBuffer[dataOffset]) < 0 ) + if ( UAVObjPack(obj, instId, &connection->txBuffer[dataOffset]) < 0 ) { return -1; } } // Store the packet length - txBuffer[2] = (uint8_t)((dataOffset+length) & 0xFF); - txBuffer[3] = (uint8_t)(((dataOffset+length) >> 8) & 0xFF); + connection->txBuffer[2] = (uint8_t)((dataOffset+length) & 0xFF); + connection->txBuffer[3] = (uint8_t)(((dataOffset+length) >> 8) & 0xFF); // Calculate checksum - txBuffer[dataOffset+length] = updateCRC(0, txBuffer, dataOffset+length); - - // Send buffer - if (outStream!=NULL) (*outStream)(txBuffer, dataOffset+length+CHECKSUM_LENGTH); + connection->txBuffer[dataOffset+length] = PIOS_CRC_updateCRC(0, connection->txBuffer, dataOffset+length); + + // Send buffer (partially if needed) + uint32_t sent=0; + while (sent < dataOffset+length+UAVTALK_CHECKSUM_LENGTH) { + uint32_t sending = dataOffset+length+UAVTALK_CHECKSUM_LENGTH - sent; + if ( sending > connection->txSize ) sending = connection->txSize; + if ( connection->outStream != NULL ) { + (*connection->outStream)(connection->txBuffer+sent, sending); + } + sent += sending; + } // Update stats - ++stats.txObjects; - stats.txBytes += dataOffset+length+CHECKSUM_LENGTH; - stats.txObjectBytes += length; + ++connection->stats.txObjects; + connection->stats.txBytes += dataOffset+length+UAVTALK_CHECKSUM_LENGTH; + connection->stats.txObjectBytes += length; // Done return 0; @@ -697,77 +717,42 @@ static int32_t sendSingleObject(UAVObjHandle obj, uint16_t instId, uint8_t type) /** * Send a NACK through the telemetry link. + * \param[in] connection UAVTalkConnection to be used * \param[in] objId Object ID to send a NACK for * \return 0 Success * \return -1 Failure */ -static int32_t sendNack(uint32_t objId) +static int32_t sendNack(UAVTalkConnectionData *connection, uint32_t objId) { int32_t dataOffset; - txBuffer[0] = SYNC_VAL; // sync byte - txBuffer[1] = TYPE_NACK; + connection->txBuffer[0] = UAVTALK_SYNC_VAL; // sync byte + connection->txBuffer[1] = UAVTALK_TYPE_NACK; // data length inserted here below - txBuffer[4] = (uint8_t)(objId & 0xFF); - txBuffer[5] = (uint8_t)((objId >> 8) & 0xFF); - txBuffer[6] = (uint8_t)((objId >> 16) & 0xFF); - txBuffer[7] = (uint8_t)((objId >> 24) & 0xFF); + connection->txBuffer[4] = (uint8_t)(objId & 0xFF); + connection->txBuffer[5] = (uint8_t)((objId >> 8) & 0xFF); + connection->txBuffer[6] = (uint8_t)((objId >> 16) & 0xFF); + connection->txBuffer[7] = (uint8_t)((objId >> 24) & 0xFF); dataOffset = 8; // Store the packet length - txBuffer[2] = (uint8_t)((dataOffset) & 0xFF); - txBuffer[3] = (uint8_t)(((dataOffset) >> 8) & 0xFF); + connection->txBuffer[2] = (uint8_t)((dataOffset) & 0xFF); + connection->txBuffer[3] = (uint8_t)(((dataOffset) >> 8) & 0xFF); // Calculate checksum - txBuffer[dataOffset] = updateCRC(0, txBuffer, dataOffset); + connection->txBuffer[dataOffset] = PIOS_CRC_updateCRC(0, connection->txBuffer, dataOffset); // Send buffer - if (outStream!=NULL) (*outStream)(txBuffer, dataOffset+CHECKSUM_LENGTH); + if (connection->outStream!=NULL) (*connection->outStream)(connection->txBuffer, dataOffset+UAVTALK_CHECKSUM_LENGTH); // Update stats - stats.txBytes += dataOffset+CHECKSUM_LENGTH; + connection->stats.txBytes += dataOffset+UAVTALK_CHECKSUM_LENGTH; // Done return 0; } - -/** - * Update the crc value with new data. - * - * Generated by pycrc v0.7.5, http://www.tty1.net/pycrc/ - * using the configuration: - * Width = 8 - * Poly = 0x07 - * XorIn = 0x00 - * ReflectIn = False - * XorOut = 0x00 - * ReflectOut = False - * Algorithm = table-driven - * - * \param crc The current crc value. - * \param data Pointer to a buffer of \a data_len bytes. - * \param length Number of bytes in the \a data buffer. - * \return The updated crc value. - */ -static uint8_t updateCRCbyte(uint8_t crc, const uint8_t data) -{ - return crc_table[crc ^ data]; -} -static uint8_t updateCRC(uint8_t crc, const uint8_t* data, int32_t length) -{ - // use registers for speed - register int32_t len = length; - register uint8_t crc8 = crc; - register const uint8_t *p = data; - - while (len--) - crc8 = crc_table[crc8 ^ *p++]; - - return crc8; -} - /** * @} * @} diff --git a/ground/openpilotgcs/packaging/packaging.pro b/ground/openpilotgcs/copydata.pro similarity index 70% rename from ground/openpilotgcs/packaging/packaging.pro rename to ground/openpilotgcs/copydata.pro index 5fa82fa70..a963e4673 100644 --- a/ground/openpilotgcs/packaging/packaging.pro +++ b/ground/openpilotgcs/copydata.pro @@ -1,7 +1,6 @@ -include(../openpilotgcs.pri) +include(openpilotgcs.pri) TEMPLATE = subdirs -SUBDIRS = winx86 # Copy Qt runtime libraries into the build directory (to run or package) equals(copydata, 1) { @@ -53,11 +52,21 @@ equals(copydata, 1) { data_copy.commands += $(COPY_FILE) $$targetPath(\"$$[QT_INSTALL_PLUGINS]/sqldrivers/$$dll\") $$targetPath(\"$$GCS_APP_PATH/sqldrivers/$$dll\") $$addNewline() } - # copy SDL (if available) - Simple DirectMedia Layer (www.libsdl.org) + # copy SDL - Simple DirectMedia Layer (www.libsdl.org) + # Check the wiki for SDL installation, it should be copied first + # (make sure that the Qt installation path below is correct) + # + # - For qt-sdk-win-opensource-2010.05.exe: + # xcopy /s /e \bin\SDL.dll C:\Qt\2010.05\mingw\bin\SDL.dll + # xcopy /s /e \include\SDL\* C:\Qt\2010.05\mingw\include\SDL + # xcopy /s /e \lib\* C:\Qt\2010.05\mingw\lib + # + # - For Qt_SDK_Win_offline_v1_1_1_en.exe: + # xcopy /s /e \bin\SDL.dll C:\QtSDK\Desktop\Qt\4.7.3\mingw\bin\SDL.dll + # xcopy /s /e \include\SDL\* C:\QtSDK\Desktop\Qt\4.7.3\mingw\include\SDL + # xcopy /s /e \lib\* C:\QtSDK\Desktop\Qt\4.7.3\mingw\lib SDL_DLL = SDL.dll - exists($$targetPath(\"$$[QT_INSTALL_BINS]/../../mingw/bin/$$SDL_DLL\")) { - data_copy.commands += $(COPY_FILE) $$targetPath(\"$$[QT_INSTALL_BINS]/../../mingw/bin/$$SDL_DLL\") $$targetPath(\"$$GCS_APP_PATH/$$SDL_DLL\") $$addNewline() - } + data_copy.commands += $(COPY_FILE) $$targetPath(\"$$[QT_INSTALL_BINS]/../../mingw/bin/$$SDL_DLL\") $$targetPath(\"$$GCS_APP_PATH/$$SDL_DLL\") $$addNewline() data_copy.target = FORCE QMAKE_EXTRA_TARGETS += data_copy diff --git a/ground/openpilotgcs/openpilotgcs.pri b/ground/openpilotgcs/openpilotgcs.pri index 94b986b0d..b9da7f671 100644 --- a/ground/openpilotgcs/openpilotgcs.pri +++ b/ground/openpilotgcs/openpilotgcs.pri @@ -19,6 +19,19 @@ defineReplace(addNewline) { return($$escape_expand(\\n\\t)) } +defineReplace(qtLibraryName) { + unset(LIBRARY_NAME) + LIBRARY_NAME = $$1 + CONFIG(debug, debug|release) { + !debug_and_release|build_pass { + mac:RET = $$member(LIBRARY_NAME, 0)_debug + else:win32:RET = $$member(LIBRARY_NAME, 0)d + } + } + isEmpty(RET):RET = $$LIBRARY_NAME + return($$RET) +} + # For use in custom compilers which just copy files win32:i_flag = i defineReplace(stripSrcDir) { @@ -62,7 +75,7 @@ isEmpty(GCS_BUILD_TREE) { GCS_APP_PATH = $$GCS_BUILD_TREE/bin macx { GCS_APP_TARGET = "OpenPilot GCS" - GCS_LIBRARY_PATH = $$GCS_APP_PATH/$${GCS_APP_TARGET}.app/Contents/PlugIns + GCS_LIBRARY_PATH = $$GCS_APP_PATH/$${GCS_APP_TARGET}.app/Contents/Plugins GCS_PLUGIN_PATH = $$GCS_LIBRARY_PATH GCS_LIBEXEC_PATH = $$GCS_APP_PATH/$${GCS_APP_TARGET}.app/Contents/Resources GCS_DATA_PATH = $$GCS_APP_PATH/$${GCS_APP_TARGET}.app/Contents/Resources diff --git a/ground/openpilotgcs/openpilotgcs.pro b/ground/openpilotgcs/openpilotgcs.pro index 5c2611a11..22a893f52 100644 --- a/ground/openpilotgcs/openpilotgcs.pro +++ b/ground/openpilotgcs/openpilotgcs.pro @@ -9,5 +9,7 @@ include(openpilotgcs.pri) TEMPLATE = subdirs CONFIG += ordered -SUBDIRS = src share packaging +SUBDIRS = src share copydata unix:!macx:!isEmpty(copydata):SUBDIRS += bin + +copydata.file = copydata.pro diff --git a/ground/openpilotgcs/packaging/winx86/make_header.cmd b/ground/openpilotgcs/packaging/winx86/make_header.cmd deleted file mode 100644 index 247b17af1..000000000 --- a/ground/openpilotgcs/packaging/winx86/make_header.cmd +++ /dev/null @@ -1,86 +0,0 @@ -@echo off -rem -rem make_header - a workaround to build NSIS version info header from -rem Makefile using different environments (Windows cmd or Unix-like sh) -rem still being more or less portable. -rem -rem This script tries to find any git command line utility on the system. -rem First, it looks at the predefined location of git.exe installed by -rem msysgit package available at http://code.google.com/p/msysgit/ -rem If not found, it searches for git executables in the system PATH. -rem If also not found, then it gives up and no commit info will be available. -rem -rem Expected parameters: -rem %1: repository source path -rem %2: header file full path and name -rem - -rem FIXME: we should have product version info somewhere else -set OUT_FILE=OpenPilotGCS-%%%%ad-%%%%h-install.exe -set PRODUCT_VERSION=0.0.0.0 -set FILE_VERSION=%%%%ad %%BRANCH%%:%%%%h -set BUILD_DESCRIPTION=Built using %%ORIGIN%% as origin, branch %%BRANCH%%, commit %%%%H, committed %%%%ci - -set REPO=%1 -set HEADER=%2 -if "%REPO%" == "" goto NoRepo -if "%HEADER%" == "" goto NoHeader -goto OK - -:NoRepo -:NoHeader -echo This script should be called from Makefile only -goto :eof - -:Ok -rem Looking for git command line utility at the predefined msysgit location -rem first, and in the PATH last. Also note that we use call command which is -rem required if we execute a .cmd or .bat file instead of .exe - -set GIT=%ProgramFiles%\Git\bin\git.exe -if exist "%GIT%" goto Found - -for %%G in (git.exe) do set GIT=%%~$PATH:G -if exist "%GIT%" goto Found - -for %%G in (git.cmd) do set GIT=%%~$PATH:G -if exist "%GIT%" goto Found - -for %%G in (git.bat) do set GIT=%%~$PATH:G -if exist "%GIT%" goto Found - -:NotFound -echo git not found, no version info available -goto :eof - -:Found -echo Using "%GIT%" to extract version info from "%REPO%"... - -rem Getting remote origin name -for /F "usebackq tokens=1-3" %%G in (`call "%GIT%" remote -v`) do ( - if "%%G" == "origin" if "%%I" == "(fetch)" set ORIGIN=%%H -) - -rem Getting branch name -for /F "usebackq tokens=1,2" %%G in (`call "%GIT%" branch --no-color`) do ( - if "%%G" == "*" set BRANCH=%%H -) - -rem Getting commit info -set OPTS=-1 --no-color --date=short -set OPTS=%OPTS% "--format=format: -set OPTS=%OPTS%;%%%%n -set OPTS=%OPTS%; AUTOGENERATED HEADER FILE%%%%n -set OPTS=%OPTS%;%%%%n -set OPTS=%OPTS%%%%%n -set OPTS=%OPTS%; Installer file name%%%%n -set OPTS=%OPTS%!define OUT_FILE \"%OUT_FILE%\"%%%%n -set OPTS=%OPTS%%%%%n -set OPTS=%OPTS%; Installer version info%%%%n -set OPTS=%OPTS%!define PRODUCT_VERSION \"%PRODUCT_VERSION%\"%%%%n -set OPTS=%OPTS%!define FILE_VERSION \"%FILE_VERSION%\"%%%%n -set OPTS=%OPTS%!define BUILD_DESCRIPTION \"%BUILD_DESCRIPTION%\"%%%%n" - -pushd "%REPO%" -call "%GIT%" log %OPTS% >%HEADER% -popd diff --git a/ground/openpilotgcs/packaging/winx86/make_installer.cmd b/ground/openpilotgcs/packaging/winx86/make_installer.cmd deleted file mode 100644 index 46c6567ac..000000000 --- a/ground/openpilotgcs/packaging/winx86/make_installer.cmd +++ /dev/null @@ -1,19 +0,0 @@ -@echo off -rem -rem NSIS installer script file for OpenPilot GCS -rem The OpenPilot Team, http://www.openpilot.org, Copyright (C) 2010-2011. -rem -rem This script requires Unicode NSIS 2.46 or higher: -rem http://www.scratchpaper.com/ -rem - -rem Set path to NSIS compiler -set NSIS=%ProgramFiles%/NSIS/Unicode -set NSISC=%NSIS%/makensis.exe - -rem Input script file (in the same directory as this batch file) -for %%D in (%0) do set NSI=%%~dD%%~pD\openpilotgcs.nsi - -rem Build installer -echo Generating Windows installer... -"%NSISC%" /V3 %NSI% diff --git a/ground/openpilotgcs/packaging/winx86/openpilotgcs.nsh b/ground/openpilotgcs/packaging/winx86/openpilotgcs.nsh deleted file mode 100644 index 222ed0d68..000000000 --- a/ground/openpilotgcs/packaging/winx86/openpilotgcs.nsh +++ /dev/null @@ -1,11 +0,0 @@ -# -# git not found, default values used instead. -# - -; Installer file name -!define OUT_FILE "OpenPilotGCS-unreleased-install.exe" - -; Installer version info -!define PRODUCT_VERSION "0.0.0.0" -!define FILE_VERSION "0.0.0.0" -!define BUILD_DESCRIPTION "Unreleased version." diff --git a/ground/openpilotgcs/packaging/winx86/winx86.pro b/ground/openpilotgcs/packaging/winx86/winx86.pro deleted file mode 100644 index f1364166a..000000000 --- a/ground/openpilotgcs/packaging/winx86/winx86.pro +++ /dev/null @@ -1,50 +0,0 @@ -include(../../openpilotgcs.pri) - -TEMPLATE = subdirs - -# Some Windows packaging magic (for release build only) -equals(copydata, 1):win32:CONFIG(release, debug|release) { - - # We need this Windows macro since building under Unix-like shell the top level - # targetPath macro will use forward slashes which don't work for such Windows - # commands like pushd, etc. But note that we still use targetPath for $(COPY_FILE) - # parameters because this command is different under native Windows and Unix-like - # build environments. - defineReplace(winTargetPath) { - return($$replace(1, /, \\)) - } - - # Some file locations - WINX86_PATH = packaging/winx86 - NSIS_HEADER = openpilotgcs.nsh - HEADER_MAKER = make_header.cmd - INSTALLER_MAKER = make_installer.cmd - - # copy defaults first (will be used if no git available) - git.commands += @echo Copying default version info... $$addNewline() - git.commands += $(COPY_FILE) - git.commands += $$targetPath($$GCS_SOURCE_TREE/$$WINX86_PATH/$$NSIS_HEADER) - git.commands += $$targetPath($$GCS_BUILD_TREE/$$WINX86_PATH/$$NSIS_HEADER) - git.commands += $$addNewline() - - # extract repository info if command line git is available - git.commands += $$winTargetPath($$GCS_SOURCE_TREE/$$WINX86_PATH/$$HEADER_MAKER) - git.commands += $$winTargetPath($$GCS_SOURCE_TREE) - git.commands += $$winTargetPath($$GCS_BUILD_TREE/$$WINX86_PATH/$$NSIS_HEADER) - git.commands += $$addNewline() - - git.target = git.dummy - QMAKE_EXTRA_TARGETS += git - force.depends += git - - # Redefine FORCE target to collect data every time - force.target = FORCE - QMAKE_EXTRA_TARGETS += force - - # Create installer build target - this WILL NOT run during build, run it by hand - message("Run \"make gcs_installer\" in $$GCS_BUILD_TREE/$$WINX86_PATH to build Windows installer (Unicode NSIS 2.46+ required)") - nsis.target = gcs_installer - nsis.depends = git - nsis.commands += @$$winTargetPath($$GCS_SOURCE_TREE/$$WINX86_PATH/$$INSTALLER_MAKER) - QMAKE_EXTRA_TARGETS += nsis -} diff --git a/ground/openpilotgcs/share/openpilotgcs/dials/default/flightmode-status.svg b/ground/openpilotgcs/share/openpilotgcs/dials/default/flightmode-status.svg index dca4d213a..80935d0c3 100644 --- a/ground/openpilotgcs/share/openpilotgcs/dials/default/flightmode-status.svg +++ b/ground/openpilotgcs/share/openpilotgcs/dials/default/flightmode-status.svg @@ -14,7 +14,7 @@ height="80.827866" id="svg10068" version="1.1" - inkscape:version="0.47 r22583" + inkscape:version="0.48.1 r9760" sodipodi:docname="flightmode-status.svg" inkscape:export-filename="H:\Documents\Hobbies\W433\My Gauges\vbat-001.png" inkscape:export-xdpi="103.61" @@ -949,6 +949,94 @@ fx="29.77438" fy="7.0922189" r="25.380436" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ground/openpilotgcs/share/openpilotgcs/dials/deluxe/lineardial-horizontal.svg b/ground/openpilotgcs/share/openpilotgcs/dials/deluxe/lineardial-horizontal.svg new file mode 100644 index 000000000..2f6f71b17 --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/dials/deluxe/lineardial-horizontal.svg @@ -0,0 +1,1329 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Edouard Lafargue + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ground/openpilotgcs/share/openpilotgcs/dials/deluxe/lineardial-vertical.svg b/ground/openpilotgcs/share/openpilotgcs/dials/deluxe/lineardial-vertical.svg new file mode 100644 index 000000000..010283c2c --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/dials/deluxe/lineardial-vertical.svg @@ -0,0 +1,929 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Edouard Lafargue + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ground/openpilotgcs/share/openpilotgcs/help/angleLimitsHelp.html b/ground/openpilotgcs/share/openpilotgcs/help/angleLimitsHelp.html new file mode 100644 index 000000000..c8a6fa682 --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/help/angleLimitsHelp.html @@ -0,0 +1 @@ +Here you will find help for Angle Limit fields diff --git a/ground/openpilotgcs/share/openpilotgcs/help/attitudeStabiHelp.html b/ground/openpilotgcs/share/openpilotgcs/help/attitudeStabiHelp.html new file mode 100644 index 000000000..410451fcf --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/help/attitudeStabiHelp.html @@ -0,0 +1 @@ +Here you will find help for tunning Attitude Stabilization diff --git a/ground/openpilotgcs/share/openpilotgcs/help/commandHelp.html b/ground/openpilotgcs/share/openpilotgcs/help/commandHelp.html new file mode 100644 index 000000000..76817e5e9 --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/help/commandHelp.html @@ -0,0 +1 @@ +Add explanation of what Get Current, Apply, and Save each do diff --git a/ground/openpilotgcs/share/openpilotgcs/help/rateStabiHelp.html b/ground/openpilotgcs/share/openpilotgcs/help/rateStabiHelp.html new file mode 100644 index 000000000..410451fcf --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/help/rateStabiHelp.html @@ -0,0 +1 @@ +Here you will find help for tunning Attitude Stabilization diff --git a/ground/openpilotgcs/share/openpilotgcs/help/updateRealTimeHelp.html b/ground/openpilotgcs/share/openpilotgcs/help/updateRealTimeHelp.html new file mode 100644 index 000000000..f7718b095 --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/help/updateRealTimeHelp.html @@ -0,0 +1 @@ +Here you will find help for what the Update in Real Time checkmark does diff --git a/ground/openpilotgcs/share/openpilotgcs/models/boards/CopterControl/CopterControl.3ds b/ground/openpilotgcs/share/openpilotgcs/models/boards/CopterControl/CopterControl.3ds new file mode 100644 index 000000000..c158dba99 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/models/boards/CopterControl/CopterControl.3ds differ diff --git a/ground/openpilotgcs/share/openpilotgcs/models/boards/CopterControl/TEXTURE.PNG b/ground/openpilotgcs/share/openpilotgcs/models/boards/CopterControl/TEXTURE.PNG new file mode 100644 index 000000000..6a8cf8344 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/models/boards/CopterControl/TEXTURE.PNG differ diff --git a/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/CC.PNG b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/CC.PNG new file mode 100644 index 000000000..467f34a97 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/CC.PNG differ diff --git a/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-QT_+.3DS b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-QT_+.3DS new file mode 100644 index 000000000..1879b07c6 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-QT_+.3DS differ diff --git a/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-QT_+.jpg b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-QT_+.jpg new file mode 100644 index 000000000..bb5d7a8de Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-QT_+.jpg differ diff --git a/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-QT_X.3DS b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-QT_X.3DS new file mode 100644 index 000000000..f26dacb45 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-QT_X.3DS differ diff --git a/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-QT_X.jpg b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-QT_X.jpg new file mode 100644 index 000000000..24bd15569 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-QT_X.jpg differ diff --git a/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-Q_+.3DS b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-Q_+.3DS new file mode 100644 index 000000000..21fbccf01 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-Q_+.3DS differ diff --git a/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-Q_+.jpg b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-Q_+.jpg new file mode 100644 index 000000000..bdc45dd07 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-Q_+.jpg differ diff --git a/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-Q_X.3DS b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-Q_X.3DS new file mode 100644 index 000000000..529e60fac Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-Q_X.3DS differ diff --git a/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-Q_X.jpg b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-Q_X.jpg new file mode 100644 index 000000000..8e1de3196 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/J14-Q_X.jpg differ diff --git a/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/TEXTURE.PNG b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/TEXTURE.PNG new file mode 100644 index 000000000..5d26bb120 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/models/multi/joes_cnc/TEXTURE.PNG differ diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg b/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg index a5daa9575..6313bf1df 100755 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg @@ -14,7 +14,7 @@ height="707.56323" id="svg2" version="1.1" - inkscape:version="0.47 r22583" + inkscape:version="0.48.1 " sodipodi:docname="pfd.svg" style="display:inline" inkscape:export-filename="H:\Documents\Hobbies\OpenPilot\SVN\artwork\PFD-2.png" @@ -1561,6 +1561,52 @@ inkscape:vp_y="0 : 1000 : 0" inkscape:vp_x="0 : 0.5 : 1" sodipodi:type="inkscape:persp3d" /> + + + + + + + - - - - - - - - - - - - - - 20 - 20 - - - - 10 - 10 - - - - 10 - 10 - - - - 20 - 20 - + transform="matrix(4.6362185,0,0,1.5267412,-1475.4746,-169.05952)" + id="g4280"> + + + + 10 + 10 + + + + + 20 + 20 + + + + + -10 + -10 + + + + + + + + + + + + + + + + + + + -20 + -20 + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2094,141 +2075,585 @@ id="tspan4328" sodipodi:role="line">GPS - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + inkscape:label="#g5089"> + id="angle-3"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + id="g7953"> + + + + + + + + + + + + + + + + + + + + inkscape:label="#path3779-1" + inkscape:connector-curvature="0" /> + inkscape:label="#path3779-7" + inkscape:connector-curvature="0" /> - - - - + inkscape:label="#g4577"> + + + style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3.06858087;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" + inkscape:connector-curvature="0" /> + d="m 280.28409,30.123177 5.7832,0 7.54688,11.08789 0,-11.08789 5.83789,0 0,20.042968 -5.83789,0 -7.50586,-11.005859 0,11.005859 -5.82422,0 z" + inkscape:connector-curvature="0" /> + id="path6986" + inkscape:connector-curvature="0" /> + d="m -217.0715,43.535286 5.89258,-0.369141 c 0.12759,0.957038 0.38736,1.686204 0.77929,2.1875 0.63801,0.811202 1.54947,1.216801 2.73438,1.216797 0.8841,4e-6 1.56542,-0.207353 2.04394,-0.62207 0.47851,-0.414709 0.71776,-0.895503 0.71778,-1.442383 -2e-5,-0.519525 -0.22788,-0.984368 -0.6836,-1.394531 -0.45574,-0.410149 -1.51303,-0.797518 -3.17187,-1.16211 -2.71616,-0.610668 -4.653,-1.421865 -5.81055,-2.433593 -1.16667,-1.011707 -1.75,-2.30142 -1.75,-3.869141 0,-1.029932 0.2985,-2.002913 0.89551,-2.918945 0.597,-0.915998 1.49479,-1.636049 2.69336,-2.160156 1.19856,-0.524069 2.84146,-0.786113 4.92871,-0.786133 2.56118,2e-5 4.51398,0.476257 5.8584,1.428711 1.34438,0.952492 2.14418,2.46779 2.39941,4.545898 l -5.83789,0.341797 c -0.15496,-0.902329 -0.48081,-1.558578 -0.97754,-1.96875 -0.49675,-0.41014 -1.18263,-0.615218 -2.05762,-0.615234 -0.72006,1.6e-5 -1.26237,0.152685 -1.62695,0.458007 -0.36459,0.305355 -0.54688,0.676774 -0.54687,1.114258 -1e-5,0.319025 0.15038,0.606134 0.45117,0.861328 0.29166,0.264337 0.98436,0.510431 2.07812,0.738282 2.70702,0.583346 4.64615,1.173514 5.81739,1.770507 1.1712,0.597017 2.02342,1.337576 2.55664,2.22168 0.53318,0.884123 0.79978,1.873055 0.7998,2.966797 -2e-5,1.285161 -0.35549,2.470056 -1.06641,3.554687 -0.71095,1.084638 -1.70444,1.907228 -2.98046,2.467774 -1.27606,0.560547 -2.88478,0.84082 -4.82618,0.84082 -3.40886,0 -5.76953,-0.656249 -7.08203,-1.96875 -1.3125,-1.312497 -2.05534,-2.980464 -2.22851,-5.003906 z" + inkscape:connector-curvature="0" /> + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" /> + d="m 778.62402,43.535286 5.89258,-0.369141 c 0.1276,0.957038 0.38736,1.686204 0.7793,2.1875 0.63801,0.811202 1.54947,1.216801 2.73437,1.216797 0.88411,4e-6 1.56542,-0.207353 2.04395,-0.62207 0.4785,-0.414709 0.71776,-0.895503 0.71777,-1.442383 -1e-5,-0.519525 -0.22788,-0.984368 -0.68359,-1.394531 -0.45574,-0.410149 -1.51303,-0.797518 -3.17188,-1.16211 -2.71615,-0.610668 -4.653,-1.421865 -5.81054,-2.433593 -1.16667,-1.011707 -1.75001,-2.30142 -1.75,-3.869141 -10e-6,-1.029932 0.2985,-2.002913 0.8955,-2.918945 0.59701,-0.915998 1.49479,-1.636049 2.69336,-2.160156 1.19856,-0.524069 2.84147,-0.786113 4.92871,-0.786133 2.56119,2e-5 4.51399,0.476257 5.8584,1.428711 1.34439,0.952492 2.14419,2.46779 2.39942,4.545898 l -5.83789,0.341797 c -0.15496,-0.902329 -0.48081,-1.558578 -0.97754,-1.96875 -0.49676,-0.41014 -1.18263,-0.615218 -2.05762,-0.615234 -0.72006,1.6e-5 -1.26238,0.152685 -1.62695,0.458007 -0.36459,0.305355 -0.54689,0.676774 -0.54688,1.114258 -1e-5,0.319025 0.15039,0.606134 0.45117,0.861328 0.29166,0.264337 0.98437,0.510431 2.07813,0.738282 2.70702,0.583346 4.64614,1.173514 5.81738,1.770507 1.17121,0.597017 2.02342,1.337576 2.55664,2.22168 0.53319,0.884123 0.79979,1.873055 0.79981,2.966797 -2e-5,1.285161 -0.35549,2.470056 -1.06641,3.554687 -0.71095,1.084638 -1.70444,1.907228 -2.98047,2.467774 -1.27605,0.560547 -2.88478,0.84082 -4.82617,0.84082 -3.40886,0 -5.76954,-0.656249 -7.08203,-1.96875 -1.3125,-1.312497 -2.05534,-2.980464 -2.22852,-5.003906 z" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + d="m 26.930511,30.123177 5.878907,0 2.11914,11.197265 3.089844,-11.197265 5.865234,0 3.103516,11.197265 2.119141,-11.197265 5.851562,0 -4.416015,20.042968 -6.070313,0 -3.513672,-12.61914 -3.5,12.61914 -6.070312,0 z" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + d="m 530.34277,30.123177 16.59766,0 0,4.279296 -10.39063,0 0,3.185547 9.63868,0 0,4.087891 -9.63868,0 0,3.951172 10.69141,0 0,4.539062 -16.89844,0 z" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3048" + inkscape:connector-curvature="0" /> + id="path3651" + inkscape:connector-curvature="0" /> + id="path3653" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3656" + inkscape:connector-curvature="0" /> + id="path3658" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3661" + inkscape:connector-curvature="0" /> + id="path3663" + inkscape:connector-curvature="0" /> + id="path3056" + inkscape:connector-curvature="0" /> + id="path3666" + inkscape:connector-curvature="0" /> + id="path3668" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3671" + inkscape:connector-curvature="0" /> + id="path3673" + inkscape:connector-curvature="0" /> + id="path3060" + inkscape:connector-curvature="0" /> + id="path3676" + inkscape:connector-curvature="0" /> + id="path3678" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3681" + inkscape:connector-curvature="0" /> + id="path3683" + inkscape:connector-curvature="0" /> + id="path3685" + inkscape:connector-curvature="0" /> + id="path3924" + inkscape:connector-curvature="0" /> + id="path3688" + inkscape:connector-curvature="0" /> + id="path3690" + inkscape:connector-curvature="0" /> + id="path3692" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3695" + inkscape:connector-curvature="0" /> + id="path3697" + inkscape:connector-curvature="0" /> + id="path3699" + inkscape:connector-curvature="0" /> + id="path3940" + inkscape:connector-curvature="0" /> + id="path3702" + inkscape:connector-curvature="0" /> + id="path3704" + inkscape:connector-curvature="0" /> + id="path3706" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3709" + inkscape:connector-curvature="0" /> + id="path3711" + inkscape:connector-curvature="0" /> + id="path3713" + inkscape:connector-curvature="0" /> + id="path3956" + inkscape:connector-curvature="0" /> + id="path3716" + inkscape:connector-curvature="0" /> + id="path3718" + inkscape:connector-curvature="0" /> + id="path3720" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3723" + inkscape:connector-curvature="0" /> + id="path3725" + inkscape:connector-curvature="0" /> + id="path3727" + inkscape:connector-curvature="0" /> + id="path3972" + inkscape:connector-curvature="0" /> + id="path3730" + inkscape:connector-curvature="0" /> + id="path3732" + inkscape:connector-curvature="0" /> + id="path3734" + inkscape:connector-curvature="0" /> + id="path4052" + inkscape:connector-curvature="0" /> + id="path3737" + inkscape:connector-curvature="0" /> + id="path3739" + inkscape:connector-curvature="0" /> + id="path3741" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3744" + inkscape:connector-curvature="0" /> + id="path3746" + inkscape:connector-curvature="0" /> + id="path3748" + inkscape:connector-curvature="0" /> + id="path4068" + inkscape:connector-curvature="0" /> + id="path3751" + inkscape:connector-curvature="0" /> + id="path3753" + inkscape:connector-curvature="0" /> + id="path3755" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3758" + inkscape:connector-curvature="0" /> + id="path3760" + inkscape:connector-curvature="0" /> + id="path3762" + inkscape:connector-curvature="0" /> + id="path4084" + inkscape:connector-curvature="0" /> + id="path3765" + inkscape:connector-curvature="0" /> + id="path3767" + inkscape:connector-curvature="0" /> + id="path3769" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3772" + inkscape:connector-curvature="0" /> + id="path3774" + inkscape:connector-curvature="0" /> + id="path3776" + inkscape:connector-curvature="0" /> + id="path4100" + inkscape:connector-curvature="0" /> + id="path3780" + inkscape:connector-curvature="0" /> + id="path3782" + inkscape:connector-curvature="0" /> + id="path3784" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3787" + inkscape:connector-curvature="0" /> + id="path3789" + inkscape:connector-curvature="0" /> + id="path3791" + inkscape:connector-curvature="0" /> + id="path4116" + inkscape:connector-curvature="0" /> + id="path3794" + inkscape:connector-curvature="0" /> + id="path3796" + inkscape:connector-curvature="0" /> + id="path3798" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3801" + inkscape:connector-curvature="0" /> + id="path3803" + inkscape:connector-curvature="0" /> + id="path3805" + inkscape:connector-curvature="0" /> + id="path4228" + inkscape:connector-curvature="0" /> + id="path3809" + inkscape:connector-curvature="0" /> + id="path3811" + inkscape:connector-curvature="0" /> + id="path3813" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3816" + inkscape:connector-curvature="0" /> + id="path3818" + inkscape:connector-curvature="0" /> + id="path3820" + inkscape:connector-curvature="0" /> + id="path4244" + inkscape:connector-curvature="0" /> + id="path3823" + inkscape:connector-curvature="0" /> + id="path3825" + inkscape:connector-curvature="0" /> + id="path3827" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3830" + inkscape:connector-curvature="0" /> + id="path3832" + inkscape:connector-curvature="0" /> + id="path3834" + inkscape:connector-curvature="0" /> + id="path4260" + inkscape:connector-curvature="0" /> + id="path3837" + inkscape:connector-curvature="0" /> + id="path3839" + inkscape:connector-curvature="0" /> + id="path3841" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3844" + inkscape:connector-curvature="0" /> + id="path3846" + inkscape:connector-curvature="0" /> + id="path3848" + inkscape:connector-curvature="0" /> + id="path3306" + inkscape:connector-curvature="0" /> + id="path3851" + inkscape:connector-curvature="0" /> + id="path3853" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3856" + inkscape:connector-curvature="0" /> + id="path3858" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" + inkscape:connector-curvature="0" /> + id="path4116-9" + inkscape:connector-curvature="0" /> + id="path3794-8" + inkscape:connector-curvature="0" /> + id="path3796-8" + inkscape:connector-curvature="0" /> + id="path3798-2" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3801-1" + inkscape:connector-curvature="0" /> + id="path3803-7" + inkscape:connector-curvature="0" /> + id="path3805-1" + inkscape:connector-curvature="0" /> + id="path4228-5" + inkscape:connector-curvature="0" /> + id="path3809-7" + inkscape:connector-curvature="0" /> + id="path3811-6" + inkscape:connector-curvature="0" /> + id="path3813-1" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3816-2" + inkscape:connector-curvature="0" /> + id="path3818-2" + inkscape:connector-curvature="0" /> + id="path3820-1" + inkscape:connector-curvature="0" /> + id="path4244-8" + inkscape:connector-curvature="0" /> + id="path3823-7" + inkscape:connector-curvature="0" /> + id="path3825-6" + inkscape:connector-curvature="0" /> + id="path3827-1" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3830-7" + inkscape:connector-curvature="0" /> + id="path3832-9" + inkscape:connector-curvature="0" /> + id="path3834-5" + inkscape:connector-curvature="0" /> + id="path4260-3" + inkscape:connector-curvature="0" /> + id="path3837-2" + inkscape:connector-curvature="0" /> + id="path3839-3" + inkscape:connector-curvature="0" /> + id="path3841-3" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3844-3" + inkscape:connector-curvature="0" /> + id="path3846-8" + inkscape:connector-curvature="0" /> + id="path3848-7" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3681-1" + inkscape:connector-curvature="0" /> + id="path3683-9" + inkscape:connector-curvature="0" /> + id="path3685-8" + inkscape:connector-curvature="0" /> + id="path3924-5" + inkscape:connector-curvature="0" /> + id="path3688-2" + inkscape:connector-curvature="0" /> + id="path3690-8" + inkscape:connector-curvature="0" /> + id="path3692-6" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3695-8" + inkscape:connector-curvature="0" /> + id="path3697-6" + inkscape:connector-curvature="0" /> + id="path3699-5" + inkscape:connector-curvature="0" /> + id="path3940-9" + inkscape:connector-curvature="0" /> + id="path3702-0" + inkscape:connector-curvature="0" /> + id="path3704-6" + inkscape:connector-curvature="0" /> + id="path3706-1" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3709-3" + inkscape:connector-curvature="0" /> + id="path3711-4" + inkscape:connector-curvature="0" /> + id="path3713-4" + inkscape:connector-curvature="0" /> + id="path3956-0" + inkscape:connector-curvature="0" /> + id="path3716-6" + inkscape:connector-curvature="0" /> + id="path3718-1" + inkscape:connector-curvature="0" /> + id="path3720-8" + inkscape:connector-curvature="0" /> + style="fill:#ffffff;fill-opacity:1;stroke:#fff8f8;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path3723-3" + inkscape:connector-curvature="0" /> + id="path3725-7" + inkscape:connector-curvature="0" /> + id="path3727-8" + inkscape:connector-curvature="0" /> + id="path3972-2" + inkscape:connector-curvature="0" /> + id="path3730-1" + inkscape:connector-curvature="0" /> + id="path3732-3" + inkscape:connector-curvature="0" /> + id="path3734-5" + inkscape:connector-curvature="0" /> @@ -3570,7 +4191,8 @@ inkscape:groupmode="layer" id="layer6" inkscape:label="Bottom area" - style="display:inline"> + style="display:none" + sodipodi:insensitive="true"> + id="path10183" + inkscape:connector-curvature="0" /> + id="path10185" + inkscape:connector-curvature="0" /> @@ -3630,19 +4254,22 @@ id="gcstelemetry-Connected" d="m -109.55949,412.40842 0,9.28125 -31.40625,0 0,4.90625 0,0.0937 0,4.90625 31.40625,0 0,9.28125 14.250003,-14.25 -14.250003,-14.21875 z" style="fill:#1c870b;fill-opacity:1;stroke:#113b05;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - inkscape:label="#path7548" /> + inkscape:label="#path7548" + inkscape:connector-curvature="0" /> + sodipodi:nodetypes="ccccccccccccccccc" + inkscape:connector-curvature="0" /> + sodipodi:nodetypes="cccccccccc" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#1c5313;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#1c5313;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + inkscape:connector-curvature="0" /> + id="path5044" + inkscape:connector-curvature="0" /> + id="path5046" + inkscape:connector-curvature="0" /> + id="path4035" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4039" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4043" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4061" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4065" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4071" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4075" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4079" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4085" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4089" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4095" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4099" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4103" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4109" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4113" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path4119" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5650" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5654" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5658" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5662" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5666" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5670" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5674" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5678" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5682" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5686" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5690" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5694" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5698" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5702" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:2.10024118;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + id="path5706" + inkscape:connector-curvature="0" /> + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> @@ -4020,6 +4713,7 @@ style="fill:#453e3e;fill-opacity:1;stroke:#000000;stroke-width:4.08031273;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" d="m -115.54603,-47.690059 c -2.50791,0 -4.54785,1.99743 -4.54785,4.50534 l 0,807.009359 c 0,2.5079 2.03994,4.54785 4.54785,4.54785 l 807.00936,0 c 2.5079,0 4.50534,-2.03995 4.50534,-4.54785 l 0,-807.009359 c 0,-2.50791 -1.99744,-4.50534 -4.50534,-4.50534 l -807.00936,0 z M 289.34,11.395534 c 150.15374,0 271.88009,59.618647 272.02085,133.162706 l 0.21252,48.57516 -0.38253,374.99409 C 556.30557,639.62843 436.47945,673.69951 289.34,673.69951 c -147.13944,0 -266.965544,-34.07108 -271.850832,-105.57202 l -0.212516,0 0,-374.99409 0.0425,-48.58122 C 17.459912,71.008115 139.18627,11.395534 289.34,11.395534 z" id="rect2816" - sodipodi:nodetypes="cccccccccccccsccccc" /> + sodipodi:nodetypes="cccccccccccccsccccc" + inkscape:connector-curvature="0" /> diff --git a/ground/openpilotgcs/share/openpilotgcs/sounds/Complete sound set.txt b/ground/openpilotgcs/share/openpilotgcs/sounds/Complete sound set.txt index 14bea3094..e539e6d24 100644 --- a/ground/openpilotgcs/share/openpilotgcs/sounds/Complete sound set.txt +++ b/ground/openpilotgcs/share/openpilotgcs/sounds/Complete sound set.txt @@ -21,6 +21,7 @@ alert altitude amps aquired +armed autonomous flight battery camera @@ -32,8 +33,10 @@ complete connected connection control +coptercontrol critical disabled +disarmed disconnected feet figure eight @@ -58,11 +61,13 @@ lost low altitude low battery low gps quality +magic manual flight maxium meters minimum mode +moved MPH navigation OpenPilot @@ -122,8 +127,4 @@ hundread thousand -Upto: OpenPilot -critical -battery -point diff --git a/ground/openpilotgcs/share/openpilotgcs/sounds/default/armed.wav b/ground/openpilotgcs/share/openpilotgcs/sounds/default/armed.wav new file mode 100644 index 000000000..22678cf67 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/sounds/default/armed.wav differ diff --git a/ground/openpilotgcs/share/openpilotgcs/sounds/default/coptercontrol.wav b/ground/openpilotgcs/share/openpilotgcs/sounds/default/coptercontrol.wav new file mode 100644 index 000000000..f41ce70b2 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/sounds/default/coptercontrol.wav differ diff --git a/ground/openpilotgcs/share/openpilotgcs/sounds/default/critical.wav b/ground/openpilotgcs/share/openpilotgcs/sounds/default/critical.wav new file mode 100644 index 000000000..3f364aae2 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/sounds/default/critical.wav differ diff --git a/ground/openpilotgcs/share/openpilotgcs/sounds/default/disarmed.wav b/ground/openpilotgcs/share/openpilotgcs/sounds/default/disarmed.wav new file mode 100644 index 000000000..d1c3e03d6 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/sounds/default/disarmed.wav differ diff --git a/ground/openpilotgcs/share/openpilotgcs/sounds/default/magic.wav b/ground/openpilotgcs/share/openpilotgcs/sounds/default/magic.wav new file mode 100644 index 000000000..15bd23b5e Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/sounds/default/magic.wav differ diff --git a/ground/openpilotgcs/share/openpilotgcs/sounds/default/moved.wav b/ground/openpilotgcs/share/openpilotgcs/sounds/default/moved.wav new file mode 100644 index 000000000..1038fc295 Binary files /dev/null and b/ground/openpilotgcs/share/openpilotgcs/sounds/default/moved.wav differ diff --git a/ground/openpilotgcs/src/app/app.pro b/ground/openpilotgcs/src/app/app.pro index 4170c0c13..c644f7c97 100644 --- a/ground/openpilotgcs/src/app/app.pro +++ b/ground/openpilotgcs/src/app/app.pro @@ -4,21 +4,22 @@ include(../shared/qtsingleapplication/qtsingleapplication.pri) TEMPLATE = app TARGET = $$GCS_APP_TARGET DESTDIR = $$GCS_APP_PATH +QT += xml SOURCES += main.cpp include(../rpath.pri) +include(../libs/utils/utils.pri) + +LIBS *= -l$$qtLibraryName(ExtensionSystem) -l$$qtLibraryName(Aggregation) win32 { - CONFIG(debug, debug|release):LIBS *= -lExtensionSystemd -lAggregationd -lQExtSerialPortd - else:LIBS *= -lExtensionSystem -lAggregation -lQExtSerialPort - +# CONFIG(debug, debug|release):LIBS *= -lExtensionSystemd -lAggregationd -lQExtSerialPortd +# else:LIBS *= -lExtensionSystem -lAggregation -lQExtSerialPort RC_FILE = openpilotgcs.rc target.path = /bin INSTALLS += target } else:macx { - CONFIG(debug, debug|release):LIBS *= -lExtensionSystem_debug -lAggregation_debug - else:LIBS *= -lExtensionSystem -lAggregation LIBS += -framework CoreFoundation ICON = openpilotgcs.icns QMAKE_INFO_PLIST = Info.plist @@ -26,8 +27,6 @@ win32 { FILETYPES.path = Contents/Resources QMAKE_BUNDLE_DATA += FILETYPES } else { - LIBS *= -lExtensionSystem -lAggregation - target.path = /bin INSTALLS += target } diff --git a/ground/openpilotgcs/src/app/main.cpp b/ground/openpilotgcs/src/app/main.cpp index 55f7d5312..62d8876a4 100644 --- a/ground/openpilotgcs/src/app/main.cpp +++ b/ground/openpilotgcs/src/app/main.cpp @@ -27,6 +27,7 @@ */ #include "qtsingleapplication.h" +#include "utils/xmlconfig.h" #include #include @@ -193,7 +194,7 @@ static inline QStringList getPluginPaths() // 2) "PlugIns" (OS X) pluginPath = rootDirPath; pluginPath += QLatin1Char('/'); - pluginPath += QLatin1String("PlugIns"); + pluginPath += QLatin1String("Plugins"); rc.push_back(pluginPath); return rc; } @@ -243,10 +244,10 @@ int main(int argc, char **argv) QString locale = QLocale::system().name(); // Must be done before any QSettings class is created - QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope, + QSettings::setPath(XmlConfig::XmlSettingsFormat, QSettings::SystemScope, QCoreApplication::applicationDirPath()+QLatin1String(SHARE_PATH)); // keep this in sync with the MainWindow ctor in coreplugin/mainwindow.cpp - QSettings settings(QSettings::IniFormat, QSettings::UserScope, + QSettings settings(XmlConfig::XmlSettingsFormat, QSettings::UserScope, QLatin1String("OpenPilot"), QLatin1String("OpenPilotGCS")); overrideSettings(settings, argc, argv); diff --git a/ground/openpilotgcs/src/experimental/USB_UPLOAD_TOOL/main.cpp b/ground/openpilotgcs/src/experimental/USB_UPLOAD_TOOL/main.cpp index e846cbea6..c9c687986 100644 --- a/ground/openpilotgcs/src/experimental/USB_UPLOAD_TOOL/main.cpp +++ b/ground/openpilotgcs/src/experimental/USB_UPLOAD_TOOL/main.cpp @@ -324,13 +324,5 @@ int main(int argc, char *argv[]) return 0; } -// OP_DFU dfu(true); -// //dfu.findDevices(); -// dfu.enterDFU(1); -// dfu.UploadFirmware("c:/ahrs.bin",true,1); -// // dfu.UploadDescription("josemanuel"); -// // QString str=dfu.DownloadDescription(12); - // dfu.JumpToApp(); - // qDebug()<<"Description="< using namespace glc; diff --git a/ground/openpilotgcs/src/libs/libqxt/libqxt.pri b/ground/openpilotgcs/src/libs/libqxt/libqxt.pri index d2001f6fe..1886943d5 100644 --- a/ground/openpilotgcs/src/libs/libqxt/libqxt.pri +++ b/ground/openpilotgcs/src/libs/libqxt/libqxt.pri @@ -1,4 +1,4 @@ -LIBS += -l$$qtLibraryTarget(QxtCore) +LIBS *= -l$$qtLibraryName(QxtCore) INCLUDEPATH += \ $$GCS_SOURCE_TREE/src/libs/libqxt/src/core diff --git a/ground/openpilotgcs/src/libs/opmapcontrol/opmapcontrol.pri b/ground/openpilotgcs/src/libs/opmapcontrol/opmapcontrol.pri index 9c0188c30..f6ea6004b 100644 --- a/ground/openpilotgcs/src/libs/opmapcontrol/opmapcontrol.pri +++ b/ground/openpilotgcs/src/libs/opmapcontrol/opmapcontrol.pri @@ -1 +1 @@ -LIBS *= -l$$qtLibraryTarget(opmapwidget) +LIBS *= -l$$qtLibraryName(opmapwidget) diff --git a/ground/openpilotgcs/src/libs/qextserialport/qextserialport.pri b/ground/openpilotgcs/src/libs/qextserialport/qextserialport.pri index 1f89982c5..286b70b87 100644 --- a/ground/openpilotgcs/src/libs/qextserialport/qextserialport.pri +++ b/ground/openpilotgcs/src/libs/qextserialport/qextserialport.pri @@ -1,2 +1,2 @@ -LIBS += -l$$qtLibraryTarget(QExtSerialPort) +LIBS *= -l$$qtLibraryName(QExtSerialPort) diff --git a/ground/openpilotgcs/src/libs/qextserialport/src/qextserialport.h b/ground/openpilotgcs/src/libs/qextserialport/src/qextserialport.h index 5e247529d..8d3ac29a6 100644 --- a/ground/openpilotgcs/src/libs/qextserialport/src/qextserialport.h +++ b/ground/openpilotgcs/src/libs/qextserialport/src/qextserialport.h @@ -135,10 +135,11 @@ struct PortSettings #include #include #elif (defined Q_OS_WIN) +#include #include #include #include -#include +#include "utils/qwineventnotifier_p.h" #endif /*! @@ -308,6 +309,9 @@ class QEXTSERIALPORT_EXPORT QextSerialPort: public QIODevice #ifdef Q_OS_WIN private slots: void onWinEvent(HANDLE h); + void triggerTxEmpty(); +private: + QTimer fakeTxEmpty; #endif private: diff --git a/ground/openpilotgcs/src/libs/qextserialport/src/win_qextserialport.cpp b/ground/openpilotgcs/src/libs/qextserialport/src/win_qextserialport.cpp index 350dc7533..1fe0ff3ba 100644 --- a/ground/openpilotgcs/src/libs/qextserialport/src/win_qextserialport.cpp +++ b/ground/openpilotgcs/src/libs/qextserialport/src/win_qextserialport.cpp @@ -53,7 +53,6 @@ bool QextSerialPort::open(OpenMode mode) { DWORD dwFlagsAndAttributes = 0; if (queryMode() == QextSerialPort::EventDriven) dwFlagsAndAttributes += FILE_FLAG_OVERLAPPED; - QMutexLocker lock(mutex); if (mode == QIODevice::NotOpen) return isOpen(); @@ -95,7 +94,10 @@ bool QextSerialPort::open(OpenMode mode) { } winEventNotifier = new QWinEventNotifier(overlap.hEvent, this); connect(winEventNotifier, SIGNAL(activated(HANDLE)), this, SLOT(onWinEvent(HANDLE))); + connect(&fakeTxEmpty,SIGNAL(timeout()),this,SLOT(triggerTxEmpty())); + fakeTxEmpty.start(10000); WaitCommEvent(Win_Handle, &eventMask, &overlap); + } } } else { @@ -111,8 +113,10 @@ is not currently open. void QextSerialPort::close() { QMutexLocker lock(mutex); + fakeTxEmpty.stop(); + disconnect(&fakeTxEmpty,SIGNAL(timeout()),this,SLOT(triggerTxEmpty())); if (isOpen()) { - flush(); + flush(); QIODevice::close(); // mark ourselves as closed CancelIo(Win_Handle); if (CloseHandle(Win_Handle)) @@ -886,4 +890,38 @@ void QextSerialPort::setTimeout(long millisec) { if (queryMode() != QextSerialPort::EventDriven) SetCommTimeouts(Win_Handle, &Win_CommTimeouts); } +/*! +emulates the EV_TXEMPTY system event not present on some BT interfaces +*/ +void QextSerialPort::triggerTxEmpty() +{ + if (bytesToWrite()>500) + { + QMutexLocker lock(mutex); + qint64 totalBytesWritten = 0; + QList overlapsToDelete; + foreach(OVERLAPPED* o, pendingWrites) { + DWORD numBytes = 0; + if (GetOverlappedResult(Win_Handle, o, & numBytes, false)) { + overlapsToDelete.append(o); + totalBytesWritten += numBytes; + } else if( GetLastError() != ERROR_IO_INCOMPLETE ) { + overlapsToDelete.append(o); + qWarning() << "CommEvent overlapped write error:" << GetLastError(); + } + } + if (totalBytesWritten > 0) { + QWriteLocker writelocker(bytesToWriteLock); + _bytesToWrite = 0; + //qDebug()<<"zeroed bytesToWrite"; + } + //qDebug()<<"overlapsToDelete"<hEvent); + delete toDelete; + } + } + +} diff --git a/ground/openpilotgcs/src/libs/qscispinbox/qscispinbox.pri b/ground/openpilotgcs/src/libs/qscispinbox/qscispinbox.pri index 3d63b6605..85cd57253 100644 --- a/ground/openpilotgcs/src/libs/qscispinbox/qscispinbox.pri +++ b/ground/openpilotgcs/src/libs/qscispinbox/qscispinbox.pri @@ -1 +1 @@ -LIBS *= -l$$qtLibraryTarget(QScienceSpinBox) +LIBS *= -l$$qtLibraryName(QScienceSpinBox) diff --git a/ground/openpilotgcs/src/libs/qtconcurrent/qtconcurrent.pri b/ground/openpilotgcs/src/libs/qtconcurrent/qtconcurrent.pri index 57929a4cf..141de8ee8 100644 --- a/ground/openpilotgcs/src/libs/qtconcurrent/qtconcurrent.pri +++ b/ground/openpilotgcs/src/libs/qtconcurrent/qtconcurrent.pri @@ -1 +1 @@ -LIBS *= -l$$qtLibraryTarget(QtConcurrent) +LIBS *= -l$$qtLibraryName(QtConcurrent) diff --git a/ground/openpilotgcs/src/libs/qwt/qwt.pri b/ground/openpilotgcs/src/libs/qwt/qwt.pri index 4241b6278..7d57a8ce7 100644 --- a/ground/openpilotgcs/src/libs/qwt/qwt.pri +++ b/ground/openpilotgcs/src/libs/qwt/qwt.pri @@ -1,2 +1,2 @@ -LIBS += -l$$qtLibraryTarget(Qwt) +LIBS *= -l$$qtLibraryName(Qwt) diff --git a/ground/openpilotgcs/src/libs/sdlgamepad/sdlgamepad.pri b/ground/openpilotgcs/src/libs/sdlgamepad/sdlgamepad.pri index 01fd85523..a5d13203c 100644 --- a/ground/openpilotgcs/src/libs/sdlgamepad/sdlgamepad.pri +++ b/ground/openpilotgcs/src/libs/sdlgamepad/sdlgamepad.pri @@ -1 +1 @@ -LIBS += -l$$qtLibraryTarget(sdlgamepad) +LIBS *= -l$$qtLibraryName(sdlgamepad) diff --git a/ground/openpilotgcs/src/libs/utils/consoleprocess_win.cpp b/ground/openpilotgcs/src/libs/utils/consoleprocess_win.cpp index f58007c5c..15eec8361 100644 --- a/ground/openpilotgcs/src/libs/utils/consoleprocess_win.cpp +++ b/ground/openpilotgcs/src/libs/utils/consoleprocess_win.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include "qwineventnotifier_p.h" #include diff --git a/ground/openpilotgcs/src/libs/utils/mylistwidget.cpp b/ground/openpilotgcs/src/libs/utils/mylistwidget.cpp new file mode 100644 index 000000000..f5fbfb639 --- /dev/null +++ b/ground/openpilotgcs/src/libs/utils/mylistwidget.cpp @@ -0,0 +1,38 @@ +/** + ****************************************************************************** + * + * @file mylistwidget.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. + * @brief + * @see The GNU Public License (GPL) Version 3 + * @defgroup + * @{ + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "mylistwidget.h" + +QStyleOptionViewItem MyListWidget::viewOptions() const +{ + QStyleOptionViewItem option = QListWidget::viewOptions(); + if (m_iconAbove) { + option.decorationPosition = QStyleOptionViewItem::Top; + option.displayAlignment = Qt::AlignCenter; + } + return option; +} diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetfactory.h b/ground/openpilotgcs/src/libs/utils/mylistwidget.h similarity index 54% rename from ground/openpilotgcs/src/plugins/importexport/importexportgadgetfactory.h rename to ground/openpilotgcs/src/libs/utils/mylistwidget.h index ac1b56494..40059927e 100644 --- a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetfactory.h +++ b/ground/openpilotgcs/src/libs/utils/mylistwidget.h @@ -1,12 +1,14 @@ /** ****************************************************************************** - * @file + * + * @file mylistwidget.h * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. + * @brief * @see The GNU Public License (GPL) Version 3 - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup importexportplugin + * @defgroup * @{ + * *****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify @@ -24,38 +26,28 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef IMPORTEXPORTGADGETFACTORY_H_ -#define IMPORTEXPORTGADGETFACTORY_H_ +#ifndef MYLISTWIDGET_H +#define MYLISTWIDGET_H -#include -#include "importexportgadgetconfiguration.h" +#include "utils_global.h" -namespace Core -{ -class IUAVGadget; -class IUAVGadgetFactory; -} +#include -using namespace Core; - -class IMPORTEXPORT_EXPORT ImportExportGadgetFactory : public IUAVGadgetFactory +/* + * MyListWidget is a plain QListWidget but with the added option + * to place the icon above the label in ListMode. This is achieved + * the easiest by subclassing QListWidget and overriding viewOptions(). + */ +class QTCREATOR_UTILS_EXPORT MyListWidget : public QListWidget { Q_OBJECT public: - ImportExportGadgetFactory(QObject *parent = 0); - ~ImportExportGadgetFactory(); - ImportExportGadgetConfiguration *getLastConfig(){ return lastConfig;} - - Core::IUAVGadget *createGadget(QWidget *parent); - IUAVGadgetConfiguration *createConfiguration(QSettings *qSettings, UAVConfigInfo *configInfo); - IOptionsPage *createOptionsPage(IUAVGadgetConfiguration *config); - + MyListWidget(QWidget *parent) : QListWidget(parent), m_iconAbove(false) { } + void setIconAbove(bool iconAbove) { m_iconAbove = iconAbove; } +protected: + QStyleOptionViewItem viewOptions() const; private: - ImportExportGadgetConfiguration *lastConfig; + bool m_iconAbove; }; -#endif // IMPORTEXPORTGADGETFACTORY_H_ -/** - * @} - * @} - */ +#endif // MYLISTWIDGET_H diff --git a/ground/openpilotgcs/src/libs/utils/mytabbedstackwidget.cpp b/ground/openpilotgcs/src/libs/utils/mytabbedstackwidget.cpp new file mode 100644 index 000000000..faf2c911e --- /dev/null +++ b/ground/openpilotgcs/src/libs/utils/mytabbedstackwidget.cpp @@ -0,0 +1,109 @@ +/** + ****************************************************************************** + * + * @file mytabbedstackwidget.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. + * @brief + * @see The GNU Public License (GPL) Version 3 + * @defgroup + * @{ + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "mytabbedstackwidget.h" +#include +#include +#include +#include + +MyTabbedStackWidget::MyTabbedStackWidget(QWidget *parent, bool isVertical, bool iconAbove) + : QWidget(parent), + m_vertical(isVertical), + m_iconAbove(iconAbove) +{ + m_listWidget = new MyListWidget(this); + m_listWidget->setIconAbove(m_iconAbove); + m_stackWidget = new QStackedWidget(); + m_stackWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + QBoxLayout *toplevelLayout; + if (m_vertical) { + toplevelLayout = new QHBoxLayout; + toplevelLayout->addWidget(m_listWidget); + toplevelLayout->addWidget(m_stackWidget); + m_listWidget->setFlow(QListView::TopToBottom); + m_listWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + } else { + toplevelLayout = new QVBoxLayout; + toplevelLayout->addWidget(m_stackWidget); + toplevelLayout->addWidget(m_listWidget); + m_listWidget->setFlow(QListView::LeftToRight); + m_listWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + } + if (m_iconAbove && m_vertical) + m_listWidget->setFixedWidth(90); // this should be computed instead + + toplevelLayout->setSpacing(0); + toplevelLayout->setContentsMargins(0, 0, 0, 0); + m_listWidget->setSpacing(0); + m_listWidget->setContentsMargins(0, 0, 0, 0); + m_stackWidget->setContentsMargins(0, 0, 0, 0); + setLayout(toplevelLayout); + + connect(m_listWidget, SIGNAL(currentRowChanged(int)), this, SLOT(showWidget(int))); +} + +void MyTabbedStackWidget::insertTab(const int index, QWidget *tab, const QIcon &icon, const QString &label) +{ + tab->setContentsMargins(0, 0, 0, 0); + m_stackWidget->insertWidget(index, tab); + QListWidgetItem *item = new QListWidgetItem(icon, label); + item->setToolTip(label); + m_listWidget->insertItem(index, item); +} + +void MyTabbedStackWidget::removeTab(int index) +{ + m_stackWidget->removeWidget(m_stackWidget->widget(index)); + QListWidgetItem *item = m_listWidget->item(index); + m_listWidget->removeItemWidget(item); + delete item; +} + +int MyTabbedStackWidget::currentIndex() const +{ + return m_listWidget->currentRow(); +} + +void MyTabbedStackWidget::setCurrentIndex(int index) +{ + m_listWidget->setCurrentRow(index); +} + +void MyTabbedStackWidget::showWidget(int index) +{ + emit currentAboutToShow(index); + m_stackWidget->setCurrentIndex(index); + emit currentChanged(index); +} + +void MyTabbedStackWidget::insertCornerWidget(int index, QWidget *widget) +{ + widget->hide(); +} + diff --git a/ground/openpilotgcs/src/libs/utils/mytabbedstackwidget.h b/ground/openpilotgcs/src/libs/utils/mytabbedstackwidget.h new file mode 100644 index 000000000..428ed8646 --- /dev/null +++ b/ground/openpilotgcs/src/libs/utils/mytabbedstackwidget.h @@ -0,0 +1,74 @@ +/** + ****************************************************************************** + * + * @file mytabbedstackwidget.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. + * @brief + * @see The GNU Public License (GPL) Version 3 + * @defgroup + * @{ + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MYTABBEDSTACKWIDGET_H +#define MYTABBEDSTACKWIDGET_H + +#include "utils/mylistwidget.h" +#include + +/* + * MyTabbedStackWidget is a MyListWidget combined with a QStackedWidget, + * similar in function to QTabWidget. + */ +class QTCREATOR_UTILS_EXPORT MyTabbedStackWidget : public QWidget +{ + Q_OBJECT + +public: + MyTabbedStackWidget(QWidget *parent = 0, bool isVertical = false, bool iconAbove = true); + + void insertTab(int index, QWidget *tab, const QIcon &icon, const QString &label); + void removeTab(int index); + void setIconSize(int size) { m_listWidget->setIconSize(QSize(size, size)); } + + int currentIndex() const; + + void insertCornerWidget(int index, QWidget *widget); + int cornerWidgetCount() { return m_cornerWidgetCount; } + +signals: + void currentAboutToShow(int index); + void currentChanged(int index); + +public slots: + void setCurrentIndex(int index); + +private slots: + void showWidget(int index); + +private: + MyListWidget *m_listWidget; + QStackedWidget *m_stackWidget; + QWidget *m_selectionWidget; + bool m_vertical; + bool m_iconAbove; + int m_cornerWidgetCount; +}; + +#endif // MYTABBEDSTACKWIDGET_H diff --git a/ground/openpilotgcs/src/libs/utils/mytabwidget.cpp b/ground/openpilotgcs/src/libs/utils/mytabwidget.cpp new file mode 100644 index 000000000..2a1a7bee4 --- /dev/null +++ b/ground/openpilotgcs/src/libs/utils/mytabwidget.cpp @@ -0,0 +1,48 @@ +/** + ****************************************************************************** + * + * @file mytabwidget.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. + * @brief + * @see The GNU Public License (GPL) Version 3 + * @defgroup + * @{ + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "mytabwidget.h" +#include + +MyTabWidget::MyTabWidget(QWidget *parent) + : QTabWidget(parent) +{ + QTabBar *tabBar = QTabWidget::tabBar(); + connect(tabBar, SIGNAL(tabMoved(int, int)), this, SLOT(myTabMoved(int,int))); +} + +void MyTabWidget::moveTab(int from, int to) +{ + QTabBar *tabBar = QTabWidget::tabBar(); + tabBar->moveTab(from, to); +} + + +void MyTabWidget::myTabMoved(int from, int to) +{ + emit tabMoved(from, to); +} diff --git a/ground/openpilotgcs/src/libs/utils/mytabwidget.h b/ground/openpilotgcs/src/libs/utils/mytabwidget.h new file mode 100644 index 000000000..8f941110b --- /dev/null +++ b/ground/openpilotgcs/src/libs/utils/mytabwidget.h @@ -0,0 +1,55 @@ +/** + ****************************************************************************** + * + * @file mytabwidget.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. + * @brief + * @see The GNU Public License (GPL) Version 3 + * @defgroup + * @{ + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef MYTABWIDGET_H +#define MYTABWIDGET_H + +#include "utils_global.h" + +#include + +/* + * MyTabWidget is a plain QTabWidget with the addition of the signal + * tabMoved(int, int) which QTabBar has but for some reason is + * not made available from QTabWidget. + */ +class QTCREATOR_UTILS_EXPORT MyTabWidget : public QTabWidget +{ + Q_OBJECT + +public: + MyTabWidget(QWidget *parent = 0); + void moveTab(int from, int to); + +private slots: + void myTabMoved(int from, int to); + +signals: + void tabMoved(int from, int to); +}; + +#endif // MYTABWIDGET_H diff --git a/ground/openpilotgcs/src/libs/utils/pathutils.cpp b/ground/openpilotgcs/src/libs/utils/pathutils.cpp index 9b42dfdf5..0ecdd3c85 100644 --- a/ground/openpilotgcs/src/libs/utils/pathutils.cpp +++ b/ground/openpilotgcs/src/libs/utils/pathutils.cpp @@ -26,6 +26,7 @@ */ #include "pathutils.h" +#include "xmlconfig.h" #include #include @@ -97,7 +98,7 @@ QString PathUtils::GetStoragePath() { // This routine works with "/" as the standard: // Work out where the settings are stored on the machine - QSettings set(QSettings::IniFormat, QSettings::UserScope,QLatin1String("OpenPilot"), QLatin1String("OpenPilotGCS")); + QSettings set(XmlConfig::XmlSettingsFormat, QSettings::UserScope,QLatin1String("OpenPilot"), QLatin1String("OpenPilotGCS")); QFileInfo f(set.fileName()); QDir dir(f.absoluteDir()); diff --git a/ground/openpilotgcs/src/libs/utils/qwineventnotifier_p.h b/ground/openpilotgcs/src/libs/utils/qwineventnotifier_p.h new file mode 100644 index 000000000..459cd6730 --- /dev/null +++ b/ground/openpilotgcs/src/libs/utils/qwineventnotifier_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINEVENTNOTIFIER_P_H +#define QWINEVENTNOTIFIER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qobject.h" +#include "QtCore/qt_windows.h" + +QT_BEGIN_NAMESPACE + +class Q_CORE_EXPORT QWinEventNotifier : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QObject) + +public: + explicit QWinEventNotifier(QObject *parent = 0); + explicit QWinEventNotifier(HANDLE hEvent, QObject *parent = 0); + ~QWinEventNotifier(); + + void setHandle(HANDLE hEvent); + HANDLE handle() const; + + bool isEnabled() const; + +public Q_SLOTS: + void setEnabled(bool enable); + +Q_SIGNALS: + void activated(HANDLE hEvent); + +protected: + bool event(QEvent * e); + +private: + Q_DISABLE_COPY(QWinEventNotifier) + + HANDLE handleToEvent; + bool enabled; +}; + +QT_END_NAMESPACE + +#endif // QWINEVENTNOTIFIER_P_H diff --git a/ground/openpilotgcs/src/libs/utils/utils.pri b/ground/openpilotgcs/src/libs/utils/utils.pri index 572895636..f6e523b74 100644 --- a/ground/openpilotgcs/src/libs/utils/utils.pri +++ b/ground/openpilotgcs/src/libs/utils/utils.pri @@ -1 +1 @@ -LIBS += -l$$qtLibraryTarget(Utils) +LIBS *= -l$$qtLibraryName(Utils) diff --git a/ground/openpilotgcs/src/libs/utils/utils.pro b/ground/openpilotgcs/src/libs/utils/utils.pro index 570b274f7..804f7c813 100644 --- a/ground/openpilotgcs/src/libs/utils/utils.pro +++ b/ground/openpilotgcs/src/libs/utils/utils.pro @@ -2,7 +2,8 @@ TEMPLATE = lib TARGET = Utils QT += gui \ - network + network \ + xml DEFINES += QTCREATOR_UTILS_LIB @@ -44,7 +45,11 @@ SOURCES += reloadpromptutils.cpp \ coordinateconversions.cpp \ pathutils.cpp \ worldmagmodel.cpp \ - homelocationutil.cpp + homelocationutil.cpp \ + mytabbedstackwidget.cpp \ + mytabwidget.cpp \ + mylistwidget.cpp +SOURCES += xmlconfig.cpp win32 { SOURCES += abstractprocess_win.cpp \ @@ -94,7 +99,11 @@ HEADERS += utils_global.h \ coordinateconversions.h \ pathutils.h \ worldmagmodel.h \ - homelocationutil.h + homelocationutil.h \ + mytabbedstackwidget.h \ + mytabwidget.h \ + mylistwidget.h +HEADERS += xmlconfig.h FORMS += filewizardpage.ui \ projectintropage.ui \ diff --git a/ground/openpilotgcs/src/plugins/importexport/xmlconfig.cpp b/ground/openpilotgcs/src/libs/utils/xmlconfig.cpp similarity index 93% rename from ground/openpilotgcs/src/plugins/importexport/xmlconfig.cpp rename to ground/openpilotgcs/src/libs/utils/xmlconfig.cpp index 79774d696..7b4cc9d5a 100644 --- a/ground/openpilotgcs/src/plugins/importexport/xmlconfig.cpp +++ b/ground/openpilotgcs/src/libs/utils/xmlconfig.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #define NUM_PREFIX "arr_" @@ -84,6 +85,10 @@ void XmlConfig::handleNode(QDomElement* node, QSettings::SettingsMap &map, QStri if ( nodeName.startsWith(NUM_PREFIX) ){ nodeName.replace(NUM_PREFIX, ""); } + // Xml tags are restrictive with allowed characters, + // so we urlencode and replace % with __PCT__ on file + nodeName = nodeName.replace("__PCT__", "%"); + nodeName = QUrl::fromPercentEncoding(nodeName.toAscii()); if ( nodeName == XmlConfig::rootName ) ; @@ -99,7 +104,7 @@ void XmlConfig::handleNode(QDomElement* node, QSettings::SettingsMap &map, QStri handleNode( static_cast(&child), map, path); } else if ( child.isText() ){ - qDebug() << "Key: " << path << " Value:" << node->text(); +// qDebug() << "Key: " << path << " Value:" << node->text(); map.insert(path, stringToVariant(node->text())); } else{ @@ -123,6 +128,10 @@ bool XmlConfig::writeXmlFile(QIODevice &device, const QSettings::SettingsMap &ma if ( elem == "" ){ continue; } + // Xml tags are restrictive with allowed characters, + // so we urlencode and replace % with __PCT__ on file + elem = QString(QUrl::toPercentEncoding(elem)); + elem = elem.replace("%", "__PCT__"); // For arrays, QT will use simple numbers as keys, which is not a valid element in XML. // Therefore we prefixed these. if ( elem.startsWith(NUM_PREFIX) ){ @@ -236,8 +245,9 @@ QString XmlConfig::variantToString(const QVariant &v) result = QLatin1String("@Variant("); result += QString::fromLatin1(a.toBase64().constData()); result += QLatin1Char(')'); - qDebug() << "Variant Type: " << v.type(); - qDebug()<< "Variant: " << result; + // These were being much too noisy!! + //qDebug() << "Variant Type: " << v.type(); + //qDebug()<< "Variant: " << result; #else Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support"); #endif diff --git a/ground/openpilotgcs/src/plugins/importexport/xmlconfig.h b/ground/openpilotgcs/src/libs/utils/xmlconfig.h similarity index 90% rename from ground/openpilotgcs/src/plugins/importexport/xmlconfig.h rename to ground/openpilotgcs/src/libs/utils/xmlconfig.h index 91cba38d1..447b2b6d4 100644 --- a/ground/openpilotgcs/src/plugins/importexport/xmlconfig.h +++ b/ground/openpilotgcs/src/libs/utils/xmlconfig.h @@ -26,13 +26,18 @@ #ifndef XMLCONFIG_H #define XMLCONFIG_H -#include "importexport_global.h" +#if defined(QTCREATOR_UTILS_LIB) +# define XMLCONFIG_EXPORT Q_DECL_EXPORT +#else +# define XMLCONFIG_EXPORT Q_DECL_IMPORT +#endif +#include #include #include #include -class IMPORTEXPORT_EXPORT XmlConfig : QObject +class XMLCONFIG_EXPORT XmlConfig : QObject { public: diff --git a/ground/openpilotgcs/src/openpilotgcslibrary.pri b/ground/openpilotgcs/src/openpilotgcslibrary.pri index 9aa6f00d2..55fe13114 100644 --- a/ground/openpilotgcs/src/openpilotgcslibrary.pri +++ b/ground/openpilotgcs/src/openpilotgcslibrary.pri @@ -8,7 +8,7 @@ DESTDIR = $$GCS_LIBRARY_PATH include(rpath.pri) -TARGET = $$qtLibraryTarget($$TARGET) +TARGET = $$qtLibraryName($$TARGET) contains(QT_CONFIG, reduce_exports):CONFIG += hGCS_symbols diff --git a/ground/openpilotgcs/src/openpilotgcsplugin.pri b/ground/openpilotgcs/src/openpilotgcsplugin.pri index 139bc9a1a..d274b71e8 100644 --- a/ground/openpilotgcs/src/openpilotgcsplugin.pri +++ b/ground/openpilotgcs/src/openpilotgcsplugin.pri @@ -23,10 +23,10 @@ copy2build.name = COPY ${QMAKE_FILE_IN} copy2build.CONFIG += no_link QMAKE_EXTRA_COMPILERS += copy2build -TARGET = $$qtLibraryTarget($$TARGET) +TARGET = $$qtLibraryName($$TARGET) macx { - QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../PlugIns/$${PROVIDER}/ + QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../Plugins/$${PROVIDER}/ } else:linux-* { #do the rpath by hand since it's not possible to use ORIGIN in QMAKE_RPATHDIR QMAKE_RPATHDIR += \$\$ORIGIN diff --git a/ground/openpilotgcs/src/plugins/config/ahrs.ui b/ground/openpilotgcs/src/plugins/config/ahrs.ui index 3ed6c93c9..a9ad4ca32 100644 --- a/ground/openpilotgcs/src/plugins/config/ahrs.ui +++ b/ground/openpilotgcs/src/plugins/config/ahrs.ui @@ -7,7 +7,7 @@ 0 0 720 - 501 + 537 @@ -41,17 +41,34 @@ - - - - 75 - true - - - - #1: Multi-Point Calibration - - + + + + + + 75 + true + + + + #1: Multi-Point Calibration + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + @@ -93,7 +110,6 @@ - @@ -111,17 +127,34 @@ - - - - 75 - true - - - - #2: Sensor noise calibration - - + + + + + + 75 + true + + + + #2: Sensor noise calibration + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + @@ -197,17 +230,34 @@ Hint: run this with engines at cruising speed. - - - - 75 - true - - - - #3: Accelerometer Bias calibration - - + + + + + + 75 + true + + + + #3: Accelerometer Bias calibration + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + @@ -253,17 +303,34 @@ Hint: run this with engines at cruising speed. - - - - 75 - true - - - - #4 Gyro temperature drift calibration - - + + + + + + 75 + true + + + + #4 Gyro temperature drift calibration + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + @@ -434,6 +501,12 @@ p, li { white-space: pre-wrap; } + + + 75 + true + + INS Algorithm: @@ -463,6 +536,12 @@ p, li { white-space: pre-wrap; } + + + 75 + true + + Home Location: @@ -551,12 +630,45 @@ new home location unless it is in indoor mode. - - - Refresh this screen with current values from the board. + + + + 0 + 0 + + + + + 32 + 32 + + + + + true + - Request + + + + + :/core/images/helpicon.svg:/core/images/helpicon.svg + + + + 32 + 32 + + + + Ctrl+S + + + false + + + true @@ -590,7 +702,9 @@ specific calibration button on top of the screen. - + + + diff --git a/ground/openpilotgcs/src/plugins/config/airframe.ui b/ground/openpilotgcs/src/plugins/config/airframe.ui index 09ed33ce7..fd039a906 100644 --- a/ground/openpilotgcs/src/plugins/config/airframe.ui +++ b/ground/openpilotgcs/src/plugins/config/airframe.ui @@ -23,7 +23,7 @@ Mixer Settings - + 5 @@ -31,6 +31,12 @@ + + + 75 + true + + Aircraft type: @@ -38,11 +44,6 @@ - - - 10 - - Select aircraft type here @@ -73,7 +74,7 @@ - 0 + 1 @@ -95,6 +96,12 @@ 0 + + + 75 + true + + Airplane type: @@ -119,131 +126,200 @@ - - - Channel Assignment - - + + + + + + 75 + true + + + + Channel Assignment + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - QFormLayout::AllNonFixedFieldsGrow + + + + 0 + 0 + - - - - Engine - - - - - - - - - - - 60 - 0 - - - - Aileron 1 - - - - - - - - - - false - - - - 60 - 0 - - - - Aileron 2 - - - - - - - false - - - - - - - - 67 - 0 - - - - Elevator 1 - - - - - - - - - - false - - - - 67 - 0 - - - - Elevator 2 - - - - - - - false - - - - - - - Rudder 1 - - - - - - - - - - Rudder 2 - - - - - - - + + + 0 + 100 + + + + Output channel asignmets + + + + + + Engine + + + + + + + Select output channel for the engine + + + + + + + + 60 + 0 + + + + Aileron 1 + + + + + + + Select output channel for the first aileron (or elevon) + + + + + + + false + + + + 60 + 0 + + + + Aileron 2 + + + + + + + false + + + Select output channel for the second aileron (or elevon) + + + + + + + + 67 + 0 + + + + Elevator 1 + + + + + + + Select output channel for the first elevator + + + + + + + false + + + + 67 + 0 + + + + Elevator 2 + + + + + + + false + + + Select output channel for a secondry elevator + + + + + + + Rudder 1 + + + + + + + Select output channel for the first rudder + + + + + + + Rudder 2 + + + + + + + Select output channel for a secondary rudder + + + + + + + + 0 + 0 + + Elevon Mix @@ -326,19 +402,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -356,61 +419,61 @@ - - - - - - - Throttle Curve - - - - - - - Reset - - - - - - - - - - 0 - 0 - - - - - 100 - 100 - - - - - 200 - 200 - - - - - 10 - 10 - - - - - - - - Val: 0.00 - - - - + + + + 0 + 100 + + + + Throttle Curve + + + + + + + 0 + 0 + + + + + 100 + 100 + + + + + 200 + 200 + + + + + 10 + 10 + + + + + + + + Reset + + + + + + + Val: 0.00 + + + + + @@ -466,13 +529,19 @@ - + + + + 75 + true + + Frame type: @@ -505,17 +574,34 @@ - - - - 75 - true - - - - Mix Level - - + + + + + + 75 + true + + + + Mix Level + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + @@ -682,92 +768,65 @@ Typical value is 50% for + or X configuration on quads. - - - QLayout::SetDefaultConstraint + + + Qt::Horizontal - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Throttle Curve - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 10 - - - - Reset - - - - - - - - - - 0 - 0 - - - - - 120 - 120 - - - - background:transparent - - - - - - - Val: 0.00 - - - - + + + 40 + 20 + + + + + + + + Throtte Curve + + + + + + + 0 + 0 + + + + + 120 + 120 + + + + background:transparent + + + + + + + + 0 + 0 + + + + Reset + + + + + + + Val: 0.00 + + + + + @@ -779,11 +838,34 @@ Typical value is 50% for + or X configuration on quads. - - - Tricopter Yaw - - + + + + + + 75 + true + + + + Tricopter Yaw + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + @@ -829,7 +911,7 @@ Typical value is 50% for + or X configuration on quads. - Motor output channels: + Motor output channels @@ -855,18 +937,8 @@ Typical value is 50% for + or X configuration on quads. - - - 8 - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Assign your motor channels using the drawing</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">on the right as a reference. Respect propeller rotation!</p></body></html> + Assign your motor output channels using the drawing above as a reference. Respect propeller rotation. @@ -879,10 +951,8 @@ p, li { white-space: pre-wrap; } - - - 8 - + + Assign your motor output channels using the drawing above as a reference. Respect propeller rotation. @@ -895,10 +965,8 @@ p, li { white-space: pre-wrap; } - - - 8 - + + Assign your motor output channels using the drawing above as a reference. Respect propeller rotation. @@ -911,10 +979,8 @@ p, li { white-space: pre-wrap; } - - - 8 - + + Assign your motor output channels using the drawing above as a reference. Respect propeller rotation. @@ -946,10 +1012,8 @@ p, li { white-space: pre-wrap; } 0 - - - 8 - + + Assign your motor output channels using the drawing above as a reference. Respect propeller rotation. @@ -965,10 +1029,8 @@ p, li { white-space: pre-wrap; } false - - - 8 - + + Assign your motor output channels using the drawing above as a reference. Respect propeller rotation. @@ -984,10 +1046,8 @@ p, li { white-space: pre-wrap; } false - - - 8 - + + Assign your motor output channels using the drawing above as a reference. Respect propeller rotation. @@ -1003,10 +1063,8 @@ p, li { white-space: pre-wrap; } false - - - 8 - + + Assign your motor output channels using the drawing above as a reference. Respect propeller rotation. @@ -1072,269 +1130,129 @@ p, li { white-space: pre-wrap; } - + - - - 2 - - + + - - - - - - - - 9 - - - - Throttle Curve 1 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 9 - - - - Reset - - - - - - - - - - 0 - 0 - - - - - 100 - 100 - - - - - 200 - 200 - - - - - - - - Val: 0.00 - - - - + + + Curve 1 + + + + + + + 0 + 0 + + + + + 100 + 100 + + + + + 200 + 200 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + Reset + + + + + + + Val: 0.00 + + + + + - - - - - - - - 9 - - - - Throttle Curve 2 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 9 - - - - Reset - - - - - - - - - - 0 - 0 - - - - - 100 - 100 - - - - - 200 - 200 - - - - - - - - Val: 0.00 - - - - + + + Qt::Horizontal + + + + 40 + 20 + + + - - - - - - - FeedForward - - - - - - - - 30 - 0 - - - - 000 - - - - - - - - - 100 - - - Qt::Horizontal - - - - - - - AccelTime - - - - - - - - - - DecelTime - - - - - - - - - - - - MaxAccel - - - - - - - 1000 - - - - - - - - - 500 - - - 2000 - - - 1000 - - - Qt::Horizontal - - - - + + + Curve 2 + + + + + + + 0 + 0 + + + + + 100 + 100 + + + + + 200 + 200 + + + + + + + + Reset + + + + + + + Val: 0.00 + + + + + - + @@ -1342,11 +1260,6 @@ p, li { white-space: pre-wrap; } 0 - - - 8 - - true @@ -1818,53 +1731,6 @@ p, li { white-space: pre-wrap; } - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Retrieve settings from OpenPilot - - - Get Current - - - - - - - Send to board, but don't save permanently (flash or SD). - - - Apply - - - - - - - Applies and Saves all settings to flash or SD depending on board. - - - Save - - - - - @@ -1873,19 +1739,36 @@ p, li { white-space: pre-wrap; } - + - - - - 75 - true - - - - Feed Forward - - + + + + + + 75 + true + + + + Feed Forward + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + @@ -2130,15 +2013,14 @@ p, li { white-space: pre-wrap; } <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> <tr> <td style="border: none;"> -<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:14pt; font-weight:600; color:#ff0000;">SETTING UP FEED FORWARD IS DANGEROUS</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Beware</span><span style=" font-size:10pt;">: Feed Forward Tuning will launch all engines around mid-throttle, you have been warned!</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;"></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Remove your props initially, and for fine-tuning, make sure your airframe is safely held in place. Wear glasses and protect your face and body.</span></p></td></tr></table></body></html> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:14pt; font-weight:600; color:#ff0000;">SETTING UP FEED FORWARD IS DANGEROUS</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu'; font-size:11pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13pt;">Beware: Feed Forward Tuning will launch all engines around mid-throttle, you have been warned!</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13pt;">Remove your props initially, and for fine-tuning, make sure your airframe is safely held in place. Wear glasses and protect your face and body.</span></p></td></tr></table></body></html> @@ -2155,59 +2037,81 @@ p, li { white-space: pre-wrap; } - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Request current settings from the board. - - - Get Current - - - - - - - Send to board, but don't save permanently (flash or SD). - - - Apply - - - - - - - Applies and Saves all settings to flash or SD depending on board. - - - Save - - - - - + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 32 + 32 + + + + + + + + :/core/images/helpicon.svg:/core/images/helpicon.svg + + + + 32 + 32 + + + + true + + + + + + + Send to board, but don't save permanently (flash or SD). + + + Apply + + + + + + + Applies and Saves all settings to flash or SD depending on board. + + + Save + + + + + @@ -2224,7 +2128,9 @@ p, li { white-space: pre-wrap; } 1 - + + + feedForwardSlider @@ -2258,54 +2164,6 @@ p, li { white-space: pre-wrap; } - - mrRollMixLevel - valueChanged(int) - label_43 - setNum(int) - - - 42 - 220 - - - 43 - 171 - - - - - mrPitchMixLevel - valueChanged(int) - label_44 - setNum(int) - - - 83 - 228 - - - 82 - 168 - - - - - mrYawMixLevel - valueChanged(int) - label_45 - setNum(int) - - - 120 - 254 - - - 121 - 172 - - - elevonSlider1 valueChanged(int) @@ -2339,34 +2197,50 @@ p, li { white-space: pre-wrap; } - customFFSlider + mrPitchMixLevel valueChanged(int) - customFeedForwardValue + label_44 setNum(int) - 115 - 117 + 83 + 228 - 115 - 117 + 82 + 168 - customFFMaxAccel + mrRollMixLevel valueChanged(int) - label_OSD + label_43 setNum(int) - 115 - 117 + 42 + 220 - 115 - 117 + 43 + 171 + + + + + mrYawMixLevel + valueChanged(int) + label_45 + setNum(int) + + + 120 + 254 + + + 121 + 172 diff --git a/ground/openpilotgcs/src/plugins/config/camerastabilization.ui b/ground/openpilotgcs/src/plugins/config/camerastabilization.ui new file mode 100644 index 000000000..28e7740c1 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/camerastabilization.ui @@ -0,0 +1,441 @@ + + + CameraStabilizationWidget + + + + 0 + 0 + 720 + 567 + + + + Form + + + + + + Enable CameraStabilization module + + + + + + + After enabling the module, you must power cycle before using and configuring. + + + + + + + Qt::Horizontal + + + + + + + Channel Ranges (number of degrees full range) + + + + + + + + Pitch + + + + + + + Yaw + + + + + + + Roll + + + + + + + 180 + + + + + + + 180 + + + + + + + 180 + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 212 + 20 + + + + + + + + + + + Channel Mapping (select output channel or none to disable) + + + + + + + + Roll + + + + + + + + None + + + + + Channel 1 + + + + + Channel 2 + + + + + Channel 3 + + + + + Channel 4 + + + + + Channel 5 + + + + + Channel 6 + + + + + Channel 7 + + + + + Channel 8 + + + + + + + + + None + + + + + Channel 1 + + + + + Channel 2 + + + + + Channel 3 + + + + + Channel 4 + + + + + Channel 5 + + + + + Channel 6 + + + + + Channel 7 + + + + + Channel 8 + + + + + + + + Pitch + + + + + + + + None + + + + + Channel 1 + + + + + Channel 2 + + + + + Channel 3 + + + + + Channel 4 + + + + + Channel 5 + + + + + Channel 6 + + + + + Channel 7 + + + + + Channel 8 + + + + + + + + Yaw + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 212 + 20 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 32 + 32 + + + + + true + + + + + + + + :/core/images/helpicon.svg:/core/images/helpicon.svg + + + + 32 + 32 + + + + Ctrl+S + + + false + + + true + + + + + + + Save settings to the board (RAM only). + +This does not save the calibration settings, this is done using the +specific calibration button on top of the screen. + + + Apply + + + + + + + Send settings to the board, and save to the non-volatile memory. + + + Save + + + false + + + + + + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/config/cc_hw_settings.ui b/ground/openpilotgcs/src/plugins/config/cc_hw_settings.ui new file mode 100644 index 000000000..a4a8586e5 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/cc_hw_settings.ui @@ -0,0 +1,283 @@ + + + CC_HW_Widget + + + + 0 + 0 + 517 + 487 + + + + Form + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + :/configgadget/images/coptercontrol.svg + + + true + + + + + + + + + + + + + MainPort + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + + + + + + + FlexiPort + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Receiver type + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + Telemetry speed: + + + + + + + Select the speed here. + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 75 + true + + + + + + + Qt::AutoText + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 75 + true + + + + Changes on this page only take effect after board reset or power cycle + + + true + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 32 + 32 + + + + + 32 + 32 + + + + + + + + :/core/images/helpicon.svg:/core/images/helpicon.svg + + + + 32 + 32 + + + + true + + + + + + + Send to OpenPilot but don't write in SD. +Beware of not locking yourself out! + + + true + + + + + + Apply + + + false + + + + + + + Applies and Saves all settings to SD. +Beware of not locking yourself out! + + + false + + + + + + Save + + + + + + + + + + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/config/ccattitude.ui b/ground/openpilotgcs/src/plugins/config/ccattitude.ui index b6b00126c..49a7ab649 100644 --- a/ground/openpilotgcs/src/plugins/config/ccattitude.ui +++ b/ground/openpilotgcs/src/plugins/config/ccattitude.ui @@ -6,254 +6,148 @@ 0 0 - 400 - 343 + 455 + 428 Form - - - - - - 0 - 0 - - - - - 0 - 110 - - - - Attitude Rotation - - - - - 10 - 70 - 81 - 25 - - - - -180 - - - 180 - - - - - - 120 - 70 - 81 - 25 - - - - -90 - - - 90 - - - - - - 220 - 70 - 81 - 25 - - - - -180 - - - 180 - - - - - - 10 - 50 - 91 - 16 - - - - Roll - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - 120 - 50 - 81 - 16 - - - - Pitch - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - 220 - 50 - 81 - 16 - - - - Yaw - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - 10 - 30 - 341 - 16 - - - - Select the amount to rotate the attitude - - - - - + + - - - 0 - 0 - - - - - 0 - 140 - - - Attitude Calibration + Rotate virtual attitude relative to board - - - - 0 - 20 - 371 - 111 - - - - - 3 - - - - - Place aircraft flat before computing - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Click "Zero Accel Bias" to start - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Launch horizontal calibration. - - - Zero Accel Bias - - - - - - - 0 - - - - - - - + + + + + Roll + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + -180 + + + 180 + + + + + + + Pitch + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + -90 + + + 90 + + + + + + + Yaw + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + -180 + + + 180 + + + + - - - - If enabled, a fast recalibration of gyro zero point will be done + + + + Calibration + + + + + + Place aircraft very flat, and then click level to compute the accelerometer and gyro bias + + + true + + + + + + + Launch horizontal calibration. + + + Level + + + + + + + 0 + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 0 + 10 + + + + + + + + If enabled, a fast recalibration of gyro zero point will be done whenever the frame is armed. Do not move the airframe while arming it in that case! - - - Zero gyro bias upon airframe arming - + + + Zero gyros while arming aircraft + + + + - + Qt::Vertical @@ -266,7 +160,7 @@ arming it in that case! - + @@ -282,9 +176,34 @@ arming it in that case! - + + + + 0 + 0 + + + + + 32 + 32 + + - Get Current + + + + + :/core/images/helpicon.svg:/core/images/helpicon.svg + + + + 32 + 32 + + + + true @@ -307,21 +226,10 @@ arming it in that case! - - - - Qt::Vertical - - - - 20 - 40 - - - - - + + + diff --git a/ground/openpilotgcs/src/plugins/config/ccpm.ui b/ground/openpilotgcs/src/plugins/config/ccpm.ui index 2522ab540..12d501f60 100644 --- a/ground/openpilotgcs/src/plugins/config/ccpm.ui +++ b/ground/openpilotgcs/src/plugins/config/ccpm.ui @@ -1,3140 +1,3875 @@ - - - ccpmWidget - - - - 0 - 0 - 660 - 572 - - - - - 0 - 0 - - - - - 300 - 300 - - - - Form - - - false - - - - - - - - QFormLayout::AllNonFixedFieldsGrow - - - 0 - - - - - Swashplate config: - - - - - - - - 10 - - - - Select aircraft type here - - - - - - - - - - 0 - 0 - - - - - 400 - 300 - - - - 0 - - - - Basic settings - - - - 3 - - - 3 - - - - - - - - 0 - 0 - - - - Outputs - - - - 3 - - - 2 - - - 3 - - - - - - 0 - 0 - - - - - 85 - 0 - - - - - 85 - 16777215 - - - - - - - - - 0 - 0 - - - - - 85 - 0 - - - - - 85 - 16777215 - - - - - - - - - 0 - 0 - - - - - 80 - 0 - - - - - 80 - 16777215 - - - - Tail Rotor - - - - - - - - 0 - 0 - - - - - 80 - 0 - - - - - 80 - 16777215 - - - - Engine - - - - - - - - - - - 0 - 0 - - - - Swashplate Outputs - - - - 3 - - - 2 - - - 3 - - - - - true - - - - 1 - 1 - - - - - 80 - 0 - - - - - 80 - 16777215 - - - - Servo W - - - - - - - true - - - - 0 - 0 - - - - - 85 - 0 - - - - - 85 - 16777215 - - - - - - - - - 0 - 0 - - - - - 85 - 0 - - - - - 85 - 16777215 - - - - - - - - true - - - - 0 - 0 - - - - - 85 - 0 - - - - - 85 - 16777215 - - - - - - - - - 1 - 1 - - - - - 80 - 0 - - - - - 80 - 16777215 - - - - Servo X - - - - - - - - 0 - 0 - - - - - 85 - 0 - - - - - 85 - 16777215 - - - - - Front - - - - - Right - - - - - Rear - - - - - Left - - - - - - - - - 1 - 1 - - - - - 80 - 0 - - - - - 80 - 16777215 - - - - Single Servo - - - - - - - - 0 - 0 - - - - - 85 - 0 - - - - - 85 - 16777215 - - - - - - - - - 1 - 1 - - - - - 80 - 0 - - - - - 80 - 16777215 - - - - Servo Z - - - - - - - true - - - - 1 - 1 - - - - - 80 - 0 - - - - - 80 - 16777215 - - - - Servo Y - - - - - - - - - - - 0 - 0 - - - - - 70 - 0 - - - - Swashplate Servo Angles - - - - 3 - - - 2 - - - 3 - - - - - - 0 - 0 - - - - - 85 - 0 - - - - - 85 - 16777215 - - - - 0 - - - 360.000000000000000 - - - 15.000000000000000 - - - - - - - true - - - - 0 - 0 - - - - - 80 - 0 - - - - - 80 - 16777215 - - - - Angle W - - - - - - - - 0 - 0 - - - - - 80 - 0 - - - - - 80 - 16777215 - - - - Angle X - - - - - - - true - - - - 0 - 0 - - - - - 80 - 0 - - - - - 80 - 16777215 - - - - Angle Y - - - - - - - - 0 - 0 - - - - - 80 - 0 - - - - - 80 - 16777215 - - - - Angle Z - - - - - - - true - - - - 0 - 0 - - - - - 80 - 0 - - - - - 80 - 16777215 - - - - CorrectionAngle - - - - - - - - 0 - 0 - - - - - 85 - 0 - - - - - 85 - 16777215 - - - - 0 - - - 360.000000000000000 - - - 15.000000000000000 - - - - - - - true - - - - 0 - 0 - - - - - 85 - 0 - - - - - 85 - 16777215 - - - - 0 - - - 360.000000000000000 - - - 15.000000000000000 - - - - - - - - 0 - 0 - - - - - 85 - 0 - - - - - 85 - 16777215 - - - - 0 - - - 360.000000000000000 - - - 15.000000000000000 - - - - - - - - 0 - 0 - - - - - 85 - 0 - - - - - 85 - 16777215 - - - - 0 - - - 360.000000000000000 - - - 15.000000000000000 - - - - - - - - - - Qt::Vertical - - - QSizePolicy::MinimumExpanding - - - - 20 - 0 - - - - - - - - - - false - - - - 0 - 0 - - - - - 50 - 100 - - - - - 50 - 600 - - - - REVO - - - - 0 - - - 3 - - - - - false - - - - 7 - - - - 100% - - - Qt::AlignCenter - - - - - - - - - Qt::Horizontal - - - - 5 - 25 - - - - - - - - false - - - - 0 - 0 - - - - - 0 - 100 - - - - 100 - - - 5 - - - Qt::Vertical - - - - - - - Qt::Horizontal - - - - 5 - 25 - - - - - - - - - - false - - - - 7 - - - - 0% - - - Qt::AlignCenter - - - - - - - - - - - - - true - - - - 0 - 0 - - - - - 50 - 100 - - - - - 50 - 600 - - - - - 8 - - - - CCPM - - - Qt::AlignCenter - - - - 0 - - - 3 - - - - - true - - - - 7 - - - - Collective - - - true - - - Qt::AlignCenter - - - - - - - - - Qt::Horizontal - - - - 5 - 25 - - - - - - - - true - - - - 0 - 0 - - - - - 0 - 100 - - - - 100 - - - 5 - - - 50 - - - Qt::Vertical - - - - - - - Qt::Horizontal - - - - 5 - 25 - - - - - - - - - - true - - - - 7 - - - - Cyclic - - - Qt::AlignCenter - - - - - - - 100 - - - 5 - - - 50 - - - - - - - - - - - - - 1 - 1 - - - - - 200 - 200 - - - - - 600 - 600 - - - - - 10 - 10 - - - - - 200 - 200 - - - - Swashplate Layout - - - Qt::AlignHCenter|Qt::AlignTop - - - false - - - false - - - - 3 - - - 3 - - - - - Qt::Vertical - - - - - 1 - 1 - - - - - 200 - 200 - - - - - 500 - 500 - - - - - 10 - 10 - - - - - 200 - 200 - - - - QFrame::Box - - - QFrame::Plain - - - 1 - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - - - 112 - 184 - 138 - - - - - - - 127 - 127 - 127 - - - - - - 0.000000000000000 - 0.000000000000000 - 400.000000000000000 - 400.000000000000000 - - - - Qt::AlignCenter - - - QGraphicsView::AnchorViewCenter - - - - - - - - - - - - - - Swashplate Levelling - - - - 3 - - - 3 - - - - - 3 - - - - - - 0 - 0 - - - - - 228 - 0 - - - - Commands - - - - 3 - - - - - 0 - - - - - - 85 - 0 - - - - - 85 - 16777215 - - - - Start - - - - - - - false - - - - 85 - 0 - - - - - 85 - 16777215 - - - - Next - - - - - - - - - - 0 - 150 - - - - - 220 - 450 - - - - Qt::ScrollBarAlwaysOff - - - true - - - - - - - - - false - - - - 170 - 0 - - - - - 170 - 16777215 - - - - Cancel - - - - - - - false - - - - 170 - 0 - - - - - 170 - 16777215 - - - - Finish - - - - - - - - - - - - - 0 - 0 - - - - - 200 - 0 - - - - Status - - - - 3 - - - 2 - - - 3 - - - - - - 220 - 0 - - - - - 190 - 125 - - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::NoSelection - - - QAbstractItemView::SelectRows - - - - Neutral - - - - :/configgadget/images/none.png - :/configgadget/images/ok.png:/configgadget/images/none.png - - - - - Max - - - - :/configgadget/images/none.png - :/configgadget/images/ok.png:/configgadget/images/none.png - - - - - Min - - - - :/configgadget/images/none.png - :/configgadget/images/ok.png:/configgadget/images/none.png - - - ItemIsSelectable|ItemIsEnabled - - - - - Verify - - - - :/configgadget/images/none.png - :/configgadget/images/ok.png:/configgadget/images/none.png - - - ItemIsEnabled - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::MinimumExpanding - - - - 20 - 0 - - - - - - - - - - true - - - - 0 - 0 - - - - - 50 - 100 - - - - - 50 - 600 - - - - - 8 - - - - Position - - - Qt::AlignCenter - - - - 0 - - - 3 - - - - - true - - - - 7 - - - - Max - - - true - - - Qt::AlignCenter - - - - - - - - - Qt::Horizontal - - - - 5 - 25 - - - - - - - - true - - - - 0 - 0 - - - - - 0 - 100 - - - - 100 - - - 5 - - - 50 - - - Qt::Vertical - - - - - - - Qt::Horizontal - - - - 5 - 25 - - - - - - - - - - true - - - - 7 - - - - Min - - - Qt::AlignCenter - - - - - - - 100 - - - 5 - - - 50 - - - - - - - - - - - 1 - 1 - - - - - 200 - 200 - - - - - 600 - 600 - - - - - 10 - 10 - - - - - 200 - 200 - - - - Swashplate Adjustment - - - Qt::AlignHCenter|Qt::AlignTop - - - false - - - false - - - - 3 - - - 3 - - - - - Qt::Vertical - - - - - 1 - 1 - - - - - 200 - 200 - - - - - 500 - 500 - - - - - 10 - 10 - - - - - 200 - 200 - - - - QFrame::Box - - - QFrame::Plain - - - 1 - - - 0 - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - - - 126 - 176 - 220 - - - - - - - 0 - 0 - 0 - - - - - - 0.000000000000000 - 0.000000000000000 - 400.000000000000000 - 400.000000000000000 - - - - Qt::AlignCenter - - - QGraphicsView::AnchorViewCenter - - - - - - - - - - - - Curve settings - - - - 3 - - - 3 - - - - - - - - 150 - 0 - - - - - 10 - - - - Select aircraft type here - - - - Linear - - - - - Flat - - - - - Step - - - - - Exp - - - - - Log - - - - - Custom - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - Number of points - - - - - - - - 0 - 0 - - - - 2 - - - 10 - - - 5 - - - - - - - - - - - Min - - - - - - - Max - - - - - - - Step point - - - - - - - 1 - - - 10.000000000000000 - - - - - - - 1 - - - 10.000000000000000 - - - 1.000000000000000 - - - - - - - 1 - - - 100.000000000000000 - - - 50.000000000000000 - - - - - - - - - - - - 0 - 0 - - - - - 150 - 0 - - - - - 10 - - - - Select aircraft type here - - - - Throttle - - - - - Pitch - - - - - - - - - 0 - 0 - - - - - 150 - 0 - - - - Generate curves based on settings - - - <-- Generate Curve - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 3 - - - - - - 0 - 0 - - - - - 250 - 200 - - - - - 250 - 273 - - - - - 8 - - - - Qt::ScrollBarAsNeeded - - - Qt::ScrollBarAsNeeded - - - true - - - true - - - true - - - true - - - true - - - 25 - - - 25 - - - - 0% - - - - - 25% - - - - - 50% - - - - - 75% - - - - - 100% - - - - - none - - - - - none - - - - - none - - - - - none - - - - - none - - - - - Throttle Curve - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - Blade Pitch Curve - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - 0.000 - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - 0.000 - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - 0.250 - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - 0.250 - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - 0.500 - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - 0.500 - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - 0.750 - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - 0.750 - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - 1.000 - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - 1.000 - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - 1 - 1 - - - - - 100 - 100 - - - - - 10 - 10 - - - - - 100 - 100 - - - - Qt::LeftToRight - - - Throttle Curve - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - false - - - - 0 - - - 0 - - - - - - 1 - 1 - - - - - 50 - 50 - - - - - 1000 - 1000 - - - - - 10 - 10 - - - - - 200 - 200 - - - - - - - - - - - - 1 - 1 - - - - - 100 - 100 - - - - - 10 - 10 - - - - - 100 - 100 - - - - Pitch Curve - - - - 0 - - - 0 - - - - - - 1 - 1 - - - - - 50 - 50 - - - - - 1000 - 1000 - - - - - 10 - 10 - - - - - 200 - 200 - - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 0 - - - - - - - - - Advanced settings - - - - 3 - - - 3 - - - - - - 0 - 0 - - - - - 0 - 200 - - - - - 1000 - 300 - - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - true - - - true - - - QAbstractItemView::NoSelection - - - false - - - true - - - 75 - - - 20 - - - - Engine - - - - - Tail Rotor - - - - - Servo W - - - - - Servo X - - - - - Servo Y - - - - - Servo Z - - - - - Channel - - - - - Curve 1 - - - - - Curve 2 - - - - - Roll - - - - - Pitch - - - - - Yaw - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - - AlignHCenter|AlignVCenter|AlignCenter - - - - - - - - Qt::Vertical - - - QSizePolicy::MinimumExpanding - - - - 20 - 40 - - - - - - - - - - - - - - - MixerCurveWidget - QWidget -
mixercurvewidget.h
- 1 -
-
- - ccpmType - TabObject - ccpmEngineChannel - ccpmTailChannel - ccpmServoWChannel - ccpmServoXChannel - ccpmServoYChannel - ccpmServoZChannel - ccpmSingleServo - ccpmAngleW - ccpmAngleX - ccpmAngleY - ccpmAngleZ - ccpmCorrectionAngle - ccpmRevoSlider - ccpmREVOspinBox - ccpmCollectiveSlider - ccpmCollectivespinBox - SwashplateImage - SwashLvlStartButton - SwashLvlNextButton - SwashLvlStepInstruction - SwashLvlCancelButton - SwashLvlFinishButton - SwashLvlStepList - SwashLvlPositionSlider - SwashLvlPositionSpinBox - SwashLvlSwashplateImage - CurveType - NumCurvePoints - CurveValue1 - CurveValue2 - CurveValue3 - CurveToGenerate - ccpmGenerateCurve - CurveSettings - ccpmAdvancedSettingsTable - - - - - ccpmCollectiveSlider - sliderMoved(int) - ccpmCollectivespinBox - setValue(int) - - - 283 - 400 - - - 294 - 550 - - - - - ccpmCollectivespinBox - valueChanged(int) - ccpmCollectiveSlider - setValue(int) - - - 294 - 550 - - - 283 - 482 - - - - - ccpmREVOspinBox - valueChanged(int) - ccpmRevoSlider - setValue(int) - - - 241 - 550 - - - 230 - 484 - - - - - ccpmRevoSlider - sliderMoved(int) - ccpmREVOspinBox - setValue(int) - - - 230 - 313 - - - 241 - 550 - - - - - SwashLvlPositionSlider - sliderMoved(int) - SwashLvlPositionSpinBox - setValue(int) - - - 276 - 486 - - - 270 - 537 - - - - - SwashLvlPositionSpinBox - valueChanged(int) - SwashLvlPositionSlider - setValue(int) - - - 257 - 535 - - - 277 - 401 - - - - -
+ + + ccpmWidget + + + + 0 + 0 + 660 + 572 + + + + + 0 + 0 + + + + + 300 + 300 + + + + Form + + + false + + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + 0 + + + + + Swashplate config: + + + + + + + Select aircraft type here + + + + + + + + + + 0 + 0 + + + + + 300 + 300 + + + + 2 + + + + Basic settings + + + + 3 + + + 0 + + + 3 + + + 3 + + + 3 + + + + + + + + 0 + 0 + + + + + 190 + 16777215 + + + + Outputs + + + + 3 + + + 2 + + + 3 + + + + + + 0 + 0 + + + + + 85 + 0 + + + + + 100 + 16777215 + + + + + + + + + 0 + 0 + + + + + 85 + 0 + + + + + 100 + 16777215 + + + + + + + + + 0 + 0 + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Tail Rotor + + + + + + + + 0 + 0 + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Engine + + + + + + + + + + + 0 + 0 + + + + + 190 + 16777215 + + + + Swashplate Outputs + + + + 3 + + + 2 + + + 3 + + + + + true + + + + 1 + 1 + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Servo W + + + + + + + true + + + + 0 + 0 + + + + + 85 + 0 + + + + + 100 + 16777215 + + + + + + + + + 0 + 0 + + + + + 85 + 0 + + + + + 100 + 16777215 + + + + + + + + true + + + + 0 + 0 + + + + + 85 + 0 + + + + + 100 + 16777215 + + + + + + + + + 1 + 1 + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Servo X + + + + + + + + 0 + 0 + + + + + 85 + 0 + + + + + 100 + 16777215 + + + + + Front + + + + + Right + + + + + Rear + + + + + Left + + + + + + + + + 1 + 1 + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + 1st Servo + + + + + + + + 0 + 0 + + + + + 85 + 0 + + + + + 100 + 16777215 + + + + + + + + + 1 + 1 + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Servo Z + + + + + + + true + + + + 1 + 1 + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Servo Y + + + + + + + + + + + 0 + 0 + + + + + 70 + 0 + + + + + 190 + 16777215 + + + + Swashplate Servo Angles + + + + 3 + + + 2 + + + 3 + + + + + + 0 + 0 + + + + + 85 + 0 + + + + + 85 + 16777215 + + + + 0 + + + 360.000000000000000 + + + 15.000000000000000 + + + + + + + true + + + + 0 + 0 + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Angle W + + + + + + + + 0 + 0 + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Angle X + + + + + + + true + + + + 0 + 0 + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Angle Y + + + + + + + + 0 + 0 + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Angle Z + + + + + + + true + + + + 0 + 0 + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Correction Angle + + + true + + + + + + + + 0 + 0 + + + + + 85 + 0 + + + + + 85 + 16777215 + + + + 0 + + + 360.000000000000000 + + + 15.000000000000000 + + + + + + + true + + + + 0 + 0 + + + + + 85 + 0 + + + + + 85 + 16777215 + + + + 0 + + + 360.000000000000000 + + + 15.000000000000000 + + + + + + + + 0 + 0 + + + + + 85 + 0 + + + + + 85 + 16777215 + + + + 0 + + + 360.000000000000000 + + + 15.000000000000000 + + + + + + + + 0 + 0 + + + + + 85 + 0 + + + + + 85 + 16777215 + + + + 0 + + + 360.000000000000000 + + + 15.000000000000000 + + + + + + + + + + + 0 + 0 + + + + + 190 + 16777215 + + + + CCPM Options + + + + 3 + + + 2 + + + 3 + + + + + Collective Pass through + + + + + + + Link Roll/Pitch + + + true + + + + + + + Link Cyclic/Collective + + + true + + + + + + + QLayout::SetNoConstraint + + + + + true + + + + 0 + 0 + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + + 11 + + + + Qt::LeftToRight + + + Collective Ch + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + + + + + true + + + + 0 + 0 + + + + + 90 + 0 + + + + + 100 + 16777215 + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 0 + + + 0 + + + + + + 1 + 1 + + + + + 200 + 200 + + + + + 600 + 600 + + + + + 10 + 10 + + + + + 200 + 200 + + + + + 11 + + + + Swashplate Layout + + + Qt::AlignHCenter|Qt::AlignTop + + + false + + + false + + + + 3 + + + 3 + + + + + Qt::Vertical + + + + + 1 + 1 + + + + + 10 + 10 + + + + + 1000 + 1000 + + + + + 10 + 10 + + + + + 200 + 200 + + + + QFrame::Box + + + QFrame::Plain + + + 1 + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + + + 112 + 184 + 138 + + + + + + + 127 + 127 + 127 + + + + + + 0.000000000000000 + 0.000000000000000 + 400.000000000000000 + 400.000000000000000 + + + + Qt::AlignCenter + + + QGraphicsView::AnchorViewCenter + + + + + + + + + + + + + QLayout::SetNoConstraint + + + 3 + + + 3 + + + + + true + + + + 0 + 0 + + + + + 50 + 100 + + + + + 50 + 600 + + + + REVO + + + + 0 + + + 3 + + + + + false + + + + 7 + + + + 100% + + + Qt::AlignCenter + + + + + + + + + Qt::Horizontal + + + + 5 + 25 + + + + + + + + true + + + + 0 + 0 + + + + + 0 + 100 + + + + 100 + + + 5 + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + + 5 + 25 + + + + + + + + + + false + + + + 7 + + + + 0% + + + Qt::AlignCenter + + + + + + + + + + + + + true + + + + 0 + 0 + + + + + 50 + 100 + + + + + 50 + 600 + + + + CCPM + + + Qt::AlignCenter + + + + 0 + + + 3 + + + + + true + + + + 7 + + + + Collective + + + true + + + Qt::AlignCenter + + + + + + + + + Qt::Horizontal + + + + 5 + 25 + + + + + + + + true + + + + 0 + 0 + + + + + 0 + 100 + + + + 100 + + + 5 + + + 50 + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + + 5 + 25 + + + + + + + + + + true + + + + 7 + + + + Cyclic + + + Qt::AlignCenter + + + + + + + 100 + + + 5 + + + 50 + + + + + + + + + + true + + + + 0 + 0 + + + + + 50 + 100 + + + + + 50 + 600 + + + + Collective + + + Qt::AlignCenter + + + + 0 + + + 3 + + + + + + + Qt::Horizontal + + + + 5 + 25 + + + + + + + + true + + + + 0 + 0 + + + + + 0 + 100 + + + + 100 + + + 5 + + + 50 + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + + 5 + 25 + + + + + + + + + + 100 + + + 5 + + + 50 + + + + + + + + + + true + + + + 0 + 0 + + + + + 50 + 100 + + + + + 50 + 600 + + + + Cyclic + + + Qt::AlignCenter + + + false + + + + 0 + + + 3 + + + + + + + Qt::Horizontal + + + + 5 + 25 + + + + + + + + true + + + + 0 + 0 + + + + + 0 + 100 + + + + 100 + + + 5 + + + 50 + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + + 5 + 25 + + + + + + + + + + 100 + + + 5 + + + 50 + + + + + + + + + + true + + + + 0 + 0 + + + + + 50 + 100 + + + + + 50 + 600 + + + + Pitch + + + Qt::AlignCenter + + + + 0 + + + 3 + + + + + + + Qt::Horizontal + + + + 5 + 25 + + + + + + + + true + + + + 0 + 0 + + + + + 0 + 100 + + + + 100 + + + 5 + + + 50 + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + + 5 + 25 + + + + + + + + + + 100 + + + 5 + + + 50 + + + + + + + + + + true + + + + 0 + 0 + + + + + 50 + 100 + + + + + 50 + 600 + + + + Roll + + + Qt::AlignCenter + + + + 0 + + + 3 + + + + + + + Qt::Horizontal + + + + 5 + 25 + + + + + + + + true + + + + 0 + 0 + + + + + 0 + 100 + + + + 100 + + + 5 + + + 50 + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + + 5 + 25 + + + + + + + + + + 100 + + + 5 + + + 50 + + + + + + + + + + + + + Swashplate Levelling + + + + 3 + + + 3 + + + + + 3 + + + + + + 0 + 0 + + + + + 228 + 0 + + + + Commands + + + + 3 + + + + + 0 + + + + + + 85 + 0 + + + + + 85 + 16777215 + + + + Start + + + + + + + false + + + + 85 + 0 + + + + + 85 + 16777215 + + + + Next + + + + + + + + + + 0 + 150 + + + + + 220 + 450 + + + + Qt::ScrollBarAlwaysOff + + + true + + + + + + + + + false + + + + 170 + 0 + + + + + 170 + 16777215 + + + + Cancel + + + + + + + false + + + + 170 + 0 + + + + + 170 + 16777215 + + + + Finish + + + + + + + + + + + + + 0 + 0 + + + + + 200 + 0 + + + + Status + + + + 3 + + + 2 + + + 3 + + + + + + 220 + 0 + + + + + 190 + 125 + + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::NoSelection + + + QAbstractItemView::SelectRows + + + + Neutral + + + + :/configgadget/images/none.png + :/configgadget/images/ok.png:/configgadget/images/none.png + + + + + Max + + + + :/configgadget/images/none.png + :/configgadget/images/ok.png:/configgadget/images/none.png + + + + + Min + + + + :/configgadget/images/none.png + :/configgadget/images/ok.png:/configgadget/images/none.png + + + ItemIsSelectable|ItemIsEnabled + + + + + Verify + + + + :/configgadget/images/none.png + :/configgadget/images/ok.png:/configgadget/images/none.png + + + ItemIsEnabled + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 0 + + + + + + + + + + true + + + + 0 + 0 + + + + + 50 + 100 + + + + + 50 + 600 + + + + Position + + + Qt::AlignCenter + + + + 0 + + + 3 + + + + + true + + + Max + + + true + + + Qt::AlignCenter + + + + + + + + + Qt::Horizontal + + + + 5 + 25 + + + + + + + + true + + + + 0 + 0 + + + + + 0 + 100 + + + + 100 + + + 5 + + + 50 + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + + 5 + 25 + + + + + + + + + + true + + + Min + + + Qt::AlignCenter + + + + + + + 100 + + + 5 + + + 50 + + + + + + + + + + + 1 + 1 + + + + + 200 + 200 + + + + + 600 + 600 + + + + + 10 + 10 + + + + + 200 + 200 + + + + Swashplate Adjustment + + + Qt::AlignHCenter|Qt::AlignTop + + + false + + + false + + + + 3 + + + 3 + + + + + Qt::Vertical + + + + + 1 + 1 + + + + + 10 + 10 + + + + + 1000 + 1000 + + + + + 10 + 10 + + + + + 200 + 200 + + + + QFrame::Box + + + QFrame::Plain + + + 1 + + + 0 + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + + + 126 + 176 + 220 + + + + + + + 0 + 0 + 0 + + + + + + 0.000000000000000 + 0.000000000000000 + 400.000000000000000 + 400.000000000000000 + + + + Qt::AlignCenter + + + QGraphicsView::AnchorViewCenter + + + + + + + + + + + + Curve settings + + + + 3 + + + 3 + + + + + + + + 150 + 0 + + + + + 10 + + + + Select aircraft type here + + + + Linear + + + + + Flat + + + + + Step + + + + + Exp + + + + + Log + + + + + Custom + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Number of points + + + + + + + + 0 + 0 + + + + 2 + + + 10 + + + 5 + + + + + + + + + + + Min + + + + + + + Max + + + + + + + Step point + + + + + + + 1 + + + 10.000000000000000 + + + + + + + 1 + + + 10.000000000000000 + + + 1.000000000000000 + + + + + + + 1 + + + 100.000000000000000 + + + 50.000000000000000 + + + + + + + + + + + + 0 + 0 + + + + + 150 + 0 + + + + + 10 + + + + Select aircraft type here + + + + Throttle + + + + + Pitch + + + + + + + + + 0 + 0 + + + + + 150 + 0 + + + + Generate curves based on settings + + + <-- Generate Curve + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 3 + + + + + + 0 + 0 + + + + + 250 + 200 + + + + + 250 + 273 + + + + Qt::ScrollBarAsNeeded + + + Qt::ScrollBarAsNeeded + + + true + + + true + + + true + + + true + + + true + + + 25 + + + 25 + + + + 0% + + + + + 25% + + + + + 50% + + + + + 75% + + + + + 100% + + + + + none + + + + + none + + + + + none + + + + + none + + + + + none + + + + + Throttle Curve + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + Blade Pitch Curve + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + 0.000 + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + 0.000 + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + 0.250 + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + 0.250 + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + 0.500 + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + 0.500 + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + 0.750 + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + 0.750 + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + 1.000 + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + 1.000 + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + + + + + 1 + 1 + + + + + 100 + 100 + + + + + 10 + 10 + + + + + 100 + 100 + + + + Qt::LeftToRight + + + Throttle Curve + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + 0 + + + 0 + + + + + + 1 + 1 + + + + + 50 + 50 + + + + + 1000 + 1000 + + + + + 10 + 10 + + + + + 200 + 200 + + + + + + + + + + + + 1 + 1 + + + + + 100 + 100 + + + + + 10 + 10 + + + + + 100 + 100 + + + + Pitch Curve + + + + 0 + + + 0 + + + + + + 1 + 1 + + + + + 50 + 50 + + + + + 1000 + 1000 + + + + + 10 + 10 + + + + + 200 + 200 + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 0 + + + + + + + + + Advanced settings + + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 0 + 200 + + + + + 1000 + 300 + + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + true + + + true + + + QAbstractItemView::NoSelection + + + false + + + true + + + 75 + + + 20 + + + + Engine + + + + + Tail Rotor + + + + + Servo W + + + + + Servo X + + + + + Servo Y + + + + + Servo Z + + + + + Channel + + + + + Curve 1 + + + + + Curve 2 + + + + + Roll + + + + + Pitch + + + + + Yaw + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + - + + + AlignHCenter|AlignVCenter|AlignCenter + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 40 + + + + + + + + + + + + + + + MixerCurveWidget + QWidget +
mixercurvewidget.h
+ 1 +
+
+ + ccpmType + TabObject + ccpmEngineChannel + ccpmTailChannel + ccpmServoWChannel + ccpmServoXChannel + ccpmServoYChannel + ccpmServoZChannel + ccpmSingleServo + ccpmAngleW + ccpmAngleX + ccpmAngleY + ccpmAngleZ + ccpmCorrectionAngle + ccpmRevoSlider + ccpmREVOspinBox + ccpmCollectiveSlider + ccpmCollectivespinBox + SwashplateImage + SwashLvlStartButton + SwashLvlNextButton + SwashLvlStepInstruction + SwashLvlCancelButton + SwashLvlFinishButton + SwashLvlStepList + SwashLvlPositionSlider + SwashLvlPositionSpinBox + SwashLvlSwashplateImage + CurveType + NumCurvePoints + CurveValue1 + CurveValue2 + CurveValue3 + CurveToGenerate + ccpmGenerateCurve + CurveSettings + ccpmAdvancedSettingsTable + + + + + ccpmCollectiveSlider + sliderMoved(int) + ccpmCollectivespinBox + setValue(int) + + + 261 + 496 + + + 269 + 546 + + + + + ccpmCollectivespinBox + valueChanged(int) + ccpmCollectiveSlider + setValue(int) + + + 269 + 546 + + + 261 + 511 + + + + + ccpmREVOspinBox + valueChanged(int) + ccpmRevoSlider + setValue(int) + + + 216 + 546 + + + 208 + 511 + + + + + ccpmRevoSlider + sliderMoved(int) + ccpmREVOspinBox + setValue(int) + + + 208 + 412 + + + 216 + 546 + + + + + SwashLvlPositionSlider + sliderMoved(int) + SwashLvlPositionSpinBox + setValue(int) + + + 276 + 486 + + + 270 + 537 + + + + + SwashLvlPositionSpinBox + valueChanged(int) + SwashLvlPositionSlider + setValue(int) + + + 301 + 546 + + + 277 + 401 + + + + + ccpmCollectiveScaleBox + valueChanged(int) + ccpmCollectiveScale + setValue(int) + + + 296 + 534 + + + 306 + 480 + + + + + ccpmCollectiveScale + sliderMoved(int) + ccpmCollectiveScaleBox + setValue(int) + + + 308 + 328 + + + 292 + 534 + + + + + ccpmCyclicScale + sliderMoved(int) + ccpmCyclicScaleBox + setValue(int) + + + 358 + 306 + + + 355 + 538 + + + + + ccpmCyclicScaleBox + valueChanged(int) + ccpmCyclicScale + setValue(int) + + + 341 + 538 + + + 351 + 376 + + + + + ccpmPitchScale + sliderMoved(int) + ccpmPitchScaleBox + setValue(int) + + + 417 + 306 + + + 406 + 531 + + + + + ccpmPitchScaleBox + valueChanged(int) + ccpmPitchScale + setValue(int) + + + 394 + 531 + + + 408 + 302 + + + + + ccpmRollScaleBox + valueChanged(int) + ccpmRollScale + setValue(int) + + + 455 + 529 + + + 458 + 466 + + + + + ccpmRollScale + sliderMoved(int) + ccpmRollScaleBox + setValue(int) + + + 461 + 388 + + + 474 + 533 + + + + +
diff --git a/ground/openpilotgcs/src/plugins/config/config.pro b/ground/openpilotgcs/src/plugins/config/config.pro index 4918feb53..c1c4b7e0e 100644 --- a/ground/openpilotgcs/src/plugins/config/config.pro +++ b/ground/openpilotgcs/src/plugins/config/config.pro @@ -24,7 +24,8 @@ HEADERS += configplugin.h \ configoutputwidget.h \ configtaskwidget.h \ configairframewidget.h \ - configtelemetrywidget.h \ + config_pro_hw_widget.h \ + config_cc_hw_widget.h \ configahrswidget.h \ configccattitudewidget.h \ mixercurvewidget.h \ @@ -34,7 +35,10 @@ HEADERS += configplugin.h \ configstabilizationwidget.h \ assertions.h \ calibration.h \ - defaultattitudewidget.h + defaultattitudewidget.h \ + smartsavebutton.h \ + defaulthwsettingswidget.h \ + configcamerastabilizationwidget.h SOURCES += configplugin.cpp \ configgadgetconfiguration.cpp \ @@ -47,7 +51,8 @@ SOURCES += configplugin.cpp \ configinputwidget.cpp \ configoutputwidget.cpp \ configairframewidget.cpp \ - configtelemetrywidget.cpp \ + config_pro_hw_widget.cpp \ + config_cc_hw_widget.cpp \ configahrswidget.cpp \ configccattitudewidget.cpp \ mixercurvewidget.cpp \ @@ -59,17 +64,27 @@ SOURCES += configplugin.cpp \ legacy-calibration.cpp \ gyro-calibration.cpp \ alignment-calibration.cpp \ - defaultattitudewidget.cpp + defaultattitudewidget.cpp \ + smartsavebutton.cpp \ + defaulthwsettingswidget.cpp \ + configcamerastabilizationwidget.cpp FORMS += \ airframe.ui \ - telemetry.ui \ + cc_hw_settings.ui \ + pro_hw_settings.ui \ ahrs.ui \ ccpm.ui \ stabilization.ui \ input.ui \ output.ui \ ccattitude.ui \ - defaultattitude.ui + defaultattitude.ui \ + defaulthwsettings.ui \ + camerastabilization.ui RESOURCES += configgadget.qrc + + + + diff --git a/ground/openpilotgcs/src/plugins/config/config_cc_hw_widget.cpp b/ground/openpilotgcs/src/plugins/config/config_cc_hw_widget.cpp new file mode 100644 index 000000000..e5adf27f1 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/config_cc_hw_widget.cpp @@ -0,0 +1,102 @@ +/** + ****************************************************************************** + * + * @file configtelemetrywidget.h + * @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief The Configuration Gadget used to update settings in the firmware + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "config_cc_hw_widget.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +ConfigCCHWWidget::ConfigCCHWWidget(QWidget *parent) : ConfigTaskWidget(parent) +{ + m_telemetry = new Ui_CC_HW_Widget(); + m_telemetry->setupUi(this); + setupButtons(m_telemetry->saveTelemetryToRAM,m_telemetry->saveTelemetryToSD); + addUAVObjectToWidgetRelation("TelemetrySettings","Speed",m_telemetry->telemetrySpeed); + addUAVObjectToWidgetRelation("HwSettings","CC_FlexiPort",m_telemetry->cbFlexi); + addUAVObjectToWidgetRelation("HwSettings","CC_MainPort",m_telemetry->cbTele); + addUAVObjectToWidgetRelation("ManualControlSettings","InputMode",m_telemetry->receiverType); + connect(m_telemetry->cchwHelp,SIGNAL(clicked()),this,SLOT(openHelp())); + enableControls(false); + populateWidgets(); + refreshWidgetsValues(); +} + +ConfigCCHWWidget::~ConfigCCHWWidget() +{ + // Do nothing +} + +void ConfigCCHWWidget::refreshValues() +{ +} + +void ConfigCCHWWidget::widgetsContentsChanged() +{ + ConfigTaskWidget::widgetsContentsChanged(); + enableControls(false); + if((m_telemetry->cbFlexi->currentText()==m_telemetry->cbTele->currentText()) && m_telemetry->cbTele->currentText()!="Disabled") + { + m_telemetry->problems->setText("Warning: you have configured the MainPort and the FlexiPort for the same function, this is currently not suported"); + } + else if((m_telemetry->cbTele->currentText()=="Spektrum" ||m_telemetry->cbFlexi->currentText()=="Spektrum") && m_telemetry->receiverType->currentText()!="Spektrum") + { + m_telemetry->problems->setText("Warning: you have a port configured as 'Spektrum' however that is not your selected receiver type"); + } + else if(m_telemetry->cbTele->currentText()=="S.Bus" && m_telemetry->receiverType->currentText()!="S.Bus") + { + m_telemetry->problems->setText("Warning: you have a port configured as 'S.Bus' however that is not your selected receiver type"); + } + else if(m_telemetry->cbTele->currentText()!="S.Bus" && m_telemetry->receiverType->currentText()=="S.Bus") + { + m_telemetry->problems->setText("Warning: you have selected 'S.Bus' as your receiver type however you have no port configured for that protocol"); + } + else if((m_telemetry->cbTele->currentText()!="Spektrum" && m_telemetry->cbFlexi->currentText()!="Spektrum") && m_telemetry->receiverType->currentText()=="Spektrum") + { + m_telemetry->problems->setText("Warning: you have selected 'Spektrum' as your receiver type however you have no port configured for that protocol"); + } + else + { + m_telemetry->problems->setText(""); + enableControls(true); + } +} + +void ConfigCCHWWidget::openHelp() +{ + QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/CopterControl+HW+Settings", QUrl::StrictMode) ); +} + +/** + * @} + * @} + */ + diff --git a/ground/openpilotgcs/src/plugins/config/config_cc_hw_widget.h b/ground/openpilotgcs/src/plugins/config/config_cc_hw_widget.h new file mode 100644 index 000000000..f815786fb --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/config_cc_hw_widget.h @@ -0,0 +1,55 @@ +/** + ****************************************************************************** + * + * @file configtelemetrytwidget.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief Telemetry configuration panel + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef CONFIGCCHWWIDGET_H +#define CONFIGCCHWWIDGET_H + +#include "ui_cc_hw_settings.h" +#include "configtaskwidget.h" +#include "extensionsystem/pluginmanager.h" +#include "uavobjectmanager.h" +#include "uavobject.h" +#include +#include +#include "smartsavebutton.h" + +class ConfigCCHWWidget: public ConfigTaskWidget +{ + Q_OBJECT + +public: + ConfigCCHWWidget(QWidget *parent = 0); + ~ConfigCCHWWidget(); +private slots: + void openHelp(); + void refreshValues(); + void widgetsContentsChanged(); + +private: + Ui_CC_HW_Widget *m_telemetry; +}; + +#endif // CONFIGCCHWWIDGET_H diff --git a/ground/openpilotgcs/src/plugins/config/config_pro_hw_widget.cpp b/ground/openpilotgcs/src/plugins/config/config_pro_hw_widget.cpp new file mode 100644 index 000000000..b3f562acd --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/config_pro_hw_widget.cpp @@ -0,0 +1,60 @@ +/** + ****************************************************************************** + * + * @file configtelemetrywidget.h + * @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief The Configuration Gadget used to update settings in the firmware + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "config_pro_hw_widget.h" + +#include +#include +#include +#include +#include +#include + + +ConfigProHWWidget::ConfigProHWWidget(QWidget *parent) : ConfigTaskWidget(parent) +{ + m_telemetry = new Ui_PRO_HW_Widget(); + m_telemetry->setupUi(this); + + setupButtons(m_telemetry->saveTelemetryToRAM,m_telemetry->saveTelemetryToSD); + addUAVObjectToWidgetRelation("TelemetrySettings","Speed",m_telemetry->telemetrySpeed); + enableControls(false); + populateWidgets(); + refreshWidgetsValues(); +} + +ConfigProHWWidget::~ConfigProHWWidget() +{ + // Do nothing +} + + +/** + Request telemetry settings from the board + */ +void ConfigProHWWidget::refreshValues() +{ +} diff --git a/ground/openpilotgcs/src/plugins/config/configtelemetrywidget.h b/ground/openpilotgcs/src/plugins/config/config_pro_hw_widget.h similarity index 77% rename from ground/openpilotgcs/src/plugins/config/configtelemetrywidget.h rename to ground/openpilotgcs/src/plugins/config/config_pro_hw_widget.h index 3f38eef3b..fbf35b9bd 100644 --- a/ground/openpilotgcs/src/plugins/config/configtelemetrywidget.h +++ b/ground/openpilotgcs/src/plugins/config/config_pro_hw_widget.h @@ -24,10 +24,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef CONFIGTELEMETRYWIDGET_H -#define CONFIGTELEMETRYWIDGET_H +#ifndef CONFIGPROHWWIDGET_H +#define CONFIGPROHWWIDGET_H -#include "ui_telemetry.h" +#include "ui_pro_hw_settings.h" #include "configtaskwidget.h" #include "extensionsystem/pluginmanager.h" #include "uavobjectmanager.h" @@ -36,22 +36,20 @@ #include -class ConfigTelemetryWidget: public ConfigTaskWidget +class ConfigProHWWidget: public ConfigTaskWidget { Q_OBJECT public: - ConfigTelemetryWidget(QWidget *parent = 0); - ~ConfigTelemetryWidget(); + ConfigProHWWidget(QWidget *parent = 0); + ~ConfigProHWWidget(); private: - Ui_TelemetryWidget *m_telemetry; + Ui_PRO_HW_Widget *m_telemetry; private slots: - void requestTelemetryUpdate(); - void sendTelemetryUpdate(); - void saveTelemetryUpdate(); + virtual void refreshValues(); }; -#endif // ConfigTelemetryWidget_H +#endif // CONFIGPROHWWIDGET_H diff --git a/ground/openpilotgcs/src/plugins/config/configahrswidget.cpp b/ground/openpilotgcs/src/plugins/config/configahrswidget.cpp index 577167dda..75cb57f78 100644 --- a/ground/openpilotgcs/src/plugins/config/configahrswidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configahrswidget.cpp @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include "assertions.h" #include "calibration.h" @@ -214,20 +216,28 @@ ConfigAHRSWidget::ConfigAHRSWidget(QWidget *parent) : ConfigTaskWidget(parent) // Connect the signals connect(m_ahrs->ahrsCalibStart, SIGNAL(clicked()), this, SLOT(launchAHRSCalibration())); connect(m_ahrs->accelBiasStart, SIGNAL(clicked()), this, SLOT(launchAccelBiasCalibration())); - connect(m_ahrs->ahrsSettingsRequest, SIGNAL(clicked()), this, SLOT(ahrsSettingsRequest())); - /* - connect(m_ahrs->algorithm, SIGNAL(currentIndexChanged(int)), this, SLOT(ahrsSettingsSave())); - connect(m_ahrs->indoorFlight, SIGNAL(stateChanged(int)), this, SLOT(homeLocationSave())); - connect(m_ahrs->homeLocation, SIGNAL(clicked()), this, SLOT(homeLocationSaveSD())); - */ + + obj = dynamic_cast(getObjectManager()->getObject(QString("AHRSSettings"))); + connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshValues())); + obj = getObjectManager()->getObject(QString("HomeLocation")); + connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshValues())); + connect(m_ahrs->ahrsSettingsSaveRAM, SIGNAL(clicked()), this, SLOT(ahrsSettingsSaveRAM())); connect(m_ahrs->ahrsSettingsSaveSD, SIGNAL(clicked()), this, SLOT(ahrsSettingsSaveSD())); connect(m_ahrs->sixPointsStart, SIGNAL(clicked()), this, SLOT(multiPointCalibrationMode())); connect(m_ahrs->sixPointsSave, SIGNAL(clicked()), this, SLOT(savePositionData())); connect(m_ahrs->startDriftCalib, SIGNAL(clicked()),this, SLOT(launchGyroDriftCalibration())); - connect(parent, SIGNAL(autopilotConnected()),this, SLOT(ahrsSettingsRequest())); + // Order is important: 1st request the settings (it will also enable the controls) + // then explicitely disable them. They will be re-enabled right afterwards by the + // configgadgetwidget if the autopilot is actually connected. + refreshValues(); + // when the AHRS Widget is instanciated, the autopilot is always connected // enableControls(false); + connect(parent, SIGNAL(autopilotConnected()),this, SLOT(onAutopilotConnect())); + connect(parent, SIGNAL(autopilotDisconnected()), this, SLOT(onAutopilotDisconnect())); + // Connect the help button + connect(m_ahrs->ahrsHelp, SIGNAL(clicked()), this, SLOT(openHelp())); } ConfigAHRSWidget::~ConfigAHRSWidget() @@ -253,6 +263,13 @@ void ConfigAHRSWidget::resizeEvent(QResizeEvent *event) m_ahrs->sixPointsHelp->fitInView(paperplane,Qt::KeepAspectRatio); } + +void ConfigAHRSWidget::enableControls(bool enable) +{ + //m_ahrs->ahrsSettingsSaveRAM->setEnabled(enable); + m_ahrs->ahrsSettingsSaveSD->setEnabled(enable); +} + /** Starts an accelerometer bias calibration. */ @@ -271,7 +288,7 @@ void ConfigAHRSWidget::launchAccelBiasCalibration() accel_accum_y.clear(); accel_accum_z.clear(); - UAVDataObject* ahrsCalib = dynamic_cast(getObjectManager()->getObject(QString("AHRSCalibration"))); +// UAVDataObject* ahrsCalib = dynamic_cast(getObjectManager()->getObject(QString("AHRSCalibration"))); // ahrsCalib->getField("accel_bias")->setDouble(0,0); // ahrsCalib->getField("accel_bias")->setDouble(0,1); // ahrsCalib->getField("accel_bias")->setDouble(0,2); @@ -406,6 +423,7 @@ void ConfigAHRSWidget::launchGyroDriftCalibration() */ void ConfigAHRSWidget::driftCalibrationAttitudeRawUpdated(UAVObject* obj) { + Q_UNUSED(obj) // This is necessary to prevent a race condition on disconnect signal and another update if (collectingData == true) { /** @@ -565,8 +583,7 @@ void ConfigAHRSWidget::saveAHRSCalibration() UAVObjectField *field = obj->getField(QString("measure_var")); field->setValue("SET"); obj->updated(); - updateObjectPersistance(ObjectPersistence::OPERATION_SAVE, obj); - + saveObjectToSD(obj); } FORCE_ALIGN_FUNC @@ -1133,17 +1150,16 @@ void ConfigAHRSWidget::drawVariancesGraph() /** Request current settings from the AHRS */ -void ConfigAHRSWidget::ahrsSettingsRequest() +void ConfigAHRSWidget::refreshValues() { - UAVObject *obj = dynamic_cast(getObjectManager()->getObject(QString("AHRSSettings"))); - obj->requestUpdate(); + UAVObject *obj = getObjectManager()->getObject(QString("AHRSSettings")); UAVObjectField *field = obj->getField(QString("Algorithm")); if (field) m_ahrs->algorithm->setCurrentIndex(m_ahrs->algorithm->findText(field->getValue().toString())); drawVariancesGraph(); - obj = dynamic_cast(getObjectManager()->getObject(QString("HomeLocation"))); + obj = getObjectManager()->getObject(QString("HomeLocation")); field = obj->getField(QString("Set")); if (field) m_ahrs->homeLocationSet->setEnabled(field->getValue().toBool()); @@ -1203,6 +1219,11 @@ void ConfigAHRSWidget::ahrsSettingsSaveSD() } +void ConfigAHRSWidget::openHelp() +{ + + QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/INS+Configuration", QUrl::StrictMode) ); +} /** @} diff --git a/ground/openpilotgcs/src/plugins/config/configahrswidget.h b/ground/openpilotgcs/src/plugins/config/configahrswidget.h index 8cfaf041e..23da6f242 100644 --- a/ground/openpilotgcs/src/plugins/config/configahrswidget.h +++ b/ground/openpilotgcs/src/plugins/config/configahrswidget.h @@ -55,6 +55,7 @@ public: private: void drawVariancesGraph(); void displayPlane(QString elementID); + virtual void enableControls(bool enable); Ui_AHRSWidget *m_ahrs; QGraphicsSvgItem *paperplane; @@ -126,10 +127,13 @@ private slots: void enableHomeLocSave(UAVObject *obj); void launchAHRSCalibration(); void saveAHRSCalibration(); + void openHelp(); void launchAccelBiasCalibration(); void calibPhase2(); void incrementProgress(); - void ahrsSettingsRequest(); + + virtual void refreshValues(); + //void ahrsSettingsRequest(); void ahrsSettingsSaveRAM(); void ahrsSettingsSaveSD(); void savePositionData(); diff --git a/ground/openpilotgcs/src/plugins/config/configairframewidget.cpp b/ground/openpilotgcs/src/plugins/config/configairframewidget.cpp index 24d74ddcd..dcf743915 100644 --- a/ground/openpilotgcs/src/plugins/config/configairframewidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configairframewidget.cpp @@ -34,6 +34,8 @@ #include #include #include +#include +#include /** Helper delegate for the custom mixer editor table. @@ -89,6 +91,32 @@ ConfigAirframeWidget::ConfigAirframeWidget(QWidget *parent) : ConfigTaskWidget(p m_aircraft = new Ui_AircraftWidget(); m_aircraft->setupUi(this); + setupButtons(m_aircraft->saveAircraftToRAM,m_aircraft->saveAircraftToSD); + addWidget(m_aircraft->customMixerTable); + addWidget(m_aircraft->customThrottle2Curve); + addWidget(m_aircraft->customThrottle1Curve); + addWidget(m_aircraft->multiThrottleCurve); + addWidget(m_aircraft->fixedWingThrottle); + addWidget(m_aircraft->fixedWingType); + addWidget(m_aircraft->feedForwardSlider); + addWidget(m_aircraft->accelTime); + addWidget(m_aircraft->decelTime); + addWidget(m_aircraft->maxAccelSlider); + addWidget(m_aircraft->multirotorFrameType); + addWidget(m_aircraft->multiMotor1); + addWidget(m_aircraft->multiMotor2); + addWidget(m_aircraft->multiMotor3); + addWidget(m_aircraft->multiMotor4); + addWidget(m_aircraft->multiMotor5); + addWidget(m_aircraft->multiMotor6); + addWidget(m_aircraft->multiMotor7); + addWidget(m_aircraft->multiMotor8); + addWidget(m_aircraft->triYawChannel); + addUAVObject("SystemSettings"); + addUAVObject("MixerSettings"); + addUAVObject("ActuatorSettings"); + + ffTuningInProgress = false; ffTuningPhase = false; @@ -162,16 +190,9 @@ ConfigAirframeWidget::ConfigAirframeWidget(QWidget *parent) : ConfigTaskWidget(p m_aircraft->customMixerTable->setItemDelegateForRow(i, sbd); } - connect(m_aircraft->saveAircraftToSD, SIGNAL(clicked()), this, SLOT(saveAircraftUpdate())); - connect(m_aircraft->saveAircraftToRAM, SIGNAL(clicked()), this, SLOT(sendAircraftUpdate())); - connect(m_aircraft->getAircraftCurrent, SIGNAL(clicked()), this, SLOT(requestAircraftUpdate())); - connect(m_aircraft->ffSave, SIGNAL(clicked()), this, SLOT(saveAircraftUpdate())); - connect(m_aircraft->ffApply, SIGNAL(clicked()), this, SLOT(sendAircraftUpdate())); - connect(m_aircraft->ffGetCurrent, SIGNAL(clicked()), this, SLOT(requestAircraftUpdate())); connect(m_aircraft->fixedWingType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString))); connect(m_aircraft->multirotorFrameType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString))); connect(m_aircraft->aircraftType, SIGNAL(currentIndexChanged(int)), this, SLOT(switchAirframeType(int))); - requestAircraftUpdate(); connect(m_aircraft->fwThrottleReset, SIGNAL(clicked()), this, SLOT(resetFwMixer())); connect(m_aircraft->mrThrottleCurveReset, SIGNAL(clicked()), this, SLOT(resetMrMixer())); @@ -190,7 +211,12 @@ ConfigAirframeWidget::ConfigAirframeWidget(QWidget *parent) : ConfigTaskWidget(p connect(m_aircraft->ffTestBox2, SIGNAL(clicked(bool)), this, SLOT(enableFFTest())); connect(m_aircraft->ffTestBox3, SIGNAL(clicked(bool)), this, SLOT(enableFFTest())); - connect(parent, SIGNAL(autopilotConnected()),this, SLOT(requestAircraftUpdate())); + enableControls(false); + refreshWidgetsValues(); + + + // Connect the help button + connect(m_aircraft->airframeHelp, SIGNAL(clicked()), this, SLOT(openHelp())); } @@ -348,7 +374,7 @@ void ConfigAirframeWidget::resetFwMixer() { UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); UAVObjectField* field = obj->getField(QString("ThrottleCurve1")); - resetMixer(m_aircraft->fixedWingThrottle, field->getNumElements()); + resetMixer(m_aircraft->fixedWingThrottle, field->getNumElements(),1); } /** @@ -358,7 +384,7 @@ void ConfigAirframeWidget::resetMrMixer() { UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); UAVObjectField* field = obj->getField(QString("ThrottleCurve1")); - resetMixer(m_aircraft->multiThrottleCurve, field->getNumElements()); + resetMixer(m_aircraft->multiThrottleCurve, field->getNumElements(),0.9); } /** @@ -368,7 +394,7 @@ void ConfigAirframeWidget::resetCt1Mixer() { UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); UAVObjectField* field = obj->getField(QString("ThrottleCurve1")); - resetMixer(m_aircraft->customThrottle1Curve, field->getNumElements()); + resetMixer(m_aircraft->customThrottle1Curve, field->getNumElements(),1); } /** @@ -378,21 +404,17 @@ void ConfigAirframeWidget::resetCt2Mixer() { UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); UAVObjectField* field = obj->getField(QString("ThrottleCurve2")); - resetMixer(m_aircraft->customThrottle2Curve, field->getNumElements()); + resetMixer(m_aircraft->customThrottle2Curve, field->getNumElements(),1); } /** Resets a mixer curve */ -void ConfigAirframeWidget::resetMixer(MixerCurveWidget *mixer, int numElements) +void ConfigAirframeWidget::resetMixer(MixerCurveWidget *mixer, int numElements, double maxvalue) { - QList curveValues; - for (double i=0; iinitCurve(curveValues); + mixer->initLinearCurve((quint32)numElements,maxvalue); } /** @@ -436,14 +458,13 @@ void ConfigAirframeWidget::updateCustomThrottle2CurveValue(QList list, d * Aircraft settings **************************/ /** - Request the current value of the SystemSettings which holds the aircraft type + Refreshes the current value of the SystemSettings which holds the aircraft type */ -void ConfigAirframeWidget::requestAircraftUpdate() +void ConfigAirframeWidget::refreshWidgetsValues() { // Get the Airframe type from the system settings: UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("SystemSettings"))); Q_ASSERT(obj); - obj->requestUpdate(); UAVObjectField *field = obj->getField(QString("AirframeType")); Q_ASSERT(field); // At this stage, we will need to have some hardcoded settings in this code, this @@ -453,25 +474,35 @@ void ConfigAirframeWidget::requestAircraftUpdate() obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); Q_ASSERT(obj); - obj->requestUpdate(); field = obj->getField(QString("ThrottleCurve1")); Q_ASSERT(field); QList curveValues; // If the 1st element of the curve is <= -10, then the curve // is a straight line (that's how the mixer works on the mainboard): if (field->getValue(0).toInt() <= -10) { - for (double i=0; igetNumElements(); i++) { - curveValues.append(i/(field->getNumElements()-1)); - } - } else { + m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),(double)1); + m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1); + } + else { + double temp=0; + double value; for (unsigned int i=0; i < field->getNumElements(); i++) { - curveValues.append(field->getValue(i).toDouble()); + value=field->getValue(i).toDouble(); + temp+=value; + curveValues.append(value); + } + if(temp==0) + { + m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),0.9);; + m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1); + } + else + { + m_aircraft->multiThrottleCurve->initCurve(curveValues); + m_aircraft->fixedWingThrottle->initCurve(curveValues); } } // Setup all Throttle1 curves for all types of airframes - m_aircraft->fixedWingThrottle->initCurve(curveValues); - m_aircraft->multiThrottleCurve->initCurve(curveValues); - // Load the Settings for fixed wing frames: if (frameType.startsWith("FixedWing")) { // Then retrieve how channels are setup @@ -634,10 +665,13 @@ void ConfigAirframeWidget::requestAircraftUpdate() val = floor(-field->getDouble(i)/1.27); m_aircraft->mrYawMixLevel->setValue(val); eng = m_aircraft->multiMotor2->currentIndex()-1; - field = obj->getField(mixerVectors.at(eng)); - i = field->getElementNames().indexOf("Roll"); - val = floor(1-field->getDouble(i)/1.27); - m_aircraft->mrRollMixLevel->setValue(val); + if(eng>-1) + { + field = obj->getField(mixerVectors.at(eng)); + i = field->getElementNames().indexOf("Roll"); + val = floor(1-field->getDouble(i)/1.27); + m_aircraft->mrRollMixLevel->setValue(val); + } } } else if (frameType == "HexaX") { // Motors 1/2/3 4/5/6 are: NE / E / SE / SW / W / NW @@ -1520,7 +1554,7 @@ bool ConfigAirframeWidget::setupMixer(double mixerFactors[8][3]) setupQuadMotor(channel, mixerFactors[i][0]*pFactor, rFactor*mixerFactors[i][1], yFactor*mixerFactors[i][2]); } - obj->updated(); +// obj->updated(); return true; } @@ -1564,7 +1598,7 @@ void ConfigAirframeWidget::setupMotors(QList motorList) field = obj->getField(motor); field->setValue(mmList.takeFirst()->currentText()); } - obj->updated(); // Save... + //obj->updated(); // Save... } @@ -1730,40 +1764,32 @@ void ConfigAirframeWidget::updateCustomAirframeUI() // If the 1st element of the curve is <= -10, then the curve // is a straight line (that's how the mixer works on the mainboard): if (field->getValue(0).toInt() <= -10) { - for (double i=0; igetNumElements(); i++) { - curveValues.append(i/(field->getNumElements()-1)); - } + m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1); } else { + double temp=0; + double value; for (unsigned int i=0; i < field->getNumElements(); i++) { - curveValues.append(field->getValue(i).toDouble()); + value=field->getValue(i).toDouble(); + temp+=value; + curveValues.append(value); } + if(temp==0) + m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1); + else + m_aircraft->customThrottle1Curve->initCurve(curveValues); } - m_aircraft->customThrottle1Curve->initCurve(curveValues); - field = obj->getField(QString("ThrottleCurve2")); curveValues.clear();; // If the 1st element of the curve is <= -10, then the curve // is a straight line (that's how the mixer works on the mainboard): if (field->getValue(0).toInt() <= -10) { - for (double i=0; igetNumElements(); i++) { - curveValues.append(i/(field->getNumElements()-1)); - } + m_aircraft->customThrottle2Curve->initLinearCurve(field->getNumElements(),(double)1); } else { for (unsigned int i=0; i < field->getNumElements(); i++) { curveValues.append(field->getValue(i).toDouble()); } + m_aircraft->customThrottle2Curve->initCurve(curveValues); } - m_aircraft->customThrottle2Curve->initCurve(curveValues); - - // Retrieve Feed Forward: - field = obj->getField(QString("FeedForward")); - m_aircraft->customFFSlider->setValue(field->getDouble()*100); - field = obj->getField(QString("AccelTime")); - m_aircraft->customFFaccel->setValue(field->getDouble()); - field = obj->getField(QString("DecelTime")); - m_aircraft->customFFdecel->setValue(field->getDouble()); - field = obj->getField(QString("MaxAccel")); - m_aircraft->customFFMaxAccel->setValue(field->getDouble()); // Update the table: for (int i=0; i<8; i++) { @@ -1794,8 +1820,9 @@ void ConfigAirframeWidget::updateCustomAirframeUI() we call additional methods for specific frames, so that we do not have a code that is too heavy. */ -void ConfigAirframeWidget::sendAircraftUpdate() +void ConfigAirframeWidget::updateObjectsFromWidgets() { + qDebug()<<"updateObjectsFromWidgets"; QString airframeType = "Custom"; if (m_aircraft->aircraftType->currentText() == "Fixed Wing") { // Save the curve (common to all Fixed wing frames) @@ -2022,14 +2049,12 @@ void ConfigAirframeWidget::sendAircraftUpdate() m_aircraft->mrStatusLabel->setText("Error: Assign a Yaw channel"); return; } + motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorS"; + setupMotors(motorList); obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); Q_ASSERT(obj); field = obj->getField("FixedWingYaw1"); field->setValue(m_aircraft->triYawChannel->currentText()); - // No need to send a obj->updated() here because setupMotors - // will do it. - motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorS"; - setupMotors(motorList); // Motor 1 to 6, Y6 Layout: // pitch roll yaw @@ -2068,13 +2093,6 @@ void ConfigAirframeWidget::sendAircraftUpdate() UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); UAVObjectField* field = obj->getField(QString("FeedForward")); - field->setDouble((double)m_aircraft->customFFSlider->value()/100); - field = obj->getField(QString("AccelTime")); - field->setDouble(m_aircraft->customFFaccel->value()); - field = obj->getField(QString("DecelTime")); - field->setDouble(m_aircraft->customFFdecel->value()); - field = obj->getField(QString("MaxAccel")); - field->setDouble(m_aircraft->customFFMaxAccel->value()); // Curve is also common to all quads: field = obj->getField("ThrottleCurve1"); @@ -2108,29 +2126,16 @@ void ConfigAirframeWidget::sendAircraftUpdate() field->setValue(m_aircraft->customMixerTable->item(5,i)->text(),ti); } - obj->updated(); } - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("SystemSettings"))); UAVObjectField* field = obj->getField(QString("AirframeType")); field->setValue(airframeType); - obj->updated(); + } -/** - Send airframe type to the board and request saving to SD card - */ -void ConfigAirframeWidget::saveAircraftUpdate() +void ConfigAirframeWidget::openHelp() { - // Send update so that the latest value is saved - sendAircraftUpdate(); - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("SystemSettings"))); - Q_ASSERT(obj); - saveObjectToSD(obj); - obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); - saveObjectToSD(obj); - obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); - saveObjectToSD(obj); + QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Airframe+configuration", QUrl::StrictMode) ); } diff --git a/ground/openpilotgcs/src/plugins/config/configairframewidget.h b/ground/openpilotgcs/src/plugins/config/configairframewidget.h index cbc8b1fc8..234a114c1 100644 --- a/ground/openpilotgcs/src/plugins/config/configairframewidget.h +++ b/ground/openpilotgcs/src/plugins/config/configairframewidget.h @@ -32,6 +32,7 @@ #include "extensionsystem/pluginmanager.h" #include "uavobjectmanager.h" #include "uavobject.h" +#include "uavtalk/telemetrymanager.h" #include #include #include @@ -59,7 +60,7 @@ private: void setupMotors(QList motorList); void resetField(UAVObjectField * field); - void resetMixer (MixerCurveWidget *mixer, int numElements); + void resetMixer (MixerCurveWidget *mixer, int numElements, double maxvalue); void resetActuators(); //void setMixerChannel(int channelNumber, bool channelIsMotor, QList vector); void setupQuadMotor(int channel, double roll, double pitch, double yaw); @@ -72,9 +73,9 @@ private: UAVObject::Metadata accInitialData; private slots: - void requestAircraftUpdate(); - void sendAircraftUpdate(); - void saveAircraftUpdate(); + virtual void refreshWidgetsValues(); + void updateObjectsFromWidgets(); + // void saveAircraftUpdate(); void setupAirframeUI(QString type); void toggleAileron2(int index); void toggleElevator2(int index); @@ -89,6 +90,7 @@ private slots: void updateCustomThrottle1CurveValue(QList list, double value); void updateCustomThrottle2CurveValue(QList list, double value); void enableFFTest(); + void openHelp(); protected: void showEvent(QShowEvent *event); diff --git a/ground/openpilotgcs/src/plugins/config/configcamerastabilizationwidget.cpp b/ground/openpilotgcs/src/plugins/config/configcamerastabilizationwidget.cpp new file mode 100644 index 000000000..afbdae760 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/configcamerastabilizationwidget.cpp @@ -0,0 +1,237 @@ +/** + ****************************************************************************** + * + * @file configcamerastabilizationwidget.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief The Configuration Gadget used to update settings in the firmware + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "configcamerastabilizationwidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "camerastabsettings.h" +#include "hwsettings.h" +#include "mixersettings.h" + +ConfigCameraStabilizationWidget::ConfigCameraStabilizationWidget(QWidget *parent) : ConfigTaskWidget(parent) +{ + m_camerastabilization = new Ui_CameraStabilizationWidget(); + m_camerastabilization->setupUi(this); + + connectUpdates(); + + // Connect buttons + connect(m_camerastabilization->camerastabilizationSaveRAM,SIGNAL(clicked()),this,SLOT(applySettings())); + connect(m_camerastabilization->camerastabilizationSaveSD,SIGNAL(clicked()),this,SLOT(saveSettings())); + connect(m_camerastabilization->camerastabilizationHelp, SIGNAL(clicked()), this, SLOT(openHelp())); +} + +ConfigCameraStabilizationWidget::~ConfigCameraStabilizationWidget() +{ + // Do nothing +} + +void ConfigCameraStabilizationWidget::connectUpdates() +{ + // Now connect the widget to the StabilizationSettings object + connect(MixerSettings::GetInstance(getObjectManager()),SIGNAL(objectUpdated(UAVObject*)),this,SLOT(refreshValues())); + connect(CameraStabSettings::GetInstance(getObjectManager()),SIGNAL(objectUpdated(UAVObject*)),this,SLOT(refreshValues())); + // TODO: This will need to support both CC and OP later + connect(HwSettings::GetInstance(getObjectManager()),SIGNAL(objectUpdated(UAVObject*)),this,SLOT(refreshValues())); +} + +void ConfigCameraStabilizationWidget::disconnectUpdates() +{ + // Now connect the widget to the StabilizationSettings object + disconnect(MixerSettings::GetInstance(getObjectManager()),SIGNAL(objectUpdated(UAVObject*)),this,SLOT(refreshValues())); + disconnect(CameraStabSettings::GetInstance(getObjectManager()),SIGNAL(objectUpdated(UAVObject*)),this,SLOT(refreshValues())); + // TODO: This will need to support both CC and OP later + disconnect(HwSettings::GetInstance(getObjectManager()),SIGNAL(objectUpdated(UAVObject*)),this,SLOT(refreshValues())); +} + +/** + * @brief Populate the gui settings into the appropriate + * UAV structures + */ +void ConfigCameraStabilizationWidget::applySettings() +{ + // Enable or disable the settings + HwSettings * hwSettings = HwSettings::GetInstance(getObjectManager()); + HwSettings::DataFields hwSettingsData = hwSettings->getData(); + hwSettingsData.OptionalModules[HwSettings::OPTIONALMODULES_CAMERASTABILIZATION] = + m_camerastabilization->enableCameraStabilization->isChecked() ? + HwSettings::OPTIONALMODULES_ENABLED : + HwSettings::OPTIONALMODULES_DISABLED; + + // Update the mixer settings + MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager()); + MixerSettings::DataFields mixerSettingsData = mixerSettings->getData(); + const int NUM_MIXERS = 8; + + QComboBox * selectors[3] = { + m_camerastabilization->rollChannel, + m_camerastabilization->pitchChannel, + m_camerastabilization->yawChannel + }; + + // TODO: Need to reformat object so types are an + // array themselves. This gets really awkward + quint8 * mixerTypes[NUM_MIXERS] = { + &mixerSettingsData.Mixer1Type, + &mixerSettingsData.Mixer2Type, + &mixerSettingsData.Mixer3Type, + &mixerSettingsData.Mixer4Type, + &mixerSettingsData.Mixer5Type, + &mixerSettingsData.Mixer6Type, + &mixerSettingsData.Mixer7Type, + &mixerSettingsData.Mixer8Type, + }; + + for (int i = 0; i < 3; i++) + { + // Channel 1 is second entry, so becomes zero + int mixerNum = selectors[i]->currentIndex() - 1; + + if ( mixerNum >= 0 && // Short circuit in case of none + *mixerTypes[mixerNum] != MixerSettings::MIXER1TYPE_DISABLED && + (*mixerTypes[mixerNum] != MixerSettings::MIXER1TYPE_CAMERAROLL + i) ) { + // If the mixer channel already to something that isn't what we are + // about to set it to reset to none + selectors[i]->setCurrentIndex(0); + } else { + // Make sure no other channels have this output set + for (int j = 0; j < NUM_MIXERS; j++) + if (*mixerTypes[j] == (MixerSettings::MIXER1TYPE_CAMERAROLL + i)) + *mixerTypes[j] = MixerSettings::MIXER1TYPE_DISABLED; + + // If this channel is assigned to one of the outputs that is not disabled + // set it + if(mixerNum >= 0 && mixerNum < NUM_MIXERS) + *mixerTypes[mixerNum] = MixerSettings::MIXER1TYPE_CAMERAROLL + i; + } + } + + // Update the ranges + CameraStabSettings * cameraStab = CameraStabSettings::GetInstance(getObjectManager()); + CameraStabSettings::DataFields cameraStabData = cameraStab->getData(); + cameraStabData.OutputRange[CameraStabSettings::OUTPUTRANGE_ROLL] = m_camerastabilization->rollOutputRange->value(); + cameraStabData.OutputRange[CameraStabSettings::OUTPUTRANGE_PITCH] = m_camerastabilization->pitchOutputRange->value(); + cameraStabData.OutputRange[CameraStabSettings::OUTPUTRANGE_YAW] = m_camerastabilization->yawOutputRange->value(); + + // Because multiple objects are updated, and all of them trigger the callback + // they must be done together (if update one then load settings from second + // the first update would wipe the UI controls). However to be extra cautious + // I'm also disabling updates during the setting to the UAVObjects + disconnectUpdates(); + hwSettings->setData(hwSettingsData); + mixerSettings->setData(mixerSettingsData); + cameraStab->setData(cameraStabData); + connectUpdates(); +} + +/** + * Push settings into UAV objects then save them + */ +void ConfigCameraStabilizationWidget::saveSettings() +{ + applySettings(); + UAVObject * obj = HwSettings::GetInstance(getObjectManager()); + saveObjectToSD(obj); + obj = MixerSettings::GetInstance(getObjectManager()); + saveObjectToSD(obj); + obj = CameraStabSettings::GetInstance(getObjectManager()); + saveObjectToSD(obj); +} + +void ConfigCameraStabilizationWidget::refreshValues() +{ + HwSettings * hwSettings = HwSettings::GetInstance(getObjectManager()); + HwSettings::DataFields hwSettingsData = hwSettings->getData(); + m_camerastabilization->enableCameraStabilization->setChecked( + hwSettingsData.OptionalModules[HwSettings::OPTIONALMODULES_CAMERASTABILIZATION] == + HwSettings::OPTIONALMODULES_ENABLED); + + CameraStabSettings * cameraStabSettings = CameraStabSettings::GetInstance(getObjectManager()); + CameraStabSettings::DataFields cameraStab = cameraStabSettings->getData(); + m_camerastabilization->rollOutputRange->setValue(cameraStab.OutputRange[CameraStabSettings::OUTPUTRANGE_ROLL]); + m_camerastabilization->pitchOutputRange->setValue(cameraStab.OutputRange[CameraStabSettings::OUTPUTRANGE_PITCH]); + m_camerastabilization->yawOutputRange->setValue(cameraStab.OutputRange[CameraStabSettings::OUTPUTRANGE_YAW]); + + MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager()); + MixerSettings::DataFields mixerSettingsData = mixerSettings->getData(); + const int NUM_MIXERS = 8; + QComboBox * selectors[3] = { + m_camerastabilization->rollChannel, + m_camerastabilization->pitchChannel, + m_camerastabilization->yawChannel + }; + + // TODO: Need to reformat object so types are an + // array themselves. This gets really awkward + quint8 * mixerTypes[NUM_MIXERS] = { + &mixerSettingsData.Mixer1Type, + &mixerSettingsData.Mixer2Type, + &mixerSettingsData.Mixer3Type, + &mixerSettingsData.Mixer4Type, + &mixerSettingsData.Mixer5Type, + &mixerSettingsData.Mixer6Type, + &mixerSettingsData.Mixer7Type, + &mixerSettingsData.Mixer8Type, + }; + + for (int i = 0; i < 3; i++) + { + // Default to none if not found. Then search for any mixer channels set to + // this + selectors[i]->setCurrentIndex(0); + for (int j = 0; j < NUM_MIXERS; j++) + if (*mixerTypes[j] == (MixerSettings::MIXER1TYPE_CAMERAROLL + i) && + selectors[i]->currentIndex() != (j + 1)) + selectors[i]->setCurrentIndex(j + 1); + } +} + +void ConfigCameraStabilizationWidget::openHelp() +{ + QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Camera+Stabilization", QUrl::StrictMode) ); +} + +void ConfigCameraStabilizationWidget::enableControls(bool enable) +{ + m_camerastabilization->camerastabilizationSaveSD->setEnabled(enable); + m_camerastabilization->camerastabilizationSaveRAM->setEnabled(enable); +} + +/** + @} + @} + */ diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetoptionspage.h b/ground/openpilotgcs/src/plugins/config/configcamerastabilizationwidget.h similarity index 51% rename from ground/openpilotgcs/src/plugins/importexport/importexportgadgetoptionspage.h rename to ground/openpilotgcs/src/plugins/config/configcamerastabilizationwidget.h index 41415dde4..f5440e360 100644 --- a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetoptionspage.h +++ b/ground/openpilotgcs/src/plugins/config/configcamerastabilizationwidget.h @@ -1,12 +1,13 @@ /** ****************************************************************************** - * @file + * + * @file configahrstwidget.h * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @see The GNU Public License (GPL) Version 3 * @addtogroup GCSPlugins GCS Plugins * @{ - * @addtogroup importexportplugin + * @addtogroup ConfigPlugin Config Plugin * @{ + * @brief Telemetry configuration panel *****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify @@ -23,52 +24,45 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef CONFIGCAMERASTABILIZATIONWIDGET_H +#define CONFIGCAMERASTABILIZATIONWIDGET_H -#ifndef IMPORTEXPORTGADGETOPTIONSPAGE_H -#define IMPORTEXPORTGADGETOPTIONSPAGE_H +#include "ui_camerastabilization.h" +#include "configtaskwidget.h" +#include "extensionsystem/pluginmanager.h" +#include "uavobjectmanager.h" +#include "uavobject.h" +#include +#include +#include +#include +#include +#include -#include "importexport_global.h" -#include "coreplugin/dialogs/ioptionspage.h" -#include -#include -#include -#include +#include "camerastabsettings.h" -namespace Core -{ -class IUAVGadgetConfiguration; -} - -class ImportExportGadgetConfiguration; - -namespace Ui -{ -class ImportExportGadgetOptionsPage; -} - -using namespace Core; - -class IMPORTEXPORT_EXPORT ImportExportGadgetOptionsPage : public IOptionsPage +class ConfigCameraStabilizationWidget: public ConfigTaskWidget { Q_OBJECT + public: - explicit ImportExportGadgetOptionsPage(ImportExportGadgetConfiguration *config, QObject *parent = 0); - - QWidget *createPage(QWidget *parent); - void apply(); - void finish(); - + ConfigCameraStabilizationWidget(QWidget *parent = 0); + ~ConfigCameraStabilizationWidget(); + private: - Ui::ImportExportGadgetOptionsPage *options_page; - ImportExportGadgetConfiguration *m_config; - QFont font; + virtual void enableControls(bool enable); + + Ui_CameraStabilizationWidget *m_camerastabilization; private slots: + void openHelp(); + void applySettings(); + void saveSettings(); + void refreshValues(); +protected: + void connectUpdates(); + void disconnectUpdates(); }; -#endif // IMPORTEXPORTGADGETOPTIONSPAGE_H -/** - * @} - * @} - */ +#endif // ConfigCameraStabilization_H diff --git a/ground/openpilotgcs/src/plugins/config/configccattitudewidget.cpp b/ground/openpilotgcs/src/plugins/config/configccattitudewidget.cpp index c8d278cfc..51b63fadb 100644 --- a/ground/openpilotgcs/src/plugins/config/configccattitudewidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configccattitudewidget.cpp @@ -27,9 +27,12 @@ #include "configccattitudewidget.h" #include "ui_ccattitude.h" #include "utils/coordinateconversions.h" +#include "attitudesettings.h" #include #include #include +#include +#include ConfigCCAttitudeWidget::ConfigCCAttitudeWidget(QWidget *parent) : ConfigTaskWidget(parent), @@ -39,11 +42,20 @@ ConfigCCAttitudeWidget::ConfigCCAttitudeWidget(QWidget *parent) : connect(ui->zeroBias,SIGNAL(clicked()),this,SLOT(startAccelCalibration())); connect(ui->saveButton,SIGNAL(clicked()),this,SLOT(saveAttitudeSettings())); connect(ui->applyButton,SIGNAL(clicked()),this,SLOT(applyAttitudeSettings())); - connect(ui->getCurrentButton,SIGNAL(clicked()),this,SLOT(getCurrentAttitudeSettings())); // Make it smart: - connect(parent, SIGNAL(autopilotConnected()),this, SLOT(getCurrentAttitudeSettings())); - getCurrentAttitudeSettings(); // The 1st time this panel is instanciated, the autopilot is already connected. + connect(parent, SIGNAL(autopilotConnected()),this, SLOT(onAutopilotConnect())); + connect(parent, SIGNAL(autopilotDisconnected()), this, SLOT(onAutopilotDisconnect())); + + enableControls(true); + refreshValues(); // The 1st time this panel is instanciated, the autopilot is already connected. + UAVObject * settings = AttitudeSettings::GetInstance(getObjectManager()); + connect(settings,SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshValues())); + + // Connect the help button + connect(ui->ccAttitudeHelp, SIGNAL(clicked()), this, SLOT(openHelp())); + + } ConfigCCAttitudeWidget::~ConfigCCAttitudeWidget() @@ -51,6 +63,12 @@ ConfigCCAttitudeWidget::~ConfigCCAttitudeWidget() delete ui; } +void ConfigCCAttitudeWidget::enableControls(bool enable) +{ + //ui->applyButton->setEnabled(enable); + ui->saveButton->setEnabled(enable); +} + void ConfigCCAttitudeWidget::attitudeRawUpdated(UAVObject * obj) { QMutexLocker locker(&startStop); @@ -62,7 +80,10 @@ void ConfigCCAttitudeWidget::attitudeRawUpdated(UAVObject * obj) { x_accum.append(field->getDouble(0)); y_accum.append(field->getDouble(1)); z_accum.append(field->getDouble(2)); - qDebug("update %d: %f, %f, %f\n",updates,field->getDouble(0),field->getDouble(1),field->getDouble(2)); + field = obj->getField(QString("gyros")); + x_gyro_accum.append(field->getDouble(0)); + y_gyro_accum.append(field->getDouble(1)); + z_gyro_accum.append(field->getDouble(2));; } else if ( updates == NUM_ACCEL_UPDATES ) { updates++; timer.stop(); @@ -73,18 +94,22 @@ void ConfigCCAttitudeWidget::attitudeRawUpdated(UAVObject * obj) { float y_bias = listMean(y_accum) / ACCEL_SCALE; float z_bias = (listMean(z_accum) + 9.81) / ACCEL_SCALE; + float x_gyro_bias = listMean(x_gyro_accum) * 100.0f; + float y_gyro_bias = listMean(y_gyro_accum) * 100.0f; + float z_gyro_bias = listMean(z_gyro_accum) * 100.0f; obj->setMetadata(initialMdata); - UAVDataObject * settings = dynamic_cast(getObjectManager()->getObject(QString("AttitudeSettings"))); - UAVObjectField * field = settings->getField("AccelBias"); - field->setDouble(field->getDouble(0) + x_bias,0); - field->setDouble(field->getDouble(1) + y_bias,1); - field->setDouble(field->getDouble(2) + z_bias,2); - qDebug("New X bias: %f\n", field->getDouble(0)+x_bias); - qDebug("New Y bias: %f\n", field->getDouble(1)+y_bias); - qDebug("New Z bias: %f\n", field->getDouble(2)+z_bias); - settings->updated(); - ui->status->setText("Calibration done."); + AttitudeSettings::DataFields attitudeSettingsData = AttitudeSettings::GetInstance(getObjectManager())->getData(); + // We offset the gyro bias by current bias to help precision + attitudeSettingsData.AccelBias[0] += x_bias; + attitudeSettingsData.AccelBias[1] += y_bias; + attitudeSettingsData.AccelBias[2] += z_bias; + attitudeSettingsData.GyroBias[0] = -x_gyro_bias; + attitudeSettingsData.GyroBias[1] = -y_gyro_bias; + attitudeSettingsData.GyroBias[2] = -z_gyro_bias; + attitudeSettingsData.BiasCorrectGyro = initialBiasCorrected; + AttitudeSettings::GetInstance(getObjectManager())->setData(attitudeSettingsData); + } else { // Possible to get here if weird threading stuff happens. Just ignore updates. qDebug("Unexpected accel update received."); @@ -106,33 +131,22 @@ void ConfigCCAttitudeWidget::timeout() { } void ConfigCCAttitudeWidget::applyAttitudeSettings() { - UAVDataObject * settings = dynamic_cast(getObjectManager()->getObject(QString("AttitudeSettings"))); - UAVObjectField * field = settings->getField("BoardRotation"); - - field->setValue(ui->rollBias->value(),0); - field->setValue(ui->pitchBias->value(),1); - field->setValue(ui->yawBias->value(),2); - - field = settings->getField("ZeroDuringArming"); - // Handling of boolean values is done through enums on - // uavobjects... - field->setValue((ui->zeroGyroBiasOnArming->isChecked()) ? "TRUE": "FALSE"); - - settings->updated(); + AttitudeSettings::DataFields attitudeSettingsData = AttitudeSettings::GetInstance(getObjectManager())->getData(); + attitudeSettingsData.BoardRotation[AttitudeSettings::BOARDROTATION_ROLL] = ui->rollBias->value(); + attitudeSettingsData.BoardRotation[AttitudeSettings::BOARDROTATION_PITCH] = ui->pitchBias->value(); + attitudeSettingsData.BoardRotation[AttitudeSettings::BOARDROTATION_YAW] = ui->yawBias->value(); + attitudeSettingsData.ZeroDuringArming = ui->zeroGyroBiasOnArming->isChecked() ? AttitudeSettings::ZERODURINGARMING_TRUE : + AttitudeSettings::ZERODURINGARMING_FALSE; + AttitudeSettings::GetInstance(getObjectManager())->setData(attitudeSettingsData); } -void ConfigCCAttitudeWidget::getCurrentAttitudeSettings() { - UAVDataObject * settings = dynamic_cast(getObjectManager()->getObject(QString("AttitudeSettings"))); - settings->requestUpdate(); - UAVObjectField * field = settings->getField("BoardRotation"); - ui->rollBias->setValue(field->getDouble(0)); - ui->pitchBias->setValue(field->getDouble(1)); - ui->yawBias->setValue(field->getDouble(2)); - field = settings->getField("ZeroDuringArming"); - // Handling of boolean values is done through enums on - // uavobjects... - bool enabled = (field->getValue().toString() == "FALSE") ? false : true; - ui->zeroGyroBiasOnArming->setChecked(enabled); +void ConfigCCAttitudeWidget::refreshValues() { + AttitudeSettings::DataFields attitudeSettingsData = AttitudeSettings::GetInstance(getObjectManager())->getData(); + + ui->rollBias->setValue(attitudeSettingsData.BoardRotation[0]); + ui->pitchBias->setValue(attitudeSettingsData.BoardRotation[1]); + ui->yawBias->setValue(attitudeSettingsData.BoardRotation[2]); + ui->zeroGyroBiasOnArming->setChecked(attitudeSettingsData.ZeroDuringArming == AttitudeSettings::ZERODURINGARMING_TRUE); } @@ -143,8 +157,15 @@ void ConfigCCAttitudeWidget::startAccelCalibration() { x_accum.clear(); y_accum.clear(); z_accum.clear(); + x_gyro_accum.clear(); + y_gyro_accum.clear(); + z_gyro_accum.clear(); - ui->status->setText(tr("Calibrating...")); + // Disable gyro bias correction to see raw data + AttitudeSettings::DataFields attitudeSettingsData = AttitudeSettings::GetInstance(getObjectManager())->getData(); + initialBiasCorrected = attitudeSettingsData.BiasCorrectGyro; + attitudeSettingsData.BiasCorrectGyro = AttitudeSettings::BIASCORRECTGYRO_FALSE; + AttitudeSettings::GetInstance(getObjectManager())->setData(attitudeSettingsData); // Set up to receive updates UAVDataObject * obj = dynamic_cast(getObjectManager()->getObject(QString("AttitudeRaw"))); @@ -169,3 +190,10 @@ void ConfigCCAttitudeWidget::saveAttitudeSettings() { UAVDataObject * obj = dynamic_cast(getObjectManager()->getObject(QString("AttitudeSettings"))); saveObjectToSD(obj); } + +void ConfigCCAttitudeWidget::openHelp() +{ + + QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/CopterControl+Attitude+Configuration", QUrl::StrictMode) ); +} + diff --git a/ground/openpilotgcs/src/plugins/config/configccattitudewidget.h b/ground/openpilotgcs/src/plugins/config/configccattitudewidget.h index a70c552ba..27176b22f 100644 --- a/ground/openpilotgcs/src/plugins/config/configccattitudewidget.h +++ b/ground/openpilotgcs/src/plugins/config/configccattitudewidget.h @@ -52,20 +52,25 @@ private slots: void startAccelCalibration(); void saveAttitudeSettings(); void applyAttitudeSettings(); - void getCurrentAttitudeSettings(); + virtual void refreshValues(); + void openHelp(); private: QMutex startStop; Ui_ccattitude *ui; QTimer timer; UAVObject::Metadata initialMdata; + quint8 initialBiasCorrected; int updates; QList x_accum, y_accum, z_accum; + QList x_gyro_accum, y_gyro_accum, z_gyro_accum; static const int NUM_ACCEL_UPDATES = 60; static const float ACCEL_SCALE = 0.004f * 9.81f; + virtual void enableControls(bool enable); + }; #endif // CCATTITUDEWIDGET_H diff --git a/ground/openpilotgcs/src/plugins/config/configccpmwidget.cpp b/ground/openpilotgcs/src/plugins/config/configccpmwidget.cpp index ea4078b52..e53cbb70c 100644 --- a/ground/openpilotgcs/src/plugins/config/configccpmwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configccpmwidget.cpp @@ -25,6 +25,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "configccpmwidget.h" +#include "mixersettings.h" #include #include @@ -32,20 +33,27 @@ #include #include #include +#include #include #include +#include "mixersettings.h" +#include "systemsettings.h" + #define Pi 3.14159265358979323846 ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent) { int i; + m_ccpm = new Ui_ccpmWidget(); m_ccpm->setupUi(this); SwashLvlConfigurationInProgress=0; SwashLvlState=0; SwashLvlServoInterlock=0; + updatingFromHardware=FALSE; + updatingToHardware=FALSE; // Now connect the widget to the ManualControlCommand / Channel UAVObject //ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); @@ -55,12 +63,12 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent) m_ccpm->SwashplateImage->setScene(new QGraphicsScene(this)); m_ccpm->SwashLvlSwashplateImage->setScene(m_ccpm->SwashplateImage->scene()); - m_ccpm->SwashLvlSwashplateImage->setSceneRect(-50,-30,500,500); - m_ccpm->SwashLvlSwashplateImage->scale(.85,.85); + m_ccpm->SwashLvlSwashplateImage->setSceneRect(-50,-50,500,500); + //m_ccpm->SwashLvlSwashplateImage->scale(.85,.85); //m_ccpm->SwashplateImage->setSceneRect(SwashplateImg->boundingRect()); m_ccpm->SwashplateImage->setSceneRect(-50,-30,500,500); - m_ccpm->SwashplateImage->scale(.85,.85); + //m_ccpm->SwashplateImage->scale(.85,.85); @@ -72,9 +80,10 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent) SwashplateImg->setSharedRenderer(renderer); SwashplateImg->setElementId("Swashplate"); SwashplateImg->setObjectName("Swashplate"); + //SwashplateImg->setScale(0.75); m_ccpm->SwashplateImage->scene()->addItem(SwashplateImg); - QFont serifFont("Times", 16, QFont::Bold); + QFont serifFont("Times", 24, QFont::Bold); QPen pen; // creates a default pen pen.setStyle(Qt::DotLine); @@ -83,6 +92,19 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent) pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin); + + QBrush brush(Qt::darkBlue); + QPen pen2; // creates a default pen + + //pen2.setStyle(Qt::DotLine); + pen2.setWidth(1); + pen2.setBrush(Qt::blue); + //pen2.setCapStyle(Qt::RoundCap); + //pen2.setJoinStyle(Qt::RoundJoin); + + + //brush.setStyle(Qt::RadialGradientPattern); + QList ServoNames; ServoNames << "ServoW" << "ServoX" << "ServoY" << "ServoZ" ; @@ -96,10 +118,16 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent) m_ccpm->SwashplateImage->scene()->addItem(Servos[i]); ServosText[i] = new QGraphicsTextItem(); - ServosText[i]->setDefaultTextColor(Qt::red); + ServosText[i]->setDefaultTextColor(Qt::yellow); ServosText[i]->setPlainText(QString("-")); ServosText[i]->setFont(serifFont); + + ServosTextCircles[i] = new QGraphicsEllipseItem(1,1,30,30); + ServosTextCircles[i]->setBrush(brush); + ServosTextCircles[i]->setPen(pen2); + m_ccpm->SwashplateImage->scene()->addItem(ServosTextCircles[i]); m_ccpm->SwashplateImage->scene()->addItem(ServosText[i]); + SwashLvlSpinBoxes[i] = new QSpinBox(m_ccpm->SwashLvlSwashplateImage); // use QGraphicsView @@ -172,7 +200,10 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent) QStringList channels; channels << "Channel1" << "Channel2" << - "Channel3" << "Channel4" << "Channel5" << "Channel6" << "Channel7" << "Channel8" << "None" ; + "Channel3" << "Channel4" << "Channel5" << "Channel6" << "Channel7" << "Channel8" ; + m_ccpm->ccpmCollectiveChannel->addItems(channels); + m_ccpm->ccpmCollectiveChannel->setCurrentIndex(8); + channels << "None" ; m_ccpm->ccpmEngineChannel->addItems(channels); m_ccpm->ccpmEngineChannel->setCurrentIndex(8); m_ccpm->ccpmTailChannel->addItems(channels); @@ -187,7 +218,7 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent) m_ccpm->ccpmServoZChannel->setCurrentIndex(8); QStringList Types; - Types << "CCPM 2 Servo 90" << "CCPM 3 Servo 120" << "CCPM 3 Servo 140" << "FP 2 Servo 90" << "Custom - User Angles" << "Custom - Advanced Settings" ; + Types << "CCPM 2 Servo 90" << "CCPM 3 Servo 90" << "CCPM 4 Servo 90" << "CCPM 3 Servo 120" << "CCPM 3 Servo 140" << "FP 2 Servo 90" << "Custom - User Angles" << "Custom - Advanced Settings" ; m_ccpm->ccpmType->addItems(Types); m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->count() - 1); requestccpmUpdate(); @@ -196,6 +227,8 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent) //disable changing number of points in curves until UAVObjects have more than 5 m_ccpm->NumCurvePoints->setEnabled(0); + + UpdateType(); @@ -237,7 +270,13 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent) connect(m_ccpm->SwashLvlCancelButton, SIGNAL(clicked()), this, SLOT(SwashLvlCancelButtonPressed())); connect(m_ccpm->SwashLvlFinishButton, SIGNAL(clicked()), this, SLOT(SwashLvlFinishButtonPressed())); + connect(m_ccpm->ccpmCollectivePassthrough, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities())); + connect(m_ccpm->ccpmLinkCyclic, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities())); + connect(m_ccpm->ccpmLinkRoll, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities())); + + + ccpmSwashplateRedraw(); // connect(parent, SIGNAL(autopilotConnected()),this, SLOT(requestccpmUpdate())); } @@ -249,11 +288,13 @@ ConfigccpmWidget::~ConfigccpmWidget() void ConfigccpmWidget::UpdateType() { - int TypeInt,SingleServoIndex; + int TypeInt,SingleServoIndex,NumServosDefined; QString TypeText; double AdjustmentAngle=0; - + UpdatCCPMOptionsFromUI(); + SetUIComponentVisibilities(); + TypeInt = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1; TypeText = m_ccpm->ccpmType->currentText(); SingleServoIndex = m_ccpm->ccpmSingleServo->currentIndex(); @@ -266,7 +307,7 @@ void ConfigccpmWidget::UpdateType() m_ccpm->ccpmAngleX->setEnabled(TypeInt==1); m_ccpm->ccpmAngleY->setEnabled(TypeInt==1); m_ccpm->ccpmAngleZ->setEnabled(TypeInt==1); - m_ccpm->ccpmCorrectionAngle->setEnabled(TypeInt==1); + m_ccpm->ccpmCorrectionAngle->setEnabled(TypeInt!=0); m_ccpm->ccpmServoWChannel->setEnabled(TypeInt>0); m_ccpm->ccpmServoXChannel->setEnabled(TypeInt>0); @@ -289,6 +330,7 @@ void ConfigccpmWidget::UpdateType() //m_ccpm->customThrottleCurve2Value->setVisible(1); //m_ccpm->label_41->setVisible(1); + NumServosDefined=4; //set values for pre defined heli types if (TypeText.compare(QString("CCPM 2 Servo 90"), Qt::CaseInsensitive)==0) { @@ -302,8 +344,34 @@ void ConfigccpmWidget::UpdateType() m_ccpm->ccpmServoZChannel->setCurrentIndex(8); m_ccpm->ccpmServoYChannel->setEnabled(0); m_ccpm->ccpmServoZChannel->setEnabled(0); - m_ccpm->ccpmCorrectionAngle->setValue(0); + //m_ccpm->ccpmCorrectionAngle->setValue(0); + NumServosDefined=2; + } + if (TypeText.compare(QString("CCPM 3 Servo 90"), Qt::CaseInsensitive)==0) + { + m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0); + m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360)); + m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 180,360)); + m_ccpm->ccpmAngleZ->setValue(0); + m_ccpm->ccpmAngleZ->setEnabled(0); + m_ccpm->ccpmServoZChannel->setCurrentIndex(8); + m_ccpm->ccpmServoZChannel->setEnabled(0); + //m_ccpm->ccpmCorrectionAngle->setValue(0); + NumServosDefined=3; + + } + if (TypeText.compare(QString("CCPM 4 Servo 90"), Qt::CaseInsensitive)==0) + { + m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0); + m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360)); + m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 180,360)); + m_ccpm->ccpmAngleZ->setValue(fmod(AdjustmentAngle + 270,360)); + //m_ccpm->ccpmCorrectionAngle->setValue(0); + m_ccpm->ccpmSingleServo->setEnabled(0); + m_ccpm->ccpmSingleServo->setCurrentIndex(0); + NumServosDefined=4; + } if (TypeText.compare(QString("CCPM 3 Servo 120"), Qt::CaseInsensitive)==0) { @@ -314,8 +382,9 @@ void ConfigccpmWidget::UpdateType() m_ccpm->ccpmAngleZ->setEnabled(0); m_ccpm->ccpmServoZChannel->setCurrentIndex(8); m_ccpm->ccpmServoZChannel->setEnabled(0); - m_ccpm->ccpmCorrectionAngle->setValue(0); - + //m_ccpm->ccpmCorrectionAngle->setValue(0); + NumServosDefined=3; + } if (TypeText.compare(QString("CCPM 3 Servo 140"), Qt::CaseInsensitive)==0) { @@ -326,7 +395,8 @@ void ConfigccpmWidget::UpdateType() m_ccpm->ccpmAngleZ->setEnabled(0); m_ccpm->ccpmServoZChannel->setCurrentIndex(8); m_ccpm->ccpmServoZChannel->setEnabled(0); - m_ccpm->ccpmCorrectionAngle->setValue(0); + //m_ccpm->ccpmCorrectionAngle->setValue(0); + NumServosDefined=3; } if (TypeText.compare(QString("FP 2 Servo 90"), Qt::CaseInsensitive)==0) @@ -341,7 +411,7 @@ void ConfigccpmWidget::UpdateType() m_ccpm->ccpmServoZChannel->setCurrentIndex(8); m_ccpm->ccpmServoYChannel->setEnabled(0); m_ccpm->ccpmServoZChannel->setEnabled(0); - m_ccpm->ccpmCorrectionAngle->setValue(0); + //m_ccpm->ccpmCorrectionAngle->setValue(0); m_ccpm->ccpmCollectivespinBox->setEnabled(0); m_ccpm->ccpmCollectiveSlider->setEnabled(0); @@ -353,8 +423,29 @@ void ConfigccpmWidget::UpdateType() m_ccpm->PitchCurve->setVisible(0); //m_ccpm->customThrottleCurve2Value->setVisible(0); //m_ccpm->label_41->setVisible(0); + NumServosDefined=2; } + //set the visibility of the swashplate servo selection boxes + m_ccpm->ccpmServoWLabel->setVisible(NumServosDefined>=1); + m_ccpm->ccpmServoXLabel->setVisible(NumServosDefined>=2); + m_ccpm->ccpmServoYLabel->setVisible(NumServosDefined>=3); + m_ccpm->ccpmServoZLabel->setVisible(NumServosDefined>=4); + m_ccpm->ccpmServoWChannel->setVisible(NumServosDefined>=1); + m_ccpm->ccpmServoXChannel->setVisible(NumServosDefined>=2); + m_ccpm->ccpmServoYChannel->setVisible(NumServosDefined>=3); + m_ccpm->ccpmServoZChannel->setVisible(NumServosDefined>=4); + + //set the visibility of the swashplate angle selection boxes + m_ccpm->ccpmServoWLabel_2->setVisible(NumServosDefined>=1); + m_ccpm->ccpmServoXLabel_2->setVisible(NumServosDefined>=2); + m_ccpm->ccpmServoYLabel_2->setVisible(NumServosDefined>=3); + m_ccpm->ccpmServoZLabel_2->setVisible(NumServosDefined>=4); + m_ccpm->ccpmAngleW->setVisible(NumServosDefined>=1); + m_ccpm->ccpmAngleX->setVisible(NumServosDefined>=2); + m_ccpm->ccpmAngleY->setVisible(NumServosDefined>=3); + m_ccpm->ccpmAngleZ->setVisible(NumServosDefined>=4); + m_ccpm->ccpmAdvancedSettingsTable->resizeColumnsToContents(); for (int i=0;i<6;i++) { @@ -362,9 +453,12 @@ void ConfigccpmWidget::UpdateType() m_ccpm->ccpmAdvancedSettingsTable->verticalHeader()->width())/6); } + + + //update UI ccpmSwashplateUpdate(); - + } /** @@ -372,12 +466,7 @@ void ConfigccpmWidget::UpdateType() */ void ConfigccpmWidget::resetMixer(MixerCurveWidget *mixer, int numElements) { - QList curveValues; - for (double i=0; iinitCurve(curveValues); + mixer->initLinearCurve(numElements,(double)1); } void ConfigccpmWidget::UpdateCurveWidgets() @@ -660,17 +749,43 @@ void ConfigccpmWidget::GenerateCurve() void ConfigccpmWidget::ccpmSwashplateRedraw() { double angle[CCPM_MAX_SWASH_SERVOS],CorrectionAngle,x,y,w,h,radius,CenterX,CenterY; - int used[CCPM_MAX_SWASH_SERVOS],i; + int used[CCPM_MAX_SWASH_SERVOS],defined[CCPM_MAX_SWASH_SERVOS],i; + QRectF bounds; + QRect size; + double scale,xscale,yscale; + + size = m_ccpm->SwashplateImage->rect(); + xscale=size.width(); + yscale=size.height(); + scale=xscale; + if (yscaleSwashplateImage->resetTransform (); + m_ccpm->SwashplateImage->scale(scale,scale); + + size = m_ccpm->SwashLvlSwashplateImage->rect(); + xscale=size.width(); + yscale=size.height(); + scale=xscale; + if (yscaleSwashLvlSwashplateImage->resetTransform (); + m_ccpm->SwashLvlSwashplateImage->scale(scale,scale); + CorrectionAngle=m_ccpm->ccpmCorrectionAngle->value(); - //CenterX=m_ccpm->SwashplateImage->scene()->sceneRect().center().x(); - // CenterY=m_ccpm->SwashplateImage->scene()->sceneRect().center().y(); CenterX=200; - CenterY=220; + CenterY=200; - SwashplateImg->setPos(CenterX-200,CenterY-200); + bounds=SwashplateImg->boundingRect(); + + SwashplateImg->setPos(CenterX-bounds.width()/2,CenterY-bounds.height()/2); + defined[0]=(m_ccpm->ccpmServoWChannel->isEnabled()); + defined[1]=(m_ccpm->ccpmServoXChannel->isEnabled()); + defined[2]=(m_ccpm->ccpmServoYChannel->isEnabled()); + defined[3]=(m_ccpm->ccpmServoZChannel->isEnabled()); used[0]=((m_ccpm->ccpmServoWChannel->currentIndex()<8)&&(m_ccpm->ccpmServoWChannel->isEnabled())); used[1]=((m_ccpm->ccpmServoXChannel->currentIndex()<8)&&(m_ccpm->ccpmServoXChannel->isEnabled())); used[2]=((m_ccpm->ccpmServoYChannel->currentIndex()<8)&&(m_ccpm->ccpmServoYChannel->isEnabled())); @@ -689,11 +804,28 @@ void ConfigccpmWidget::ccpmSwashplateRedraw() Servos[i]->setPos(x, y); Servos[i]->setVisible(used[i]!=0); - radius=170; - x=CenterX-(radius*sin(angle[i]))-10.00; - y=CenterY+(radius*cos(angle[i]))-10.00; + radius=150; + bounds=ServosText[i]->boundingRect(); + x=CenterX-(radius*sin(angle[i]))-bounds.width()/2; + y=CenterY+(radius*cos(angle[i]))-bounds.height()/2; + ServosText[i]->setPos(x, y); ServosText[i]->setVisible(used[i]!=0); + + if (bounds.width()>bounds.height()) + { + bounds.setHeight(bounds.width()); + } + else + { + bounds.setWidth(bounds.height()); + } + x=CenterX-(radius*sin(angle[i]))-bounds.width()/2; + y=CenterY+(radius*cos(angle[i]))-bounds.height()/2; + + ServosTextCircles[i]->setRect(bounds); + ServosTextCircles[i]->setPos(x, y); + ServosTextCircles[i]->setVisible(used[i]!=0); w=SwashLvlSpinBoxes[i]->width()/2; h=SwashLvlSpinBoxes[i]->height()/2; @@ -707,7 +839,7 @@ void ConfigccpmWidget::ccpmSwashplateRedraw() x=CenterX-(radius*sin(angle[i])); y=CenterY+(radius*cos(angle[i])); ServoLines[i]->setLine(CenterX,CenterY,x,y); - ServoLines[i]->setVisible(used[i]!=0); + ServoLines[i]->setVisible(defined[i]!=0); } //m_ccpm->SwashplateImage->centerOn (CenterX, CenterY); @@ -718,22 +850,104 @@ void ConfigccpmWidget::ccpmSwashplateRedraw() void ConfigccpmWidget::ccpmSwashplateUpdate() { ccpmSwashplateRedraw(); + SetUIComponentVisibilities(); UpdateMixer(); } +void ConfigccpmWidget::ccpmChannelCheck() +{ + if((m_ccpm->ccpmServoWChannel->currentIndex()==8)&&(m_ccpm->ccpmServoWChannel->isEnabled())) + { + m_ccpm->ccpmServoWLabel->setText("Servo W"); + } + else + { + m_ccpm->ccpmServoWLabel->setText("Servo W"); + } + if((m_ccpm->ccpmServoXChannel->currentIndex()==8)&&(m_ccpm->ccpmServoXChannel->isEnabled())) + { + m_ccpm->ccpmServoXLabel->setText("Servo X"); + } + else + { + m_ccpm->ccpmServoXLabel->setText("Servo X"); + } + if((m_ccpm->ccpmServoYChannel->currentIndex()==8)&&(m_ccpm->ccpmServoYChannel->isEnabled())) + { + m_ccpm->ccpmServoYLabel->setText("Servo Y"); + } + else + { + m_ccpm->ccpmServoYLabel->setText("Servo Y"); + } + if((m_ccpm->ccpmServoZChannel->currentIndex()==8)&&(m_ccpm->ccpmServoZChannel->isEnabled())) + { + m_ccpm->ccpmServoZLabel->setText("Servo Z"); + } + else + { + m_ccpm->ccpmServoZLabel->setText("Servo Z"); + } + + if((m_ccpm->ccpmEngineChannel->currentIndex()==8)&&(m_ccpm->ccpmEngineChannel->isEnabled())) + { + m_ccpm->ccpmEngineLabel->setText("Engine"); + } + else + { + m_ccpm->ccpmEngineLabel->setText("Engine"); + } + + if((m_ccpm->ccpmTailChannel->currentIndex()==8)&&(m_ccpm->ccpmTailChannel->isEnabled())) + { + m_ccpm->ccpmTailLabel->setText("Tail Rotor"); + } + else + { + m_ccpm->ccpmTailLabel->setText("Tail Rotor"); + } + +} + void ConfigccpmWidget::UpdateMixer() { - int i,j,Type,ThisEnable[6]; - float CollectiveConstant,CorrectionAngle,ThisAngle[6]; + bool useCCPM; + bool useCyclic; + int i,j,ThisEnable[6]; + float CollectiveConstant,PitchConstant,RollConstant,ThisAngle[6]; //QTableWidgetItem *newItem;// = new QTableWidgetItem(); QString Channel; - Type = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1; - CollectiveConstant=m_ccpm->ccpmCollectiveSlider->value()/100.0; - CorrectionAngle=m_ccpm->ccpmCorrectionAngle->value(); + ccpmChannelCheck(); + //Type = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1; + //CollectiveConstant=m_ccpm->ccpmCollectiveSlider->value()/100.0; + //CorrectionAngle=m_ccpm->ccpmCorrectionAngle->value(); + UpdatCCPMOptionsFromUI(); + + useCCPM = !(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState); + useCyclic = GUIConfigData.heli.ccpmLinkRollState; + CollectiveConstant = (float)GUIConfigData.heli.SliderValue0 / 100.00; - if (Type>0) + if (useCCPM) + {//cyclic = 1 - collective + PitchConstant = 1-CollectiveConstant; + RollConstant = PitchConstant; + } + else + { + PitchConstant = (float)GUIConfigData.heli.SliderValue1 / 100.00;; + if (useCyclic) + { + RollConstant = PitchConstant; + } + else + { + RollConstant = (float)GUIConfigData.heli.SliderValue2 / 100.00;; + } + } + + if (GUIConfigData.heli.SwasplateType>0) {//not advanced settings //get the channel data from the ui MixerChannelData[0] = m_ccpm->ccpmEngineChannel->currentIndex(); @@ -797,8 +1011,8 @@ void ConfigccpmWidget::UpdateMixer() {//Swashplate m_ccpm->ccpmAdvancedSettingsTable->item(i,1)->setText(QString("%1").arg(0));//ThrottleCurve1 m_ccpm->ccpmAdvancedSettingsTable->item(i,2)->setText(QString("%1").arg((int)(127.0*CollectiveConstant)));//ThrottleCurve2 - m_ccpm->ccpmAdvancedSettingsTable->item(i,3)->setText(QString("%1").arg((int)(127.0*(1-CollectiveConstant)*sin((180+CorrectionAngle + ThisAngle[i])*Pi/180.00))));//Roll - m_ccpm->ccpmAdvancedSettingsTable->item(i,4)->setText(QString("%1").arg((int)(127.0*(1-CollectiveConstant)*cos((CorrectionAngle + ThisAngle[i])*Pi/180.00))));//Pitch + m_ccpm->ccpmAdvancedSettingsTable->item(i,3)->setText(QString("%1").arg((int)(127.0*(RollConstant)*sin((180+GUIConfigData.heli.CorrectionAngle + ThisAngle[i])*Pi/180.00))));//Roll + m_ccpm->ccpmAdvancedSettingsTable->item(i,4)->setText(QString("%1").arg((int)(127.0*(PitchConstant)*cos((GUIConfigData.heli.CorrectionAngle + ThisAngle[i])*Pi/180.00))));//Pitch m_ccpm->ccpmAdvancedSettingsTable->item(i,5)->setText(QString("%1").arg(0));//Yaw } @@ -827,6 +1041,140 @@ void ConfigccpmWidget::UpdateMixer() /************************** * ccpm settings **************************/ +/* + Get the state of the UI check boxes and change the visibility of sliders + typedef struct { + uint SwasplateType:3; + uint FirstServoIndex:2; + uint CorrectionAngle:9; + uint ccpmCollectivePassthroughState:1; + uint ccpmLinkCyclicState:1; + uint ccpmLinkRollState:1; + uint CollectiveChannel:3; + uint padding:12; + } __attribute__((packed)) heliGUISettingsStruct; + + */ +void ConfigccpmWidget::UpdatCCPMOptionsFromUI() +{ + bool useCCPM; + bool useCyclic; + + if (updatingFromHardware) return; + //get the user options + //swashplate config + GUIConfigData.heli.SwasplateType = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1; + GUIConfigData.heli.FirstServoIndex = m_ccpm->ccpmSingleServo->currentIndex(); + + //ccpm mixing options + GUIConfigData.heli.ccpmCollectivePassthroughState = m_ccpm->ccpmCollectivePassthrough->isChecked(); + GUIConfigData.heli.ccpmLinkCyclicState = m_ccpm->ccpmLinkCyclic->isChecked(); + GUIConfigData.heli.ccpmLinkRollState = m_ccpm->ccpmLinkRoll->isChecked(); + useCCPM = !(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState); + useCyclic = GUIConfigData.heli.ccpmLinkRollState; + + //correction angle + GUIConfigData.heli.CorrectionAngle = m_ccpm->ccpmCorrectionAngle->value(); + + //CollectiveChannel + GUIConfigData.heli.CollectiveChannel = m_ccpm->ccpmCollectiveChannel->currentIndex(); + + //update sliders + if (useCCPM) + { + GUIConfigData.heli.SliderValue0 = m_ccpm->ccpmCollectiveSlider->value(); + } + else + { + GUIConfigData.heli.SliderValue0 = m_ccpm->ccpmCollectiveScale->value(); + } + if (useCyclic) + { + GUIConfigData.heli.SliderValue1 = m_ccpm->ccpmCyclicScale->value(); + } + else + { + GUIConfigData.heli.SliderValue1 = m_ccpm->ccpmPitchScale->value(); + } + GUIConfigData.heli.SliderValue2 = m_ccpm->ccpmRollScale->value(); + //GUIConfigData.heli.RevoSlider = m_ccpm->ccpmREVOScale->value(); + + //servo assignments + GUIConfigData.heli.ServoIndexW = m_ccpm->ccpmServoWChannel->currentIndex(); + GUIConfigData.heli.ServoIndexX = m_ccpm->ccpmServoXChannel->currentIndex(); + GUIConfigData.heli.ServoIndexY = m_ccpm->ccpmServoYChannel->currentIndex(); + GUIConfigData.heli.ServoIndexZ = m_ccpm->ccpmServoZChannel->currentIndex(); + +} +void ConfigccpmWidget::UpdatCCPMUIFromOptions() +{ + //swashplate config + m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->count() - (GUIConfigData.heli.SwasplateType +1)); + m_ccpm->ccpmSingleServo->setCurrentIndex(GUIConfigData.heli.FirstServoIndex); + + //ccpm mixing options + m_ccpm->ccpmCollectivePassthrough->setChecked(GUIConfigData.heli.ccpmCollectivePassthroughState); + m_ccpm->ccpmLinkCyclic->setChecked(GUIConfigData.heli.ccpmLinkCyclicState); + m_ccpm->ccpmLinkRoll->setChecked(GUIConfigData.heli.ccpmLinkRollState); + + //correction angle + m_ccpm->ccpmCorrectionAngle->setValue(GUIConfigData.heli.CorrectionAngle); + + //CollectiveChannel + m_ccpm->ccpmCollectiveChannel->setCurrentIndex(GUIConfigData.heli.CollectiveChannel); + + //update sliders + m_ccpm->ccpmCollectiveScale->setValue(GUIConfigData.heli.SliderValue0); + m_ccpm->ccpmCollectiveScaleBox->setValue(GUIConfigData.heli.SliderValue0); + m_ccpm->ccpmCyclicScale->setValue(GUIConfigData.heli.SliderValue1); + m_ccpm->ccpmCyclicScaleBox->setValue(GUIConfigData.heli.SliderValue1); + m_ccpm->ccpmPitchScale->setValue(GUIConfigData.heli.SliderValue1); + m_ccpm->ccpmPitchScaleBox->setValue(GUIConfigData.heli.SliderValue1); + m_ccpm->ccpmRollScale->setValue(GUIConfigData.heli.SliderValue2); + m_ccpm->ccpmRollScaleBox->setValue(GUIConfigData.heli.SliderValue2); + m_ccpm->ccpmCollectiveSlider->setValue(GUIConfigData.heli.SliderValue0); + m_ccpm->ccpmCollectivespinBox->setValue(GUIConfigData.heli.SliderValue0); + //m_ccpm->ccpmREVOScale->setValue(GUIConfigData.heli.RevoSlider); + + //servo assignments + m_ccpm->ccpmServoWChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexW); + m_ccpm->ccpmServoXChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexX); + m_ccpm->ccpmServoYChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexY); + m_ccpm->ccpmServoZChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexZ); + +} + + +void ConfigccpmWidget::SetUIComponentVisibilities() +{ + UpdatCCPMOptionsFromUI(); + //set which sliders are user... + m_ccpm->ccpmRevoMixingBox->setVisible(0); + + m_ccpm->ccpmPitchMixingBox->setVisible(!GUIConfigData.heli.ccpmCollectivePassthroughState && GUIConfigData.heli.ccpmLinkCyclicState); + m_ccpm->ccpmCollectiveScalingBox->setVisible(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState); + + m_ccpm->ccpmCollectiveChLabel->setVisible(GUIConfigData.heli.ccpmCollectivePassthroughState); + m_ccpm->ccpmCollectiveChannel->setVisible(GUIConfigData.heli.ccpmCollectivePassthroughState); + + m_ccpm->ccpmLinkCyclic->setVisible(!GUIConfigData.heli.ccpmCollectivePassthroughState); + + m_ccpm->ccpmCyclicScalingBox->setVisible((GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState) && GUIConfigData.heli.ccpmLinkRollState); + if (!GUIConfigData.heli.ccpmCollectivePassthroughState && GUIConfigData.heli.ccpmLinkCyclicState) + { + m_ccpm->ccpmPitchScalingBox->setVisible(0); + m_ccpm->ccpmRollScalingBox->setVisible(0); + m_ccpm->ccpmLinkRoll->setVisible(0); + + } + else + { + m_ccpm->ccpmPitchScalingBox->setVisible(!GUIConfigData.heli.ccpmLinkRollState); + m_ccpm->ccpmRollScalingBox->setVisible(!GUIConfigData.heli.ccpmLinkRollState); + m_ccpm->ccpmLinkRoll->setVisible(1); + } + +} /** Request the current value of the SystemSettings which holds the ccpm type */ @@ -834,7 +1182,7 @@ void ConfigccpmWidget::requestccpmUpdate() { #define MaxAngleError 2 int MixerDataFromHeli[8][5]; - QString MixerOutputType[8]; + quint8 MixerOutputType[8]; int EngineChannel,TailRotorChannel,ServoChannels[4],ServoAngles[4],SortAngles[4],CalcAngles[4],ServoCurve2[4]; int NumServos=0; double Collective=0.0; @@ -843,32 +1191,48 @@ void ConfigccpmWidget::requestccpmUpdate() int isCCPM=0; if (SwashLvlConfigurationInProgress)return; - - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); + if (updatingToHardware)return; + updatingFromHardware=TRUE; + int i,j; - UAVObjectField *field; - UAVDataObject* obj; - obj = dynamic_cast(objManager->getObject(QString("MixerSettings"))); - Q_ASSERT(obj); + + SystemSettings * systemSettings = SystemSettings::GetInstance(getObjectManager()); + SystemSettings::DataFields systemSettingsData = systemSettings->getData(); + Q_ASSERT(SystemSettings::GUICONFIGDATA_NUMELEM == + (sizeof(GUIConfigData.UAVObject) / sizeof(GUIConfigData.UAVObject[0]))); + + for(i = 0; i < SystemSettings::GUICONFIGDATA_NUMELEM; i++) + GUIConfigData.UAVObject[i]=systemSettingsData.GUIConfigData[i]; + + UpdatCCPMUIFromOptions(); + + // Get existing mixer settings + MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager()); + MixerSettings::DataFields mixerSettingsData = mixerSettings->getData(); + //go through the user data and update the mixer matrix - for (i=0;i<8;i++) + for (j=0;j<5;j++) { - field = obj->getField(tr( "Mixer%1Vector" ).arg(i+1)); - //config the vector - for (j=0;j<5;j++) - { - MixerDataFromHeli[i][j] = field->getValue(j).toInt(); - //field->setValue(m_ccpm->ccpmAdvancedSettingsTable->item(i,j+1)->text().toInt(),j); - } - } - for (i=0;i<8;i++) - { - field = obj->getField(tr( "Mixer%1Type" ).arg(i+1)); - MixerOutputType[i] = field->getValue().toString(); + MixerDataFromHeli[0][j] = mixerSettingsData.Mixer1Vector[j]; + MixerDataFromHeli[1][j] = mixerSettingsData.Mixer2Vector[j]; + MixerDataFromHeli[2][j] = mixerSettingsData.Mixer3Vector[j]; + MixerDataFromHeli[3][j] = mixerSettingsData.Mixer4Vector[j]; + MixerDataFromHeli[4][j] = mixerSettingsData.Mixer5Vector[j]; + MixerDataFromHeli[5][j] = mixerSettingsData.Mixer6Vector[j]; + MixerDataFromHeli[6][j] = mixerSettingsData.Mixer7Vector[j]; + MixerDataFromHeli[7][j] = mixerSettingsData.Mixer8Vector[j]; } + MixerOutputType[0] = mixerSettingsData.Mixer1Type; + MixerOutputType[1] = mixerSettingsData.Mixer2Type; + MixerOutputType[2] = mixerSettingsData.Mixer3Type; + MixerOutputType[3] = mixerSettingsData.Mixer4Type; + MixerOutputType[4] = mixerSettingsData.Mixer5Type; + MixerOutputType[5] = mixerSettingsData.Mixer6Type; + MixerOutputType[6] = mixerSettingsData.Mixer7Type; + MixerOutputType[7] = mixerSettingsData.Mixer8Type; + EngineChannel =-1; TailRotorChannel =-1; for (j=0;j<5;j++) @@ -884,7 +1248,7 @@ void ConfigccpmWidget::requestccpmUpdate() for (i=0;i<8;i++) { //check if this is the engine... Throttle only - if ((MixerOutputType[i].compare("Motor")==0)&& + if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_MOTOR)&& (MixerDataFromHeli[i][0]>0)&&//ThrottleCurve1 (MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2 (MixerDataFromHeli[i][2]==0)&&//Roll @@ -896,7 +1260,7 @@ void ConfigccpmWidget::requestccpmUpdate() } //check if this is the tail rotor... REVO and YAW - if ((MixerOutputType[i].compare("Servo")==0)&& + if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_SERVO)&& //(MixerDataFromHeli[i][0]!=0)&&//ThrottleCurve1 (MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2 (MixerDataFromHeli[i][2]==0)&&//Roll @@ -909,7 +1273,7 @@ void ConfigccpmWidget::requestccpmUpdate() m_ccpm->ccpmREVOspinBox->setValue((MixerDataFromHeli[i][0]*100)/127); } //check if this is a swashplate servo... Throttle is zero - if ((MixerOutputType[i].compare("Servo")==0)&& + if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_SERVO)&& (MixerDataFromHeli[i][0]==0)&&//ThrottleCurve1 //(MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2 //(MixerDataFromHeli[i][2]==0)&&//Roll @@ -920,185 +1284,23 @@ void ConfigccpmWidget::requestccpmUpdate() ServoCurve2[NumServos]=MixerDataFromHeli[i][1];//record the ThrottleCurve2 contribution to this servo ServoAngles[NumServos]=NumServos*45;//make this 0 for the final version - //if (NumServos==0)m_ccpm->ccpmServoWChannel->setCurrentIndex(i); - //if (NumServos==1)m_ccpm->ccpmServoXChannel->setCurrentIndex(i); - //if (NumServos==2)m_ccpm->ccpmServoYChannel->setCurrentIndex(i); - //if (NumServos==3)m_ccpm->ccpmServoZChannel->setCurrentIndex(i); NumServos++; } } - - - - //just call it user angles for now.... - m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("Custom - User Angles")); - - if (NumServos>1) - { - if((ServoCurve2[0]==0)&&(ServoCurve2[1]==0)&&(ServoCurve2[2]==0)&&(ServoCurve2[3]==0)) - { - //fixed pitch heli - isCCPM=0; - m_ccpm->ccpmCollectiveSlider->setValue(0); - Collective = 0.0; - } - if(ServoCurve2[0]==ServoCurve2[1]) - { - if ((NumServos<3)||(ServoCurve2[1]==ServoCurve2[2])) - { - if ((NumServos<4)||(ServoCurve2[2]==ServoCurve2[3])) - {//all the servos have the same ThrottleCurve2 setting so this must be a CCPM config - isCCPM=1; - Collective = ((double)ServoCurve2[0]*100.00)/127.00; - m_ccpm->ccpmCollectiveSlider->setValue((int)Collective); - m_ccpm->ccpmCollectivespinBox->setValue((int)Collective); - - } - } - } - } - else - {//must be a custom config... "Custom - Advanced Settings" - m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("Custom - Advanced Settings")); - } - - HeadRotation=0; - //calculate the angles - for(j=0;jccpmSingleServo->setCurrentIndex(HeadRotation); - - //calculate the un rotated angles - for(j=0;j CalcAngles[SortAngles[j+1]]) - {//swap the sorted angles - temp = SortAngles[j]; - SortAngles[j]=SortAngles[j+1]; - SortAngles[j+1]=temp; - } - - } - - m_ccpm->ccpmAngleW->setValue(ServoAngles[SortAngles[0]]); - m_ccpm->ccpmAngleX->setValue(ServoAngles[SortAngles[1]]); - m_ccpm->ccpmAngleY->setValue(ServoAngles[SortAngles[2]]); - m_ccpm->ccpmAngleZ->setValue(ServoAngles[SortAngles[3]]); - - m_ccpm->ccpmServoWChannel->setCurrentIndex(ServoChannels[SortAngles[0]]); - m_ccpm->ccpmServoXChannel->setCurrentIndex(ServoChannels[SortAngles[1]]); - m_ccpm->ccpmServoYChannel->setCurrentIndex(ServoChannels[SortAngles[2]]); - m_ccpm->ccpmServoZChannel->setCurrentIndex(ServoChannels[SortAngles[3]]); - - - //Types << "CCPM 2 Servo 90" << "CCPM 3 Servo 120" << "CCPM 3 Servo 140" << "FP 2 Servo 90" << "Custom - User Angles" << "Custom - Advanced Settings" ; - - - //check this against known combinations - if (NumServos==2) - { - if ((fabs(CalcAngles[SortAngles[0]])ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("CCPM 2 Servo 90")); - UpdateType(); - } - else - { - m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("FP 2 Servo 90")); - UpdateType(); - } - - } - } - if (NumServos==3) - { - if ((fabs(CalcAngles[SortAngles[0]])ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("CCPM 3 Servo 120")); - UpdateType(); - - } - else - { - m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("FP 3 Servo 120")); - UpdateType(); - } - - } - else if ((fabs(CalcAngles[SortAngles[0]])ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("CCPM 3 Servo 140")); - UpdateType(); - } - else - { - m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->findText("FP 3 Servo 140")); - UpdateType(); - } - - } - - } - if (NumServos==4) - { - - } - - - - //get the settings for the curve from the mixer settings - field = obj->getField(QString("ThrottleCurve1")); for (i=0;i<5;i++) { - m_ccpm->CurveSettings->item(i, 0)->setText(QString().sprintf("%.3f",field->getValue(i).toDouble())); - //m_ccpm->CurveSettings->item(i, 0)->setText(field->getValue(i).toString()); - } - field = obj->getField(QString("ThrottleCurve2")); - for (i=0;i<5;i++) - { - m_ccpm->CurveSettings->item(i, 1)->setText(QString().sprintf("%.3f",field->getValue(i).toDouble())); - //m_ccpm->CurveSettings->item(i, 1)->setText(field->getValue(i).toString()); + m_ccpm->CurveSettings->item(i, 0)->setText(QString().sprintf("%.3f", + mixerSettingsData.ThrottleCurve1[i])); + m_ccpm->CurveSettings->item(i, 1)->setText(QString().sprintf("%.3f", + mixerSettingsData.ThrottleCurve2[i])); } - - - - + updatingFromHardware=FALSE; + UpdatCCPMUIFromOptions(); ccpmSwashplateUpdate(); - } @@ -1112,10 +1314,22 @@ void ConfigccpmWidget::sendccpmUpdate() UAVDataObject* obj; if (SwashLvlConfigurationInProgress)return; - ShowDisclaimer(1); + updatingToHardware=TRUE; + //ShowDisclaimer(1); + + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); UAVObjectManager *objManager = pm->getObject(); + UpdatCCPMOptionsFromUI(); + obj = dynamic_cast(getObjectManager()->getObject(QString("SystemSettings"))); + field = obj->getField(QString("GUIConfigData")); + field->setValue(GUIConfigData.UAVObject[0],0); + field->setValue(GUIConfigData.UAVObject[1],1); + obj->updated(); + + + obj = dynamic_cast(objManager->getObject(QString("MixerSettings"))); Q_ASSERT(obj); @@ -1124,7 +1338,7 @@ void ConfigccpmWidget::sendccpmUpdate() //clear the output types for (i=0;i<8;i++) { - field = obj->getField(tr( "Mixer%1Type" ).arg( i+1 )); + field = obj->getField( QString( "Mixer%1Type" ).arg( i+1 )); //clear the mixer type field->setValue("Disabled"); } @@ -1145,7 +1359,7 @@ void ConfigccpmWidget::sendccpmUpdate() if (MixerChannelData[i]<8) { //select the correct mixer for this config element - field = obj->getField(tr( "Mixer%1Type" ).arg( MixerChannelData[i]+1 )); + field = obj->getField(QString( "Mixer%1Type" ).arg( MixerChannelData[i]+1 )); //set the mixer type if (i==0) { @@ -1157,7 +1371,7 @@ void ConfigccpmWidget::sendccpmUpdate() } //select the correct mixer for this config element - field = obj->getField(tr( "Mixer%1Vector" ).arg( MixerChannelData[i]+1 )); + field = obj->getField(QString( "Mixer%1Vector" ).arg( MixerChannelData[i]+1 )); //config the vector for (j=0;j<5;j++) { @@ -1181,8 +1395,32 @@ void ConfigccpmWidget::sendccpmUpdate() field->setValue(m_ccpm->CurveSettings->item(i, 1)->text().toDouble(),i); } + obj->updated(); + + field = obj->getField(QString("Curve2Source")); + + //mapping of collective input to curve 2... + //MixerSettings.Curve2Source = Throttle,Roll,Pitch,Yaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5 + //check if we are using throttle or directly from a channel... + if (GUIConfigData.heli.ccpmCollectivePassthroughState) + {// input channel + field->setValue("Accessory0"); obj->updated(); - + + obj = dynamic_cast(objManager->getObject(QString("ManualControlSettings"))); + Q_ASSERT(obj); + field = obj->getField(QString("Accessory0")); + field->setValue(tr( "Channel%1" ).arg(GUIConfigData.heli.CollectiveChannel+1)); + + } + else + {// throttle + + field->setValue("Throttle"); + } + + obj->updated(); + updatingToHardware=FALSE; } @@ -1195,11 +1433,9 @@ void ConfigccpmWidget::saveccpmUpdate() ShowDisclaimer(0); // Send update so that the latest value is saved sendccpmUpdate(); - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - UAVDataObject* obj = dynamic_cast(objManager->getObject(QString("MixerSettings"))); + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); Q_ASSERT(obj); - updateObjectPersistance(ObjectPersistence::OPERATION_SAVE, obj); + saveObjectToSD(obj); } void ConfigccpmWidget::resizeEvent(QResizeEvent* event) @@ -1222,6 +1458,7 @@ void ConfigccpmWidget::showEvent(QShowEvent *event) m_ccpm->ccpmAdvancedSettingsTable->setColumnWidth(i,(m_ccpm->ccpmAdvancedSettingsTable->width()- m_ccpm->ccpmAdvancedSettingsTable->verticalHeader()->width())/6); } + ccpmSwashplateRedraw(); } @@ -1276,7 +1513,7 @@ void ConfigccpmWidget::SwashLvlStartButtonPressed() // Get the channel assignements: obj = dynamic_cast(objManager->getObject(QString("ActuatorSettings"))); Q_ASSERT(obj); - obj->requestUpdate(); + // obj->requestUpdate(); MinField = obj->getField(QString("ChannelMin")); NeutralField = obj->getField(QString("ChannelNeutral")); MaxField = obj->getField(QString("ChannelMax")); @@ -1506,8 +1743,7 @@ void ConfigccpmWidget::SwashLvlFinishButtonPressed() } obj->updated(); - - updateObjectPersistance(ObjectPersistence::OPERATION_SAVE, obj); + saveObjectToSD(obj); //restore Flight control of ActuatorCommand enableSwashplateLevellingControl(false); @@ -1536,7 +1772,7 @@ int ConfigccpmWidget::ShowDisclaimer(int messageID) break; case 1: // Not Tested disclaimer - msgBox.setInformativeText("

The CCPM mixer code has not been used to fly a helicopter!

Use it at your own risk!

Do you wish to continue?"); + msgBox.setInformativeText("

The CCPM mixer code needs more testing!

Use it at your own risk!

Do you wish to continue?"); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Cancel); msgBox.setIcon(QMessageBox::Warning); diff --git a/ground/openpilotgcs/src/plugins/config/configccpmwidget.h b/ground/openpilotgcs/src/plugins/config/configccpmwidget.h index 21b4e1b38..d07da53c8 100644 --- a/ground/openpilotgcs/src/plugins/config/configccpmwidget.h +++ b/ground/openpilotgcs/src/plugins/config/configccpmwidget.h @@ -34,6 +34,7 @@ #include "uavobject.h" #include #include +#include #include #include @@ -49,6 +50,30 @@ typedef struct { int Min[CCPM_MAX_SWASH_SERVOS]; } SwashplateServoSettingsStruct; +typedef struct { + uint SwasplateType:3; + uint FirstServoIndex:2; + uint CorrectionAngle:9; + uint ccpmCollectivePassthroughState:1; + uint ccpmLinkCyclicState:1; + uint ccpmLinkRollState:1; + uint CollectiveChannel:3;//20bits + uint SliderValue0:7; + uint SliderValue1:7; + uint SliderValue2:7;//41bits + uint ServoIndexW:4; + uint ServoIndexX:4; + uint ServoIndexY:4; + uint ServoIndexZ:4;//57bits + uint padding:7; +} __attribute__((packed)) heliGUISettingsStruct; + +typedef union +{ + uint UAVObject[2];//32bits * 2 + heliGUISettingsStruct heli;//64bits +} GUIConfigDataUnion; + class ConfigccpmWidget: public ConfigTaskWidget { Q_OBJECT @@ -72,6 +97,7 @@ private: QGraphicsSvgItem *Servos[CCPM_MAX_SWASH_SERVOS]; QGraphicsTextItem *ServosText[CCPM_MAX_SWASH_SERVOS]; QGraphicsLineItem *ServoLines[CCPM_MAX_SWASH_SERVOS]; + QGraphicsEllipseItem *ServosTextCircles[CCPM_MAX_SWASH_SERVOS]; QSpinBox *SwashLvlSpinBoxes[CCPM_MAX_SWASH_SERVOS]; bool SwashLvlConfigurationInProgress; @@ -82,9 +108,14 @@ private: SwashplateServoSettingsStruct oldSwashLvlConfiguration; SwashplateServoSettingsStruct newSwashLvlConfiguration; + GUIConfigDataUnion GUIConfigData; int MixerChannelData[6]; int ShowDisclaimer(int messageID); + virtual void enableControls(bool enable) { Q_UNUSED(enable)}; // Not used by this widget + + bool updatingFromHardware; + bool updatingToHardware; private slots: void ccpmSwashplateUpdate(); @@ -103,14 +134,24 @@ private: void SwashLvlCancelButtonPressed(); void SwashLvlFinishButtonPressed(); + void UpdatCCPMOptionsFromUI(); + void UpdatCCPMUIFromOptions(); + + void SetUIComponentVisibilities(); + void ccpmChannelCheck(); + void enableSwashplateLevellingControl(bool state); void setSwashplateLevel(int percent); void SwashLvlSpinBoxChanged(int value); void FocusChanged(QWidget *oldFocus, QWidget *newFocus); + + virtual void refreshValues() {}; // Not used + public slots: void requestccpmUpdate(); void sendccpmUpdate(); void saveccpmUpdate(); + protected: void showEvent(QShowEvent *event); void resizeEvent(QResizeEvent *event); diff --git a/ground/openpilotgcs/src/plugins/config/configgadget.qrc b/ground/openpilotgcs/src/plugins/config/configgadget.qrc index e23c636d0..473063c48 100644 --- a/ground/openpilotgcs/src/plugins/config/configgadget.qrc +++ b/ground/openpilotgcs/src/plugins/config/configgadget.qrc @@ -1,17 +1,20 @@ - - - images/XBee.svg - images/Airframe.png - images/Servo.png - images/ahrs-calib.svg - images/AHRS-v1.3.png - images/paper-plane.svg - images/curve-bg.svg - images/quad-shapes.svg - images/ccpm_setup.svg - images/PipXtreme.png - images/gyroscope.svg - images/Transmitter.png - images/help.png - - + + + images/help2.png + images/Airframe.png + images/Servo.png + images/ahrs-calib.svg + images/AHRS-v1.3.png + images/paper-plane.svg + images/curve-bg.svg + images/quad-shapes.svg + images/ccpm_setup.svg + images/PipXtreme.png + images/Transmitter.png + images/help.png + images/coptercontrol.svg + images/hw_config.png + images/gyroscope.png + images/camera.png + + diff --git a/ground/openpilotgcs/src/plugins/config/configgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/config/configgadgetwidget.cpp index 415b68192..426d6e646 100644 --- a/ground/openpilotgcs/src/plugins/config/configgadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configgadgetwidget.cpp @@ -33,9 +33,11 @@ #include "configinputwidget.h" #include "configoutputwidget.h" #include "configstabilizationwidget.h" -#include "configtelemetrywidget.h" +#include "configcamerastabilizationwidget.h" +#include "config_pro_hw_widget.h" +#include "config_cc_hw_widget.h" #include "defaultattitudewidget.h" - +#include "defaulthwsettingswidget.h" #include "uavobjectutilmanager.h" #include @@ -51,34 +53,37 @@ ConfigGadgetWidget::ConfigGadgetWidget(QWidget *parent) : QWidget(parent) { setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - ftw = new FancyTabWidget(this, true); - + ftw = new MyTabbedStackWidget(this, true, true); ftw->setIconSize(64); QVBoxLayout *layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(ftw); setLayout(layout); // ********************* QWidget *qwd; + qwd = new DefaultHwSettingsWidget(this); + ftw->insertTab(ConfigGadgetWidget::hardware, qwd, QIcon(":/configgadget/images/hw_config.png"), QString("HW Settings")); + qwd = new ConfigAirframeWidget(this); - ftw->insertTab(0, qwd, QIcon(":/configgadget/images/Airframe.png"), QString("Aircraft")); + ftw->insertTab(ConfigGadgetWidget::aircraft, qwd, QIcon(":/configgadget/images/Airframe.png"), QString("Aircraft")); qwd = new ConfigInputWidget(this); - ftw->insertTab(1, qwd, QIcon(":/configgadget/images/Transmitter.png"), QString("Input")); + ftw->insertTab(ConfigGadgetWidget::input, qwd, QIcon(":/configgadget/images/Transmitter.png"), QString("Input")); qwd = new ConfigOutputWidget(this); - ftw->insertTab(2, qwd, QIcon(":/configgadget/images/Servo.png"), QString("Output")); + ftw->insertTab(ConfigGadgetWidget::output, qwd, QIcon(":/configgadget/images/Servo.png"), QString("Output")); qwd = new DefaultAttitudeWidget(this); - ftw->insertTab(3, qwd, QIcon(":/configgadget/images/AHRS-v1.3.png"), QString("INS")); + ftw->insertTab(ConfigGadgetWidget::ins, qwd, QIcon(":/configgadget/images/AHRS-v1.3.png"), QString("INS")); qwd = new ConfigStabilizationWidget(this); - ftw->insertTab(4, qwd, QIcon(":/configgadget/images/gyroscope.svg"), QString("Stabilization")); + ftw->insertTab(ConfigGadgetWidget::stabilization, qwd, QIcon(":/configgadget/images/gyroscope.png"), QString("Stabilization")); - qwd = new ConfigTelemetryWidget(this); - ftw->insertTab(5, qwd, QIcon(":/configgadget/images/XBee.svg"), QString("Telemetry")); + qwd = new ConfigCameraStabilizationWidget(this); + ftw->insertTab(ConfigGadgetWidget::camerastabilization, qwd, QIcon(":/configgadget/images/camera.png"), QString("Camera Stab")); // qwd = new ConfigPipXtremeWidget(this); @@ -90,11 +95,13 @@ ConfigGadgetWidget::ConfigGadgetWidget(QWidget *parent) : QWidget(parent) ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); TelemetryManager* telMngr = pm->getObject(); connect(telMngr, SIGNAL(connected()), this, SLOT(onAutopilotConnect())); + connect(telMngr, SIGNAL(disconnected()), this, SLOT(onAutopilotDisconnect())); // And check whether by any chance we are not already connected if (telMngr->isConnected()) - onAutopilotConnect(); + onAutopilotConnect(); + help = 0; } ConfigGadgetWidget::~ConfigGadgetWidget() @@ -110,6 +117,10 @@ void ConfigGadgetWidget::resizeEvent(QResizeEvent *event) QWidget::resizeEvent(event); } +void ConfigGadgetWidget::onAutopilotDisconnect() { + emit autopilotDisconnected(); +} + void ConfigGadgetWidget::onAutopilotConnect() { // First of all, check what Board type we are talking to, and @@ -122,20 +133,28 @@ void ConfigGadgetWidget::onAutopilotConnect() { if ((board & 0xff00) == 1024) { // CopterControl family // Delete the INS panel, replace with CC Panel: - ftw->setCurrentIndex(0); - ftw->removeTab(3); + ftw->setCurrentIndex(ConfigGadgetWidget::hardware); + ftw->removeTab(ConfigGadgetWidget::ins); QWidget *qwd = new ConfigCCAttitudeWidget(this); - ftw->insertTab(3, qwd, QIcon(":/configgadget/images/AHRS-v1.3.png"), QString("Attitude")); + ftw->insertTab(ConfigGadgetWidget::ins, qwd, QIcon(":/configgadget/images/AHRS-v1.3.png"), QString("Attitude")); + ftw->removeTab(ConfigGadgetWidget::hardware); + qwd = new ConfigCCHWWidget(this); + ftw->insertTab(ConfigGadgetWidget::hardware, qwd, QIcon(":/configgadget/images/hw_config.png"), QString("HW Settings")); + ftw->setCurrentIndex(ConfigGadgetWidget::hardware); } else if ((board & 0xff00) == 256 ) { // Mainboard family - ftw->setCurrentIndex(0); - ftw->removeTab(3); + ftw->setCurrentIndex(ConfigGadgetWidget::hardware); + ftw->removeTab(ConfigGadgetWidget::ins); QWidget *qwd = new ConfigAHRSWidget(this); - ftw->insertTab(3, qwd, QIcon(":/configgadget/images/AHRS-v1.3.png"), QString("INS")); + ftw->insertTab(ConfigGadgetWidget::ins, qwd, QIcon(":/configgadget/images/AHRS-v1.3.png"), QString("INS")); + ftw->removeTab(ConfigGadgetWidget::hardware); + qwd = new ConfigProHWWidget(this); + ftw->insertTab(ConfigGadgetWidget::hardware, qwd, QIcon(":/configgadget/images/hw_config.png"), QString("HW Settings")); + ftw->setCurrentIndex(ConfigGadgetWidget::hardware); } } - - emit autopilotConnected(); } + + diff --git a/ground/openpilotgcs/src/plugins/config/configgadgetwidget.h b/ground/openpilotgcs/src/plugins/config/configgadgetwidget.h index 5bf3e8f0a..6cfa6e20d 100644 --- a/ground/openpilotgcs/src/plugins/config/configgadgetwidget.h +++ b/ground/openpilotgcs/src/plugins/config/configgadgetwidget.h @@ -34,28 +34,35 @@ #include "objectpersistence.h" #include #include +//#include +#include +#include "utils/pathutils.h" -#include "fancytabwidget.h" +//#include "fancytabwidget.h" +#include "utils/mytabbedstackwidget.h" class ConfigGadgetWidget: public QWidget { Q_OBJECT + QTextBrowser* help; public: ConfigGadgetWidget(QWidget *parent = 0); ~ConfigGadgetWidget(); + enum widgetTabs {hardware=0, aircraft, input, output, ins, stabilization, camerastabilization}; public slots: void onAutopilotConnect(); + void onAutopilotDisconnect(); signals: void autopilotConnected(); + void autopilotDisconnected(); protected: void resizeEvent(QResizeEvent * event); - FancyTabWidget *ftw; - + MyTabbedStackWidget *ftw; }; #endif // CONFIGGADGETWIDGET_H diff --git a/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp b/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp index 5b79254e2..83e1a02ac 100644 --- a/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp @@ -35,14 +35,19 @@ #include #include #include +#include +#include +#include + +#include "manualcontrolsettings.h" ConfigInputWidget::ConfigInputWidget(QWidget *parent) : ConfigTaskWidget(parent) { m_config = new Ui_InputWidget(); m_config->setupUi(this); - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager *objManager = pm->getObject(); // First of all, put all the channel widgets into lists, so that we can // manipulate those: @@ -66,15 +71,6 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : ConfigTaskWidget(parent) << m_config->ch6Min << m_config->ch7Min; - inNeuLabels << m_config->ch0Cur - << m_config->ch1Cur - << m_config->ch2Cur - << m_config->ch3Cur - << m_config->ch4Cur - << m_config->ch5Cur - << m_config->ch6Cur - << m_config->ch7Cur; - inSliders << m_config->inSlider0 << m_config->inSlider1 << m_config->inSlider2 @@ -93,20 +89,28 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : ConfigTaskWidget(parent) << m_config->ch6Rev << m_config->ch7Rev; + inChannelAssign << m_config->ch0Assign + << m_config->ch1Assign + << m_config->ch2Assign + << m_config->ch3Assign + << m_config->ch4Assign + << m_config->ch5Assign + << m_config->ch6Assign + << m_config->ch7Assign; // Now connect the widget to the ManualControlCommand / Channel UAVObject - UAVDataObject* obj = dynamic_cast(objManager->getObject(QString("ManualControlCommand"))); connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(updateChannels(UAVObject*))); + // Register for ManualControlSettings changes: + obj = dynamic_cast(objManager->getObject(QString("ManualControlSettings"))); + connect(obj,SIGNAL(objectUpdated(UAVObject*)),this,SLOT(refreshValues())); + + // Get the receiver types supported by OpenPilot and fill the corresponding // dropdown menu: obj = dynamic_cast(objManager->getObject(QString("ManualControlSettings"))); - QString fieldName = QString("InputMode"); - UAVObjectField *field = obj->getField(fieldName); - m_config->receiverType->addItems(field->getOptions()); - m_config->receiverType->setDisabled(true); // This option does not work for now, it is a compile-time option. - + UAVObjectField * field; // Fill in the dropdown menus for the channel RC Input assignement. QStringList channelsList; channelsList << "None"; @@ -149,32 +153,14 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : ConfigTaskWidget(parent) m_config->armControl->clear(); m_config->armControl->addItems(field->getOptions()); - requestRCInputUpdate(); connect(m_config->saveRCInputToSD, SIGNAL(clicked()), this, SLOT(saveRCInputObject())); connect(m_config->saveRCInputToRAM, SIGNAL(clicked()), this, SLOT(sendRCInputUpdate())); - connect(m_config->getRCInputCurrent, SIGNAL(clicked()), this, SLOT(requestRCInputUpdate())); - // Flightmode panel is connected to the same as rcinput because - // the underlying object is the same! - connect(m_config->saveFmsToSD, SIGNAL(clicked()), this, SLOT(saveRCInputObject())); - connect(m_config->saveFmsToRAM, SIGNAL(clicked()), this, SLOT(sendRCInputUpdate())); - connect(m_config->getFmsCurrent, SIGNAL(clicked()), this, SLOT(requestRCInputUpdate())); - - connect(m_config->saveArmToSD, SIGNAL(clicked()), this, SLOT(saveRCInputObject())); - connect(m_config->saveArmToRAM, SIGNAL(clicked()), this, SLOT(sendRCInputUpdate())); - connect(m_config->getArmCurrent, SIGNAL(clicked()), this, SLOT(requestRCInputUpdate())); - - connect(parent, SIGNAL(autopilotConnected()),this, SLOT(requestRCInputUpdate())); - - connect(m_config->inSlider0, SIGNAL(valueChanged(int)),this, SLOT(onInSliderValueChanged0(int))); - connect(m_config->inSlider1, SIGNAL(valueChanged(int)),this, SLOT(onInSliderValueChanged1(int))); - connect(m_config->inSlider2, SIGNAL(valueChanged(int)),this, SLOT(onInSliderValueChanged2(int))); - connect(m_config->inSlider3, SIGNAL(valueChanged(int)),this, SLOT(onInSliderValueChanged3(int))); - connect(m_config->inSlider4, SIGNAL(valueChanged(int)),this, SLOT(onInSliderValueChanged4(int))); - connect(m_config->inSlider5, SIGNAL(valueChanged(int)),this, SLOT(onInSliderValueChanged5(int))); - connect(m_config->inSlider6, SIGNAL(valueChanged(int)),this, SLOT(onInSliderValueChanged6(int))); - connect(m_config->inSlider7, SIGNAL(valueChanged(int)),this, SLOT(onInSliderValueChanged7(int))); + enableControls(false); + refreshValues(); + connect(parent, SIGNAL(autopilotConnected()),this, SLOT(onAutopilotConnect())); + connect(parent, SIGNAL(autopilotDisconnected()), this, SLOT(onAutopilotDisconnect())); connect(m_config->ch0Rev, SIGNAL(toggled(bool)), this, SLOT(reverseCheckboxClicked(bool))); connect(m_config->ch1Rev, SIGNAL(toggled(bool)), this, SLOT(reverseCheckboxClicked(bool))); @@ -184,21 +170,13 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : ConfigTaskWidget(parent) connect(m_config->ch5Rev, SIGNAL(toggled(bool)), this, SLOT(reverseCheckboxClicked(bool))); connect(m_config->ch6Rev, SIGNAL(toggled(bool)), this, SLOT(reverseCheckboxClicked(bool))); connect(m_config->ch7Rev, SIGNAL(toggled(bool)), this, SLOT(reverseCheckboxClicked(bool))); - + connect(m_config->doRCInputCalibration,SIGNAL(stateChanged(int)),this,SLOT(updateTips(int))); firstUpdate = true; - enableControls(false); + // Connect the help button + connect(m_config->inputHelp, SIGNAL(clicked()), this, SLOT(openHelp())); + updateTips(Qt::Unchecked); - // Listen to telemetry connection events - if (pm) { - TelemetryManager *tm = pm->getObject(); - if (tm) { - connect(tm, SIGNAL(myStart()), this, SLOT(onTelemetryStart())); - connect(tm, SIGNAL(myStop()), this, SLOT(onTelemetryStop())); - connect(tm, SIGNAL(connected()), this, SLOT(onTelemetryConnect())); - connect(tm, SIGNAL(disconnected()), this, SLOT(onTelemetryDisconnect())); - } - } } ConfigInputWidget::~ConfigInputWidget() @@ -224,98 +202,19 @@ void ConfigInputWidget::reverseCheckboxClicked(bool state) } } -// ************************************ -// slider value changed signals - -void ConfigInputWidget::onInSliderValueChanged0(int value) -{ - inNeuLabels[0]->setText(QString::number(value)); -} - -void ConfigInputWidget::onInSliderValueChanged1(int value) -{ - inNeuLabels[1]->setText(QString::number(value)); -} - -void ConfigInputWidget::onInSliderValueChanged2(int value) -{ - inNeuLabels[2]->setText(QString::number(value)); -} - -void ConfigInputWidget::onInSliderValueChanged3(int value) -{ - inNeuLabels[3]->setText(QString::number(value)); -} - -void ConfigInputWidget::onInSliderValueChanged4(int value) -{ - inNeuLabels[4]->setText(QString::number(value)); -} - -void ConfigInputWidget::onInSliderValueChanged5(int value) -{ - inNeuLabels[5]->setText(QString::number(value)); -} - -void ConfigInputWidget::onInSliderValueChanged6(int value) -{ - inNeuLabels[6]->setText(QString::number(value)); -} - -void ConfigInputWidget::onInSliderValueChanged7(int value) -{ - inNeuLabels[7]->setText(QString::number(value)); -} - -// ************************************ -// telemetry start/stop connect/disconnect signals - -void ConfigInputWidget::onTelemetryStart() -{ -} - -void ConfigInputWidget::onTelemetryStop() -{ -} - -void ConfigInputWidget::onTelemetryConnect() -{ - enableControls(true); -} - -void ConfigInputWidget::onTelemetryDisconnect() -{ - enableControls(false); - m_config->doRCInputCalibration->setChecked(false); -} // ************************************ +/* + Enable or disable some controls depending on whether we are connected + or not to the board. Actually, this i mostly useless IMHO, I don't + know who added this into the code (Ed's note) + */ void ConfigInputWidget::enableControls(bool enable) { - m_config->getRCInputCurrent->setEnabled(enable); - m_config->saveRCInputToRAM->setEnabled(enable); + //m_config->saveRCInputToRAM->setEnabled(enable); m_config->saveRCInputToSD->setEnabled(enable); - - m_config->saveFmsToSD->setEnabled(enable); - m_config->saveFmsToRAM->setEnabled(enable); - m_config->getFmsCurrent->setEnabled(enable); - - m_config->saveArmToSD->setEnabled(enable); - m_config->saveArmToRAM->setEnabled(enable); - m_config->getArmCurrent->setEnabled(enable); - - m_config->doRCInputCalibration->setEnabled(enable); - - m_config->ch0Assign->setEnabled(enable); - m_config->ch1Assign->setEnabled(enable); - m_config->ch2Assign->setEnabled(enable); - m_config->ch3Assign->setEnabled(enable); - m_config->ch4Assign->setEnabled(enable); - m_config->ch5Assign->setEnabled(enable); - m_config->ch6Assign->setEnabled(enable); - m_config->ch7Assign->setEnabled(enable); } @@ -326,11 +225,11 @@ void ConfigInputWidget::enableControls(bool enable) /** Request the current config from the board */ -void ConfigInputWidget::requestRCInputUpdate() +void ConfigInputWidget::refreshValues() { UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ManualControlSettings"))); Q_ASSERT(obj); - obj->requestUpdate(); + //obj->requestUpdate(); UAVObjectField *field; // Now update all the slider values: @@ -361,17 +260,12 @@ void ConfigInputWidget::requestRCInputUpdate() // Update receiver type field = obj->getField(QString("InputMode")); - m_config->receiverType->setCurrentIndex(m_config->receiverType->findText(field->getValue().toString())); + m_config->receiverType->setText(field->getValue().toString()); // Reset all channel assignement dropdowns: - m_config->ch0Assign->setCurrentIndex(0); - m_config->ch1Assign->setCurrentIndex(0); - m_config->ch2Assign->setCurrentIndex(0); - m_config->ch3Assign->setCurrentIndex(0); - m_config->ch4Assign->setCurrentIndex(0); - m_config->ch5Assign->setCurrentIndex(0); - m_config->ch6Assign->setCurrentIndex(0); - m_config->ch7Assign->setCurrentIndex(0); + foreach (QComboBox *combo, inChannelAssign) { + combo->setCurrentIndex(0); + } // Update all channels assignements QList fieldList = obj->getFields(); @@ -434,11 +328,6 @@ void ConfigInputWidget::sendRCInputUpdate() for (int i = 0; i < 8; i++) field->setValue(inSliders[i]->value(), i); - // Set RC Receiver type: - fieldName = QString("InputMode"); - field = obj->getField(fieldName); - field->setValue(m_config->receiverType->currentText()); - // Set Roll/Pitch/Yaw/Etc assignement: // Rule: if two channels have the same setting (which is wrong!) the higher channel // will get the setting. @@ -522,11 +411,9 @@ void ConfigInputWidget::saveRCInputObject() { // Send update so that the latest value is saved sendRCInputUpdate(); - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - UAVDataObject* obj = dynamic_cast(objManager->getObject(QString("ManualControlSettings"))); + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ManualControlSettings"))); Q_ASSERT(obj); - updateObjectPersistance(ObjectPersistence::OPERATION_SAVE, obj); + saveObjectToSD(obj); } @@ -575,41 +462,68 @@ void ConfigInputWidget::updateChannels(UAVObject* controlCommand) QString fieldName = QString("Connected"); UAVObjectField *field = controlCommand->getField(fieldName); if (field->getValue().toBool()) + { m_config->RCInputConnected->setText("RC Receiver connected"); + m_config->lblMissingInputs->setText(""); + } else + { m_config->RCInputConnected->setText("RC Receiver not connected or invalid input configuration (missing channels)"); - + receiverHelp(); + } if (m_config->doRCInputCalibration->isChecked()) { if (firstUpdate) { - // Increase the data rate from the board so that the sliders - // move faster - UAVObject::Metadata mdata = controlCommand->getMetadata(); - mdata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_PERIODIC; - mccDataRate = mdata.flightTelemetryUpdatePeriod; - mdata.flightTelemetryUpdatePeriod = 150; - controlCommand->setMetadata(mdata); - - // Also protect the user by setting all values to zero - // and making the ActuatorCommand object readonly - UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorCommand"))); - mdata = obj->getMetadata(); - mdata.flightAccess = UAVObject::ACCESS_READONLY; - obj->setMetadata(mdata); - UAVObjectField *field = obj->getField("Channel"); - for (int i=0; i< field->getNumElements(); i++) { - field->setValue(0,i); - } - obj->updated(); + // Increase the data rate from the board so that the sliders + // move faster + UAVObject::Metadata mdata = controlCommand->getMetadata(); + mdata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_PERIODIC; + mccDataRate = mdata.flightTelemetryUpdatePeriod; + mdata.flightTelemetryUpdatePeriod = 150; + controlCommand->setMetadata(mdata); + // Also protect the user by setting all values to zero + // and making the ActuatorCommand object readonly + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorCommand"))); + mdata = obj->getMetadata(); + mdata.flightAccess = UAVObject::ACCESS_READONLY; + obj->setMetadata(mdata); + UAVObjectField *field = obj->getField("Channel"); + for (uint i=0; i< field->getNumElements(); i++) { + field->setValue(0,i); } + obj->updated(); + + // OP-534: make sure the airframe can NEVER arm + obj = dynamic_cast(getObjectManager()->getObject(QString("ManualControlSettings"))); + field = obj->getField("Arming"); + field->setValue("Always Disarmed"); + obj->updated(); + + // Last, make sure the user won't apply/save during calibration + m_config->saveRCInputToRAM->setEnabled(false); + m_config->saveRCInputToSD->setEnabled(false); + + // Reset all slider values to zero + field = controlCommand->getField(QString("Channel")); + for (int i = 0; i < 8; i++) + updateChannelInSlider(inSliders[i], inMinLabels[i], inMaxLabels[i], field->getValue(i).toInt(),inRevCheckboxes[i]->isChecked()); + firstUpdate = false; + // Tell a few things to the user: + QMessageBox msgBox; + msgBox.setText(tr("Arming Settings are now set to Always Disarmed for your safety.")); + msgBox.setDetailedText(tr("You will have to reconfigure arming settings yourself afterwards.")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setDefaultButton(QMessageBox::Ok); + msgBox.exec(); + + } field = controlCommand->getField(QString("Channel")); for (int i = 0; i < 8; i++) updateChannelInSlider(inSliders[i], inMinLabels[i], inMaxLabels[i], field->getValue(i).toInt(),inRevCheckboxes[i]->isChecked()); - firstUpdate = false; - } - else { - if (!firstUpdate) { + } + else { + if (!firstUpdate) { // Restore original data rate from the board: UAVObject::Metadata mdata = controlCommand->getMetadata(); mdata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_PERIODIC; @@ -620,44 +534,83 @@ void ConfigInputWidget::updateChannels(UAVObject* controlCommand) mdata = obj->getMetadata(); mdata.flightAccess = UAVObject::ACCESS_READWRITE; obj->setMetadata(mdata); + + // Set some slider values to better defaults + // Find some channels first + int throttleChannel = -1; + int fmChannel = -1; + for (int i=0; i < inChannelAssign.length(); i++) { + if (inChannelAssign.at(i)->currentText() == "Throttle") { + // TODO: this is very ugly, because this relies on the name of the + // channel input, everywhere else in the gadget we don't rely on the + // naming... + throttleChannel = i; + } + if (inChannelAssign.at(i)->currentText() == "FlightMode") { + // TODO: this is very ugly, because this relies on the name of the + // channel input, everywhere else in the gadget we don't rely on the + // naming... + fmChannel = i; + } + } + + // Throttle neutral defaults to 2% of range + if (throttleChannel > -1) { + inSliders.at(throttleChannel)->setValue( + inSliders.at(throttleChannel)->minimum() + + (inSliders.at(throttleChannel)->maximum()- + inSliders.at(throttleChannel)->minimum())*0.02); + } + + // Flight mode at 50% of range: + if (fmChannel > -1) { + inSliders.at(fmChannel)->setValue( + inSliders.at(fmChannel)->minimum()+ + (inSliders.at(fmChannel)->maximum()- + inSliders.at(fmChannel)->minimum())*0.5); + } + + m_config->saveRCInputToRAM->setEnabled(true); + m_config->saveRCInputToSD->setEnabled(true); } firstUpdate = true; } + //Update the Flight mode channel slider - UAVObject* obj = getObjectManager()->getObject("ManualControlSettings"); - // Find the channel currently assigned to flightmode - field = obj->getField("FlightMode"); - int chIndex = field->getOptions().indexOf(field->getValue().toString()); - if (chIndex < field->getOptions().length() - 1) { + ManualControlSettings * manualSettings = ManualControlSettings::GetInstance(getObjectManager()); + ManualControlSettings::DataFields manualSettingsData = manualSettings->getData(); + uint chIndex = manualSettingsData.FlightMode; + if (chIndex < manualSettings->FLIGHTMODE_NONE) { float valueScaled; - int chMin = inSliders[chIndex]->minimum(); - int chMax = inSliders[chIndex]->maximum(); - int chNeutral = inSliders[chIndex]->value(); + int chMin = manualSettingsData.ChannelMin[chIndex]; + int chMax = manualSettingsData.ChannelMax[chIndex]; + int chNeutral = manualSettingsData.ChannelNeutral[chIndex]; int value = controlCommand->getField("Channel")->getValue(chIndex).toInt(); if ((chMax > chMin && value >= chNeutral) || (chMin > chMax && value <= chNeutral)) { - if (chMax != chNeutral) - valueScaled = (float)(value - chNeutral) / (float)(chMax - chNeutral); - else - valueScaled = 0; + if (chMax != chNeutral) + valueScaled = (float)(value - chNeutral) / (float)(chMax - chNeutral); + else + valueScaled = 0; } else { - if (chMin != chNeutral) - valueScaled = (float)(value - chNeutral) / (float)(chNeutral - chMin); - else - valueScaled = 0; + if (chMin != chNeutral) + valueScaled = (float)(value - chNeutral) / (float)(chNeutral - chMin); + else + valueScaled = 0; } - // Bound - if (valueScaled > 1.0) valueScaled = 1.0; - else - if (valueScaled < -1.0) valueScaled = -1.0; + if(valueScaled < -(1.0 / 3.0)) + m_config->fmsSlider->setValue(-100); + else if (valueScaled > (1.0/3.0)) + m_config->fmsSlider->setValue(100); + else + m_config->fmsSlider->setValue(0); - m_config->fmsSlider->setValue(valueScaled * 100); - } + } } void ConfigInputWidget::updateChannelInSlider(QSlider *slider, QLabel *min, QLabel *max, int value, bool reversed) @@ -694,3 +647,83 @@ void ConfigInputWidget::updateChannelInSlider(QSlider *slider, QLabel *min, QLab slider->setValue(value); } } + +void ConfigInputWidget::openHelp() +{ + + QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Input+Configuration", QUrl::StrictMode) ); +} +void ConfigInputWidget::receiverHelp() +{ + QString unassigned; + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager *objManager = pm->getObject(); + UAVDataObject* controlCommand = dynamic_cast(objManager->getObject(QString("ManualControlSettings"))); + + UAVObjectField *field; + + field= controlCommand->getField("Roll"); + if(field->getValue().toString()=="None") + unassigned.append("Roll"); + + field =controlCommand->getField("Pitch"); + if(field->getValue().toString()=="None") + { + if(unassigned.length()>0) + unassigned.append(", "); + unassigned.append("Pitch"); + } + + field =controlCommand->getField("Yaw"); + if(field->getValue().toString()=="None") + { + if(unassigned.length()>0) + unassigned.append(", "); + unassigned.append("Yaw"); + } + + field =controlCommand->getField("Throttle"); + if(field->getValue().toString()=="None") + { + if(unassigned.length()>0) + unassigned.append(", "); + unassigned.append("Throttle"); + } + + field =controlCommand->getField("FlightMode"); + if(field->getValue().toString()=="None") + { + if(unassigned.length()>0) + unassigned.append(", "); + unassigned.append("FlightMode"); + } + if(unassigned.length()>0) + m_config->lblMissingInputs->setText(QString("Channels left to assign: ")+unassigned); + else + m_config->lblMissingInputs->setText(""); +} +void ConfigInputWidget::updateTips(int value) +{ + if(value==Qt::Checked) + { + m_config->ch0Cur->setToolTip("Current channel value"); + m_config->ch1Cur->setToolTip("Current channel value"); + m_config->ch2Cur->setToolTip("Current channel value"); + m_config->ch3Cur->setToolTip("Current channel value"); + m_config->ch4Cur->setToolTip("Current channel value"); + m_config->ch5Cur->setToolTip("Current channel value"); + m_config->ch6Cur->setToolTip("Current channel value"); + m_config->ch7Cur->setToolTip("Current channel value"); + } + else + { + m_config->ch0Cur->setToolTip("Channel neutral point"); + m_config->ch1Cur->setToolTip("Channel neutral point"); + m_config->ch2Cur->setToolTip("Channel neutral point"); + m_config->ch3Cur->setToolTip("Channel neutral point"); + m_config->ch4Cur->setToolTip("Channel neutral point"); + m_config->ch5Cur->setToolTip("Channel neutral point"); + m_config->ch6Cur->setToolTip("Channel neutral point"); + m_config->ch7Cur->setToolTip("Channel neutral point"); + } +} diff --git a/ground/openpilotgcs/src/plugins/config/configinputwidget.h b/ground/openpilotgcs/src/plugins/config/configinputwidget.h index 4f0fa0182..75f47cc8d 100644 --- a/ground/openpilotgcs/src/plugins/config/configinputwidget.h +++ b/ground/openpilotgcs/src/plugins/config/configinputwidget.h @@ -46,19 +46,6 @@ public: ~ConfigInputWidget(); public slots: - void onTelemetryStart(); - void onTelemetryStop(); - void onTelemetryConnect(); - void onTelemetryDisconnect(); - - void onInSliderValueChanged0(int value); - void onInSliderValueChanged1(int value); - void onInSliderValueChanged2(int value); - void onInSliderValueChanged3(int value); - void onInSliderValueChanged4(int value); - void onInSliderValueChanged5(int value); - void onInSliderValueChanged6(int value); - void onInSliderValueChanged7(int value); private: Ui_InputWidget *m_config; @@ -79,17 +66,20 @@ private: QList inMinLabels; QList inNeuLabels; QList inRevCheckboxes; + QList inChannelAssign; bool firstUpdate; - void enableControls(bool enable); - + virtual void enableControls(bool enable); + void receiverHelp(); private slots: void updateChannels(UAVObject* obj); - void requestRCInputUpdate(); + virtual void refreshValues(); void sendRCInputUpdate(); void saveRCInputObject(); void reverseCheckboxClicked(bool state); + void openHelp(); + void updateTips(int); }; #endif diff --git a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp index a762ce742..1a961805b 100644 --- a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp @@ -36,6 +36,8 @@ #include #include #include +#include +#include ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(parent) { @@ -94,30 +96,18 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren << m_config->ch6Rev << m_config->ch7Rev; - links << m_config->ch0Link - << m_config->ch1Link - << m_config->ch2Link - << m_config->ch3Link - << m_config->ch4Link - << m_config->ch5Link - << m_config->ch6Link - << m_config->ch7Link; - - UAVDataObject * obj = dynamic_cast(objManager->getObject(QString("ActuatorSettings"))); - QList fieldList = obj->getFields(); - foreach (UAVObjectField* field, fieldList) { - if (field->getUnits().contains("channel")) { - m_config->ch0Output->addItem(field->getName()); - m_config->ch1Output->addItem(field->getName()); - m_config->ch2Output->addItem(field->getName()); - m_config->ch3Output->addItem(field->getName()); - m_config->ch4Output->addItem(field->getName()); - m_config->ch5Output->addItem(field->getName()); - m_config->ch6Output->addItem(field->getName()); - m_config->ch7Output->addItem(field->getName()); - } - } + links << m_config->ch0Link + << m_config->ch1Link + << m_config->ch2Link + << m_config->ch3Link + << m_config->ch4Link + << m_config->ch5Link + << m_config->ch6Link + << m_config->ch7Link; + // Register for ActuatorSettings changes: + UAVDataObject * obj = dynamic_cast(objManager->getObject(QString("ActuatorSettings"))); + connect(obj,SIGNAL(objectUpdated(UAVObject*)),this,SLOT(refreshValues())); for (int i = 0; i < 8; i++) { connect(outMin[i], SIGNAL(editingFinished()), this, SLOT(setChOutRange())); @@ -129,37 +119,25 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren connect(m_config->channelOutTest, SIGNAL(toggled(bool)), this, SLOT(runChannelTests(bool))); - for (int i = 0; i < links.count(); i++) - links[i]->setChecked(false); - for (int i = 0; i < links.count(); i++) - connect(links[i], SIGNAL(toggled(bool)), this, SLOT(linkToggled(bool))); - - requestRCOutputUpdate(); + for (int i = 0; i < links.count(); i++) + links[i]->setChecked(false); + for (int i = 0; i < links.count(); i++) + connect(links[i], SIGNAL(toggled(bool)), this, SLOT(linkToggled(bool))); connect(m_config->saveRCOutputToSD, SIGNAL(clicked()), this, SLOT(saveRCOutputObject())); connect(m_config->saveRCOutputToRAM, SIGNAL(clicked()), this, SLOT(sendRCOutputUpdate())); - connect(m_config->getRCOutputCurrent, SIGNAL(clicked()), this, SLOT(requestRCOutputUpdate())); - connect(parent, SIGNAL(autopilotConnected()),this, SLOT(requestRCOutputUpdate())); + enableControls(false); + refreshValues(); + connect(parent, SIGNAL(autopilotConnected()),this, SLOT(onAutopilotConnect())); + connect(parent, SIGNAL(autopilotDisconnected()), this, SLOT(onAutopilotDisconnect())); firstUpdate = true; connect(m_config->spinningArmed, SIGNAL(toggled(bool)), this, SLOT(setSpinningArmed(bool))); - enableControls(false); - - // Listen to telemetry connection events - if (pm) - { - TelemetryManager *tm = pm->getObject(); - if (tm) - { - connect(tm, SIGNAL(myStart()), this, SLOT(onTelemetryStart())); - connect(tm, SIGNAL(myStop()), this, SLOT(onTelemetryStop())); - connect(tm, SIGNAL(connected()), this, SLOT(onTelemetryConnect())); - connect(tm, SIGNAL(disconnected()), this, SLOT(onTelemetryDisconnect())); - } - } + // Connect the help button + connect(m_config->outputHelp, SIGNAL(clicked()), this, SLOT(openHelp())); } ConfigOutputWidget::~ConfigOutputWidget() @@ -168,35 +146,12 @@ ConfigOutputWidget::~ConfigOutputWidget() } - -// ************************************ -// telemetry start/stop connect/disconnect signals - -void ConfigOutputWidget::onTelemetryStart() -{ -} - -void ConfigOutputWidget::onTelemetryStop() -{ -} - -void ConfigOutputWidget::onTelemetryConnect() -{ - enableControls(true); -} - -void ConfigOutputWidget::onTelemetryDisconnect() -{ - enableControls(false); -} - // ************************************ void ConfigOutputWidget::enableControls(bool enable) { m_config->saveRCOutputToSD->setEnabled(enable); - m_config->saveRCOutputToRAM->setEnabled(enable); - m_config->getRCOutputCurrent->setEnabled(enable); + //m_config->saveRCOutputToRAM->setEnabled(enable); } // ************************************ @@ -206,29 +161,30 @@ void ConfigOutputWidget::enableControls(bool enable) */ void ConfigOutputWidget::linkToggled(bool state) { - // find the minimum slider value for the linked ones - int min = 10000; - int linked_count = 0; - for (int i = 0; i < outSliders.count(); i++) - { - if (!links[i]->checkState()) continue; - int value = outSliders[i]->value(); - if (min > value) min = value; - linked_count++; - } + Q_UNUSED(state) + // find the minimum slider value for the linked ones + int min = 10000; + int linked_count = 0; + for (int i = 0; i < outSliders.count(); i++) + { + if (!links[i]->checkState()) continue; + int value = outSliders[i]->value(); + if (min > value) min = value; + linked_count++; + } - if (linked_count <= 0) - return; // no linked channels + if (linked_count <= 0) + return; // no linked channels - if (!m_config->channelOutTest->checkState()) - return; // we are not in Test Output mode + if (!m_config->channelOutTest->checkState()) + return; // we are not in Test Output mode - // set the linked channels to the same value - for (int i = 0; i < outSliders.count(); i++) - { - if (!links[i]->checkState()) continue; - outSliders[i]->setValue(min); - } + // set the linked channels to the same value + for (int i = 0; i < outSliders.count(); i++) + { + if (!links[i]->checkState()) continue; + outSliders[i]->setValue(min); + } } /** @@ -240,7 +196,7 @@ void ConfigOutputWidget::runChannelTests(bool state) // Confirm this is definitely what they want if(state) { QMessageBox mbox; - mbox.setText(QString(tr("This option will requires you to be in the armed state and will start your motors by the amount selected on the sliders. It is recommended to remove any blades from motors. Are you sure you want to do this?"))); + mbox.setText(QString(tr("This option will start your motors by the amount selected on the sliders regardless of transmitter. It is recommended to remove any blades from motors. Are you sure you want to do this?"))); mbox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); int retval = mbox.exec(); if(retval != QMessageBox::Yes) { @@ -265,17 +221,34 @@ void ConfigOutputWidget::runChannelTests(bool state) mdata.gcsTelemetryAcked = false; mdata.gcsTelemetryUpdateMode = UAVObject::UPDATEMODE_ONCHANGE; mdata.gcsTelemetryUpdatePeriod = 100; + + // Prevent stupid users from touching the minimum & maximum ranges while + // moving the sliders. Thanks Ivan for the tip :) + foreach (QSpinBox* box, outMin) { + box->setEnabled(false); + } + foreach (QSpinBox* box, outMax) { + box->setEnabled(false); + } + } else { mdata = accInitialData; // Restore metadata + foreach (QSpinBox* box, outMin) { + box->setEnabled(true); + } + foreach (QSpinBox* box, outMax) { + box->setEnabled(true); + } + } obj->setMetadata(mdata); } /** - * Set the dropdown option for a channel output assignement + * Set the label for a channel output assignement */ void ConfigOutputWidget::assignOutputChannel(UAVDataObject *obj, QString str) { @@ -283,28 +256,28 @@ void ConfigOutputWidget::assignOutputChannel(UAVDataObject *obj, QString str) QStringList options = field->getOptions(); switch (options.indexOf(field->getValue().toString())) { case 0: - m_config->ch0Output->setCurrentIndex(m_config->ch0Output->findText(str)); + m_config->ch0Output->setText(str); break; case 1: - m_config->ch1Output->setCurrentIndex(m_config->ch1Output->findText(str)); + m_config->ch1Output->setText(str); break; case 2: - m_config->ch2Output->setCurrentIndex(m_config->ch2Output->findText(str)); + m_config->ch2Output->setText(str); break; case 3: - m_config->ch3Output->setCurrentIndex(m_config->ch3Output->findText(str)); + m_config->ch3Output->setText(str); break; case 4: - m_config->ch4Output->setCurrentIndex(m_config->ch4Output->findText(str)); + m_config->ch4Output->setText(str); break; case 5: - m_config->ch5Output->setCurrentIndex(m_config->ch5Output->findText(str)); + m_config->ch5Output->setText(str); break; case 6: - m_config->ch6Output->setCurrentIndex(m_config->ch6Output->findText(str)); + m_config->ch6Output->setText(str); break; case 7: - m_config->ch7Output->setCurrentIndex(m_config->ch7Output->findText(str)); + m_config->ch7Output->setText(str); break; } } @@ -382,25 +355,24 @@ void ConfigOutputWidget::sendChannelTest(int value) /** Request the current config from the board (RC Output) */ -void ConfigOutputWidget::requestRCOutputUpdate() +void ConfigOutputWidget::refreshValues() { ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); UAVObjectManager *objManager = pm->getObject(); // Reset all channel assignements: - m_config->ch0Output->setCurrentIndex(0); - m_config->ch1Output->setCurrentIndex(0); - m_config->ch2Output->setCurrentIndex(0); - m_config->ch3Output->setCurrentIndex(0); - m_config->ch4Output->setCurrentIndex(0); - m_config->ch5Output->setCurrentIndex(0); - m_config->ch6Output->setCurrentIndex(0); - m_config->ch7Output->setCurrentIndex(0); + m_config->ch0Output->setText("-"); + m_config->ch1Output->setText("-"); + m_config->ch2Output->setText("-"); + m_config->ch3Output->setText("-"); + m_config->ch4Output->setText("-"); + m_config->ch5Output->setText("-"); + m_config->ch6Output->setText("-"); + m_config->ch7Output->setText("-"); // Get the channel assignements: UAVDataObject * obj = dynamic_cast(objManager->getObject(QString("ActuatorSettings"))); Q_ASSERT(obj); - obj->requestUpdate(); QList fieldList = obj->getFields(); foreach (UAVObjectField* field, fieldList) { if (field->getUnits().contains("channel")) { @@ -508,57 +480,9 @@ void ConfigOutputWidget::sendRCOutputUpdate() field->setValue(m_config->outputRate3->value(),2); field->setValue(m_config->outputRate4->value(),3); - // Set Actuator assignement for each channel: - // Rule: if two channels have the same setting (which is wrong!) the higher channel - // will get the setting. - - // First, reset all channel assignements: - QList fieldList = obj->getFields(); - foreach (UAVObjectField* field, fieldList) { - // NOTE: we assume that all options in ActuatorSettings are a channel assignement - // except for the options called "ChannelXXX" - if (field->getUnits().contains("channel")) { - field->setValue(field->getOptions().last()); - } - } - - if (m_config->ch0Output->currentIndex() != 0) { - field = obj->getField(m_config->ch0Output->currentText()); - field->setValue(field->getOptions().at(0)); // -> This way we don't depend on channel naming convention - } - if (m_config->ch1Output->currentIndex() != 0) { - field = obj->getField(m_config->ch1Output->currentText()); - field->setValue(field->getOptions().at(1)); // -> This way we don't depend on channel naming convention - } - if (m_config->ch2Output->currentIndex() != 0) { - field = obj->getField(m_config->ch2Output->currentText()); - field->setValue(field->getOptions().at(2)); // -> This way we don't depend on channel naming convention - } - if (m_config->ch3Output->currentIndex() != 0) { - field = obj->getField(m_config->ch3Output->currentText()); - field->setValue(field->getOptions().at(3)); // -> This way we don't depend on channel naming convention - } - if (m_config->ch4Output->currentIndex() != 0) { - field = obj->getField(m_config->ch4Output->currentText()); - field->setValue(field->getOptions().at(4)); // -> This way we don't depend on channel naming convention - } - if (m_config->ch5Output->currentIndex() != 0) { - field = obj->getField(m_config->ch5Output->currentText()); - field->setValue(field->getOptions().at(5)); // -> This way we don't depend on channel naming convention - } - if (m_config->ch6Output->currentIndex() != 0) { - field = obj->getField(m_config->ch6Output->currentText()); - field->setValue(field->getOptions().at(6)); // -> This way we don't depend on channel naming convention - } - if (m_config->ch7Output->currentIndex() != 0) { - field = obj->getField(m_config->ch7Output->currentText()); - field->setValue(field->getOptions().at(7)); // -> This way we don't depend on channel naming convention - } - // ... and send to the OP Board obj->updated(); - } @@ -569,11 +493,9 @@ void ConfigOutputWidget::saveRCOutputObject() { // Send update so that the latest value is saved sendRCOutputUpdate(); - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - UAVDataObject* obj = dynamic_cast(objManager->getObject(QString("ActuatorSettings"))); + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); Q_ASSERT(obj); - updateObjectPersistance(ObjectPersistence::OPERATION_SAVE, obj); + saveObjectToSD(obj); } @@ -582,8 +504,8 @@ void ConfigOutputWidget::saveRCOutputObject() Sets the minimum/maximum value of the channel 0 to seven output sliders. Have to do it here because setMinimum is not a slot. - One added trick: if the slider is at either its max or its min when the value - is changed, then keep it on the max/min. + One added trick: if the slider is at its min when the value + is changed, then keep it on the min. */ void ConfigOutputWidget::setChOutRange() { @@ -596,7 +518,7 @@ void ConfigOutputWidget::setChOutRange() QSlider *slider = outSliders[index]; int oldMini = slider->minimum(); - int oldMaxi = slider->maximum(); +// int oldMaxi = slider->maximum(); if (outMin[index]->value()value()) { @@ -651,5 +573,10 @@ void ConfigOutputWidget::reverseChannel(bool state) } +void ConfigOutputWidget::openHelp() +{ + + QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Output+Configuration", QUrl::StrictMode) ); +} diff --git a/ground/openpilotgcs/src/plugins/config/configoutputwidget.h b/ground/openpilotgcs/src/plugins/config/configoutputwidget.h index f3083e725..2a197e3ac 100644 --- a/ground/openpilotgcs/src/plugins/config/configoutputwidget.h +++ b/ground/openpilotgcs/src/plugins/config/configoutputwidget.h @@ -46,12 +46,6 @@ public: ConfigOutputWidget(QWidget *parent = 0); ~ConfigOutputWidget(); -public slots: - void onTelemetryStart(); - void onTelemetryStop(); - void onTelemetryConnect(); - void onTelemetryDisconnect(); - private: Ui_OutputWidget *m_config; @@ -75,10 +69,10 @@ private: bool firstUpdate; - void enableControls(bool enable); + virtual void enableControls(bool enable); private slots: - void requestRCOutputUpdate(); + virtual void refreshValues(); void sendRCOutputUpdate(); void saveRCOutputObject(); void runChannelTests(bool state); @@ -87,6 +81,7 @@ private slots: void reverseChannel(bool state); void linkToggled(bool state); void setSpinningArmed(bool val); + void openHelp(); }; #endif diff --git a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp index 1005c178a..5cd0cfa04 100644 --- a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.cpp @@ -32,8 +32,8 @@ #include #include #include - - +#include +#include ConfigStabilizationWidget::ConfigStabilizationWidget(QWidget *parent) : ConfigTaskWidget(parent) { @@ -42,15 +42,18 @@ ConfigStabilizationWidget::ConfigStabilizationWidget(QWidget *parent) : ConfigTa m_stabilization = new Ui_StabilizationWidget(); m_stabilization->setupUi(this); - // Now connect the widget to the ManualControlCommand / Channel UAVObject - UAVObject *obj = dynamic_cast(getObjectManager()->getObject(QString("StabilizationSettings"))); - requestStabilizationUpdate(); connect(m_stabilization->saveStabilizationToSD, SIGNAL(clicked()), this, SLOT(saveStabilizationUpdate())); connect(m_stabilization->saveStabilizationToRAM, SIGNAL(clicked()), this, SLOT(sendStabilizationUpdate())); - connect(m_stabilization->getStabilizationCurrent, SIGNAL(clicked()), this, SLOT(requestStabilizationUpdate())); - connect(parent, SIGNAL(autopilotConnected()),this, SLOT(requestStabilizationUpdate())); + enableControls(false); + refreshValues(); + connect(parent, SIGNAL(autopilotConnected()),this, SLOT(onAutopilotConnect())); + connect(parent, SIGNAL(autopilotDisconnected()),this, SLOT(onAutopilotDisconnect())); + + // Now connect the widget to the StabilizationSettings object + UAVObject *obj = getObjectManager()->getObject(QString("StabilizationSettings")); + connect(obj,SIGNAL(objectUpdated(UAVObject*)),this,SLOT(refreshValues())); // Create a timer to regularly send the object update in case // we want realtime updates. @@ -74,6 +77,8 @@ ConfigStabilizationWidget::ConfigStabilizationWidget(QWidget *parent) : ConfigTa connect(m_stabilization->pitchKi, SIGNAL(valueChanged(double)), this, SLOT(updatePitchKI(double))); connect(m_stabilization->pitchILimit, SIGNAL(valueChanged(double)), this, SLOT(updatePitchILimit(double))); + // Connect the help button + connect(m_stabilization->stabilizationHelp, SIGNAL(clicked()), this, SLOT(openHelp())); } ConfigStabilizationWidget::~ConfigStabilizationWidget() @@ -82,6 +87,12 @@ ConfigStabilizationWidget::~ConfigStabilizationWidget() } +void ConfigStabilizationWidget::enableControls(bool enable) +{ + //m_stabilization->saveStabilizationToRAM->setEnabled(enable); + m_stabilization->saveStabilizationToSD->setEnabled(enable); +} + void ConfigStabilizationWidget::updateRateRollKP(double val) { if (m_stabilization->linkRateRP->isChecked()) { @@ -176,22 +187,24 @@ void ConfigStabilizationWidget::updatePitchILimit(double val) /** Request stabilization settings from the board */ -void ConfigStabilizationWidget::requestStabilizationUpdate() +void ConfigStabilizationWidget::refreshValues() { - stabSettings->requestUpdate(); + // Not needed anymore as this slot is only called whenever we get + // a signal that the object was just updated + // stabSettings->requestUpdate(); StabilizationSettings::DataFields stabData = stabSettings->getData(); // Now fill in all the fields, this is fairly tedious: - m_stabilization->rateRollKp->setValue(stabData.RollRatePI[StabilizationSettings::ROLLRATEPI_KP]); - m_stabilization->rateRollKi->setValue(stabData.RollRatePI[StabilizationSettings::ROLLRATEPI_KI]); - m_stabilization->rateRollILimit->setValue(stabData.RollRatePI[StabilizationSettings::ROLLRATEPI_ILIMIT]); + m_stabilization->rateRollKp->setValue(stabData.RollRatePID[StabilizationSettings::ROLLRATEPID_KP]); + m_stabilization->rateRollKi->setValue(stabData.RollRatePID[StabilizationSettings::ROLLRATEPID_KI]); + m_stabilization->rateRollILimit->setValue(stabData.RollRatePID[StabilizationSettings::ROLLRATEPID_ILIMIT]); - m_stabilization->ratePitchKp->setValue(stabData.PitchRatePI[StabilizationSettings::PITCHRATEPI_KP]); - m_stabilization->ratePitchKi->setValue(stabData.PitchRatePI[StabilizationSettings::PITCHRATEPI_KI]); - m_stabilization->ratePitchILimit->setValue(stabData.PitchRatePI[StabilizationSettings::PITCHRATEPI_ILIMIT]); + m_stabilization->ratePitchKp->setValue(stabData.PitchRatePID[StabilizationSettings::PITCHRATEPID_KP]); + m_stabilization->ratePitchKi->setValue(stabData.PitchRatePID[StabilizationSettings::PITCHRATEPID_KI]); + m_stabilization->ratePitchILimit->setValue(stabData.PitchRatePID[StabilizationSettings::PITCHRATEPID_ILIMIT]); - m_stabilization->rateYawKp->setValue(stabData.YawRatePI[StabilizationSettings::YAWRATEPI_KP]); - m_stabilization->rateYawKi->setValue(stabData.YawRatePI[StabilizationSettings::YAWRATEPI_KI]); - m_stabilization->rateYawILimit->setValue(stabData.YawRatePI[StabilizationSettings::YAWRATEPI_ILIMIT]); + m_stabilization->rateYawKp->setValue(stabData.YawRatePID[StabilizationSettings::YAWRATEPID_KP]); + m_stabilization->rateYawKi->setValue(stabData.YawRatePID[StabilizationSettings::YAWRATEPID_KI]); + m_stabilization->rateYawILimit->setValue(stabData.YawRatePID[StabilizationSettings::YAWRATEPID_ILIMIT]); m_stabilization->rollKp->setValue(stabData.RollPI[StabilizationSettings::ROLLPI_KP]); m_stabilization->rollKi->setValue(stabData.RollPI[StabilizationSettings::ROLLPI_KI]); @@ -209,6 +222,16 @@ void ConfigStabilizationWidget::requestStabilizationUpdate() m_stabilization->pitchMax->setValue(stabData.PitchMax); m_stabilization->yawMax->setValue(stabData.YawMax); + m_stabilization->manualRoll->setValue(stabData.ManualRate[StabilizationSettings::MANUALRATE_ROLL]); + m_stabilization->manualPitch->setValue(stabData.ManualRate[StabilizationSettings::MANUALRATE_PITCH]); + m_stabilization->manualYaw->setValue(stabData.ManualRate[StabilizationSettings::MANUALRATE_YAW]); + + m_stabilization->maximumRoll->setValue(stabData.MaximumRate[StabilizationSettings::MAXIMUMRATE_ROLL]); + m_stabilization->maximumPitch->setValue(stabData.MaximumRate[StabilizationSettings::MAXIMUMRATE_PITCH]); + m_stabilization->maximumYaw->setValue(stabData.MaximumRate[StabilizationSettings::MAXIMUMRATE_YAW]); + + m_stabilization->lowThrottleZeroIntegral->setChecked( + stabData.LowThrottleZeroIntegral == StabilizationSettings::LOWTHROTTLEZEROINTEGRAL_TRUE); } @@ -220,17 +243,17 @@ void ConfigStabilizationWidget::sendStabilizationUpdate() { StabilizationSettings::DataFields stabData = stabSettings->getData(); - stabData.RollRatePI[StabilizationSettings::ROLLRATEPI_KP] = m_stabilization->rateRollKp->value(); - stabData.RollRatePI[StabilizationSettings::ROLLRATEPI_KI] = m_stabilization->rateRollKi->value(); - stabData.RollRatePI[StabilizationSettings::ROLLRATEPI_ILIMIT] = m_stabilization->rateRollILimit->value(); + stabData.RollRatePID[StabilizationSettings::ROLLRATEPID_KP] = m_stabilization->rateRollKp->value(); + stabData.RollRatePID[StabilizationSettings::ROLLRATEPID_KI] = m_stabilization->rateRollKi->value(); + stabData.RollRatePID[StabilizationSettings::ROLLRATEPID_ILIMIT] = m_stabilization->rateRollILimit->value(); - stabData.PitchRatePI[StabilizationSettings::PITCHRATEPI_KP] = m_stabilization->ratePitchKp->value(); - stabData.PitchRatePI[StabilizationSettings::PITCHRATEPI_KI] = m_stabilization->ratePitchKi->value(); - stabData.PitchRatePI[StabilizationSettings::PITCHRATEPI_ILIMIT] = m_stabilization->ratePitchILimit->value(); + stabData.PitchRatePID[StabilizationSettings::PITCHRATEPID_KP] = m_stabilization->ratePitchKp->value(); + stabData.PitchRatePID[StabilizationSettings::PITCHRATEPID_KI] = m_stabilization->ratePitchKi->value(); + stabData.PitchRatePID[StabilizationSettings::PITCHRATEPID_ILIMIT] = m_stabilization->ratePitchILimit->value(); - stabData.YawRatePI[StabilizationSettings::YAWRATEPI_KP] = m_stabilization->rateYawKp->value(); - stabData.YawRatePI[StabilizationSettings::YAWRATEPI_KI] = m_stabilization->rateYawKi->value(); - stabData.YawRatePI[StabilizationSettings::YAWRATEPI_ILIMIT] = m_stabilization->rateYawILimit->value(); + stabData.YawRatePID[StabilizationSettings::YAWRATEPID_KP] = m_stabilization->rateYawKp->value(); + stabData.YawRatePID[StabilizationSettings::YAWRATEPID_KI] = m_stabilization->rateYawKi->value(); + stabData.YawRatePID[StabilizationSettings::YAWRATEPID_ILIMIT] = m_stabilization->rateYawILimit->value(); stabData.RollPI[StabilizationSettings::ROLLPI_KP] = m_stabilization->rollKp->value(); stabData.RollPI[StabilizationSettings::ROLLPI_KI] = m_stabilization->rollKi->value(); @@ -248,6 +271,18 @@ void ConfigStabilizationWidget::sendStabilizationUpdate() stabData.PitchMax = m_stabilization->pitchMax->value(); stabData.YawMax = m_stabilization->yawMax->value(); + stabData.ManualRate[StabilizationSettings::MANUALRATE_ROLL] = m_stabilization->manualRoll->value(); + stabData.ManualRate[StabilizationSettings::MANUALRATE_PITCH] = m_stabilization->manualPitch->value(); + stabData.ManualRate[StabilizationSettings::MANUALRATE_YAW] = m_stabilization->manualYaw->value(); + + stabData.MaximumRate[StabilizationSettings::MAXIMUMRATE_ROLL] = m_stabilization->maximumRoll->value(); + stabData.MaximumRate[StabilizationSettings::MAXIMUMRATE_PITCH] = m_stabilization->maximumPitch->value(); + stabData.MaximumRate[StabilizationSettings::MAXIMUMRATE_YAW] = m_stabilization->maximumYaw->value(); + + stabData.LowThrottleZeroIntegral = m_stabilization->lowThrottleZeroIntegral->isChecked() ? + StabilizationSettings::LOWTHROTTLEZEROINTEGRAL_TRUE : + StabilizationSettings::LOWTHROTTLEZEROINTEGRAL_FALSE; + stabSettings->setData(stabData); // this is atomic } @@ -260,18 +295,24 @@ void ConfigStabilizationWidget::saveStabilizationUpdate() { // Send update so that the latest value is saved sendStabilizationUpdate(); - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - UAVDataObject* obj = dynamic_cast(objManager->getObject(QString("StabilizationSettings"))); + UAVDataObject* obj = dynamic_cast(getObjectManager()->getObject(QString("StabilizationSettings"))); Q_ASSERT(obj); - updateObjectPersistance(ObjectPersistence::OPERATION_SAVE, obj); + saveObjectToSD(obj); } void ConfigStabilizationWidget::realtimeUpdateToggle(bool state) { - if (state) + if (state) { updateTimer.start(300); - else + } else { updateTimer.stop(); + } } + +void ConfigStabilizationWidget::openHelp() +{ + + QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Stabilization+panel", QUrl::StrictMode) ); +} + diff --git a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.h b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.h index 557aa263a..98db5530f 100644 --- a/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.h +++ b/ground/openpilotgcs/src/plugins/config/configstabilizationwidget.h @@ -49,13 +49,14 @@ private: Ui_StabilizationWidget *m_stabilization; StabilizationSettings* stabSettings; QTimer updateTimer; - + virtual void enableControls(bool enable); private slots: - void requestStabilizationUpdate(); + virtual void refreshValues(); void sendStabilizationUpdate(); void saveStabilizationUpdate(); void realtimeUpdateToggle(bool); + void openHelp(); void updateRateRollKP(double); void updateRateRollKI(double); @@ -72,8 +73,6 @@ private slots: void updatePitchKP(double); void updatePitchKI(double); void updatePitchILimit(double); - - }; #endif // ConfigStabilizationWidget_H diff --git a/ground/openpilotgcs/src/plugins/config/configtaskwidget.cpp b/ground/openpilotgcs/src/plugins/config/configtaskwidget.cpp index 8fb743ef0..8fd35c596 100644 --- a/ground/openpilotgcs/src/plugins/config/configtaskwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configtaskwidget.cpp @@ -28,113 +28,83 @@ #include -ConfigTaskWidget::ConfigTaskWidget(QWidget *parent) : QWidget(parent) +ConfigTaskWidget::ConfigTaskWidget(QWidget *parent) : QWidget(parent),smartsave(NULL),dirty(false) { - saveState = IDLE; - queue.clear(); + pm = ExtensionSystem::PluginManager::instance(); + objManager = pm->getObject(); + connect(parent, SIGNAL(autopilotConnected()),this, SLOT(onAutopilotConnect())); + connect(parent, SIGNAL(autopilotDisconnected()),this, SLOT(onAutopilotDisconnect())); } +void ConfigTaskWidget::addWidget(QWidget * widget) +{ + addUAVObjectToWidgetRelation("","",widget); +} +void ConfigTaskWidget::addUAVObject(QString objectName) +{ + addUAVObjectToWidgetRelation(objectName,"",NULL); +} +void ConfigTaskWidget::addUAVObjectToWidgetRelation(QString object, QString field, QWidget * widget) +{ + UAVObject *obj=NULL; + UAVObjectField *_field=NULL; + if(!object.isEmpty()) + obj = objManager->getObject(QString(object)); + connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshWidgetsValues())); + //smartsave->addObject(obj); + if(!field.isEmpty() && obj) + _field = obj->getField(QString(field)); + objectToWidget * ow=new objectToWidget(); + ow->field=_field; + ow->object=obj; + ow->widget=widget; + objOfInterest.append(ow); + if(obj) + smartsave->addObject(obj); + if(widget==NULL) + { + // do nothing + } + else if(QComboBox * cb=qobject_cast(widget)) + { + connect(cb,SIGNAL(currentIndexChanged(int)),this,SLOT(widgetsContentsChanged())); + } + else if(QSlider * cb=qobject_cast(widget)) + { + connect(cb,SIGNAL(sliderMoved(int)),this,SLOT(widgetsContentsChanged())); + } + else if(MixerCurveWidget * cb=qobject_cast(widget)) + { + connect(cb,SIGNAL(curveUpdated(QList,double)),this,SLOT(widgetsContentsChanged())); + } + else if(QTableWidget * cb=qobject_cast(widget)) + { + connect(cb,SIGNAL(cellChanged(int,int)),this,SLOT(widgetsContentsChanged())); + } + else if(QSpinBox * cb=qobject_cast(widget)) + { + connect(cb,SIGNAL(valueChanged(int)),this,SLOT(widgetsContentsChanged())); + } + else if(QDoubleSpinBox * cb=qobject_cast(widget)) + { + connect(cb,SIGNAL(valueChanged(double)),this,SLOT(widgetsContentsChanged())); + } +} + ConfigTaskWidget::~ConfigTaskWidget() { - // Do nothing + delete smartsave; } void ConfigTaskWidget::saveObjectToSD(UAVObject *obj) { - // Add to queue - queue.enqueue(obj); - // If queue length is one, then start sending (call sendNextObject) - // Otherwise, do nothing, it's sending anyway - if (queue.length()==1) - saveNextObject(); - + // saveObjectToSD is now handled by the UAVUtils plugin in one + // central place (and one central queue) + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectUtilManager* utilMngr = pm->getObject(); + utilMngr->saveObjectToSD(obj); } -void ConfigTaskWidget::saveNextObject() -{ - if ( queue.isEmpty() ) - { - return; - } - - Q_ASSERT(saveState == IDLE); - - // Get next object from the queue - UAVObject* obj = queue.head(); - ObjectPersistence* objper = dynamic_cast( getObjectManager()->getObject(ObjectPersistence::NAME) ); - connect(objper, SIGNAL(transactionCompleted(UAVObject*,bool)), this, SLOT(objectPersistenceTransactionCompleted(UAVObject*,bool))); - connect(objper, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(objectPersistenceUpdated(UAVObject *))); - saveState = AWAITING_ACK; - if (obj != NULL) - { - ObjectPersistence::DataFields data; - data.Operation = ObjectPersistence::OPERATION_SAVE; - data.Selection = ObjectPersistence::SELECTION_SINGLEOBJECT; - data.ObjectID = obj->getObjID(); - data.InstanceID = obj->getInstID(); - objper->setData(data); - objper->updated(); - } -} - -/** - * @brief Process the transactionCompleted message from Telemetry indicating request sent successfully - * @param[in] The object just transsacted. Must be ObjectPersistance - * @param[in] success Indicates that the transaction did not time out - * - * After a failed transaction (usually timeout) resends the save request. After a succesful - * transaction will then wait for a save completed update from the autopilot. - */ -void ConfigTaskWidget::objectPersistenceTransactionCompleted(UAVObject* obj, bool success) -{ - if(success) { - Q_ASSERT(obj->getName().compare("ObjectPersistence") == 0); - Q_ASSERT(saveState == AWAITING_ACK); - saveState = AWAITING_COMPLETED; - disconnect(obj, SIGNAL(transactionCompleted(UAVObject*,bool)), this, SLOT(objectPersistenceTransactionCompleted(UAVObject*,bool))); - } else if (!success) { - // Can be caused by timeout errors on sending. Send again. - saveNextObject(); - } -} - -/** - * @brief Process the ObjectPersistence updated message to confirm the right object saved - * then requests next object be saved. - * @param[in] The object just received. Must be ObjectPersistance - */ -void ConfigTaskWidget::objectPersistenceUpdated(UAVObject * obj) -{ - Q_ASSERT(obj->getName().compare("ObjectPersistence") == 0); - if(saveState == AWAITING_COMPLETED) { - // Check flight is saying it completed. This is the only thing flight should do to trigger an update. - Q_ASSERT( obj->getField("Operation")->getValue().toString().compare(QString("Completed")) == 0 ); - - // Check right object saved - UAVObject* savingObj = queue.head(); - Q_ASSERT( obj->getField("ObjectID")->getValue() == savingObj->getObjID() ); - - obj->disconnect(this); - queue.dequeue(); // We can now remove the object, it's done. - saveState = IDLE; - saveNextObject(); - } -} - -void ConfigTaskWidget::updateObjectPersistance(ObjectPersistence::OperationOptions op, UAVObject *obj) -{ - ObjectPersistence* objper = dynamic_cast( getObjectManager()->getObject(ObjectPersistence::NAME) ); - if (obj != NULL) - { - ObjectPersistence::DataFields data; - data.Operation = op; - data.Selection = ObjectPersistence::SELECTION_SINGLEOBJECT; - data.ObjectID = obj->getObjID(); - data.InstanceID = obj->getInstID(); - objper->setData(data); - objper->updated(); - } -} UAVObjectManager* ConfigTaskWidget::getObjectManager() { ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); @@ -151,6 +121,137 @@ double ConfigTaskWidget::listMean(QList list) return accum / list.size(); } +// ************************************ +// telemetry start/stop connect/disconnect signals + +void ConfigTaskWidget::onAutopilotDisconnect() +{ + enableControls(false); +} + +void ConfigTaskWidget::onAutopilotConnect() +{ + enableControls(true); + refreshWidgetsValues(); +} + +void ConfigTaskWidget::populateWidgets() +{ + foreach(objectToWidget * ow,objOfInterest) + { + if(ow->object==NULL || ow->field==NULL) + { + // do nothing + } + else if(QComboBox * cb=qobject_cast(ow->widget)) + { + cb->addItems(ow->field->getOptions()); + cb->setCurrentIndex(cb->findText(ow->field->getValue().toString())); + } + else if(QLabel * cb=qobject_cast(ow->widget)) + { + cb->setText(ow->field->getValue().toString()); + } + } + dirty=false; +} + +void ConfigTaskWidget::refreshWidgetsValues() +{ + foreach(objectToWidget * ow,objOfInterest) + { + if(ow->object==NULL || ow->field==NULL) + { + //do nothing + } + else if(QComboBox * cb=qobject_cast(ow->widget)) + { + cb->setCurrentIndex(cb->findText(ow->field->getValue().toString())); + } + else if(QLabel * cb=qobject_cast(ow->widget)) + { + cb->setText(ow->field->getValue().toString()); + } + } +} + +void ConfigTaskWidget::updateObjectsFromWidgets() +{ + foreach(objectToWidget * ow,objOfInterest) + { + if(ow->object==NULL || ow->field==NULL) + { + //do nothing + } + else if(QComboBox * cb=qobject_cast(ow->widget)) + { + ow->field->setValue(cb->currentText()); + } + else if(QLabel * cb=qobject_cast(ow->widget)) + { + ow->field->setValue(cb->text()); + } + } +} + +void ConfigTaskWidget::setupButtons(QPushButton *update, QPushButton *save) +{ + smartsave=new smartSaveButton(update,save); + connect(smartsave, SIGNAL(preProcessOperations()), this, SLOT(updateObjectsFromWidgets())); + connect(smartsave,SIGNAL(saveSuccessfull()),this,SLOT(clearDirty())); + connect(smartsave,SIGNAL(beginOp()),this,SLOT(disableObjUpdates())); + connect(smartsave,SIGNAL(endOp()),this,SLOT(enableObjUpdates())); +} + +void ConfigTaskWidget::enableControls(bool enable) +{ + if(smartsave) + smartsave->enableControls(enable); +} + +void ConfigTaskWidget::widgetsContentsChanged() +{ + dirty=true; +} + +void ConfigTaskWidget::clearDirty() +{ + dirty=false; +} + +bool ConfigTaskWidget::isDirty() +{ + return dirty; +} + +void ConfigTaskWidget::refreshValues() +{ +} + +void ConfigTaskWidget::disableObjUpdates() +{ + foreach(objectToWidget * obj,objOfInterest) + { + if(obj->object) + disconnect(obj->object, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshWidgetsValues())); + } +} + +void ConfigTaskWidget::enableObjUpdates() +{ + foreach(objectToWidget * obj,objOfInterest) + { + if(obj->object) + connect(obj->object, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(refreshWidgetsValues())); + } +} + + + + + + + /** @} diff --git a/ground/openpilotgcs/src/plugins/config/configtaskwidget.h b/ground/openpilotgcs/src/plugins/config/configtaskwidget.h index 0650ddb25..bd293ce5f 100644 --- a/ground/openpilotgcs/src/plugins/config/configtaskwidget.h +++ b/ground/openpilotgcs/src/plugins/config/configtaskwidget.h @@ -31,34 +31,60 @@ #include "extensionsystem/pluginmanager.h" #include "uavobjectmanager.h" #include "uavobject.h" -#include "objectpersistence.h" +#include "uavobjectutilmanager.h" #include #include #include - - +#include +#include "smartsavebutton.h" +#include "mixercurvewidget.h" +#include +#include +#include class ConfigTaskWidget: public QWidget { Q_OBJECT public: + struct objectToWidget + { + UAVObject * object; + UAVObjectField * field; + QWidget * widget; + }; + ConfigTaskWidget(QWidget *parent = 0); ~ConfigTaskWidget(); void saveObjectToSD(UAVObject *obj); - void updateObjectPersistance(ObjectPersistence::OperationOptions op, UAVObject *obj); UAVObjectManager* getObjectManager(); - static double listMean(QList list); + void addUAVObject(QString objectName); + void addWidget(QWidget * widget); + void addUAVObjectToWidgetRelation(QString object,QString field,QWidget * widget); + void setupButtons(QPushButton * update,QPushButton * save); + bool isDirty(); +public slots: + void onAutopilotDisconnect(); + void onAutopilotConnect(); private slots: - void objectPersistenceTransactionCompleted(UAVObject* obj, bool success); - void objectPersistenceUpdated(UAVObject * obj); - + virtual void refreshValues(); + virtual void updateObjectsFromWidgets(); private: - QQueue queue; - void saveNextObject(); - enum {IDLE, AWAITING_ACK, AWAITING_COMPLETED} saveState; - + QList objOfInterest; + ExtensionSystem::PluginManager *pm; + UAVObjectManager *objManager; + smartSaveButton *smartsave; + bool dirty; +protected slots: + virtual void disableObjUpdates(); + virtual void enableObjUpdates(); + virtual void clearDirty(); + virtual void widgetsContentsChanged(); + virtual void populateWidgets(); + virtual void refreshWidgetsValues(); +protected: + virtual void enableControls(bool enable); }; diff --git a/ground/openpilotgcs/src/plugins/config/configtelemetrywidget.cpp b/ground/openpilotgcs/src/plugins/config/configtelemetrywidget.cpp deleted file mode 100644 index fa9838de1..000000000 --- a/ground/openpilotgcs/src/plugins/config/configtelemetrywidget.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/** - ****************************************************************************** - * - * @file configtelemetrywidget.h - * @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup ConfigPlugin Config Plugin - * @{ - * @brief The Configuration Gadget used to update settings in the firmware - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "configtelemetrywidget.h" - -#include -#include -#include -#include -#include -#include - - - -ConfigTelemetryWidget::ConfigTelemetryWidget(QWidget *parent) : ConfigTaskWidget(parent) -{ - m_telemetry = new Ui_TelemetryWidget(); - m_telemetry->setupUi(this); - - // Now connect the widget to the ManualControlCommand / Channel UAVObject - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - - UAVObject *obj = dynamic_cast(objManager->getObject(QString("TelemetrySettings"))); - UAVObjectField *field = obj->getField(QString("Speed")); - m_telemetry->telemetrySpeed->addItems(field->getOptions()); - - requestTelemetryUpdate(); - connect(m_telemetry->saveTelemetryToSD, SIGNAL(clicked()), this, SLOT(saveTelemetryUpdate())); - connect(m_telemetry->saveTelemetryToRAM, SIGNAL(clicked()), this, SLOT(sendTelemetryUpdate())); - connect(m_telemetry->getTelemetryCurrent, SIGNAL(clicked()), this, SLOT(requestTelemetryUpdate())); - - connect(parent, SIGNAL(autopilotConnected()),this, SLOT(requestTelemetryUpdate())); - -} - -ConfigTelemetryWidget::~ConfigTelemetryWidget() -{ - // Do nothing -} - - -/******************************* - * Telemetry Settings - *****************************/ - -/** - Request telemetry settings from the board - */ -void ConfigTelemetryWidget::requestTelemetryUpdate() -{ - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - UAVDataObject* obj = dynamic_cast(objManager->getObject(QString("TelemetrySettings"))); - Q_ASSERT(obj); - obj->requestUpdate(); - UAVObjectField *field = obj->getField(QString("Speed")); - m_telemetry->telemetrySpeed->setCurrentIndex(m_telemetry->telemetrySpeed->findText(field->getValue().toString())); -} - -/** - Send telemetry settings to the board - */ -void ConfigTelemetryWidget::sendTelemetryUpdate() -{ - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - UAVDataObject* obj = dynamic_cast(objManager->getObject(QString("TelemetrySettings"))); - Q_ASSERT(obj); - UAVObjectField* field = obj->getField(QString("Speed")); - field->setValue(m_telemetry->telemetrySpeed->currentText()); - obj->updated(); -} - -/** - Send telemetry settings to the board and request saving to SD card - */ -void ConfigTelemetryWidget::saveTelemetryUpdate() -{ - // Send update so that the latest value is saved - sendTelemetryUpdate(); - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - UAVDataObject* obj = dynamic_cast(objManager->getObject(QString("TelemetrySettings"))); - Q_ASSERT(obj); - updateObjectPersistance(ObjectPersistence::OPERATION_SAVE, obj); -} - - diff --git a/ground/openpilotgcs/src/plugins/config/defaultattitudewidget.cpp b/ground/openpilotgcs/src/plugins/config/defaultattitudewidget.cpp index 8fb68d910..4705bb02e 100644 --- a/ground/openpilotgcs/src/plugins/config/defaultattitudewidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/defaultattitudewidget.cpp @@ -31,7 +31,7 @@ #include DefaultAttitudeWidget::DefaultAttitudeWidget(QWidget *parent) : - ConfigTaskWidget(parent), + QWidget(parent), ui(new Ui_defaultattitude) { ui->setupUi(this); diff --git a/ground/openpilotgcs/src/plugins/config/defaultattitudewidget.h b/ground/openpilotgcs/src/plugins/config/defaultattitudewidget.h index 25b8809d4..5541eee37 100644 --- a/ground/openpilotgcs/src/plugins/config/defaultattitudewidget.h +++ b/ground/openpilotgcs/src/plugins/config/defaultattitudewidget.h @@ -38,7 +38,7 @@ class Ui_Widget; -class DefaultAttitudeWidget : public ConfigTaskWidget +class DefaultAttitudeWidget : public QWidget { Q_OBJECT diff --git a/ground/openpilotgcs/src/plugins/config/defaulthwsettings.ui b/ground/openpilotgcs/src/plugins/config/defaulthwsettings.ui new file mode 100644 index 000000000..d1ef7d913 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/defaulthwsettings.ui @@ -0,0 +1,77 @@ + + + defaulthwsettings + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt; font-weight:600;">Hardware Configuration</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu'; font-size:11pt; font-weight:600;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;">This panel will be updated to provide the relevant controls to let you configure your hardware once telemetry is connected and running.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu'; font-size:11pt;"></p></body></html> + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/config/defaulthwsettingswidget.cpp b/ground/openpilotgcs/src/plugins/config/defaulthwsettingswidget.cpp new file mode 100644 index 000000000..69eef9117 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/defaulthwsettingswidget.cpp @@ -0,0 +1,44 @@ +/** + ****************************************************************************** + * + * @file DefaultHwSettingsWidget.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief Placeholder for attitude panel until board is connected. + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "defaulthwsettingswidget.h" +#include "ui_defaultattitude.h" +#include +#include +#include + +DefaultHwSettingsWidget::DefaultHwSettingsWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui_defaulthwsettings) +{ + ui->setupUi(this); +} + +DefaultHwSettingsWidget::~DefaultHwSettingsWidget() +{ + delete ui; +} + diff --git a/ground/openpilotgcs/src/plugins/config/defaulthwsettingswidget.h b/ground/openpilotgcs/src/plugins/config/defaulthwsettingswidget.h new file mode 100644 index 000000000..e94435f8d --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/defaulthwsettingswidget.h @@ -0,0 +1,55 @@ +/** + ****************************************************************************** + * + * @file defaultccattitudewidget.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief Placeholder for attitude settings widget until board connected. + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef DEFAULTHWSETTINGSt_H +#define DEFAULTHWSETTINGSt_H + +#include "ui_defaulthwsettings.h" +#include "configtaskwidget.h" +#include "extensionsystem/pluginmanager.h" +#include "uavobjectmanager.h" +#include "uavobject.h" +#include +#include +#include + +class Ui_Widget; + +class DefaultHwSettingsWidget : public QWidget +{ + Q_OBJECT + +public: + explicit DefaultHwSettingsWidget(QWidget *parent = 0); + ~DefaultHwSettingsWidget(); + +private slots: + +private: + Ui_defaulthwsettings *ui; +}; + +#endif // DEFAULTHWSETTINGSt_H diff --git a/ground/openpilotgcs/src/plugins/config/images/camera.png b/ground/openpilotgcs/src/plugins/config/images/camera.png new file mode 100644 index 000000000..50ee47904 Binary files /dev/null and b/ground/openpilotgcs/src/plugins/config/images/camera.png differ diff --git a/ground/openpilotgcs/src/plugins/config/images/coptercontrol.svg b/ground/openpilotgcs/src/plugins/config/images/coptercontrol.svg new file mode 100644 index 000000000..669199ef6 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/images/coptercontrol.svg @@ -0,0 +1,2647 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/ground/openpilotgcs/src/plugins/config/images/gyroscope.png b/ground/openpilotgcs/src/plugins/config/images/gyroscope.png new file mode 100644 index 000000000..b6277f5cc Binary files /dev/null and b/ground/openpilotgcs/src/plugins/config/images/gyroscope.png differ diff --git a/ground/openpilotgcs/src/plugins/config/images/help2.png b/ground/openpilotgcs/src/plugins/config/images/help2.png new file mode 100644 index 000000000..d161c0455 Binary files /dev/null and b/ground/openpilotgcs/src/plugins/config/images/help2.png differ diff --git a/ground/openpilotgcs/src/plugins/config/images/hw_config.png b/ground/openpilotgcs/src/plugins/config/images/hw_config.png new file mode 100644 index 000000000..ff69b90f3 Binary files /dev/null and b/ground/openpilotgcs/src/plugins/config/images/hw_config.png differ diff --git a/ground/openpilotgcs/src/plugins/config/images/hw_config.svg b/ground/openpilotgcs/src/plugins/config/images/hw_config.svg new file mode 100644 index 000000000..a40c3c3f3 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/images/hw_config.svg @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/config/images/quad-shapes.svg b/ground/openpilotgcs/src/plugins/config/images/quad-shapes.svg index 8452bfd11..1fccbd6ce 100644 --- a/ground/openpilotgcs/src/plugins/config/images/quad-shapes.svg +++ b/ground/openpilotgcs/src/plugins/config/images/quad-shapes.svg @@ -16,7 +16,7 @@ width="4065.2493" height="1760.019" xml:space="preserve" - sodipodi:docname="quad-shapes.svg">image/svg+xml \ No newline at end of file + inkscape:connector-curvature="0" /> diff --git a/ground/openpilotgcs/src/plugins/config/input.ui b/ground/openpilotgcs/src/plugins/config/input.ui index 61462ed5f..e1eb0b435 100644 --- a/ground/openpilotgcs/src/plugins/config/input.ui +++ b/ground/openpilotgcs/src/plugins/config/input.ui @@ -6,8 +6,8 @@ 0 0 - 617 - 395 + 626 + 532 @@ -19,1394 +19,788 @@ 0 - + RC Input - - - - 530 - 40 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + + + 75 + true + + + + Receiver Type: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + 234 + 54 + + + + + 75 + true + + + + Indicates whether OpenPilot is getting a signal from the RC receiver. + + + RC Receiver not connected or invalid input configuration (missing channels) + + + true + + + + + + + + + Rev. + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + 16 + 16 + + + + true + + + + + + + true + + + 1000 + + + 2000 + + + 1500 + + + Qt::Horizontal + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum channel pulse width</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 2000 - - - - - - 150 - 40 - 51 - 17 - - - - - FreeSans - 10 - 75 - true - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> - - - 1000 - - - - - - 205 - 70 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 1000 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 205 - 220 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 1000 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 150 - 250 - 51 - 17 - - - - - FreeSans - 10 - 75 - true - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> - - - 1000 - - - - - - 530 - 160 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + 2000 + + + + + + + Check this to reverse the channel. +(Useful for transmitters without channel +reversal capabilities). + + + + + + + + + + + + + true + + + 1000 + + + 2000 + + + 1500 + + + Qt::Horizontal + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum channel pulse width</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 2000 - - - - - - 205 - 250 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 1000 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 260 - 280 - 93 - 27 - - - - Retrieve settings from OpenPilot - - - Get Current - - - - - - 205 - 100 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 1000 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 530 - 220 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + 2000 + + + + + + + Check this to reverse the channel. +(Useful for transmitters without channel +reversal capabilities). + + + + + + + + + + + + + true + + + 1000 + + + 2000 + + + 1500 + + + Qt::Horizontal + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum channel pulse width</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 2000 - - - - - - 530 - 190 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + 2000 + + + + + + + Check this to reverse the channel. +(Useful for transmitters without channel +reversal capabilities). + + + + + + + + + + + + + true + + + 1000 + + + 2000 + + + 1500 + + + Qt::Horizontal + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum channel pulse width</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 2000 - - - - - - 530 - 130 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + 2000 + + + + + + + Check this to reverse the channel. +(Useful for transmitters without channel +reversal capabilities). + + + + + + + + + + + + + true + + + 1000 + + + 2000 + + + 1500 + + + Qt::Horizontal + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum channel pulse width</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 2000 - - - - - - 460 - 280 - 93 - 27 - - - - Be sure to set the Neutral position on all sliders before sending! -Applies and Saves all settings to SD - - - Save - - - - - - 150 - 160 - 51 - 17 - - - - - FreeSans - 10 - 75 - true - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> - - - 1000 - - - - - - 205 - 160 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 1000 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 360 - 280 - 93 - 27 - - - - Send to OpenPilot but don't write in SD. -Be sure to set the Neutral position on all sliders before sending! - - - Apply - - - - - - 20 - 40 - 121 - 21 - - - - - MS Shell Dlg 2 - 8 - - - - - 16 - 16 - - - - true - - - - - - 205 - 130 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 1000 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 530 - 250 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + 2000 + + + + + + + Check this to reverse the channel. +(Useful for transmitters without channel +reversal capabilities). + + + + + + + + + + + + + true + + + 1000 + + + 2000 + + + 1500 + + + Qt::Horizontal + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum channel pulse width</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 2000 - - - - - - 150 - 100 - 51 - 17 - - - - - FreeSans - 10 - 75 - true - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> - - - 1000 - - - - - - 150 - 190 - 51 - 17 - - - - - FreeSans - 10 - 75 - true - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> - - - 1000 - - - - - - 205 - 190 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 1000 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 150 - 70 - 51 - 17 - - - - - FreeSans - 10 - 75 - true - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> - - - 1000 - - - - - - 150 - 220 - 51 - 17 - - - - - FreeSans - 10 - 75 - true - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> - - - 1000 - - - - - - 150 - 130 - 51 - 17 - - - - - FreeSans - 10 - 75 - true - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> - - - 1000 - - - - - - 530 - 100 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + 2000 + + + + + + + Check this to reverse the channel. +(Useful for transmitters without channel +reversal capabilities). + + + + + + + + + + + + + true + + + 1000 + + + 2000 + + + 1500 + + + Qt::Horizontal + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum channel pulse width</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 2000 - - - - - - 530 - 70 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + 2000 + + + + + + + Check this to reverse the channel. +(Useful for transmitters without channel +reversal capabilities). + + + + + + + + + + + + + true + + + 1000 + + + 2000 + + + 1500 + + + Qt::Horizontal + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum channel pulse width</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 2000 - - - - - - 205 - 40 - 36 - 17 - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> - - - 1000 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 20 - 70 - 121 - 21 - - - - - MS Shell Dlg 2 - 8 - - - - - - - 20 - 100 - 121 - 21 - - - - - MS Shell Dlg 2 - 8 - - - - - - - 20 - 130 - 121 - 21 - - - - - MS Shell Dlg 2 - 8 - - - - - - - 20 - 160 - 121 - 21 - - - - - MS Shell Dlg 2 - 8 - - - - - - - 20 - 190 - 121 - 21 - - - - - MS Shell Dlg 2 - 8 - - - - - - - 20 - 220 - 121 - 21 - - - - - MS Shell Dlg 2 - 8 - - - - - - - 20 - 250 - 121 - 21 - - - - - MS Shell Dlg 2 - 8 - - - - - - - 20 - 283 - 181 - 22 - - - - - 75 - true - - - - Start calibrating the RC Inputs. + + + 2000 + + + + + + + Check this to reverse the channel. +(Useful for transmitters without channel +reversal capabilities). + + + + + + + + + + + 75 + true + + + + BEWARE: make sure your engines are not connected when running calibration! + + + + + + + + + 75 + true + + + + + + + + + + + + 50 + false + + + + Start calibrating the RC Inputs. Uncheck/Check to restart calibration. During calibration: move your RC controls over their whole range, then leave them on Neutral, uncheck calibration and save. Neutral should be put at the bottom of the slider for the throttle. - - - Run Calibration - - - - - - 260 - 0 - 291 - 41 - - - - - 11 - 75 - true - - - - Indicates whether OpenPilot is getting a signal from the RC receiver. - - - RC Receiver not connected or invalid input configuration (missing channels) - - - true - - - - - - 140 - 10 - 91 - 21 - - - - Select the receiver type here: -- PWM is the most usual type -- PPM is connected to input XXX -- Spektrum is used with Spektrum 'satellite' receivers - - - - - - 20 - 10 - 111 - 17 - - - - Receiver Type: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 20 - 310 - 561 - 21 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + Run Calibration + + + + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt; font-weight:600; color:#ff0000;">BEWARE: make sure your engines are not connected when running calibration!</span></p></body></html> - - - - - - 250 - 40 - 271 - 21 - - - - true - - - 1000 - - - 2000 - - - 1500 - - - Qt::Horizontal - - - - - - 250 - 70 - 271 - 21 - - - - true - - - 1000 - - - 2000 - - - 1500 - - - Qt::Horizontal - - - - - - 250 - 100 - 271 - 21 - - - - true - - - 1000 - - - 2000 - - - 1500 - - - Qt::Horizontal - - - - - - 250 - 130 - 271 - 21 - - - - true - - - 1000 - - - 2000 - - - 1500 - - - Qt::Horizontal - - - - - - 250 - 160 - 271 - 21 - - - - true - - - 1000 - - - 2000 - - - 1500 - - - Qt::Horizontal - - - - - - 250 - 190 - 271 - 21 - - - - true - - - 1000 - - - 2000 - - - 1500 - - - Qt::Horizontal - - - - - - 250 - 220 - 271 - 21 - - - - true - - - 1000 - - - 2000 - - - 1500 - - - Qt::Horizontal - - - - - - 250 - 250 - 271 - 21 - - - - true - - - 1000 - - - 2000 - - - 1500 - - - Qt::Horizontal - - - - - - 560 - 40 - 21 - 22 - - - - Check this to reverse the channel. -(Useful for transmitters without channel -reversal capabilities). - - - - - - - - - 560 - 20 - 31 - 20 - - - - Rev. - - - - - - 560 - 70 - 21 - 22 - - - - Check this to reverse the channel. -(Useful for transmitters without channel -reversal capabilities). - - - - - - - - - 560 - 100 - 21 - 22 - - - - Check this to reverse the channel. -(Useful for transmitters without channel -reversal capabilities). - - - - - - - - - 560 - 130 - 21 - 22 - - - - Check this to reverse the channel. -(Useful for transmitters without channel -reversal capabilities). - - - - - - - - - 560 - 160 - 21 - 22 - - - - Check this to reverse the channel. -(Useful for transmitters without channel -reversal capabilities). - - - - - - - - - 560 - 190 - 21 - 22 - - - - Check this to reverse the channel. -(Useful for transmitters without channel -reversal capabilities). - - - - - - - - - 560 - 220 - 21 - 22 - - - - Check this to reverse the channel. -(Useful for transmitters without channel -reversal capabilities). - - - - - - - - - 560 - 250 - 21 - 22 - - - - Check this to reverse the channel. -(Useful for transmitters without channel -reversal capabilities). - - - - - +</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> + + + 1000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> + + + 1000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> + + + 1000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> + + + 1000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> + + + 1000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> + + + 1000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> + + + 1000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum channel pulse width</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(microseconds)</p></body></html> + + + 1000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> + + + 1500 + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> + + + 1500 + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> + + + 1500 + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> + + + 1500 + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> + + + 1500 + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> + + + 1500 + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> + + + 1500 + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'FreeSans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Current channel value.</span></p></body></html> + + + 1500 + + + + Flight Mode Switch Settings - - - - 270 - 310 - 93 - 27 - - - - Retrieve settings from OpenPilot - - - Get Current - - - - - - 380 - 310 - 93 - 27 - - - - Send to OpenPilot but don't write in SD. -Be sure to set the Neutral position on all sliders before sending! - - - Apply - - - - - - 490 - 310 - 93 - 27 - - - - Be sure to set the Neutral position on all sliders before sending! -Applies and Saves all settings to SD - - - Save - - - 390 + 310 10 201 17 @@ -1425,7 +819,7 @@ Applies and Saves all settings to SD - 390 + 310 30 201 17 @@ -1444,7 +838,7 @@ Applies and Saves all settings to SD - 10 + 30 130 445 155 @@ -1546,7 +940,7 @@ Applies and Saves all settings to SD - 10 + 30 0 261 121 @@ -1559,9 +953,9 @@ Applies and Saves all settings to SD 100 - 50 + 55 151 - 31 + 26 @@ -1569,9 +963,9 @@ Applies and Saves all settings to SD 100 - 20 + 25 151 - 31 + 26 @@ -1595,9 +989,9 @@ Applies and Saves all settings to SD 100 - 80 + 85 151 - 31 + 26 @@ -1663,7 +1057,7 @@ if you have not done so already. QSlider::TicksBelow - 66 + 100 @@ -1751,6 +1145,13 @@ if you have not done so already. + + + + Airframe disarm is done by throttle off and opposite of above combination. + + + @@ -1764,48 +1165,81 @@ if you have not done so already. - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Get Current - - - - - - - Apply - - - - - - - Save - - - - - + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 32 + 32 + + + + + + + + :/core/images/helpicon.svg:/core/images/helpicon.svg + + + + 32 + 32 + + + + true + + + + + + + Send to OpenPilot but don't write in SD. +Be sure to set the Neutral position on all sliders before sending! + + + Apply + + + + + + + Be sure to set the Neutral position on all sliders before sending! +Applies and Saves all settings to SD + + + Save + + + + + @@ -1817,11 +1251,6 @@ if you have not done so already. ch5Assign ch6Assign ch7Assign - receiverType - doRCInputCalibration - getRCInputCurrent - saveRCInputToRAM - saveRCInputToSD fmsSlider fmsModePos3 fmsSsPos3Roll @@ -1835,10 +1264,138 @@ if you have not done so already. fmsSsPos1Roll fmsSsPos1Pitch fmsSsPos1Yaw - getFmsCurrent - saveFmsToRAM - saveFmsToSD - - + + + + + + inSlider0 + valueChanged(int) + ch0Cur + setNum(int) + + + 291 + 93 + + + 150 + 104 + + + + + inSlider1 + valueChanged(int) + ch1Cur + setNum(int) + + + 283 + 137 + + + 160 + 138 + + + + + inSlider2 + valueChanged(int) + ch2Cur + setNum(int) + + + 341 + 163 + + + 156 + 167 + + + + + inSlider3 + valueChanged(int) + ch3Cur + setNum(int) + + + 283 + 211 + + + 159 + 210 + + + + + inSlider4 + valueChanged(int) + ch4Cur + setNum(int) + + + 287 + 239 + + + 156 + 242 + + + + + inSlider5 + valueChanged(int) + ch5Cur + setNum(int) + + + 309 + 272 + + + 164 + 276 + + + + + inSlider6 + valueChanged(int) + ch6Cur + setNum(int) + + + 282 + 300 + + + 144 + 311 + + + + + inSlider7 + valueChanged(int) + ch7Cur + setNum(int) + + + 278 + 339 + + + 168 + 340 + + + + diff --git a/ground/openpilotgcs/src/plugins/config/mixercurvewidget.cpp b/ground/openpilotgcs/src/plugins/config/mixercurvewidget.cpp index 2acf5babd..6e031d8d7 100644 --- a/ground/openpilotgcs/src/plugins/config/mixercurvewidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/mixercurvewidget.cpp @@ -147,7 +147,17 @@ QList MixerCurveWidget::getCurve() { return list; } - +/** + Sets a linear graph + */ +void MixerCurveWidget::initLinearCurve(quint32 numPoints, double maxValue) +{ + QList points; + for (double i=0; i points); QList getCurve(); + void initLinearCurve(quint32 numPoints, double maxValue); void setCurve(QList); void setMin(double value); void setMax(double value); diff --git a/ground/openpilotgcs/src/plugins/config/output.ui b/ground/openpilotgcs/src/plugins/config/output.ui index db63ba4c7..9c1fdacca 100644 --- a/ground/openpilotgcs/src/plugins/config/output.ui +++ b/ground/openpilotgcs/src/plugins/config/output.ui @@ -6,8 +6,8 @@ 0 0 - 663 - 500 + 659 + 523 @@ -124,16 +124,6 @@ Leave at 50Hz for fixed wing. - - - - Update rate: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - @@ -145,14 +135,76 @@ Leave at 50Hz for fixed wing. - - - Channel: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 40 + 20 + + + + + + + + + 75 + true + + + + Channel: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 40 + 20 + + + + + + + + + 75 + true + + + + Update rate: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + @@ -162,27 +214,7 @@ Leave at 50Hz for fixed wing. - Channel 1 - - - - - - - false - - - - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">This is the actuator connected to this channel.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">You can change this through the &quot;Airframe&quot; dialog (on the left).</span></p></body></html> + Channel 1: @@ -191,11 +223,6 @@ p, li { white-space: pre-wrap; } true - - - 8 - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> @@ -226,11 +253,6 @@ p, li { white-space: pre-wrap; } true - - - 8 - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> @@ -300,27 +322,7 @@ p, li { white-space: pre-wrap; } - Channel 2 - - - - - - - false - - - - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">This is the actuator connected to this channel.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">You can change this through the &quot;Airframe&quot; dialog (on the left).</span></p></body></html> + Channel 2: @@ -329,11 +331,6 @@ p, li { white-space: pre-wrap; } true - - - 8 - - 9999 @@ -357,11 +354,6 @@ p, li { white-space: pre-wrap; } true - - - 8 - - 9999 @@ -407,27 +399,7 @@ p, li { white-space: pre-wrap; } - Channel 3 - - - - - - - false - - - - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">This is the actuator connected to this channel.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">You can change this through the &quot;Airframe&quot; dialog (on the left).</span></p></body></html> + Channel 3: @@ -436,11 +408,6 @@ p, li { white-space: pre-wrap; } true - - - 8 - - 9999 @@ -464,11 +431,6 @@ p, li { white-space: pre-wrap; } true - - - 8 - - 9999 @@ -514,27 +476,7 @@ p, li { white-space: pre-wrap; } - Channel 4 - - - - - - - false - - - - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">This is the actuator connected to this channel.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">You can change this through the &quot;Airframe&quot; dialog (on the left).</span></p></body></html> + Channel 4: @@ -543,11 +485,6 @@ p, li { white-space: pre-wrap; } true - - - 8 - - 9999 @@ -571,11 +508,6 @@ p, li { white-space: pre-wrap; } true - - - 8 - - 9999 @@ -621,37 +553,12 @@ p, li { white-space: pre-wrap; } - Channel 5 - - - - - - - false - - - - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">This is the actuator connected to this channel.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">You can change this through the &quot;Airframe&quot; dialog (on the left).</span></p></body></html> + Channel 5: - - - 8 - - 9999 @@ -669,11 +576,6 @@ p, li { white-space: pre-wrap; } - - - 8 - - 9999 @@ -719,37 +621,12 @@ p, li { white-space: pre-wrap; } - Channel 6 - - - - - - - false - - - - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">This is the actuator connected to this channel.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">You can change this through the &quot;Airframe&quot; dialog (on the left).</span></p></body></html> + Channel 6: - - - 8 - - 9999 @@ -767,11 +644,6 @@ p, li { white-space: pre-wrap; } - - - 8 - - 9999 @@ -817,64 +689,19 @@ p, li { white-space: pre-wrap; } - Channel 7 - - - - - - - false - - - - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">This is the actuator connected to this channel.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">You can change this through the &quot;Airframe&quot; dialog (on the left).</span></p></body></html> + Channel 7: - Channel 8 - - - - - - - false - - - - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">This is the actuator connected to this channel.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans';">You can change this through the &quot;Airframe&quot; dialog (on the left).</span></p></body></html> + Channel 8: - - - 8 - - 9999 @@ -892,11 +719,6 @@ p, li { white-space: pre-wrap; } - - - 8 - - 9999 @@ -941,11 +763,6 @@ p, li { white-space: pre-wrap; } - - - 8 - - 9999 @@ -963,11 +780,6 @@ p, li { white-space: pre-wrap; } - - - 8 - - 9999 @@ -1010,14 +822,171 @@ p, li { white-space: pre-wrap; } + + + + + 9 + + + + - + + + Qt::AlignCenter + + + + + + + + 9 + + + + - + + + Qt::AlignCenter + + + + + + + + 9 + + + + - + + + Qt::AlignCenter + + + + + + + + 9 + + + + - + + + Qt::AlignCenter + + + + + + + + 9 + + + + - + + + Qt::AlignCenter + + + + + + + + 9 + + + + - + + + Qt::AlignCenter + + + + + + + + 9 + + + + - + + + Qt::AlignCenter + + + + + + + + 9 + + + + - + + + Qt::AlignCenter + + + + + + + Assignment + + + - - - Motors spin at neutral output when armed and throttle below zero (be careful) + + + Qt::Vertical - + + + 20 + 40 + + + + + + + + + + Motors spin at neutral output when armed and throttle below zero (be careful) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + @@ -1063,12 +1032,34 @@ p, li { white-space: pre-wrap; } - - - Retrieve settings from OpenPilot + + + + 0 + 0 + + + + + 32 + 32 + - Get Current + + + + + :/core/images/helpicon.svg:/core/images/helpicon.svg + + + + 32 + 32 + + + + true @@ -1119,44 +1110,36 @@ Applies and Saves all settings to SD ch6OutMax ch7OutMin ch7OutMax - ch0Output ch0OutSlider ch0Rev ch0Link - ch1Output ch1OutSlider ch1Rev ch1Link - ch2Output ch2OutSlider ch2Rev ch2Link - ch3Output ch3OutSlider ch3Rev ch3Link - ch4Output ch4OutSlider ch4Rev ch4Link - ch5Output ch5OutSlider ch5Rev ch5Link - ch6Output ch6OutSlider ch6Rev ch6Link - ch7Output ch7OutSlider ch7Rev ch7Link - spinningArmed channelOutTest - getRCOutputCurrent saveRCOutputToRAM saveRCOutputToSD - + + + diff --git a/ground/openpilotgcs/src/plugins/config/pro_hw_settings.ui b/ground/openpilotgcs/src/plugins/config/pro_hw_settings.ui new file mode 100644 index 000000000..6e6751b87 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/pro_hw_settings.ui @@ -0,0 +1,123 @@ + + + PRO_HW_Widget + + + + 0 + 0 + 505 + 389 + + + + Form + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">Set the serial speed of your onboard telemetry modem here. It is the speed between the OpenPilot board and the onboard modem, and could be different from the radio link speed.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">Beware of not locking yourself out! You should only modify this setting when the OpenPilot board is connected through the USB port.</span></p></body></html> + + + + + + + + + + 11 + 75 + true + + + + Telemetry speed: + + + + + + + Select the speed here. + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Send to OpenPilot but don't write in SD. +Beware of not locking yourself out! + + + Apply + + + + + + + Applies and Saves all settings to SD. +Beware of not locking yourself out! + + + Save + + + + + + + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/config/smartsavebutton.cpp b/ground/openpilotgcs/src/plugins/config/smartsavebutton.cpp new file mode 100644 index 000000000..ed5abf2c7 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/smartsavebutton.cpp @@ -0,0 +1,122 @@ +#include "smartsavebutton.h" + +smartSaveButton::smartSaveButton(QPushButton * update, QPushButton * save):bupdate(update),bsave(save) +{ + connect(bsave,SIGNAL(clicked()),this,SLOT(processClick())); + connect(bupdate,SIGNAL(clicked()),this,SLOT(processClick())); + +} +void smartSaveButton::processClick() +{ + emit beginOp(); + bool save=false; + QPushButton *button=bupdate; + if(sender()==bsave) + { + save=true; + button=bsave; + } + emit preProcessOperations(); + button->setEnabled(false); + button->setIcon(QIcon(":/uploader/images/system-run.svg")); + QTimer timer; + timer.setSingleShot(true); + bool error=false; + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectUtilManager* utilMngr = pm->getObject(); + foreach(UAVObject * obj,objects) + { + up_result=false; + current_object=obj; + for(int i=0;i<3;++i) + { + + connect(obj,SIGNAL(transactionCompleted(UAVObject*,bool)),this,SLOT(transaction_finished(UAVObject*, bool))); + connect(&timer,SIGNAL(timeout()),&loop,SLOT(quit())); + obj->updated(); + timer.start(1000); + loop.exec(); + timer.stop(); + disconnect(obj,SIGNAL(transactionCompleted(UAVObject*,bool)),this,SLOT(transaction_finished(UAVObject*, bool))); + disconnect(&timer,SIGNAL(timeout()),&loop,SLOT(quit())); + if(up_result) + break; + } + if(up_result==false) + { + error=true; + continue; + } + sv_result=false; + current_objectID=obj->getObjID(); + if(save) + { + for(int i=0;i<3;++i) + { + connect(utilMngr,SIGNAL(saveCompleted(int,bool)),this,SLOT(saving_finished(int,bool))); + connect(&timer,SIGNAL(timeout()),&loop,SLOT(quit())); + utilMngr->saveObjectToSD(obj); + timer.start(1000); + loop.exec(); + timer.stop(); + disconnect(utilMngr,SIGNAL(saveCompleted(int,bool)),this,SLOT(saving_finished(int,bool))); + disconnect(&timer,SIGNAL(timeout()),&loop,SLOT(quit())); + if(sv_result) + break; + } + if(sv_result==false) + { + error=true; + } + } + } + button->setEnabled(true); + if(!error) + { + button->setIcon(QIcon(":/uploader/images/dialog-apply.svg")); + emit saveSuccessfull(); + } + else + { + button->setIcon(QIcon(":/uploader/images/process-stop.svg")); + } + emit endOp(); +} + +void smartSaveButton::setObjects(QList list) +{ + objects=list; +} + +void smartSaveButton::addObject(UAVObject * obj) +{ + objects.append(obj); +} + +void smartSaveButton::clearObjects() +{ + objects.clear(); +} +void smartSaveButton::transaction_finished(UAVObject* obj, bool result) +{ + if(current_object==obj) + { + up_result=result; + loop.quit(); + } +} + +void smartSaveButton::saving_finished(int id, bool result) +{ + if(id==current_objectID) + { + sv_result=result; + loop.quit(); + } +} + +void smartSaveButton::enableControls(bool value) +{ + bupdate->setEnabled(value); + bsave->setEnabled(value); +} diff --git a/ground/openpilotgcs/src/plugins/config/smartsavebutton.h b/ground/openpilotgcs/src/plugins/config/smartsavebutton.h new file mode 100644 index 000000000..d0238d034 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/smartsavebutton.h @@ -0,0 +1,49 @@ +#ifndef SMARTSAVEBUTTON_H +#define SMARTSAVEBUTTON_H + +#include "uavtalk/telemetrymanager.h" +#include "extensionsystem/pluginmanager.h" +#include "uavobjectmanager.h" +#include "uavobject.h" +#include +#include +#include +#include "uavobjectutilmanager.h" +#include +#include +class smartSaveButton:public QObject +{ +public: + Q_OBJECT +public: + smartSaveButton(QPushButton * update,QPushButton * save); + void setObjects(QList); + void addObject(UAVObject *); + void clearObjects(); +signals: + void preProcessOperations(); + void saveSuccessfull(); + void beginOp(); + void endOp(); +private slots: + void processClick(); + void transaction_finished(UAVObject* obj, bool result); + void saving_finished(int,bool); + +private: + QPushButton *bupdate; + QPushButton *bsave; + quint32 current_objectID; + UAVObject * current_object; + bool up_result; + bool sv_result; + QEventLoop loop; + QList objects; +protected: +public slots: + void enableControls(bool value); + +}; + + +#endif // SMARTSAVEBUTTON_H diff --git a/ground/openpilotgcs/src/plugins/config/stabilization.ui b/ground/openpilotgcs/src/plugins/config/stabilization.ui index a643cde0e..96c414055 100644 --- a/ground/openpilotgcs/src/plugins/config/stabilization.ui +++ b/ground/openpilotgcs/src/plugins/config/stabilization.ui @@ -7,7 +7,7 @@ 0 0 639 - 470 + 611 @@ -15,529 +15,627 @@ - - - - - - - - - - Rate Stabilization (inner loop) - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Hint: read the toolips! - - - - - - - - - First, work on rate stabilization. - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - Roll - - - - - - - Slowly raise Kp until you start seeing clear oscillations when you fly. + + + + 0 + 0 + + + + + 0 + 150 + + + + Rate Stabilization Coefficients (Inner Loop) + + + + + + Kp + + + Qt::AlignCenter + + + + + + + Ki + + + Qt::AlignCenter + + + + + + + ILimit + + + Qt::AlignCenter + + + + + + + Roll + + + + + + + Slowly raise Kp until you start seeing clear oscillations when you fly. Then lower the value by 20% or so. - - - 6 - - - 0.000100000000000 - - - - - - - Pitch - - - - - - - Slowly raise Kp until you start seeing clear oscillations when you fly. -Then lower the value by 20% or so. - - - 6 - - - 0.000100000000000 - - - - - - - Kp - - - Qt::AlignCenter - - - - - - - I factor for rate stabilization is usually very low or even zero. - - - 6 - - - 0.000100000000000 - - - - - - - I factor for rate stabilization is usually very low or even zero. - - - 6 - - - 0.000100000000000 - - - - - - - Ki - - - Qt::AlignCenter - - - - - - - 6 - - - 0.000100000000000 - - - - - - - 6 - - - 0.000100000000000 - - - - - - - ILimit - - - Qt::AlignCenter - - - - - - - If checked, the Roll and Pitch factors will be identical. + + + 6 + + + 0.000100000000000 + + + + + + + I factor for rate stabilization is usually very low or even zero. + + + 6 + + + 0.000100000000000 + + + + + + + 6 + + + 0.000100000000000 + + + + + + + If checked, the Roll and Pitch factors will be identical. When you change one, the other is updated. - - - Link - - - - - - - Yaw - - - - - - - Slowly raise Kp until you start seeing clear oscillations when you fly. + + + Link + + + + + + + Pitch + + + + + + + Slowly raise Kp until you start seeing clear oscillations when you fly. +Then lower the value by 20% or so. + + + 6 + + + 0.000100000000000 + + + + + + + I factor for rate stabilization is usually very low or even zero. + + + 6 + + + 0.000100000000000 + + + + + + + 6 + + + 0.000100000000000 + + + + + + + Yaw + + + + + + + Slowly raise Kp until you start seeing clear oscillations when you fly. Then lower the value by 20% or so. You can usually go for higher values for Yaw factors. - - - 6 - - - 0.000100000000000 - - - - - - - As a rule of thumb, you can set YawRate Ki at roughly the same -value as YawRate Kp. - - - 6 - - - 0.000100000000000 - - - - - - - 6 - - - 0.000100000000000 - - - - - - - - - - Attitude Stabilization (outer loop) - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - If checked, the Roll and Pitch factors will be identical. -When you change one, the other is updated. - - - Link - - - - - - - Roll - - - - - - - Pitch - - - - - - - Yaw - - - - - - - Once Rate stabilization is done, you should increase the Kp factor until the airframe oscillates again, and go back down 20% or so. - - - - 6 - - - 0.100000000000000 - - - - - - - Once Rate stabilization is done, you should increase the Kp factor until the airframe oscillates again, and go back down 20% or so. - - - - 6 - - - 0.100000000000000 - - - - - - - Once Rate stabilization is done, you should increase the Kp factor until the airframe oscillates again, and go back down 20% or so. - - - - 6 - - - 0.100000000000000 - - - - - - - Ki can usually be almost identical to Kp. - - - 6 - - - 0.100000000000000 - - - - - - - Ki can usually be almost identical to Kp. - - - 6 - - - 0.100000000000000 - - - - - - - Ki can usually be almost identical to Kp. - - - 6 - - - 0.100000000000000 - - - - - - - ILimit can be equal to three to four times Ki, but you can adjust -depending on whether your airframe is well balanced, and your -flying style. - - - 6 - - - 0.100000000000000 - - - - - - - ILimit can be equal to three to four times Ki, but you can adjust -depending on whether your airframe is well balanced, and your -flying style. - - - 6 - - - 0.100000000000000 - - - - - - - ILimit can be equal to three to four times Ki, but you can adjust -depending on whether your airframe is well balanced, and your -flying style. - - - 6 - - - 0.100000000000000 - - - - - - - Kp - - - Qt::AlignCenter - - - - - - - Ki - - - Qt::AlignCenter - - - - - - - ILimit - - - Qt::AlignCenter - - - - - - - + + + 6 + + + 0.000100000000000 + + - - - - - - - 75 - true - - - - Angle Limits: - - - - - - - RollMax - - - - - - - 180 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - PitchMax - - - - - - - 180 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - YawMax - - - - - - - 180 - - - - + + + + As a rule of thumb, you can set YawRate Ki at roughly the same +value as YawRate Kp. + + + 6 + + + 0.000100000000000 + + + + + + + 6 + + + 0.000100000000000 + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + + 0 + 0 + + + + + 0 + 150 + + + + Attitude Stabization Coefficients (Outer Loop) + + + + + + Once Rate stabilization is done, you should increase the Kp factor until the airframe oscillates again, and go back down 20% or so. + + + + 6 + + + 0.100000000000000 + + + + + + + Ki can usually be almost identical to Kp. + + + 6 + + + 0.100000000000000 + + + + + + + ILimit can be equal to three to four times Ki, but you can adjust +depending on whether your airframe is well balanced, and your +flying style. + + + 6 + + + 0.100000000000000 + + + + + + + Kp + + + Qt::AlignCenter + + + + + + + Ki + + + Qt::AlignCenter + + + + + + + ILimit + + + Qt::AlignCenter + + + + + + + ILimit can be equal to three to four times Ki, but you can adjust +depending on whether your airframe is well balanced, and your +flying style. + + + 6 + + + 0.100000000000000 + + + + + + + Ki can usually be almost identical to Kp. + + + 6 + + + 0.100000000000000 + + + + + + + Once Rate stabilization is done, you should increase the Kp factor until the airframe oscillates again, and go back down 20% or so. + + + + 6 + + + 0.100000000000000 + + + + + + + Once Rate stabilization is done, you should increase the Kp factor until the airframe oscillates again, and go back down 20% or so. + + + + 6 + + + 0.100000000000000 + + + + + + + Yaw + + + + + + + Pitch + + + + + + + Roll + + + + + + + Ki can usually be almost identical to Kp. + + + 6 + + + 0.100000000000000 + + + + + + + ILimit can be equal to three to four times Ki, but you can adjust +depending on whether your airframe is well balanced, and your +flying style. + + + 6 + + + 0.100000000000000 + + + + + + + If checked, the Roll and Pitch factors will be identical. +When you change one, the other is updated. + + + Link + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + Stick range and limits + + + + QLayout::SetMinAndMaxSize + + + + + Roll + + + Qt::AlignCenter + + + + + + + Pitch + + + Qt::AlignCenter + + + + + + + Yaw + + + Qt::AlignCenter + + + + + + + 180 + + + + + + + 180 + + + + + + + 180 + + + + + + + + 150 + 0 + + + + + 50 + false + + + + Full stick angle (deg) + + + + + + + + 150 + 0 + + + + + 50 + false + + + + Full stick rate (deg/s) + + + + + + + 300 + + + + + + + 300 + + + + + + + 300 + + + + + + + + 150 + 0 + + + + + 50 + false + + + + + + + Maximum rate in attitude mode (deg/s) + + + + + + + 300 + + + + + + + 300 + + + + + + + 300 + + + + + + + + + + Zero the integral when throttle is low + + + @@ -578,9 +676,34 @@ automatically every 300ms, which will help for fast tuning. - + + + + 0 + 0 + + + + + 32 + 32 + + - Get Current + + + + + :/core/images/helpicon.svg:/core/images/helpicon.svg + + + + 32 + 32 + + + + true @@ -602,6 +725,8 @@ automatically every 300ms, which will help for fast tuning. - + + + diff --git a/ground/openpilotgcs/src/plugins/config/telemetry.ui b/ground/openpilotgcs/src/plugins/config/telemetry.ui deleted file mode 100644 index 588c5539e..000000000 --- a/ground/openpilotgcs/src/plugins/config/telemetry.ui +++ /dev/null @@ -1,130 +0,0 @@ - - - TelemetryWidget - - - - 0 - 0 - 720 - 480 - - - - Form - - - - - 10 - 10 - 411 - 321 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 10 - 10 - 361 - 151 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">Set the serial speed of your onboard telemetry modem here. It is the speed between the OpenPilot board and the onboard modem, and could be different from the radio link speed.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;"></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">Beware of not locking yourself out! You should only modify this setting when the OpenPilot board is connected through the USB port.</span></p></body></html> - - - - - - 20 - 200 - 131 - 17 - - - - Telemetry speed: - - - - - - 140 - 190 - 141 - 31 - - - - Select the speed here. - - - - - - 190 - 280 - 93 - 27 - - - - Send to OpenPilot but don't write in SD. -Beware of not locking yourself out! - - - Apply - - - - - - 80 - 280 - 93 - 27 - - - - Retrieve settings from OpenPilot - - - Get Current - - - - - - 300 - 280 - 93 - 27 - - - - Applies and Saves all settings to SD. -Beware of not locking yourself out! - - - Save - - - - - - - diff --git a/ground/openpilotgcs/src/plugins/coreplugin/CREDITS.html b/ground/openpilotgcs/src/plugins/coreplugin/CREDITS.html index e2abee7b3..2f3f2bc5b 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/CREDITS.html +++ b/ground/openpilotgcs/src/plugins/coreplugin/CREDITS.html @@ -1,15 +1,15 @@ -

This is a credits file of people that are or have been key contributors to the OpenPilot project. -Without the work of the people in this file OpenPilot would not be what it is today. +

This is a credits file of people that are or have been key contributors to the OpenPilot project. +Without the work of the people in this file OpenPilot would not be what it is today.

-

It is sorted alphabetically by name and formatted so that it allows for easy grepping and beautification by scripts. +

It is sorted alphabetically by name and formatted so that it allows for easy grepping and beautification by scripts.

-The fields are: 
+The fields are:
 
 Name (N)
 Email (E),
-Description of work (D) 
+Description of work (D)
 Current maintainer function (M)
 
 ----------
@@ -21,8 +21,8 @@ M: SITL Win32
 
 N: David Ankers
 E: david (at) openpilot (dot) org
-D: Co-founder, Project Coordination     
-D: Minor GCS infrastructure, updating the credit file 
+D: Co-founder, Project Coordination
+D: Minor GCS infrastructure, updating the credit file
 M: Admin
 
 N: Pedro Assuncao
@@ -33,22 +33,17 @@ N: Jose Barros
 E: josembarros (at) hotmail (dot) com
 D: Next-Gen OP Map Lib, Y-Modem Library, Uploader Plugin
 D: OP Bootloader, AHRS Bootloader, OPUploadTool
-M: Bootloader, OP MAP Lib 
- 
-N: David "Buzz" Carlson 
+M: Bootloader, OP MAP Lib
+
+N: David "Buzz" Carlson
 E: chebuzz (plus) openpilot (at) gmail (dot) com
 D: 3D ModelView GCS Plugin, sponsor of HITL merge work and XPlane addition
 M: 3D Modelview
 
-N: Eric Price
-E: corvus (dot) corax (at) cybertrench (dot) com
-D: IL2 HITL GCS Plugin, Posix OpenPilot, Advanced stabilisation module
-M: SITL Posix
-
 N: James Cotton
 E: peabody124 (plus) openpilot (at) gmail (dot) com
-D: Multiplatform HID implementation (firmware & GCS), GCS Joystick control 
-D: Posix OpenPilot work and Mac implementation 
+D: Multiplatform HID implementation (firmware & GCS), GCS Joystick control
+D: Posix OpenPilot work and Mac implementation
 D: Firmware implementation of Professor Schinstock's INS/GPS
 M: Architecture co-lead
 
@@ -59,7 +54,7 @@ D: Floss-JTAG Rev A, 4-layer initial design
 N: Frederic Goddeeris
 E: fredericgoddeeris (at) hotmail (dot) com
 D: I2C work and FreeRTOS work, MK integration
-D: EagleTree OSD implementation   
+D: EagleTree OSD implementation
 M: OSD Module
 
 N: Daniel Godin
@@ -85,17 +80,26 @@ D: Creator of http://pythononachip.org
 
 N: Joe Hlebasko
 E: joe (dot) hlebasko(plus) openpilot (at) gmail (dot) com
-D: Version 3 Main Board routing 
+D: Production Main Board & Production OP GPS
+M: Hardware Architecture Team
+
+N: Mark James
+E: mjames (plus) openpilot (at) gmail (dot) com
+D: Some of Silk Icon set used in GCS - http://www.famfamfam.com/lab/icons/silk
 
 N: Sami Korhonen
 E: samik (dot) korhonen (plus) openpilot (at) gmail (dot) com
-D: GPS Module, Spektrum RC Module 
+D: GPS Module, Spektrum RC Module, OSD work
 
 N: Thorsten Klose
-E: thorsten.klose (at) dmx (dot) de
-D: Embedded STM32 infrastructure  
+E: thorsten (dot) klose (at) dmx (dot) de
+D: Embedded STM32 infrastructure
 
-N: Edouard Lafargue 
+N: Hallvard Kristiansen
+E: hal (at) fleshmx (dot) com
+D: GCS Artwork, Quad layout diagrams
+
+N: Edouard Lafargue
 E: edouard (at) lafargue (dot) name
 D: GCS Dial Plugins, GCS PFD Plugin, GCS GPS plugin, GCS Config plugin
 D: Artwork including standard display dials
@@ -103,7 +107,7 @@ M: GCS Core
 
 N: Matt Lipski
 E: mattlipski (plus) openpilot (at) gmail (dot) com
-D: Deluxe Dials Set artwork, (Artificial Horizon, Compass, Turn Indicator)  
+D: Deluxe Dials Set artwork, (Artificial Horizon, Compass, Turn Indicator)
 
 N: Les Newell
 E: les (dot) newell (at) fastmail (dot) co (dot) uk
@@ -111,9 +115,9 @@ D: Advanced mixer matrix, SPI protocol based on UAVObjects
 
 N: Ken Northup
 E: helos360 (at) bellsouth (dot) net
-D: 3D Modelling, Easystar adaption from FMS  
+D: 3D Modelling, Easystar adaption from FMS
 
-N: Guy McCaldin 
+N: Guy McCaldin
 E: guymcc (at) gmail (dot) com
 D: Artwork and design including work on the Deluxe Dial Set
 
@@ -121,14 +125,19 @@ N: Cathy Moss
 E: cmoss296 (at) blueyonder (dot) co (dot) uk
 D: Hardware design Lead: Gen 2 Mainboard, PipXtreme, Current Sensor
 D: Lead dev PipXtreme, creator OP Map Plugin
-M: PipX Modems
+M: Hardware Architecture Team / PipX Modem
 
 N: Angus Peart
 E: gussy (at) openpilot (dot) org
-D: Co-founder, Principal hardware architect.  
+D: Co-founder, Principal hardware architect.
 D: Hardware design of OpenPilot, AHRS, GPS and other hardware
 D: Core developer embedded code
 
+N: Eric Price
+E: corvus (dot) corax (at) cybertrench (dot) com
+D: IL2 HITL GCS Plugin, Posix OpenPilot, Advanced stabilisation module
+M: SITL Posix
+
 N: Richard Querin
 E: rfquerin (plus) openpilot (at) gmail (dot) com
 D: Graphic Design, OpenPilot Logo
@@ -139,27 +148,35 @@ D: The GLC_lib as used in the ModelView Plugin
 D: See: http://www.glc-lib.net/
 
 N: Julien Rouviere
-E: julien.rouviere (plus) openpilot (at) gmail (dot) com
+E: julien (dot) rouviere (plus) openpilot (at) gmail (dot) com
 D: GCS Core Developer
 D: GCS Framework and Plugins for the GCS
 
 N: Zik Saleeba
 E: zik (at) zikzak (dot) net
-D: Initial schematic based on Zik's Flying Fox schematic     
+D: Initial schematic based on Zik's Flying Fox schematic
 
 N: Professor Dale Schinstock
 E: dales (at) ksu (dot) edu
 D: Lead AHRS Developer
 D: Creator of the OpenPilot INS / EKF
 
+N: Oleg Semyonov
+E: os-openpilot-org (at) os-propo (dot) info
+D: Core tester & Project organisation
+M: Common part of multi-platform packaging system
+M: Windows NSIS Installer
+M: Russian Documentation Lead
+
 N: Stacey Sheldon
 E: stac (at) solidgoldbomb (dot) org
 D: Core Embedded Developer
-D: SPI protocol for AHRS, I2C rewrite and much core work  
+D: SPI protocol for AHRS, I2C rewrite and much core work
 
 N: Troy Schultz
 E: troy (dot) schultz (at) rogers (dot) com
-D: INS design review and optimisation 
+D: INS design review and optimisation
+M: Hardware Architecture Team
 
 N: Dr. Erhard Siegl
 E: Erhard (dot) Siegl (at) zogazoga (dot) at
@@ -181,12 +198,12 @@ D: Helicopter support code and mixing for CCPM
 
 N: Vassilis Varveropoulos
 E: vassilis (at) openpilot (dot) org
-D: Co-founder, Principal embedded software architect. 
+D: Co-founder, Principal embedded software architect.
 D: Module architecture and UAVTalk/UAVObjects implementation.
 M: Architecture co-lead
 
 N: Alex Vrubel
-E: alex.vrubel (plus) openpilot (at) gmail (dot) com
+E: alex (dot) vrubel (plus) openpilot (at) gmail (dot) com
 D: Russian translation of the GCS
 
diff --git a/ground/openpilotgcs/src/plugins/coreplugin/OpenPilotGCS.ini b/ground/openpilotgcs/src/plugins/coreplugin/OpenPilotGCS.ini deleted file mode 100644 index 37f9d42f5..000000000 --- a/ground/openpilotgcs/src/plugins/coreplugin/OpenPilotGCS.ini +++ /dev/null @@ -1,1908 +0,0 @@ -[General] -ViewGroup_Default=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\0\0\0\x5\xa0\0\0\x3/\0\0\0\x4\0\0\0\x4\0\0\0\x1\0\0\0\b\xfc\0\0\0\0) - -[Workspace] -NumberOfWorkspaces=6 -Workspace1=Flight data -Icon1=:/core/images/ah.png -Workspace2=Configuration -Icon2=:/core/images/config.png -Workspace3=Large Map -Icon3=:/core/images/world.png -Workspace4=Scopes -Icon4=:/core/images/scopes.png -Workspace5=HITL -Icon5=:/core/images/joystick.png -Workspace6=Firmware -Icon6=:/core/images/cog.png -Workspace7=Workspace7 -Icon7=:/core/images/openpilot_logo_64.png -Workspace8=Workspace8 -Icon8=:/core/images/openpilot_logo_64.png -Workspace9=Workspace9 -Icon9=:/core/images/openpilot_logo_64.png -Workspace10=Workspace10 -Icon10=:/core/images/openpilot_logo_64.png - -[MainWindow] -Color=@Variant(\0\0\0\x43\x1\xff\xff\x66\x66\x66\x66\x66\x66\0\0) -Maximized=true -FullScreen=false - -[UAVGadgetManager] -Mode1\version=UAVGadgetManagerV1 -Mode1\showToolbars=false -Mode1\splitter\type=splitter -Mode1\splitter\splitterOrientation=1 -Mode1\splitter\splitterSizes=738, 701 -Mode1\splitter\side0\type=splitter -Mode1\splitter\side0\splitterOrientation=2 -Mode1\splitter\side0\splitterSizes=453, 327 -Mode1\splitter\side0\side0\type=splitter -Mode1\splitter\side0\side0\splitterOrientation=1 -Mode1\splitter\side0\side0\splitterSizes=144, 608 -Mode1\splitter\side0\side0\side0\type=splitter -Mode1\splitter\side0\side0\side1\type=uavGadget -Mode1\splitter\side0\side1\type=splitter -Mode1\splitter\side1\type=splitter -Mode1\splitter\side1\splitterOrientation=2 -Mode1\splitter\side1\splitterSizes=492, 288 -Mode1\splitter\side1\side0\type=uavGadget -Mode1\splitter\side1\side1\type=splitter -Mode1\splitter\side1\side1\splitterOrientation=1 -Mode1\splitter\side1\side1\splitterSizes=441, 259 -Mode1\splitter\side1\side1\side0\type=splitter -Mode1\splitter\side1\side1\side1\type=splitter -Mode2\version=UAVGadgetManagerV1 -Mode2\showToolbars=false -Mode2\splitter\type=splitter -Mode2\splitter\splitterOrientation=1 -Mode2\splitter\splitterSizes=734, 631 -Mode2\splitter\side0\type=splitter -Mode2\splitter\side0\splitterOrientation=2 -Mode2\splitter\side0\splitterSizes=565, 66 -Mode2\splitter\side0\side0\type=uavGadget -Mode2\splitter\side0\side0\classId=ConfigGadget -Mode2\splitter\side0\side0\gadget\activeConfiguration=default -Mode2\splitter\side0\side1\type=splitter -Mode2\splitter\side0\side1\splitterOrientation=1 -Mode2\splitter\side0\side1\splitterSizes=@Invalid() -Mode2\splitter\side0\side1\side0\type=uavGadget -Mode2\splitter\side0\side1\side0\classId=LineardialGadget -Mode2\splitter\side0\side1\side0\gadget\activeConfiguration=Telemetry RX Rate Horizontal -Mode2\splitter\side0\side1\side1\type=uavGadget -Mode2\splitter\side0\side1\side1\classId=LineardialGadget -Mode2\splitter\side0\side1\side1\gadget\activeConfiguration=Telemetry TX Rate Horizontal -Mode2\splitter\side1\type=splitter -Mode2\splitter\side1\splitterOrientation=2 -Mode2\splitter\side1\splitterSizes=433, 347 -Mode2\splitter\side1\side0\type=uavGadget -Mode2\splitter\side1\side0\classId=UAVObjectBrowser -Mode2\splitter\side1\side0\gadget\activeConfiguration=default -Mode2\splitter\side1\side1\type=uavGadget -Mode2\splitter\side1\side1\classId=GCSControlGadget -Mode2\splitter\side1\side1\gadget\activeConfiguration=MS Sidewinder -Mode3\version=UAVGadgetManagerV1 -Mode3\showToolbars=false -Mode3\splitter\type=splitter -Mode3\splitter\splitterOrientation=1 -Mode3\splitter\splitterSizes=980, 385 -Mode3\splitter\side0\type=uavGadget -Mode3\splitter\side0\classId=OPMapGadget -Mode3\splitter\side0\gadget\activeConfiguration=default -Mode3\splitter\side1\type=splitter -Mode3\splitter\side1\splitterOrientation=2 -Mode3\splitter\side1\splitterSizes=395, 236 -Mode3\splitter\side1\side0\type=uavGadget -Mode3\splitter\side1\side0\classId=ModelViewGadget -Mode3\splitter\side1\side0\gadget\activeConfiguration=Test Quad X -Mode3\splitter\side1\side1\type=splitter -Mode3\splitter\side1\side1\splitterOrientation=1 -Mode3\splitter\side1\side1\splitterSizes=@Invalid() -Mode3\splitter\side1\side1\side0\type=uavGadget -Mode3\splitter\side1\side1\side0\classId=DialGadget -Mode3\splitter\side1\side1\side0\gadget\activeConfiguration=Attitude -Mode3\splitter\side1\side1\side1\type=uavGadget -Mode3\splitter\side1\side1\side1\classId=DialGadget -Mode3\splitter\side1\side1\side1\gadget\activeConfiguration=Compass -Mode4\version=UAVGadgetManagerV1 -Mode4\showToolbars=false -Mode4\splitter\type=splitter -Mode4\splitter\splitterOrientation=1 -Mode4\splitter\splitterSizes=653, 660 -Mode4\splitter\side0\type=splitter -Mode4\splitter\side1\type=splitter -Mode4\splitter\side1\splitterOrientation=2 -Mode4\splitter\side1\splitterSizes=661, 119 -Mode4\splitter\side1\side0\type=splitter -Mode4\splitter\side1\side1\type=uavGadget -Mode5\version=UAVGadgetManagerV1 -Mode5\showToolbars=false -Mode5\splitter\type=splitter -Mode5\splitter\splitterOrientation=1 -Mode5\splitter\splitterSizes=780, 585 -Mode5\splitter\side0\type=splitter -Mode5\splitter\side0\splitterOrientation=2 -Mode5\splitter\side0\splitterSizes=361, 270 -Mode5\splitter\side0\side0\type=uavGadget -Mode5\splitter\side0\side0\classId=HITL -Mode5\splitter\side0\side0\gadget\activeConfiguration=XPlane HITL -Mode5\splitter\side0\side1\type=splitter -Mode5\splitter\side0\side1\splitterOrientation=1 -Mode5\splitter\side0\side1\splitterSizes=488, 194 -Mode5\splitter\side0\side1\side0\type=uavGadget -Mode5\splitter\side0\side1\side0\classId=GCSControlGadget -Mode5\splitter\side0\side1\side0\gadget\activeConfiguration=MS Sidewinder -Mode5\splitter\side0\side1\side1\type=splitter -Mode5\splitter\side0\side1\side1\splitterOrientation=1 -Mode5\splitter\side0\side1\side1\splitterSizes=276, 64 -Mode5\splitter\side0\side1\side1\side0\type=splitter -Mode5\splitter\side0\side1\side1\side0\splitterOrientation=1 -Mode5\splitter\side0\side1\side1\side0\splitterSizes=@Invalid() -Mode5\splitter\side0\side1\side1\side0\side0\type=uavGadget -Mode5\splitter\side0\side1\side1\side0\side0\classId=LineardialGadget -Mode5\splitter\side0\side1\side1\side0\side0\gadget\activeConfiguration=PitchDesired -Mode5\splitter\side0\side1\side1\side0\side1\type=uavGadget -Mode5\splitter\side0\side1\side1\side0\side1\classId=LineardialGadget -Mode5\splitter\side0\side1\side1\side0\side1\gadget\activeConfiguration=PitchActual -Mode5\splitter\side0\side1\side1\side1\type=uavGadget -Mode5\splitter\side0\side1\side1\side1\classId=LineardialGadget -Mode5\splitter\side0\side1\side1\side1\gadget\activeConfiguration=PitchCommand -Mode5\splitter\side1\type=uavGadget -Mode5\splitter\side1\classId=UAVObjectBrowser -Mode5\splitter\side1\gadget\activeConfiguration=default -Mode1\splitter\side0\side0\side0\splitterOrientation=2 -Mode1\splitter\side0\side0\side0\splitterSizes=215, 237 -Mode1\splitter\side0\side0\side0\side0\type=splitter -Mode1\splitter\side0\side0\side0\side1\type=splitter -Mode1\splitter\side0\side0\side0\side1\splitterOrientation=2 -Mode1\splitter\side0\side0\side0\side1\splitterSizes=@Invalid() -Mode1\splitter\side0\side0\side0\side1\side0\type=uavGadget -Mode1\splitter\side0\side0\side0\side1\side0\classId=LineardialGadget -Mode1\splitter\side0\side0\side0\side1\side0\gadget\activeConfiguration=Flight mode -Mode1\splitter\side0\side0\side0\side1\side1\type=uavGadget -Mode1\splitter\side0\side0\side0\side1\side1\classId=LineardialGadget -Mode1\splitter\side0\side0\side0\side1\side1\gadget\activeConfiguration=Arm Status -Mode1\splitter\side1\side0\classId=OPMapGadget -Mode1\splitter\side1\side0\gadget\activeConfiguration=Google Sat -Mode1\splitter\side1\side1\side0\splitterOrientation=1 -Mode1\splitter\side1\side1\side0\splitterSizes=277, 135 -Mode1\splitter\side1\side1\side0\side0\type=splitter -Mode1\splitter\side1\side1\side0\side1\type=splitter -Mode1\splitter\side0\side1\splitterOrientation=1 -Mode1\splitter\side0\side1\splitterSizes=304, 433 -Mode1\splitter\side0\side1\side0\type=uavGadget -Mode1\splitter\side0\side1\side1\type=splitter -Mode1\splitter\side0\side1\side1\splitterOrientation=2 -Mode1\splitter\side0\side1\side1\splitterSizes=293, 64 -Mode1\splitter\side0\side1\side1\side0\type=splitter -Mode1\splitter\side0\side1\side1\side1\type=splitter -Mode1\splitter\side1\side1\side0\side0\splitterOrientation=1 -Mode1\splitter\side1\side1\side0\side0\splitterSizes=131, 138 -Mode1\splitter\side1\side1\side0\side0\side0\type=splitter -Mode1\splitter\side1\side1\side0\side0\side1\type=splitter -Mode1\splitter\side0\side1\side0\classId=ModelViewGadget -Mode1\splitter\side0\side1\side0\gadget\activeConfiguration=Test Quad X -Mode1\splitter\side0\side1\side1\side0\splitterOrientation=1 -Mode1\splitter\side0\side1\side1\side0\splitterSizes=291, 141 -Mode1\splitter\side0\side1\side1\side0\side0\type=uavGadget -Mode1\splitter\side0\side1\side1\side0\side0\classId=SystemHealthGadget -Mode1\splitter\side0\side1\side1\side0\side0\gadget\activeConfiguration=default -Mode1\splitter\side0\side1\side1\side0\side1\type=splitter -Mode1\splitter\side0\side1\side1\side1\splitterOrientation=1 -Mode1\splitter\side0\side1\side1\side1\splitterSizes=@Invalid() -Mode1\splitter\side0\side1\side1\side1\side0\type=uavGadget -Mode1\splitter\side0\side1\side1\side1\side0\classId=LineardialGadget -Mode1\splitter\side0\side1\side1\side1\side0\gadget\activeConfiguration=Telemetry RX Rate Horizontal -Mode1\splitter\side0\side1\side1\side1\side1\type=uavGadget -Mode1\splitter\side0\side1\side1\side1\side1\classId=LineardialGadget -Mode1\splitter\side0\side1\side1\side1\side1\gadget\activeConfiguration=Telemetry TX Rate Horizontal -Mode1\splitter\side0\side1\side1\side0\side1\splitterOrientation=1 -Mode1\splitter\side0\side1\side1\side0\side1\splitterSizes=64, 64 -Mode1\splitter\side0\side1\side1\side0\side1\side0\type=uavGadget -Mode1\splitter\side0\side1\side1\side0\side1\side0\classId=LineardialGadget -Mode1\splitter\side0\side1\side1\side0\side1\side0\gadget\activeConfiguration=Mainboard CPU -Mode1\splitter\side0\side1\side1\side0\side1\side1\type=uavGadget -Mode1\splitter\side0\side1\side1\side0\side1\side1\classId=LineardialGadget -Mode1\splitter\side0\side1\side1\side0\side1\side1\gadget\activeConfiguration=AHRS CPU -Mode1\splitter\side1\side1\side0\side0\side0\splitterOrientation=2 -Mode1\splitter\side1\side1\side0\side0\side0\splitterSizes=@Invalid() -Mode1\splitter\side1\side1\side0\side0\side0\side0\type=uavGadget -Mode1\splitter\side1\side1\side0\side0\side0\side0\classId=DialGadget -Mode1\splitter\side1\side1\side0\side0\side0\side0\gadget\activeConfiguration=Deluxe Groundspeed kph -Mode1\splitter\side1\side1\side0\side0\side0\side1\type=uavGadget -Mode1\splitter\side1\side1\side0\side0\side0\side1\classId=DialGadget -Mode1\splitter\side1\side1\side0\side0\side0\side1\gadget\activeConfiguration=Deluxe Barometer -Mode1\splitter\side1\side1\side0\side0\side1\splitterOrientation=2 -Mode1\splitter\side1\side1\side0\side0\side1\splitterSizes=@Invalid() -Mode1\splitter\side1\side1\side0\side0\side1\side0\type=uavGadget -Mode1\splitter\side1\side1\side0\side0\side1\side0\classId=DialGadget -Mode1\splitter\side1\side1\side0\side0\side1\side0\gadget\activeConfiguration=Deluxe Attitude -Mode1\splitter\side1\side1\side0\side0\side1\side1\type=uavGadget -Mode1\splitter\side1\side1\side0\side0\side1\side1\classId=DialGadget -Mode1\splitter\side1\side1\side0\side0\side1\side1\gadget\activeConfiguration=Deluxe Compass -Mode1\splitter\side1\side1\side0\side1\splitterOrientation=2 -Mode1\splitter\side1\side1\side0\side1\splitterSizes=@Invalid() -Mode1\splitter\side1\side1\side0\side1\side0\type=uavGadget -Mode1\splitter\side1\side1\side0\side1\side0\classId=DialGadget -Mode1\splitter\side1\side1\side0\side1\side0\gadget\activeConfiguration=Deluxe Baro Altimeter -Mode1\splitter\side1\side1\side0\side1\side1\type=uavGadget -Mode1\splitter\side1\side1\side0\side1\side1\classId=DialGadget -Mode1\splitter\side1\side1\side0\side1\side1\gadget\activeConfiguration=Deluxe Climbrate -Mode1\splitter\side0\side0\side0\side0\splitterOrientation=2 -Mode1\splitter\side0\side0\side0\side0\splitterSizes=@Invalid() -Mode1\splitter\side0\side0\side0\side0\side0\type=uavGadget -Mode1\splitter\side0\side0\side0\side0\side0\classId=LineardialGadget -Mode1\splitter\side0\side0\side0\side0\side0\gadget\activeConfiguration=Flight Time -Mode1\splitter\side0\side0\side0\side0\side1\type=uavGadget -Mode1\splitter\side0\side0\side0\side0\side1\classId=LineardialGadget -Mode1\splitter\side0\side0\side0\side0\side1\gadget\activeConfiguration=GPS Sats -Mode1\splitter\side0\side0\side1\classId=PFDGadget -Mode1\splitter\side0\side0\side1\gadget\activeConfiguration=raw -Mode1\splitter\side1\side1\side1\splitterOrientation=1 -Mode1\splitter\side1\side1\side1\splitterSizes=64, 441 -Mode1\splitter\side1\side1\side1\side0\type=uavGadget -Mode1\splitter\side1\side1\side1\side0\classId=LineardialGadget -Mode1\splitter\side1\side1\side1\side0\gadget\activeConfiguration=Throttle -Mode1\splitter\side1\side1\side1\side1\type=splitter -Mode1\splitter\side1\side1\side1\side1\splitterOrientation=1 -Mode1\splitter\side1\side1\side1\side1\splitterSizes=64, 376 -Mode1\splitter\side1\side1\side1\side1\side0\type=uavGadget -Mode1\splitter\side1\side1\side1\side1\side0\classId=LineardialGadget -Mode1\splitter\side1\side1\side1\side1\side0\gadget\activeConfiguration=Roll -Mode1\splitter\side1\side1\side1\side1\side1\type=splitter -Mode1\splitter\side1\side1\side1\side1\side1\splitterOrientation=1 -Mode1\splitter\side1\side1\side1\side1\side1\splitterSizes=64, 311 -Mode1\splitter\side1\side1\side1\side1\side1\side0\type=uavGadget -Mode1\splitter\side1\side1\side1\side1\side1\side0\classId=LineardialGadget -Mode1\splitter\side1\side1\side1\side1\side1\side0\gadget\activeConfiguration=PitchActual -Mode1\splitter\side1\side1\side1\side1\side1\side1\type=uavGadget -Mode1\splitter\side1\side1\side1\side1\side1\side1\classId=LineardialGadget -Mode1\splitter\side1\side1\side1\side1\side1\side1\gadget\activeConfiguration=Yaw -Mode6\version=UAVGadgetManagerV1 -Mode6\showToolbars=false -Mode6\splitter\type=splitter -Mode4\splitter\side0\splitterOrientation=2 -Mode4\splitter\side0\splitterSizes=@Invalid() -Mode4\splitter\side0\side0\type=uavGadget -Mode4\splitter\side0\side0\classId=ScopeGadget -Mode4\splitter\side0\side0\gadget\activeConfiguration=Accel -Mode4\splitter\side0\side1\type=uavGadget -Mode4\splitter\side0\side1\classId=ScopeGadget -Mode4\splitter\side0\side1\gadget\activeConfiguration=Raw Gyros -Mode4\splitter\side1\side0\splitterOrientation=2 -Mode4\splitter\side1\side0\splitterSizes=390, 270 -Mode4\splitter\side1\side0\side0\type=uavGadget -Mode4\splitter\side1\side0\side0\classId=ScopeGadget -Mode4\splitter\side1\side0\side0\gadget\activeConfiguration=Attitude -Mode4\splitter\side1\side0\side1\type=uavGadget -Mode4\splitter\side1\side0\side1\classId=ScopeGadget -Mode4\splitter\side1\side0\side1\gadget\activeConfiguration=Uptimes -Mode4\splitter\side1\side1\classId=LoggingGadget -Mode6\splitter\splitterOrientation=1 -Mode6\splitter\splitterSizes=@Invalid() -Mode6\splitter\side0\type=uavGadget -Mode6\splitter\side0\classId=Uploader -Mode6\splitter\side0\gadget\activeConfiguration=default -Mode6\splitter\side1\type=splitter -Mode6\splitter\side1\splitterOrientation=2 -Mode6\splitter\side1\splitterSizes=274, 506 -Mode6\splitter\side1\side0\type=splitter -Mode6\splitter\side1\side1\type=uavGadget -Mode6\splitter\side1\side1\classId=ScopeGadget -Mode6\splitter\side1\side1\gadget\activeConfiguration=Uptimes -Mode6\splitter\side1\side0\splitterOrientation=1 -Mode6\splitter\side1\side0\splitterSizes=322, 396 -Mode6\splitter\side1\side0\side0\type=uavGadget -Mode6\splitter\side1\side0\side0\classId=SystemHealthGadget -Mode6\splitter\side1\side0\side0\gadget\activeConfiguration=default -Mode6\splitter\side1\side0\side1\type=uavGadget -Mode6\splitter\side1\side0\side1\classId=PFDGadget -Mode6\splitter\side1\side0\side1\gadget\activeConfiguration=raw - -[KeyBindings] -size=0 - -[%General] -SaveSettingsOnExit=true -LastPreferenceCategory=OPMapGadget -LastPreferencePage=default -SettingsWindowWidth=697 -SettingsWindowHeight=476 -OverrideLanguage=en_AU - -[UAVGadgetConfigurations] -configInfo\version=1.2.0 -configInfo\locked=false -ConfigGadget\default\configInfo\version=0.0.0 -ConfigGadget\default\configInfo\locked=false -DialGadget\Attitude\data\dialFile=%%DATAPATH%%dials/default/attitude.svg -DialGadget\Attitude\data\dialBackgroundID=background -DialGadget\Attitude\data\dialForegroundID=foreground -DialGadget\Attitude\data\dialNeedleID1=needle -DialGadget\Attitude\data\dialNeedleID2=needle -DialGadget\Attitude\data\dialNeedleID3=needle3 -DialGadget\Attitude\data\needle1MinValue=0 -DialGadget\Attitude\data\needle1MaxValue=360 -DialGadget\Attitude\data\needle2MinValue=0 -DialGadget\Attitude\data\needle2MaxValue=20 -DialGadget\Attitude\data\needle3MinValue=0 -DialGadget\Attitude\data\needle3MaxValue=360 -DialGadget\Attitude\data\needle1DataObject=AttitudeActual -DialGadget\Attitude\data\needle1ObjectField=Roll -DialGadget\Attitude\data\needle2DataObject=AttitudeActual -DialGadget\Attitude\data\needle2ObjectField=Pitch -DialGadget\Attitude\data\needle3DataObject=AttitudeActual -DialGadget\Attitude\data\needle3ObjectField=Roll -DialGadget\Attitude\data\needle1Factor=-1 -DialGadget\Attitude\data\needle2Factor=75 -DialGadget\Attitude\data\needle3Factor=-1 -DialGadget\Attitude\data\needle1Move=Rotate -DialGadget\Attitude\data\needle2Move=Vertical -DialGadget\Attitude\data\needle3Move=Rotate -DialGadget\Attitude\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Attitude\data\useOpenGLFlag=false -DialGadget\Attitude\data\beSmooth=false -DialGadget\Attitude\configInfo\version=0.0.0 -DialGadget\Attitude\configInfo\locked=false -DialGadget\Baro%20Altimeter\data\dialFile=%%DATAPATH%%dials/default/altimeter.svg -DialGadget\Baro%20Altimeter\data\dialBackgroundID=background -DialGadget\Baro%20Altimeter\data\dialForegroundID=foreground -DialGadget\Baro%20Altimeter\data\dialNeedleID1=needle -DialGadget\Baro%20Altimeter\data\dialNeedleID2=needle2 -DialGadget\Baro%20Altimeter\data\dialNeedleID3=needle3 -DialGadget\Baro%20Altimeter\data\needle1MinValue=0 -DialGadget\Baro%20Altimeter\data\needle1MaxValue=10 -DialGadget\Baro%20Altimeter\data\needle2MinValue=0 -DialGadget\Baro%20Altimeter\data\needle2MaxValue=100 -DialGadget\Baro%20Altimeter\data\needle3MinValue=0 -DialGadget\Baro%20Altimeter\data\needle3MaxValue=1000 -DialGadget\Baro%20Altimeter\data\needle1DataObject=BaroAltitude -DialGadget\Baro%20Altimeter\data\needle1ObjectField=Altitude -DialGadget\Baro%20Altimeter\data\needle2DataObject=BaroAltitude -DialGadget\Baro%20Altimeter\data\needle2ObjectField=Altitude -DialGadget\Baro%20Altimeter\data\needle3DataObject=BaroAltitude -DialGadget\Baro%20Altimeter\data\needle3ObjectField=Altitude -DialGadget\Baro%20Altimeter\data\needle1Factor=1 -DialGadget\Baro%20Altimeter\data\needle2Factor=1 -DialGadget\Baro%20Altimeter\data\needle3Factor=1 -DialGadget\Baro%20Altimeter\data\needle1Move=Rotate -DialGadget\Baro%20Altimeter\data\needle2Move=Rotate -DialGadget\Baro%20Altimeter\data\needle3Move=Rotate -DialGadget\Baro%20Altimeter\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Baro%20Altimeter\data\useOpenGLFlag=false -DialGadget\Baro%20Altimeter\data\beSmooth=false -DialGadget\Baro%20Altimeter\configInfo\version=0.0.0 -DialGadget\Baro%20Altimeter\configInfo\locked=false -DialGadget\Barometer\data\dialFile=%%DATAPATH%%dials/default/barometer.svg -DialGadget\Barometer\data\dialBackgroundID=background -DialGadget\Barometer\data\dialForegroundID= -DialGadget\Barometer\data\dialNeedleID1=needle -DialGadget\Barometer\data\dialNeedleID2= -DialGadget\Barometer\data\dialNeedleID3= -DialGadget\Barometer\data\needle1MinValue=1000 -DialGadget\Barometer\data\needle1MaxValue=1120 -DialGadget\Barometer\data\needle2MinValue=0 -DialGadget\Barometer\data\needle2MaxValue=100 -DialGadget\Barometer\data\needle3MinValue=0 -DialGadget\Barometer\data\needle3MaxValue=1000 -DialGadget\Barometer\data\needle1DataObject=BaroAltitude -DialGadget\Barometer\data\needle1ObjectField=Pressure -DialGadget\Barometer\data\needle2DataObject=BaroAltitude -DialGadget\Barometer\data\needle2ObjectField=Altitude -DialGadget\Barometer\data\needle3DataObject=BaroAltitude -DialGadget\Barometer\data\needle3ObjectField=Altitude -DialGadget\Barometer\data\needle1Factor=10 -DialGadget\Barometer\data\needle2Factor=1 -DialGadget\Barometer\data\needle3Factor=1 -DialGadget\Barometer\data\needle1Move=Rotate -DialGadget\Barometer\data\needle2Move=Rotate -DialGadget\Barometer\data\needle3Move=Rotate -DialGadget\Barometer\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Barometer\data\useOpenGLFlag=false -DialGadget\Barometer\data\beSmooth=false -DialGadget\Barometer\configInfo\version=0.0.0 -DialGadget\Barometer\configInfo\locked=false -DialGadget\Climbrate\data\dialFile=%%DATAPATH%%dials/default/vsi.svg -DialGadget\Climbrate\data\dialBackgroundID=background -DialGadget\Climbrate\data\dialForegroundID= -DialGadget\Climbrate\data\dialNeedleID1=needle -DialGadget\Climbrate\data\dialNeedleID2= -DialGadget\Climbrate\data\dialNeedleID3= -DialGadget\Climbrate\data\needle1MinValue=-12 -DialGadget\Climbrate\data\needle1MaxValue=12 -DialGadget\Climbrate\data\needle2MinValue=0 -DialGadget\Climbrate\data\needle2MaxValue=100 -DialGadget\Climbrate\data\needle3MinValue=0 -DialGadget\Climbrate\data\needle3MaxValue=1000 -DialGadget\Climbrate\data\needle1DataObject=VelocityActual -DialGadget\Climbrate\data\needle1ObjectField=Down -DialGadget\Climbrate\data\needle2DataObject=BaroAltitude -DialGadget\Climbrate\data\needle2ObjectField=Altitude -DialGadget\Climbrate\data\needle3DataObject=BaroAltitude -DialGadget\Climbrate\data\needle3ObjectField=Altitude -DialGadget\Climbrate\data\needle1Factor=0.01 -DialGadget\Climbrate\data\needle2Factor=1 -DialGadget\Climbrate\data\needle3Factor=1 -DialGadget\Climbrate\data\needle1Move=Rotate -DialGadget\Climbrate\data\needle2Move=Rotate -DialGadget\Climbrate\data\needle3Move=Rotate -DialGadget\Climbrate\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Climbrate\data\useOpenGLFlag=false -DialGadget\Climbrate\data\beSmooth=false -DialGadget\Climbrate\configInfo\version=0.0.0 -DialGadget\Climbrate\configInfo\locked=false -DialGadget\Compass\data\dialFile=%%DATAPATH%%dials/default/compass.svg -DialGadget\Compass\data\dialBackgroundID=background -DialGadget\Compass\data\dialForegroundID=foreground -DialGadget\Compass\data\dialNeedleID1=needle -DialGadget\Compass\data\dialNeedleID2= -DialGadget\Compass\data\dialNeedleID3= -DialGadget\Compass\data\needle1MinValue=0 -DialGadget\Compass\data\needle1MaxValue=360 -DialGadget\Compass\data\needle2MinValue=0 -DialGadget\Compass\data\needle2MaxValue=100 -DialGadget\Compass\data\needle3MinValue=0 -DialGadget\Compass\data\needle3MaxValue=1000 -DialGadget\Compass\data\needle1DataObject=AttitudeActual -DialGadget\Compass\data\needle1ObjectField=Yaw -DialGadget\Compass\data\needle2DataObject=BaroAltitude -DialGadget\Compass\data\needle2ObjectField=Altitude -DialGadget\Compass\data\needle3DataObject=BaroAltitude -DialGadget\Compass\data\needle3ObjectField=Altitude -DialGadget\Compass\data\needle1Factor=-1 -DialGadget\Compass\data\needle2Factor=1 -DialGadget\Compass\data\needle3Factor=1 -DialGadget\Compass\data\needle1Move=Rotate -DialGadget\Compass\data\needle2Move=Rotate -DialGadget\Compass\data\needle3Move=Rotate -DialGadget\Compass\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Compass\data\useOpenGLFlag=false -DialGadget\Compass\data\beSmooth=false -DialGadget\Compass\configInfo\version=0.0.0 -DialGadget\Compass\configInfo\locked=false -DialGadget\Deluxe%20Attitude\data\dialFile=%%DATAPATH%%dials/deluxe/attitude.svg -DialGadget\Deluxe%20Attitude\data\dialBackgroundID=background -DialGadget\Deluxe%20Attitude\data\dialForegroundID=foreground -DialGadget\Deluxe%20Attitude\data\dialNeedleID1=needle -DialGadget\Deluxe%20Attitude\data\dialNeedleID2=needle -DialGadget\Deluxe%20Attitude\data\dialNeedleID3=needle3 -DialGadget\Deluxe%20Attitude\data\needle1MinValue=0 -DialGadget\Deluxe%20Attitude\data\needle1MaxValue=360 -DialGadget\Deluxe%20Attitude\data\needle2MinValue=0 -DialGadget\Deluxe%20Attitude\data\needle2MaxValue=20 -DialGadget\Deluxe%20Attitude\data\needle3MinValue=0 -DialGadget\Deluxe%20Attitude\data\needle3MaxValue=360 -DialGadget\Deluxe%20Attitude\data\needle1DataObject=AttitudeActual -DialGadget\Deluxe%20Attitude\data\needle1ObjectField=Roll -DialGadget\Deluxe%20Attitude\data\needle2DataObject=AttitudeActual -DialGadget\Deluxe%20Attitude\data\needle2ObjectField=Pitch -DialGadget\Deluxe%20Attitude\data\needle3DataObject=AttitudeActual -DialGadget\Deluxe%20Attitude\data\needle3ObjectField=Roll -DialGadget\Deluxe%20Attitude\data\needle1Factor=-1 -DialGadget\Deluxe%20Attitude\data\needle2Factor=75 -DialGadget\Deluxe%20Attitude\data\needle3Factor=-1 -DialGadget\Deluxe%20Attitude\data\needle1Move=Rotate -DialGadget\Deluxe%20Attitude\data\needle2Move=Vertical -DialGadget\Deluxe%20Attitude\data\needle3Move=Rotate -DialGadget\Deluxe%20Attitude\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Deluxe%20Attitude\data\useOpenGLFlag=false -DialGadget\Deluxe%20Attitude\data\beSmooth=false -DialGadget\Deluxe%20Attitude\configInfo\version=0.0.0 -DialGadget\Deluxe%20Attitude\configInfo\locked=false -DialGadget\Deluxe%20Baro%20Altimeter\data\dialFile=%%DATAPATH%%dials/deluxe/altimeter.svg -DialGadget\Deluxe%20Baro%20Altimeter\data\dialBackgroundID=background -DialGadget\Deluxe%20Baro%20Altimeter\data\dialForegroundID=foreground -DialGadget\Deluxe%20Baro%20Altimeter\data\dialNeedleID1=needle -DialGadget\Deluxe%20Baro%20Altimeter\data\dialNeedleID2=needle2 -DialGadget\Deluxe%20Baro%20Altimeter\data\dialNeedleID3=needle3 -DialGadget\Deluxe%20Baro%20Altimeter\data\needle1MinValue=0 -DialGadget\Deluxe%20Baro%20Altimeter\data\needle1MaxValue=10 -DialGadget\Deluxe%20Baro%20Altimeter\data\needle2MinValue=0 -DialGadget\Deluxe%20Baro%20Altimeter\data\needle2MaxValue=100 -DialGadget\Deluxe%20Baro%20Altimeter\data\needle3MinValue=0 -DialGadget\Deluxe%20Baro%20Altimeter\data\needle3MaxValue=1000 -DialGadget\Deluxe%20Baro%20Altimeter\data\needle1DataObject=BaroAltitude -DialGadget\Deluxe%20Baro%20Altimeter\data\needle1ObjectField=Altitude -DialGadget\Deluxe%20Baro%20Altimeter\data\needle2DataObject=BaroAltitude -DialGadget\Deluxe%20Baro%20Altimeter\data\needle2ObjectField=Altitude -DialGadget\Deluxe%20Baro%20Altimeter\data\needle3DataObject=BaroAltitude -DialGadget\Deluxe%20Baro%20Altimeter\data\needle3ObjectField=Altitude -DialGadget\Deluxe%20Baro%20Altimeter\data\needle1Factor=1 -DialGadget\Deluxe%20Baro%20Altimeter\data\needle2Factor=1 -DialGadget\Deluxe%20Baro%20Altimeter\data\needle3Factor=1 -DialGadget\Deluxe%20Baro%20Altimeter\data\needle1Move=Rotate -DialGadget\Deluxe%20Baro%20Altimeter\data\needle2Move=Rotate -DialGadget\Deluxe%20Baro%20Altimeter\data\needle3Move=Rotate -DialGadget\Deluxe%20Baro%20Altimeter\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Deluxe%20Baro%20Altimeter\data\useOpenGLFlag=false -DialGadget\Deluxe%20Baro%20Altimeter\data\beSmooth=false -DialGadget\Deluxe%20Baro%20Altimeter\configInfo\version=0.0.0 -DialGadget\Deluxe%20Baro%20Altimeter\configInfo\locked=false -DialGadget\Deluxe%20Barometer\data\dialFile=%%DATAPATH%%dials/deluxe/barometer.svg -DialGadget\Deluxe%20Barometer\data\dialBackgroundID=background -DialGadget\Deluxe%20Barometer\data\dialForegroundID=foreground -DialGadget\Deluxe%20Barometer\data\dialNeedleID1=needle -DialGadget\Deluxe%20Barometer\data\dialNeedleID2= -DialGadget\Deluxe%20Barometer\data\dialNeedleID3= -DialGadget\Deluxe%20Barometer\data\needle1MinValue=1000 -DialGadget\Deluxe%20Barometer\data\needle1MaxValue=1120 -DialGadget\Deluxe%20Barometer\data\needle2MinValue=0 -DialGadget\Deluxe%20Barometer\data\needle2MaxValue=100 -DialGadget\Deluxe%20Barometer\data\needle3MinValue=0 -DialGadget\Deluxe%20Barometer\data\needle3MaxValue=1000 -DialGadget\Deluxe%20Barometer\data\needle1DataObject=BaroAltitude -DialGadget\Deluxe%20Barometer\data\needle1ObjectField=Pressure -DialGadget\Deluxe%20Barometer\data\needle2DataObject=BaroAltitude -DialGadget\Deluxe%20Barometer\data\needle2ObjectField=Altitude -DialGadget\Deluxe%20Barometer\data\needle3DataObject=BaroAltitude -DialGadget\Deluxe%20Barometer\data\needle3ObjectField=Altitude -DialGadget\Deluxe%20Barometer\data\needle1Factor=10 -DialGadget\Deluxe%20Barometer\data\needle2Factor=1 -DialGadget\Deluxe%20Barometer\data\needle3Factor=1 -DialGadget\Deluxe%20Barometer\data\needle1Move=Rotate -DialGadget\Deluxe%20Barometer\data\needle2Move=Rotate -DialGadget\Deluxe%20Barometer\data\needle3Move=Rotate -DialGadget\Deluxe%20Barometer\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Deluxe%20Barometer\data\useOpenGLFlag=false -DialGadget\Deluxe%20Barometer\data\beSmooth=false -DialGadget\Deluxe%20Barometer\configInfo\version=0.0.0 -DialGadget\Deluxe%20Barometer\configInfo\locked=false -DialGadget\Deluxe%20Climbrate\data\dialFile=%%DATAPATH%%dials/deluxe/vsi.svg -DialGadget\Deluxe%20Climbrate\data\dialBackgroundID=background -DialGadget\Deluxe%20Climbrate\data\dialForegroundID=foreground -DialGadget\Deluxe%20Climbrate\data\dialNeedleID1=needle -DialGadget\Deluxe%20Climbrate\data\dialNeedleID2= -DialGadget\Deluxe%20Climbrate\data\dialNeedleID3= -DialGadget\Deluxe%20Climbrate\data\needle1MinValue=-11.2 -DialGadget\Deluxe%20Climbrate\data\needle1MaxValue=11.2 -DialGadget\Deluxe%20Climbrate\data\needle2MinValue=0 -DialGadget\Deluxe%20Climbrate\data\needle2MaxValue=100 -DialGadget\Deluxe%20Climbrate\data\needle3MinValue=0 -DialGadget\Deluxe%20Climbrate\data\needle3MaxValue=1000 -DialGadget\Deluxe%20Climbrate\data\needle1DataObject=VelocityActual -DialGadget\Deluxe%20Climbrate\data\needle1ObjectField=Down -DialGadget\Deluxe%20Climbrate\data\needle2DataObject=BaroAltitude -DialGadget\Deluxe%20Climbrate\data\needle2ObjectField=Altitude -DialGadget\Deluxe%20Climbrate\data\needle3DataObject=BaroAltitude -DialGadget\Deluxe%20Climbrate\data\needle3ObjectField=Altitude -DialGadget\Deluxe%20Climbrate\data\needle1Factor=0.01 -DialGadget\Deluxe%20Climbrate\data\needle2Factor=1 -DialGadget\Deluxe%20Climbrate\data\needle3Factor=1 -DialGadget\Deluxe%20Climbrate\data\needle1Move=Rotate -DialGadget\Deluxe%20Climbrate\data\needle2Move=Rotate -DialGadget\Deluxe%20Climbrate\data\needle3Move=Rotate -DialGadget\Deluxe%20Climbrate\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Deluxe%20Climbrate\data\useOpenGLFlag=false -DialGadget\Deluxe%20Climbrate\data\beSmooth=false -DialGadget\Deluxe%20Climbrate\configInfo\version=0.0.0 -DialGadget\Deluxe%20Climbrate\configInfo\locked=false -DialGadget\Deluxe%20Compass\data\dialFile=%%DATAPATH%%dials/deluxe/compass.svg -DialGadget\Deluxe%20Compass\data\dialBackgroundID=background -DialGadget\Deluxe%20Compass\data\dialForegroundID=foreground -DialGadget\Deluxe%20Compass\data\dialNeedleID1=needle -DialGadget\Deluxe%20Compass\data\dialNeedleID2= -DialGadget\Deluxe%20Compass\data\dialNeedleID3= -DialGadget\Deluxe%20Compass\data\needle1MinValue=0 -DialGadget\Deluxe%20Compass\data\needle1MaxValue=360 -DialGadget\Deluxe%20Compass\data\needle2MinValue=0 -DialGadget\Deluxe%20Compass\data\needle2MaxValue=100 -DialGadget\Deluxe%20Compass\data\needle3MinValue=0 -DialGadget\Deluxe%20Compass\data\needle3MaxValue=1000 -DialGadget\Deluxe%20Compass\data\needle1DataObject=AttitudeActual -DialGadget\Deluxe%20Compass\data\needle1ObjectField=Yaw -DialGadget\Deluxe%20Compass\data\needle2DataObject=BaroAltitude -DialGadget\Deluxe%20Compass\data\needle2ObjectField=Altitude -DialGadget\Deluxe%20Compass\data\needle3DataObject=BaroAltitude -DialGadget\Deluxe%20Compass\data\needle3ObjectField=Altitude -DialGadget\Deluxe%20Compass\data\needle1Factor=-1 -DialGadget\Deluxe%20Compass\data\needle2Factor=1 -DialGadget\Deluxe%20Compass\data\needle3Factor=1 -DialGadget\Deluxe%20Compass\data\needle1Move=Rotate -DialGadget\Deluxe%20Compass\data\needle2Move=Rotate -DialGadget\Deluxe%20Compass\data\needle3Move=Rotate -DialGadget\Deluxe%20Compass\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Deluxe%20Compass\data\useOpenGLFlag=false -DialGadget\Deluxe%20Compass\data\beSmooth=false -DialGadget\Deluxe%20Compass\configInfo\version=0.0.0 -DialGadget\Deluxe%20Compass\configInfo\locked=false -DialGadget\Deluxe%20Groundspeed%20kph\data\dialFile=%%DATAPATH%%dials/deluxe/speed.svg -DialGadget\Deluxe%20Groundspeed%20kph\data\dialBackgroundID=background -DialGadget\Deluxe%20Groundspeed%20kph\data\dialForegroundID=foreground -DialGadget\Deluxe%20Groundspeed%20kph\data\dialNeedleID1=needle -DialGadget\Deluxe%20Groundspeed%20kph\data\dialNeedleID2= -DialGadget\Deluxe%20Groundspeed%20kph\data\dialNeedleID3= -DialGadget\Deluxe%20Groundspeed%20kph\data\needle1MinValue=0 -DialGadget\Deluxe%20Groundspeed%20kph\data\needle1MaxValue=120 -DialGadget\Deluxe%20Groundspeed%20kph\data\needle2MinValue=0 -DialGadget\Deluxe%20Groundspeed%20kph\data\needle2MaxValue=100 -DialGadget\Deluxe%20Groundspeed%20kph\data\needle3MinValue=0 -DialGadget\Deluxe%20Groundspeed%20kph\data\needle3MaxValue=1000 -DialGadget\Deluxe%20Groundspeed%20kph\data\needle1DataObject=GPSPosition -DialGadget\Deluxe%20Groundspeed%20kph\data\needle1ObjectField=Groundspeed -DialGadget\Deluxe%20Groundspeed%20kph\data\needle2DataObject=BaroAltitude -DialGadget\Deluxe%20Groundspeed%20kph\data\needle2ObjectField=Altitude -DialGadget\Deluxe%20Groundspeed%20kph\data\needle3DataObject=BaroAltitude -DialGadget\Deluxe%20Groundspeed%20kph\data\needle3ObjectField=Altitude -DialGadget\Deluxe%20Groundspeed%20kph\data\needle1Factor=3.6 -DialGadget\Deluxe%20Groundspeed%20kph\data\needle2Factor=1 -DialGadget\Deluxe%20Groundspeed%20kph\data\needle3Factor=1 -DialGadget\Deluxe%20Groundspeed%20kph\data\needle1Move=Rotate -DialGadget\Deluxe%20Groundspeed%20kph\data\needle2Move=Rotate -DialGadget\Deluxe%20Groundspeed%20kph\data\needle3Move=Rotate -DialGadget\Deluxe%20Groundspeed%20kph\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Deluxe%20Groundspeed%20kph\data\useOpenGLFlag=false -DialGadget\Deluxe%20Groundspeed%20kph\data\beSmooth=false -DialGadget\Deluxe%20Groundspeed%20kph\configInfo\version=0.0.0 -DialGadget\Deluxe%20Groundspeed%20kph\configInfo\locked=false -DialGadget\Deluxe%20Temperature\data\dialFile=%%DATAPATH%%dials/deluxe/thermometer.svg -DialGadget\Deluxe%20Temperature\data\dialBackgroundID=background -DialGadget\Deluxe%20Temperature\data\dialForegroundID=foreground -DialGadget\Deluxe%20Temperature\data\dialNeedleID1=needle -DialGadget\Deluxe%20Temperature\data\dialNeedleID2=needle2 -DialGadget\Deluxe%20Temperature\data\dialNeedleID3=needle3 -DialGadget\Deluxe%20Temperature\data\needle1MinValue=0 -DialGadget\Deluxe%20Temperature\data\needle1MaxValue=120 -DialGadget\Deluxe%20Temperature\data\needle2MinValue=0 -DialGadget\Deluxe%20Temperature\data\needle2MaxValue=100 -DialGadget\Deluxe%20Temperature\data\needle3MinValue=0 -DialGadget\Deluxe%20Temperature\data\needle3MaxValue=1000 -DialGadget\Deluxe%20Temperature\data\needle1DataObject=BaroAltitude -DialGadget\Deluxe%20Temperature\data\needle1ObjectField=Temperature -DialGadget\Deluxe%20Temperature\data\needle2DataObject=BaroAltitude -DialGadget\Deluxe%20Temperature\data\needle2ObjectField=Altitude -DialGadget\Deluxe%20Temperature\data\needle3DataObject=BaroAltitude -DialGadget\Deluxe%20Temperature\data\needle3ObjectField=Altitude -DialGadget\Deluxe%20Temperature\data\needle1Factor=1 -DialGadget\Deluxe%20Temperature\data\needle2Factor=1 -DialGadget\Deluxe%20Temperature\data\needle3Factor=1 -DialGadget\Deluxe%20Temperature\data\needle1Move=Rotate -DialGadget\Deluxe%20Temperature\data\needle2Move=Rotate -DialGadget\Deluxe%20Temperature\data\needle3Move=Rotate -DialGadget\Deluxe%20Temperature\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Deluxe%20Temperature\data\useOpenGLFlag=false -DialGadget\Deluxe%20Temperature\data\beSmooth=false -DialGadget\Deluxe%20Temperature\configInfo\version=0.0.0 -DialGadget\Deluxe%20Temperature\configInfo\locked=false -DialGadget\Deluxe%20Turn%20Coordinator\data\dialFile=/home/lafargue/OP/OpenPilot/trunk/artwork/Dials/deluxe/turncoordinator.svg -DialGadget\Deluxe%20Turn%20Coordinator\data\dialBackgroundID=background -DialGadget\Deluxe%20Turn%20Coordinator\data\dialForegroundID=foreground -DialGadget\Deluxe%20Turn%20Coordinator\data\dialNeedleID1=needle -DialGadget\Deluxe%20Turn%20Coordinator\data\dialNeedleID2=needle2 -DialGadget\Deluxe%20Turn%20Coordinator\data\dialNeedleID3=needle2 -DialGadget\Deluxe%20Turn%20Coordinator\data\needle1MinValue=0 -DialGadget\Deluxe%20Turn%20Coordinator\data\needle1MaxValue=360 -DialGadget\Deluxe%20Turn%20Coordinator\data\needle2MinValue=-20 -DialGadget\Deluxe%20Turn%20Coordinator\data\needle2MaxValue=20 -DialGadget\Deluxe%20Turn%20Coordinator\data\needle3MinValue=0 -DialGadget\Deluxe%20Turn%20Coordinator\data\needle3MaxValue=360 -DialGadget\Deluxe%20Turn%20Coordinator\data\needle1DataObject=AttitudeActual -DialGadget\Deluxe%20Turn%20Coordinator\data\needle1ObjectField=Roll -DialGadget\Deluxe%20Turn%20Coordinator\data\needle2DataObject=AttitudeRaw -DialGadget\Deluxe%20Turn%20Coordinator\data\needle2ObjectField=accels-X -DialGadget\Deluxe%20Turn%20Coordinator\data\needle3DataObject=AttitudeRaw -DialGadget\Deluxe%20Turn%20Coordinator\data\needle3ObjectField=accels-X -DialGadget\Deluxe%20Turn%20Coordinator\data\needle1Factor=-1 -DialGadget\Deluxe%20Turn%20Coordinator\data\needle2Factor=1 -DialGadget\Deluxe%20Turn%20Coordinator\data\needle3Factor=-1 -DialGadget\Deluxe%20Turn%20Coordinator\data\needle1Move=Rotate -DialGadget\Deluxe%20Turn%20Coordinator\data\needle2Move=Horizontal -DialGadget\Deluxe%20Turn%20Coordinator\data\needle3Move=Rotate -DialGadget\Deluxe%20Turn%20Coordinator\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Deluxe%20Turn%20Coordinator\data\useOpenGLFlag=false -DialGadget\Deluxe%20Turn%20Coordinator\data\beSmooth=false -DialGadget\Deluxe%20Turn%20Coordinator\configInfo\version=0.0.0 -DialGadget\Deluxe%20Turn%20Coordinator\configInfo\locked=false -DialGadget\Groundspeed%20kph\data\dialFile=%%DATAPATH%%dials/default/speed.svg -DialGadget\Groundspeed%20kph\data\dialBackgroundID=background -DialGadget\Groundspeed%20kph\data\dialForegroundID= -DialGadget\Groundspeed%20kph\data\dialNeedleID1=needle -DialGadget\Groundspeed%20kph\data\dialNeedleID2= -DialGadget\Groundspeed%20kph\data\dialNeedleID3= -DialGadget\Groundspeed%20kph\data\needle1MinValue=0 -DialGadget\Groundspeed%20kph\data\needle1MaxValue=120 -DialGadget\Groundspeed%20kph\data\needle2MinValue=0 -DialGadget\Groundspeed%20kph\data\needle2MaxValue=100 -DialGadget\Groundspeed%20kph\data\needle3MinValue=0 -DialGadget\Groundspeed%20kph\data\needle3MaxValue=1000 -DialGadget\Groundspeed%20kph\data\needle1DataObject=GPSPosition -DialGadget\Groundspeed%20kph\data\needle1ObjectField=Groundspeed -DialGadget\Groundspeed%20kph\data\needle2DataObject=BaroAltitude -DialGadget\Groundspeed%20kph\data\needle2ObjectField=Altitude -DialGadget\Groundspeed%20kph\data\needle3DataObject=BaroAltitude -DialGadget\Groundspeed%20kph\data\needle3ObjectField=Altitude -DialGadget\Groundspeed%20kph\data\needle1Factor=3.6 -DialGadget\Groundspeed%20kph\data\needle2Factor=1 -DialGadget\Groundspeed%20kph\data\needle3Factor=1 -DialGadget\Groundspeed%20kph\data\needle1Move=Rotate -DialGadget\Groundspeed%20kph\data\needle2Move=Rotate -DialGadget\Groundspeed%20kph\data\needle3Move=Rotate -DialGadget\Groundspeed%20kph\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Groundspeed%20kph\data\useOpenGLFlag=false -DialGadget\Groundspeed%20kph\data\beSmooth=false -DialGadget\Groundspeed%20kph\configInfo\version=0.0.0 -DialGadget\Groundspeed%20kph\configInfo\locked=false -DialGadget\HiContrast%20Attitude\data\dialFile=%%DATAPATH%%dials/hi-contrast/attitude.svg -DialGadget\HiContrast%20Attitude\data\dialBackgroundID=background -DialGadget\HiContrast%20Attitude\data\dialForegroundID=foreground -DialGadget\HiContrast%20Attitude\data\dialNeedleID1=needle -DialGadget\HiContrast%20Attitude\data\dialNeedleID2=needle -DialGadget\HiContrast%20Attitude\data\dialNeedleID3=needle3 -DialGadget\HiContrast%20Attitude\data\needle1MinValue=0 -DialGadget\HiContrast%20Attitude\data\needle1MaxValue=360 -DialGadget\HiContrast%20Attitude\data\needle2MinValue=0 -DialGadget\HiContrast%20Attitude\data\needle2MaxValue=20 -DialGadget\HiContrast%20Attitude\data\needle3MinValue=0 -DialGadget\HiContrast%20Attitude\data\needle3MaxValue=360 -DialGadget\HiContrast%20Attitude\data\needle1DataObject=AttitudeActual -DialGadget\HiContrast%20Attitude\data\needle1ObjectField=Roll -DialGadget\HiContrast%20Attitude\data\needle2DataObject=AttitudeActual -DialGadget\HiContrast%20Attitude\data\needle2ObjectField=Pitch -DialGadget\HiContrast%20Attitude\data\needle3DataObject=AttitudeActual -DialGadget\HiContrast%20Attitude\data\needle3ObjectField=Roll -DialGadget\HiContrast%20Attitude\data\needle1Factor=-1 -DialGadget\HiContrast%20Attitude\data\needle2Factor=75 -DialGadget\HiContrast%20Attitude\data\needle3Factor=-1 -DialGadget\HiContrast%20Attitude\data\needle1Move=Rotate -DialGadget\HiContrast%20Attitude\data\needle2Move=Vertical -DialGadget\HiContrast%20Attitude\data\needle3Move=Rotate -DialGadget\HiContrast%20Attitude\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\HiContrast%20Attitude\data\useOpenGLFlag=false -DialGadget\HiContrast%20Attitude\data\beSmooth=false -DialGadget\HiContrast%20Attitude\configInfo\version=0.0.0 -DialGadget\HiContrast%20Attitude\configInfo\locked=false -DialGadget\HiContrast%20Baro%20Altimeter\data\dialFile=%%DATAPATH%%dials/hi-contrast/altimeter.svg -DialGadget\HiContrast%20Baro%20Altimeter\data\dialBackgroundID=background -DialGadget\HiContrast%20Baro%20Altimeter\data\dialForegroundID=foreground -DialGadget\HiContrast%20Baro%20Altimeter\data\dialNeedleID1=needle -DialGadget\HiContrast%20Baro%20Altimeter\data\dialNeedleID2=needle2 -DialGadget\HiContrast%20Baro%20Altimeter\data\dialNeedleID3=needle3 -DialGadget\HiContrast%20Baro%20Altimeter\data\needle1MinValue=0 -DialGadget\HiContrast%20Baro%20Altimeter\data\needle1MaxValue=10 -DialGadget\HiContrast%20Baro%20Altimeter\data\needle2MinValue=0 -DialGadget\HiContrast%20Baro%20Altimeter\data\needle2MaxValue=100 -DialGadget\HiContrast%20Baro%20Altimeter\data\needle3MinValue=0 -DialGadget\HiContrast%20Baro%20Altimeter\data\needle3MaxValue=1000 -DialGadget\HiContrast%20Baro%20Altimeter\data\needle1DataObject=BaroAltitude -DialGadget\HiContrast%20Baro%20Altimeter\data\needle1ObjectField=Altitude -DialGadget\HiContrast%20Baro%20Altimeter\data\needle2DataObject=BaroAltitude -DialGadget\HiContrast%20Baro%20Altimeter\data\needle2ObjectField=Altitude -DialGadget\HiContrast%20Baro%20Altimeter\data\needle3DataObject=BaroAltitude -DialGadget\HiContrast%20Baro%20Altimeter\data\needle3ObjectField=Altitude -DialGadget\HiContrast%20Baro%20Altimeter\data\needle1Factor=1 -DialGadget\HiContrast%20Baro%20Altimeter\data\needle2Factor=1 -DialGadget\HiContrast%20Baro%20Altimeter\data\needle3Factor=1 -DialGadget\HiContrast%20Baro%20Altimeter\data\needle1Move=Rotate -DialGadget\HiContrast%20Baro%20Altimeter\data\needle2Move=Rotate -DialGadget\HiContrast%20Baro%20Altimeter\data\needle3Move=Rotate -DialGadget\HiContrast%20Baro%20Altimeter\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\HiContrast%20Baro%20Altimeter\data\useOpenGLFlag=false -DialGadget\HiContrast%20Baro%20Altimeter\data\beSmooth=false -DialGadget\HiContrast%20Baro%20Altimeter\configInfo\version=0.0.0 -DialGadget\HiContrast%20Baro%20Altimeter\configInfo\locked=false -DialGadget\HiContrast%20Barometer\data\dialFile=%%DATAPATH%%dials/hi-contrast/barometer.svg -DialGadget\HiContrast%20Barometer\data\dialBackgroundID=background -DialGadget\HiContrast%20Barometer\data\dialForegroundID= -DialGadget\HiContrast%20Barometer\data\dialNeedleID1=needle -DialGadget\HiContrast%20Barometer\data\dialNeedleID2= -DialGadget\HiContrast%20Barometer\data\dialNeedleID3= -DialGadget\HiContrast%20Barometer\data\needle1MinValue=1000 -DialGadget\HiContrast%20Barometer\data\needle1MaxValue=1120 -DialGadget\HiContrast%20Barometer\data\needle2MinValue=0 -DialGadget\HiContrast%20Barometer\data\needle2MaxValue=100 -DialGadget\HiContrast%20Barometer\data\needle3MinValue=0 -DialGadget\HiContrast%20Barometer\data\needle3MaxValue=1000 -DialGadget\HiContrast%20Barometer\data\needle1DataObject=BaroAltitude -DialGadget\HiContrast%20Barometer\data\needle1ObjectField=Pressure -DialGadget\HiContrast%20Barometer\data\needle2DataObject=BaroAltitude -DialGadget\HiContrast%20Barometer\data\needle2ObjectField=Altitude -DialGadget\HiContrast%20Barometer\data\needle3DataObject=BaroAltitude -DialGadget\HiContrast%20Barometer\data\needle3ObjectField=Altitude -DialGadget\HiContrast%20Barometer\data\needle1Factor=10 -DialGadget\HiContrast%20Barometer\data\needle2Factor=1 -DialGadget\HiContrast%20Barometer\data\needle3Factor=1 -DialGadget\HiContrast%20Barometer\data\needle1Move=Rotate -DialGadget\HiContrast%20Barometer\data\needle2Move=Rotate -DialGadget\HiContrast%20Barometer\data\needle3Move=Rotate -DialGadget\HiContrast%20Barometer\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\HiContrast%20Barometer\data\useOpenGLFlag=false -DialGadget\HiContrast%20Barometer\data\beSmooth=false -DialGadget\HiContrast%20Barometer\configInfo\version=0.0.0 -DialGadget\HiContrast%20Barometer\configInfo\locked=false -DialGadget\HiContrast%20Climbrate\data\dialFile=%%DATAPATH%%dials/hi-contrast/vsi.svg -DialGadget\HiContrast%20Climbrate\data\dialBackgroundID=background -DialGadget\HiContrast%20Climbrate\data\dialForegroundID= -DialGadget\HiContrast%20Climbrate\data\dialNeedleID1=needle -DialGadget\HiContrast%20Climbrate\data\dialNeedleID2= -DialGadget\HiContrast%20Climbrate\data\dialNeedleID3= -DialGadget\HiContrast%20Climbrate\data\needle1MinValue=-12 -DialGadget\HiContrast%20Climbrate\data\needle1MaxValue=12 -DialGadget\HiContrast%20Climbrate\data\needle2MinValue=0 -DialGadget\HiContrast%20Climbrate\data\needle2MaxValue=100 -DialGadget\HiContrast%20Climbrate\data\needle3MinValue=0 -DialGadget\HiContrast%20Climbrate\data\needle3MaxValue=1000 -DialGadget\HiContrast%20Climbrate\data\needle1DataObject=VelocityActual -DialGadget\HiContrast%20Climbrate\data\needle1ObjectField=Down -DialGadget\HiContrast%20Climbrate\data\needle2DataObject=BaroAltitude -DialGadget\HiContrast%20Climbrate\data\needle2ObjectField=Altitude -DialGadget\HiContrast%20Climbrate\data\needle3DataObject=BaroAltitude -DialGadget\HiContrast%20Climbrate\data\needle3ObjectField=Altitude -DialGadget\HiContrast%20Climbrate\data\needle1Factor=0.01 -DialGadget\HiContrast%20Climbrate\data\needle2Factor=1 -DialGadget\HiContrast%20Climbrate\data\needle3Factor=1 -DialGadget\HiContrast%20Climbrate\data\needle1Move=Rotate -DialGadget\HiContrast%20Climbrate\data\needle2Move=Rotate -DialGadget\HiContrast%20Climbrate\data\needle3Move=Rotate -DialGadget\HiContrast%20Climbrate\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\HiContrast%20Climbrate\data\useOpenGLFlag=false -DialGadget\HiContrast%20Climbrate\data\beSmooth=false -DialGadget\HiContrast%20Climbrate\configInfo\version=0.0.0 -DialGadget\HiContrast%20Climbrate\configInfo\locked=false -DialGadget\HiContrast%20Compass\data\dialFile=%%DATAPATH%%dials/hi-contrast/compass.svg -DialGadget\HiContrast%20Compass\data\dialBackgroundID=background -DialGadget\HiContrast%20Compass\data\dialForegroundID=foreground -DialGadget\HiContrast%20Compass\data\dialNeedleID1=needle -DialGadget\HiContrast%20Compass\data\dialNeedleID2= -DialGadget\HiContrast%20Compass\data\dialNeedleID3= -DialGadget\HiContrast%20Compass\data\needle1MinValue=0 -DialGadget\HiContrast%20Compass\data\needle1MaxValue=360 -DialGadget\HiContrast%20Compass\data\needle2MinValue=0 -DialGadget\HiContrast%20Compass\data\needle2MaxValue=100 -DialGadget\HiContrast%20Compass\data\needle3MinValue=0 -DialGadget\HiContrast%20Compass\data\needle3MaxValue=1000 -DialGadget\HiContrast%20Compass\data\needle1DataObject=AttitudeActual -DialGadget\HiContrast%20Compass\data\needle1ObjectField=Yaw -DialGadget\HiContrast%20Compass\data\needle2DataObject=BaroAltitude -DialGadget\HiContrast%20Compass\data\needle2ObjectField=Altitude -DialGadget\HiContrast%20Compass\data\needle3DataObject=BaroAltitude -DialGadget\HiContrast%20Compass\data\needle3ObjectField=Altitude -DialGadget\HiContrast%20Compass\data\needle1Factor=-1 -DialGadget\HiContrast%20Compass\data\needle2Factor=1 -DialGadget\HiContrast%20Compass\data\needle3Factor=1 -DialGadget\HiContrast%20Compass\data\needle1Move=Rotate -DialGadget\HiContrast%20Compass\data\needle2Move=Rotate -DialGadget\HiContrast%20Compass\data\needle3Move=Rotate -DialGadget\HiContrast%20Compass\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\HiContrast%20Compass\data\useOpenGLFlag=false -DialGadget\HiContrast%20Compass\data\beSmooth=false -DialGadget\HiContrast%20Compass\configInfo\version=0.0.0 -DialGadget\HiContrast%20Compass\configInfo\locked=false -DialGadget\HiContrast%20Groundspeed%20kph\data\dialFile=%%DATAPATH%%dials/hi-contrast/speed.svg -DialGadget\HiContrast%20Groundspeed%20kph\data\dialBackgroundID=background -DialGadget\HiContrast%20Groundspeed%20kph\data\dialForegroundID= -DialGadget\HiContrast%20Groundspeed%20kph\data\dialNeedleID1=needle -DialGadget\HiContrast%20Groundspeed%20kph\data\dialNeedleID2= -DialGadget\HiContrast%20Groundspeed%20kph\data\dialNeedleID3= -DialGadget\HiContrast%20Groundspeed%20kph\data\needle1MinValue=0 -DialGadget\HiContrast%20Groundspeed%20kph\data\needle1MaxValue=120 -DialGadget\HiContrast%20Groundspeed%20kph\data\needle2MinValue=0 -DialGadget\HiContrast%20Groundspeed%20kph\data\needle2MaxValue=100 -DialGadget\HiContrast%20Groundspeed%20kph\data\needle3MinValue=0 -DialGadget\HiContrast%20Groundspeed%20kph\data\needle3MaxValue=1000 -DialGadget\HiContrast%20Groundspeed%20kph\data\needle1DataObject=GPSPosition -DialGadget\HiContrast%20Groundspeed%20kph\data\needle1ObjectField=Groundspeed -DialGadget\HiContrast%20Groundspeed%20kph\data\needle2DataObject=BaroAltitude -DialGadget\HiContrast%20Groundspeed%20kph\data\needle2ObjectField=Altitude -DialGadget\HiContrast%20Groundspeed%20kph\data\needle3DataObject=BaroAltitude -DialGadget\HiContrast%20Groundspeed%20kph\data\needle3ObjectField=Altitude -DialGadget\HiContrast%20Groundspeed%20kph\data\needle1Factor=3.6 -DialGadget\HiContrast%20Groundspeed%20kph\data\needle2Factor=1 -DialGadget\HiContrast%20Groundspeed%20kph\data\needle3Factor=1 -DialGadget\HiContrast%20Groundspeed%20kph\data\needle1Move=Rotate -DialGadget\HiContrast%20Groundspeed%20kph\data\needle2Move=Rotate -DialGadget\HiContrast%20Groundspeed%20kph\data\needle3Move=Rotate -DialGadget\HiContrast%20Groundspeed%20kph\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\HiContrast%20Groundspeed%20kph\data\useOpenGLFlag=false -DialGadget\HiContrast%20Groundspeed%20kph\data\beSmooth=false -DialGadget\HiContrast%20Groundspeed%20kph\configInfo\version=0.0.0 -DialGadget\HiContrast%20Groundspeed%20kph\configInfo\locked=false -DialGadget\HiContrast%20Temperature\data\dialFile=%%DATAPATH%%dials/hi-contrast/thermometer.svg -DialGadget\HiContrast%20Temperature\data\dialBackgroundID=background -DialGadget\HiContrast%20Temperature\data\dialForegroundID= -DialGadget\HiContrast%20Temperature\data\dialNeedleID1=needle -DialGadget\HiContrast%20Temperature\data\dialNeedleID2=needle2 -DialGadget\HiContrast%20Temperature\data\dialNeedleID3=needle3 -DialGadget\HiContrast%20Temperature\data\needle1MinValue=0 -DialGadget\HiContrast%20Temperature\data\needle1MaxValue=120 -DialGadget\HiContrast%20Temperature\data\needle2MinValue=0 -DialGadget\HiContrast%20Temperature\data\needle2MaxValue=100 -DialGadget\HiContrast%20Temperature\data\needle3MinValue=0 -DialGadget\HiContrast%20Temperature\data\needle3MaxValue=1000 -DialGadget\HiContrast%20Temperature\data\needle1DataObject=BaroAltitude -DialGadget\HiContrast%20Temperature\data\needle1ObjectField=Temperature -DialGadget\HiContrast%20Temperature\data\needle2DataObject=BaroAltitude -DialGadget\HiContrast%20Temperature\data\needle2ObjectField=Altitude -DialGadget\HiContrast%20Temperature\data\needle3DataObject=BaroAltitude -DialGadget\HiContrast%20Temperature\data\needle3ObjectField=Altitude -DialGadget\HiContrast%20Temperature\data\needle1Factor=1 -DialGadget\HiContrast%20Temperature\data\needle2Factor=1 -DialGadget\HiContrast%20Temperature\data\needle3Factor=1 -DialGadget\HiContrast%20Temperature\data\needle1Move=Rotate -DialGadget\HiContrast%20Temperature\data\needle2Move=Rotate -DialGadget\HiContrast%20Temperature\data\needle3Move=Rotate -DialGadget\HiContrast%20Temperature\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\HiContrast%20Temperature\data\useOpenGLFlag=false -DialGadget\HiContrast%20Temperature\data\beSmooth=false -DialGadget\HiContrast%20Temperature\configInfo\version=0.0.0 -DialGadget\HiContrast%20Temperature\configInfo\locked=false -DialGadget\Servo%20Channel%201\data\dialFile=%%DATAPATH%%dials/default/thermometer.svg -DialGadget\Servo%20Channel%201\data\dialBackgroundID=background -DialGadget\Servo%20Channel%201\data\dialForegroundID= -DialGadget\Servo%20Channel%201\data\dialNeedleID1=needle -DialGadget\Servo%20Channel%201\data\dialNeedleID2=needle2 -DialGadget\Servo%20Channel%201\data\dialNeedleID3=needle3 -DialGadget\Servo%20Channel%201\data\needle1MinValue=1000 -DialGadget\Servo%20Channel%201\data\needle1MaxValue=2000 -DialGadget\Servo%20Channel%201\data\needle2MinValue=0 -DialGadget\Servo%20Channel%201\data\needle2MaxValue=100 -DialGadget\Servo%20Channel%201\data\needle3MinValue=0 -DialGadget\Servo%20Channel%201\data\needle3MaxValue=1000 -DialGadget\Servo%20Channel%201\data\needle1DataObject=ManualControlCommand -DialGadget\Servo%20Channel%201\data\needle1ObjectField=Channel-3 -DialGadget\Servo%20Channel%201\data\needle2DataObject=BaroAltitude -DialGadget\Servo%20Channel%201\data\needle2ObjectField=Altitude -DialGadget\Servo%20Channel%201\data\needle3DataObject=BaroAltitude -DialGadget\Servo%20Channel%201\data\needle3ObjectField=Altitude -DialGadget\Servo%20Channel%201\data\needle1Factor=1 -DialGadget\Servo%20Channel%201\data\needle2Factor=1 -DialGadget\Servo%20Channel%201\data\needle3Factor=1 -DialGadget\Servo%20Channel%201\data\needle1Move=Rotate -DialGadget\Servo%20Channel%201\data\needle2Move=Rotate -DialGadget\Servo%20Channel%201\data\needle3Move=Rotate -DialGadget\Servo%20Channel%201\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Servo%20Channel%201\data\useOpenGLFlag=false -DialGadget\Servo%20Channel%201\data\beSmooth=false -DialGadget\Servo%20Channel%201\configInfo\version=0.0.0 -DialGadget\Servo%20Channel%201\configInfo\locked=false -DialGadget\Temperature\data\dialFile=%%DATAPATH%%dials/default/thermometer.svg -DialGadget\Temperature\data\dialBackgroundID=background -DialGadget\Temperature\data\dialForegroundID= -DialGadget\Temperature\data\dialNeedleID1=needle -DialGadget\Temperature\data\dialNeedleID2=needle2 -DialGadget\Temperature\data\dialNeedleID3=needle3 -DialGadget\Temperature\data\needle1MinValue=0 -DialGadget\Temperature\data\needle1MaxValue=120 -DialGadget\Temperature\data\needle2MinValue=0 -DialGadget\Temperature\data\needle2MaxValue=100 -DialGadget\Temperature\data\needle3MinValue=0 -DialGadget\Temperature\data\needle3MaxValue=1000 -DialGadget\Temperature\data\needle1DataObject=BaroAltitude -DialGadget\Temperature\data\needle1ObjectField=Temperature -DialGadget\Temperature\data\needle2DataObject=BaroAltitude -DialGadget\Temperature\data\needle2ObjectField=Altitude -DialGadget\Temperature\data\needle3DataObject=BaroAltitude -DialGadget\Temperature\data\needle3ObjectField=Altitude -DialGadget\Temperature\data\needle1Factor=1 -DialGadget\Temperature\data\needle2Factor=1 -DialGadget\Temperature\data\needle3Factor=1 -DialGadget\Temperature\data\needle1Move=Rotate -DialGadget\Temperature\data\needle2Move=Rotate -DialGadget\Temperature\data\needle3Move=Rotate -DialGadget\Temperature\data\font="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" -DialGadget\Temperature\data\useOpenGLFlag=false -DialGadget\Temperature\data\beSmooth=false -DialGadget\Temperature\configInfo\version=0.0.0 -DialGadget\Temperature\configInfo\locked=false -GCSControlGadget\MS%20Sidewinder\data\controlsMode=2 -GCSControlGadget\MS%20Sidewinder\data\rollChannel=0 -GCSControlGadget\MS%20Sidewinder\data\pitchChannel=1 -GCSControlGadget\MS%20Sidewinder\data\yawChannel=3 -GCSControlGadget\MS%20Sidewinder\data\throttleChannel=2 -GCSControlGadget\MS%20Sidewinder\data\button0Action=0 -GCSControlGadget\MS%20Sidewinder\data\button0Function=0 -GCSControlGadget\MS%20Sidewinder\data\button0Amount=0 -GCSControlGadget\MS%20Sidewinder\data\channel0Reverse=false -GCSControlGadget\MS%20Sidewinder\data\button1Action=0 -GCSControlGadget\MS%20Sidewinder\data\button1Function=0 -GCSControlGadget\MS%20Sidewinder\data\button1Amount=0 -GCSControlGadget\MS%20Sidewinder\data\channel1Reverse=false -GCSControlGadget\MS%20Sidewinder\data\button2Action=0 -GCSControlGadget\MS%20Sidewinder\data\button2Function=3 -GCSControlGadget\MS%20Sidewinder\data\button2Amount=0.1 -GCSControlGadget\MS%20Sidewinder\data\channel2Reverse=true -GCSControlGadget\MS%20Sidewinder\data\button3Action=0 -GCSControlGadget\MS%20Sidewinder\data\button3Function=3 -GCSControlGadget\MS%20Sidewinder\data\button3Amount=0.1 -GCSControlGadget\MS%20Sidewinder\data\channel3Reverse=false -GCSControlGadget\MS%20Sidewinder\data\button4Action=0 -GCSControlGadget\MS%20Sidewinder\data\button4Function=0 -GCSControlGadget\MS%20Sidewinder\data\button4Amount=0 -GCSControlGadget\MS%20Sidewinder\data\channel4Reverse=false -GCSControlGadget\MS%20Sidewinder\data\button5Action=0 -GCSControlGadget\MS%20Sidewinder\data\button5Function=0 -GCSControlGadget\MS%20Sidewinder\data\button5Amount=0 -GCSControlGadget\MS%20Sidewinder\data\channel5Reverse=false -GCSControlGadget\MS%20Sidewinder\data\button6Action=0 -GCSControlGadget\MS%20Sidewinder\data\button6Function=0 -GCSControlGadget\MS%20Sidewinder\data\button6Amount=0 -GCSControlGadget\MS%20Sidewinder\data\channel6Reverse=false -GCSControlGadget\MS%20Sidewinder\data\button7Action=0 -GCSControlGadget\MS%20Sidewinder\data\button7Function=0 -GCSControlGadget\MS%20Sidewinder\data\button7Amount=0 -GCSControlGadget\MS%20Sidewinder\data\channel7Reverse=false -GCSControlGadget\MS%20Sidewinder\configInfo\version=0.0.0 -GCSControlGadget\MS%20Sidewinder\configInfo\locked=false -GpsDisplayGadget\Flight%20GPS\data\defaultSpeed=11 -GpsDisplayGadget\Flight%20GPS\data\defaultDataBits=3 -GpsDisplayGadget\Flight%20GPS\data\defaultFlow=0 -GpsDisplayGadget\Flight%20GPS\data\defaultParity=0 -GpsDisplayGadget\Flight%20GPS\data\defaultStopBits=0 -GpsDisplayGadget\Flight%20GPS\data\defaultPort=Communications Port (COM1) -GpsDisplayGadget\Flight%20GPS\data\connectionMode=Telemetry -GpsDisplayGadget\Flight%20GPS\configInfo\version=0.0.0 -GpsDisplayGadget\Flight%20GPS\configInfo\locked=false -GpsDisplayGadget\GPS%20Mouse\data\defaultSpeed=17 -GpsDisplayGadget\GPS%20Mouse\data\defaultDataBits=3 -GpsDisplayGadget\GPS%20Mouse\data\defaultFlow=0 -GpsDisplayGadget\GPS%20Mouse\data\defaultParity=0 -GpsDisplayGadget\GPS%20Mouse\data\defaultStopBits=0 -GpsDisplayGadget\GPS%20Mouse\data\defaultPort=Communications Port (COM1) -GpsDisplayGadget\GPS%20Mouse\data\connectionMode=Serial -GpsDisplayGadget\GPS%20Mouse\configInfo\version=0.0.0 -GpsDisplayGadget\GPS%20Mouse\configInfo\locked=false -HITL\Flightgear%20HITL\data\simulatorId=FG -HITL\Flightgear%20HITL\data\binPath=\\usr\\games\\fgfs -HITL\Flightgear%20HITL\data\dataPath=\\usr\\share\\games\\FlightGear -HITL\Flightgear%20HITL\data\manual=false -HITL\Flightgear%20HITL\data\startSim=true -HITL\Flightgear%20HITL\data\hostAddress=127.0.0.1 -HITL\Flightgear%20HITL\data\remoteHostAddress=127.0.0.1 -HITL\Flightgear%20HITL\data\outPort=9010 -HITL\Flightgear%20HITL\data\inPort=9009 -HITL\Flightgear%20HITL\data\latitude= -HITL\Flightgear%20HITL\data\longitude= -HITL\Flightgear%20HITL\configInfo\version=0.0.0 -HITL\Flightgear%20HITL\configInfo\locked=false -HITL\XPlane%20HITL\data\simulatorId=X-Plane -HITL\XPlane%20HITL\data\binPath=\\home\\lafargue\\X-Plane 9\\X-Plane-i686 -HITL\XPlane%20HITL\data\dataPath=\\usr\\share\\games\\FlightGear -HITL\XPlane%20HITL\data\manual=false -HITL\XPlane%20HITL\data\startSim=false -HITL\XPlane%20HITL\data\hostAddress=127.0.0.3 -HITL\XPlane%20HITL\data\remoteHostAddress=127.0.0.1 -HITL\XPlane%20HITL\data\outPort=49000 -HITL\XPlane%20HITL\data\inPort=6756 -HITL\XPlane%20HITL\data\latitude= -HITL\XPlane%20HITL\data\longitude= -HITL\XPlane%20HITL\configInfo\version=0.0.0 -HITL\XPlane%20HITL\configInfo\locked=false -ImportExportGadget\default\data\iniFile=gcs.ini -ImportExportGadget\default\configInfo\version=1.0.1 -ImportExportGadget\default\configInfo\locked=false -LineardialGadget\AHRS%20CPU\data\dFile=%%DATAPATH%%dials/default/lineardial-vertical.svg -LineardialGadget\AHRS%20CPU\data\sourceDataObject=AhrsStatus -LineardialGadget\AHRS%20CPU\data\sourceObjectField=CPULoad -LineardialGadget\AHRS%20CPU\data\minValue=0 -LineardialGadget\AHRS%20CPU\data\maxValue=100 -LineardialGadget\AHRS%20CPU\data\redMin=80 -LineardialGadget\AHRS%20CPU\data\redMax=100 -LineardialGadget\AHRS%20CPU\data\yellowMin=50 -LineardialGadget\AHRS%20CPU\data\yellowMax=80 -LineardialGadget\AHRS%20CPU\data\greenMin=0 -LineardialGadget\AHRS%20CPU\data\greenMax=50 -LineardialGadget\AHRS%20CPU\data\font="Andale Mono,12,-1,5,75,0,0,0,0,0" -LineardialGadget\AHRS%20CPU\data\decimalPlaces=0 -LineardialGadget\AHRS%20CPU\data\factor=1 -LineardialGadget\AHRS%20CPU\data\useOpenGLFlag=false -LineardialGadget\AHRS%20CPU\configInfo\version=0.0.0 -LineardialGadget\AHRS%20CPU\configInfo\locked=false -LineardialGadget\Accel%20Horizontal%20X\data\dFile=%%DATAPATH%%dials/default/lineardial-horizontal.svg -LineardialGadget\Accel%20Horizontal%20X\data\sourceDataObject=AttitudeRaw -LineardialGadget\Accel%20Horizontal%20X\data\sourceObjectField=accels-X -LineardialGadget\Accel%20Horizontal%20X\data\minValue=-11 -LineardialGadget\Accel%20Horizontal%20X\data\maxValue=11 -LineardialGadget\Accel%20Horizontal%20X\data\redMin=-11 -LineardialGadget\Accel%20Horizontal%20X\data\redMax=11 -LineardialGadget\Accel%20Horizontal%20X\data\yellowMin=-11 -LineardialGadget\Accel%20Horizontal%20X\data\yellowMax=-5 -LineardialGadget\Accel%20Horizontal%20X\data\greenMin=-10 -LineardialGadget\Accel%20Horizontal%20X\data\greenMax=-9 -LineardialGadget\Accel%20Horizontal%20X\data\font="Andale Mono,8,-1,5,50,0,0,0,0,0" -LineardialGadget\Accel%20Horizontal%20X\data\decimalPlaces=2 -LineardialGadget\Accel%20Horizontal%20X\data\factor=1 -LineardialGadget\Accel%20Horizontal%20X\data\useOpenGLFlag=false -LineardialGadget\Accel%20Horizontal%20X\configInfo\version=0.0.0 -LineardialGadget\Accel%20Horizontal%20X\configInfo\locked=false -LineardialGadget\Accel%20Horizontal%20Y\data\dFile=%%DATAPATH%%dials/default/lineardial-horizontal.svg -LineardialGadget\Accel%20Horizontal%20Y\data\sourceDataObject=AttitudeRaw -LineardialGadget\Accel%20Horizontal%20Y\data\sourceObjectField=accels-Y -LineardialGadget\Accel%20Horizontal%20Y\data\minValue=-11 -LineardialGadget\Accel%20Horizontal%20Y\data\maxValue=11 -LineardialGadget\Accel%20Horizontal%20Y\data\redMin=-11 -LineardialGadget\Accel%20Horizontal%20Y\data\redMax=11 -LineardialGadget\Accel%20Horizontal%20Y\data\yellowMin=-11 -LineardialGadget\Accel%20Horizontal%20Y\data\yellowMax=-5 -LineardialGadget\Accel%20Horizontal%20Y\data\greenMin=-10 -LineardialGadget\Accel%20Horizontal%20Y\data\greenMax=-9 -LineardialGadget\Accel%20Horizontal%20Y\data\font="Andale Mono,6,-1,5,50,0,0,0,0,0" -LineardialGadget\Accel%20Horizontal%20Y\data\decimalPlaces=2 -LineardialGadget\Accel%20Horizontal%20Y\data\factor=1 -LineardialGadget\Accel%20Horizontal%20Y\data\useOpenGLFlag=false -LineardialGadget\Accel%20Horizontal%20Y\configInfo\version=0.0.0 -LineardialGadget\Accel%20Horizontal%20Y\configInfo\locked=false -LineardialGadget\Accel%20Horizontal%20Z\data\dFile=%%DATAPATH%%dials/default/lineardial-horizontal.svg -LineardialGadget\Accel%20Horizontal%20Z\data\sourceDataObject=AttitudeRaw -LineardialGadget\Accel%20Horizontal%20Z\data\sourceObjectField=accels-Z -LineardialGadget\Accel%20Horizontal%20Z\data\minValue=-11 -LineardialGadget\Accel%20Horizontal%20Z\data\maxValue=11 -LineardialGadget\Accel%20Horizontal%20Z\data\redMin=-11 -LineardialGadget\Accel%20Horizontal%20Z\data\redMax=11 -LineardialGadget\Accel%20Horizontal%20Z\data\yellowMin=-11 -LineardialGadget\Accel%20Horizontal%20Z\data\yellowMax=-5 -LineardialGadget\Accel%20Horizontal%20Z\data\greenMin=-10 -LineardialGadget\Accel%20Horizontal%20Z\data\greenMax=-9 -LineardialGadget\Accel%20Horizontal%20Z\data\font="Andale Mono,8,-1,5,50,0,0,0,0,0" -LineardialGadget\Accel%20Horizontal%20Z\data\decimalPlaces=2 -LineardialGadget\Accel%20Horizontal%20Z\data\factor=1 -LineardialGadget\Accel%20Horizontal%20Z\data\useOpenGLFlag=false -LineardialGadget\Accel%20Horizontal%20Z\configInfo\version=0.0.0 -LineardialGadget\Accel%20Horizontal%20Z\configInfo\locked=false -LineardialGadget\Arm%20Status\data\dFile=%%DATAPATH%%dials/default/arm-status.svg -LineardialGadget\Arm%20Status\data\sourceDataObject=FlightStatus -LineardialGadget\Arm%20Status\data\sourceObjectField=Armed -LineardialGadget\Arm%20Status\data\minValue=0 -LineardialGadget\Arm%20Status\data\maxValue=100 -LineardialGadget\Arm%20Status\data\redMin=0 -LineardialGadget\Arm%20Status\data\redMax=33 -LineardialGadget\Arm%20Status\data\yellowMin=33 -LineardialGadget\Arm%20Status\data\yellowMax=66 -LineardialGadget\Arm%20Status\data\greenMin=66 -LineardialGadget\Arm%20Status\data\greenMax=100 -LineardialGadget\Arm%20Status\data\font=",12,-1,5,50,0,0,0,0,0" -LineardialGadget\Arm%20Status\data\decimalPlaces=0 -LineardialGadget\Arm%20Status\data\factor=1 -LineardialGadget\Arm%20Status\data\useOpenGLFlag=false -LineardialGadget\Arm%20Status\configInfo\version=0.0.0 -LineardialGadget\Arm%20Status\configInfo\locked=false -LineardialGadget\Flight%20Time\data\dFile=%%DATAPATH%%dials/default/textonly.svg -LineardialGadget\Flight%20Time\data\sourceDataObject=SystemStats -LineardialGadget\Flight%20Time\data\sourceObjectField=FlightTime -LineardialGadget\Flight%20Time\data\minValue=0 -LineardialGadget\Flight%20Time\data\maxValue=100 -LineardialGadget\Flight%20Time\data\redMin=0 -LineardialGadget\Flight%20Time\data\redMax=33 -LineardialGadget\Flight%20Time\data\yellowMin=33 -LineardialGadget\Flight%20Time\data\yellowMax=66 -LineardialGadget\Flight%20Time\data\greenMin=66 -LineardialGadget\Flight%20Time\data\greenMax=100 -LineardialGadget\Flight%20Time\data\font=",12,-1,5,50,0,0,0,0,0" -LineardialGadget\Flight%20Time\data\decimalPlaces=0 -LineardialGadget\Flight%20Time\data\factor=0.001 -LineardialGadget\Flight%20Time\data\useOpenGLFlag=false -LineardialGadget\Flight%20Time\configInfo\version=0.0.0 -LineardialGadget\Flight%20Time\configInfo\locked=false -LineardialGadget\Flight%20mode\data\dFile=%%DATAPATH%%dials/default/flightmode-status.svg -LineardialGadget\Flight%20mode\data\sourceDataObject=FlightStatus -LineardialGadget\Flight%20mode\data\sourceObjectField=FlightMode -LineardialGadget\Flight%20mode\data\minValue=0 -LineardialGadget\Flight%20mode\data\maxValue=100 -LineardialGadget\Flight%20mode\data\redMin=0 -LineardialGadget\Flight%20mode\data\redMax=33 -LineardialGadget\Flight%20mode\data\yellowMin=33 -LineardialGadget\Flight%20mode\data\yellowMax=66 -LineardialGadget\Flight%20mode\data\greenMin=66 -LineardialGadget\Flight%20mode\data\greenMax=100 -LineardialGadget\Flight%20mode\data\font=",12,-1,5,50,0,0,0,0,0" -LineardialGadget\Flight%20mode\data\decimalPlaces=0 -LineardialGadget\Flight%20mode\data\factor=1 -LineardialGadget\Flight%20mode\data\useOpenGLFlag=false -LineardialGadget\Flight%20mode\configInfo\version=0.0.0 -LineardialGadget\Flight%20mode\configInfo\locked=false -LineardialGadget\GPS%20Sats\data\dFile=%%DATAPATH%%dials/default/gps-signal.svg -LineardialGadget\GPS%20Sats\data\sourceDataObject=GPSPosition -LineardialGadget\GPS%20Sats\data\sourceObjectField=Satellites -LineardialGadget\GPS%20Sats\data\minValue=0 -LineardialGadget\GPS%20Sats\data\maxValue=12 -LineardialGadget\GPS%20Sats\data\redMin=0 -LineardialGadget\GPS%20Sats\data\redMax=0 -LineardialGadget\GPS%20Sats\data\yellowMin=0 -LineardialGadget\GPS%20Sats\data\yellowMax=0 -LineardialGadget\GPS%20Sats\data\greenMin=0 -LineardialGadget\GPS%20Sats\data\greenMax=0 -LineardialGadget\GPS%20Sats\data\font=",12,-1,5,50,0,0,0,0,0" -LineardialGadget\GPS%20Sats\data\decimalPlaces=0 -LineardialGadget\GPS%20Sats\data\factor=1 -LineardialGadget\GPS%20Sats\data\useOpenGLFlag=false -LineardialGadget\GPS%20Sats\configInfo\version=0.0.0 -LineardialGadget\GPS%20Sats\configInfo\locked=false -LineardialGadget\GPS%20Status\data\dFile=%%DATAPATH%%dials/default/gps-status.svg -LineardialGadget\GPS%20Status\data\sourceDataObject=GPSPosition -LineardialGadget\GPS%20Status\data\sourceObjectField=Status -LineardialGadget\GPS%20Status\data\minValue=0 -LineardialGadget\GPS%20Status\data\maxValue=100 -LineardialGadget\GPS%20Status\data\redMin=0 -LineardialGadget\GPS%20Status\data\redMax=33 -LineardialGadget\GPS%20Status\data\yellowMin=33 -LineardialGadget\GPS%20Status\data\yellowMax=66 -LineardialGadget\GPS%20Status\data\greenMin=66 -LineardialGadget\GPS%20Status\data\greenMax=100 -LineardialGadget\GPS%20Status\data\font=",12,-1,5,50,0,0,0,0,0" -LineardialGadget\GPS%20Status\data\decimalPlaces=0 -LineardialGadget\GPS%20Status\data\factor=1 -LineardialGadget\GPS%20Status\data\useOpenGLFlag=false -LineardialGadget\GPS%20Status\configInfo\version=0.0.0 -LineardialGadget\GPS%20Status\configInfo\locked=false -LineardialGadget\Mainboard%20CPU\data\dFile=%%DATAPATH%%dials/default/lineardial-vertical.svg -LineardialGadget\Mainboard%20CPU\data\sourceDataObject=SystemStats -LineardialGadget\Mainboard%20CPU\data\sourceObjectField=CPULoad -LineardialGadget\Mainboard%20CPU\data\minValue=0 -LineardialGadget\Mainboard%20CPU\data\maxValue=100 -LineardialGadget\Mainboard%20CPU\data\redMin=80 -LineardialGadget\Mainboard%20CPU\data\redMax=100 -LineardialGadget\Mainboard%20CPU\data\yellowMin=50 -LineardialGadget\Mainboard%20CPU\data\yellowMax=80 -LineardialGadget\Mainboard%20CPU\data\greenMin=0 -LineardialGadget\Mainboard%20CPU\data\greenMax=50 -LineardialGadget\Mainboard%20CPU\data\font="Andale Mono,12,-1,5,75,0,0,0,0,0" -LineardialGadget\Mainboard%20CPU\data\decimalPlaces=0 -LineardialGadget\Mainboard%20CPU\data\factor=1 -LineardialGadget\Mainboard%20CPU\data\useOpenGLFlag=false -LineardialGadget\Mainboard%20CPU\configInfo\version=0.0.0 -LineardialGadget\Mainboard%20CPU\configInfo\locked=false -LineardialGadget\PitchActual\data\dFile=%%DATAPATH%%dials/default/lineardial-vertical.svg -LineardialGadget\PitchActual\data\sourceDataObject=AttitudeActual -LineardialGadget\PitchActual\data\sourceObjectField=Pitch -LineardialGadget\PitchActual\data\minValue=-90 -LineardialGadget\PitchActual\data\maxValue=90 -LineardialGadget\PitchActual\data\redMin=0 -LineardialGadget\PitchActual\data\redMax=1 -LineardialGadget\PitchActual\data\yellowMin=0.1 -LineardialGadget\PitchActual\data\yellowMax=0.9 -LineardialGadget\PitchActual\data\greenMin=0.3 -LineardialGadget\PitchActual\data\greenMax=0.8 -LineardialGadget\PitchActual\data\font="Andale Mono,12,-1,5,75,0,0,0,0,0" -LineardialGadget\PitchActual\data\decimalPlaces=2 -LineardialGadget\PitchActual\data\factor=1 -LineardialGadget\PitchActual\data\useOpenGLFlag=false -LineardialGadget\PitchActual\configInfo\version=0.0.0 -LineardialGadget\PitchActual\configInfo\locked=false -LineardialGadget\PitchCommand\data\dFile=%%DATAPATH%%dials/default/lineardial-vertical.svg -LineardialGadget\PitchCommand\data\sourceDataObject=ManualControlCommand -LineardialGadget\PitchCommand\data\sourceObjectField=Pitch -LineardialGadget\PitchCommand\data\minValue=-1 -LineardialGadget\PitchCommand\data\maxValue=1 -LineardialGadget\PitchCommand\data\redMin=0 -LineardialGadget\PitchCommand\data\redMax=1 -LineardialGadget\PitchCommand\data\yellowMin=0.1 -LineardialGadget\PitchCommand\data\yellowMax=0.9 -LineardialGadget\PitchCommand\data\greenMin=0.3 -LineardialGadget\PitchCommand\data\greenMax=0.8 -LineardialGadget\PitchCommand\data\font="Andale Mono,12,-1,5,75,0,0,0,0,0" -LineardialGadget\PitchCommand\data\decimalPlaces=2 -LineardialGadget\PitchCommand\data\factor=1 -LineardialGadget\PitchCommand\data\useOpenGLFlag=false -LineardialGadget\PitchCommand\configInfo\version=0.0.0 -LineardialGadget\PitchCommand\configInfo\locked=false -LineardialGadget\PitchDesired\data\dFile=%%DATAPATH%%dials/default/lineardial-vertical.svg -LineardialGadget\PitchDesired\data\sourceDataObject=ActuatorDesired -LineardialGadget\PitchDesired\data\sourceObjectField=Pitch -LineardialGadget\PitchDesired\data\minValue=-1 -LineardialGadget\PitchDesired\data\maxValue=1 -LineardialGadget\PitchDesired\data\redMin=0 -LineardialGadget\PitchDesired\data\redMax=1 -LineardialGadget\PitchDesired\data\yellowMin=0.1 -LineardialGadget\PitchDesired\data\yellowMax=0.9 -LineardialGadget\PitchDesired\data\greenMin=0.3 -LineardialGadget\PitchDesired\data\greenMax=0.8 -LineardialGadget\PitchDesired\data\font="Andale Mono,12,-1,5,75,0,0,0,0,0" -LineardialGadget\PitchDesired\data\decimalPlaces=2 -LineardialGadget\PitchDesired\data\factor=1 -LineardialGadget\PitchDesired\data\useOpenGLFlag=false -LineardialGadget\PitchDesired\configInfo\version=0.0.0 -LineardialGadget\PitchDesired\configInfo\locked=false -LineardialGadget\Roll\data\dFile=%%DATAPATH%%dials/default/lineardial-vertical.svg -LineardialGadget\Roll\data\sourceDataObject=ManualControlCommand -LineardialGadget\Roll\data\sourceObjectField=Roll -LineardialGadget\Roll\data\minValue=0 -LineardialGadget\Roll\data\maxValue=1 -LineardialGadget\Roll\data\redMin=0 -LineardialGadget\Roll\data\redMax=1 -LineardialGadget\Roll\data\yellowMin=0.1 -LineardialGadget\Roll\data\yellowMax=0.9 -LineardialGadget\Roll\data\greenMin=0.3 -LineardialGadget\Roll\data\greenMax=0.8 -LineardialGadget\Roll\data\font="Andale Mono,12,-1,5,75,0,0,0,0,0" -LineardialGadget\Roll\data\decimalPlaces=2 -LineardialGadget\Roll\data\factor=1 -LineardialGadget\Roll\data\useOpenGLFlag=false -LineardialGadget\Roll\configInfo\version=0.0.0 -LineardialGadget\Roll\configInfo\locked=false -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\dFile=%%DATAPATH%%dials/default/lineardial-horizontal.svg -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\sourceDataObject=GCSTelemetryStats -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\sourceObjectField=RxDataRate -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\minValue=0 -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\maxValue=1200 -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\redMin=900 -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\redMax=1200 -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\yellowMin=650 -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\yellowMax=900 -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\greenMin=0 -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\greenMax=650 -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\font="Andale Mono,12,-1,5,75,0,0,0,0,0" -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\decimalPlaces=0 -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\factor=1 -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\data\useOpenGLFlag=false -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\configInfo\version=0.0.0 -LineardialGadget\Telemetry%20RX%20Rate%20Horizontal\configInfo\locked=false -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\dFile=%%DATAPATH%%dials/default/lineardial-horizontal.svg -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\sourceDataObject=GCSTelemetryStats -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\sourceObjectField=TxDataRate -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\minValue=0 -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\maxValue=1200 -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\redMin=900 -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\redMax=1200 -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\yellowMin=650 -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\yellowMax=900 -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\greenMin=0 -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\greenMax=650 -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\font="Andale Mono,12,-1,5,75,0,0,0,0,0" -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\decimalPlaces=0 -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\factor=1 -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\data\useOpenGLFlag=false -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\configInfo\version=0.0.0 -LineardialGadget\Telemetry%20TX%20Rate%20Horizontal\configInfo\locked=false -LineardialGadget\Throttle\data\dFile=%%DATAPATH%%dials/default/lineardial-vertical.svg -LineardialGadget\Throttle\data\sourceDataObject=ManualControlCommand -LineardialGadget\Throttle\data\sourceObjectField=Throttle -LineardialGadget\Throttle\data\minValue=0 -LineardialGadget\Throttle\data\maxValue=1 -LineardialGadget\Throttle\data\redMin=0 -LineardialGadget\Throttle\data\redMax=1 -LineardialGadget\Throttle\data\yellowMin=0.1 -LineardialGadget\Throttle\data\yellowMax=0.9 -LineardialGadget\Throttle\data\greenMin=0.3 -LineardialGadget\Throttle\data\greenMax=0.8 -LineardialGadget\Throttle\data\font="Andale Mono,12,-1,5,75,0,0,0,0,0" -LineardialGadget\Throttle\data\decimalPlaces=2 -LineardialGadget\Throttle\data\factor=1 -LineardialGadget\Throttle\data\useOpenGLFlag=false -LineardialGadget\Throttle\configInfo\version=0.0.0 -LineardialGadget\Throttle\configInfo\locked=false -LineardialGadget\Yaw\data\dFile=%%DATAPATH%%dials/default/lineardial-vertical.svg -LineardialGadget\Yaw\data\sourceDataObject=ManualControlCommand -LineardialGadget\Yaw\data\sourceObjectField=Yaw -LineardialGadget\Yaw\data\minValue=0 -LineardialGadget\Yaw\data\maxValue=1 -LineardialGadget\Yaw\data\redMin=0 -LineardialGadget\Yaw\data\redMax=1 -LineardialGadget\Yaw\data\yellowMin=0.1 -LineardialGadget\Yaw\data\yellowMax=0.9 -LineardialGadget\Yaw\data\greenMin=0.3 -LineardialGadget\Yaw\data\greenMax=0.8 -LineardialGadget\Yaw\data\font="Andale Mono,12,-1,5,75,0,0,0,0,0" -LineardialGadget\Yaw\data\decimalPlaces=2 -LineardialGadget\Yaw\data\factor=1 -LineardialGadget\Yaw\data\useOpenGLFlag=false -LineardialGadget\Yaw\configInfo\version=0.0.0 -LineardialGadget\Yaw\configInfo\locked=false -ModelViewGadget\Aeroquad%20%2B\data\acFilename=%%DATAPATH%%models/multi/aeroquad/aeroquad_+.3ds -ModelViewGadget\Aeroquad%20%2B\data\bgFilename=%%DATAPATH%%models/backgrounds/default_background.png -ModelViewGadget\Aeroquad%20%2B\data\enableVbo=false -ModelViewGadget\Aeroquad%20%2B\configInfo\version=0.0.0 -ModelViewGadget\Aeroquad%20%2B\configInfo\locked=false -ModelViewGadget\Easyquad%20X\data\acFilename=%%DATAPATH%%models/multi/easy_quad/easy_quad_X.3ds -ModelViewGadget\Easyquad%20X\data\bgFilename=%%DATAPATH%%models/backgrounds/default_background.png -ModelViewGadget\Easyquad%20X\data\enableVbo=false -ModelViewGadget\Easyquad%20X\configInfo\version=0.0.0 -ModelViewGadget\Easyquad%20X\configInfo\locked=false -ModelViewGadget\Easystar\data\acFilename=%%DATAPATH%%models/planes/Easystar/easystar.3ds -ModelViewGadget\Easystar\data\bgFilename=%%DATAPATH%%models/backgrounds/default_background.png -ModelViewGadget\Easystar\data\enableVbo=false -ModelViewGadget\Easystar\configInfo\version=0.0.0 -ModelViewGadget\Easystar\configInfo\locked=false -ModelViewGadget\Firecracker\data\acFilename=%%DATAPATH%%models/planes/firecracker/firecracker.3ds -ModelViewGadget\Firecracker\data\bgFilename=%%DATAPATH%%models/backgrounds/default_background.png -ModelViewGadget\Firecracker\data\enableVbo=false -ModelViewGadget\Firecracker\configInfo\version=0.0.0 -ModelViewGadget\Firecracker\configInfo\locked=false -ModelViewGadget\Funjet\data\acFilename=%%DATAPATH%%models/planes/funjet/funjet.3ds -ModelViewGadget\Funjet\data\bgFilename=%%DATAPATH%%models/backgrounds/default_background.png -ModelViewGadget\Funjet\data\enableVbo=false -ModelViewGadget\Funjet\configInfo\version=0.0.0 -ModelViewGadget\Funjet\configInfo\locked=false -ModelViewGadget\Gaui%20330X\data\acFilename=%%DATAPATH%%models/multi/gaui_330x/gaui_330x.3ds -ModelViewGadget\Gaui%20330X\data\bgFilename=%%DATAPATH%%models/backgrounds/default_background.png -ModelViewGadget\Gaui%20330X\data\enableVbo=false -ModelViewGadget\Gaui%20330X\configInfo\version=0.0.0 -ModelViewGadget\Gaui%20330X\configInfo\locked=false -ModelViewGadget\Helicopter%20-%20TRex%20450\data\acFilename=%%DATAPATH%%models/helis/t-rex/t-rex_450_xl.3ds -ModelViewGadget\Helicopter%20-%20TRex%20450\data\bgFilename=%%DATAPATH%%models/backgrounds/default_background.png -ModelViewGadget\Helicopter%20-%20TRex%20450\data\enableVbo=false -ModelViewGadget\Helicopter%20-%20TRex%20450\configInfo\version=0.0.0 -ModelViewGadget\Helicopter%20-%20TRex%20450\configInfo\locked=false -ModelViewGadget\Hexacopter\data\acFilename=%%DATAPATH%%models/multi/mikrokopter/MK_Hexa.3ds -ModelViewGadget\Hexacopter\data\bgFilename=%%DATAPATH%%models/backgrounds/default_background.png -ModelViewGadget\Hexacopter\data\enableVbo=false -ModelViewGadget\Hexacopter\configInfo\version=0.0.0 -ModelViewGadget\Hexacopter\configInfo\locked=false -ModelViewGadget\Quadcopter\data\acFilename=%%DATAPATH%%models/multi/mikrokopter/MK_L4-ME.3ds -ModelViewGadget\Quadcopter\data\bgFilename=%%DATAPATH%%models/backgrounds/default_background.png -ModelViewGadget\Quadcopter\data\enableVbo=false -ModelViewGadget\Quadcopter\configInfo\version=0.0.0 -ModelViewGadget\Quadcopter\configInfo\locked=false -ModelViewGadget\Scorpion%20Tricopter\data\acFilename=%%DATAPATH%%models/multi/scorpion_tricopter/scorpion_tricopter.3ds -ModelViewGadget\Scorpion%20Tricopter\data\bgFilename=%%DATAPATH%%models/backgrounds/default_background.png -ModelViewGadget\Scorpion%20Tricopter\data\enableVbo=false -ModelViewGadget\Scorpion%20Tricopter\configInfo\version=0.0.0 -ModelViewGadget\Scorpion%20Tricopter\configInfo\locked=false -ModelViewGadget\Test%20Quad%20%2B\data\acFilename=%%DATAPATH%%models/multi/test_quad/test_quad_+.3ds -ModelViewGadget\Test%20Quad%20%2B\data\bgFilename=%%DATAPATH%%models/backgrounds/default_background.png -ModelViewGadget\Test%20Quad%20%2B\data\enableVbo=false -ModelViewGadget\Test%20Quad%20%2B\configInfo\version=0.0.0 -ModelViewGadget\Test%20Quad%20%2B\configInfo\locked=false -ModelViewGadget\Test%20Quad%20X\data\acFilename=%%DATAPATH%%models/multi/test_quad/test_quad_X.3ds -ModelViewGadget\Test%20Quad%20X\data\bgFilename=%%DATAPATH%%models/backgrounds/default_background.png -ModelViewGadget\Test%20Quad%20X\data\enableVbo=false -ModelViewGadget\Test%20Quad%20X\configInfo\version=0.0.0 -ModelViewGadget\Test%20Quad%20X\configInfo\locked=false -OPMapGadget\Google%20Sat\data\mapProvider=GoogleSatellite -OPMapGadget\Google%20Sat\data\defaultZoom=2 -OPMapGadget\Google%20Sat\data\defaultLatitude=0 -OPMapGadget\Google%20Sat\data\defaultLongitude=0 -OPMapGadget\Google%20Sat\data\useOpenGL=true -OPMapGadget\Google%20Sat\data\showTileGridLines=false -OPMapGadget\Google%20Sat\data\accessMode=ServerAndCache -OPMapGadget\Google%20Sat\data\useMemoryCache=true -OPMapGadget\Google%20Sat\data\uavSymbol=mapquad.png -OPMapGadget\Google%20Sat\data\cacheLocation= -OPMapGadget\Google%20Sat\configInfo\version=0.0.0 -OPMapGadget\Google%20Sat\configInfo\locked=false -OPMapGadget\Memory%20Only\data\mapProvider=GoogleMap -OPMapGadget\Memory%20Only\data\defaultZoom=2 -OPMapGadget\Memory%20Only\data\defaultLatitude=0 -OPMapGadget\Memory%20Only\data\defaultLongitude=0 -OPMapGadget\Memory%20Only\data\useOpenGL=true -OPMapGadget\Memory%20Only\data\showTileGridLines=false -OPMapGadget\Memory%20Only\data\accessMode=CacheOnly -OPMapGadget\Memory%20Only\data\useMemoryCache=true -OPMapGadget\Memory%20Only\data\uavSymbol=airplanepip.png -OPMapGadget\Memory%20Only\data\cacheLocation= -OPMapGadget\Memory%20Only\configInfo\version=0.0.0 -OPMapGadget\Memory%20Only\configInfo\locked=false -OPMapGadget\default\data\mapProvider=GoogleMap -OPMapGadget\default\data\defaultZoom=2 -OPMapGadget\default\data\defaultLatitude=0 -OPMapGadget\default\data\defaultLongitude=0 -OPMapGadget\default\data\useOpenGL=false -OPMapGadget\default\data\showTileGridLines=false -OPMapGadget\default\data\accessMode=ServerAndCache -OPMapGadget\default\data\useMemoryCache=true -OPMapGadget\default\data\uavSymbol=mapquad.png -OPMapGadget\default\data\cacheLocation= -OPMapGadget\default\configInfo\version=0.0.0 -OPMapGadget\default\configInfo\locked=false -PFDGadget\raw\data\dialFile=%%DATAPATH%%pfd/default/pfd.svg -PFDGadget\raw\data\useOpenGLFlag=false -PFDGadget\raw\data\hqFonts=false -PFDGadget\raw\data\beSmooth=false -PFDGadget\raw\configInfo\version=0.0.0 -PFDGadget\raw\configInfo\locked=false -PFDGadget\smooth\data\dialFile=%%DATAPATH%%pfd/default/pfd.svg -PFDGadget\smooth\data\useOpenGLFlag=false -PFDGadget\smooth\data\hqFonts=false -PFDGadget\smooth\data\beSmooth=true -PFDGadget\smooth\configInfo\version=0.0.0 -PFDGadget\smooth\configInfo\locked=false -PipXtreme\default\configInfo\version=0.0.0 -PipXtreme\default\configInfo\locked=false -ScopeGadget\Accel\data\configurationStreamVersion=1000 -ScopeGadget\Accel\data\plotType=1 -ScopeGadget\Accel\data\dataSize=60 -ScopeGadget\Accel\data\refreshInterval=100 -ScopeGadget\Accel\data\plotCurveCount=3 -ScopeGadget\Accel\data\plotCurve0\uavObject=AttitudeRaw -ScopeGadget\Accel\data\plotCurve0\uavField=accels-X -ScopeGadget\Accel\data\plotCurve0\color=4294901760 -ScopeGadget\Accel\data\plotCurve0\yScalePower=0 -ScopeGadget\Accel\data\plotCurve0\yMinimum=0 -ScopeGadget\Accel\data\plotCurve0\yMaximum=0 -ScopeGadget\Accel\data\plotCurve1\uavObject=AttitudeRaw -ScopeGadget\Accel\data\plotCurve1\uavField=accels-Y -ScopeGadget\Accel\data\plotCurve1\color=4283782655 -ScopeGadget\Accel\data\plotCurve1\yScalePower=0 -ScopeGadget\Accel\data\plotCurve1\yMinimum=0 -ScopeGadget\Accel\data\plotCurve1\yMaximum=0 -ScopeGadget\Accel\data\plotCurve2\uavObject=AttitudeRaw -ScopeGadget\Accel\data\plotCurve2\uavField=accels-Z -ScopeGadget\Accel\data\plotCurve2\color=4283804160 -ScopeGadget\Accel\data\plotCurve2\yScalePower=0 -ScopeGadget\Accel\data\plotCurve2\yMinimum=0 -ScopeGadget\Accel\data\plotCurve2\yMaximum=0 -ScopeGadget\Accel\data\LoggingEnabled=false -ScopeGadget\Accel\data\LoggingNewFileOnConnect=false -ScopeGadget\Accel\data\LoggingPath= -ScopeGadget\Accel\configInfo\version=0.0.0 -ScopeGadget\Accel\configInfo\locked=false -ScopeGadget\Actuators\data\configurationStreamVersion=1000 -ScopeGadget\Actuators\data\plotType=1 -ScopeGadget\Actuators\data\dataSize=20 -ScopeGadget\Actuators\data\refreshInterval=100 -ScopeGadget\Actuators\data\plotCurveCount=4 -ScopeGadget\Actuators\data\plotCurve0\uavObject=ActuatorCommand -ScopeGadget\Actuators\data\plotCurve0\uavField=Channel-4 -ScopeGadget\Actuators\data\plotCurve0\color=4294901760 -ScopeGadget\Actuators\data\plotCurve0\yScalePower=0 -ScopeGadget\Actuators\data\plotCurve0\yMinimum=0 -ScopeGadget\Actuators\data\plotCurve0\yMaximum=0 -ScopeGadget\Actuators\data\plotCurve1\uavObject=ActuatorCommand -ScopeGadget\Actuators\data\plotCurve1\uavField=Channel-5 -ScopeGadget\Actuators\data\plotCurve1\color=4294901760 -ScopeGadget\Actuators\data\plotCurve1\yScalePower=0 -ScopeGadget\Actuators\data\plotCurve1\yMinimum=0 -ScopeGadget\Actuators\data\plotCurve1\yMaximum=0 -ScopeGadget\Actuators\data\plotCurve2\uavObject=ActuatorCommand -ScopeGadget\Actuators\data\plotCurve2\uavField=Channel-6 -ScopeGadget\Actuators\data\plotCurve2\color=4289374847 -ScopeGadget\Actuators\data\plotCurve2\yScalePower=0 -ScopeGadget\Actuators\data\plotCurve2\yMinimum=0 -ScopeGadget\Actuators\data\plotCurve2\yMaximum=0 -ScopeGadget\Actuators\data\plotCurve3\uavObject=ActuatorCommand -ScopeGadget\Actuators\data\plotCurve3\uavField=Channel-7 -ScopeGadget\Actuators\data\plotCurve3\color=4289374847 -ScopeGadget\Actuators\data\plotCurve3\yScalePower=0 -ScopeGadget\Actuators\data\plotCurve3\yMinimum=0 -ScopeGadget\Actuators\data\plotCurve3\yMaximum=0 -ScopeGadget\Actuators\data\LoggingEnabled=false -ScopeGadget\Actuators\data\LoggingNewFileOnConnect=false -ScopeGadget\Actuators\data\LoggingPath= -ScopeGadget\Actuators\configInfo\version=0.0.0 -ScopeGadget\Actuators\configInfo\locked=false -ScopeGadget\Attitude\data\configurationStreamVersion=1000 -ScopeGadget\Attitude\data\plotType=1 -ScopeGadget\Attitude\data\dataSize=60 -ScopeGadget\Attitude\data\refreshInterval=100 -ScopeGadget\Attitude\data\plotCurveCount=3 -ScopeGadget\Attitude\data\plotCurve0\uavObject=AttitudeActual -ScopeGadget\Attitude\data\plotCurve0\uavField=Roll -ScopeGadget\Attitude\data\plotCurve0\color=4283760895 -ScopeGadget\Attitude\data\plotCurve0\yScalePower=0 -ScopeGadget\Attitude\data\plotCurve0\yMinimum=0 -ScopeGadget\Attitude\data\plotCurve0\yMaximum=0 -ScopeGadget\Attitude\data\plotCurve1\uavObject=AttitudeActual -ScopeGadget\Attitude\data\plotCurve1\uavField=Yaw -ScopeGadget\Attitude\data\plotCurve1\color=4278233600 -ScopeGadget\Attitude\data\plotCurve1\yScalePower=0 -ScopeGadget\Attitude\data\plotCurve1\yMinimum=0 -ScopeGadget\Attitude\data\plotCurve1\yMaximum=0 -ScopeGadget\Attitude\data\plotCurve2\uavObject=AttitudeActual -ScopeGadget\Attitude\data\plotCurve2\uavField=Pitch -ScopeGadget\Attitude\data\plotCurve2\color=4294901760 -ScopeGadget\Attitude\data\plotCurve2\yScalePower=0 -ScopeGadget\Attitude\data\plotCurve2\yMinimum=0 -ScopeGadget\Attitude\data\plotCurve2\yMaximum=0 -ScopeGadget\Attitude\data\LoggingEnabled=false -ScopeGadget\Attitude\data\LoggingNewFileOnConnect=false -ScopeGadget\Attitude\data\LoggingPath= -ScopeGadget\Attitude\configInfo\version=0.0.0 -ScopeGadget\Attitude\configInfo\locked=false -ScopeGadget\Barometer\data\configurationStreamVersion=1000 -ScopeGadget\Barometer\data\plotType=1 -ScopeGadget\Barometer\data\dataSize=60 -ScopeGadget\Barometer\data\refreshInterval=1000 -ScopeGadget\Barometer\data\plotCurveCount=1 -ScopeGadget\Barometer\data\plotCurve0\uavObject=BaroAltitude -ScopeGadget\Barometer\data\plotCurve0\uavField=Pressure -ScopeGadget\Barometer\data\plotCurve0\color=4278190080 -ScopeGadget\Barometer\data\plotCurve0\yScalePower=0 -ScopeGadget\Barometer\data\plotCurve0\yMinimum=0 -ScopeGadget\Barometer\data\plotCurve0\yMaximum=0 -ScopeGadget\Barometer\data\LoggingEnabled=false -ScopeGadget\Barometer\data\LoggingNewFileOnConnect=false -ScopeGadget\Barometer\data\LoggingPath= -ScopeGadget\Barometer\configInfo\version=0.0.0 -ScopeGadget\Barometer\configInfo\locked=false -ScopeGadget\Inputs\data\configurationStreamVersion=1000 -ScopeGadget\Inputs\data\plotType=1 -ScopeGadget\Inputs\data\dataSize=40 -ScopeGadget\Inputs\data\refreshInterval=200 -ScopeGadget\Inputs\data\plotCurveCount=8 -ScopeGadget\Inputs\data\plotCurve0\uavObject=ManualControlCommand -ScopeGadget\Inputs\data\plotCurve0\uavField=Channel-1 -ScopeGadget\Inputs\data\plotCurve0\color=4278190207 -ScopeGadget\Inputs\data\plotCurve0\yScalePower=0 -ScopeGadget\Inputs\data\plotCurve0\yMinimum=0 -ScopeGadget\Inputs\data\plotCurve0\yMaximum=0 -ScopeGadget\Inputs\data\plotCurve1\uavObject=ManualControlCommand -ScopeGadget\Inputs\data\plotCurve1\uavField=Channel-4 -ScopeGadget\Inputs\data\plotCurve1\color=4294901760 -ScopeGadget\Inputs\data\plotCurve1\yScalePower=0 -ScopeGadget\Inputs\data\plotCurve1\yMinimum=0 -ScopeGadget\Inputs\data\plotCurve1\yMaximum=0 -ScopeGadget\Inputs\data\plotCurve2\uavObject=ManualControlCommand -ScopeGadget\Inputs\data\plotCurve2\uavField=Channel-5 -ScopeGadget\Inputs\data\plotCurve2\color=4294901760 -ScopeGadget\Inputs\data\plotCurve2\yScalePower=0 -ScopeGadget\Inputs\data\plotCurve2\yMinimum=0 -ScopeGadget\Inputs\data\plotCurve2\yMaximum=0 -ScopeGadget\Inputs\data\plotCurve3\uavObject=ManualControlCommand -ScopeGadget\Inputs\data\plotCurve3\uavField=Channel-6 -ScopeGadget\Inputs\data\plotCurve3\color=4294901760 -ScopeGadget\Inputs\data\plotCurve3\yScalePower=0 -ScopeGadget\Inputs\data\plotCurve3\yMinimum=0 -ScopeGadget\Inputs\data\plotCurve3\yMaximum=0 -ScopeGadget\Inputs\data\plotCurve4\uavObject=ManualControlCommand -ScopeGadget\Inputs\data\plotCurve4\uavField=Channel-7 -ScopeGadget\Inputs\data\plotCurve4\color=4294901760 -ScopeGadget\Inputs\data\plotCurve4\yScalePower=0 -ScopeGadget\Inputs\data\plotCurve4\yMinimum=0 -ScopeGadget\Inputs\data\plotCurve4\yMaximum=0 -ScopeGadget\Inputs\data\plotCurve5\uavObject=ManualControlCommand -ScopeGadget\Inputs\data\plotCurve5\uavField=Channel-2 -ScopeGadget\Inputs\data\plotCurve5\color=4283825920 -ScopeGadget\Inputs\data\plotCurve5\yScalePower=0 -ScopeGadget\Inputs\data\plotCurve5\yMinimum=0 -ScopeGadget\Inputs\data\plotCurve5\yMaximum=0 -ScopeGadget\Inputs\data\plotCurve6\uavObject=ManualControlCommand -ScopeGadget\Inputs\data\plotCurve6\uavField=Channel-3 -ScopeGadget\Inputs\data\plotCurve6\color=4294923520 -ScopeGadget\Inputs\data\plotCurve6\yScalePower=0 -ScopeGadget\Inputs\data\plotCurve6\yMinimum=0 -ScopeGadget\Inputs\data\plotCurve6\yMaximum=0 -ScopeGadget\Inputs\data\plotCurve7\uavObject=ManualControlCommand -ScopeGadget\Inputs\data\plotCurve7\uavField=Channel-0 -ScopeGadget\Inputs\data\plotCurve7\color=4294967040 -ScopeGadget\Inputs\data\plotCurve7\yScalePower=0 -ScopeGadget\Inputs\data\plotCurve7\yMinimum=0 -ScopeGadget\Inputs\data\plotCurve7\yMaximum=0 -ScopeGadget\Inputs\data\LoggingEnabled=false -ScopeGadget\Inputs\data\LoggingNewFileOnConnect=false -ScopeGadget\Inputs\data\LoggingPath= -ScopeGadget\Inputs\configInfo\version=0.0.0 -ScopeGadget\Inputs\configInfo\locked=false -ScopeGadget\Raw%20Accels\data\configurationStreamVersion=1000 -ScopeGadget\Raw%20Accels\data\plotType=1 -ScopeGadget\Raw%20Accels\data\dataSize=60 -ScopeGadget\Raw%20Accels\data\refreshInterval=500 -ScopeGadget\Raw%20Accels\data\plotCurveCount=3 -ScopeGadget\Raw%20Accels\data\plotCurve0\uavObject=AttitudeRaw -ScopeGadget\Raw%20Accels\data\plotCurve0\uavField=accels-X -ScopeGadget\Raw%20Accels\data\plotCurve0\color=4294901760 -ScopeGadget\Raw%20Accels\data\plotCurve0\yScalePower=0 -ScopeGadget\Raw%20Accels\data\plotCurve0\yMinimum=0 -ScopeGadget\Raw%20Accels\data\plotCurve0\yMaximum=0 -ScopeGadget\Raw%20Accels\data\plotCurve1\uavObject=AttitudeRaw -ScopeGadget\Raw%20Accels\data\plotCurve1\uavField=accels-Y -ScopeGadget\Raw%20Accels\data\plotCurve1\color=4283782655 -ScopeGadget\Raw%20Accels\data\plotCurve1\yScalePower=0 -ScopeGadget\Raw%20Accels\data\plotCurve1\yMinimum=0 -ScopeGadget\Raw%20Accels\data\plotCurve1\yMaximum=0 -ScopeGadget\Raw%20Accels\data\plotCurve2\uavObject=AttitudeRaw -ScopeGadget\Raw%20Accels\data\plotCurve2\uavField=accels-Z -ScopeGadget\Raw%20Accels\data\plotCurve2\color=4283804160 -ScopeGadget\Raw%20Accels\data\plotCurve2\yScalePower=0 -ScopeGadget\Raw%20Accels\data\plotCurve2\yMinimum=0 -ScopeGadget\Raw%20Accels\data\plotCurve2\yMaximum=0 -ScopeGadget\Raw%20Accels\data\LoggingEnabled=false -ScopeGadget\Raw%20Accels\data\LoggingNewFileOnConnect=false -ScopeGadget\Raw%20Accels\data\LoggingPath= -ScopeGadget\Raw%20Accels\configInfo\version=0.0.0 -ScopeGadget\Raw%20Accels\configInfo\locked=false -ScopeGadget\Raw%20Gyros\data\configurationStreamVersion=1000 -ScopeGadget\Raw%20Gyros\data\plotType=1 -ScopeGadget\Raw%20Gyros\data\dataSize=60 -ScopeGadget\Raw%20Gyros\data\refreshInterval=500 -ScopeGadget\Raw%20Gyros\data\plotCurveCount=3 -ScopeGadget\Raw%20Gyros\data\plotCurve0\uavObject=AttitudeRaw -ScopeGadget\Raw%20Gyros\data\plotCurve0\uavField=gyros-Z -ScopeGadget\Raw%20Gyros\data\plotCurve0\color=4283804160 -ScopeGadget\Raw%20Gyros\data\plotCurve0\yScalePower=0 -ScopeGadget\Raw%20Gyros\data\plotCurve0\yMinimum=0 -ScopeGadget\Raw%20Gyros\data\plotCurve0\yMaximum=0 -ScopeGadget\Raw%20Gyros\data\plotCurve1\uavObject=AttitudeRaw -ScopeGadget\Raw%20Gyros\data\plotCurve1\uavField=gyros-Y -ScopeGadget\Raw%20Gyros\data\plotCurve1\color=4283782655 -ScopeGadget\Raw%20Gyros\data\plotCurve1\yScalePower=0 -ScopeGadget\Raw%20Gyros\data\plotCurve1\yMinimum=0 -ScopeGadget\Raw%20Gyros\data\plotCurve1\yMaximum=0 -ScopeGadget\Raw%20Gyros\data\plotCurve2\uavObject=AttitudeRaw -ScopeGadget\Raw%20Gyros\data\plotCurve2\uavField=gyros-X -ScopeGadget\Raw%20Gyros\data\plotCurve2\color=4294901760 -ScopeGadget\Raw%20Gyros\data\plotCurve2\yScalePower=0 -ScopeGadget\Raw%20Gyros\data\plotCurve2\yMinimum=0 -ScopeGadget\Raw%20Gyros\data\plotCurve2\yMaximum=0 -ScopeGadget\Raw%20Gyros\data\LoggingEnabled=false -ScopeGadget\Raw%20Gyros\data\LoggingNewFileOnConnect=false -ScopeGadget\Raw%20Gyros\data\LoggingPath= -ScopeGadget\Raw%20Gyros\configInfo\version=0.0.0 -ScopeGadget\Raw%20Gyros\configInfo\locked=false -ScopeGadget\Raw%20magnetometers\data\configurationStreamVersion=1000 -ScopeGadget\Raw%20magnetometers\data\plotType=1 -ScopeGadget\Raw%20magnetometers\data\dataSize=60 -ScopeGadget\Raw%20magnetometers\data\refreshInterval=500 -ScopeGadget\Raw%20magnetometers\data\plotCurveCount=3 -ScopeGadget\Raw%20magnetometers\data\plotCurve0\uavObject=AttitudeRaw -ScopeGadget\Raw%20magnetometers\data\plotCurve0\uavField=magnetometers-X -ScopeGadget\Raw%20magnetometers\data\plotCurve0\color=4294901760 -ScopeGadget\Raw%20magnetometers\data\plotCurve0\yScalePower=0 -ScopeGadget\Raw%20magnetometers\data\plotCurve0\yMinimum=0 -ScopeGadget\Raw%20magnetometers\data\plotCurve0\yMaximum=0 -ScopeGadget\Raw%20magnetometers\data\plotCurve1\uavObject=AttitudeRaw -ScopeGadget\Raw%20magnetometers\data\plotCurve1\uavField=magnetometers-Y -ScopeGadget\Raw%20magnetometers\data\plotCurve1\color=4283782655 -ScopeGadget\Raw%20magnetometers\data\plotCurve1\yScalePower=0 -ScopeGadget\Raw%20magnetometers\data\plotCurve1\yMinimum=0 -ScopeGadget\Raw%20magnetometers\data\plotCurve1\yMaximum=0 -ScopeGadget\Raw%20magnetometers\data\plotCurve2\uavObject=AttitudeRaw -ScopeGadget\Raw%20magnetometers\data\plotCurve2\uavField=magnetometers-Z -ScopeGadget\Raw%20magnetometers\data\plotCurve2\color=4283804160 -ScopeGadget\Raw%20magnetometers\data\plotCurve2\yScalePower=0 -ScopeGadget\Raw%20magnetometers\data\plotCurve2\yMinimum=0 -ScopeGadget\Raw%20magnetometers\data\plotCurve2\yMaximum=0 -ScopeGadget\Raw%20magnetometers\data\LoggingEnabled=false -ScopeGadget\Raw%20magnetometers\data\LoggingNewFileOnConnect=false -ScopeGadget\Raw%20magnetometers\data\LoggingPath= -ScopeGadget\Raw%20magnetometers\configInfo\version=0.0.0 -ScopeGadget\Raw%20magnetometers\configInfo\locked=false -ScopeGadget\Stacks%20monitor\data\configurationStreamVersion=1000 -ScopeGadget\Stacks%20monitor\data\plotType=1 -ScopeGadget\Stacks%20monitor\data\dataSize=240 -ScopeGadget\Stacks%20monitor\data\refreshInterval=1000 -ScopeGadget\Stacks%20monitor\data\plotCurveCount=12 -ScopeGadget\Stacks%20monitor\data\plotCurve0\uavObject=TaskInfo -ScopeGadget\Stacks%20monitor\data\plotCurve0\uavField=StackRemaining-System -ScopeGadget\Stacks%20monitor\data\plotCurve0\color=4294945280 -ScopeGadget\Stacks%20monitor\data\plotCurve0\yScalePower=0 -ScopeGadget\Stacks%20monitor\data\plotCurve0\yMinimum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve0\yMaximum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve1\uavObject=TaskInfo -ScopeGadget\Stacks%20monitor\data\plotCurve1\uavField=StackRemaining-Actuator -ScopeGadget\Stacks%20monitor\data\plotCurve1\color=4294945280 -ScopeGadget\Stacks%20monitor\data\plotCurve1\yScalePower=0 -ScopeGadget\Stacks%20monitor\data\plotCurve1\yMinimum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve1\yMaximum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve2\uavObject=TaskInfo -ScopeGadget\Stacks%20monitor\data\plotCurve2\uavField=StackRemaining-TelemetryTx -ScopeGadget\Stacks%20monitor\data\plotCurve2\color=4294945280 -ScopeGadget\Stacks%20monitor\data\plotCurve2\yScalePower=0 -ScopeGadget\Stacks%20monitor\data\plotCurve2\yMinimum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve2\yMaximum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve3\uavObject=TaskInfo -ScopeGadget\Stacks%20monitor\data\plotCurve3\uavField=StackRemaining-TelemetryTxPri -ScopeGadget\Stacks%20monitor\data\plotCurve3\color=4294945280 -ScopeGadget\Stacks%20monitor\data\plotCurve3\yScalePower=0 -ScopeGadget\Stacks%20monitor\data\plotCurve3\yMinimum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve3\yMaximum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve4\uavObject=TaskInfo -ScopeGadget\Stacks%20monitor\data\plotCurve4\uavField=StackRemaining-TelemetryRx -ScopeGadget\Stacks%20monitor\data\plotCurve4\color=4294945280 -ScopeGadget\Stacks%20monitor\data\plotCurve4\yScalePower=0 -ScopeGadget\Stacks%20monitor\data\plotCurve4\yMinimum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve4\yMaximum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve5\uavObject=TaskInfo -ScopeGadget\Stacks%20monitor\data\plotCurve5\uavField=StackRemaining-GPS -ScopeGadget\Stacks%20monitor\data\plotCurve5\color=4294945280 -ScopeGadget\Stacks%20monitor\data\plotCurve5\yScalePower=0 -ScopeGadget\Stacks%20monitor\data\plotCurve5\yMinimum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve5\yMaximum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve6\uavObject=TaskInfo -ScopeGadget\Stacks%20monitor\data\plotCurve6\uavField=StackRemaining-ManualControl -ScopeGadget\Stacks%20monitor\data\plotCurve6\color=4294945280 -ScopeGadget\Stacks%20monitor\data\plotCurve6\yScalePower=0 -ScopeGadget\Stacks%20monitor\data\plotCurve6\yMinimum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve6\yMaximum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve7\uavObject=TaskInfo -ScopeGadget\Stacks%20monitor\data\plotCurve7\uavField=StackRemaining-Altitude -ScopeGadget\Stacks%20monitor\data\plotCurve7\color=4294945280 -ScopeGadget\Stacks%20monitor\data\plotCurve7\yScalePower=0 -ScopeGadget\Stacks%20monitor\data\plotCurve7\yMinimum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve7\yMaximum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve8\uavObject=TaskInfo -ScopeGadget\Stacks%20monitor\data\plotCurve8\uavField=StackRemaining-AHRSComms -ScopeGadget\Stacks%20monitor\data\plotCurve8\color=4294945280 -ScopeGadget\Stacks%20monitor\data\plotCurve8\yScalePower=0 -ScopeGadget\Stacks%20monitor\data\plotCurve8\yMinimum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve8\yMaximum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve9\uavObject=TaskInfo -ScopeGadget\Stacks%20monitor\data\plotCurve9\uavField=StackRemaining-Stabilization -ScopeGadget\Stacks%20monitor\data\plotCurve9\color=4294945280 -ScopeGadget\Stacks%20monitor\data\plotCurve9\yScalePower=0 -ScopeGadget\Stacks%20monitor\data\plotCurve9\yMinimum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve9\yMaximum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve10\uavObject=TaskInfo -ScopeGadget\Stacks%20monitor\data\plotCurve10\uavField=StackRemaining-Guidance -ScopeGadget\Stacks%20monitor\data\plotCurve10\color=4294945280 -ScopeGadget\Stacks%20monitor\data\plotCurve10\yScalePower=0 -ScopeGadget\Stacks%20monitor\data\plotCurve10\yMinimum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve10\yMaximum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve11\uavObject=TaskInfo -ScopeGadget\Stacks%20monitor\data\plotCurve11\uavField=StackRemaining-Watchdog -ScopeGadget\Stacks%20monitor\data\plotCurve11\color=4294945280 -ScopeGadget\Stacks%20monitor\data\plotCurve11\yScalePower=0 -ScopeGadget\Stacks%20monitor\data\plotCurve11\yMinimum=0 -ScopeGadget\Stacks%20monitor\data\plotCurve11\yMaximum=0 -ScopeGadget\Stacks%20monitor\data\LoggingEnabled=false -ScopeGadget\Stacks%20monitor\data\LoggingNewFileOnConnect=false -ScopeGadget\Stacks%20monitor\data\LoggingPath= -ScopeGadget\Stacks%20monitor\configInfo\version=0.0.0 -ScopeGadget\Stacks%20monitor\configInfo\locked=false -ScopeGadget\Telemetry%20quality\data\configurationStreamVersion=1000 -ScopeGadget\Telemetry%20quality\data\plotType=1 -ScopeGadget\Telemetry%20quality\data\dataSize=20 -ScopeGadget\Telemetry%20quality\data\refreshInterval=100 -ScopeGadget\Telemetry%20quality\data\plotCurveCount=3 -ScopeGadget\Telemetry%20quality\data\plotCurve0\uavObject=GCSTelemetryStats -ScopeGadget\Telemetry%20quality\data\plotCurve0\uavField=TxFailures -ScopeGadget\Telemetry%20quality\data\plotCurve0\color=4289374847 -ScopeGadget\Telemetry%20quality\data\plotCurve0\yScalePower=0 -ScopeGadget\Telemetry%20quality\data\plotCurve0\yMinimum=0 -ScopeGadget\Telemetry%20quality\data\plotCurve0\yMaximum=0 -ScopeGadget\Telemetry%20quality\data\plotCurve1\uavObject=GCSTelemetryStats -ScopeGadget\Telemetry%20quality\data\plotCurve1\uavField=RxFailures -ScopeGadget\Telemetry%20quality\data\plotCurve1\color=4283782655 -ScopeGadget\Telemetry%20quality\data\plotCurve1\yScalePower=0 -ScopeGadget\Telemetry%20quality\data\plotCurve1\yMinimum=0 -ScopeGadget\Telemetry%20quality\data\plotCurve1\yMaximum=0 -ScopeGadget\Telemetry%20quality\data\plotCurve2\uavObject=GCSTelemetryStats -ScopeGadget\Telemetry%20quality\data\plotCurve2\uavField=TxRetries -ScopeGadget\Telemetry%20quality\data\plotCurve2\color=4294901760 -ScopeGadget\Telemetry%20quality\data\plotCurve2\yScalePower=0 -ScopeGadget\Telemetry%20quality\data\plotCurve2\yMinimum=0 -ScopeGadget\Telemetry%20quality\data\plotCurve2\yMaximum=0 -ScopeGadget\Telemetry%20quality\data\LoggingEnabled=false -ScopeGadget\Telemetry%20quality\data\LoggingNewFileOnConnect=false -ScopeGadget\Telemetry%20quality\data\LoggingPath= -ScopeGadget\Telemetry%20quality\configInfo\version=0.0.0 -ScopeGadget\Telemetry%20quality\configInfo\locked=false -ScopeGadget\Uptimes\data\configurationStreamVersion=1000 -ScopeGadget\Uptimes\data\plotType=1 -ScopeGadget\Uptimes\data\dataSize=240 -ScopeGadget\Uptimes\data\refreshInterval=800 -ScopeGadget\Uptimes\data\plotCurveCount=2 -ScopeGadget\Uptimes\data\plotCurve0\uavObject=AhrsStatus -ScopeGadget\Uptimes\data\plotCurve0\uavField=RunningTime -ScopeGadget\Uptimes\data\plotCurve0\color=4289374847 -ScopeGadget\Uptimes\data\plotCurve0\yScalePower=0 -ScopeGadget\Uptimes\data\plotCurve0\yMinimum=0 -ScopeGadget\Uptimes\data\plotCurve0\yMaximum=0 -ScopeGadget\Uptimes\data\plotCurve1\uavObject=SystemStats -ScopeGadget\Uptimes\data\plotCurve1\uavField=FlightTime -ScopeGadget\Uptimes\data\plotCurve1\color=4294945407 -ScopeGadget\Uptimes\data\plotCurve1\yScalePower=0 -ScopeGadget\Uptimes\data\plotCurve1\yMinimum=0 -ScopeGadget\Uptimes\data\plotCurve1\yMaximum=0 -ScopeGadget\Uptimes\data\LoggingEnabled=false -ScopeGadget\Uptimes\data\LoggingNewFileOnConnect=false -ScopeGadget\Uptimes\data\LoggingPath= -ScopeGadget\Uptimes\configInfo\version=0.0.0 -ScopeGadget\Uptimes\configInfo\locked=false -SystemHealthGadget\default\data\diagram=%%DATAPATH%%diagrams/default/system-health.svg -SystemHealthGadget\default\configInfo\version=0.0.0 -SystemHealthGadget\default\configInfo\locked=false -UAVObjectBrowser\default\data\recentlyUpdatedColor=@Variant(\0\0\0\x43\x1\xff\xff\xff\xffyyWW\0\0) -UAVObjectBrowser\default\data\manuallyChangedColor=@Variant(\0\0\0\x43\x1\xff\xff[[\xaa\xaaVV\0\0) -UAVObjectBrowser\default\data\recentlyUpdatedTimeout=500 -UAVObjectBrowser\default\configInfo\version=0.0.0 -UAVObjectBrowser\default\configInfo\locked=false -Uploader\default\data\defaultSpeed=14 -Uploader\default\data\defaultDataBits=3 -Uploader\default\data\defaultFlow=0 -Uploader\default\data\defaultParity=0 -Uploader\default\data\defaultStopBits=0 -Uploader\default\data\defaultPort=/dev/ttyS0 -Uploader\default\configInfo\version=0.0.0 -Uploader\default\configInfo\locked=false - -[Plugins] -SoundNotifyPlugin\data\Current\1\SoundCollectionPath=%%DATAPATH%%sounds -SoundNotifyPlugin\data\Current\1\CurrentLanguage=default -SoundNotifyPlugin\data\Current\1\ObjectField=Channel -SoundNotifyPlugin\data\Current\1\DataObject=ActuatorCommand -SoundNotifyPlugin\data\Current\1\Value=Equal to -SoundNotifyPlugin\data\Current\1\ValueSpinBox=0 -SoundNotifyPlugin\data\Current\1\Sound1= -SoundNotifyPlugin\data\Current\1\Sound2= -SoundNotifyPlugin\data\Current\1\Sound3= -SoundNotifyPlugin\data\Current\1\SayOrder=Never -SoundNotifyPlugin\data\Current\1\Repeat= -SoundNotifyPlugin\data\Current\1\ExpireTimeout=0 -SoundNotifyPlugin\data\Current\size=1 -SoundNotifyPlugin\data\listNotifies\size=0 -SoundNotifyPlugin\data\EnableSound=false -SoundNotifyPlugin\configInfo\version=1.0.0 -SoundNotifyPlugin\configInfo\locked=false - -[IPconnection] -Current\1\HostName= -Current\1\Port=1 -Current\1\UseTCP=0 -Current\size=1 diff --git a/ground/openpilotgcs/src/plugins/coreplugin/OpenPilotGCS.xml b/ground/openpilotgcs/src/plugins/coreplugin/OpenPilotGCS.xml new file mode 100644 index 000000000..9847730e8 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/coreplugin/OpenPilotGCS.xml @@ -0,0 +1,2887 @@ + + + en_AU + true + + + 0 + + + #666666 + false + true + + + + + false + 1.0.0 + + + + + + + 0 + + + + + + + + + 0 + + 1 + + false + + 0 + + + + + + + + + false + 0.0.0 + + + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/default/attitude.svg + foreground + needle + needle + needle3 + Ubuntu,11,-1,5,50,0,0,0,0,0 + AttitudeActual + -1 + 360 + 0 + Rotate + Roll + AttitudeActual + 75 + 20 + 0 + Vertical + Pitch + AttitudeActual + -1 + 360 + 0 + Rotate + Roll + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/default/altimeter.svg + foreground + needle + needle2 + needle3 + Ubuntu,11,-1,5,50,0,0,0,0,0 + BaroAltitude + 1 + 10 + 0 + Rotate + Altitude + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/default/barometer.svg + + needle + + + Ubuntu,11,-1,5,50,0,0,0,0,0 + BaroAltitude + 10 + 1120 + 1000 + Rotate + Pressure + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/default/vsi.svg + + needle + + + Ubuntu,11,-1,5,50,0,0,0,0,0 + VelocityActual + 0.01 + 12 + -12 + Rotate + Down + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/default/compass.svg + foreground + needle + + + Ubuntu,11,-1,5,50,0,0,0,0,0 + AttitudeActual + -1 + 360 + 0 + Rotate + Yaw + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/deluxe/attitude.svg + foreground + needle + needle + needle3 + Ubuntu,11,-1,5,50,0,0,0,0,0 + AttitudeActual + -1 + 360 + 0 + Rotate + Roll + AttitudeActual + 75 + 20 + 0 + Vertical + Pitch + AttitudeActual + -1 + 360 + 0 + Rotate + Roll + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/deluxe/altimeter.svg + foreground + needle + needle2 + needle3 + Ubuntu,11,-1,5,50,0,0,0,0,0 + BaroAltitude + 1 + 10 + 0 + Rotate + Altitude + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/deluxe/barometer.svg + foreground + needle + + + Ubuntu,11,-1,5,50,0,0,0,0,0 + BaroAltitude + 10 + 1120 + 1000 + Rotate + Pressure + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/deluxe/vsi.svg + foreground + needle + + + Ubuntu,11,-1,5,50,0,0,0,0,0 + VelocityActual + 0.01 + 11.2 + -11.2 + Rotate + Down + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/deluxe/compass.svg + foreground + needle + + + Ubuntu,11,-1,5,50,0,0,0,0,0 + AttitudeActual + -1 + 360 + 0 + Rotate + Yaw + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/deluxe/speed.svg + foreground + needle + + + Ubuntu,11,-1,5,50,0,0,0,0,0 + GPSPosition + 3.6 + 120 + 0 + Rotate + Groundspeed + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/deluxe/thermometer.svg + foreground + needle + needle2 + needle3 + Ubuntu,11,-1,5,50,0,0,0,0,0 + BaroAltitude + 1 + 120 + 0 + Rotate + Temperature + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + /home/lafargue/OP/OpenPilot/trunk/artwork/Dials/deluxe/turncoordinator.svg + foreground + needle + needle2 + needle2 + Ubuntu,11,-1,5,50,0,0,0,0,0 + AttitudeActual + -1 + 360 + 0 + Rotate + Roll + AttitudeRaw + 1 + 20 + -20 + Horizontal + accels-X + AttitudeRaw + -1 + 360 + 0 + Rotate + accels-X + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/default/speed.svg + + needle + + + Ubuntu,11,-1,5,50,0,0,0,0,0 + GPSPosition + 3.6 + 120 + 0 + Rotate + Groundspeed + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/hi-contrast/attitude.svg + foreground + needle + needle + needle3 + Ubuntu,11,-1,5,50,0,0,0,0,0 + AttitudeActual + -1 + 360 + 0 + Rotate + Roll + AttitudeActual + 75 + 20 + 0 + Vertical + Pitch + AttitudeActual + -1 + 360 + 0 + Rotate + Roll + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/hi-contrast/altimeter.svg + foreground + needle + needle2 + needle3 + Ubuntu,11,-1,5,50,0,0,0,0,0 + BaroAltitude + 1 + 10 + 0 + Rotate + Altitude + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/hi-contrast/barometer.svg + + needle + + + Ubuntu,11,-1,5,50,0,0,0,0,0 + BaroAltitude + 10 + 1120 + 1000 + Rotate + Pressure + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/hi-contrast/vsi.svg + + needle + + + Ubuntu,11,-1,5,50,0,0,0,0,0 + VelocityActual + 0.01 + 12 + -12 + Rotate + Down + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/hi-contrast/compass.svg + foreground + needle + + + Ubuntu,11,-1,5,50,0,0,0,0,0 + AttitudeActual + -1 + 360 + 0 + Rotate + Yaw + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/hi-contrast/speed.svg + + needle + + + Ubuntu,11,-1,5,50,0,0,0,0,0 + GPSPosition + 3.6 + 120 + 0 + Rotate + Groundspeed + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/hi-contrast/thermometer.svg + + needle + needle2 + needle3 + Ubuntu,11,-1,5,50,0,0,0,0,0 + BaroAltitude + 1 + 120 + 0 + Rotate + Temperature + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/default/thermometer.svg + + needle + needle2 + needle3 + Ubuntu,11,-1,5,50,0,0,0,0,0 + ManualControlCommand + 1 + 2000 + 1000 + Rotate + Channel-3 + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + false + 0.0.0 + + + false + background + %%DATAPATH%%dials/default/thermometer.svg + + needle + needle2 + needle3 + Ubuntu,11,-1,5,50,0,0,0,0,0 + BaroAltitude + 1 + 120 + 0 + Rotate + Temperature + BaroAltitude + 1 + 100 + 0 + Rotate + Altitude + BaroAltitude + 1 + 1000 + 0 + Rotate + Altitude + false + + + + + + + false + 0.0.0 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0.1 + 3 + 0 + 0.1 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + false + false + true + false + false + false + false + false + 2 + 1 + 0 + 2 + 3 + + + + + + + false + 0.0.0 + + + Telemetry + 3 + 0 + 0 + Serial port 0 + 11 + 0 + + + + + false + 0.0.0 + + + Serial + 3 + 0 + 0 + Serial port 0 + 17 + 0 + + + + + + + false + 0.0.0 + + + \usr\games\fgfs + \usr\share\games\FlightGear + 127.0.0.1 + 9009 + + + false + 9010 + 127.0.0.1 + FG + true + + + + + false + 0.0.0 + + + \home\lafargue\X-Plane 9\X-Plane-i686 + \usr\share\games\FlightGear + 127.0.0.3 + 6756 + + + false + 49000 + 127.0.0.1 + X-Plane + false + + + + + + + false + 1.0.1 + + + gcs.ini + + + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-vertical.svg + 0 + 1 + Andale Mono,12,-1,5,75,0,0,0,0,0 + 50 + 0 + 100 + 0 + 100 + 80 + AhrsStatus + CPULoad + false + 80 + 50 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-horizontal.svg + 2 + 1 + Andale Mono,8,-1,5,50,0,0,0,0,0 + -9 + -10 + 11 + -11 + 11 + -11 + AttitudeRaw + accels-X + false + -5 + -11 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-horizontal.svg + 2 + 1 + Andale Mono,6,-1,5,50,0,0,0,0,0 + -9 + -10 + 11 + -11 + 11 + -11 + AttitudeRaw + accels-Y + false + -5 + -11 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-horizontal.svg + 2 + 1 + Andale Mono,8,-1,5,50,0,0,0,0,0 + -9 + -10 + 11 + -11 + 11 + -11 + AttitudeRaw + accels-Z + false + -5 + -11 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/arm-status.svg + 0 + 1 + ,12,-1,5,50,0,0,0,0,0 + 100 + 66 + 100 + 0 + 33 + 0 + FlightStatus + Armed + false + 66 + 33 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/textonly.svg + 0 + 0.001 + ,12,-1,5,50,0,0,0,0,0 + 100 + 66 + 100 + 0 + 33 + 0 + SystemStats + FlightTime + false + 66 + 33 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/flightmode-status.svg + 0 + 1 + ,12,-1,5,50,0,0,0,0,0 + 100 + 66 + 100 + 0 + 33 + 0 + FlightStatus + FlightMode + false + 66 + 33 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/gps-signal.svg + 0 + 1 + ,12,-1,5,50,0,0,0,0,0 + 0 + 0 + 12 + 0 + 0 + 0 + GPSPosition + Satellites + false + 0 + 0 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/gps-status.svg + 0 + 1 + ,12,-1,5,50,0,0,0,0,0 + 100 + 66 + 100 + 0 + 33 + 0 + GPSPosition + Status + false + 66 + 33 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-vertical.svg + 0 + 1 + Andale Mono,12,-1,5,75,0,0,0,0,0 + 50 + 0 + 100 + 0 + 100 + 80 + SystemStats + CPULoad + false + 80 + 50 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-vertical.svg + 2 + 1 + Andale Mono,12,-1,5,75,0,0,0,0,0 + 0.5 + -0.5 + 1 + -1 + 1 + -1 + ActuatorDesired + Pitch + false + 0.8 + -0.8 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-vertical.svg + 2 + 1 + Andale Mono,12,-1,5,75,0,0,0,0,0 + 0.5 + -0.5 + 1 + -1 + 1 + -1 + ManualControlCommand + Pitch + false + 0.8 + -0.8 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-vertical.svg + 2 + 1 + Andale Mono,12,-1,5,75,0,0,0,0,0 + 0.8 + 0.3 + 90 + -90 + 1 + 0 + AttitudeActual + Pitch + false + 0.9 + 0.1 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-vertical.svg + 2 + 1 + Andale Mono,12,-1,5,75,0,0,0,0,0 + 0.5 + -0.5 + 1 + -1 + 1 + -1 + ActuatorDesired + Roll + false + 0.8 + -0.8 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-vertical.svg + 2 + 1 + Andale Mono,12,-1,5,75,0,0,0,0,0 + 0.5 + -0.5 + 1 + -1 + 1 + -1 + ManualControlCommand + Roll + false + 0.8 + -0.8 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-horizontal.svg + 0 + 1 + Andale Mono,12,-1,5,75,0,0,0,0,0 + 650 + 0 + 1200 + 0 + 1200 + 900 + GCSTelemetryStats + RxDataRate + false + 900 + 650 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-horizontal.svg + 0 + 1 + Andale Mono,12,-1,5,75,0,0,0,0,0 + 650 + 0 + 1200 + 0 + 1200 + 900 + GCSTelemetryStats + TxDataRate + false + 900 + 650 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-vertical.svg + 2 + 1 + Andale Mono,12,-1,5,75,0,0,0,0,0 + 0.5 + 0 + 1 + 0 + 1 + 0.75 + ManualControlCommand + Throttle + false + 0.75 + 0.5 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-vertical.svg + 2 + 1 + Andale Mono,12,-1,5,75,0,0,0,0,0 + 0.5 + -0.5 + 1 + -1 + 1 + -1 + ActuatorDesired + Yaw + false + 0.8 + -0.8 + + + + + false + 0.0.0 + + + %%DATAPATH%%dials/default/lineardial-vertical.svg + 2 + 1 + Andale Mono,12,-1,5,75,0,0,0,0,0 + 0.5 + -0.5 + 1 + -1 + 1 + -1 + ManualControlCommand + Yaw + false + 0.8 + -0.8 + + + + + + + false + 0.0.0 + + + %%DATAPATH%%models/multi/aeroquad/aeroquad_+.3ds + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/multi/easy_quad/easy_quad_X.3ds + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/planes/Easystar/easystar.3ds + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/planes/firecracker/firecracker.3ds + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/planes/funjet/funjet.3ds + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/multi/gaui_330x/gaui_330x.3ds + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/helis/t-rex/t-rex_450_xl.3ds + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/multi/mikrokopter/MK_Hexa.3ds + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/multi/joes_cnc/J14-Q_+.3DS + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/multi/joes_cnc/J14-Q_X.3DS + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/multi/joes_cnc/J14-QT_+.3DS + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/multi/joes_cnc/J14-QT_X.3DS + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/multi/mikrokopter/MK_L4-ME.3ds + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/multi/scorpion_tricopter/scorpion_tricopter.3ds + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/multi/test_quad/test_quad_+.3ds + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/multi/test_quad/test_quad_X.3ds + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + false + 0.0.0 + + + %%DATAPATH%%models/boards/CopterControl/CopterControl.3ds + %%DATAPATH%%models/backgrounds/default_background.png + false + + + + + + + false + 0.0.0 + + + ServerAndCache + %%STOREPATH%%mapscache/ + 0 + 0 + 2 + GoogleSatellite + 2000 + false + mapquad.png + true + false + + + + + false + 0.0.0 + + + CacheOnly + %%STOREPATH%%mapscache/ + 0 + 0 + 2 + GoogleMap + 2000 + false + airplanepip.png + true + false + + + + + false + 0.0.0 + + + ServerAndCache + %%STOREPATH%%mapscache/ + 0 + 0 + 2 + GoogleMap + 2000 + false + mapquad.png + true + false + + + + + + + false + 0.0.0 + + + false + %%DATAPATH%%pfd/default/pfd.svg + false + false + + + + + false + 0.0.0 + + + true + %%DATAPATH%%pfd/default/pfd.svg + false + false + + + + + + + false + 0.0.0 + + + + + + + false + 0.0.0 + + + false + false + + 1000 + 60 + + 4294901760 + accels-X + AttitudeRaw + 0 + 0 + 0 + + + 4283782655 + accels-Y + AttitudeRaw + 0 + 0 + 0 + + + 4283804160 + accels-Z + AttitudeRaw + 0 + 0 + 0 + + 3 + 1 + 100 + + + + + false + 0.0.0 + + + false + false + + 1000 + 20 + + 4294901760 + Channel-4 + ActuatorCommand + 0 + 0 + 0 + + + 4294901760 + Channel-5 + ActuatorCommand + 0 + 0 + 0 + + + 4289374847 + Channel-6 + ActuatorCommand + 0 + 0 + 0 + + + 4289374847 + Channel-7 + ActuatorCommand + 0 + 0 + 0 + + 4 + 1 + 100 + + + + + false + 0.0.0 + + + false + false + + 1000 + 60 + + 4283760895 + Roll + AttitudeActual + 0 + 0 + 0 + + + 4278233600 + Yaw + AttitudeActual + 0 + 0 + 0 + + + 4294901760 + Pitch + AttitudeActual + 0 + 0 + 0 + + 3 + 1 + 100 + + + + + false + 0.0.0 + + + false + false + + 1000 + 60 + + 4278190080 + Pressure + BaroAltitude + 0 + 0 + 0 + + 1 + 1 + 1000 + + + + + false + 0.0.0 + + + false + false + + 1000 + 40 + + 4278190207 + Channel-1 + ManualControlCommand + 0 + 0 + 0 + + + 4294901760 + Channel-4 + ManualControlCommand + 0 + 0 + 0 + + + 4294901760 + Channel-5 + ManualControlCommand + 0 + 0 + 0 + + + 4294901760 + Channel-6 + ManualControlCommand + 0 + 0 + 0 + + + 4294901760 + Channel-7 + ManualControlCommand + 0 + 0 + 0 + + + 4283825920 + Channel-2 + ManualControlCommand + 0 + 0 + 0 + + + 4294923520 + Channel-3 + ManualControlCommand + 0 + 0 + 0 + + + 4294967040 + Channel-0 + ManualControlCommand + 0 + 0 + 0 + + 8 + 1 + 200 + + + + + false + 0.0.0 + + + false + false + + 1000 + 60 + + 4294901760 + accels-X + AttitudeRaw + 0 + 0 + 0 + + + 4283782655 + accels-Y + AttitudeRaw + 0 + 0 + 0 + + + 4283804160 + accels-Z + AttitudeRaw + 0 + 0 + 0 + + 3 + 1 + 500 + + + + + false + 0.0.0 + + + false + false + + 1000 + 60 + + 4283804160 + gyros-Z + AttitudeRaw + 0 + 0 + 0 + + + 4283782655 + gyros-Y + AttitudeRaw + 0 + 0 + 0 + + + 4294901760 + gyros-X + AttitudeRaw + 0 + 0 + 0 + + 3 + 1 + 500 + + + + + false + 0.0.0 + + + false + false + + 1000 + 60 + + 4294901760 + magnetometers-X + AttitudeRaw + 0 + 0 + 0 + + + 4283782655 + magnetometers-Y + AttitudeRaw + 0 + 0 + 0 + + + 4283804160 + magnetometers-Z + AttitudeRaw + 0 + 0 + 0 + + 3 + 1 + 500 + + + + + false + 0.0.0 + + + false + false + + 1000 + 240 + + 4294945280 + StackRemaining-System + TaskInfo + 0 + 0 + 0 + + + 4294945280 + StackRemaining-Actuator + TaskInfo + 0 + 0 + 0 + + + 4294945280 + StackRemaining-Guidance + TaskInfo + 0 + 0 + 0 + + + 4294945280 + StackRemaining-Watchdog + TaskInfo + 0 + 0 + 0 + + + 4294945280 + StackRemaining-TelemetryTx + TaskInfo + 0 + 0 + 0 + + + 4294945280 + StackRemaining-TelemetryTxPri + TaskInfo + 0 + 0 + 0 + + + 4294945280 + StackRemaining-TelemetryRx + TaskInfo + 0 + 0 + 0 + + + 4294945280 + StackRemaining-GPS + TaskInfo + 0 + 0 + 0 + + + 4294945280 + StackRemaining-ManualControl + TaskInfo + 0 + 0 + 0 + + + 4294945280 + StackRemaining-Altitude + TaskInfo + 0 + 0 + 0 + + + 4294945280 + StackRemaining-AHRSComms + TaskInfo + 0 + 0 + 0 + + + 4294945280 + StackRemaining-Stabilization + TaskInfo + 0 + 0 + 0 + + 12 + 1 + 1000 + + + + + false + 0.0.0 + + + false + false + + 1000 + 20 + + 4289374847 + TxFailures + GCSTelemetryStats + 0 + 0 + 0 + + + 4283782655 + RxFailures + GCSTelemetryStats + 0 + 0 + 0 + + + 4294901760 + TxRetries + GCSTelemetryStats + 0 + 0 + 0 + + 3 + 1 + 100 + + + + + false + 0.0.0 + + + false + false + + 1000 + 240 + + 4289374847 + RunningTime + AhrsStatus + 0 + 0 + 0 + + + 4294945407 + FlightTime + SystemStats + 0 + 0 + 0 + + 2 + 1 + 800 + + + + + + + false + 0.0.0 + + + %%DATAPATH%%diagrams/default/system-health.svg + + + + + + + false + 0.0.0 + + + #5baa56 + #ff7957 + 500 + + + + + + + false + 0.0.0 + + + 3 + 0 + 0 + /dev/ttyS0 + 14 + 0 + + + + + false + 1.2.0 + + + + + false + + + + + + + LineardialGadget + + Flight Time + + uavGadget + + + LineardialGadget + + GPS Sats + + uavGadget + + 2 + @Variant(AAAACQAAAAA=) + splitter + + + + LineardialGadget + + Flight mode + + uavGadget + + + LineardialGadget + + Arm Status + + uavGadget + + 2 + @Variant(AAAACQAAAAA=) + splitter + + 2 + @Variant(AAAACQAAAAIAAAACAAAA1wAAAAIAAADt) + splitter + + + PFDGadget + + raw + + uavGadget + + 1 + @Variant(AAAACQAAAAIAAAACAAAAkAAAAAIAAAJg) + splitter + + + + ModelViewGadget + + Test Quad X + + uavGadget + + + + + SystemHealthGadget + + default + + uavGadget + + + + LineardialGadget + + Mainboard CPU + + uavGadget + + + LineardialGadget + + AHRS CPU + + uavGadget + + 1 + @Variant(AAAACQAAAAIAAAACAAAAQAAAAAIAAABA) + splitter + + 1 + @Variant(AAAACQAAAAIAAAACAAABIwAAAAIAAACN) + splitter + + + + LineardialGadget + + Telemetry RX Rate Horizontal + + uavGadget + + + LineardialGadget + + Telemetry TX Rate Horizontal + + uavGadget + + 1 + @Variant(AAAACQAAAAA=) + splitter + + 2 + @Variant(AAAACQAAAAIAAAACAAABJQAAAAIAAABA) + splitter + + 1 + @Variant(AAAACQAAAAIAAAACAAABMAAAAAIAAAGx) + splitter + + 2 + @Variant(AAAACQAAAAIAAAACAAABxQAAAAIAAAFH) + splitter + + + + OPMapGadget + + Google Sat + + uavGadget + + + + + + + DialGadget + + Deluxe Groundspeed kph + + uavGadget + + + DialGadget + + Deluxe Barometer + + uavGadget + + 2 + @Variant(AAAACQAAAAA=) + splitter + + + + DialGadget + + Deluxe Attitude + + uavGadget + + + DialGadget + + Deluxe Compass + + uavGadget + + 2 + @Variant(AAAACQAAAAA=) + splitter + + 1 + @Variant(AAAACQAAAAIAAAACAAAAgwAAAAIAAACK) + splitter + + + + DialGadget + + Deluxe Baro Altimeter + + uavGadget + + + DialGadget + + Deluxe Climbrate + + uavGadget + + 2 + @Variant(AAAACQAAAAA=) + splitter + + 1 + @Variant(AAAACQAAAAIAAAACAAABFQAAAAIAAACH) + splitter + + + + LineardialGadget + + Throttle + + uavGadget + + + + LineardialGadget + + Roll Desired + + uavGadget + + + + LineardialGadget + + Pitch Desired + + uavGadget + + + LineardialGadget + + Yaw Desired + + uavGadget + + 1 + @Variant(AAAACQAAAAIAAAACAAAAQAAAAAIAAAE3) + splitter + + 1 + @Variant(AAAACQAAAAIAAAACAAAAQAAAAAIAAAF4) + splitter + + 1 + @Variant(AAAACQAAAAIAAAACAAAAQAAAAAIAAAG5) + splitter + + 1 + @Variant(AAAACQAAAAIAAAACAAABuQAAAAIAAAED) + splitter + + 2 + @Variant(AAAACQAAAAIAAAACAAAB7AAAAAIAAAEg) + splitter + + 1 + @Variant(AAAACQAAAAIAAAACAAAC4gAAAAIAAAK9) + splitter + + UAVGadgetManagerV1 + + + false + + + + ConfigGadget + + default + + uavGadget + + + + LineardialGadget + + Telemetry RX Rate Horizontal + + uavGadget + + + LineardialGadget + + Telemetry TX Rate Horizontal + + uavGadget + + 1 + @Variant(AAAACQAAAAA=) + splitter + + 2 + @Variant(AAAACQAAAAIAAAACAAACNQAAAAIAAABC) + splitter + + + + UAVObjectBrowser + + default + + uavGadget + + + GCSControlGadget + + MS Sidewinder + + uavGadget + + 2 + @Variant(AAAACQAAAAIAAAACAAABqgAAAAIAAAFi) + splitter + + 1 + @Variant(AAAACQAAAAIAAAACAAAC3gAAAAIAAAJ3) + splitter + + UAVGadgetManagerV1 + + + false + + + OPMapGadget + + default + + uavGadget + + + + ModelViewGadget + + Test Quad X + + uavGadget + + + + DialGadget + + Attitude + + uavGadget + + + DialGadget + + Compass + + uavGadget + + 1 + @Variant(AAAACQAAAAA=) + splitter + + 2 + @Variant(AAAACQAAAAIAAAACAAABiwAAAAIAAADs) + splitter + + 1 + @Variant(AAAACQAAAAIAAAACAAAD1AAAAAIAAAGB) + splitter + + UAVGadgetManagerV1 + + + false + + + + ScopeGadget + + Accel + + uavGadget + + + ScopeGadget + + Raw Gyros + + uavGadget + + 2 + @Variant(AAAACQAAAAA=) + splitter + + + + + ScopeGadget + + Attitude + + uavGadget + + + ScopeGadget + + Uptimes + + uavGadget + + 2 + @Variant(AAAACQAAAAIAAAACAAABhgAAAAIAAAEO) + splitter + + + LoggingGadget + uavGadget + + 2 + @Variant(AAAACQAAAAIAAAACAAAClQAAAAIAAAB3) + splitter + + 1 + @Variant(AAAACQAAAAIAAAACAAACjQAAAAIAAAKU) + splitter + + UAVGadgetManagerV1 + + + false + + + + HITL + + XPlane HITL + + uavGadget + + + + GCSControlGadget + + MS Sidewinder + + uavGadget + + + + + LineardialGadget + + Pitch Desired + + uavGadget + + + LineardialGadget + + PitchActual + + uavGadget + + 1 + @Variant(AAAACQAAAAA=) + splitter + + + LineardialGadget + + Pitch + + uavGadget + + 1 + @Variant(AAAACQAAAAIAAAACAAABFAAAAAIAAABA) + splitter + + 1 + @Variant(AAAACQAAAAIAAAACAAAB6AAAAAIAAADC) + splitter + + 2 + @Variant(AAAACQAAAAIAAAACAAABaQAAAAIAAAEO) + splitter + + + UAVObjectBrowser + + default + + uavGadget + + 1 + @Variant(AAAACQAAAAIAAAACAAADDAAAAAIAAAJJ) + splitter + + UAVGadgetManagerV1 + + + false + + + Uploader + + default + + uavGadget + + + + + SystemHealthGadget + + default + + uavGadget + + + PFDGadget + + raw + + uavGadget + + 1 + @Variant(AAAACQAAAAIAAAACAAABQgAAAAIAAAGM) + splitter + + + ScopeGadget + + Uptimes + + uavGadget + + 2 + @Variant(AAAACQAAAAIAAAACAAABEgAAAAIAAAH6) + splitter + + 1 + @Variant(AAAACQAAAAA=) + splitter + + UAVGadgetManagerV1 + + + @ByteArray(AAAA/wAAAAD9AAAAAAAABQAAAALCAAAABAAAAAQAAAABAAAACPwAAAAA) + + :/core/images/ah.png + :/core/images/openpilot_logo_64.png + :/core/images/config.png + :/core/images/world.png + :/core/images/scopes.png + :/core/images/joystick.png + :/core/images/cog.png + :/core/images/openpilot_logo_64.png + :/core/images/openpilot_logo_64.png + :/core/images/openpilot_logo_64.png + 6 + Flight data + Workspace10 + Configuration + Flight Planner + Scopes + HITL + Firmware + Workspace7 + Workspace8 + Workspace9 + + diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp index 2fb7778e7..f63c6e7da 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp @@ -32,14 +32,8 @@ #include #include -#include - -#include "fancytabwidget.h" -#include "fancyactionbar.h" -#include "mainwindow.h" #include "qextserialport/src/qextserialenumerator.h" #include "qextserialport/src/qextserialport.h" - #include #include #include @@ -48,22 +42,23 @@ namespace Core { -ConnectionManager::ConnectionManager(Internal::MainWindow *mainWindow, Internal::FancyTabWidget *modeStack) : +ConnectionManager::ConnectionManager(Internal::MainWindow *mainWindow, QTabWidget *modeStack) : QWidget(mainWindow), // Pip m_availableDevList(0), m_connectBtn(0), - m_ioDev(NULL) + m_ioDev(NULL), + m_mainWindow(mainWindow) { - Q_UNUSED(mainWindow); + // Q_UNUSED(mainWindow); - QVBoxLayout *top = new QVBoxLayout; +/* QVBoxLayout *top = new QVBoxLayout; top->setSpacing(0); - top->setMargin(0); + top->setMargin(0);*/ QHBoxLayout *layout = new QHBoxLayout; - layout->setSpacing(0); - layout->setContentsMargins(5,0,5,0); - layout->addWidget(new QLabel("Connections: ")); + layout->setSpacing(5); + layout->setContentsMargins(5,5,5,5); + layout->addWidget(new QLabel(tr("Connections:"))); m_availableDevList = new QComboBox; //m_availableDevList->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -72,17 +67,18 @@ ConnectionManager::ConnectionManager(Internal::MainWindow *mainWindow, Internal: m_availableDevList->setContextMenuPolicy(Qt::CustomContextMenu); layout->addWidget(m_availableDevList); - m_connectBtn = new QPushButton("Connect"); + m_connectBtn = new QPushButton(tr("Connect")); m_connectBtn->setEnabled(false); layout->addWidget(m_connectBtn); - Utils::StyledBar *bar = new Utils::StyledBar; +/* Utils::StyledBar *bar = new Utils::StyledBar; bar->setLayout(layout); - top->addWidget(bar); - setLayout(top); + top->addWidget(bar);*/ + setLayout(layout); - modeStack->insertCornerWidget(modeStack->cornerWidgetCount()-1, this); + // modeStack->insertCornerWidget(modeStack->cornerWidgetCount()-1, this); + modeStack->setCornerWidget(this, Qt::TopRightCorner); QObject::connect(m_connectBtn, SIGNAL(pressed()), this, SLOT(onConnectPressed())); } @@ -221,8 +217,9 @@ void ConnectionManager::aboutToRemoveObject(QObject *obj) void ConnectionManager::onConnectionDestroyed(QObject *obj) // Pip { - //onConnectionClosed(obj); - disconnectDevice(); + Q_UNUSED(obj) + //onConnectionClosed(obj); + disconnectDevice(); } /** @@ -344,7 +341,7 @@ void ConnectionManager::devChanged(IConnection *connection) //and add them back in the list QList availableDev = connection->availableDevices(); - foreach (IConnection::device dev, availableDev) + foreach (IConnection::device dev, availableDev) { QString cbName = connection->shortName() + ": " + dev.name; QString disp = connection->shortName() + " : " + dev.displayName; @@ -352,11 +349,27 @@ void ConnectionManager::devChanged(IConnection *connection) } //add all the list again to the combobox - foreach (devListItem d, m_devList) + foreach (devListItem d, m_devList) { m_availableDevList->addItem(d.displayName); m_availableDevList->setItemData(m_availableDevList->count()-1,(const QString)d.devName,Qt::ToolTipRole); + if(!m_ioDev && d.displayName.startsWith("USB")) + { + if(m_mainWindow->generalSettings()->autoConnect() || m_mainWindow->generalSettings()->autoSelect()) + m_availableDevList->setCurrentIndex(m_availableDevList->count()-1); + if(m_mainWindow->generalSettings()->autoConnect()) + connectDevice(); + } } + if(m_ioDev)//if a device is connected make it the one selected on the dropbox + { + for(int x=0;xcount();++x) + { + if(m_connectionDevice.devName==m_availableDevList->itemData(x,Qt::ToolTipRole).toString()) + m_availableDevList->setCurrentIndex(x); + } + } + //disable connection button if the liNameif (m_availableDevList->count() > 0) if (m_availableDevList->count() > 0) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h index 20da52ed4..beb809915 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h @@ -30,7 +30,8 @@ #define CONNECTIONMANAGER_H #include - +#include "mainwindow.h" +#include "generalsettings.h" #include #include #include @@ -39,6 +40,10 @@ #include "core_global.h" +QT_BEGIN_NAMESPACE +class QTabWidget; +QT_END_NAMESPACE + namespace Core { class IConnection; @@ -64,7 +69,7 @@ class CORE_EXPORT ConnectionManager : public QWidget Q_OBJECT public: - ConnectionManager(Internal::MainWindow *mainWindow, Internal::FancyTabWidget *modeStack); + ConnectionManager(Internal::MainWindow *mainWindow, QTabWidget *modeStack); virtual ~ConnectionManager(); void init(); @@ -108,6 +113,7 @@ protected: private: bool connectDevice(); + Internal::MainWindow *m_mainWindow; }; diff --git a/ground/openpilotgcs/src/plugins/coreplugin/core.qrc b/ground/openpilotgcs/src/plugins/coreplugin/core.qrc index 917018476..c1b0f8e36 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/core.qrc +++ b/ground/openpilotgcs/src/plugins/coreplugin/core.qrc @@ -50,7 +50,6 @@ images/optionsicon.png images/helpicon.png images/openpiloticon.png - OpenPilotGCS.ini CREDITS.html images/ah.png images/config.png @@ -60,5 +59,7 @@ images/scopes.png images/world.png images/cog.png + OpenPilotGCS.xml + images/helpicon.svg diff --git a/ground/openpilotgcs/src/plugins/coreplugin/coreimpl.cpp b/ground/openpilotgcs/src/plugins/coreplugin/coreimpl.cpp index f3e95a8cb..b45582628 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/coreimpl.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/coreimpl.cpp @@ -183,12 +183,13 @@ void CoreImpl::updateContext() void CoreImpl::openFiles(const QStringList &arguments) { + Q_UNUSED(arguments) //m_mainwindow->openFiles(arguments); } -void CoreImpl::readMainSettings(QSettings* qs) +void CoreImpl::readMainSettings(QSettings* qs, bool workspaceDiffOnly) { - m_mainwindow->readSettings(qs); + m_mainwindow->readSettings(qs, workspaceDiffOnly); } void CoreImpl::saveMainSettings(QSettings* qs) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/coreimpl.h b/ground/openpilotgcs/src/plugins/coreplugin/coreimpl.h index eaebdc3d0..cd0dfd928 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/coreimpl.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/coreimpl.h @@ -64,7 +64,7 @@ public: QSettings *settings(QSettings::Scope scope = QSettings::UserScope) const; SettingsDatabase *settingsDatabase() const; - void readMainSettings(QSettings* qs); + void readMainSettings(QSettings* qs, bool workspaceDiffOnly); void saveMainSettings(QSettings* qs); void readSettings(IConfigurablePlugin* plugin, QSettings* qs = 0 ); void saveSettings(IConfigurablePlugin* plugin, QSettings* qs = 0 ); diff --git a/ground/openpilotgcs/src/plugins/coreplugin/coreplugin.pri b/ground/openpilotgcs/src/plugins/coreplugin/coreplugin.pri index fc5fc7aae..26143cbc1 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/coreplugin.pri +++ b/ground/openpilotgcs/src/plugins/coreplugin/coreplugin.pri @@ -1,2 +1,2 @@ include(coreplugin_dependencies.pri) -LIBS *= -l$$qtLibraryTarget(Core) +LIBS *= -l$$qtLibraryName(Core) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/coreplugin.pro b/ground/openpilotgcs/src/plugins/coreplugin/coreplugin.pro index 8112438ed..8c73b00ef 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/coreplugin.pro +++ b/ground/openpilotgcs/src/plugins/coreplugin/coreplugin.pro @@ -24,10 +24,8 @@ SOURCES += mainwindow.cpp \ uniqueidmanager.cpp \ messagemanager.cpp \ messageoutputwindow.cpp \ - viewmanager.cpp \ versiondialog.cpp \ iuavgadget.cpp \ - uavgadgetmode.cpp \ uavgadgetmanager/uavgadgetmanager.cpp \ uavgadgetmanager/uavgadgetview.cpp \ uavgadgetmanager/splitterorview.cpp \ @@ -73,9 +71,7 @@ HEADERS += mainwindow.h \ uniqueidmanager.h \ messagemanager.h \ messageoutputwindow.h \ - viewmanager.h \ iuavgadget.h \ - uavgadgetmode.h \ iuavgadgetfactory.h \ uavgadgetmanager/uavgadgetmanager.h \ uavgadgetmanager/uavgadgetview.h \ @@ -141,3 +137,5 @@ unix:!macx { INSTALLS += images } OTHER_FILES += Core.pluginspec + +include(gcsversioninfo.pri) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/ioptionspage.h b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/ioptionspage.h index 1f470b97c..21a299508 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -32,6 +32,7 @@ #include #include +#include QT_BEGIN_NAMESPACE class QWidget; @@ -43,9 +44,14 @@ class CORE_EXPORT IOptionsPage : public QObject { Q_OBJECT public: - IOptionsPage(QObject *parent = 0) : QObject(parent) {} + IOptionsPage(QObject *parent = 0) : + QObject(parent), + m_icon(QIcon()) {} virtual ~IOptionsPage() {} + void setIcon(QIcon icon) { m_icon = icon; } + QIcon icon() { return m_icon; } + /* gadget options pages can leave these 4 functions as is, since they are decorated by UAVGadgetOptionsPageDecorator, all other options pages must override these */ @@ -57,6 +63,8 @@ public: virtual QWidget *createPage(QWidget *parent) = 0; virtual void apply() = 0; virtual void finish() = 0; +private: + QIcon m_icon; }; } // namespace Core diff --git a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp index e32f013f7..413cdb63b 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.cpp @@ -59,10 +59,13 @@ bool optionsPageLessThan(const IOptionsPage *p1, const IOptionsPage *p2) const UAVGadgetOptionsPageDecorator *gp2 = qobject_cast(p2); if (gp1 && (gp2 == NULL)) return false; + if (gp2 && (gp1 == NULL)) return true; + if (const int cc = QString::localeAwareCompare(p1->trCategory(), p2->trCategory())) return cc < 0; + return QString::localeAwareCompare(p1->trName(), p2->trName()) < 0; } @@ -97,6 +100,7 @@ SettingsDialog::SettingsDialog(QWidget *parent, const QString &categoryId, } if (m_windowWidth > 0 && m_windowHeight > 0) resize(m_windowWidth, m_windowHeight); + buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(apply())); @@ -105,10 +109,12 @@ SettingsDialog::SettingsDialog(QWidget *parent, const QString &categoryId, connect(this, SIGNAL(settingsDialogShown(Core::Internal::SettingsDialog*)), m_instanceManager, SLOT(settingsDialogShown(Core::Internal::SettingsDialog*))); connect(this, SIGNAL(settingsDialogRemoved()), m_instanceManager, SLOT(settingsDialogRemoved())); + connect(this, SIGNAL(categoryItemSelected()), this, SLOT(categoryItemSelectedShowChildInstead()), Qt::QueuedConnection); splitter->setCollapsible(0, false); splitter->setCollapsible(1, false); pageTree->header()->setVisible(false); +// pageTree->setIconSize(QSize(24, 24)); connect(pageTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(pageSelected())); @@ -129,44 +135,34 @@ SettingsDialog::SettingsDialog(QWidget *parent, const QString &categoryId, item->setText(0, page->trName()); item->setData(0, Qt::UserRole, qVariantFromValue(pageData)); - QStringList categoriesId = page->category().split(QLatin1Char('|')); - QStringList trCategories = page->trCategory().split(QLatin1Char('|')); - QString currentCategory = categoriesId.at(0); + QString trCategories = page->trCategory(); + QString currentCategory = page->category(); - QTreeWidgetItem *treeitem; + QTreeWidgetItem *categoryItem; if (!categories.contains(currentCategory)) { - if (!firstUavGadgetOptionsPageFound) - { + // Above the first gadget option we insert a separator + if (!firstUavGadgetOptionsPageFound) { UAVGadgetOptionsPageDecorator *pd = qobject_cast(page); - if (pd) - { + if (pd) { firstUavGadgetOptionsPageFound = true; QTreeWidgetItem *separator = new QTreeWidgetItem(pageTree); - separator->setFlags(item->flags() & ~Qt::ItemIsSelectable & ~Qt::ItemIsEnabled); + separator->setFlags(separator->flags() & ~Qt::ItemIsSelectable & ~Qt::ItemIsEnabled); separator->setText(0, QString(30, 0xB7)); } } - treeitem = new QTreeWidgetItem(pageTree); - treeitem->setText(0, trCategories.at(0)); - treeitem->setData(0, Qt::UserRole, qVariantFromValue(pageData)); - categories.insert(currentCategory, treeitem); + categoryItem = new QTreeWidgetItem(pageTree); + categoryItem->setIcon(0, page->icon()); + categoryItem->setText(0, trCategories); + categoryItem->setData(0, Qt::UserRole, qVariantFromValue(pageData)); + categories.insert(currentCategory, categoryItem); } - int catCount = 1; - while (catCount < categoriesId.count()) { - if (!categories.contains(currentCategory + QLatin1Char('|') + categoriesId.at(catCount))) { - treeitem = new QTreeWidgetItem(categories.value(currentCategory)); - currentCategory += QLatin1Char('|') + categoriesId.at(catCount); - treeitem->setText(0, trCategories.at(catCount)); - treeitem->setData(0, Qt::UserRole, qVariantFromValue(pageData)); - categories.insert(currentCategory, treeitem); - } else { - currentCategory += QLatin1Char('|') + categoriesId.at(catCount); - } - ++catCount; + QList *categoryItemList = m_categoryItemsMap.value(currentCategory); + if (!categoryItemList) { + categoryItemList = new QList(); + m_categoryItemsMap.insert(currentCategory, categoryItemList); } - - categories.value(currentCategory)->addChild(item); + categoryItemList->append(item); m_pages.append(page); stackedPages->addWidget(page->createPage(stackedPages)); @@ -179,6 +175,16 @@ SettingsDialog::SettingsDialog(QWidget *parent, const QString &categoryId, index++; } + foreach(QString category, m_categoryItemsMap.keys()) { + QList *categoryItemList = m_categoryItemsMap.value(category); + if (categoryItemList->size() > 1) { + foreach (QTreeWidgetItem *item, *categoryItemList) { + QTreeWidgetItem *categoryItem = categories.value(category); + categoryItem->addChild(item); + } + } + } + QList sizes; sizes << 150 << 300; splitter->setSizes(sizes); @@ -189,22 +195,49 @@ SettingsDialog::SettingsDialog(QWidget *parent, const QString &categoryId, SettingsDialog::~SettingsDialog() { + foreach(QString category, m_categoryItemsMap.keys()) { + QList *categoryItemList = m_categoryItemsMap.value(category); + delete categoryItemList; + } } void SettingsDialog::pageSelected() { QTreeWidgetItem *item = pageTree->currentItem(); + if (!item) + return; + PageData data = item->data(0, Qt::UserRole).value(); int index = data.index; m_currentCategory = data.category; m_currentPage = data.id; stackedPages->setCurrentIndex(index); + // If user selects a toplevel item, select the first child for them + // I.e. Top level items are not really selectable + if ((pageTree->indexOfTopLevelItem(item) >= 0) && (item->childCount() > 0)) { + emit categoryItemSelected(); + } +} + +void SettingsDialog::categoryItemSelectedShowChildInstead() +{ + QTreeWidgetItem *item = pageTree->currentItem(); + item->setExpanded(true); + pageTree->setCurrentItem(item->child(0), 0, QItemSelectionModel::SelectCurrent); } void SettingsDialog::deletePage() { QTreeWidgetItem *item = pageTree->currentItem(); - item->parent()->removeChild(item); + PageData data = item->data(0, Qt::UserRole).value(); + QString category = data.category; + QList *categoryItemList = m_categoryItemsMap.value(category); + QTreeWidgetItem *parentItem = item->parent(); + parentItem->removeChild(item); + categoryItemList->removeOne(item); + if (parentItem->childCount() == 1) { + parentItem->removeChild(parentItem->child(0)); + } pageSelected(); } @@ -227,11 +260,20 @@ void SettingsDialog::insertPage(IOptionsPage* page) if (!categoryItem) return; + // If this category has no child right now + // we need to add the "default child" + QList *categoryItemList = m_categoryItemsMap.value(page->category()); + if (categoryItem->childCount() == 0) { + QTreeWidgetItem *defaultItem = categoryItemList->at(0); + categoryItem->addChild(defaultItem); + } + QTreeWidgetItem *item = new QTreeWidgetItem; item->setText(0, page->trName()); item->setData(0, Qt::UserRole, qVariantFromValue(pageData)); categoryItem->addChild(item); + categoryItemList->append(item); m_pages.append(page); stackedPages->addWidget(page->createPage(stackedPages)); @@ -256,7 +298,7 @@ void SettingsDialog::accept() { m_applied = true; foreach (IOptionsPage *page, m_pages) { - page->apply(); + page->apply(); page->finish(); } done(QDialog::Accepted); @@ -266,14 +308,15 @@ void SettingsDialog::reject() { foreach (IOptionsPage *page, m_pages) page->finish(); + done(QDialog::Rejected); } void SettingsDialog::apply() { - foreach (IOptionsPage *page, m_pages) { - page->apply(); - } + foreach (IOptionsPage *page, m_pages) + page->apply(); + m_applied = true; } diff --git a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.h b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.h index 4a5f161f8..3000084a2 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/dialogs/settingsdialog.h @@ -62,6 +62,7 @@ public: signals: void settingsDialogShown(Core::Internal::SettingsDialog*); void settingsDialogRemoved(); + void categoryItemSelected(); public slots: void done(int); @@ -71,9 +72,13 @@ private slots: void accept(); void reject(); void apply(); + void categoryItemSelectedShowChildInstead(); + private: + QList m_pages; + QMap *> m_categoryItemsMap; UAVGadgetInstanceManager *m_instanceManager; bool m_applied; QString m_currentCategory; diff --git a/ground/openpilotgcs/src/plugins/coreplugin/gcsversioninfo.pri b/ground/openpilotgcs/src/plugins/coreplugin/gcsversioninfo.pri new file mode 100644 index 000000000..559dc3528 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/coreplugin/gcsversioninfo.pri @@ -0,0 +1,35 @@ +# +# This qmake file generates a header with the GCS version info string. +# +# This is a bit tricky since the script should be run always and before +# the other dependencies evaluation. +# + +# Since debug_and_release option is set, we need this +!debug_and_release|build_pass { + ROOT_DIR = $$GCS_SOURCE_TREE/../.. + VERSION_INFO_HEADER = $$GCS_BUILD_TREE/gcsversioninfo.h + VERSION_INFO_SCRIPT = $$ROOT_DIR/make/scripts/version-info.py + VERSION_INFO_TEMPLATE = $$ROOT_DIR/make/templates/gcsversioninfotemplate.h + VERSION_INFO_COMMAND = python \"$$VERSION_INFO_SCRIPT\" + + # Create custom version_info target which generates a header + version_info.target = $$VERSION_INFO_HEADER + version_info.commands = $$VERSION_INFO_COMMAND \ + --path=\"$$GCS_SOURCE_TREE\" \ + --template=\"$$VERSION_INFO_TEMPLATE\" \ + --outfile=\"$$VERSION_INFO_HEADER\" + version_info.depends = FORCE + QMAKE_EXTRA_TARGETS += version_info + + # Hook version_info target in between qmake's Makefile update and + # the actual project target + version_info_hook.depends = version_info + debug_and_release { + CONFIG(debug,debug|release):version_info_hook.target = Makefile.Debug + CONFIG(release,debug|release):version_info_hook.target = Makefile.Release + } else { + version_info_hook.target = Makefile + } + QMAKE_EXTRA_TARGETS += version_info_hook +} diff --git a/ground/openpilotgcs/src/plugins/coreplugin/generalsettings.cpp b/ground/openpilotgcs/src/plugins/coreplugin/generalsettings.cpp index d1f047c15..f0bc7bf4f 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/generalsettings.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/generalsettings.cpp @@ -44,8 +44,10 @@ using namespace Utils; using namespace Core::Internal; GeneralSettings::GeneralSettings(): + m_saveSettingsOnExit(true), m_dialog(0), - m_saveSettingsOnExit(true) + m_autoConnect(true), + m_autoSelect(true) { } @@ -113,27 +115,14 @@ QWidget *GeneralSettings::createPage(QWidget *parent) m_page->setupUi(w); fillLanguageBox(); + connect(m_page->checkAutoConnect,SIGNAL(stateChanged(int)),this,SLOT(slotAutoConnect(int))); m_page->checkBoxSaveOnExit->setChecked(m_saveSettingsOnExit); - + m_page->checkAutoConnect->setChecked(m_autoConnect); + m_page->checkAutoSelect->setChecked(m_autoSelect); m_page->colorButton->setColor(StyleHelper::baseColor()); -#ifdef Q_OS_UNIX - m_page->terminalEdit->setText(ConsoleProcess::terminalEmulator(Core::ICore::instance()->settings())); -#else - m_page->terminalLabel->hide(); - m_page->terminalEdit->hide(); - m_page->resetTerminalButton->hide(); -#endif connect(m_page->resetButton, SIGNAL(clicked()), this, SLOT(resetInterfaceColor())); - connect(m_page->resetEditorButton, SIGNAL(clicked()), - this, SLOT(resetExternalEditor())); - connect(m_page->helpExternalEditorButton, SIGNAL(clicked()), - this, SLOT(showHelpForExternalEditor())); -#ifdef Q_OS_UNIX - connect(m_page->resetTerminalButton, SIGNAL(clicked()), - this, SLOT(resetTerminal())); -#endif return w; } @@ -146,11 +135,8 @@ void GeneralSettings::apply() StyleHelper::setBaseColor(m_page->colorButton->color()); m_saveSettingsOnExit = m_page->checkBoxSaveOnExit->isChecked(); -#ifdef Q_OS_UNIX - ConsoleProcess::setTerminalEmulator(Core::ICore::instance()->settings(), - m_page->terminalEdit->text()); -#endif - + m_autoConnect = m_page->checkAutoConnect->isChecked(); + m_autoSelect = m_page->checkAutoSelect->isChecked(); } void GeneralSettings::finish() @@ -163,8 +149,9 @@ void GeneralSettings::readSettings(QSettings* qs) qs->beginGroup(QLatin1String("General")); m_language = qs->value(QLatin1String("OverrideLanguage"),QLocale::system().name()).toString(); m_saveSettingsOnExit = qs->value(QLatin1String("SaveSettingsOnExit"),m_saveSettingsOnExit).toBool(); + m_autoConnect = qs->value(QLatin1String("AutoConnect"),m_autoConnect).toBool(); + m_autoSelect = qs->value(QLatin1String("AutoSelect"),m_autoSelect).toBool(); qs->endGroup(); - } void GeneralSettings::saveSettings(QSettings* qs) @@ -177,6 +164,8 @@ void GeneralSettings::saveSettings(QSettings* qs) qs->setValue(QLatin1String("OverrideLanguage"), m_language); qs->setValue(QLatin1String("SaveSettingsOnExit"), m_saveSettingsOnExit); + qs->setValue(QLatin1String("AutoConnect"), m_autoConnect); + qs->setValue(QLatin1String("AutoSelect"), m_autoSelect); qs->endGroup(); } @@ -185,17 +174,6 @@ void GeneralSettings::resetInterfaceColor() m_page->colorButton->setColor(0x666666); } -void GeneralSettings::resetExternalEditor() -{ -} - -#ifdef Q_OS_UNIX -void GeneralSettings::resetTerminal() -{ - m_page->terminalEdit->setText(ConsoleProcess::defaultTerminalEmulator() + QLatin1String(" -e")); -} -#endif - void GeneralSettings::showHelpForExternalEditor() { if (m_dialog) { @@ -229,10 +207,11 @@ QString GeneralSettings::language() const void GeneralSettings::setLanguage(const QString &locale) { - if (m_language != locale) - { + if (m_language != locale) { + if (!locale.isEmpty()) { QMessageBox::information((QWidget*)Core::ICore::instance()->mainWindow(), tr("Restart required"), tr("The language change will take effect after a restart of the OpenPilot GCS.")); + } m_language = locale; } } @@ -241,3 +220,21 @@ bool GeneralSettings::saveSettingsOnExit() const { return m_saveSettingsOnExit; } + +bool GeneralSettings::autoConnect() const +{ + return m_autoConnect; +} + +bool GeneralSettings::autoSelect() const +{ + return m_autoSelect; +} + +void GeneralSettings::slotAutoConnect(int value) +{ + if (value==Qt::Checked) + m_page->checkAutoSelect->setEnabled(false); + else + m_page->checkAutoSelect->setEnabled(true); +} diff --git a/ground/openpilotgcs/src/plugins/coreplugin/generalsettings.h b/ground/openpilotgcs/src/plugins/coreplugin/generalsettings.h index 816deb8db..f70d7c9a9 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/generalsettings.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/generalsettings.h @@ -56,17 +56,18 @@ public: void apply(); void finish(); bool saveSettingsOnExit() const; + bool autoConnect() const; + bool autoSelect() const; void readSettings(QSettings* qs); void saveSettings(QSettings* qs); +signals: + private slots: void resetInterfaceColor(); void resetLanguage(); - void resetExternalEditor(); void showHelpForExternalEditor(); -#ifdef Q_OS_UNIX - void resetTerminal(); -#endif + void slotAutoConnect(int); private: void fillLanguageBox() const; @@ -75,6 +76,8 @@ private: Ui::GeneralSettings *m_page; QString m_language; bool m_saveSettingsOnExit; + bool m_autoConnect; + bool m_autoSelect; QPointer m_dialog; QList m_codecs; diff --git a/ground/openpilotgcs/src/plugins/coreplugin/generalsettings.ui b/ground/openpilotgcs/src/plugins/coreplugin/generalsettings.ui index 3f009f4aa..1be8020ce 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/generalsettings.ui +++ b/ground/openpilotgcs/src/plugins/coreplugin/generalsettings.ui @@ -17,33 +17,6 @@ General settings
- - - - Terminal: - - - - - - - External editor: - - - - - - - When files are externally modified: - - - true - - - - - - @@ -51,44 +24,6 @@ - - - - Reset to default - - - R - - - - :/core/images/reset.png:/core/images/reset.png - - - - - - - - - - Reset to default - - - R - - - - :/core/images/reset.png:/core/images/reset.png - - - - - - - ? - - - @@ -144,53 +79,12 @@ - + 0 - - - - - 0 - 0 - - - - 0 - - - - Always ask - - - - - Reload all modified files - - - - - Ignore modifications - - - - - - - - Qt::Horizontal - - - - 132 - 20 - - - - @@ -221,7 +115,7 @@ - + @@ -231,16 +125,59 @@ - + - Save configuration settings on on exit + Save configuration settings on exit: true + + + + Automatically connect an OpenPilot USB device: + + + true + + + + + + + + + + true + + + + + + + Automatically select an OpenPilot USB device: + + + true + + + + + + + false + + + + + + true + + + diff --git a/ground/openpilotgcs/src/plugins/coreplugin/icore.h b/ground/openpilotgcs/src/plugins/coreplugin/icore.h index 6e8110ca1..f06479883 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/icore.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/icore.h @@ -88,7 +88,7 @@ public: virtual QSettings *settings(QSettings::Scope scope = QSettings::UserScope) const = 0; virtual SettingsDatabase *settingsDatabase() const = 0; - virtual void readMainSettings(QSettings* qs) = 0; + virtual void readMainSettings(QSettings* qs, bool workspaceDiffOnly = false) = 0; virtual void saveMainSettings(QSettings* qs) = 0; virtual void readSettings(IConfigurablePlugin* plugin, QSettings* qs = 0) = 0; virtual void saveSettings(IConfigurablePlugin* plugin, QSettings* qs = 0) = 0; diff --git a/ground/openpilotgcs/src/plugins/coreplugin/images/helpicon.svg b/ground/openpilotgcs/src/plugins/coreplugin/images/helpicon.svg new file mode 100644 index 000000000..620acb6ae --- /dev/null +++ b/ground/openpilotgcs/src/plugins/coreplugin/images/helpicon.svg @@ -0,0 +1,37 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/coreplugin/imode.h b/ground/openpilotgcs/src/plugins/coreplugin/imode.h index 50d31eba7..f548acd0a 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/imode.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/imode.h @@ -49,6 +49,7 @@ public: virtual QString name() const = 0; virtual QIcon icon() const = 0; virtual int priority() const = 0; + virtual void setPriority(int priority) = 0; virtual const char *uniqueModeName() const = 0; }; diff --git a/ground/openpilotgcs/src/plugins/coreplugin/iuavgadgetfactory.h b/ground/openpilotgcs/src/plugins/coreplugin/iuavgadgetfactory.h index 96fed8b28..5b8029241 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/iuavgadgetfactory.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/iuavgadgetfactory.h @@ -31,6 +31,7 @@ #include "core_global.h" #include +#include #include #include "uavconfiginfo.h" @@ -51,7 +52,9 @@ public: IUAVGadgetFactory(QString classId, QString name, QObject *parent = 0) : QObject(parent), m_classId(classId), - m_name(name) {} + m_name(name), + m_icon(QIcon()), + m_singleConfigurationGadget(false) {} virtual ~IUAVGadgetFactory() {} virtual IUAVGadget *createGadget(QWidget *parent) = 0; @@ -60,9 +63,16 @@ public: virtual IOptionsPage *createOptionsPage(IUAVGadgetConfiguration */*config*/) { return 0; } QString classId() const { return m_classId; } QString name() const { return m_name; } + QIcon icon() const { return m_icon; } + bool isSingleConfigurationGadget() { return m_singleConfigurationGadget; } +protected: + void setIcon(QIcon icon) { m_icon = icon; } + void setSingleConfigurationGadgetTrue() { m_singleConfigurationGadget = true; } private: QString m_classId; // unique class id QString m_name; // display name, should also be unique + QIcon m_icon; + bool m_singleConfigurationGadget; // true if there is exactly one configuration for this gadget }; } // namespace Core diff --git a/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.cpp b/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.cpp index 3a1fc324e..1849b4e8b 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.cpp @@ -30,44 +30,42 @@ #include "actioncontainer.h" #include "actionmanager_p.h" #include "basemode.h" +#include "connectionmanager.h" #include "coreimpl.h" #include "coreconstants.h" -#include "fancytabwidget.h" +#include "utils/mytabwidget.h" #include "generalsettings.h" #include "messagemanager.h" #include "modemanager.h" #include "mimedatabase.h" #include "outputpane.h" #include "plugindialog.h" -#include "shortcutsettings.h" -#include "workspacesettings.h" -#include "modemanager.h" -#include "uavgadgetmode.h" -#include "uavgadgetmanager.h" -#include "uavgadgetinstancemanager.h" -#include "connectionmanager.h" #include "qxtlogger.h" #include "qxtbasicstdloggerengine.h" +#include "shortcutsettings.h" +#include "uavgadgetmanager.h" +#include "uavgadgetinstancemanager.h" +#include "workspacesettings.h" -#include "settingsdialog.h" -#include "variablemanager.h" -#include "threadmanager.h" -#include "versiondialog.h" #include "authorsdialog.h" -#include "viewmanager.h" -#include "uniqueidmanager.h" -#include "manhattanstyle.h" -#include "dialogs/iwizard.h" -#include "rightpane.h" #include "baseview.h" #include "ioutputpane.h" #include "icorelistener.h" #include "iconfigurableplugin.h" +#include "manhattanstyle.h" +#include "rightpane.h" +#include "settingsdialog.h" +#include "threadmanager.h" +#include "uniqueidmanager.h" +#include "variablemanager.h" +#include "versiondialog.h" #include +#include +#include "dialogs/iwizard.h" #include #include -#include +#include #include #include @@ -112,9 +110,9 @@ MainWindow::MainWindow() : m_globalContext(QList() << Constants::C_GLOBAL_ID), m_additionalContexts(m_globalContext), // keep this in sync with main() in app/main.cpp - m_settings(new QSettings(QSettings::IniFormat, QSettings::UserScope, + m_settings(new QSettings(XmlConfig::XmlSettingsFormat, QSettings::UserScope, QLatin1String("OpenPilot"), QLatin1String("OpenPilotGCS"), this)), - m_globalSettings(new QSettings(QSettings::IniFormat, QSettings::SystemScope, + m_globalSettings(new QSettings(XmlConfig::XmlSettingsFormat, QSettings::SystemScope, QLatin1String("OpenPilot"), QLatin1String("OpenPilotGCS"), this)), m_settingsDatabase(new SettingsDatabase(QFileInfo(m_settings->fileName()).path(), QLatin1String("OpenPilotGCS"), @@ -123,7 +121,6 @@ MainWindow::MainWindow() : m_actionManager(new ActionManagerPrivate(this)), m_variableManager(new VariableManager(this)), m_threadManager(new ThreadManager(this)), - m_viewManager(0), m_modeManager(0), m_connectionManager(0), m_mimeDatabase(new MimeDatabase), @@ -155,7 +152,7 @@ MainWindow::MainWindow() : QCoreApplication::setApplicationVersion(QLatin1String(Core::Constants::GCS_VERSION_LONG)); QCoreApplication::setOrganizationName(QLatin1String("OpenPilot")); QCoreApplication::setOrganizationDomain(QLatin1String("openpilot.org")); - QSettings::setDefaultFormat(QSettings::IniFormat); + QSettings::setDefaultFormat(XmlConfig::XmlSettingsFormat); QString baseName = qApp->style()->objectName(); #ifdef Q_WS_X11 if (baseName == QLatin1String("windows")) { @@ -178,17 +175,27 @@ MainWindow::MainWindow() : registerDefaultContainers(); registerDefaultActions(); - m_modeStack = new FancyTabWidget(this); + m_modeStack = new MyTabWidget(this); + m_modeStack->setIconSize(QSize(24,24)); + m_modeStack->setTabPosition(QTabWidget::South); + m_modeStack->setMovable(false); + m_modeStack->setMinimumWidth(512); + m_modeStack->setElideMode(Qt::ElideRight); +#ifndef Q_WS_MAC + m_modeStack->setDocumentMode(true); +#endif m_modeManager = new ModeManager(this, m_modeStack); m_connectionManager = new ConnectionManager(this, m_modeStack); - m_viewManager = new ViewManager(this); m_messageManager = new MessageManager; setCentralWidget(m_modeStack); connect(QApplication::instance(), SIGNAL(focusChanged(QWidget*,QWidget*)), this, SLOT(updateFocusWidget(QWidget*,QWidget*))); + connect(m_workspaceSettings, SIGNAL(tabBarSettingsApplied(QTabWidget::TabPosition,bool)), + this, SLOT(applyTabBarSettings(QTabWidget::TabPosition,bool))); + connect(m_modeManager, SIGNAL(newModeOrder(QVector)), m_workspaceSettings, SLOT(newModeOrder(QVector))); // setUnifiedTitleAndToolBarOnMac(true); #ifdef Q_OS_UNIX @@ -218,8 +225,8 @@ MainWindow::~MainWindow() foreach (QString engine, qxtLog->allLoggerEngines()) qxtLog->removeLoggerEngine(engine); ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - if (m_uavGadgetModes.count() > 0) { - foreach (UAVGadgetMode *mode, m_uavGadgetModes) + if (m_uavGadgetManagers.count() > 0) { + foreach (UAVGadgetManager *mode, m_uavGadgetManagers) { pm->removeObject(mode); delete mode; @@ -242,9 +249,6 @@ MainWindow::~MainWindow() delete m_uniqueIDManager; m_uniqueIDManager = 0; - delete m_viewManager; - m_viewManager = 0; - pm->removeObject(m_coreImpl); delete m_coreImpl; m_coreImpl = 0; @@ -264,7 +268,6 @@ bool MainWindow::init(QString *errorMessage) ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); pm->addObject(m_coreImpl); - m_viewManager->init(); m_modeManager->init(); m_connectionManager->init(); @@ -284,18 +287,17 @@ void MainWindow::extensionsInitialized() { QSettings* qs = m_settings; - QSettings defaultSettings(":/core/OpenPilotGCS.ini", QSettings::IniFormat); + QSettings defaultSettings(":/core/OpenPilotGCS.xml", XmlConfig::XmlSettingsFormat); +// QSettings defaultSettings(":/core/OpenPilotGCS.ini", QSettings::IniFormat); if ( ! qs->allKeys().count() ){ QMessageBox msgBox; msgBox.setText(tr("No configuration file could be found.")); - msgBox.setInformativeText(tr("Do you want to load the default configuration?")); - msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - msgBox.setDefaultButton(QMessageBox::Yes); - if ( msgBox.exec() == QMessageBox::Yes ){ - qDebug() << "Load default config from resource /core/OpenPilotGCS.ini"; - qs = &defaultSettings; - } + msgBox.setInformativeText(tr("The default configuration will be loaded.")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); + qDebug() << "Load default config from resource /core/OpenPilotGCS.xml"; + qs = &defaultSettings; } m_uavGadgetInstanceManager = new UAVGadgetInstanceManager(this); @@ -394,7 +396,7 @@ IContext *MainWindow::currentContextObject() const QStatusBar *MainWindow::statusBar() const { - return m_modeStack->statusBar(); + return new QStatusBar();// m_modeStack->statusBar(); } void MainWindow::registerDefaultContainers() @@ -670,6 +672,60 @@ void MainWindow::registerDefaultActions() connect(m_toggleFullScreenAction, SIGNAL(triggered(bool)), this, SLOT(setFullScreen(bool))); #endif + /* + * UavGadgetManager Actions + */ + const QList uavGadgetManagerContext = + QList() << CoreImpl::instance()->uniqueIDManager()->uniqueIdentifier(Constants::C_UAVGADGETMANAGER); + //Window menu separators + QAction *tmpaction1 = new QAction(this); + tmpaction1->setSeparator(true); + cmd = am->registerAction(tmpaction1, QLatin1String("OpenPilot.Window.Sep.Split"), uavGadgetManagerContext); + mwindow->addAction(cmd, Constants::G_WINDOW_HIDE_TOOLBAR); + + m_showToolbarsAction = new QAction(tr("Edit Gadgets Mode"), this); + m_showToolbarsAction->setCheckable(true); + cmd = am->registerAction(m_showToolbarsAction, Constants::HIDE_TOOLBARS, uavGadgetManagerContext); + cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+F10"))); + mwindow->addAction(cmd, Constants::G_WINDOW_HIDE_TOOLBAR); + + //Window menu separators + QAction *tmpaction2 = new QAction(this); + tmpaction2->setSeparator(true); + cmd = am->registerAction(tmpaction2, QLatin1String("OpenPilot.Window.Sep.Split2"), uavGadgetManagerContext); + mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); + +#ifdef Q_WS_MAC + QString prefix = tr("Meta+Shift"); +#else + QString prefix = tr("Ctrl+Shift"); +#endif + + m_splitAction = new QAction(tr("Split"), this); + cmd = am->registerAction(m_splitAction, Constants::SPLIT, uavGadgetManagerContext); + cmd->setDefaultKeySequence(QKeySequence(tr("%1+Down").arg(prefix))); + mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); + + m_splitSideBySideAction = new QAction(tr("Split Side by Side"), this); + cmd = am->registerAction(m_splitSideBySideAction, Constants::SPLIT_SIDE_BY_SIDE, uavGadgetManagerContext); + cmd->setDefaultKeySequence(QKeySequence(tr("%1+Right").arg(prefix))); + mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); + + m_removeCurrentSplitAction = new QAction(tr("Close Current View"), this); + cmd = am->registerAction(m_removeCurrentSplitAction, Constants::REMOVE_CURRENT_SPLIT, uavGadgetManagerContext); + cmd->setDefaultKeySequence(QKeySequence(tr("%1+C").arg(prefix))); + mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); + + m_removeAllSplitsAction = new QAction(tr("Close All Other Views"), this); + cmd = am->registerAction(m_removeAllSplitsAction, Constants::REMOVE_ALL_SPLITS, uavGadgetManagerContext); + cmd->setDefaultKeySequence(QKeySequence(tr("%1+A").arg(prefix))); + mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); + + m_gotoOtherSplitAction = new QAction(tr("Goto Next View"), this); + cmd = am->registerAction(m_gotoOtherSplitAction, Constants::GOTO_OTHER_SPLIT, uavGadgetManagerContext); + cmd->setDefaultKeySequence(QKeySequence(tr("%1+N").arg(prefix))); + mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); + //Help Action tmpaction = new QAction(QIcon(Constants::ICON_HELP), tr("&Help..."), this); cmd = am->registerAction(tmpaction, Constants::G_HELP_HELP, m_globalContext); @@ -808,6 +864,12 @@ void MainWindow::openFileWith() } +void MainWindow::applyTabBarSettings(QTabWidget::TabPosition pos, bool movable) { + if (m_modeStack->tabPosition() != pos) + m_modeStack->setTabPosition(pos); + m_modeStack->setMovable(movable); +} + ActionManager *MainWindow::actionManager() const { return m_actionManager; @@ -846,12 +908,6 @@ ConnectionManager *MainWindow::connectionManager() const return m_connectionManager; } -void MainWindow::addUAVGadgetManager(UAVGadgetManager *manager) -{ - if (!m_uavGadgetManagers.contains(manager)) - m_uavGadgetManagers.append(manager); -} - QList MainWindow::uavGadgetManagers() const { return m_uavGadgetManagers; @@ -873,6 +929,11 @@ MimeDatabase *MainWindow::mimeDatabase() const return m_mimeDatabase; } +GeneralSettings * MainWindow::generalSettings() const +{ + return m_generalSettings; +} + IContext *MainWindow::contextObject(QWidget *widget) { return m_contextWidgets.value(widget); @@ -982,40 +1043,83 @@ void MainWindow::shutdown() uavGadgetInstanceManager()->removeAllGadgets(); } -void MainWindow::createWorkspaces() { +/* Enable/disable menus for uavgadgets */ +void MainWindow::showUavGadgetMenus(bool show, bool hasSplitter) +{ + m_showToolbarsAction->setChecked(show); + m_splitAction->setEnabled(show); + m_splitSideBySideAction->setEnabled(show); + m_removeCurrentSplitAction->setEnabled(show && hasSplitter); + m_removeAllSplitsAction->setEnabled(show && hasSplitter); + m_gotoOtherSplitAction->setEnabled(show && hasSplitter); +} + +inline int takeLeastPriorityUavGadgetManager(const QList m_uavGadgetManagers) { + int index = 0; + int prio = m_uavGadgetManagers.at(0)->priority(); + for (int i = 0; i < m_uavGadgetManagers.count(); i++) { + int prio2 = m_uavGadgetManagers.at(i)->priority(); + if (prio2 < prio) { + prio = prio2; + index = i; + } + } + return index; +} + +void MainWindow::createWorkspaces(QSettings* qs, bool diffOnly) { ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVGadgetMode *uavGadgetMode; Core::UAVGadgetManager *uavGadgetManager; - while (!m_uavGadgetModes.isEmpty()){ - pm->removeObject(m_uavGadgetModes.takeFirst()); - } - while (!m_uavGadgetManagers.isEmpty()){ - Core::UAVGadgetManager* uavGadgetManager = m_uavGadgetManagers.takeLast(); - uavGadgetManager->removeAllSplits(); - // TODO Fixthis: This only happens, when settings are reloaded. - // then the old GadgetManagers should be deleted, but if - // I delete them the GCS segfaults. - //delete uavGadgetManager; - } - m_uavGadgetManagers.clear(); - m_uavGadgetModes.clear(); - for (int i = 0; i < m_workspaceSettings->numberOfWorkspaces(); ++i) { + // If diffOnly is true, we only add/remove the number of workspaces + // that has changed, + // otherwise a complete reload of workspaces is done + int toRemoveFirst = m_uavGadgetManagers.count(); + int newWorkspacesNo = m_workspaceSettings->numberOfWorkspaces(); + if (diffOnly && m_uavGadgetManagers.count() > newWorkspacesNo) + toRemoveFirst = m_uavGadgetManagers.count() - newWorkspacesNo; + else + toRemoveFirst = 0; + + int removed = 0; + + while (!m_uavGadgetManagers.isEmpty() && (toRemoveFirst > removed)) { + int index = takeLeastPriorityUavGadgetManager(m_uavGadgetManagers); + uavGadgetManager = m_uavGadgetManagers.takeAt(index); + uavGadgetManager->removeAllSplits(); + pm->removeObject(uavGadgetManager); + delete uavGadgetManager; + removed++; + } + + int start = 0; + if (diffOnly) { + start = m_uavGadgetManagers.count(); + } else { + m_uavGadgetManagers.clear(); + } + for (int i = start; i < newWorkspacesNo; ++i) { - uavGadgetManager = new Core::UAVGadgetManager(CoreImpl::instance(), this); - uavGadgetManager->hide(); const QString name = m_workspaceSettings->name(i); const QString iconName = m_workspaceSettings->iconName(i); const QString modeName = m_workspaceSettings->modeName(i); + uavGadgetManager = new Core::UAVGadgetManager(CoreImpl::instance(), name, + QIcon(iconName), 90-i+1, modeName, this); - uavGadgetMode = new UAVGadgetMode(uavGadgetManager, name, - QIcon(iconName), 90-i+1, modeName); - uavGadgetManager->setUAVGadgetMode(uavGadgetMode); - m_uavGadgetModes.append(uavGadgetMode); - pm->addObject(uavGadgetMode); - addUAVGadgetManager(uavGadgetManager); + connect(uavGadgetManager, SIGNAL(showUavGadgetMenus(bool, bool)), this, SLOT(showUavGadgetMenus(bool, bool))); + + connect(m_showToolbarsAction, SIGNAL(triggered(bool)), uavGadgetManager, SLOT(showToolbars(bool))); + connect(m_splitAction, SIGNAL(triggered()), uavGadgetManager, SLOT(split())); + connect(m_splitSideBySideAction, SIGNAL(triggered()), uavGadgetManager, SLOT(splitSideBySide())); + connect(m_removeCurrentSplitAction, SIGNAL(triggered()), uavGadgetManager, SLOT(removeCurrentSplit())); + connect(m_removeAllSplitsAction, SIGNAL(triggered()), uavGadgetManager, SLOT(removeAllSplits())); + connect(m_gotoOtherSplitAction, SIGNAL(triggered()), uavGadgetManager, SLOT(gotoOtherSplit())); + + pm->addObject(uavGadgetManager); + m_uavGadgetManagers.append(uavGadgetManager); + uavGadgetManager->readSettings(qs); } } @@ -1024,13 +1128,19 @@ static const char *geometryKey = "Geometry"; static const char *colorKey = "Color"; static const char *maxKey = "Maximized"; static const char *fullScreenKey = "FullScreen"; +static const char *modePriorities = "ModePriorities"; -void MainWindow::readSettings(QSettings* qs) +void MainWindow::readSettings(QSettings* qs, bool workspaceDiffOnly) { if ( !qs ){ qs = m_settings; } + if (workspaceDiffOnly) { + createWorkspaces(qs, workspaceDiffOnly); + return; + } + m_generalSettings->readSettings(qs); m_actionManager->readSettings(qs); @@ -1052,13 +1162,18 @@ void MainWindow::readSettings(QSettings* qs) m_workspaceSettings->readSettings(qs); - createWorkspaces(); + createWorkspaces(qs); - foreach (UAVGadgetManager *manager, m_uavGadgetManagers) { - manager->readSettings(qs); + // Read tab ordering + qs->beginGroup(QLatin1String(modePriorities)); + QStringList modeNames = qs->childKeys(); + QMap map; + foreach (QString modeName, modeNames) { + map.insert(modeName, qs->value(modeName).toInt()); } + m_modeManager->reorderModes(map); - m_viewManager->readSettings(qs); + qs->endGroup(); } @@ -1088,11 +1203,18 @@ void MainWindow::saveSettings(QSettings* qs) qs->endGroup(); + // Write tab ordering + qs->beginGroup(QLatin1String(modePriorities)); + QVector modes = m_modeManager->modes(); + foreach (IMode *mode, modes) { + qs->setValue(QLatin1String(mode->uniqueModeName()), mode->priority()); + } + qs->endGroup(); + foreach (UAVGadgetManager *manager, m_uavGadgetManagers) { manager->saveSettings(qs); } - m_viewManager->saveSettings(qs); m_actionManager->saveSettings(qs); m_generalSettings->saveSettings(qs); diff --git a/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.h b/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.h index a7ce53419..7d1c61ebc 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.h @@ -40,6 +40,7 @@ QT_BEGIN_NAMESPACE class QSettings; class QShortcut; class QToolButton; +class MyTabWidget; QT_END_NAMESPACE namespace Core { @@ -73,10 +74,8 @@ class FancyTabWidget; class GeneralSettings; class ShortcutSettings; class WorkspaceSettings; -class ViewManager; class VersionDialog; class AuthorsDialog; -class UAVGadgetMode; class CORE_EXPORT MainWindow : public EventFilteringMainWindow { @@ -94,7 +93,7 @@ public: void addContextObject(IContext *contex); void removeContextObject(IContext *contex); void resetContext(); - void readSettings(QSettings* qs = 0); + void readSettings(QSettings* qs = 0, bool workspaceDiffOnly = false); void saveSettings(QSettings* qs = 0); void readSettings(IConfigurablePlugin* plugin, QSettings* qs = 0); void saveSettings(IConfigurablePlugin* plugin, QSettings* qs = 0); @@ -111,7 +110,7 @@ public: Core::ThreadManager *threadManager() const; Core::ModeManager *modeManager() const; Core::MimeDatabase *mimeDatabase() const; - + Internal::GeneralSettings *generalSettings() const; QSettings *settings(QSettings::Scope scope) const; inline SettingsDatabase *settingsDatabase() const { return m_settingsDatabase; } IContext * currentContextObject() const; @@ -162,14 +161,14 @@ private slots: void destroyVersionDialog(); void destroyAuthorsDialog(); void modeChanged(Core::IMode *mode); + void showUavGadgetMenus(bool show, bool hasSplitter); + void applyTabBarSettings(QTabWidget::TabPosition pos, bool movable); private: - void addUAVGadgetManager(Core::UAVGadgetManager *manager); void updateContextObject(IContext *context); void registerDefaultContainers(); void registerDefaultActions(); - - void createWorkspaces(); + void createWorkspaces(QSettings* qs, bool diffOnly = false); CoreImpl *m_coreImpl; UniqueIDManager *m_uniqueIDManager; @@ -177,21 +176,18 @@ private: QList m_additionalContexts; QSettings *m_settings; QSettings *m_globalSettings; - bool m_dontSaveSettings; // In case of an Error or if we reset the settings, never save them. SettingsDatabase *m_settingsDatabase; + bool m_dontSaveSettings; // In case of an Error or if we reset the settings, never save them. ActionManagerPrivate *m_actionManager; MessageManager *m_messageManager; VariableManager *m_variableManager; ThreadManager *m_threadManager; - ViewManager *m_viewManager; ModeManager *m_modeManager; QList m_uavGadgetManagers; - QList m_uavGadgetModes; UAVGadgetInstanceManager *m_uavGadgetInstanceManager; ConnectionManager *m_connectionManager; MimeDatabase *m_mimeDatabase; - FancyTabWidget *m_modeStack; -// RightPaneWidget *m_rightPaneWidget; + MyTabWidget *m_modeStack; Core::BaseView *m_outputView; VersionDialog *m_versionDialog; AuthorsDialog *m_authorsDialog; @@ -213,6 +209,14 @@ private: QAction *m_exitAction; QAction *m_optionsAction; QAction *m_toggleFullScreenAction; + // UavGadgetManager actions + QAction *m_showToolbarsAction; + QAction *m_splitAction; + QAction *m_splitSideBySideAction; + QAction *m_removeCurrentSplitAction; + QAction *m_removeAllSplitsAction; + QAction *m_gotoOtherSplitAction; + #ifdef Q_WS_MAC QAction *m_minimizeAction; QAction *m_zoomAction; diff --git a/ground/openpilotgcs/src/plugins/coreplugin/modemanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/modemanager.cpp index 3dc36bbe8..ac3c4c224 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/modemanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/modemanager.cpp @@ -30,6 +30,7 @@ #include "fancytabwidget.h" #include "fancyactionbar.h" +#include "utils/mytabwidget.h" #include "icore.h" #include "mainwindow.h" @@ -59,18 +60,17 @@ using namespace Core::Internal; ModeManager *ModeManager::m_instance = 0; -ModeManager::ModeManager(Internal::MainWindow *mainWindow, FancyTabWidget *modeStack) : +ModeManager::ModeManager(Internal::MainWindow *mainWindow, MyTabWidget *modeStack) : m_mainWindow(mainWindow), m_modeStack(modeStack), - m_signalMapper(new QSignalMapper(this)) + m_signalMapper(new QSignalMapper(this)), + m_isReprioritizing(false) { m_instance = this; - m_actionBar = new FancyActionBar(modeStack); -// m_modeStack->addCornerWidget(m_actionBar); - - connect(m_modeStack, SIGNAL(currentAboutToShow(int)), SLOT(currentTabAboutToChange(int))); - connect(m_modeStack, SIGNAL(currentChanged(int)), SLOT(currentTabChanged(int))); +// connect((m_modeStack), SIGNAL(currentAboutToShow(int)), SLOT(currentTabAboutToChange(int))); + connect(m_modeStack, SIGNAL(currentChanged(int)), this, SLOT(currentTabChanged(int))); + connect(m_modeStack, SIGNAL(tabMoved(int,int)), this, SLOT(tabMoved(int,int))); connect(m_signalMapper, SIGNAL(mapped(QString)), this, SLOT(activateMode(QString))); } @@ -87,7 +87,7 @@ void ModeManager::addWidget(QWidget *widget) // We want the actionbar to stay on the bottom // so m_modeStack->cornerWidgetCount() -1 inserts it at the position immediately above // the actionbar - m_modeStack->insertCornerWidget(m_modeStack->cornerWidgetCount() -1, widget); +// m_modeStack->insertCornerWidget(m_modeStack->cornerWidgetCount() -1, widget); } IMode *ModeManager::currentMode() const @@ -150,6 +150,14 @@ void ModeManager::objectAdded(QObject *obj) m_modeShortcuts.insert(index, cmd); connect(cmd, SIGNAL(keySequenceChanged()), this, SLOT(updateModeToolTip())); + + setDefaultKeyshortcuts(); + + m_signalMapper->setMapping(shortcut, mode->uniqueModeName()); + connect(shortcut, SIGNAL(activated()), m_signalMapper, SLOT(map())); +} + +void ModeManager::setDefaultKeyshortcuts() { for (int i = 0; i < m_modeShortcuts.size(); ++i) { Command *currentCmd = m_modeShortcuts.at(i); bool currentlyHasDefaultSequence = (currentCmd->keySequence() @@ -162,9 +170,6 @@ void ModeManager::objectAdded(QObject *obj) if (currentlyHasDefaultSequence) currentCmd->setKeySequence(currentCmd->defaultKeySequence()); } - - m_signalMapper->setMapping(shortcut, mode->uniqueModeName()); - connect(shortcut, SIGNAL(activated()), m_signalMapper, SLOT(map())); } void ModeManager::updateModeToolTip() @@ -182,7 +187,8 @@ void ModeManager::updateModeNameIcon(IMode *mode, const QIcon &icon, const QStri int index = indexOf(mode->uniqueModeName()); if (index < 0) return; - m_modeStack->updateTabNameIcon(index, icon, label); + m_modeStack->setTabIcon(index, icon); + m_modeStack->setTabText(index, label); } void ModeManager::aboutToRemoveObject(QObject *obj) @@ -194,7 +200,9 @@ void ModeManager::aboutToRemoveObject(QObject *obj) const int index = m_modes.indexOf(mode); m_modes.remove(index); m_modeShortcuts.remove(index); + disconnect(m_modeStack, SIGNAL(currentChanged(int)), this, SLOT(currentTabChanged(int))); m_modeStack->removeTab(index); + connect(m_modeStack, SIGNAL(currentChanged(int)), this, SLOT(currentTabChanged(int))); m_mainWindow->removeContextObject(mode); } @@ -209,7 +217,7 @@ void ModeManager::addAction(Command *command, int priority, QMenu *menu) if (p > priority) ++index; - m_actionBar->insertAction(index, command->action(), menu); +// m_actionBar->insertAction(index, command->action(), menu); } void ModeManager::currentTabAboutToChange(int index) @@ -223,6 +231,7 @@ void ModeManager::currentTabAboutToChange(int index) void ModeManager::currentTabChanged(int index) { +// qDebug() << "Current tab changed " << index; // Tab index changes to -1 when there is no tab left. if (index >= 0) { IMode *mode = m_modes.at(index); @@ -242,6 +251,53 @@ void ModeManager::currentTabChanged(int index) } } +void ModeManager::tabMoved(int from, int to) +{ + IMode *mode = m_modes.at(from); + m_modes.remove(from); + m_modes.insert(to, mode); + Command *cmd = m_modeShortcuts.at(from); + m_modeShortcuts.remove(from); + m_modeShortcuts.insert(to, cmd); + setDefaultKeyshortcuts(); + // Reprioritize, high priority means show to the left + if (!m_isReprioritizing) { + for (int i = 0; i < m_modes.count(); ++i) { + m_modes.at(i)->setPriority(100-i); + } + emit newModeOrder(m_modes); + } +} + +void ModeManager::reorderModes(QMap priorities) +{ + foreach (IMode *mode, m_modes) + mode->setPriority(priorities.value(QString(QLatin1String(mode->uniqueModeName())), mode->priority())); + + m_isReprioritizing = true; + IMode *current = currentMode(); + // Bubble sort + bool swapped = false; + do { + swapped = false; + for (int i = 0; i < m_modes.count()-1; ++i) { + IMode *mode1 = m_modes.at(i); + IMode *mode2 = m_modes.at(i+1); +// qDebug() << "Comparing " << i << " to " << i+1 << " p1 " << mode1->priority() << " p2 " << mode2->priority(); + if (mode2->priority() > mode1->priority()) { + m_modeStack->moveTab(i, i+1); +// qDebug() << "Tab moved from " << i << " to " << i+1; + swapped = true; + } + } + } while (swapped); + m_isReprioritizing = false; + m_modeStack->setCurrentIndex(0); + activateMode(current->uniqueModeName()); + emit newModeOrder(m_modes); +} + + void ModeManager::setFocusToCurrentMode() { IMode *mode = currentMode(); diff --git a/ground/openpilotgcs/src/plugins/coreplugin/modemanager.h b/ground/openpilotgcs/src/plugins/coreplugin/modemanager.h index 0dbae6a01..687ec0a51 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/modemanager.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/modemanager.h @@ -40,6 +40,7 @@ QT_BEGIN_NAMESPACE class QSignalMapper; class QMenu; class QIcon; +class MyTabWidget; QT_END_NAMESPACE namespace Core { @@ -58,7 +59,7 @@ class CORE_EXPORT ModeManager : public QObject Q_OBJECT public: - ModeManager(Internal::MainWindow *mainWindow, Internal::FancyTabWidget *modeStack); + ModeManager(Internal::MainWindow *mainWindow, MyTabWidget *modeStack); void init(); static ModeManager *instance() { return m_instance; } @@ -69,10 +70,13 @@ public: void addAction(Command *command, int priority, QMenu *menu = 0); void addWidget(QWidget *widget); void updateModeNameIcon(IMode *mode, const QIcon &icon, const QString &label); + QVector modes() const { return m_modes; } + void reorderModes(QMap priorities); signals: void currentModeAboutToChange(Core::IMode *mode); void currentModeChanged(Core::IMode *mode); + void newModeOrder(QVector modes); public slots: void activateMode(const QString &id); @@ -84,19 +88,22 @@ private slots: void currentTabAboutToChange(int index); void currentTabChanged(int index); void updateModeToolTip(); + void tabMoved(int from, int to); private: int indexOf(const QString &id) const; + void setDefaultKeyshortcuts(); static ModeManager *m_instance; Internal::MainWindow *m_mainWindow; - Internal::FancyTabWidget *m_modeStack; - Internal::FancyActionBar *m_actionBar; + MyTabWidget *m_modeStack; QMap m_actions; QVector m_modes; QVector m_modeShortcuts; QSignalMapper *m_signalMapper; QList m_addedContexts; + QList m_tabOrder; + bool m_isReprioritizing; }; } // namespace Core diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.cpp index f93e5cb60..55dc239a8 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.cpp @@ -56,7 +56,9 @@ UAVGadgetInstanceManager::UAVGadgetInstanceManager(QObject *parent) : m_factories.append(f); QString classId = f->classId(); QString name = f->name(); - m_classIds.insert(classId, name); + QIcon icon = f->icon(); + m_classIdNameMap.insert(classId, name); + m_classIdIconMap.insert(classId, icon); } } } @@ -108,7 +110,7 @@ void UAVGadgetInstanceManager::readConfigs_1_2_0(QSettings *qs) { UAVConfigInfo configInfo; - foreach (QString classId, m_classIds.keys()) + foreach (QString classId, m_classIdNameMap.keys()) { IUAVGadgetFactory *f = factory(classId); qs->beginGroup(classId); @@ -159,7 +161,7 @@ void UAVGadgetInstanceManager::readConfigs_1_1_0(QSettings *qs) { UAVConfigInfo configInfo; - foreach (QString classId, m_classIds.keys()) + foreach (QString classId, m_classIdNameMap.keys()) { IUAVGadgetFactory *f = factory(classId); qs->beginGroup(classId); @@ -242,7 +244,8 @@ void UAVGadgetInstanceManager::createOptionsPages() IUAVGadgetFactory *f = factory(config->classId()); IOptionsPage *p = f->createOptionsPage(config); if (p) { - IOptionsPage *page = new UAVGadgetOptionsPageDecorator(p, config); + IOptionsPage *page = new UAVGadgetOptionsPageDecorator(p, config, f->isSingleConfigurationGadget()); + page->setIcon(f->icon()); m_optionsPages.append(page); m_pm->addObject(page); } @@ -334,6 +337,7 @@ void UAVGadgetInstanceManager::cloneConfiguration(IUAVGadgetConfiguration *conf IUAVGadgetFactory *f = factory(config->classId()); IOptionsPage *p = f->createOptionsPage(config); IOptionsPage *page = new UAVGadgetOptionsPageDecorator(p, config); + page->setIcon(f->icon()); m_provisionalConfigs.append(config); m_provisionalOptionsPages.append(page); m_settingsDialog->insertPage(page); @@ -452,7 +456,12 @@ QStringList UAVGadgetInstanceManager::configurationNames(QString classId) const QString UAVGadgetInstanceManager::gadgetName(QString classId) const { - return m_classIds.value(classId); + return m_classIdNameMap.value(classId); +} + +QIcon UAVGadgetInstanceManager::gadgetIcon(QString classId) const +{ + return m_classIdIconMap.value(classId); } IUAVGadgetFactory *UAVGadgetInstanceManager::factory(QString classId) const diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.h b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.h index 1b8f574ee..fab30f284 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetinstancemanager.h @@ -32,6 +32,7 @@ #include #include #include +#include #include "core_global.h" #include "uavconfiginfo.h" @@ -68,9 +69,10 @@ public: void cloneConfiguration(IUAVGadgetConfiguration *config); void applyChanges(IUAVGadgetConfiguration *config); void configurationNameEdited(QString text, bool hasText = true); - QStringList classIds() const { return m_classIds.keys(); } + QStringList classIds() const { return m_classIdNameMap.keys(); } QStringList configurationNames(QString classId) const; QString gadgetName(QString classId) const; + QIcon gadgetIcon(QString classId) const; signals: void configurationChanged(IUAVGadgetConfiguration* config); @@ -91,7 +93,8 @@ private: QList m_factories; QList m_configurations; QList m_optionsPages; - QMap m_classIds; + QMap m_classIdNameMap; + QMap m_classIdIconMap; QMap m_takenNames; QList m_provisionalConfigs; QList m_provisionalDeletes; diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/splitterorview.cpp b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/splitterorview.cpp index 611f3c0ad..183ffa185 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/splitterorview.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/splitterorview.cpp @@ -73,57 +73,6 @@ void SplitterOrView::mousePressEvent(QMouseEvent *e) } } -//void SplitterOrView::paintEvent(QPaintEvent *event) -//{ -// if (m_uavGadgetManager->currentSplitterOrView() != this) -// return; -// -// if (!m_view) -// return; -// -// if (hasGadget()) -// return; -// -// if (m_uavGadgetManager->toolbarsShown()) -// return; -// -// // Discreet indication where an uavGadget would be if there is none -// QPainter painter(this); -// painter.setRenderHint(QPainter::Antialiasing, true); -// painter.setPen(Qt::NoPen); -// QColor shadeBrush(Qt::black); -// shadeBrush.setAlpha(25); -// painter.setBrush(shadeBrush); -// const int r = 3; -// painter.drawRoundedRect(rect().adjusted(r, r, -r, -r), r * 2, r * 2); -// -//#if 0 -// if (hasFocus()) { -//#ifdef Q_WS_MAC -// // With QMacStyle, we have to draw our own focus rect, since I didn't find -// // a way to draw the nice mac focus rect _inside_ this widget -// if (qobject_cast(style())) { -// painter.setPen(Qt::DotLine); -// painter.setBrush(Qt::NoBrush); -// painter.setOpacity(0.75); -// painter.drawRect(rect()); -// } else { -//#endif -// QStyleOptionFocusRect option; -// option.initFrom(this); -// option.backgroundColor = palette().color(QPalette::Background); -// -// // Some styles require a certain state flag in order to draw the focus rect -// option.state |= QStyle::State_KeyboardFocusChange; -// -// style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter); -//#ifdef Q_WS_MAC -// } -//#endif -// } -//#endif -//} - /* Contract: return SplitterOrView that is not splitter, or 0 if not found. * Implications: must not return SplitterOrView that is splitter. */ diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/uavgadgetmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/uavgadgetmanager.cpp index 71078ffee..c581a052c 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/uavgadgetmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/uavgadgetmanager.cpp @@ -29,7 +29,6 @@ #include "uavgadgetmanager.h" #include "uavgadgetview.h" #include "splitterorview.h" -#include "uavgadgetmode.h" #include "uavgadgetinstancemanager.h" #include "iuavgadgetfactory.h" #include "iuavgadget.h" @@ -79,229 +78,76 @@ static inline ExtensionSystem::PluginManager *pluginManager() //===================UAVGadgetManager===================== -//UAVGadgetManagerPlaceHolder *UAVGadgetManagerPlaceHolder::m_current = 0; - -UAVGadgetManagerPlaceHolder::UAVGadgetManagerPlaceHolder(Core::Internal::UAVGadgetMode *mode, QWidget *parent) - : QWidget(parent), - m_uavGadgetMode(mode), - m_current(0) -{ - m_mode = dynamic_cast(mode); - setLayout(new QVBoxLayout); - layout()->setMargin(0); - connect(Core::ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode *)), - this, SLOT(currentModeChanged(Core::IMode *))); - - currentModeChanged(Core::ModeManager::instance()->currentMode()); -} - -UAVGadgetManagerPlaceHolder::~UAVGadgetManagerPlaceHolder() -{ - if (m_current == this) { - m_uavGadgetMode->uavGadgetManager()->setParent(0); - m_uavGadgetMode->uavGadgetManager()->hide(); - } -} - -void UAVGadgetManagerPlaceHolder::currentModeChanged(Core::IMode *mode) -{ - UAVGadgetManager *gm = m_uavGadgetMode->uavGadgetManager(); - if (m_current == this) { - m_current = 0; - gm->setParent(0); - gm->hide(); - } - if (m_mode == mode) { - m_current = this; - layout()->addWidget(gm); - gm->showToolbars(gm->toolbarsShown()); - gm->show(); - } -} - -// ---------------- UAVGadgetManager - -namespace Core { - - -struct UAVGadgetManagerPrivate { - explicit UAVGadgetManagerPrivate(ICore *core, QWidget *parent); - ~UAVGadgetManagerPrivate(); - - // The root splitter or view. - QPointer m_splitterOrView; - - // The gadget which is currently 'active'. - QPointer m_currentGadget; - - QPointer m_core; - - QPointer m_coreListener; - - // actions - static QAction *m_showToolbarsAction; - static QAction *m_splitAction; - static QAction *m_splitSideBySideAction; - static QAction *m_removeCurrentSplitAction; - static QAction *m_removeAllSplitsAction; - static QAction *m_gotoOtherSplitAction; -}; -} - -QAction *UAVGadgetManagerPrivate::m_showToolbarsAction = 0; -QAction *UAVGadgetManagerPrivate::m_splitAction = 0; -QAction *UAVGadgetManagerPrivate::m_splitSideBySideAction = 0; -QAction *UAVGadgetManagerPrivate::m_removeCurrentSplitAction = 0; -QAction *UAVGadgetManagerPrivate::m_removeAllSplitsAction = 0; -QAction *UAVGadgetManagerPrivate::m_gotoOtherSplitAction = 0; - -UAVGadgetManagerPrivate::UAVGadgetManagerPrivate(ICore *core, QWidget *parent) : +UAVGadgetManager::UAVGadgetManager(ICore *core, QString name, QIcon icon, int priority, QString uniqueName, QWidget *parent) : + m_showToolbars(true), m_splitterOrView(0), m_currentGadget(0), m_core(core), - m_coreListener(0) -{ - Q_UNUSED(parent); -} - -UAVGadgetManagerPrivate::~UAVGadgetManagerPrivate() -{ -} - -UAVGadgetManager::UAVGadgetManager(ICore *core, QWidget *parent) : - QWidget(parent), - m_showToolbars(false), - m_d(new UAVGadgetManagerPrivate(core, parent)), - m_uavGadgetMode(0) + m_name(name), + m_icon(icon), + m_priority(priority), + m_widget(new QWidget(parent)) { - connect(m_d->m_core, SIGNAL(contextAboutToChange(Core::IContext *)), + // checking that the mode name is unique gives harmless + // warnings on the console output + ModeManager *modeManager = ModeManager::instance(); + if (!modeManager->mode(uniqueName)) { + m_uniqueName = uniqueName; + } else { + // this shouldn't happen + m_uniqueName = uniqueName + QString::number(quint64(this)); + } + m_uniqueNameBA = m_uniqueName.toLatin1(); + m_uniqueModeName = m_uniqueNameBA.data(); + + connect(m_core, SIGNAL(contextAboutToChange(Core::IContext *)), this, SLOT(handleContextChange(Core::IContext *))); - const QList uavGadgetManagerContext = - QList() << m_d->m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_UAVGADGETMANAGER); - ActionManager *am = m_d->m_core->actionManager(); - - //Window Menu - ActionContainer *mwindow = am->actionContainer(Constants::M_WINDOW); - Command *cmd; - - // The actions m_d->m_showToolbarsAction etc are common to all instances of UAVGadgetManager - // which means that they share the menu items/signals in the Window menu. - // That is, they all connect their slots to the same signal and have to check in the slot - // if the current mode is their mode, otherwise they just ignore the signal. - // The first UAVGadgetManager creates the actions, and the following just use them - // (This also implies that they share the same context.) - if (m_d->m_showToolbarsAction == 0) - { - //Window menu separators - QAction *tmpaction = new QAction(this); - tmpaction->setSeparator(true); - cmd = am->registerAction(tmpaction, QLatin1String("OpenPilot.Window.Sep.Split"), uavGadgetManagerContext); - mwindow->addAction(cmd, Constants::G_WINDOW_HIDE_TOOLBAR); - - m_d->m_showToolbarsAction = new QAction(tr("Edit Gadgets Mode"), this); - m_d->m_showToolbarsAction->setCheckable(true); - cmd = am->registerAction(m_d->m_showToolbarsAction, Constants::HIDE_TOOLBARS, uavGadgetManagerContext); - cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+F10"))); - mwindow->addAction(cmd, Constants::G_WINDOW_HIDE_TOOLBAR); - - //Window menu separators - QAction *tmpaction2 = new QAction(this); - tmpaction2->setSeparator(true); - cmd = am->registerAction(tmpaction2, QLatin1String("OpenPilot.Window.Sep.Split2"), uavGadgetManagerContext); - mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); - } - connect(m_d->m_showToolbarsAction, SIGNAL(triggered(bool)), this, SLOT(showToolbars(bool))); - -#ifdef Q_WS_MAC - QString prefix = tr("Meta+Shift"); -#else - QString prefix = tr("Ctrl+Shift"); -#endif - - if (m_d->m_splitAction == 0) - { - m_d->m_splitAction = new QAction(tr("Split"), this); - cmd = am->registerAction(m_d->m_splitAction, Constants::SPLIT, uavGadgetManagerContext); - cmd->setDefaultKeySequence(QKeySequence(tr("%1+Down").arg(prefix))); - mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); - } - connect(m_d->m_splitAction, SIGNAL(triggered()), this, SLOT(split())); - - if (m_d->m_splitSideBySideAction == 0) - { - m_d->m_splitSideBySideAction = new QAction(tr("Split Side by Side"), this); - cmd = am->registerAction(m_d->m_splitSideBySideAction, Constants::SPLIT_SIDE_BY_SIDE, uavGadgetManagerContext); - cmd->setDefaultKeySequence(QKeySequence(tr("%1+Right").arg(prefix))); - mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); - } - connect(m_d->m_splitSideBySideAction, SIGNAL(triggered()), this, SLOT(splitSideBySide())); - - if (m_d->m_removeCurrentSplitAction == 0) - { - m_d->m_removeCurrentSplitAction = new QAction(tr("Close Current View"), this); - cmd = am->registerAction(m_d->m_removeCurrentSplitAction, Constants::REMOVE_CURRENT_SPLIT, uavGadgetManagerContext); - cmd->setDefaultKeySequence(QKeySequence(tr("%1+C").arg(prefix))); - mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); - } - connect(m_d->m_removeCurrentSplitAction, SIGNAL(triggered()), this, SLOT(removeCurrentSplit())); - - if (m_d->m_removeAllSplitsAction == 0) - { - m_d->m_removeAllSplitsAction = new QAction(tr("Close All Other Views"), this); - cmd = am->registerAction(m_d->m_removeAllSplitsAction, Constants::REMOVE_ALL_SPLITS, uavGadgetManagerContext); - cmd->setDefaultKeySequence(QKeySequence(tr("%1+A").arg(prefix))); - mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); - } - connect(m_d->m_removeAllSplitsAction, SIGNAL(triggered()), this, SLOT(removeAllSplits())); - - if (m_d->m_gotoOtherSplitAction == 0) - { - m_d->m_gotoOtherSplitAction = new QAction(tr("Goto Next View"), this); - cmd = am->registerAction(m_d->m_gotoOtherSplitAction, Constants::GOTO_OTHER_SPLIT, uavGadgetManagerContext); - cmd->setDefaultKeySequence(QKeySequence(tr("%1+N").arg(prefix))); - mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); - } - connect(m_d->m_gotoOtherSplitAction, SIGNAL(triggered()), this, SLOT(gotoOtherSplit())); + connect(modeManager, SIGNAL(currentModeChanged(Core::IMode*)), + this, SLOT(modeChanged(Core::IMode*))); // other setup - m_d->m_splitterOrView = new SplitterOrView(this, 0); + m_splitterOrView = new SplitterOrView(this, 0); + // SplitterOrView with 0 as gadget calls our setCurrentGadget, which relies on currentSplitterOrView(), // which needs our m_splitterorView to be set, which isn't set yet at that time. // So directly set our currentGadget to 0, and do it again. - m_d->m_currentGadget = 0; - setCurrentGadget(m_d->m_splitterOrView->view()->gadget()); + m_currentGadget = 0; + setCurrentGadget(m_splitterOrView->view()->gadget()); - QHBoxLayout *layout = new QHBoxLayout(this); + QHBoxLayout *layout = new QHBoxLayout(m_widget); layout->setMargin(0); layout->setSpacing(0); - layout->addWidget(m_d->m_splitterOrView); + layout->addWidget(m_splitterOrView); showToolbars(m_showToolbars); - updateActions(); } UAVGadgetManager::~UAVGadgetManager() { - if (m_d->m_core) { - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - if (m_d->m_coreListener) { - pm->removeObject(m_d->m_coreListener); - delete m_d->m_coreListener; - } - } - delete m_d; +} + +QList UAVGadgetManager::context() const +{ + static QList contexts = QList() << + UniqueIDManager::instance()->uniqueIdentifier(Constants::C_UAVGADGETMANAGER); + return contexts; +} + +void UAVGadgetManager::modeChanged(Core::IMode *mode) +{ + if (mode != this) + return; + + m_currentGadget->widget()->setFocus(); + showToolbars(toolbarsShown()); } void UAVGadgetManager::init() { QList context; - context << m_d->m_core->uniqueIDManager()->uniqueIdentifier("OpenPilot.UAVGadgetManager"); - - m_d->m_coreListener = new UAVGadgetClosingCoreListener(this); - - pluginManager()->addObject(m_d->m_coreListener); + context << m_core->uniqueIDManager()->uniqueIdentifier("OpenPilot.UAVGadgetManager"); } void UAVGadgetManager::handleContextChange(Core::IContext *context) @@ -311,16 +157,15 @@ void UAVGadgetManager::handleContextChange(Core::IContext *context) IUAVGadget *uavGadget = context ? qobject_cast(context) : 0; if (uavGadget) setCurrentGadget(uavGadget); - updateActions(); } void UAVGadgetManager::setCurrentGadget(IUAVGadget *uavGadget) { - if (m_d->m_currentGadget == uavGadget) + if (m_currentGadget == uavGadget) return; SplitterOrView *oldView = currentSplitterOrView(); - m_d->m_currentGadget = uavGadget; + m_currentGadget = uavGadget; SplitterOrView *view = currentSplitterOrView(); if (oldView != view) { if (oldView) @@ -330,8 +175,6 @@ void UAVGadgetManager::setCurrentGadget(IUAVGadget *uavGadget) } uavGadget->widget()->setFocus(); emit currentGadgetChanged(uavGadget); - updateActions(); -// emit currentGadgetChanged(uavGadget); } /* Contract: return current SplitterOrView. @@ -339,17 +182,17 @@ void UAVGadgetManager::setCurrentGadget(IUAVGadget *uavGadget) */ Core::Internal::SplitterOrView *UAVGadgetManager::currentSplitterOrView() const { - if (!m_d->m_splitterOrView) // this is only for startup + if (!m_splitterOrView) // this is only for startup return 0; - SplitterOrView *view = m_d->m_currentGadget ? - m_d->m_splitterOrView->findView(m_d->m_currentGadget) : + SplitterOrView *view = m_currentGadget ? + m_splitterOrView->findView(m_currentGadget) : 0; return view; } IUAVGadget *UAVGadgetManager::currentGadget() const { - return m_d->m_currentGadget; + return m_currentGadget; } void UAVGadgetManager::emptyView(Core::Internal::UAVGadgetView *view) @@ -369,10 +212,10 @@ void UAVGadgetManager::closeView(Core::Internal::UAVGadgetView *view) { if (!view) return; - SplitterOrView *splitterOrView = m_d->m_splitterOrView->findView(view); + SplitterOrView *splitterOrView = m_splitterOrView->findView(view); Q_ASSERT(splitterOrView); Q_ASSERT(splitterOrView->view() == view); - if (splitterOrView == m_d->m_splitterOrView) + if (splitterOrView == m_splitterOrView) return; IUAVGadget *gadget = view->gadget(); @@ -380,7 +223,7 @@ void UAVGadgetManager::closeView(Core::Internal::UAVGadgetView *view) UAVGadgetInstanceManager *im = ICore::instance()->uavGadgetInstanceManager(); im->removeGadget(gadget); - SplitterOrView *splitter = m_d->m_splitterOrView->findSplitter(splitterOrView); + SplitterOrView *splitter = m_splitterOrView->findSplitter(splitterOrView); Q_ASSERT(splitterOrView->hasGadget() == false); Q_ASSERT(splitter->isSplitter() == true); splitterOrView->hide(); @@ -398,7 +241,7 @@ void UAVGadgetManager::addGadgetToContext(IUAVGadget *gadget) { if (!gadget) return; - m_d->m_core->addContextObject(gadget); + m_core->addContextObject(gadget); // emit uavGadgetOpened(uavGadget); } @@ -407,27 +250,39 @@ void UAVGadgetManager::removeGadget(IUAVGadget *gadget) { if (!gadget) return; - m_d->m_core->removeContextObject(qobject_cast(gadget)); + m_core->removeContextObject(qobject_cast(gadget)); } void UAVGadgetManager::ensureUAVGadgetManagerVisible() { - if (!isVisible()) - m_d->m_core->modeManager()->activateMode(m_uavGadgetMode->uniqueModeName()); + if (!m_widget->isVisible()) + m_core->modeManager()->activateMode(this->uniqueModeName()); } -void UAVGadgetManager::updateActions() +void UAVGadgetManager::showToolbars(bool show) { - if (m_d->m_core->modeManager()->currentMode() != m_uavGadgetMode) + if (m_core->modeManager()->currentMode() != this) return; - if (!m_d->m_splitterOrView) // this is only for startup + + m_showToolbars = show; + SplitterOrView *next = m_splitterOrView->findFirstView(); + do { + next->view()->showToolbar(show); + next = m_splitterOrView->findNextView(next); + } while (next); + + updateUavGadgetMenus(); +} + +void UAVGadgetManager::updateUavGadgetMenus() +{ + if (m_core->modeManager()->currentMode() != this) + return; + if (!m_splitterOrView) // this is only for startup return; // Splitting is only possible when the toolbars are shown - bool shown = m_d->m_showToolbarsAction->isChecked(); - bool hasSplitter = m_d->m_splitterOrView->isSplitter(); - m_d->m_removeCurrentSplitAction->setEnabled(shown && hasSplitter); - m_d->m_removeAllSplitsAction->setEnabled(shown && hasSplitter); - m_d->m_gotoOtherSplitAction->setEnabled(shown && hasSplitter); + bool hasSplitter = m_splitterOrView->isSplitter(); + emit showUavGadgetMenus(m_showToolbars, hasSplitter); } void UAVGadgetManager::saveState(QSettings* qSettings) const @@ -435,7 +290,7 @@ void UAVGadgetManager::saveState(QSettings* qSettings) const qSettings->setValue("version","UAVGadgetManagerV1"); qSettings->setValue("showToolbars",m_showToolbars); qSettings->beginGroup("splitter"); - m_d->m_splitterOrView->saveState(qSettings); + m_splitterOrView->saveState(qSettings); qSettings->endGroup(); } @@ -444,8 +299,8 @@ bool UAVGadgetManager::restoreState(QSettings* qSettings) removeAllSplits(); UAVGadgetInstanceManager *im = ICore::instance()->uavGadgetInstanceManager(); - IUAVGadget *gadget = m_d->m_splitterOrView->view()->gadget(); - emptyView(m_d->m_splitterOrView->view()); + IUAVGadget *gadget = m_splitterOrView->view()->gadget(); + emptyView(m_splitterOrView->view()); im->removeGadget(gadget); QString version = qSettings->value("version").toString(); @@ -458,7 +313,7 @@ bool UAVGadgetManager::restoreState(QSettings* qSettings) QApplication::setOverrideCursor(Qt::WaitCursor); qSettings->beginGroup("splitter"); - m_d->m_splitterOrView->restoreState(qSettings); + m_splitterOrView->restoreState(qSettings); qSettings->endGroup(); QApplication::restoreOverrideCursor(); @@ -468,7 +323,7 @@ bool UAVGadgetManager::restoreState(QSettings* qSettings) void UAVGadgetManager::saveSettings(QSettings *qs) { qs->beginGroup("UAVGadgetManager"); - qs->beginGroup(m_uavGadgetMode->uniqueModeName()); + qs->beginGroup(this->uniqueModeName()); // Make sure the old tree is wiped. qs->remove(""); @@ -488,16 +343,15 @@ void UAVGadgetManager::readSettings(QSettings *qs) } qs->beginGroup(uavGadgetManagerRootKey); - if(!qs->childGroups().contains(m_uavGadgetMode->uniqueModeName())) { + if(!qs->childGroups().contains(uniqueModeName())) { qs->endGroup(); return; } - qs->beginGroup(m_uavGadgetMode->uniqueModeName()); + qs->beginGroup(uniqueModeName()); restoreState(qs); showToolbars(m_showToolbars); - updateActions(); qs->endGroup(); qs->endGroup(); @@ -505,18 +359,19 @@ void UAVGadgetManager::readSettings(QSettings *qs) void UAVGadgetManager::split(Qt::Orientation orientation) { - if (m_d->m_core->modeManager()->currentMode() != m_uavGadgetMode) + if (m_core->modeManager()->currentMode() != this) return; - IUAVGadget *uavGadget = m_d->m_currentGadget; + IUAVGadget *uavGadget = m_currentGadget; Q_ASSERT(uavGadget); SplitterOrView *view = currentSplitterOrView(); Q_ASSERT(view); view->split(orientation); - SplitterOrView *sor = m_d->m_splitterOrView->findView(uavGadget); - SplitterOrView *next = m_d->m_splitterOrView->findNextView(sor); + SplitterOrView *sor = m_splitterOrView->findView(uavGadget); + SplitterOrView *next = m_splitterOrView->findNextView(sor); setCurrentGadget(next->gadget()); + updateUavGadgetMenus(); } void UAVGadgetManager::split() @@ -531,37 +386,38 @@ void UAVGadgetManager::splitSideBySide() void UAVGadgetManager::removeCurrentSplit() { - if (m_d->m_core->modeManager()->currentMode() != m_uavGadgetMode) + if (m_core->modeManager()->currentMode() != this) return; SplitterOrView *viewToClose = currentSplitterOrView(); - if (viewToClose == m_d->m_splitterOrView) + if (viewToClose == m_splitterOrView) return; closeView(viewToClose->view()); + updateUavGadgetMenus(); } // Removes all gadgets and splits in the workspace, except the current/active gadget. void UAVGadgetManager::removeAllSplits() { - if (m_d->m_core->modeManager()->currentMode() != m_uavGadgetMode) + if (m_core->modeManager()->currentMode() != this) return; - if (!m_d->m_splitterOrView->isSplitter()) + if (!m_splitterOrView->isSplitter()) return; // Use a QPointer, just in case we accidently delete the gadget we want to keep. - QPointer currentGadget = m_d->m_currentGadget; + QPointer currentGadget = m_currentGadget; Q_ASSERT(currentGadget); - QList gadgets = m_d->m_splitterOrView->gadgets(); + QList gadgets = m_splitterOrView->gadgets(); Q_ASSERT(gadgets.count(currentGadget) == 1); gadgets.removeOne(currentGadget); // Remove all splits and their gadgets, then create a new view with the current gadget. - m_d->m_splitterOrView->unsplitAll(currentGadget); + m_splitterOrView->unsplitAll(currentGadget); // Zeroing the current gadget means setCurrentGadget will do something when we call it. - m_d->m_currentGadget = 0; + m_currentGadget = 0; setCurrentGadget(currentGadget); // Remove all other gadgets from the instance manager. @@ -569,53 +425,21 @@ void UAVGadgetManager::removeAllSplits() foreach (IUAVGadget *g, gadgets) { im->removeGadget(g); } + updateUavGadgetMenus(); } void UAVGadgetManager::gotoOtherSplit() { - if (m_d->m_core->modeManager()->currentMode() != m_uavGadgetMode) + if (m_core->modeManager()->currentMode() != this) return; - if (m_d->m_splitterOrView->isSplitter()) { + if (m_splitterOrView->isSplitter()) { SplitterOrView *currentView = currentSplitterOrView(); - SplitterOrView *view = m_d->m_splitterOrView->findNextView(currentView); + SplitterOrView *view = m_splitterOrView->findNextView(currentView); if (!view) - view = m_d->m_splitterOrView->findFirstView(); + view = m_splitterOrView->findFirstView(); if (view) { setCurrentGadget(view->gadget()); } } } - -void UAVGadgetManager::showToolbars(bool show) -{ - if (m_d->m_core->modeManager()->currentMode() != m_uavGadgetMode) - return; - - m_d->m_showToolbarsAction->setChecked(show); - m_showToolbars = show; - SplitterOrView *next = m_d->m_splitterOrView->findFirstView(); - do { - next->view()->showToolbar(show); - next = m_d->m_splitterOrView->findNextView(next); - } while (next); - - m_d->m_splitAction->setEnabled(show); - m_d->m_splitSideBySideAction->setEnabled(show); - m_d->m_removeCurrentSplitAction->setEnabled(show); - m_d->m_removeAllSplitsAction->setEnabled(show); - m_d->m_gotoOtherSplitAction->setEnabled(show); -} -//===================UAVGadgetClosingCoreListener====================== - -UAVGadgetClosingCoreListener::UAVGadgetClosingCoreListener(UAVGadgetManager *em) - : m_em(em) -{ -} - -bool UAVGadgetClosingCoreListener::coreAboutToClose() -{ - // Do not ask for files to save. - // MainWindow::closeEvent has already done that. - return true; -} diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/uavgadgetmanager.h b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/uavgadgetmanager.h index 1eea66b2a..3764fa1fb 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/uavgadgetmanager.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/uavgadgetmanager.h @@ -32,14 +32,15 @@ #include "../core_global.h" #include +#include #include #include #include #include +#include QT_BEGIN_NAMESPACE -class QSettings; class QModelIndex; QT_END_NAMESPACE @@ -48,49 +49,33 @@ namespace Core { class IContext; class ICore; class IUAVGadget; -class IMode; - -struct UAVGadgetManagerPrivate; namespace Internal { -class UAVGadgetMode; class UAVGadgetView; class SplitterOrView; -class UAVGadgetClosingCoreListener; - - } // namespace Internal -class CORE_EXPORT UAVGadgetManagerPlaceHolder : public QWidget -{ - Q_OBJECT -public: - UAVGadgetManagerPlaceHolder(Core::Internal::UAVGadgetMode *mode, QWidget *parent = 0); - ~UAVGadgetManagerPlaceHolder(); -// static UAVGadgetManagerPlaceHolder* current(); -private slots: - void currentModeChanged(Core::IMode *); -private: - Core::IMode *m_mode; - Core::Internal::UAVGadgetMode *m_uavGadgetMode; - UAVGadgetManagerPlaceHolder* m_current; -}; - - -class CORE_EXPORT UAVGadgetManager : public QWidget +class CORE_EXPORT UAVGadgetManager : public IMode { Q_OBJECT public: - explicit UAVGadgetManager(ICore *core, QWidget *parent); + explicit UAVGadgetManager(ICore *core, QString name, QIcon icon, int priority, QString uniqueName, QWidget *parent); virtual ~UAVGadgetManager(); + + // IMode + QString name() const { return m_name; } + QIcon icon() const { return m_icon; } + int priority() const { return m_priority; } + void setPriority(int priority) { m_priority = priority; } + const char *uniqueModeName() const { return m_uniqueModeName; } + QList context() const; + void init(); - // setUAVGadgetMode should be called exactly once - // right after the mode has been created, and never thereafter - void setUAVGadgetMode(Core::Internal::UAVGadgetMode *mode) { m_uavGadgetMode = mode; } + QWidget *widget() { return m_widget; } void ensureUAVGadgetManagerVisible(); @@ -105,10 +90,14 @@ public: signals: void currentGadgetChanged(IUAVGadget *gadget); + void showUavGadgetMenus(bool show, bool hasSplitter); + void updateSplitMenus(bool hasSplitter); private slots: void handleContextChange(Core::IContext *context); - void updateActions(); + void updateUavGadgetMenus(); + void modeChanged(Core::IMode *mode); + public slots: void split(Qt::Orientation orientation); @@ -120,16 +109,25 @@ public slots: void showToolbars(bool show); private: + void setCurrentGadget(IUAVGadget *gadget); void addGadgetToContext(IUAVGadget *gadget); void removeGadget(IUAVGadget *gadget); - void setCurrentGadget(IUAVGadget *gadget); void closeView(Core::Internal::UAVGadgetView *view); void emptyView(Core::Internal::UAVGadgetView *view); Core::Internal::SplitterOrView *currentSplitterOrView() const; bool m_showToolbars; - UAVGadgetManagerPrivate *m_d; - Core::Internal::UAVGadgetMode *m_uavGadgetMode; + Core::Internal::SplitterOrView *m_splitterOrView; + Core::IUAVGadget *m_currentGadget; + Core::ICore *m_core; + + QString m_name; + QIcon m_icon; + int m_priority; + QString m_uniqueName; + QByteArray m_uniqueNameBA; + const char* m_uniqueModeName; + QWidget *m_widget; friend class Core::Internal::SplitterOrView; friend class Core::Internal::UAVGadgetView; @@ -137,26 +135,4 @@ private: } // namespace Core - -//===================UAVGadgetClosingCoreListener====================== - -namespace Core { -namespace Internal { - -class UAVGadgetClosingCoreListener : public ICoreListener -{ - Q_OBJECT - -public: - UAVGadgetClosingCoreListener(UAVGadgetManager *em); - bool uavGadgetAboutToClose(IUAVGadget *gadget); - bool coreAboutToClose(); - -private: - UAVGadgetManager *m_em; -}; - -} // namespace Internal -} // namespace Core - #endif // UAVGADGETMANAGER_H diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/uavgadgetview.cpp b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/uavgadgetview.cpp index a86b52d17..13b2b3062 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/uavgadgetview.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmanager/uavgadgetview.cpp @@ -91,6 +91,7 @@ UAVGadgetView::UAVGadgetView(Core::UAVGadgetManager *uavGadgetManager, IUAVGadge m_defaultIndex = 0; startFromOne = true; m_uavGadgetList->insertItem(0, im->gadgetName(classId), classId); + m_uavGadgetList->setItemIcon(0, im->gadgetIcon(classId)); m_uavGadgetList->insertSeparator(1); } else { @@ -101,6 +102,7 @@ UAVGadgetView::UAVGadgetView(Core::UAVGadgetManager *uavGadgetManager, IUAVGadge break; } m_uavGadgetList->insertItem(i, im->gadgetName(classId), classId); + m_uavGadgetList->setItemIcon(i, im->gadgetIcon(classId)); } ++index; } diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmode.cpp b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmode.cpp deleted file mode 100644 index eeb6df7a3..000000000 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmode.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/** - ****************************************************************************** - * - * @file uavgadgetmode.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "uavgadgetmode.h" -#include "uavgadgetmanager.h" -#include "coreconstants.h" -#include "modemanager.h" -#include "uniqueidmanager.h" -#include "minisplitter.h" -#include "outputpane.h" -#include "rightpane.h" -#include "iuavgadget.h" - -#include -#include -#include -#include -#include - -using namespace Core; -using namespace Core::Internal; - -UAVGadgetMode::UAVGadgetMode(UAVGadgetManager *uavGadgetManager, QString name, QIcon icon, int priority, QString uniqueName) : - m_uavGadgetManager(uavGadgetManager), - m_name(name), - m_icon(icon), - m_widget(new QWidget), - m_priority(priority), - m_layout(new QVBoxLayout) -{ - m_layout->setSpacing(0); - m_layout->setMargin(0); - m_widget->setLayout(m_layout); - m_layout->insertWidget(0, new Core::UAVGadgetManagerPlaceHolder(this)); - - ModeManager *modeManager = ModeManager::instance(); - // checking that the mode name is unique gives harmless - // warnings on the console output - if (!modeManager->mode(uniqueName)) { - m_uniqueName = uniqueName; - } else { - // this shouldn't happen - m_uniqueName = uniqueName + QString::number(quint64(this)); - } - m_uniqueNameBA = m_uniqueName.toLatin1(); - m_uniqueNameC = m_uniqueNameBA.data(); - connect(modeManager, SIGNAL(currentModeChanged(Core::IMode*)), - this, SLOT(grabUAVGadgetManager(Core::IMode*))); - m_widget->setFocusProxy(m_uavGadgetManager); -} - -UAVGadgetMode::~UAVGadgetMode() -{ - // TODO: see if this leftover from Qt Creator still applies - // Make sure the uavGadget manager does not get deleted - m_uavGadgetManager->setParent(0); - delete m_widget; -} - -QString UAVGadgetMode::name() const -{ - return m_name; -} - -void UAVGadgetMode::setName(QString name) -{ - m_name = name; -} - -QIcon UAVGadgetMode::icon() const -{ - return m_icon; -} - -void UAVGadgetMode::setIcon(QIcon icon) -{ - m_icon = icon; -} - -int UAVGadgetMode::priority() const -{ - return m_priority; -} - -QWidget* UAVGadgetMode::widget() -{ - return m_widget; -} - -const char* UAVGadgetMode::uniqueModeName() const -{ - return m_uniqueNameC; -} - -QList UAVGadgetMode::context() const -{ - static QList contexts = QList() << - UniqueIDManager::instance()->uniqueIdentifier(Constants::C_UAVGADGET_MODE) << - UniqueIDManager::instance()->uniqueIdentifier(Constants::C_UAVGADGETMANAGER); - return contexts; -} - -void UAVGadgetMode::grabUAVGadgetManager(Core::IMode *mode) -{ - if (mode != this) - return; - - if (m_uavGadgetManager->currentGadget()) - m_uavGadgetManager->currentGadget()->widget()->setFocus(); -} diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmode.h b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmode.h deleted file mode 100644 index 5aac09221..000000000 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetmode.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - ****************************************************************************** - * - * @file uavgadgetmode.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef UAVGADGETMODE_H -#define UAVGADGETMODE_H - -#include - -#include -#include - -QT_BEGIN_NAMESPACE -class QSplitter; -class QWidget; -class QIcon; -class QVBoxLayout; -QT_END_NAMESPACE - -namespace Core { - -class UAVGadgetManager; - -namespace Internal { - -class UAVGadgetMode : public Core::IMode -{ - Q_OBJECT - -public: - UAVGadgetMode(UAVGadgetManager *uavGadgetManager, QString name, QIcon icon, int priority, QString uniqueName); - ~UAVGadgetMode(); - - // IMode - QString name() const; - QIcon icon() const; - int priority() const; - QWidget* widget(); - const char* uniqueModeName() const; - QList context() const; - UAVGadgetManager* uavGadgetManager() const { return m_uavGadgetManager; } - void setName(QString name); - void setIcon(QIcon icon); - -private slots: - void grabUAVGadgetManager(Core::IMode *mode); - -private: - UAVGadgetManager *m_uavGadgetManager; - QString m_name; - QIcon m_icon; - QWidget *m_widget; - int m_priority; - QVBoxLayout *m_layout; - QString m_uniqueName; - QByteArray m_uniqueNameBA; - const char *m_uniqueNameC; -}; - -} // namespace Internal -} // namespace Core - -#endif // UAVGADGETMODE_H diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp index d5fc1b054..f95f7e4c1 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.cpp @@ -34,10 +34,12 @@ using namespace Core; -UAVGadgetOptionsPageDecorator::UAVGadgetOptionsPageDecorator(IOptionsPage *page, IUAVGadgetConfiguration *config, QObject *parent) : +UAVGadgetOptionsPageDecorator::UAVGadgetOptionsPageDecorator(IOptionsPage *page, IUAVGadgetConfiguration *config, + bool isSingleConfigurationGadget, QObject *parent) : Core::IOptionsPage(parent), m_optionsPage(page), m_config(config), + m_isSingleConfigurationGadget(isSingleConfigurationGadget), m_id(config->name()), m_category(config->classId()) { @@ -65,6 +67,11 @@ QWidget *UAVGadgetOptionsPageDecorator::createPage(QWidget *parent) wi->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); m_page->verticalLayout_4->addWidget(wi); + // For some gadgets it might not make sense to have multiple configurations + if (m_isSingleConfigurationGadget) { + m_page->configurationBox->hide(); + } + connect(m_page->cloneButton, SIGNAL(clicked()), this, SLOT(cloneConfiguration())); connect(m_page->deleteButton, SIGNAL(clicked()), this, SLOT(deleteConfiguration())); connect(m_page->nameLineEdit, SIGNAL(textEdited(QString)), this, SLOT(textEdited(QString))); diff --git a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.h b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.h index 919a8c510..14ec5bf39 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/uavgadgetoptionspagedecorator.h @@ -43,7 +43,7 @@ class CORE_EXPORT UAVGadgetOptionsPageDecorator : public Core::IOptionsPage { Q_OBJECT public: - explicit UAVGadgetOptionsPageDecorator(IOptionsPage *page, IUAVGadgetConfiguration *config, QObject *parent = 0); + explicit UAVGadgetOptionsPageDecorator(IOptionsPage *page, IUAVGadgetConfiguration *config, bool isSingleConfigurationGadget = false, QObject *parent = 0); QString id() const { return m_id; } QString trName() const { return m_id; } @@ -66,6 +66,7 @@ private slots: private: IOptionsPage *m_optionsPage; IUAVGadgetConfiguration *m_config; + bool m_isSingleConfigurationGadget; UAVGadgetInstanceManager *m_instanceManager; QString m_id; QString m_category; diff --git a/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.cpp b/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.cpp index cd4200765..aa8239f6e 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.cpp @@ -65,7 +65,7 @@ VersionDialog::VersionDialog(QWidget *parent) QString ideRev; #ifdef GCS_REVISION //: This gets conditionally inserted as argument %8 into the description string. - ideRev = tr("From revision %1
").arg(QString::fromLatin1(GCS_REVISION_STR).left(10)); + ideRev = tr("From revision %1
").arg(QString::fromLatin1(GCS_REVISION_STR).left(60)); #endif const QString description = tr( diff --git a/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.h b/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.h index 1293e7313..ab6ec24d2 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.h @@ -29,6 +29,9 @@ #ifndef VERSIONDIALOG_H #define VERSIONDIALOG_H +// autogenerated version info string +#include "../../../../../build/ground/openpilotgcs/gcsversioninfo.h" + #include namespace Core { diff --git a/ground/openpilotgcs/src/plugins/coreplugin/viewmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/viewmanager.cpp deleted file mode 100644 index 4acc08683..000000000 --- a/ground/openpilotgcs/src/plugins/coreplugin/viewmanager.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/** - ****************************************************************************** - * - * @file viewmanager.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "viewmanager.h" - -#include "coreconstants.h" -#include "mainwindow.h" -#include "uniqueidmanager.h" -#include "iview.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace Core; -using namespace Core::Internal; - -ViewManager::ViewManager(MainWindow *mainWnd) - : QObject(mainWnd), - m_mainWnd(mainWnd) -{ - for (int i = 0; i < 3; ++i) { - QWidget *w = new QWidget(); - m_mainWnd->statusBar()->insertPermanentWidget(i, w); - w->setLayout(new QHBoxLayout); - w->setVisible(true); - w->layout()->setMargin(0); - m_statusBarWidgets.append(w); - } - QLabel *l = new QLabel(); - m_mainWnd->statusBar()->insertPermanentWidget(3, l, 1); -} - -ViewManager::~ViewManager() -{ -} - -void ViewManager::init() -{ - connect(ExtensionSystem::PluginManager::instance(), SIGNAL(objectAdded(QObject*)), - this, SLOT(objectAdded(QObject*))); - connect(ExtensionSystem::PluginManager::instance(), SIGNAL(aboutToRemoveObject(QObject*)), - this, SLOT(aboutToRemoveObject(QObject*))); -} - -void ViewManager::objectAdded(QObject *obj) -{ - IView *view = Aggregation::query(obj); - if (!view) - return; - - QWidget *viewWidget = 0; - viewWidget = view->widget(); - m_statusBarWidgets.at(view->defaultPosition())->layout()->addWidget(viewWidget); - - m_viewMap.insert(view, viewWidget); - viewWidget->setObjectName(view->uniqueViewName()); - m_mainWnd->addContextObject(view); -} - -void ViewManager::aboutToRemoveObject(QObject *obj) -{ - IView *view = Aggregation::query(obj); - if (!view) - return; - m_mainWnd->removeContextObject(view); -} - -void ViewManager::readSettings(QSettings *settings) -{ - m_mainWnd->restoreState(settings->value(QLatin1String("ViewGroup_Default"), QByteArray()).toByteArray()); -} - -void ViewManager::saveSettings(QSettings *settings) -{ - settings->setValue(QLatin1String("ViewGroup_Default"), m_mainWnd->saveState()); -} - -IView *ViewManager::view(const QString &id) -{ - QList list = - ExtensionSystem::PluginManager::instance()->getObjects(); - foreach (IView *view, list) { - if (view->uniqueViewName() == id) - return view; - } - return 0; -} diff --git a/ground/openpilotgcs/src/plugins/coreplugin/viewmanager.h b/ground/openpilotgcs/src/plugins/coreplugin/viewmanager.h deleted file mode 100644 index 6d6dee120..000000000 --- a/ground/openpilotgcs/src/plugins/coreplugin/viewmanager.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - ****************************************************************************** - * - * @file viewmanager.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef VIEWMANAGER_H -#define VIEWMANAGER_H - -#include -#include - -QT_BEGIN_NAMESPACE -class QAction; -class QSettings; -class QMainWindow; -class QComboBox; -class QStackedWidget; -QT_END_NAMESPACE - -namespace Core { - -class IView; - -namespace Internal { - -class MainWindow; -class NavigationWidget; - -class ViewManager : public QObject -{ - Q_OBJECT - -public: - ViewManager(MainWindow *mainWnd); - ~ViewManager(); - - void init(); - void readSettings(QSettings *settings); - void saveSettings(QSettings *settings); - - IView * view(const QString & id); -private slots: - void objectAdded(QObject *obj); - void aboutToRemoveObject(QObject *obj); - -private: - QMap m_viewMap; - - MainWindow *m_mainWnd; - QList m_statusBarWidgets; -}; - -} // namespace Internal -} // namespace Core - -#endif // VIEWMANAGER_H diff --git a/ground/openpilotgcs/src/plugins/coreplugin/workspacesettings.cpp b/ground/openpilotgcs/src/plugins/coreplugin/workspacesettings.cpp index 367a8af20..6bc2dc20c 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/workspacesettings.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/workspacesettings.cpp @@ -28,7 +28,7 @@ #include "workspacesettings.h" #include #include -#include +#include #include #include "ui_workspacesettings.h" @@ -95,26 +95,37 @@ QWidget *WorkspaceSettings::createPage(QWidget *parent) m_currentIndex = 0; selectWorkspace(m_currentIndex); + if (0 <= m_tabBarPlacementIndex && m_tabBarPlacementIndex < m_page->comboBoxTabBarPlacement->count()) + m_page->comboBoxTabBarPlacement->setCurrentIndex(m_tabBarPlacementIndex); + m_page->checkBoxAllowTabMovement->setChecked(m_allowTabBarMovement); + return w; } void WorkspaceSettings::readSettings(QSettings* qs) { - m_iconNames.clear(); m_names.clear(); + m_iconNames.clear(); + m_modeNames.clear(); qs->beginGroup(QLatin1String("Workspace")); m_numberOfWorkspaces = qs->value(QLatin1String("NumberOfWorkspaces"), 2).toInt(); + m_previousNumberOfWorkspaces = m_numberOfWorkspaces; for (int i = 1; i <= MAX_WORKSPACES; ++i) { QString numberString = QString::number(i); QString defaultName = "Workspace" + numberString; QString defaultIconName = "Icon" + numberString; - const QString name = qs->value(defaultName, defaultName).toString(); - const QString iconName = qs->value(defaultIconName, ":/core/images/openpilot_logo_64.png").toString(); - m_iconNames.append(iconName); + QString name = qs->value(defaultName, defaultName).toString(); + QString iconName = qs->value(defaultIconName, ":/core/images/openpilot_logo_64.png").toString(); m_names.append(name); + m_iconNames.append(iconName); + m_modeNames.append(QString("Mode")+ QString::number(i)); } + m_tabBarPlacementIndex = qs->value(QLatin1String("TabBarPlacementIndex"), 1).toInt(); // 1 == "Bottom" + m_allowTabBarMovement = qs->value(QLatin1String("AllowTabBarMovement"), false).toBool(); qs->endGroup(); + QTabWidget::TabPosition pos = m_tabBarPlacementIndex == 0 ? QTabWidget::North : QTabWidget::South; + emit tabBarSettingsApplied(pos, m_allowTabBarMovement); } void WorkspaceSettings::saveSettings(QSettings* qs) @@ -122,12 +133,16 @@ void WorkspaceSettings::saveSettings(QSettings* qs) qs->beginGroup(QLatin1String("Workspace")); qs->setValue(QLatin1String("NumberOfWorkspaces"), m_numberOfWorkspaces); for (int i = 0; i < MAX_WORKSPACES; ++i) { + QString mode = QString("Mode")+ QString::number(i+1); + int j = m_modeNames.indexOf(mode); QString numberString = QString::number(i+1); QString defaultName = "Workspace" + numberString; QString defaultIconName = "Icon" + numberString; - qs->setValue(defaultName, m_names.at(i)); - qs->setValue(defaultIconName, m_iconNames.at(i)); + qs->setValue(defaultName, m_names.at(j)); + qs->setValue(defaultIconName, m_iconNames.at(j)); } + qs->setValue(QLatin1String("TabBarPlacementIndex"), m_tabBarPlacementIndex); + qs->setValue(QLatin1String("AllowTabBarMovement"), m_allowTabBarMovement); qs->endGroup(); } @@ -137,15 +152,23 @@ void WorkspaceSettings::apply() saveSettings(Core::ICore::instance()->settings()); + if (m_numberOfWorkspaces != m_previousNumberOfWorkspaces) { + Core::ICore::instance()->readMainSettings(Core::ICore::instance()->settings(), true); + m_previousNumberOfWorkspaces = m_numberOfWorkspaces; + } + ModeManager* modeManager = Core::ICore::instance()->modeManager(); for (int i = 0; i < MAX_WORKSPACES; ++i) { - Core::Internal::UAVGadgetMode *mode = - qobject_cast(modeManager->mode(modeName(i))); + IMode *baseMode = modeManager->mode(modeName(i)); + Core::UAVGadgetManager *mode = qobject_cast(baseMode); if (mode) { modeManager->updateModeNameIcon(mode, QIcon(iconName(i)), name(i)); } } - + m_tabBarPlacementIndex = m_page->comboBoxTabBarPlacement->currentIndex(); + m_allowTabBarMovement = m_page->checkBoxAllowTabMovement->isChecked(); + QTabWidget::TabPosition pos = m_tabBarPlacementIndex == 0 ? QTabWidget::North : QTabWidget::South; + emit tabBarSettingsApplied(pos, m_allowTabBarMovement); } void WorkspaceSettings::finish() @@ -186,8 +209,8 @@ void WorkspaceSettings::selectWorkspace(int index, bool store) // write old values of workspace not shown anymore m_iconNames.replace(m_currentIndex, m_page->iconPathChooser->path()); m_names.replace(m_currentIndex, m_page->nameEdit->text()); - m_page->workspaceComboBox->setItemIcon(m_currentIndex, QIcon(m_page->iconPathChooser->path())); - m_page->workspaceComboBox->setItemText(m_currentIndex, m_page->nameEdit->text()); + m_page->workspaceComboBox->setItemIcon(m_currentIndex, QIcon(m_iconNames.at(m_currentIndex))); + m_page->workspaceComboBox->setItemText(m_currentIndex, m_names.at(m_currentIndex)); } // display current workspace @@ -196,3 +219,34 @@ void WorkspaceSettings::selectWorkspace(int index, bool store) m_page->nameEdit->setText(m_names.at(index)); m_currentIndex = index; } + +void WorkspaceSettings::newModeOrder(QVector modes) +{ + QList priorities; + QStringList modeNames; + for (int i = 0; i < modes.count(); ++i) { + Core::UAVGadgetManager *mode = qobject_cast(modes.at(i)); + if (mode) { + priorities.append(mode->priority()); + modeNames.append(mode->uniqueModeName()); + } + } + // Bubble sort + bool swapped = false; + do { + swapped = false; + for (int i = 0; i < m_names.count()-1; ++i) { + int j = i+1; + int p = modeNames.indexOf(m_modeNames.at(i)); + int q = modeNames.indexOf(m_modeNames.at(j)); + bool nonShowingMode = (p == -1 && q >=0); + bool pqBothFound = (p >= 0 && q >= 0); + if (nonShowingMode || (pqBothFound && (priorities.at(q) > priorities.at(p)))) { + m_names.swap(i, j); + m_iconNames.swap(i, j); + m_modeNames.swap(i, j); + swapped = true; + } + } + } while (swapped); +} diff --git a/ground/openpilotgcs/src/plugins/coreplugin/workspacesettings.h b/ground/openpilotgcs/src/plugins/coreplugin/workspacesettings.h index 15a98eaf2..ba790de56 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/workspacesettings.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/workspacesettings.h @@ -31,12 +31,14 @@ #include #include #include +#include class QSettings; namespace Core { class ModeManager; + class IMode; namespace Internal { @@ -65,24 +67,29 @@ public: int numberOfWorkspaces() const { return m_numberOfWorkspaces;} QString iconName(int i) const { return m_iconNames.at(i);} QString name(int i) const { return m_names.at(i);} - QString modeName(int i) const { return QString("Mode")+ QString::number(i+1);} + QString modeName(int i) const { return m_modeNames.at(i);} signals: + void tabBarSettingsApplied(QTabWidget::TabPosition pos, bool movable); public slots: void selectWorkspace(int index, bool store = false); void numberOfWorkspacesChanged(int value); void textEdited(QString string); void iconChanged(); + void newModeOrder(QVector modes); + private: Ui::WorkspaceSettings *m_page; QStringList m_iconNames; QStringList m_names; + QStringList m_modeNames; int m_currentIndex; + int m_previousNumberOfWorkspaces; int m_numberOfWorkspaces; + int m_tabBarPlacementIndex; + bool m_allowTabBarMovement; static const int MAX_WORKSPACES; - - }; } // namespace Internal diff --git a/ground/openpilotgcs/src/plugins/coreplugin/workspacesettings.ui b/ground/openpilotgcs/src/plugins/coreplugin/workspacesettings.ui index 8e19687df..1c646b693 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/workspacesettings.ui +++ b/ground/openpilotgcs/src/plugins/coreplugin/workspacesettings.ui @@ -6,7 +6,7 @@ 0 0 - 400 + 414 320 @@ -145,11 +145,71 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note:</span> A restart is needed for changes to number of workspaces to take effect.</p></body></html> - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note:</span> A restart is needed for changes to number of workspaces to take effect.</p></body></html> + + + +
+ + + + + + + Workspace panel + + + + + + Placement: + + + + + + + + + 1 + + + + Top + + + + + Bottom + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Allow reordering: + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/dial/dialgadgetfactory.cpp b/ground/openpilotgcs/src/plugins/dial/dialgadgetfactory.cpp index c267b4ee3..88cb6a024 100644 --- a/ground/openpilotgcs/src/plugins/dial/dialgadgetfactory.cpp +++ b/ground/openpilotgcs/src/plugins/dial/dialgadgetfactory.cpp @@ -34,7 +34,7 @@ DialGadgetFactory::DialGadgetFactory(QObject *parent) : IUAVGadgetFactory(QString("DialGadget"), - tr("Analog Dial Gadget"), + tr("Analog Dial"), parent) { } diff --git a/ground/openpilotgcs/src/plugins/dial/dialgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/dial/dialgadgetwidget.cpp index a3bdebe42..ba6f35f19 100644 --- a/ground/openpilotgcs/src/plugins/dial/dialgadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/dial/dialgadgetwidget.cpp @@ -478,13 +478,13 @@ void DialGadgetWidget::setDialFont(QString fontProps) // this enables smooth rotation in rotateNeedles below void DialGadgetWidget::setNeedle1(double value) { if (rotateN1) { - needle1Target = 360*(value*n1Factor-n1MinValue)/(n1MaxValue-n1MinValue); + needle1Target = 360*(value*n1Factor)/(n1MaxValue-n1MinValue); } if (horizN1) { - needle1Target = (value*n1Factor-n1MinValue)/(n1MaxValue-n1MinValue); + needle1Target = (value*n1Factor)/(n1MaxValue-n1MinValue); } if (vertN1) { - needle1Target = (value*n1Factor-n1MinValue)/(n1MaxValue-n1MinValue); + needle1Target = (value*n1Factor)/(n1MaxValue-n1MinValue); } if (!dialTimer.isActive()) dialTimer.start(); @@ -497,13 +497,13 @@ void DialGadgetWidget::setNeedle1(double value) { void DialGadgetWidget::setNeedle2(double value) { if (rotateN2) { - needle2Target = 360*(value*n2Factor-n2MinValue)/(n2MaxValue-n2MinValue); + needle2Target = 360*(value*n2Factor)/(n2MaxValue-n2MinValue); } if (horizN2) { - needle2Target = (value*n2Factor-n2MinValue)/(n2MaxValue-n2MinValue); + needle2Target = (value*n2Factor)/(n2MaxValue-n2MinValue); } if (vertN2) { - needle2Target = (value*n2Factor-n2MinValue)/(n2MaxValue-n2MinValue); + needle2Target = (value*n2Factor)/(n2MaxValue-n2MinValue); } if (!dialTimer.isActive()) dialTimer.start(); @@ -517,13 +517,13 @@ void DialGadgetWidget::setNeedle2(double value) { void DialGadgetWidget::setNeedle3(double value) { if (rotateN3) { - needle3Target = 360*(value*n3Factor-n3MinValue)/(n3MaxValue-n3MinValue); + needle3Target = 360*(value*n3Factor)/(n3MaxValue-n3MinValue); } if (horizN3) { - needle3Target = (value*n3Factor-n3MinValue)/(n3MaxValue-n3MinValue); + needle3Target = (value*n3Factor)/(n3MaxValue-n3MinValue); } if (vertN3) { - needle3Target = (value*n3Factor-n3MinValue)/(n3MaxValue-n3MinValue); + needle3Target = (value*n3Factor)/(n3MaxValue-n3MinValue); } if (!dialTimer.isActive()) dialTimer.start(); diff --git a/ground/openpilotgcs/src/plugins/gcscontrol/gcscontrolgadget.cpp b/ground/openpilotgcs/src/plugins/gcscontrol/gcscontrolgadget.cpp index 9480d789e..3c00987f7 100644 --- a/ground/openpilotgcs/src/plugins/gcscontrol/gcscontrolgadget.cpp +++ b/ground/openpilotgcs/src/plugins/gcscontrol/gcscontrolgadget.cpp @@ -283,8 +283,8 @@ void GCSControlGadget::buttonState(ButtonNumber number, bool pressed) void GCSControlGadget::axesValues(QListInt16 values) { int chMax = values.length(); - if (rollChannel > chMax || pitchChannel > chMax || - yawChannel > chMax || throttleChannel > chMax ) { + if (rollChannel >= chMax || pitchChannel >= chMax || + yawChannel >= chMax || throttleChannel >= chMax ) { qDebug() << "GCSControl: configuration is inconsistent with current joystick! Aborting update."; return; } diff --git a/ground/openpilotgcs/src/plugins/gcscontrol/gcscontrolgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/gcscontrol/gcscontrolgadgetwidget.cpp index 287479d8d..d266ec18b 100644 --- a/ground/openpilotgcs/src/plugins/gcscontrol/gcscontrolgadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/gcscontrol/gcscontrolgadgetwidget.cpp @@ -73,8 +73,10 @@ GCSControlGadgetWidget::GCSControlGadgetWidget(QWidget *parent) : QLabel(parent) rightX = 0; rightY = 0; - m_gcscontrol->widgetLeftStick->enableOpenGL(true); - m_gcscontrol->widgetRightStick->enableOpenGL(true); + // No point enabling OpenGL for the joysticks, and causes + // issues on some computers: +// m_gcscontrol->widgetLeftStick->enableOpenGL(true); +// m_gcscontrol->widgetRightStick->enableOpenGL(true); } GCSControlGadgetWidget::~GCSControlGadgetWidget() diff --git a/ground/openpilotgcs/src/plugins/gpsdisplay/gpsdisplaygadgetfactory.cpp b/ground/openpilotgcs/src/plugins/gpsdisplay/gpsdisplaygadgetfactory.cpp index 673891a16..e87290cba 100644 --- a/ground/openpilotgcs/src/plugins/gpsdisplay/gpsdisplaygadgetfactory.cpp +++ b/ground/openpilotgcs/src/plugins/gpsdisplay/gpsdisplaygadgetfactory.cpp @@ -33,7 +33,7 @@ GpsDisplayGadgetFactory::GpsDisplayGadgetFactory(QObject *parent) : IUAVGadgetFactory(QString("GpsDisplayGadget"), - tr("GPS Display Gadget"), + tr("GPS Display"), parent) { } diff --git a/ground/openpilotgcs/src/plugins/hitlnew/hitlwidget.cpp b/ground/openpilotgcs/src/plugins/hitlnew/hitlwidget.cpp index 1678e64a5..f965b5ad3 100644 --- a/ground/openpilotgcs/src/plugins/hitlnew/hitlwidget.cpp +++ b/ground/openpilotgcs/src/plugins/hitlnew/hitlwidget.cpp @@ -46,23 +46,23 @@ HITLWidget::HITLWidget(QWidget *parent) : QWidget(parent), simulator(0) { - widget = new Ui_HITLWidget(); - widget->setupUi(this); + widget = new Ui_HITLWidget(); + widget->setupUi(this); widget->startButton->setEnabled(true); widget->stopButton->setEnabled(false); greenColor = "rgb(35, 221, 35)"; - strAutopilotDisconnected = " Autopilot disconnected "; - strSimulatorDisconnected = " Simulator disconnected "; - strAutopilotConnected = " Autopilot connected "; - strSimulatorConnected = " Simulator connected "; + strAutopilotDisconnected = " Autopilot OFF "; + strSimulatorDisconnected = " Simulator OFF "; + strAutopilotConnected = " Autopilot ON "; + strSimulatorConnected = " Simulator ON "; widget->apLabel->setText(strAutopilotDisconnected); widget->simLabel->setText(strSimulatorDisconnected); - connect(widget->startButton, SIGNAL(clicked()), this, SLOT(startButtonClicked())); - connect(widget->stopButton, SIGNAL(clicked()), this, SLOT(stopButtonClicked())); + connect(widget->startButton, SIGNAL(clicked()), this, SLOT(startButtonClicked())); + connect(widget->stopButton, SIGNAL(clicked()), this, SLOT(stopButtonClicked())); connect(widget->buttonClearLog, SIGNAL(clicked()), this, SLOT(buttonClearLogClicked())); } @@ -188,10 +188,9 @@ void HITLWidget::buttonClearLogClicked() void HITLWidget::onAutopilotConnect() { - widget->simLabel->setStyleSheet(QString::fromUtf8("QFrame{\n""background-color: %1; color: white}").arg(greenColor)); - + widget->apLabel->setStyleSheet(QString::fromUtf8("QFrame{\n""background-color: %1; color: white}").arg(greenColor)); widget->apLabel->setText(strAutopilotConnected); - qxtLog->info("HITL: Autopilot connected, initializing for HITL simulation"); + qxtLog->info("HITL: Autopilot connected, initializing for HITL simulation"); } void HITLWidget::onAutopilotDisconnect() @@ -214,5 +213,3 @@ void HITLWidget::onSimulatorDisconnect() widget->simLabel->setText(" " + simulator->Name() +" disconnected "); qxtLog->info(QString("HITL: %1 disconnected").arg(simulator->Name())); } - - diff --git a/ground/openpilotgcs/src/plugins/importexport/importexport.pro b/ground/openpilotgcs/src/plugins/importexport/importexport.pro index e3ae374a9..3c9b6ba13 100644 --- a/ground/openpilotgcs/src/plugins/importexport/importexport.pro +++ b/ground/openpilotgcs/src/plugins/importexport/importexport.pro @@ -6,21 +6,10 @@ include(../../openpilotgcsplugin.pri) include(importexport_dependencies.pri) HEADERS += importexportplugin.h \ importexportgadgetwidget.h \ - importexportdialog.h \ - xmlconfig.h -HEADERS += importexportgadget.h -HEADERS += importexportgadgetfactory.h -HEADERS += importexportgadgetconfiguration.h -HEADERS += importexportgadgetoptionspage.h + importexportdialog.h SOURCES += importexportplugin.cpp \ importexportgadgetwidget.cpp \ - importexportdialog.cpp \ - xmlconfig.cpp -SOURCES += importexportgadget.cpp -SOURCES += importexportgadgetfactory.cpp -SOURCES += importexportgadgetconfiguration.cpp -SOURCES += importexportgadgetoptionspage.cpp + importexportdialog.cpp OTHER_FILES += ImportExportGadget.pluginspec -FORMS += importexportgadgetoptionspage.ui \ - importexportgadgetwidget.ui \ +FORMS += importexportgadgetwidget.ui \ importexportdialog.ui diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportdialog.cpp b/ground/openpilotgcs/src/plugins/importexport/importexportdialog.cpp index 74efb81e1..df38653f8 100644 --- a/ground/openpilotgcs/src/plugins/importexport/importexportdialog.cpp +++ b/ground/openpilotgcs/src/plugins/importexport/importexportdialog.cpp @@ -1,12 +1,11 @@ #include "importexportdialog.h" #include "ui_importexportdialog.h" -ImportExportDialog::ImportExportDialog( ImportExportGadgetConfiguration *config, QWidget *parent) : +ImportExportDialog::ImportExportDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ImportExportDialog) { ui->setupUi(this); - ui->widget->loadConfiguration(config); setWindowTitle(tr("Import Export Settings")); connect( ui->widget, SIGNAL(done()), this, SLOT(close())); diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportdialog.h b/ground/openpilotgcs/src/plugins/importexport/importexportdialog.h index e93addd77..008d588d1 100644 --- a/ground/openpilotgcs/src/plugins/importexport/importexportdialog.h +++ b/ground/openpilotgcs/src/plugins/importexport/importexportdialog.h @@ -27,7 +27,6 @@ #define IMPORTEXPORTDIALOG_H #include -#include "importexportgadgetconfiguration.h" namespace Ui { class ImportExportDialog; @@ -38,7 +37,7 @@ class ImportExportDialog : public QDialog Q_OBJECT public: - explicit ImportExportDialog( ImportExportGadgetConfiguration *config, QWidget *parent = 0); + explicit ImportExportDialog(QWidget *parent = 0); ~ImportExportDialog(); protected: diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportdialog.ui b/ground/openpilotgcs/src/plugins/importexport/importexportdialog.ui index eca016fc4..3c0fca682 100644 --- a/ground/openpilotgcs/src/plugins/importexport/importexportdialog.ui +++ b/ground/openpilotgcs/src/plugins/importexport/importexportdialog.ui @@ -23,7 +23,7 @@ Qt::Horizontal - QDialogButtonBox::Cancel + QDialogButtonBox::Close diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetconfiguration.cpp b/ground/openpilotgcs/src/plugins/importexport/importexportgadgetconfiguration.cpp deleted file mode 100644 index 8e97c9bec..000000000 --- a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetconfiguration.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/** - ****************************************************************************** - * - * @file importexportgadgetconfiguration.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @see The GNU Public License (GPL) Version 3 - * @brief Configuration for Import/Export Plugin - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup importexportplugin - * @{ - * - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "importexportgadgetconfiguration.h" - -static const QString VERSION = "1.0.1"; - -/** - * Loads a saved configuration or defaults if non exist. - * - */ -ImportExportGadgetConfiguration::ImportExportGadgetConfiguration(QString classId, QSettings* qSettings, UAVConfigInfo *configInfo, QObject *parent) : - IUAVGadgetConfiguration(classId, parent) -{ - if ( ! qSettings ) - return; - - if ( configInfo->version() == UAVConfigVersion() ) - configInfo->setVersion("1.0.0"); - - if ( !configInfo->standardVersionHandlingOK(VERSION)) - return; - - iniFile = qSettings->value("iniFile", "gcs.xml").toString(); -} - -/** - * Clones a configuration. - * - */ -IUAVGadgetConfiguration *ImportExportGadgetConfiguration::clone() -{ - ImportExportGadgetConfiguration *m = new ImportExportGadgetConfiguration(this->classId()); - m->iniFile = iniFile; - return m; -} - -/** - * Saves a configuration. - * - */ -void ImportExportGadgetConfiguration::saveConfig(QSettings* qSettings, Core::UAVConfigInfo *configInfo) const { - configInfo->setVersion(VERSION); - qSettings->setValue("iniFile", iniFile); -} - -/** - * @} - * @} - */ diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetconfiguration.h b/ground/openpilotgcs/src/plugins/importexport/importexportgadgetconfiguration.h deleted file mode 100644 index 21a87ff27..000000000 --- a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetconfiguration.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - ****************************************************************************** - * @file - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @see The GNU Public License (GPL) Version 3 - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup importexportplugin - * @{ - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef IMPORTEXPORTGADGETCONFIGURATION_H -#define IMPORTEXPORTGADGETCONFIGURATION_H - -#include -#include "importexport_global.h" - -using namespace Core; - -/* This is a generic bargraph dial - supporting one indicator. - */ -class IMPORTEXPORT_EXPORT ImportExportGadgetConfiguration : public IUAVGadgetConfiguration -{ - Q_OBJECT -public: - ImportExportGadgetConfiguration(QString classId, QSettings* qSettings = 0, UAVConfigInfo *configInfo = 0, QObject *parent = 0); - - //set dial configuration functions - void setIniFile(QString filename) { - iniFile = filename; - } - - //get dial configuration functions - QString getIniFile() const{ - return iniFile; - } - - void saveConfig(QSettings* settings, Core::UAVConfigInfo *configInfo) const; - IUAVGadgetConfiguration *clone(); - -private: - QString iniFile; -}; - -#endif // IMPORTEXPORTGADGETCONFIGURATION_H -/** - * @} - * @} - */ diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetfactory.cpp b/ground/openpilotgcs/src/plugins/importexport/importexportgadgetfactory.cpp deleted file mode 100644 index b9d93fde3..000000000 --- a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetfactory.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/** - ****************************************************************************** - * - * @file importexportgadgetfactory.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @see The GNU Public License (GPL) Version 3 - * @brief Factory for Import/Export Plugin - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup importexportplugin - * @{ - * - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "importexportgadgetfactory.h" -#include "importexportgadgetwidget.h" -#include "importexportgadget.h" -#include "importexportgadgetconfiguration.h" -#include "importexportgadgetoptionspage.h" -#include - -ImportExportGadgetFactory::ImportExportGadgetFactory(QObject *parent) : - IUAVGadgetFactory(QString("ImportExportGadget"), - tr("Import/Export GCS Config"), - parent) -{ -} - -ImportExportGadgetFactory::~ImportExportGadgetFactory() -{ -} - -Core::IUAVGadget* ImportExportGadgetFactory::createGadget(QWidget *parent) -{ - ImportExportGadgetWidget* gadgetWidget = new ImportExportGadgetWidget(parent); - return new ImportExportGadget(QString("ImportExportGadget"), gadgetWidget, parent); -} - -IUAVGadgetConfiguration *ImportExportGadgetFactory::createConfiguration(QSettings* qSettings, UAVConfigInfo *configInfo) -{ - lastConfig = new ImportExportGadgetConfiguration(QString("ImportExportGadget"), qSettings, configInfo); - return lastConfig; -} - -IOptionsPage *ImportExportGadgetFactory::createOptionsPage(IUAVGadgetConfiguration *config) -{ - return new ImportExportGadgetOptionsPage(qobject_cast(config)); -} - -/** - * @} - * @} - */ diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetoptionspage.cpp b/ground/openpilotgcs/src/plugins/importexport/importexportgadgetoptionspage.cpp deleted file mode 100644 index ade45bb5f..000000000 --- a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetoptionspage.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/** - ****************************************************************************** - * - * @file importexportgadgetoptionspage.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @see The GNU Public License (GPL) Version 3 - * @brief Option page for Import/Export Plugin - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup importexportplugin - * @{ - * - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "importexportgadgetoptionspage.h" -#include "importexportgadgetconfiguration.h" -#include "ui_importexportgadgetoptionspage.h" - -#include -#include - -ImportExportGadgetOptionsPage::ImportExportGadgetOptionsPage(ImportExportGadgetConfiguration *config, QObject *parent) : - IOptionsPage(parent), - m_config(config) -{ -} - -//creates options page widget (uses the UI file) -QWidget *ImportExportGadgetOptionsPage::createPage(QWidget *parent) -{ - - options_page = new Ui::ImportExportGadgetOptionsPage(); - //main widget - QWidget *optionsPageWidget = new QWidget; - //main layout - options_page->setupUi(optionsPageWidget); - - // Restore the contents from the settings: - options_page->iniFile->setExpectedKind(Utils::PathChooser::File); - options_page->iniFile->setPromptDialogFilter(tr("INI file (*.ini);; XML file (*.xml)")); - options_page->iniFile->setPromptDialogTitle(tr("Choose configuration file")); - options_page->iniFile->setPath(m_config->getIniFile()); - - return optionsPageWidget; -} - -/** - * Called when the user presses apply or OK. - * - * Saves the current values - * - */ -void ImportExportGadgetOptionsPage::apply() -{ - m_config->setIniFile(options_page->iniFile->path()); -} - - -void ImportExportGadgetOptionsPage::finish() -{ - -} -/** - * @} - * @} - */ diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetoptionspage.ui b/ground/openpilotgcs/src/plugins/importexport/importexportgadgetoptionspage.ui deleted file mode 100644 index 176d5dd6c..000000000 --- a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetoptionspage.ui +++ /dev/null @@ -1,103 +0,0 @@ - - - ImportExportGadgetOptionsPage - - - - 0 - 0 - 486 - 300 - - - - - 0 - 0 - - - - Form - - - - - -1 - -1 - 485 - 339 - - - - - QLayout::SetMinimumSize - - - 10 - - - 5 - - - 10 - - - 10 - - - - - 10 - - - QLayout::SetMaximumSize - - - 10 - - - - - Default Config File - - - - - - - - 0 - 0 - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Utils::PathChooser - QWidget -
utils/pathchooser.h
- 1 -
-
- - -
diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/importexport/importexportgadgetwidget.cpp index da8a284af..6e1d4d2c3 100644 --- a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/importexport/importexportgadgetwidget.cpp @@ -28,7 +28,7 @@ */ #include "importexportgadgetwidget.h" #include "ui_importexportgadgetwidget.h" -#include "xmlconfig.h" +#include "utils/xmlconfig.h" #include "coreplugin/uavgadgetinstancemanager.h" #include "coreplugin/icore.h" #include @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -47,11 +48,8 @@ ImportExportGadgetWidget::ImportExportGadgetWidget(QWidget *parent) : { setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); ui->setupUi(this); - ui->configFile->setExpectedKind(Utils::PathChooser::File); - ui->configFile->setPromptDialogFilter(tr("INI file (*.ini);; XML file (*.xml)")); - ui->configFile->setPromptDialogTitle(tr("Choose configuration file")); - + filename = ""; } ImportExportGadgetWidget::~ImportExportGadgetWidget() @@ -70,33 +68,24 @@ void ImportExportGadgetWidget::changeEvent(QEvent *e) break; } } -void ImportExportGadgetWidget::loadConfiguration(const ImportExportGadgetConfiguration* config) -{ - if ( !config ) - return; - - ui->configFile->setPath(config->getIniFile()); -} void ImportExportGadgetWidget::on_exportButton_clicked() { - QString file = ui->configFile->path(); + QString file = filename; + QString filter = tr("GCS Settings file (*.xml)"); + file = QFileDialog::getSaveFileName(this, tr("Save GCS Settings too file .."), QFileInfo(file).absoluteFilePath(), filter).trimmed(); + if (file.isEmpty()) { + return; + } + + // Add a "XML" extension to the file in case it does not exist: + if (!file.toLower().endsWith(".xml")) + file.append(".xml"); + + filename = file; + qDebug() << "Export pressed! Write to file " << QFileInfo(file).absoluteFilePath(); - if ( QFileInfo(file).exists() ){ - QMessageBox msgBox; - msgBox.setText(tr("File already exists.")); - msgBox.setInformativeText(tr("Do you want to overwrite the existing file?")); - msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - msgBox.setDefaultButton(QMessageBox::Ok); - if ( msgBox.exec() == QMessageBox::Ok ){ - QFileInfo(file).absoluteDir().remove(QFileInfo(file).fileName()); - } - else{ - qDebug() << "Export canceled!"; - return; - } - } QMessageBox msgBox; QDir dir = QFileInfo(file).absoluteDir(); if (! dir.exists()) { @@ -133,18 +122,7 @@ void ImportExportGadgetWidget::exportConfiguration(const QString& fileName) bool doAllGadgets = ui->checkBoxAllGadgets->isChecked(); bool doPlugins = ui->checkBoxPlugins->isChecked(); - QSettings::Format format; - if ( ui->radioButtonIniFormat->isChecked() ){ - format = QSettings::IniFormat; - } - else if ( ui->radioButtonXmlFormat->isChecked() ){ - format = XmlConfig::XmlSettingsFormat; - } - else { - qWarning() << "Program Error in ImportExportGadgetWidget::exportConfiguration: unknown format. Assume XML!"; - format = XmlConfig::XmlSettingsFormat; - } - + QSettings::Format format = XmlConfig::XmlSettingsFormat; QSettings qs(fileName, format); if (doGeneral) { @@ -170,8 +148,17 @@ void ImportExportGadgetWidget::writeError(const QString& msg) const void ImportExportGadgetWidget::on_importButton_clicked() { - QString file = ui->configFile->path(); + QString file = filename; + QString filter = tr("GCS Settings file (*.xml)"); + file = QFileDialog::getOpenFileName(this, tr("Load GCS Settings from file .."), QFileInfo(file).absoluteFilePath(), filter).trimmed(); + if (file.isEmpty()) { + return; + } + + filename = file; + qDebug() << "Import pressed! Read from file " << QFileInfo(file).absoluteFilePath(); + QMessageBox msgBox; if (! QFileInfo(file).isReadable()) { msgBox.setText(tr("Can't read file ") + QFileInfo(file).absoluteFilePath()); @@ -193,19 +180,7 @@ void ImportExportGadgetWidget::importConfiguration(const QString& fileName) bool doAllGadgets = ui->checkBoxAllGadgets->isChecked(); bool doPlugins = ui->checkBoxPlugins->isChecked(); - QSettings::Format format; - if ( ui->radioButtonIniFormat->isChecked() ){ - format = QSettings::IniFormat; - } - else if ( ui->radioButtonXmlFormat->isChecked() ){ - format = XmlConfig::XmlSettingsFormat; - } - else { - qWarning() << "Program Error in ImportExportGadgetWidget::exportConfiguration: unknown format. Assume XML!"; - format = XmlConfig::XmlSettingsFormat; - } - - QSettings qs(fileName, format); + QSettings qs(fileName, XmlConfig::XmlSettingsFormat); if ( doAllGadgets ) { Core::ICore::instance()->uavGadgetInstanceManager()->readSettings(&qs); diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetwidget.h b/ground/openpilotgcs/src/plugins/importexport/importexportgadgetwidget.h index 37393678c..bb6d46aa3 100644 --- a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetwidget.h +++ b/ground/openpilotgcs/src/plugins/importexport/importexportgadgetwidget.h @@ -13,8 +13,8 @@ #include #include +#include "importexport_global.h" #include -#include "importexportgadgetconfiguration.h" namespace Ui { @@ -28,8 +28,6 @@ public: ImportExportGadgetWidget(QWidget *parent = 0); ~ImportExportGadgetWidget(); - void loadConfiguration(const ImportExportGadgetConfiguration* config); - signals: void done(); @@ -43,8 +41,10 @@ private: void importConfiguration(const QString& fileName); QList getConfigurables(); + QString filename; + private slots: - void on_resetButton_clicked(); + void on_resetButton_clicked(); void on_helpButton_clicked(); void on_importButton_clicked(); void on_exportButton_clicked(); diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetwidget.ui b/ground/openpilotgcs/src/plugins/importexport/importexportgadgetwidget.ui index 2aba80711..a4631aba0 100644 --- a/ground/openpilotgcs/src/plugins/importexport/importexportgadgetwidget.ui +++ b/ground/openpilotgcs/src/plugins/importexport/importexportgadgetwidget.ui @@ -7,147 +7,120 @@ 0 0 483 - 271 + 174 Form - - - + + + - - - - 0 - 0 - - - - Config File + + + Items + + + + + General (Workspace, Key-Bindings) + + + true + + + + + + + All Gadgets + + + true + + + + + + + Plugins + + + true + + + + - - - - 0 - 0 - - - + + + + + + 32 + 32 + + + + + + + + :/core/images/helpicon.svg:/core/images/helpicon.svg + + + + 32 + 32 + + + + true + + + + + + + Export the GCS settings selected in the checkboxes above. + + + Export... + + + + + + + Import settings from the config file, only for the items checked above. + + + Import... + + + + + + + Resets your GCS configuration to its default configuration. + + + Reset Config + + + + - - - - Items - - - - - - General (Workspace, Key-Bindings) - - - true - - - - - - - All Gadgets - - - true - - - - - - - Plugins - - - true - - - - - - - - - - - - Export - - - - - - - Import - - - - - - - Reset Config - - - - - - - Help - - - - - - - - - Format - - - - - - XML Format - - - true - - - - - - - INI Format - - - - - - - - - Utils::PathChooser - QWidget -
utils/pathchooser.h
- 1 -
-
- + + + diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportplugin.cpp b/ground/openpilotgcs/src/plugins/importexport/importexportplugin.cpp index 44d2b82a1..d7fa31a54 100644 --- a/ground/openpilotgcs/src/plugins/importexport/importexportplugin.cpp +++ b/ground/openpilotgcs/src/plugins/importexport/importexportplugin.cpp @@ -4,7 +4,7 @@ * @file importexportplugin.cpp * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @see The GNU Public License (GPL) Version 3 - * @brief Import/Export Plugin + * @brief Import/Export Plugin for GCS Settings * @addtogroup GCSPlugins GCS Plugins * @{ * @defgroup importexportplugin @@ -28,7 +28,6 @@ */ #include "importexportplugin.h" -#include "importexportgadgetfactory.h" #include "importexportdialog.h" #include #include @@ -55,8 +54,6 @@ bool ImportExportPlugin::initialize(const QStringList& args, QString *errMsg) { Q_UNUSED(args); Q_UNUSED(errMsg); - mf = new ImportExportGadgetFactory(this); - addAutoReleasedObject(mf); // Add Menu entry Core::ActionManager* am = Core::ICore::instance()->actionManager(); @@ -66,7 +63,7 @@ bool ImportExportPlugin::initialize(const QStringList& args, QString *errMsg) "ImportExportPlugin.ImportExport", QList() << Core::Constants::C_GLOBAL_ID); - cmd->setDefaultKeySequence(QKeySequence("Ctrl+I")); + cmd->setDefaultKeySequence(QKeySequence("Ctrl+S")); cmd->action()->setText(tr("GCS Settings Import/Export...")); // ac->menu()->addSeparator(); @@ -82,7 +79,7 @@ bool ImportExportPlugin::initialize(const QStringList& args, QString *errMsg) void ImportExportPlugin::importExport() { - ImportExportDialog(mf->getLastConfig()).exec(); + ImportExportDialog().exec(); } void ImportExportPlugin::extensionsInitialized() diff --git a/ground/openpilotgcs/src/plugins/importexport/importexportplugin.h b/ground/openpilotgcs/src/plugins/importexport/importexportplugin.h index 91b3ed901..7070ce56c 100644 --- a/ground/openpilotgcs/src/plugins/importexport/importexportplugin.h +++ b/ground/openpilotgcs/src/plugins/importexport/importexportplugin.h @@ -30,8 +30,6 @@ #include #include "importexport_global.h" -class ImportExportGadgetFactory; - class IMPORTEXPORT_EXPORT ImportExportPlugin : public ExtensionSystem::IPlugin { Q_OBJECT @@ -44,7 +42,6 @@ public: bool initialize(const QStringList & arguments, QString * errorString); void shutdown(); private: - ImportExportGadgetFactory *mf; private slots: void importExport(); diff --git a/ground/openpilotgcs/src/plugins/ipconnection/ipconnection.pri b/ground/openpilotgcs/src/plugins/ipconnection/ipconnection.pri index fc15b3efc..74f3f4380 100644 --- a/ground/openpilotgcs/src/plugins/ipconnection/ipconnection.pri +++ b/ground/openpilotgcs/src/plugins/ipconnection/ipconnection.pri @@ -1,3 +1,3 @@ include(ipconnection_dependencies.pri) -LIBS *= -l$$qtLibraryTarget(IPconnection) +LIBS *= -l$$qtLibraryName(IPconnection) diff --git a/ground/openpilotgcs/src/plugins/lineardial/lineardialgadgetfactory.cpp b/ground/openpilotgcs/src/plugins/lineardial/lineardialgadgetfactory.cpp index 33f6e0421..9e79256d3 100644 --- a/ground/openpilotgcs/src/plugins/lineardial/lineardialgadgetfactory.cpp +++ b/ground/openpilotgcs/src/plugins/lineardial/lineardialgadgetfactory.cpp @@ -33,7 +33,7 @@ LineardialGadgetFactory::LineardialGadgetFactory(QObject *parent) : IUAVGadgetFactory(QString("LineardialGadget"), - tr("Bargraph Dial Gadget"), + tr("Bargraph Dial"), parent) { } diff --git a/ground/openpilotgcs/src/plugins/lineardial/lineardialgadgetoptionspage.ui b/ground/openpilotgcs/src/plugins/lineardial/lineardialgadgetoptionspage.ui index 1d94b3cf4..9bf5c93e0 100644 --- a/ground/openpilotgcs/src/plugins/lineardial/lineardialgadgetoptionspage.ui +++ b/ground/openpilotgcs/src/plugins/lineardial/lineardialgadgetoptionspage.ui @@ -1,546 +1,507 @@ - - - LineardialGadgetOptionsPage - - - - 0 - 0 - 540 - 347 - - - - - 0 - 0 - - - - Form - - - - - -1 - -1 - 533 - 321 - - - - - QLayout::SetMinimumSize - - - 10 - - - 5 - - - 10 - - - 10 - - - - - - - Use OpenGL - - - true - - - - - - - - - Qt::Horizontal - - - - - - - 10 - - - QLayout::SetMaximumSize - - - 10 - - - - - Dial SVG: - - - - - - - - 0 - 0 - - - - - - - - - - - - - 0 - 0 - - - - Whole range: - - - - - - - Min: - - - - - - - - 0 - 0 - - - - 3 - - - -99999.000000000000000 - - - 99999.990000000005239 - - - - - - - Max: - - - - - - - - 0 - 0 - - - - 3 - - - -99999.000000000000000 - - - 99999.990000000005239 - - - - - - - - - Qt::Horizontal - - - - - - - - - - 0 - 0 - - - - Green: - - - - - - - Min: - - - - - - - - 0 - 0 - - - - 3 - - - -99999.000000000000000 - - - 99999.990000000005239 - - - - - - - Max: - - - - - - - - 0 - 0 - - - - 3 - - - -99999.000000000000000 - - - 99999.990000000005239 - - - - - - - - - Qt::Horizontal - - - - - - - - - - 0 - 0 - - - - Yellow: - - - - - - - Min: - - - - - - - - 0 - 0 - - - - 3 - - - -99999.000000000000000 - - - 99999.990000000005239 - - - - - - - Max: - - - - - - - - 0 - 0 - - - - 3 - - - -99999.000000000000000 - - - 99999.990000000005239 - - - - - - - - - Qt::Horizontal - - - - - - - - - - 0 - 0 - - - - Red: - - - - - - - Min: - - - - - - - - 0 - 0 - - - - 3 - - - -99999.000000000000000 - - - 99999.990000000005239 - - - - - - - Max: - - - - - - - - 0 - 0 - - - - 3 - - - -99999.000000000000000 - - - 99999.990000000005239 - - - - - - - - - - - - 0 - 0 - - - - Input: - - - - - - - ObjectName - - - - - - - - 0 - 0 - - - - - - - - ObjectField - - - - - - - - 0 - 0 - - - - - - - - - - 0 - - - - - - 0 - 0 - - - - Dial font: - - - - - - - Select... - - - - - - - Decimal places: - - - - - - - 99 - - - - - - - Factor: - - - - - - - 6 - - - -10000.000000000000000 - - - 100000.000000000000000 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Utils::PathChooser - QWidget -
utils/pathchooser.h
- 1 -
-
- - -
+ + + LineardialGadgetOptionsPage + + + + 0 + 0 + 540 + 347 + + + + + 0 + 0 + + + + Form + + + + + + + + Use OpenGL + + + true + + + + + + + + + Qt::Horizontal + + + + + + + 10 + + + QLayout::SetMaximumSize + + + 10 + + + + + Dial SVG: + + + + + + + + 0 + 0 + + + + + + + + + + + + + 0 + 0 + + + + Whole range: + + + + + + + Min: + + + + + + + + 0 + 0 + + + + 3 + + + -99999.000000000000000 + + + 99999.990000000005239 + + + + + + + Max: + + + + + + + + 0 + 0 + + + + 3 + + + -99999.000000000000000 + + + 99999.990000000005239 + + + + + + + + + Qt::Horizontal + + + + + + + + + + 0 + 0 + + + + Green: + + + + + + + Min: + + + + + + + + 0 + 0 + + + + 3 + + + -99999.000000000000000 + + + 99999.990000000005239 + + + + + + + Max: + + + + + + + + 0 + 0 + + + + 3 + + + -99999.000000000000000 + + + 99999.990000000005239 + + + + + + + + + + + + 0 + 0 + + + + Yellow: + + + + + + + Min: + + + + + + + + 0 + 0 + + + + 3 + + + -99999.000000000000000 + + + 99999.990000000005239 + + + + + + + Max: + + + + + + + + 0 + 0 + + + + 3 + + + -99999.000000000000000 + + + 99999.990000000005239 + + + + + + + + + + + + 0 + 0 + + + + Red: + + + + + + + Min: + + + + + + + + 0 + 0 + + + + 3 + + + -99999.000000000000000 + + + 99999.990000000005239 + + + + + + + Max: + + + + + + + + 0 + 0 + + + + 3 + + + -99999.000000000000000 + + + 99999.990000000005239 + + + + + + + + + + + + 0 + 0 + + + + Input: + + + + + + + ObjectName + + + + + + + + 0 + 0 + + + + + + + + ObjectField + + + + + + + + 0 + 0 + + + + + + + + + + 0 + + + + + + 0 + 0 + + + + Dial font: + + + + + + + Select... + + + + + + + Decimal places: + + + + + + + 99 + + + + + + + Factor: + + + + + + + 6 + + + -10000.000000000000000 + + + 100000.000000000000000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Utils::PathChooser + QWidget +
utils/pathchooser.h
+ 1 +
+
+ + +
diff --git a/ground/openpilotgcs/src/plugins/logging/loggingplugin.cpp b/ground/openpilotgcs/src/plugins/logging/loggingplugin.cpp index d5e85ccae..6333c4e98 100644 --- a/ground/openpilotgcs/src/plugins/logging/loggingplugin.cpp +++ b/ground/openpilotgcs/src/plugins/logging/loggingplugin.cpp @@ -76,11 +76,10 @@ QIODevice* LoggingConnection::openDevice(const QString &deviceName) if (logFile.isOpen()){ logFile.close(); } - QFileDialog * fd = new QFileDialog(); - fd->setAcceptMode(QFileDialog::AcceptOpen); - fd->setNameFilter("OpenPilot Log (*.opl)"); - connect(fd, SIGNAL(fileSelected(QString)), this, SLOT(startReplay(QString))); - fd->exec(); + QString fileName = QFileDialog::getOpenFileName(NULL, tr("Open file"), QString(""), tr("OpenPilot Log (*.opl)")); + if (!fileName.isNull()) { + startReplay(fileName); + } return &logFile; } diff --git a/ground/openpilotgcs/src/plugins/modelview/modelviewgadgetfactory.cpp b/ground/openpilotgcs/src/plugins/modelview/modelviewgadgetfactory.cpp index a87bbbe75..090c6cc70 100644 --- a/ground/openpilotgcs/src/plugins/modelview/modelviewgadgetfactory.cpp +++ b/ground/openpilotgcs/src/plugins/modelview/modelviewgadgetfactory.cpp @@ -33,7 +33,7 @@ #include ModelViewGadgetFactory::ModelViewGadgetFactory(QObject *parent) : - IUAVGadgetFactory(QString("ModelViewGadget"), tr("ModelView Gadget"), parent) + IUAVGadgetFactory(QString("ModelViewGadget"), tr("ModelView"), parent) { } diff --git a/ground/openpilotgcs/src/plugins/modelview/modelviewgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/modelview/modelviewgadgetwidget.cpp index 09ffafd5a..6e1b2858d 100644 --- a/ground/openpilotgcs/src/plugins/modelview/modelviewgadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/modelview/modelviewgadgetwidget.cpp @@ -291,16 +291,12 @@ void ModelViewGadgetWidget::updateAttitude() { AttitudeActual::DataFields data = attActual->getData(); // get attitude data GLC_StructOccurence* rootObject= m_World.rootOccurence(); // get the full 3D model - // create quaternions rotations for each axis - QQuaternion qX= QQuaternion::fromAxisAndAngle(QVector3D(1,0,0),data.Pitch); - QQuaternion qY= QQuaternion::fromAxisAndAngle(QVector3D(0,1,0),data.Roll); - QQuaternion qZ= QQuaternion::fromAxisAndAngle(QVector3D(0,0,1),data.Yaw); - QQuaternion quat= qX * qY * qZ; // create the quaternion of all the rotations - // pass values to simpler variables - double x= quat.vector().x(); - double y= quat.vector().y(); - double z= quat.vector().z(); - double w= quat.scalar(); + double x= data.q3; + double y= data.q2; + double z= data.q4; + double w= data.q1; + if (w == 0.0) + w = 1.0; // create and gives the product of 2 4x4 matrices to get the rotation of the 3D model's matrix QMatrix4x4 m1; m1.setRow(0, QVector4D(w,z,-y,x)); diff --git a/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.ui b/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.ui index 3d6d77045..b3f48432a 100644 --- a/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.ui +++ b/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.ui @@ -31,7 +31,7 @@ Sound Collection - + 10 diff --git a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetconfiguration.cpp b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetconfiguration.cpp index 25069571f..67d1d1f98 100644 --- a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetconfiguration.cpp +++ b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetconfiguration.cpp @@ -1,102 +1,116 @@ -/** - ****************************************************************************** - * - * @file opmapgadgetconfiguration.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin OpenPilot Map Plugin - * @{ - * @brief The OpenPilot Map plugin - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "opmapgadgetconfiguration.h" -#include "utils/pathutils.h" -#include - -OPMapGadgetConfiguration::OPMapGadgetConfiguration(QString classId, QSettings* qSettings, QObject *parent) : - IUAVGadgetConfiguration(classId, parent), - m_mapProvider("GoogleHybrid"), - m_defaultZoom(2), - m_defaultLatitude(0), - m_defaultLongitude(0), - m_useOpenGL(false), - m_showTileGridLines(false), - m_accessMode("ServerAndCache"), - m_useMemoryCache(true), - m_cacheLocation(Utils::PathUtils().GetStoragePath() + "mapscache" + QDir::separator()), - m_uavSymbol(QString::fromUtf8(":/uavs/images/mapquad.png")) -{ - - //if a saved configuration exists load it - if(qSettings != 0) { - QString mapProvider = qSettings->value("mapProvider").toString(); - int zoom = qSettings->value("defaultZoom").toInt(); - double latitude= qSettings->value("defaultLatitude").toDouble(); - double longitude= qSettings->value("defaultLongitude").toDouble(); - bool useOpenGL= qSettings->value("useOpenGL").toBool(); - bool showTileGridLines= qSettings->value("showTileGridLines").toBool(); - QString accessMode= qSettings->value("accessMode").toString(); - bool useMemoryCache= qSettings->value("useMemoryCache").toBool(); - QString cacheLocation= qSettings->value("cacheLocation").toString(); - QString uavSymbol=qSettings->value("uavSymbol").toString(); - if (!mapProvider.isEmpty()) m_mapProvider = mapProvider; - m_defaultZoom = zoom; - m_defaultLatitude = latitude; - m_defaultLongitude = longitude; - m_useOpenGL = useOpenGL; - m_showTileGridLines = showTileGridLines; - m_uavSymbol=uavSymbol; - if (!accessMode.isEmpty()) m_accessMode = accessMode; - m_useMemoryCache = useMemoryCache; - if (!cacheLocation.isEmpty()) m_cacheLocation = Utils::PathUtils().InsertStoragePath(cacheLocation); - } -} - -IUAVGadgetConfiguration * OPMapGadgetConfiguration::clone() -{ - OPMapGadgetConfiguration *m = new OPMapGadgetConfiguration(this->classId()); - - m->m_mapProvider = m_mapProvider; - m->m_defaultZoom = m_defaultZoom; - m->m_defaultLatitude = m_defaultLatitude; - m->m_defaultLongitude = m_defaultLongitude; - m->m_useOpenGL = m_useOpenGL; - m->m_showTileGridLines = m_showTileGridLines; - m->m_accessMode = m_accessMode; - m->m_useMemoryCache = m_useMemoryCache; - m->m_cacheLocation = m_cacheLocation; - m->m_uavSymbol=m_uavSymbol; - return m; -} - -void OPMapGadgetConfiguration::saveConfig(QSettings* qSettings) const { - qSettings->setValue("mapProvider", m_mapProvider); - qSettings->setValue("defaultZoom", m_defaultZoom); - qSettings->setValue("defaultLatitude", m_defaultLatitude); - qSettings->setValue("defaultLongitude", m_defaultLongitude); - qSettings->setValue("useOpenGL", m_useOpenGL); - qSettings->setValue("showTileGridLines", m_showTileGridLines); - qSettings->setValue("accessMode", m_accessMode); - qSettings->setValue("useMemoryCache", m_useMemoryCache); - qSettings->setValue("uavSymbol", m_uavSymbol); - qSettings->setValue("cacheLocation", Utils::PathUtils().RemoveStoragePath(m_cacheLocation)); -} -void OPMapGadgetConfiguration::setCacheLocation(QString cacheLocation){ - m_cacheLocation = cacheLocation; -} +/** + ****************************************************************************** + * + * @file opmapgadgetconfiguration.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup OPMapPlugin OpenPilot Map Plugin + * @{ + * @brief The OpenPilot Map plugin + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "opmapgadgetconfiguration.h" +#include "utils/pathutils.h" +#include + +OPMapGadgetConfiguration::OPMapGadgetConfiguration(QString classId, QSettings* qSettings, QObject *parent) : + IUAVGadgetConfiguration(classId, parent), + m_mapProvider("GoogleHybrid"), + m_defaultZoom(2), + m_defaultLatitude(0), + m_defaultLongitude(0), + m_useOpenGL(false), + m_showTileGridLines(false), + m_accessMode("ServerAndCache"), + m_useMemoryCache(true), + m_cacheLocation(Utils::PathUtils().GetStoragePath() + "mapscache" + QDir::separator()), + m_uavSymbol(QString::fromUtf8(":/uavs/images/mapquad.png")), + m_maxUpdateRate(2000) // ms +{ + + //if a saved configuration exists load it + if (qSettings != 0) { + + QString mapProvider = qSettings->value("mapProvider").toString(); + int zoom = qSettings->value("defaultZoom").toInt(); + double latitude= qSettings->value("defaultLatitude").toDouble(); + double longitude= qSettings->value("defaultLongitude").toDouble(); + bool useOpenGL= qSettings->value("useOpenGL").toBool(); + bool showTileGridLines= qSettings->value("showTileGridLines").toBool(); + QString accessMode= qSettings->value("accessMode").toString(); + bool useMemoryCache= qSettings->value("useMemoryCache").toBool(); + QString cacheLocation= qSettings->value("cacheLocation").toString(); + QString uavSymbol=qSettings->value("uavSymbol").toString(); + int max_update_rate = qSettings->value("maxUpdateRate").toInt(); + + if (!mapProvider.isEmpty()) m_mapProvider = mapProvider; + m_defaultZoom = zoom; + m_defaultLatitude = latitude; + m_defaultLongitude = longitude; + m_useOpenGL = useOpenGL; + m_showTileGridLines = showTileGridLines; + m_uavSymbol = uavSymbol; + + m_maxUpdateRate = max_update_rate; + if (m_maxUpdateRate < 100 || m_maxUpdateRate > 5000) + m_maxUpdateRate = 2000; + + if (!accessMode.isEmpty()) + m_accessMode = accessMode; + m_useMemoryCache = useMemoryCache; + if (!cacheLocation.isEmpty()) + m_cacheLocation = Utils::PathUtils().InsertStoragePath(cacheLocation); + } +} + +IUAVGadgetConfiguration * OPMapGadgetConfiguration::clone() +{ + OPMapGadgetConfiguration *m = new OPMapGadgetConfiguration(this->classId()); + + m->m_mapProvider = m_mapProvider; + m->m_defaultZoom = m_defaultZoom; + m->m_defaultLatitude = m_defaultLatitude; + m->m_defaultLongitude = m_defaultLongitude; + m->m_useOpenGL = m_useOpenGL; + m->m_showTileGridLines = m_showTileGridLines; + m->m_accessMode = m_accessMode; + m->m_useMemoryCache = m_useMemoryCache; + m->m_cacheLocation = m_cacheLocation; + m->m_uavSymbol = m_uavSymbol; + m->m_maxUpdateRate = m_maxUpdateRate; + + return m; +} + +void OPMapGadgetConfiguration::saveConfig(QSettings* qSettings) const { + qSettings->setValue("mapProvider", m_mapProvider); + qSettings->setValue("defaultZoom", m_defaultZoom); + qSettings->setValue("defaultLatitude", m_defaultLatitude); + qSettings->setValue("defaultLongitude", m_defaultLongitude); + qSettings->setValue("useOpenGL", m_useOpenGL); + qSettings->setValue("showTileGridLines", m_showTileGridLines); + qSettings->setValue("accessMode", m_accessMode); + qSettings->setValue("useMemoryCache", m_useMemoryCache); + qSettings->setValue("uavSymbol", m_uavSymbol); + qSettings->setValue("cacheLocation", Utils::PathUtils().RemoveStoragePath(m_cacheLocation)); + qSettings->setValue("maxUpdateRate", m_maxUpdateRate); +} +void OPMapGadgetConfiguration::setCacheLocation(QString cacheLocation){ + m_cacheLocation = cacheLocation; +} diff --git a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetconfiguration.h b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetconfiguration.h index 4b4476f71..1e630dc00 100644 --- a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetconfiguration.h +++ b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetconfiguration.h @@ -1,93 +1,97 @@ -/** - ****************************************************************************** - * - * @file opmapgadgetconfiguration.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin OpenPilot Map Plugin - * @{ - * @brief The OpenPilot Map plugin - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OPMAP_GADGETCONFIGURATION_H -#define OPMAP_GADGETCONFIGURATION_H - -#include -#include - -using namespace Core; - -class OPMapGadgetConfiguration : public IUAVGadgetConfiguration -{ -Q_OBJECT - -Q_PROPERTY(QString mapProvider READ mapProvider WRITE setMapProvider) -Q_PROPERTY(int zoommo READ zoom WRITE setZoom) -Q_PROPERTY(double latitude READ latitude WRITE setLatitude) -Q_PROPERTY(double longitude READ longitude WRITE setLongitude) -Q_PROPERTY(bool useOpenGL READ useOpenGL WRITE setUseOpenGL) -Q_PROPERTY(bool showTileGridLines READ showTileGridLines WRITE setShowTileGridLines) -Q_PROPERTY(QString accessMode READ accessMode WRITE setAccessMode) -Q_PROPERTY(bool useMemoryCache READ useMemoryCache WRITE setUseMemoryCache) -Q_PROPERTY(QString cacheLocation READ cacheLocation WRITE setCacheLocation) -Q_PROPERTY(QString uavSymbol READ uavSymbol WRITE setUavSymbol) - -public: - explicit OPMapGadgetConfiguration(QString classId, QSettings* qSettings = 0, QObject *parent = 0); - - void saveConfig(QSettings* settings) const; - IUAVGadgetConfiguration *clone(); - - QString mapProvider() const { return m_mapProvider; } - int zoom() const { return m_defaultZoom; } - double latitude() const { return m_defaultLatitude; } - double longitude() const { return m_defaultLongitude; } - bool useOpenGL() const { return m_useOpenGL; } - bool showTileGridLines() const { return m_showTileGridLines; } - QString accessMode() const { return m_accessMode; } - bool useMemoryCache() const { return m_useMemoryCache; } - QString cacheLocation() const { return m_cacheLocation; } - QString uavSymbol() const { return m_uavSymbol; } - -public slots: - void setMapProvider(QString provider) { m_mapProvider = provider; } - void setZoom(int zoom) { m_defaultZoom = zoom; } - void setLatitude(double latitude) { m_defaultLatitude = latitude; } - void setLongitude(double longitude) { m_defaultLongitude = longitude; } - void setUseOpenGL(bool useOpenGL) { m_useOpenGL = useOpenGL; } - void setShowTileGridLines(bool showTileGridLines) { m_showTileGridLines = showTileGridLines; } - void setAccessMode(QString accessMode) { m_accessMode = accessMode; } - void setUseMemoryCache(bool useMemoryCache) { m_useMemoryCache = useMemoryCache; } - void setCacheLocation(QString cacheLocation); - void setUavSymbol(QString symbol){m_uavSymbol=symbol;} -private: - QString m_mapProvider; - int m_defaultZoom; - double m_defaultLatitude; - double m_defaultLongitude; - bool m_useOpenGL; - bool m_showTileGridLines; - QString m_accessMode; - bool m_useMemoryCache; - QString m_cacheLocation; - QString m_uavSymbol; - -}; - -#endif // OPMAP_GADGETCONFIGURATION_H +/** + ****************************************************************************** + * + * @file opmapgadgetconfiguration.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup OPMapPlugin OpenPilot Map Plugin + * @{ + * @brief The OpenPilot Map plugin + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OPMAP_GADGETCONFIGURATION_H +#define OPMAP_GADGETCONFIGURATION_H + +#include +#include + +using namespace Core; + +class OPMapGadgetConfiguration : public IUAVGadgetConfiguration +{ +Q_OBJECT + +Q_PROPERTY(QString mapProvider READ mapProvider WRITE setMapProvider) +Q_PROPERTY(int zoommo READ zoom WRITE setZoom) +Q_PROPERTY(double latitude READ latitude WRITE setLatitude) +Q_PROPERTY(double longitude READ longitude WRITE setLongitude) +Q_PROPERTY(bool useOpenGL READ useOpenGL WRITE setUseOpenGL) +Q_PROPERTY(bool showTileGridLines READ showTileGridLines WRITE setShowTileGridLines) +Q_PROPERTY(QString accessMode READ accessMode WRITE setAccessMode) +Q_PROPERTY(bool useMemoryCache READ useMemoryCache WRITE setUseMemoryCache) +Q_PROPERTY(QString cacheLocation READ cacheLocation WRITE setCacheLocation) +Q_PROPERTY(QString uavSymbol READ uavSymbol WRITE setUavSymbol) +Q_PROPERTY(int maxUpdateRate READ maxUpdateRate WRITE setMaxUpdateRate) + +public: + explicit OPMapGadgetConfiguration(QString classId, QSettings* qSettings = 0, QObject *parent = 0); + + void saveConfig(QSettings* settings) const; + IUAVGadgetConfiguration *clone(); + + QString mapProvider() const { return m_mapProvider; } + int zoom() const { return m_defaultZoom; } + double latitude() const { return m_defaultLatitude; } + double longitude() const { return m_defaultLongitude; } + bool useOpenGL() const { return m_useOpenGL; } + bool showTileGridLines() const { return m_showTileGridLines; } + QString accessMode() const { return m_accessMode; } + bool useMemoryCache() const { return m_useMemoryCache; } + QString cacheLocation() const { return m_cacheLocation; } + QString uavSymbol() const { return m_uavSymbol; } + int maxUpdateRate() const { return m_maxUpdateRate; } + +public slots: + void setMapProvider(QString provider) { m_mapProvider = provider; } + void setZoom(int zoom) { m_defaultZoom = zoom; } + void setLatitude(double latitude) { m_defaultLatitude = latitude; } + void setLongitude(double longitude) { m_defaultLongitude = longitude; } + void setUseOpenGL(bool useOpenGL) { m_useOpenGL = useOpenGL; } + void setShowTileGridLines(bool showTileGridLines) { m_showTileGridLines = showTileGridLines; } + void setAccessMode(QString accessMode) { m_accessMode = accessMode; } + void setUseMemoryCache(bool useMemoryCache) { m_useMemoryCache = useMemoryCache; } + void setCacheLocation(QString cacheLocation); + void setUavSymbol(QString symbol){m_uavSymbol=symbol;} + void setMaxUpdateRate(int update_rate){m_maxUpdateRate = update_rate;} + +private: + QString m_mapProvider; + int m_defaultZoom; + double m_defaultLatitude; + double m_defaultLongitude; + bool m_useOpenGL; + bool m_showTileGridLines; + QString m_accessMode; + bool m_useMemoryCache; + QString m_cacheLocation; + QString m_uavSymbol; + int m_maxUpdateRate; +}; + +#endif // OPMAP_GADGETCONFIGURATION_H diff --git a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetfactory.cpp b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetfactory.cpp index fa60d10f0..5a3908c89 100644 --- a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetfactory.cpp +++ b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetfactory.cpp @@ -32,7 +32,7 @@ #include OPMapGadgetFactory::OPMapGadgetFactory(QObject *parent) : - IUAVGadgetFactory(QString("OPMapGadget"), tr("OPMap Gadget"), parent) + IUAVGadgetFactory(QString("OPMapGadget"), tr("OPMap"), parent) { } diff --git a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetoptionspage.cpp b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetoptionspage.cpp index b6f07b9bd..2136a24d0 100644 --- a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetoptionspage.cpp +++ b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetoptionspage.cpp @@ -1,133 +1,149 @@ -/** - ****************************************************************************** - * - * @file opmapgadgetoptionspage.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin OpenPilot Map Plugin - * @{ - * @brief The OpenPilot Map plugin - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "opmapgadgetoptionspage.h" -#include "opmapgadgetconfiguration.h" -#include -#include -#include -#include -#include -#include -#include - -#include "opmapcontrol/opmapcontrol.h" -#include "utils/pathutils.h" -#include "ui_opmapgadgetoptionspage.h" - -// ********************************************* - -OPMapGadgetOptionsPage::OPMapGadgetOptionsPage(OPMapGadgetConfiguration *config, QObject *parent) : - IOptionsPage(parent), - m_config(config) -{ -} - -QWidget *OPMapGadgetOptionsPage::createPage(QWidget *parent) -{ - m_page = new Ui::OPMapGadgetOptionsPage(); - QWidget *w = new QWidget(parent); - m_page->setupUi(w); - - // populate the map provider combobox - m_page->providerComboBox->clear(); - m_page->providerComboBox->addItems(mapcontrol::Helper::MapTypes()); - - // populate the access mode combobox - m_page->accessModeComboBox->clear(); - m_page->accessModeComboBox->addItems(mapcontrol::Helper::AccessModeTypes()); - - int index = m_page->providerComboBox->findText(m_config->mapProvider()); - index = (index >= 0) ? index : 0; - m_page->providerComboBox->setCurrentIndex(index); - - m_page->zoomSpinBox->setValue(m_config->zoom()); - m_page->latitudeSpinBox->setValue(m_config->latitude()); - m_page->longitudeSpinBox->setValue(m_config->longitude()); - - m_page->checkBoxUseOpenGL->setChecked(m_config->useOpenGL()); - m_page->checkBoxShowTileGridLines->setChecked(m_config->showTileGridLines()); - - index = m_page->accessModeComboBox->findText(m_config->accessMode()); - index = (index >= 0) ? index : 0; - m_page->accessModeComboBox->setCurrentIndex(index); - - m_page->checkBoxUseMemoryCache->setChecked(m_config->useMemoryCache()); - - m_page->lineEditCacheLocation->setExpectedKind(Utils::PathChooser::Directory); - m_page->lineEditCacheLocation->setPromptDialogTitle(tr("Choose Cache Directory")); - m_page->lineEditCacheLocation->setPath(m_config->cacheLocation()); - - QDir dir(":/uavs/images/"); - QStringList list=dir.entryList(); - foreach(QString i,list) - { - QIcon icon(QPixmap(":/uavs/images/"+i)); - m_page->uavSymbolComboBox->addItem(icon,QString(),i); - } - for(int x=0;xuavSymbolComboBox->count();++x) - { - if(m_page->uavSymbolComboBox->itemData(x).toString()==m_config->uavSymbol()) - { - m_page->uavSymbolComboBox->setCurrentIndex(x); - } - } - - connect(m_page->pushButtonCacheDefaults, SIGNAL(clicked()), this, SLOT(on_pushButtonCacheDefaults_clicked())); - - return w; -} - -void OPMapGadgetOptionsPage::on_pushButtonCacheDefaults_clicked() -{ - int index = m_page->accessModeComboBox->findText("ServerAndCache"); - index = (index >= 0) ? index : 0; - m_page->accessModeComboBox->setCurrentIndex(index); - - m_page->checkBoxUseMemoryCache->setChecked(true); - m_page->lineEditCacheLocation->setPath(Utils::PathUtils().GetStoragePath() + "mapscache" + QDir::separator()); - -} - -void OPMapGadgetOptionsPage::apply() -{ - m_config->setMapProvider(m_page->providerComboBox->currentText()); - m_config->setZoom(m_page->zoomSpinBox->value()); - m_config->setLatitude(m_page->latitudeSpinBox->value()); - m_config->setLongitude(m_page->longitudeSpinBox->value()); - m_config->setUseOpenGL(m_page->checkBoxUseOpenGL->isChecked()); - m_config->setShowTileGridLines(m_page->checkBoxShowTileGridLines->isChecked()); - m_config->setAccessMode(m_page->accessModeComboBox->currentText()); - m_config->setUseMemoryCache(m_page->checkBoxUseMemoryCache->isChecked()); - m_config->setCacheLocation(m_page->lineEditCacheLocation->path()); - m_config->setUavSymbol(m_page->uavSymbolComboBox->itemData(m_page->uavSymbolComboBox->currentIndex()).toString()); -} - -void OPMapGadgetOptionsPage::finish() -{ - delete m_page; -} +/** + ****************************************************************************** + * + * @file opmapgadgetoptionspage.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup OPMapPlugin OpenPilot Map Plugin + * @{ + * @brief The OpenPilot Map plugin + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "opmapgadgetoptionspage.h" +#include "opmapgadgetconfiguration.h" +#include +#include +#include +#include +#include +#include +#include + +#include "opmapcontrol/opmapcontrol.h" +#include "utils/pathutils.h" +#include "ui_opmapgadgetoptionspage.h" + +// ********************************************* + +OPMapGadgetOptionsPage::OPMapGadgetOptionsPage(OPMapGadgetConfiguration *config, QObject *parent) : + IOptionsPage(parent), + m_config(config) +{ +} + +QWidget *OPMapGadgetOptionsPage::createPage(QWidget *parent) +{ + int index; + + m_page = new Ui::OPMapGadgetOptionsPage(); + QWidget *w = new QWidget(parent); + m_page->setupUi(w); + + // populate the map provider combobox + m_page->providerComboBox->clear(); + m_page->providerComboBox->addItems(mapcontrol::Helper::MapTypes()); + + // populate the access mode combobox + m_page->accessModeComboBox->clear(); + m_page->accessModeComboBox->addItems(mapcontrol::Helper::AccessModeTypes()); + + index = m_page->providerComboBox->findText(m_config->mapProvider()); + index = (index >= 0) ? index : 0; + m_page->providerComboBox->setCurrentIndex(index); + + // populate the map max update rate combobox + m_page->maxUpdateRateComboBox->clear(); + m_page->maxUpdateRateComboBox->addItem("100ms", 100); + m_page->maxUpdateRateComboBox->addItem("200ms", 200); + m_page->maxUpdateRateComboBox->addItem("500ms", 500); + m_page->maxUpdateRateComboBox->addItem("1 sec", 1000); + m_page->maxUpdateRateComboBox->addItem("2 sec", 2000); + m_page->maxUpdateRateComboBox->addItem("5 sec", 5000); + + index = m_page->maxUpdateRateComboBox->findData(m_config->maxUpdateRate()); + index = (index >= 0) ? index : 4; + m_page->maxUpdateRateComboBox->setCurrentIndex(index); + + m_page->zoomSpinBox->setValue(m_config->zoom()); + m_page->latitudeSpinBox->setValue(m_config->latitude()); + m_page->longitudeSpinBox->setValue(m_config->longitude()); + + m_page->checkBoxUseOpenGL->setChecked(m_config->useOpenGL()); + m_page->checkBoxShowTileGridLines->setChecked(m_config->showTileGridLines()); + + index = m_page->accessModeComboBox->findText(m_config->accessMode()); + index = (index >= 0) ? index : 0; + m_page->accessModeComboBox->setCurrentIndex(index); + + m_page->checkBoxUseMemoryCache->setChecked(m_config->useMemoryCache()); + + m_page->lineEditCacheLocation->setExpectedKind(Utils::PathChooser::Directory); + m_page->lineEditCacheLocation->setPromptDialogTitle(tr("Choose Cache Directory")); + m_page->lineEditCacheLocation->setPath(m_config->cacheLocation()); + + QDir dir(":/uavs/images/"); + QStringList list=dir.entryList(); + foreach(QString i,list) + { + QIcon icon(QPixmap(":/uavs/images/"+i)); + m_page->uavSymbolComboBox->addItem(icon,QString(),i); + } + for(int x=0;xuavSymbolComboBox->count();++x) + { + if(m_page->uavSymbolComboBox->itemData(x).toString()==m_config->uavSymbol()) + { + m_page->uavSymbolComboBox->setCurrentIndex(x); + } + } + + connect(m_page->pushButtonCacheDefaults, SIGNAL(clicked()), this, SLOT(on_pushButtonCacheDefaults_clicked())); + + return w; +} + +void OPMapGadgetOptionsPage::on_pushButtonCacheDefaults_clicked() +{ + int index = m_page->accessModeComboBox->findText("ServerAndCache"); + index = (index >= 0) ? index : 0; + m_page->accessModeComboBox->setCurrentIndex(index); + + m_page->checkBoxUseMemoryCache->setChecked(true); + m_page->lineEditCacheLocation->setPath(Utils::PathUtils().GetStoragePath() + "mapscache" + QDir::separator()); + +} + +void OPMapGadgetOptionsPage::apply() +{ + m_config->setMapProvider(m_page->providerComboBox->currentText()); + m_config->setZoom(m_page->zoomSpinBox->value()); + m_config->setLatitude(m_page->latitudeSpinBox->value()); + m_config->setLongitude(m_page->longitudeSpinBox->value()); + m_config->setUseOpenGL(m_page->checkBoxUseOpenGL->isChecked()); + m_config->setShowTileGridLines(m_page->checkBoxShowTileGridLines->isChecked()); + m_config->setAccessMode(m_page->accessModeComboBox->currentText()); + m_config->setUseMemoryCache(m_page->checkBoxUseMemoryCache->isChecked()); + m_config->setCacheLocation(m_page->lineEditCacheLocation->path()); + m_config->setUavSymbol(m_page->uavSymbolComboBox->itemData(m_page->uavSymbolComboBox->currentIndex()).toString()); + m_config->setMaxUpdateRate(m_page->maxUpdateRateComboBox->itemData(m_page->maxUpdateRateComboBox->currentIndex()).toInt()); +} + +void OPMapGadgetOptionsPage::finish() +{ + delete m_page; +} diff --git a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetoptionspage.ui b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetoptionspage.ui index 9869ad38d..913678fae 100644 --- a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetoptionspage.ui +++ b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetoptionspage.ui @@ -30,7 +30,7 @@ 5 - + @@ -249,6 +249,19 @@
+ + + + + + + Default Max Update Rate + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + +
diff --git a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetwidget.cpp index 46fc99e18..abc51de20 100644 --- a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetwidget.cpp @@ -1,2371 +1,2451 @@ -/** - ****************************************************************************** - * - * @file opmapgadgetwidget.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin OpenPilot Map Plugin - * @{ - * @brief The OpenPilot Map plugin - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "opmapgadgetwidget.h" -#include "ui_opmap_widget.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "utils/stylehelper.h" -#include "utils/homelocationutil.h" -#include "utils/worldmagmodel.h" - -#include "uavtalk/telemetrymanager.h" - -#include "positionactual.h" -#include "homelocation.h" - -#define allow_manual_home_location_move - -// ************************************************************************************* - -#define deg_to_rad ((double)M_PI / 180.0) -#define rad_to_deg (180.0 / (double)M_PI) - -#define earth_mean_radius 6371 // kilometers - -#define max_digital_zoom 3 // maximum allowed digital zoom level - -const int safe_area_radius_list[] = {5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000}; // meters - -const int uav_trail_time_list[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // seconds - -const int uav_trail_distance_list[] = {1, 2, 5, 10, 20, 50, 100, 200, 500}; // meters - -// ************************************************************************************* - - -// ************************************************************************************* -// NOTE: go back to SVN REV 2137 and earlier to get back to experimental waypoint support. -// ************************************************************************************* - - -// constructor -OPMapGadgetWidget::OPMapGadgetWidget(QWidget *parent) : QWidget(parent) -{ - // ************** - - m_widget = NULL; - m_map = NULL; - findPlaceCompleter = NULL; - - m_mouse_waypoint = NULL; - - pm = NULL; - obm = NULL; - obum = NULL; - - prev_tile_number = 0; - - min_zoom = max_zoom = 0; - - m_map_mode = Normal_MapMode; - - telemetry_connected = false; - - context_menu_lat_lon = mouse_lat_lon = internals::PointLatLng(0, 0); - - setMouseTracking(true); - - pm = ExtensionSystem::PluginManager::instance(); - if (pm) - { - obm = pm->getObject(); - obum = pm->getObject(); - } - - // ************** - // get current location - - double latitude = 0; - double longitude = 0; - double altitude = 0; - - // current position - getUAVPosition(latitude, longitude, altitude); - - internals::PointLatLng pos_lat_lon = internals::PointLatLng(latitude, longitude); - - // ************** - // default home position - - home_position.coord = pos_lat_lon; - home_position.altitude = altitude; - home_position.locked = false; - - // ************** - // default magic waypoint params - - magic_waypoint.map_wp_item = NULL; - magic_waypoint.coord = home_position.coord; - magic_waypoint.altitude = altitude; - magic_waypoint.description = "Magic waypoint"; - magic_waypoint.locked = false; - magic_waypoint.time_seconds = 0; - magic_waypoint.hold_time_seconds = 0; - - // ************** - // create the widget that holds the user controls and the map - - m_widget = new Ui::OPMap_Widget(); - m_widget->setupUi(this); - - // ************** - // create the central map widget - - m_map = new mapcontrol::OPMapWidget(); // create the map object - - m_map->setFrameStyle(QFrame::NoFrame); // no border frame - m_map->setBackgroundBrush(QBrush(Utils::StyleHelper::baseColor())); // tile background - - m_map->configuration->DragButton = Qt::LeftButton; // use the left mouse button for map dragging - - m_widget->horizontalSliderZoom->setMinimum(m_map->MinZoom()); // - m_widget->horizontalSliderZoom->setMaximum(m_map->MaxZoom() + max_digital_zoom); // - - min_zoom = m_widget->horizontalSliderZoom->minimum(); // minimum zoom we can accept - max_zoom = m_widget->horizontalSliderZoom->maximum(); // maximum zoom we can accept - - m_map->SetMouseWheelZoomType(internals::MouseWheelZoomType::MousePositionWithoutCenter); // set how the mouse wheel zoom functions - m_map->SetFollowMouse(true); // we want a contiuous mouse position reading - - m_map->SetShowHome(true); // display the HOME position on the map - m_map->SetShowUAV(true); // display the UAV position on the map - - m_map->Home->SetSafeArea(safe_area_radius_list[0]); // set radius (meters) - m_map->Home->SetShowSafeArea(true); // show the safe area - - m_map->UAV->SetTrailTime(uav_trail_time_list[0]); // seconds - m_map->UAV->SetTrailDistance(uav_trail_distance_list[1]); // meters - - m_map->UAV->SetTrailType(UAVTrailType::ByTimeElapsed); -// m_map->UAV->SetTrailType(UAVTrailType::ByDistance); - - m_map->GPS->SetTrailTime(uav_trail_time_list[0]); // seconds - m_map->GPS->SetTrailDistance(uav_trail_distance_list[1]); // meters - - m_map->GPS->SetTrailType(UAVTrailType::ByTimeElapsed); -// m_map->GPS->SetTrailType(UAVTrailType::ByDistance); - - // ************** - - setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - - QVBoxLayout *layout = new QVBoxLayout; - layout->setSpacing(0); - layout->setContentsMargins(0, 0, 0, 0); - layout->addWidget(m_map); - m_widget->mapWidget->setLayout(layout); - - // ************** - // set the user control options - - // TODO: this switch does not make sense, does it?? - - switch (m_map_mode) - { - case Normal_MapMode: - m_widget->toolButtonMagicWaypointMapMode->setChecked(false); - m_widget->toolButtonNormalMapMode->setChecked(true); - hideMagicWaypointControls(); - break; - - case MagicWaypoint_MapMode: - m_widget->toolButtonNormalMapMode->setChecked(false); - m_widget->toolButtonMagicWaypointMapMode->setChecked(true); - showMagicWaypointControls(); - break; - - default: - m_map_mode = Normal_MapMode; - m_widget->toolButtonMagicWaypointMapMode->setChecked(false); - m_widget->toolButtonNormalMapMode->setChecked(true); - hideMagicWaypointControls(); - break; - } - - m_widget->labelUAVPos->setText("---"); - m_widget->labelMapPos->setText("---"); - m_widget->labelMousePos->setText("---"); - m_widget->labelMapZoom->setText("---"); - - - // Splitter is not used at the moment: - // m_widget->splitter->setCollapsible(1, false); - - // set the size of the collapsable widgets - //QList m_SizeList; - //m_SizeList << 0 << 0 << 0; - //m_widget->splitter->setSizes(m_SizeList); - - m_widget->progressBarMap->setMaximum(1); - -/* - #if defined(Q_OS_MAC) - #elif defined(Q_OS_WIN) - m_widget->comboBoxFindPlace->clear(); - loadComboBoxLines(m_widget->comboBoxFindPlace, QCoreApplication::applicationDirPath() + "/opmap_find_place_history.txt"); - m_widget->comboBoxFindPlace->setCurrentIndex(-1); - #else - #endif -*/ - - - // ************** - // map stuff - - connect(m_map, SIGNAL(zoomChanged(double, double, double)), this, SLOT(zoomChanged(double, double, double))); // map zoom change signals - connect(m_map, SIGNAL(OnCurrentPositionChanged(internals::PointLatLng)), this, SLOT(OnCurrentPositionChanged(internals::PointLatLng))); // map poisition change signals - connect(m_map, SIGNAL(OnTileLoadComplete()), this, SLOT(OnTileLoadComplete())); // tile loading stop signals - connect(m_map, SIGNAL(OnTileLoadStart()), this, SLOT(OnTileLoadStart())); // tile loading start signals - connect(m_map, SIGNAL(OnMapDrag()), this, SLOT(OnMapDrag())); // map drag signals - connect(m_map, SIGNAL(OnMapZoomChanged()), this, SLOT(OnMapZoomChanged())); // map zoom changed - connect(m_map, SIGNAL(OnMapTypeChanged(MapType::Types)), this, SLOT(OnMapTypeChanged(MapType::Types))); // map type changed - connect(m_map, SIGNAL(OnEmptyTileError(int, core::Point)), this, SLOT(OnEmptyTileError(int, core::Point))); // tile error - connect(m_map, SIGNAL(OnTilesStillToLoad(int)), this, SLOT(OnTilesStillToLoad(int))); // tile loading signals - connect(m_map, SIGNAL(WPNumberChanged(int const&,int const&,WayPointItem*)), this, SLOT(WPNumberChanged(int const&,int const&,WayPointItem*))); - connect(m_map, SIGNAL(WPValuesChanged(WayPointItem*)), this, SLOT(WPValuesChanged(WayPointItem*))); - connect(m_map, SIGNAL(WPInserted(int const&, WayPointItem*)), this, SLOT(WPInserted(int const&, WayPointItem*))); - connect(m_map, SIGNAL(WPDeleted(int const&)), this, SLOT(WPDeleted(int const&))); - - m_map->SetCurrentPosition(home_position.coord); // set the map position - m_map->Home->SetCoord(home_position.coord); // set the HOME position - m_map->UAV->SetUAVPos(home_position.coord, 0.0); // set the UAV position - m_map->GPS->SetUAVPos(home_position.coord, 0.0); // set the UAV position - - // ************** - // create various context menu (mouse right click menu) actions - - createActions(); - - // ************** - // connect to the UAVObject updates we require to become a bit aware of our environment: - - if (pm) - { - // Register for Home Location state changes - if (obm) - { - UAVDataObject *obj = dynamic_cast(obm->getObject(QString("HomeLocation"))); - if (obj) - { - connect(obj, SIGNAL(objectUpdated(UAVObject *)), this , SLOT(homePositionUpdated(UAVObject *))); - } - } - - // Listen to telemetry connection events - TelemetryManager *telMngr = pm->getObject(); - if (telMngr) - { - connect(telMngr, SIGNAL(connected()), this, SLOT(onTelemetryConnect())); - connect(telMngr, SIGNAL(disconnected()), this, SLOT(onTelemetryDisconnect())); - } - } - - // ************** - // create the desired timers - - m_updateTimer = new QTimer(); - m_updateTimer->setInterval(200); - connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(updatePosition())); - m_updateTimer->start(); - - m_statusUpdateTimer = new QTimer(); - m_statusUpdateTimer->setInterval(100); - connect(m_statusUpdateTimer, SIGNAL(timeout()), this, SLOT(updateMousePos())); - m_statusUpdateTimer->start(); - - // ************** - - m_map->setFocus(); -} - -// destructor -OPMapGadgetWidget::~OPMapGadgetWidget() -{ - if (m_map) - { - disconnect(m_map, 0, 0, 0); - m_map->SetShowHome(false); // doing this appears to stop the map lib crashing on exit - m_map->SetShowUAV(false); // " " - } - - - // this destructor doesn't appear to be called at shutdown??? - -// #if defined(Q_OS_MAC) -// #elif defined(Q_OS_WIN) -// saveComboBoxLines(m_widget->comboBoxFindPlace, QCoreApplication::applicationDirPath() + "/opmap_find_place_history.txt"); -// #else -// #endif - - m_waypoint_list_mutex.lock(); - foreach (t_waypoint *wp, m_waypoint_list) - { - if (!wp) continue; - - - // todo: - - - delete wp->map_wp_item; - } - m_waypoint_list_mutex.unlock(); - m_waypoint_list.clear(); - - if (m_map) - { - delete m_map; - m_map = NULL; - } -} - -// ************************************************************************************* -// widget signals .. the mouseMoveEvent does not get called - don't yet know why - -void OPMapGadgetWidget::resizeEvent(QResizeEvent *event) -{ - qDebug("opmap: resizeEvent"); - - QWidget::resizeEvent(event); -} - -void OPMapGadgetWidget::mouseMoveEvent(QMouseEvent *event) -{ - qDebug("opmap: mouseMoveEvent"); - - if (m_widget && m_map) - { - } - - if (event->buttons() & Qt::LeftButton) - { -// QPoint pos = event->pos(); - } - - QWidget::mouseMoveEvent(event); -} - -void OPMapGadgetWidget::contextMenuEvent(QContextMenuEvent *event) -{ // the user has right clicked on the map - create the pop-up context menu and display it - - QString s; - - if (!m_widget || !m_map) - return; - - if (event->reason() != QContextMenuEvent::Mouse) - return; // not a mouse click event - - // current mouse position - QPoint p = m_map->mapFromGlobal(event->globalPos()); - context_menu_lat_lon = m_map->GetFromLocalToLatLng(p); -// context_menu_lat_lon = m_map->currentMousePosition(); - - if (!m_map->contentsRect().contains(p)) - return; // the mouse click was not on the map - - // show the mouse position - s = QString::number(context_menu_lat_lon.Lat(), 'f', 7) + " " + QString::number(context_menu_lat_lon.Lng(), 'f', 7); - m_widget->labelMousePos->setText(s); - - // find out if we have a waypoint under the mouse cursor - QGraphicsItem *item = m_map->itemAt(p); - m_mouse_waypoint = qgraphicsitem_cast(item); - - // find out if the waypoint is locked (or not) - bool waypoint_locked = false; - if (m_mouse_waypoint) - waypoint_locked = (m_mouse_waypoint->flags() & QGraphicsItem::ItemIsMovable) == 0; - - // **************** - // Dynamically create the popup menu - - QMenu menu(this); - - menu.addAction(closeAct1); - - menu.addSeparator(); - - menu.addAction(reloadAct); - - menu.addSeparator(); - - switch (m_map_mode) - { - case Normal_MapMode: s = tr(" (Normal)"); break; - case MagicWaypoint_MapMode: s = tr(" (Magic Waypoint)"); break; - default: s = tr(" (Unknown)"); break; - } - for (int i = 0; i < mapModeAct.count(); i++) - { // set the menu to checked (or not) - QAction *act = mapModeAct.at(i); - if (!act) continue; - if (act->data().toInt() == (int)m_map_mode) - act->setChecked(true); - } - QMenu mapModeSubMenu(tr("Map mode") + s, this); - for (int i = 0; i < mapModeAct.count(); i++) - mapModeSubMenu.addAction(mapModeAct.at(i)); - menu.addMenu(&mapModeSubMenu); - - menu.addSeparator(); - - QMenu copySubMenu(tr("Copy"), this); - copySubMenu.addAction(copyMouseLatLonToClipAct); - copySubMenu.addAction(copyMouseLatToClipAct); - copySubMenu.addAction(copyMouseLonToClipAct); - menu.addMenu(©SubMenu); - - menu.addSeparator(); - - /* - menu.addAction(findPlaceAct); - - menu.addSeparator(); - */ - - menu.addAction(showSafeAreaAct); - QMenu safeAreaSubMenu(tr("Safe Area Radius") + " (" + QString::number(m_map->Home->SafeArea()) + "m)", this); - for (int i = 0; i < safeAreaAct.count(); i++) - safeAreaSubMenu.addAction(safeAreaAct.at(i)); - menu.addMenu(&safeAreaSubMenu); - - menu.addSeparator(); - - menu.addAction(showCompassAct); - - menu.addAction(showDiagnostics); - - menu.addSeparator()->setText(tr("Zoom")); - - menu.addAction(zoomInAct); - menu.addAction(zoomOutAct); - - QMenu zoomSubMenu(tr("&Zoom ") + "(" + QString::number(m_map->ZoomTotal()) + ")", this); - for (int i = 0; i < zoomAct.count(); i++) - zoomSubMenu.addAction(zoomAct.at(i)); - menu.addMenu(&zoomSubMenu); - - menu.addSeparator(); - - menu.addAction(goMouseClickAct); - - menu.addSeparator()->setText(tr("HOME")); - - menu.addAction(setHomeAct); - menu.addAction(showHomeAct); - menu.addAction(goHomeAct); - - // **** - // uav trails - - menu.addSeparator()->setText(tr("UAV Trail")); - - QMenu uavTrailTypeSubMenu(tr("UAV trail type") + " (" + mapcontrol::Helper::StrFromUAVTrailType(m_map->UAV->GetTrailType()) + ")", this); - for (int i = 0; i < uavTrailTypeAct.count(); i++) - uavTrailTypeSubMenu.addAction(uavTrailTypeAct.at(i)); - menu.addMenu(&uavTrailTypeSubMenu); - - QMenu uavTrailTimeSubMenu(tr("UAV trail time") + " (" + QString::number(m_map->UAV->TrailTime()) + " sec)", this); - for (int i = 0; i < uavTrailTimeAct.count(); i++) - uavTrailTimeSubMenu.addAction(uavTrailTimeAct.at(i)); - menu.addMenu(&uavTrailTimeSubMenu); - - QMenu uavTrailDistanceSubMenu(tr("UAV trail distance") + " (" + QString::number(m_map->UAV->TrailDistance()) + " meters)", this); - for (int i = 0; i < uavTrailDistanceAct.count(); i++) - uavTrailDistanceSubMenu.addAction(uavTrailDistanceAct.at(i)); - menu.addMenu(&uavTrailDistanceSubMenu); - - menu.addAction(showTrailAct); - - menu.addAction(showTrailLineAct); - - menu.addAction(clearUAVtrailAct); - - // **** - - menu.addSeparator()->setText(tr("UAV")); - - menu.addAction(showUAVAct); - menu.addAction(followUAVpositionAct); - menu.addAction(followUAVheadingAct); - menu.addAction(goUAVAct); - - // ********* - - switch (m_map_mode) - { - case Normal_MapMode: - // only show the waypoint stuff if not in 'magic waypoint' mode - /* - menu.addSeparator()->setText(tr("Waypoints")); - - menu.addAction(wayPointEditorAct); - menu.addAction(addWayPointAct); - - if (m_mouse_waypoint) - { // we have a waypoint under the mouse - menu.addAction(editWayPointAct); - - lockWayPointAct->setChecked(waypoint_locked); - menu.addAction(lockWayPointAct); - - if (!waypoint_locked) - menu.addAction(deleteWayPointAct); - } - - m_waypoint_list_mutex.lock(); - if (m_waypoint_list.count() > 0) - menu.addAction(clearWayPointsAct); // we have waypoints - m_waypoint_list_mutex.unlock(); - */ - - break; - - case MagicWaypoint_MapMode: - menu.addSeparator()->setText(tr("Waypoints")); - menu.addAction(homeMagicWaypointAct); - break; - } - - // ********* - - menu.addSeparator(); - - menu.addAction(closeAct2); - - menu.exec(event->globalPos()); // popup the menu - - // **************** -} - -void OPMapGadgetWidget::keyPressEvent(QKeyEvent* event) -{ - qDebug() << "opmap: keyPressEvent, key =" << event->key() << endl; - - switch (event->key()) - { - case Qt::Key_Escape: - break; - - case Qt::Key_F1: - break; - - case Qt::Key_F2: - break; - - case Qt::Key_Up: - break; - - case Qt::Key_Down: - break; - - case Qt::Key_Left: - break; - - case Qt::Key_Right: - break; - - case Qt::Key_PageUp: - break; - - case Qt::Key_PageDown: - break; - } -} - -// ************************************************************************************* -// timer signals - - -/** - Updates the UAV position on the map. It is called every 200ms - by a timer. - - TODO: consider updating upon object update, not timer. - */ -void OPMapGadgetWidget::updatePosition() -{ - if (!m_widget || !m_map) - return; - - QMutexLocker locker(&m_map_mutex); -//Pip I'm sorry, I know this was here with a purpose vvv - //if (!telemetry_connected) - // return; - - double latitude; - double longitude; - double altitude; - - // get current UAV position - if (!getUAVPosition(latitude, longitude, altitude)) - return; - - // get current UAV heading - float yaw = getUAV_Yaw(); - - internals::PointLatLng uav_pos = internals::PointLatLng(latitude, longitude); // current UAV position - float uav_heading_degrees = yaw; // current UAV heading - float uav_altitude_meters = altitude; // current UAV height - float uav_ground_speed_meters_per_second = 0; //data.Groundspeed; // current UAV ground speed - - // display the UAV lat/lon position - QString str = - "lat: " + QString::number(uav_pos.Lat(), 'f', 7) + - " lon: " + QString::number(uav_pos.Lng(), 'f', 7) + - " " + QString::number(uav_heading_degrees, 'f', 1) + "deg" + - " " + QString::number(uav_altitude_meters, 'f', 1) + "m" + - " " + QString::number(uav_ground_speed_meters_per_second, 'f', 1) + "m/s"; - m_widget->labelUAVPos->setText(str); - - m_map->UAV->SetUAVPos(uav_pos, uav_altitude_meters); // set the maps UAV position - // qDebug()<<"UAVPOSITION"<UAV->SetUAVHeading(uav_heading_degrees); // set the maps UAV heading - - if (!getGPSPosition(latitude, longitude, altitude)) - return; - - uav_pos = internals::PointLatLng(latitude, longitude); // current UAV position - m_map->GPS->SetUAVPos(uav_pos, uav_altitude_meters); // set the maps UAV position - m_map->GPS->SetUAVHeading(uav_heading_degrees); // set the maps UAV heading -} - -/** - Update plugin behaviour based on mouse position; Called every few ms by a - timer. - */ -void OPMapGadgetWidget::updateMousePos() -{ - if (!m_widget || !m_map) - return; - - QMutexLocker locker(&m_map_mutex); - - QPoint p = m_map->mapFromGlobal(QCursor::pos()); - internals::PointLatLng lat_lon = m_map->GetFromLocalToLatLng(p); // fetch the current lat/lon mouse position - - if (!m_map->contentsRect().contains(p)) - return; // the mouse is not on the map - -// internals::PointLatLng lat_lon = m_map->currentMousePosition(); // fetch the current lat/lon mouse position - - QGraphicsItem *item = m_map->itemAt(p); - - // find out if we are over the home position - mapcontrol::HomeItem *home = qgraphicsitem_cast(item); - - // find out if we are over the UAV - mapcontrol::UAVItem *uav = qgraphicsitem_cast(item); - - // find out if we have a waypoint under the mouse cursor - mapcontrol::WayPointItem *wp = qgraphicsitem_cast(item); - - if (mouse_lat_lon == lat_lon) - return; // the mouse has not moved - - mouse_lat_lon = lat_lon; // yes it has! - - internals::PointLatLng home_lat_lon = m_map->Home->Coord(); - - QString s = QString::number(mouse_lat_lon.Lat(), 'f', 7) + " " + QString::number(mouse_lat_lon.Lng(), 'f', 7); - if (wp) - { - s += " wp[" + QString::number(wp->Number()) + "]"; - - double dist = distance(home_lat_lon, wp->Coord()); - double bear = bearing(home_lat_lon, wp->Coord()); - s += " " + QString::number(dist * 1000, 'f', 1) + "m"; - s += " " + QString::number(bear, 'f', 1) + "deg"; - } - else - if (home) - { - s += " home"; - - double dist = distance(home_lat_lon, mouse_lat_lon); - double bear = bearing(home_lat_lon, mouse_lat_lon); - s += " " + QString::number(dist * 1000, 'f', 1) + "m"; - s += " " + QString::number(bear, 'f', 1) + "deg"; - } - else - if (uav) - { - s += " uav"; - - double latitude; - double longitude; - double altitude; - if (getUAVPosition(latitude, longitude, altitude)) // get current UAV position - { - internals::PointLatLng uav_pos = internals::PointLatLng(latitude, longitude); - -// double dist = distance(home_lat_lon, uav_pos); -// double bear = bearing(home_lat_lon, uav_pos); -// s += " " + QString::number(dist * 1000, 'f', 1) + "m"; -// s += " " + QString::number(bear, 'f', 1) + "deg"; - } - } - m_widget->labelMousePos->setText(s); -} - -// ************************************************************************************* -// map signals - - -/** - Update the Plugin UI to reflect a change in zoom level - */ -void OPMapGadgetWidget::zoomChanged(double zoomt, double zoom, double zoomd) -{ - if (!m_widget || !m_map) - return; - - QString s = "tot:" + QString::number(zoomt, 'f', 1) + " rea:" + QString::number(zoom, 'f', 1) + " dig:" + QString::number(zoomd, 'f', 1); - m_widget->labelMapZoom->setText(s); - - int i_zoom = (int)(zoomt + 0.5); - - if (i_zoom < min_zoom) i_zoom = min_zoom; - else - if (i_zoom > max_zoom) i_zoom = max_zoom; - - if (m_widget->horizontalSliderZoom->value() != i_zoom) - m_widget->horizontalSliderZoom->setValue(i_zoom); // set the GUI zoom slider position - - int index0_zoom = i_zoom - min_zoom; // zoom level starting at index level '0' - if (index0_zoom < zoomAct.count()) - zoomAct.at(index0_zoom)->setChecked(true); // set the right-click context menu zoom level -} - -void OPMapGadgetWidget::OnMapDrag() -{ -} - -void OPMapGadgetWidget::OnCurrentPositionChanged(internals::PointLatLng point) -{ - if (!m_widget || !m_map) - return; - - QString coord_str = QString::number(point.Lat(), 'f', 7) + " " + QString::number(point.Lng(), 'f', 7) + " "; - m_widget->labelMapPos->setText(coord_str); -} - -/** - Update the progress bar while there are still tiles to load - */ -void OPMapGadgetWidget::OnTilesStillToLoad(int number) -{ - if (!m_widget || !m_map) - return; - -// if (prev_tile_number < number || m_widget->progressBarMap->maximum() < number) -// m_widget->progressBarMap->setMaximum(number); - - if (m_widget->progressBarMap->maximum() < number) - m_widget->progressBarMap->setMaximum(number); - - m_widget->progressBarMap->setValue(m_widget->progressBarMap->maximum() - number); // update the progress bar - -// m_widget->labelNumTilesToLoad->setText(QString::number(number)); - - prev_tile_number = number; -} - -/** - Show the progress bar as soon as the map lib starts downloading - */ -void OPMapGadgetWidget::OnTileLoadStart() -{ - if (!m_widget || !m_map) - return; - - m_widget->progressBarMap->setVisible(true); -} - -/** - Hide the progress bar once the map lib has finished downloading - - TODO: somehow this gets called before tile load is actually complete? - */ - -void OPMapGadgetWidget::OnTileLoadComplete() -{ - if (!m_widget || !m_map) - return; - - m_widget->progressBarMap->setVisible(false); -} - -void OPMapGadgetWidget::OnMapZoomChanged() -{ -} - -void OPMapGadgetWidget::OnMapTypeChanged(MapType::Types type) -{ - Q_UNUSED(type); -} - -void OPMapGadgetWidget::OnEmptyTileError(int zoom, core::Point pos) -{ - Q_UNUSED(zoom); - Q_UNUSED(pos); -} - -void OPMapGadgetWidget::WPNumberChanged(int const &oldnumber, int const &newnumber, WayPointItem *waypoint) -{ - Q_UNUSED(oldnumber); - Q_UNUSED(newnumber); - Q_UNUSED(waypoint); -} - -void OPMapGadgetWidget::WPValuesChanged(WayPointItem *waypoint) -{ -// qDebug("opmap: WPValuesChanged"); - - switch (m_map_mode) - { - case Normal_MapMode: - m_waypoint_list_mutex.lock(); - foreach (t_waypoint *wp, m_waypoint_list) - { // search for the waypoint in our own waypoint list and update it - if (!wp) continue; - if (!wp->map_wp_item) continue; - if (wp->map_wp_item != waypoint) continue; - // found the waypoint in our list - wp->coord = waypoint->Coord(); - wp->altitude = waypoint->Altitude(); - wp->description = waypoint->Description(); - break; - } - m_waypoint_list_mutex.unlock(); - break; - - case MagicWaypoint_MapMode: - // update our copy of the magic waypoint - if (magic_waypoint.map_wp_item && magic_waypoint.map_wp_item == waypoint) - { - magic_waypoint.coord = waypoint->Coord(); - magic_waypoint.altitude = waypoint->Altitude(); - magic_waypoint.description = waypoint->Description(); - - // move the UAV to the magic waypoint position - // moveToMagicWaypointPosition(); - } - break; - } - -} - -/** - TODO: slot to do something upon Waypoint insertion - */ -void OPMapGadgetWidget::WPInserted(int const &number, WayPointItem *waypoint) -{ - Q_UNUSED(number); - Q_UNUSED(waypoint); -} - -/** - TODO: slot to do something upon Waypoint deletion - */ -void OPMapGadgetWidget::WPDeleted(int const &number) -{ - Q_UNUSED(number); -} - - -void OPMapGadgetWidget::on_toolButtonZoomP_clicked() -{ - QMutexLocker locker(&m_map_mutex); - zoomIn(); -} - -void OPMapGadgetWidget::on_toolButtonZoomM_clicked() -{ - QMutexLocker locker(&m_map_mutex); - zoomOut(); -} - -void OPMapGadgetWidget::on_toolButtonMapHome_clicked() -{ - QMutexLocker locker(&m_map_mutex); - goHome(); -} - -void OPMapGadgetWidget::on_toolButtonMapUAV_clicked() -{ - if (!m_widget || !m_map) - return; - - QMutexLocker locker(&m_map_mutex); - - followUAVpositionAct->toggle(); -} - -void OPMapGadgetWidget::on_toolButtonMapUAVheading_clicked() -{ - if (!m_widget || !m_map) - return; - - followUAVheadingAct->toggle(); -} - -void OPMapGadgetWidget::on_horizontalSliderZoom_sliderMoved(int position) -{ - if (!m_widget || !m_map) - return; - - QMutexLocker locker(&m_map_mutex); - - setZoom(position); -} - - -void OPMapGadgetWidget::on_toolButtonNormalMapMode_clicked() -{ - setMapMode(Normal_MapMode); -} - -void OPMapGadgetWidget::on_toolButtonMagicWaypointMapMode_clicked() -{ - setMapMode(MagicWaypoint_MapMode); -} - -void OPMapGadgetWidget::on_toolButtonHomeWaypoint_clicked() -{ - homeMagicWaypoint(); -} - -void OPMapGadgetWidget::on_toolButtonMoveToWP_clicked() -{ - moveToMagicWaypointPosition(); -} - -// ************************************************************************************* -// public slots - -void OPMapGadgetWidget::onTelemetryConnect() -{ - telemetry_connected = true; - - if (!obum) return; - - bool set; - double LLA[3]; - - // *********************** - // fetch the home location - - if (obum->getHomeLocation(set, LLA) < 0) - return; // error - - setHome(internals::PointLatLng(LLA[0], LLA[1])); - - if (m_map) - m_map->SetCurrentPosition(home_position.coord); // set the map position - - // *********************** -} - -void OPMapGadgetWidget::onTelemetryDisconnect() -{ - telemetry_connected = false; -} - -// Updates the Home position icon whenever the HomePosition object is updated -void OPMapGadgetWidget::homePositionUpdated(UAVObject *hp) -{ - if (!hp) - return; - - double lat = hp->getField("Latitude")->getDouble() * 1e-7; - double lon = hp->getField("Longitude")->getDouble() * 1e-7; - setHome(internals::PointLatLng(lat, lon)); -} - -// ************************************************************************************* -// public functions - -/** - Sets the home position on the map widget - */ -void OPMapGadgetWidget::setHome(QPointF pos) -{ - if (!m_widget || !m_map) - return; - - double latitude = pos.x(); - double longitude = pos.y(); - - if (latitude > 90) latitude = 90; - else - if (latitude < -90) latitude = -90; - - if (longitude != longitude) longitude = 0; // nan detection - else - if (longitude > 180) longitude = 180; - else - if (longitude < -180) longitude = -180; - - setHome(internals::PointLatLng(latitude, longitude)); -} - -/** - Sets the home position on the map widget - */ -void OPMapGadgetWidget::setHome(internals::PointLatLng pos_lat_lon) -{ - if (!m_widget || !m_map) - return; - - if (pos_lat_lon.Lat() != pos_lat_lon.Lat() || pos_lat_lon.Lng() != pos_lat_lon.Lng()) - return;; // nan prevention - - double latitude = pos_lat_lon.Lat(); - double longitude = pos_lat_lon.Lng(); - - if (latitude != latitude) latitude = 0; // nan detection - else - if (latitude > 90) latitude = 90; - else - if (latitude < -90) latitude = -90; - - if (longitude != longitude) longitude = 0; // nan detection - else - if (longitude > 180) longitude = 180; - else - if (longitude < -180) longitude = -180; - - // ********* - - home_position.coord = internals::PointLatLng(latitude, longitude); - - m_map->Home->SetCoord(home_position.coord); - m_map->Home->RefreshPos(); - - // move the magic waypoint to keep it within the safe area boundry - keepMagicWaypointWithInSafeArea(); -} - - -/** - Centers the map over the home position - */ -void OPMapGadgetWidget::goHome() -{ - if (!m_widget || !m_map) - return; - - followUAVpositionAct->setChecked(false); - - internals::PointLatLng home_pos = home_position.coord; // get the home location - m_map->SetCurrentPosition(home_pos); // center the map onto the home location -} - - -void OPMapGadgetWidget::zoomIn() -{ - if (!m_widget || !m_map) - return; - - int zoom = m_map->ZoomTotal() + 1; - - if (zoom < min_zoom) zoom = min_zoom; - else - if (zoom > max_zoom) zoom = max_zoom; - - m_map->SetZoom(zoom); -} - -void OPMapGadgetWidget::zoomOut() -{ - if (!m_widget || !m_map) - return; - - int zoom = m_map->ZoomTotal() - 1; - - if (zoom < min_zoom) zoom = min_zoom; - else - if (zoom > max_zoom) zoom = max_zoom; - - m_map->SetZoom(zoom); -} - -void OPMapGadgetWidget::setZoom(int zoom) -{ - if (!m_widget || !m_map) - return; - - if (zoom < min_zoom) zoom = min_zoom; - else - if (zoom > max_zoom) zoom = max_zoom; - - internals::MouseWheelZoomType::Types zoom_type = m_map->GetMouseWheelZoomType(); - m_map->SetMouseWheelZoomType(internals::MouseWheelZoomType::ViewCenter); - - m_map->SetZoom(zoom); - - m_map->SetMouseWheelZoomType(zoom_type); -} - -void OPMapGadgetWidget::setPosition(QPointF pos) -{ - if (!m_widget || !m_map) - return; - - double latitude = pos.y(); - double longitude = pos.x(); - - if (latitude != latitude || longitude != longitude) - return; // nan prevention - - if (latitude > 90) latitude = 90; - else - if (latitude < -90) latitude = -90; - - if (longitude > 180) longitude = 180; - else - if (longitude < -180) longitude = -180; - - m_map->SetCurrentPosition(internals::PointLatLng(latitude, longitude)); -} - -void OPMapGadgetWidget::setMapProvider(QString provider) -{ - if (!m_widget || !m_map) - return; - - m_map->SetMapType(mapcontrol::Helper::MapTypeFromString(provider)); -} - -void OPMapGadgetWidget::setAccessMode(QString accessMode) -{ - if (!m_widget || !m_map) - return; - - m_map->configuration->SetAccessMode(mapcontrol::Helper::AccessModeFromString(accessMode)); -} - -void OPMapGadgetWidget::setUseOpenGL(bool useOpenGL) -{ - if (!m_widget || !m_map) - return; - - m_map->SetUseOpenGL(useOpenGL); -} - -void OPMapGadgetWidget::setShowTileGridLines(bool showTileGridLines) -{ - if (!m_widget || !m_map) - return; - - m_map->SetShowTileGridLines(showTileGridLines); -} - -void OPMapGadgetWidget::setUseMemoryCache(bool useMemoryCache) -{ - if (!m_widget || !m_map) - return; - - m_map->configuration->SetUseMemoryCache(useMemoryCache); -} - -void OPMapGadgetWidget::setCacheLocation(QString cacheLocation) -{ - if (!m_widget || !m_map) - return; - - cacheLocation = cacheLocation.simplified(); // remove any surrounding spaces - - if (cacheLocation.isEmpty()) return; - -// #if defined(Q_WS_WIN) -// if (!cacheLocation.endsWith('\\')) cacheLocation += '\\'; -// #elif defined(Q_WS_X11) - if (!cacheLocation.endsWith(QDir::separator())) cacheLocation += QDir::separator(); -// #elif defined(Q_WS_MAC) -// if (!cacheLocation.endsWith(QDir::separator())) cacheLocation += QDir::separator(); -// #endif - - QDir dir; - if (!dir.exists(cacheLocation)) - if (!dir.mkpath(cacheLocation)) - return; - -// qDebug() << "opmap: map cache dir: " << cacheLocation; - - m_map->configuration->SetCacheLocation(cacheLocation); -} - -void OPMapGadgetWidget::setMapMode(opMapModeType mode) -{ - if (!m_widget || !m_map) - return; - - if (mode != Normal_MapMode && mode != MagicWaypoint_MapMode) - mode = Normal_MapMode; // fix error - - if (m_map_mode == mode) - { // no change in map mode - switch (mode) - { // make sure the UI buttons are set correctly - case Normal_MapMode: - m_widget->toolButtonMagicWaypointMapMode->setChecked(false); - m_widget->toolButtonNormalMapMode->setChecked(true); - break; - case MagicWaypoint_MapMode: - m_widget->toolButtonNormalMapMode->setChecked(false); - m_widget->toolButtonMagicWaypointMapMode->setChecked(true); - break; - } - return; - } - - switch (mode) - { - case Normal_MapMode: - m_map_mode = Normal_MapMode; - - m_widget->toolButtonMagicWaypointMapMode->setChecked(false); - m_widget->toolButtonNormalMapMode->setChecked(true); - - hideMagicWaypointControls(); - - // delete the magic waypoint from the map - if (magic_waypoint.map_wp_item) - { - magic_waypoint.coord = magic_waypoint.map_wp_item->Coord(); - magic_waypoint.altitude = magic_waypoint.map_wp_item->Altitude(); - magic_waypoint.description = magic_waypoint.map_wp_item->Description(); - magic_waypoint.map_wp_item = NULL; - } - m_map->WPDeleteAll(); - - // restore the normal waypoints on the map - m_waypoint_list_mutex.lock(); - foreach (t_waypoint *wp, m_waypoint_list) - { - if (!wp) continue; - wp->map_wp_item = m_map->WPCreate(wp->coord, wp->altitude, wp->description); - if (!wp->map_wp_item) continue; - wp->map_wp_item->setZValue(10 + wp->map_wp_item->Number()); - wp->map_wp_item->setFlag(QGraphicsItem::ItemIsMovable, !wp->locked); - if (!wp->locked) - wp->map_wp_item->picture.load(QString::fromUtf8(":/opmap/images/waypoint_marker1.png")); - else - wp->map_wp_item->picture.load(QString::fromUtf8(":/opmap/images/waypoint_marker2.png")); - wp->map_wp_item->update(); - } - m_waypoint_list_mutex.unlock(); - - break; - - case MagicWaypoint_MapMode: - m_map_mode = MagicWaypoint_MapMode; - - m_widget->toolButtonNormalMapMode->setChecked(false); - m_widget->toolButtonMagicWaypointMapMode->setChecked(true); - - showMagicWaypointControls(); - - // delete the normal waypoints from the map - m_waypoint_list_mutex.lock(); - foreach (t_waypoint *wp, m_waypoint_list) - { - if (!wp) continue; - if (!wp->map_wp_item) continue; - wp->coord = wp->map_wp_item->Coord(); - wp->altitude = wp->map_wp_item->Altitude(); - wp->description = wp->map_wp_item->Description(); - wp->locked = (wp->map_wp_item->flags() & QGraphicsItem::ItemIsMovable) == 0; - wp->map_wp_item = NULL; - } - m_map->WPDeleteAll(); - m_waypoint_list_mutex.unlock(); - - // restore the magic waypoint on the map - magic_waypoint.map_wp_item = m_map->WPCreate(magic_waypoint.coord, magic_waypoint.altitude, magic_waypoint.description); - magic_waypoint.map_wp_item->setZValue(10 + magic_waypoint.map_wp_item->Number()); - magic_waypoint.map_wp_item->SetShowNumber(false); - magic_waypoint.map_wp_item->picture.load(QString::fromUtf8(":/opmap/images/waypoint_marker3.png")); - - break; - } -} - -// ************************************************************************************* -// Context menu stuff - -void OPMapGadgetWidget::createActions() -{ - if (!m_widget) - return; - - // *********************** - // create menu actions - - closeAct1 = new QAction(tr("Close menu"), this); - closeAct1->setStatusTip(tr("Close the context menu")); - - closeAct2 = new QAction(tr("Close menu"), this); - closeAct2->setStatusTip(tr("Close the context menu")); - - reloadAct = new QAction(tr("&Reload map"), this); - reloadAct->setShortcut(tr("F5")); - reloadAct->setStatusTip(tr("Reload the map tiles")); - connect(reloadAct, SIGNAL(triggered()), this, SLOT(onReloadAct_triggered())); - - copyMouseLatLonToClipAct = new QAction(tr("Mouse latitude and longitude"), this); - copyMouseLatLonToClipAct->setStatusTip(tr("Copy the mouse latitude and longitude to the clipboard")); - connect(copyMouseLatLonToClipAct, SIGNAL(triggered()), this, SLOT(onCopyMouseLatLonToClipAct_triggered())); - - copyMouseLatToClipAct = new QAction(tr("Mouse latitude"), this); - copyMouseLatToClipAct->setStatusTip(tr("Copy the mouse latitude to the clipboard")); - connect(copyMouseLatToClipAct, SIGNAL(triggered()), this, SLOT(onCopyMouseLatToClipAct_triggered())); - - copyMouseLonToClipAct = new QAction(tr("Mouse longitude"), this); - copyMouseLonToClipAct->setStatusTip(tr("Copy the mouse longitude to the clipboard")); - connect(copyMouseLonToClipAct, SIGNAL(triggered()), this, SLOT(onCopyMouseLonToClipAct_triggered())); - - /* - findPlaceAct = new QAction(tr("&Find place"), this); - findPlaceAct->setShortcut(tr("Ctrl+F")); - findPlaceAct->setStatusTip(tr("Find a location")); - connect(findPlaceAct, SIGNAL(triggered()), this, SLOT(onFindPlaceAct_triggered())); - */ - - showCompassAct = new QAction(tr("Show compass"), this); - showCompassAct->setStatusTip(tr("Show/Hide the compass")); - showCompassAct->setCheckable(true); - showCompassAct->setChecked(true); - connect(showCompassAct, SIGNAL(toggled(bool)), this, SLOT(onShowCompassAct_toggled(bool))); - - showDiagnostics = new QAction(tr("Show Diagnostics"), this); - showDiagnostics->setStatusTip(tr("Show/Hide the diagnostics")); - showDiagnostics->setCheckable(true); - showDiagnostics->setChecked(false); - connect(showDiagnostics, SIGNAL(toggled(bool)), this, SLOT(onShowDiagnostics_toggled(bool))); - - showHomeAct = new QAction(tr("Show Home"), this); - showHomeAct->setStatusTip(tr("Show/Hide the Home location")); - showHomeAct->setCheckable(true); - showHomeAct->setChecked(true); - connect(showHomeAct, SIGNAL(toggled(bool)), this, SLOT(onShowHomeAct_toggled(bool))); - - showUAVAct = new QAction(tr("Show UAV"), this); - showUAVAct->setStatusTip(tr("Show/Hide the UAV")); - showUAVAct->setCheckable(true); - showUAVAct->setChecked(true); - connect(showUAVAct, SIGNAL(toggled(bool)), this, SLOT(onShowUAVAct_toggled(bool))); - - zoomInAct = new QAction(tr("Zoom &In"), this); - zoomInAct->setShortcut(Qt::Key_PageUp); - zoomInAct->setStatusTip(tr("Zoom the map in")); - connect(zoomInAct, SIGNAL(triggered()), this, SLOT(onGoZoomInAct_triggered())); - - zoomOutAct = new QAction(tr("Zoom &Out"), this); - zoomOutAct->setShortcut(Qt::Key_PageDown); - zoomOutAct->setStatusTip(tr("Zoom the map out")); - connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(onGoZoomOutAct_triggered())); - - goMouseClickAct = new QAction(tr("Go to where you right clicked the mouse"), this); - goMouseClickAct->setStatusTip(tr("Center the map onto where you right clicked the mouse")); - connect(goMouseClickAct, SIGNAL(triggered()), this, SLOT(onGoMouseClickAct_triggered())); - - setHomeAct = new QAction(tr("Set the home location"), this); - setHomeAct->setStatusTip(tr("Set the home location to where you clicked")); - #if !defined(allow_manual_home_location_move) - setHomeAct->setEnabled(false); - #endif - connect(setHomeAct, SIGNAL(triggered()), this, SLOT(onSetHomeAct_triggered())); - - goHomeAct = new QAction(tr("Go to &Home location"), this); - goHomeAct->setShortcut(tr("Ctrl+H")); - goHomeAct->setStatusTip(tr("Center the map onto the home location")); - connect(goHomeAct, SIGNAL(triggered()), this, SLOT(onGoHomeAct_triggered())); - - goUAVAct = new QAction(tr("Go to &UAV location"), this); - goUAVAct->setShortcut(tr("Ctrl+U")); - goUAVAct->setStatusTip(tr("Center the map onto the UAV location")); - connect(goUAVAct, SIGNAL(triggered()), this, SLOT(onGoUAVAct_triggered())); - - followUAVpositionAct = new QAction(tr("Follow UAV position"), this); - followUAVpositionAct->setShortcut(tr("Ctrl+F")); - followUAVpositionAct->setStatusTip(tr("Keep the map centered onto the UAV")); - followUAVpositionAct->setCheckable(true); - followUAVpositionAct->setChecked(false); - connect(followUAVpositionAct, SIGNAL(toggled(bool)), this, SLOT(onFollowUAVpositionAct_toggled(bool))); - - followUAVheadingAct = new QAction(tr("Follow UAV heading"), this); - followUAVheadingAct->setShortcut(tr("Ctrl+F")); - followUAVheadingAct->setStatusTip(tr("Keep the map rotation to the UAV heading")); - followUAVheadingAct->setCheckable(true); - followUAVheadingAct->setChecked(false); - connect(followUAVheadingAct, SIGNAL(toggled(bool)), this, SLOT(onFollowUAVheadingAct_toggled(bool))); - - /* - TODO: Waypoint support is disabled for v1.0 - */ - - /* - wayPointEditorAct = new QAction(tr("&Waypoint editor"), this); - wayPointEditorAct->setShortcut(tr("Ctrl+W")); - wayPointEditorAct->setStatusTip(tr("Open the waypoint editor")); - wayPointEditorAct->setEnabled(false); // temporary - connect(wayPointEditorAct, SIGNAL(triggered()), this, SLOT(onOpenWayPointEditorAct_triggered())); - - addWayPointAct = new QAction(tr("&Add waypoint"), this); - addWayPointAct->setShortcut(tr("Ctrl+A")); - addWayPointAct->setStatusTip(tr("Add waypoint")); - connect(addWayPointAct, SIGNAL(triggered()), this, SLOT(onAddWayPointAct_triggered())); - - editWayPointAct = new QAction(tr("&Edit waypoint"), this); - editWayPointAct->setShortcut(tr("Ctrl+E")); - editWayPointAct->setStatusTip(tr("Edit waypoint")); - connect(editWayPointAct, SIGNAL(triggered()), this, SLOT(onEditWayPointAct_triggered())); - - lockWayPointAct = new QAction(tr("&Lock waypoint"), this); - lockWayPointAct->setStatusTip(tr("Lock/Unlock a waypoint")); - lockWayPointAct->setCheckable(true); - lockWayPointAct->setChecked(false); - connect(lockWayPointAct, SIGNAL(triggered()), this, SLOT(onLockWayPointAct_triggered())); - - deleteWayPointAct = new QAction(tr("&Delete waypoint"), this); - deleteWayPointAct->setShortcut(tr("Ctrl+D")); - deleteWayPointAct->setStatusTip(tr("Delete waypoint")); - connect(deleteWayPointAct, SIGNAL(triggered()), this, SLOT(onDeleteWayPointAct_triggered())); - - clearWayPointsAct = new QAction(tr("&Clear waypoints"), this); - clearWayPointsAct->setShortcut(tr("Ctrl+C")); - clearWayPointsAct->setStatusTip(tr("Clear waypoints")); - connect(clearWayPointsAct, SIGNAL(triggered()), this, SLOT(onClearWayPointsAct_triggered())); - */ - - homeMagicWaypointAct = new QAction(tr("Home magic waypoint"), this); - homeMagicWaypointAct->setStatusTip(tr("Move the magic waypoint to the home position")); - connect(homeMagicWaypointAct, SIGNAL(triggered()), this, SLOT(onHomeMagicWaypointAct_triggered())); - - mapModeActGroup = new QActionGroup(this); - connect(mapModeActGroup, SIGNAL(triggered(QAction *)), this, SLOT(onMapModeActGroup_triggered(QAction *))); - mapModeAct.clear(); - { - QAction *map_mode_act; - - map_mode_act = new QAction(tr("Normal"), mapModeActGroup); - map_mode_act->setCheckable(true); - map_mode_act->setChecked(m_map_mode == Normal_MapMode); - map_mode_act->setData((int)Normal_MapMode); - mapModeAct.append(map_mode_act); - - map_mode_act = new QAction(tr("Magic Waypoint"), mapModeActGroup); - map_mode_act->setCheckable(true); - map_mode_act->setChecked(m_map_mode == MagicWaypoint_MapMode); - map_mode_act->setData((int)MagicWaypoint_MapMode); - mapModeAct.append(map_mode_act); - } - - zoomActGroup = new QActionGroup(this); - connect(zoomActGroup, SIGNAL(triggered(QAction *)), this, SLOT(onZoomActGroup_triggered(QAction *))); - zoomAct.clear(); - for (int i = min_zoom; i <= max_zoom; i++) - { - QAction *zoom_act = new QAction(QString::number(i), zoomActGroup); - zoom_act->setCheckable(true); - zoom_act->setData(i); - zoomAct.append(zoom_act); - } - - // ***** - // safe area - - showSafeAreaAct = new QAction(tr("Show Safe Area"), this); - showSafeAreaAct->setStatusTip(tr("Show/Hide the Safe Area around the home location")); - showSafeAreaAct->setCheckable(true); - showSafeAreaAct->setChecked(m_map->Home->ShowSafeArea()); - connect(showSafeAreaAct, SIGNAL(toggled(bool)), this, SLOT(onShowSafeAreaAct_toggled(bool))); - - safeAreaActGroup = new QActionGroup(this); - connect(safeAreaActGroup, SIGNAL(triggered(QAction *)), this, SLOT(onSafeAreaActGroup_triggered(QAction *))); - safeAreaAct.clear(); - for (int i = 0; i < (int)(sizeof(safe_area_radius_list) / sizeof(safe_area_radius_list[0])); i++) - { - int safeArea = safe_area_radius_list[i]; - QAction *safeArea_act = new QAction(QString::number(safeArea) + "m", safeAreaActGroup); - safeArea_act->setCheckable(true); - safeArea_act->setChecked(safeArea == m_map->Home->SafeArea()); - safeArea_act->setData(safeArea); - safeAreaAct.append(safeArea_act); - } - - // ***** - // UAV trail - - uavTrailTypeActGroup = new QActionGroup(this); - connect(uavTrailTypeActGroup, SIGNAL(triggered(QAction *)), this, SLOT(onUAVTrailTypeActGroup_triggered(QAction *))); - uavTrailTypeAct.clear(); - QStringList uav_trail_type_list = mapcontrol::Helper::UAVTrailTypes(); - for (int i = 0; i < uav_trail_type_list.count(); i++) - { - mapcontrol::UAVTrailType::Types uav_trail_type = mapcontrol::Helper::UAVTrailTypeFromString(uav_trail_type_list[i]); - QAction *uavTrailType_act = new QAction(mapcontrol::Helper::StrFromUAVTrailType(uav_trail_type), uavTrailTypeActGroup); - uavTrailType_act->setCheckable(true); - uavTrailType_act->setChecked(uav_trail_type == m_map->UAV->GetTrailType()); - uavTrailType_act->setData(i); - uavTrailTypeAct.append(uavTrailType_act); - } - - showTrailAct = new QAction(tr("Show Trail dots"), this); - showTrailAct->setStatusTip(tr("Show/Hide the Trail dots")); - showTrailAct->setCheckable(true); - showTrailAct->setChecked(true); - connect(showTrailAct, SIGNAL(toggled(bool)), this, SLOT(onShowTrailAct_toggled(bool))); - - showTrailLineAct = new QAction(tr("Show Trail lines"), this); - showTrailLineAct->setStatusTip(tr("Show/Hide the Trail lines")); - showTrailLineAct->setCheckable(true); - showTrailLineAct->setChecked(true); - connect(showTrailLineAct, SIGNAL(toggled(bool)), this, SLOT(onShowTrailLineAct_toggled(bool))); - - clearUAVtrailAct = new QAction(tr("Clear UAV trail"), this); - clearUAVtrailAct->setStatusTip(tr("Clear the UAV trail")); - connect(clearUAVtrailAct, SIGNAL(triggered()), this, SLOT(onClearUAVtrailAct_triggered())); - - uavTrailTimeActGroup = new QActionGroup(this); - connect(uavTrailTimeActGroup, SIGNAL(triggered(QAction *)), this, SLOT(onUAVTrailTimeActGroup_triggered(QAction *))); - uavTrailTimeAct.clear(); - for (int i = 0; i < (int)(sizeof(uav_trail_time_list) / sizeof(uav_trail_time_list[0])); i++) - { - int uav_trail_time = uav_trail_time_list[i]; - QAction *uavTrailTime_act = new QAction(QString::number(uav_trail_time) + " sec", uavTrailTimeActGroup); - uavTrailTime_act->setCheckable(true); - uavTrailTime_act->setChecked(uav_trail_time == m_map->UAV->TrailTime()); - uavTrailTime_act->setData(uav_trail_time); - uavTrailTimeAct.append(uavTrailTime_act); - } - - uavTrailDistanceActGroup = new QActionGroup(this); - connect(uavTrailDistanceActGroup, SIGNAL(triggered(QAction *)), this, SLOT(onUAVTrailDistanceActGroup_triggered(QAction *))); - uavTrailDistanceAct.clear(); - for (int i = 0; i < (int)(sizeof(uav_trail_distance_list) / sizeof(uav_trail_distance_list[0])); i++) - { - int uav_trail_distance = uav_trail_distance_list[i]; - QAction *uavTrailDistance_act = new QAction(QString::number(uav_trail_distance) + " meters", uavTrailDistanceActGroup); - uavTrailDistance_act->setCheckable(true); - uavTrailDistance_act->setChecked(uav_trail_distance == m_map->UAV->TrailDistance()); - uavTrailDistance_act->setData(uav_trail_distance); - uavTrailDistanceAct.append(uavTrailDistance_act); - } - - // ***** - - // *********************** -} - -void OPMapGadgetWidget::onReloadAct_triggered() -{ - if (!m_widget || !m_map) - return; - - m_map->ReloadMap(); -} - -void OPMapGadgetWidget::onCopyMouseLatLonToClipAct_triggered() -{ -// QClipboard *clipboard = qApp->clipboard(); - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(QString::number(context_menu_lat_lon.Lat(), 'f', 7) + ", " + QString::number(context_menu_lat_lon.Lng(), 'f', 7), QClipboard::Clipboard); -} - -void OPMapGadgetWidget::onCopyMouseLatToClipAct_triggered() -{ -// QClipboard *clipboard = qApp->clipboard(); - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(QString::number(context_menu_lat_lon.Lat(), 'f', 7), QClipboard::Clipboard); -} - -void OPMapGadgetWidget::onCopyMouseLonToClipAct_triggered() -{ -// QClipboard *clipboard = qApp->clipboard(); - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(QString::number(context_menu_lat_lon.Lng(), 'f', 7), QClipboard::Clipboard); -} - - -void OPMapGadgetWidget::onShowCompassAct_toggled(bool show) -{ - if (!m_widget || !m_map) - return; - - m_map->SetShowCompass(show); -} - -void OPMapGadgetWidget::onShowDiagnostics_toggled(bool show) -{ - if (!m_widget || !m_map) - return; - - m_map->SetShowDiagnostics(show); -} - -void OPMapGadgetWidget::onShowHomeAct_toggled(bool show) -{ - if (!m_widget || !m_map) - return; - - m_map->Home->setVisible(show); -} - -void OPMapGadgetWidget::onShowUAVAct_toggled(bool show) -{ - if (!m_widget || !m_map) - return; - - m_map->UAV->setVisible(show); - m_map->GPS->setVisible(show); -} - -void OPMapGadgetWidget::onShowTrailAct_toggled(bool show) -{ - if (!m_widget || !m_map) - return; - - m_map->UAV->SetShowTrail(show); - m_map->GPS->SetShowTrail(show); -} - -void OPMapGadgetWidget::onShowTrailLineAct_toggled(bool show) -{ - if (!m_widget || !m_map) - return; - - m_map->UAV->SetShowTrailLine(show); - m_map->GPS->SetShowTrailLine(show); -} - -void OPMapGadgetWidget::onMapModeActGroup_triggered(QAction *action) -{ - if (!m_widget || !m_map || !action) - return; - - opMapModeType mode = (opMapModeType)action->data().toInt(); - - setMapMode(mode); -} - -void OPMapGadgetWidget::onGoZoomInAct_triggered() -{ - zoomIn(); -} - -void OPMapGadgetWidget::onGoZoomOutAct_triggered() -{ - zoomOut(); -} - -void OPMapGadgetWidget::onZoomActGroup_triggered(QAction *action) -{ - if (!m_widget || !action) - return; - - setZoom(action->data().toInt()); -} - -void OPMapGadgetWidget::onGoMouseClickAct_triggered() -{ - if (!m_widget || !m_map) - return; - - m_map->SetCurrentPosition(m_map->currentMousePosition()); // center the map onto the mouse position -} - -void OPMapGadgetWidget::onSetHomeAct_triggered() -{ - if (!m_widget || !m_map) - return; - - setHome(context_menu_lat_lon); - - setHomeLocationObject(); // update the HomeLocation UAVObject -} - -void OPMapGadgetWidget::onGoHomeAct_triggered() -{ - if (!m_widget || !m_map) - return; - - goHome(); -} - -void OPMapGadgetWidget::onGoUAVAct_triggered() -{ - if (!m_widget || !m_map) - return; - - double latitude; - double longitude; - double altitude; - if (getUAVPosition(latitude, longitude, altitude)) // get current UAV position - { - internals::PointLatLng uav_pos = internals::PointLatLng(latitude, longitude); // current UAV position - internals::PointLatLng map_pos = m_map->CurrentPosition(); // current MAP position - if (map_pos != uav_pos) m_map->SetCurrentPosition(uav_pos); // center the map onto the UAV - } -} - -void OPMapGadgetWidget::onFollowUAVpositionAct_toggled(bool checked) -{ - if (!m_widget || !m_map) - return; - - if (m_widget->toolButtonMapUAV->isChecked() != checked) - m_widget->toolButtonMapUAV->setChecked(checked); - - setMapFollowingMode(); -} - -void OPMapGadgetWidget::onFollowUAVheadingAct_toggled(bool checked) -{ - if (!m_widget || !m_map) - return; - - if (m_widget->toolButtonMapUAVheading->isChecked() != checked) - m_widget->toolButtonMapUAVheading->setChecked(checked); - - setMapFollowingMode(); -} - -void OPMapGadgetWidget::onUAVTrailTypeActGroup_triggered(QAction *action) -{ - if (!m_widget || !m_map) - return; - - int trail_type_idx = action->data().toInt(); - - QStringList uav_trail_type_list = mapcontrol::Helper::UAVTrailTypes(); - mapcontrol::UAVTrailType::Types uav_trail_type = mapcontrol::Helper::UAVTrailTypeFromString(uav_trail_type_list[trail_type_idx]); - - m_map->UAV->SetTrailType(uav_trail_type); -} - -void OPMapGadgetWidget::onClearUAVtrailAct_triggered() -{ - if (!m_widget || !m_map) - return; - - m_map->UAV->DeleteTrail(); - m_map->GPS->DeleteTrail(); -} - -void OPMapGadgetWidget::onUAVTrailTimeActGroup_triggered(QAction *action) -{ - if (!m_widget || !m_map) - return; - - int trail_time = (double)action->data().toInt(); - - m_map->UAV->SetTrailTime(trail_time); -} - -void OPMapGadgetWidget::onUAVTrailDistanceActGroup_triggered(QAction *action) -{ - if (!m_widget || !m_map) - return; - - int trail_distance = action->data().toInt(); - - m_map->UAV->SetTrailDistance(trail_distance); -} - -/** - * TODO: unused for v1.0 - **/ -/* -void OPMapGadgetWidget::onAddWayPointAct_triggered() -{ - if (!m_widget || !m_map) - return; - - if (m_map_mode != Normal_MapMode) - return; - - m_waypoint_list_mutex.lock(); - - // create a waypoint on the map at the last known mouse position - t_waypoint *wp = new t_waypoint; - wp->map_wp_item = NULL; - wp->coord = context_menu_lat_lon; - wp->altitude = 0; - wp->description = ""; - wp->locked = false; - wp->time_seconds = 0; - wp->hold_time_seconds = 0; - wp->map_wp_item = m_map->WPCreate(wp->coord, wp->altitude, wp->description); - - wp->map_wp_item->setZValue(10 + wp->map_wp_item->Number()); - - wp->map_wp_item->setFlag(QGraphicsItem::ItemIsMovable, !wp->locked); - - if (wp->map_wp_item) - { - if (!wp->locked) - wp->map_wp_item->picture.load(QString::fromUtf8(":/opmap/images/waypoint_marker1.png")); - else - wp->map_wp_item->picture.load(QString::fromUtf8(":/opmap/images/waypoint_marker2.png")); - wp->map_wp_item->update(); - } - - // and remember it in our own local waypoint list - m_waypoint_list.append(wp); - - m_waypoint_list_mutex.unlock(); -} -*/ - -/** - * Called when the user asks to edit a waypoint from the map - * - * TODO: should open an interface to edit waypoint properties, or - * propagate the signal to a specific WP plugin (tbd). - **/ -/* -void OPMapGadgetWidget::onEditWayPointAct_triggered() -{ - if (!m_widget || !m_map) - return; - - if (m_map_mode != Normal_MapMode) - return; - - if (!m_mouse_waypoint) - return; - - //waypoint_edit_dialog.editWaypoint(m_mouse_waypoint); - - m_mouse_waypoint = NULL; -} -*/ - -/** - * TODO: unused for v1.0 - */ -/* -void OPMapGadgetWidget::onLockWayPointAct_triggered() -{ - if (!m_widget || !m_map || !m_mouse_waypoint) - return; - - if (m_map_mode != Normal_MapMode) - return; - - bool locked = (m_mouse_waypoint->flags() & QGraphicsItem::ItemIsMovable) == 0; - m_mouse_waypoint->setFlag(QGraphicsItem::ItemIsMovable, locked); - - if (!locked) - m_mouse_waypoint->picture.load(QString::fromUtf8(":/opmap/images/waypoint_marker2.png")); - else - m_mouse_waypoint->picture.load(QString::fromUtf8(":/opmap/images/waypoint_marker1.png")); - m_mouse_waypoint->update(); - - m_mouse_waypoint = NULL; -} -*/ - -/** - * TODO: unused for v1.0 - */ -/* -void OPMapGadgetWidget::onDeleteWayPointAct_triggered() -{ - if (!m_widget || !m_map) - return; - - if (m_map_mode != Normal_MapMode) - return; - - if (!m_mouse_waypoint) - return; - - bool locked = (m_mouse_waypoint->flags() & QGraphicsItem::ItemIsMovable) == 0; - - if (locked) return; // waypoint is locked - - QMutexLocker locker(&m_waypoint_list_mutex); - - for (int i = 0; i < m_waypoint_list.count(); i++) - { - t_waypoint *wp = m_waypoint_list.at(i); - if (!wp) continue; - if (!wp->map_wp_item || wp->map_wp_item != m_mouse_waypoint) continue; - - // delete the waypoint from the map - m_map->WPDelete(wp->map_wp_item); - - // delete the waypoint from our local waypoint list - m_waypoint_list.removeAt(i); - - delete wp; - - break; - } -// -// foreach (t_waypoint *wp, m_waypoint_list) -// { -// if (!wp) continue; -// if (!wp->map_wp_item || wp->map_wp_item != m_mouse_waypoint) continue; -// -// // delete the waypoint from the map -// m_map->WPDelete(wp->map_wp_item); -// -// // delete the waypoint from our local waypoint list -// m_waypoint_list.removeOne(wp); -// -// delete wp; -// -// break; -// } - - m_mouse_waypoint = NULL; -} -*/ - -/** - * TODO: No Waypoint support in v1.0 - */ -/* -void OPMapGadgetWidget::onClearWayPointsAct_triggered() -{ - if (!m_widget || !m_map) - return; - - if (m_map_mode != Normal_MapMode) - return; - - QMutexLocker locker(&m_waypoint_list_mutex); - - m_map->WPDeleteAll(); - - foreach (t_waypoint *wp, m_waypoint_list) - { - if (wp) - { - delete wp; - wp = NULL; - } - } - - m_waypoint_list.clear(); -} -*/ - -void OPMapGadgetWidget::onHomeMagicWaypointAct_triggered() -{ - // center the magic waypoint on the home position - homeMagicWaypoint(); -} - -void OPMapGadgetWidget::onShowSafeAreaAct_toggled(bool show) -{ - if (!m_widget || !m_map) - return; - - m_map->Home->SetShowSafeArea(show); // show the safe area - m_map->Home->RefreshPos(); -} - -void OPMapGadgetWidget::onSafeAreaActGroup_triggered(QAction *action) -{ - if (!m_widget || !m_map) - return; - - int radius = action->data().toInt(); - - m_map->Home->SetSafeArea(radius); // set the radius (meters) - m_map->Home->RefreshPos(); - - // move the magic waypoint if need be to keep it within the safe area around the home position - keepMagicWaypointWithInSafeArea(); -} - -/** -* move the magic waypoint to the home position -**/ -void OPMapGadgetWidget::homeMagicWaypoint() -{ - if (!m_widget || !m_map) - return; - - if (m_map_mode != MagicWaypoint_MapMode) - return; - - magic_waypoint.coord = home_position.coord; - - if (magic_waypoint.map_wp_item) - magic_waypoint.map_wp_item->SetCoord(magic_waypoint.coord); -} - -// ************************************************************************************* -// move the UAV to the magic waypoint position - -void OPMapGadgetWidget::moveToMagicWaypointPosition() -{ - if (!m_widget || !m_map) - return; - - if (m_map_mode != MagicWaypoint_MapMode) - return; - -// internals::PointLatLng coord = magic_waypoint.coord; -// double altitude = magic_waypoint.altitude; - - - // ToDo: - -} - -// ************************************************************************************* -// temporary until an object is created for managing the save/restore - -// load the contents of a simple text file into a combobox -void OPMapGadgetWidget::loadComboBoxLines(QComboBox *comboBox, QString filename) -{ - if (!comboBox) return; - if (filename.isNull() || filename.isEmpty()) return; - - QFile file(filename); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) - return; - - QTextStream in(&file); - - while (!in.atEnd()) - { - QString line = in.readLine().simplified(); - if (line.isNull() || line.isEmpty()) continue; - comboBox->addItem(line); - } - - file.close(); -} - -// save a combobox text contents to a simple text file -void OPMapGadgetWidget::saveComboBoxLines(QComboBox *comboBox, QString filename) -{ - if (!comboBox) return; - if (filename.isNull() || filename.isEmpty()) return; - - QFile file(filename); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) - return; - - QTextStream out(&file); - - for (int i = 0; i < comboBox->count(); i++) - { - QString line = comboBox->itemText(i).simplified(); - if (line.isNull() || line.isEmpty()) continue; - out << line << "\n"; - } - - file.close(); -} - -// ************************************************************************************* -// show/hide the magic waypoint controls - -void OPMapGadgetWidget::hideMagicWaypointControls() -{ - m_widget->lineWaypoint->setVisible(false); - m_widget->toolButtonHomeWaypoint->setVisible(false); - m_widget->toolButtonMoveToWP->setVisible(false); -} - -void OPMapGadgetWidget::showMagicWaypointControls() -{ - m_widget->lineWaypoint->setVisible(true); - m_widget->toolButtonHomeWaypoint->setVisible(true); - - #if defined(allow_manual_home_location_move) - m_widget->toolButtonMoveToWP->setVisible(true); - #else - m_widget->toolButtonMoveToWP->setVisible(false); - #endif -} - -// ************************************************************************************* -// move the magic waypoint to keep it within the safe area boundry - -void OPMapGadgetWidget::keepMagicWaypointWithInSafeArea() -{ - - // calcute the bearing and distance from the home position to the magic waypoint - double dist = distance(home_position.coord, magic_waypoint.coord); - double bear = bearing(home_position.coord, magic_waypoint.coord); - - // get the maximum safe distance - in kilometers - double boundry_dist = (double)m_map->Home->SafeArea() / 1000; - -// if (dist <= boundry_dist) -// return; // the magic waypoint is still within the safe area, don't move it - - if (dist > boundry_dist) dist = boundry_dist; - - // move the magic waypoint - - magic_waypoint.coord = destPoint(home_position.coord, bear, dist); - - if (m_map_mode == MagicWaypoint_MapMode) - { // move the on-screen waypoint - if (magic_waypoint.map_wp_item) - magic_waypoint.map_wp_item->SetCoord(magic_waypoint.coord); - } -} - -// ************************************************************************************* -// return the distance between two points .. in kilometers - -double OPMapGadgetWidget::distance(internals::PointLatLng from, internals::PointLatLng to) -{ - double lat1 = from.Lat() * deg_to_rad; - double lon1 = from.Lng() * deg_to_rad; - - double lat2 = to.Lat() * deg_to_rad; - double lon2 = to.Lng() * deg_to_rad; - - // *********************** - // Haversine formula -/* - double delta_lat = lat2 - lat1; - double delta_lon = lon2 - lon1; - - double t1 = sin(delta_lat / 2); - double t2 = sin(delta_lon / 2); - double a = (t1 * t1) + cos(lat1) * cos(lat2) * (t2 * t2); - double c = 2 * atan2(sqrt(a), sqrt(1 - a)); - - return (earth_mean_radius * c); -*/ - // *********************** - // Spherical Law of Cosines - - return (acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon2 - lon1)) * earth_mean_radius); - - // *********************** -} - -// ************************************************************************************* -// return the bearing from one point to another .. in degrees - -double OPMapGadgetWidget::bearing(internals::PointLatLng from, internals::PointLatLng to) -{ - double lat1 = from.Lat() * deg_to_rad; - double lon1 = from.Lng() * deg_to_rad; - - double lat2 = to.Lat() * deg_to_rad; - double lon2 = to.Lng() * deg_to_rad; - -// double delta_lat = lat2 - lat1; - double delta_lon = lon2 - lon1; - - double y = sin(delta_lon) * cos(lat2); - double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(delta_lon); - double bear = atan2(y, x) * rad_to_deg; - - bear += 360; - while (bear < 0) bear += 360; - while (bear >= 360) bear -= 360; - - return bear; -} - -// ************************************************************************************* -// return a destination lat/lon point given a source lat/lon point and the bearing and distance from the source point - -internals::PointLatLng OPMapGadgetWidget::destPoint(internals::PointLatLng source, double bear, double dist) -{ - double lat1 = source.Lat() * deg_to_rad; - double lon1 = source.Lng() * deg_to_rad; - - bear *= deg_to_rad; - - double ad = dist / earth_mean_radius; - - double lat2 = asin(sin(lat1) * cos(ad) + cos(lat1) * sin(ad) * cos(bear)); - double lon2 = lon1 + atan2(sin(bear) * sin(ad) * cos(lat1), cos(ad) - sin(lat1) * sin(lat2)); - - return internals::PointLatLng(lat2 * rad_to_deg, lon2 * rad_to_deg); -} - -// ************************************************************************************* - -bool OPMapGadgetWidget::getUAVPosition(double &latitude, double &longitude, double &altitude) -{ - double BaseECEF[3]; - double NED[3]; - double LLA[3]; - UAVObject *obj; - - if (!obm) - return false; - - obj = dynamic_cast(obm->getObject(QString("HomeLocation"))); - if (!obj) return false; - BaseECEF[0] = obj->getField(QString("ECEF"))->getDouble(0) / 100; - BaseECEF[1] = obj->getField(QString("ECEF"))->getDouble(1) / 100; - BaseECEF[2] = obj->getField(QString("ECEF"))->getDouble(2) / 100; - - obj = dynamic_cast(obm->getObject(QString("PositionActual"))); - if (!obj) return false; - NED[0] = obj->getField(QString("North"))->getDouble() / 100; - NED[1] = obj->getField(QString("East"))->getDouble() / 100; - NED[2] = obj->getField(QString("Down"))->getDouble() / 100; - -// obj = dynamic_cast(om->getObject(QString("PositionDesired"))); - -// obj = dynamic_cast(objManager->getObject("VelocityActual")); // air speed - - Utils::CoordinateConversions().GetLLA(BaseECEF, NED, LLA); - - latitude = LLA[0]; - longitude = LLA[1]; - altitude = LLA[2]; - - if (latitude != latitude) latitude = 0; // nan detection -// if (isNan(latitude)) latitude = 0; // nan detection - else -// if (!isFinite(latitude)) latitude = 0; -// else - if (latitude > 90) latitude = 90; - else - if (latitude < -90) latitude = -90; - - if (longitude != longitude) longitude = 0; // nan detection - else -// if (longitude > std::numeric_limits::max()) longitude = 0; // +infinite -// else -// if (longitude < -std::numeric_limits::max()) longitude = 0; // -infinite -// else - if (longitude > 180) longitude = 180; - else - if (longitude < -180) longitude = -180; - - if (altitude != altitude) altitude = 0; // nan detection - - return true; -} - -// ************************************************************************************* - -bool OPMapGadgetWidget::getGPSPosition(double &latitude, double &longitude, double &altitude) -{ - double LLA[3]; - - if (!obum) - return false; - - if (obum->getGPSPosition(LLA) < 0) - return false; // error - - latitude = LLA[0]; - longitude = LLA[1]; - altitude = LLA[2]; - - return true; -} - -double OPMapGadgetWidget::getUAV_Yaw() -{ - if (!obm) - return 0; - - UAVObject *obj = dynamic_cast(obm->getObject(QString("AttitudeActual"))); - double yaw = obj->getField(QString("Yaw"))->getDouble(); - - if (yaw != yaw) yaw = 0; // nan detection - - while (yaw < 0) yaw += 360; - while (yaw >= 360) yaw -= 360; - - return yaw; -} - -// ************************************************************************************* - -void OPMapGadgetWidget::setMapFollowingMode() -{ - if (!m_widget || !m_map) - return; - - if (!followUAVpositionAct->isChecked()) - { - m_map->UAV->SetMapFollowType(UAVMapFollowType::None); - m_map->SetRotate(0); // reset map rotation to 0deg - } - else - if (!followUAVheadingAct->isChecked()) - { - m_map->UAV->SetMapFollowType(UAVMapFollowType::CenterMap); - m_map->SetRotate(0); // reset map rotation to 0deg - } - else - { - m_map->UAV->SetMapFollowType(UAVMapFollowType::CenterMap); // the map library won't let you reset the uav rotation if it's already in rotate mode - - m_map->UAV->SetUAVHeading(0); // reset the UAV heading to 0deg - m_map->UAV->SetMapFollowType(UAVMapFollowType::CenterAndRotateMap); - } -} - -// ************************************************************************************* -// update the HomeLocation UAV Object - -bool OPMapGadgetWidget::setHomeLocationObject() -{ - if (!obum) - return false; - - double LLA[3] = {home_position.coord.Lat(), home_position.coord.Lng(), home_position.altitude}; - return (obum->setHomeLocation(LLA, true) >= 0); -} - -// ************************************************************************************* - -void OPMapGadgetWidget::SetUavPic(QString UAVPic) -{ - m_map->SetUavPic(UAVPic); -} +/** + ****************************************************************************** + * + * @file opmapgadgetwidget.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup OPMapPlugin OpenPilot Map Plugin + * @{ + * @brief The OpenPilot Map plugin + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "opmapgadgetwidget.h" +#include "ui_opmap_widget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "utils/stylehelper.h" +#include "utils/homelocationutil.h" +#include "utils/worldmagmodel.h" + +#include "uavtalk/telemetrymanager.h" + +#include "positionactual.h" +#include "homelocation.h" + +#define allow_manual_home_location_move + +// ************************************************************************************* + +#define deg_to_rad ((double)M_PI / 180.0) +#define rad_to_deg (180.0 / (double)M_PI) + +#define earth_mean_radius 6371 // kilometers + +#define max_digital_zoom 3 // maximum allowed digital zoom level + +const int safe_area_radius_list[] = {5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000}; // meters + +const int uav_trail_time_list[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // seconds + +const int uav_trail_distance_list[] = {1, 2, 5, 10, 20, 50, 100, 200, 500}; // meters + +const int max_update_rate_list[] = {100, 200, 500, 1000, 2000, 5000}; // milliseconds + +// ************************************************************************************* + + +// ************************************************************************************* +// NOTE: go back to SVN REV 2137 and earlier to get back to experimental waypoint support. +// ************************************************************************************* + + +// constructor +OPMapGadgetWidget::OPMapGadgetWidget(QWidget *parent) : QWidget(parent) +{ + // ************** + + m_widget = NULL; + m_map = NULL; + findPlaceCompleter = NULL; + + m_mouse_waypoint = NULL; + + pm = NULL; + obm = NULL; + obum = NULL; + + m_prev_tile_number = 0; + + m_min_zoom = m_max_zoom = 0; + + m_map_mode = Normal_MapMode; + + m_maxUpdateRate = max_update_rate_list[4]; // 2 seconds + + m_telemetry_connected = false; + + m_context_menu_lat_lon = m_mouse_lat_lon = internals::PointLatLng(0, 0); + + setMouseTracking(true); + + pm = ExtensionSystem::PluginManager::instance(); + if (pm) + { + obm = pm->getObject(); + obum = pm->getObject(); + } + + // ************** + // get current location + + double latitude = 0; + double longitude = 0; + double altitude = 0; + + // current position + getUAVPosition(latitude, longitude, altitude); + + internals::PointLatLng pos_lat_lon = internals::PointLatLng(latitude, longitude); + + // ************** + // default home position + + m_home_position.coord = pos_lat_lon; + m_home_position.altitude = altitude; + m_home_position.locked = false; + + // ************** + // default magic waypoint params + + m_magic_waypoint.map_wp_item = NULL; + m_magic_waypoint.coord = m_home_position.coord; + m_magic_waypoint.altitude = altitude; + m_magic_waypoint.description = "Magic waypoint"; + m_magic_waypoint.locked = false; + m_magic_waypoint.time_seconds = 0; + m_magic_waypoint.hold_time_seconds = 0; + + // ************** + // create the widget that holds the user controls and the map + + m_widget = new Ui::OPMap_Widget(); + m_widget->setupUi(this); + + // ************** + // create the central map widget + + m_map = new mapcontrol::OPMapWidget(); // create the map object + + m_map->setFrameStyle(QFrame::NoFrame); // no border frame + m_map->setBackgroundBrush(QBrush(Utils::StyleHelper::baseColor())); // tile background + + m_map->configuration->DragButton = Qt::LeftButton; // use the left mouse button for map dragging + + m_widget->horizontalSliderZoom->setMinimum(m_map->MinZoom()); // + m_widget->horizontalSliderZoom->setMaximum(m_map->MaxZoom() + max_digital_zoom); // + + m_min_zoom = m_widget->horizontalSliderZoom->minimum(); // minimum zoom we can accept + m_max_zoom = m_widget->horizontalSliderZoom->maximum(); // maximum zoom we can accept + + m_map->SetMouseWheelZoomType(internals::MouseWheelZoomType::MousePositionWithoutCenter); // set how the mouse wheel zoom functions + m_map->SetFollowMouse(true); // we want a contiuous mouse position reading + + m_map->SetShowHome(true); // display the HOME position on the map + m_map->SetShowUAV(true); // display the UAV position on the map + + m_map->Home->SetSafeArea(safe_area_radius_list[0]); // set radius (meters) + m_map->Home->SetShowSafeArea(true); // show the safe area + + m_map->UAV->SetTrailTime(uav_trail_time_list[0]); // seconds + m_map->UAV->SetTrailDistance(uav_trail_distance_list[1]); // meters + + m_map->UAV->SetTrailType(UAVTrailType::ByTimeElapsed); +// m_map->UAV->SetTrailType(UAVTrailType::ByDistance); + + m_map->GPS->SetTrailTime(uav_trail_time_list[0]); // seconds + m_map->GPS->SetTrailDistance(uav_trail_distance_list[1]); // meters + + m_map->GPS->SetTrailType(UAVTrailType::ByTimeElapsed); +// m_map->GPS->SetTrailType(UAVTrailType::ByDistance); + + // ************** + + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + + QVBoxLayout *layout = new QVBoxLayout; + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(m_map); + m_widget->mapWidget->setLayout(layout); + + // ************** + // set the user control options + + // TODO: this switch does not make sense, does it?? + + switch (m_map_mode) + { + case Normal_MapMode: + m_widget->toolButtonMagicWaypointMapMode->setChecked(false); + m_widget->toolButtonNormalMapMode->setChecked(true); + hideMagicWaypointControls(); + break; + + case MagicWaypoint_MapMode: + m_widget->toolButtonNormalMapMode->setChecked(false); + m_widget->toolButtonMagicWaypointMapMode->setChecked(true); + showMagicWaypointControls(); + break; + + default: + m_map_mode = Normal_MapMode; + m_widget->toolButtonMagicWaypointMapMode->setChecked(false); + m_widget->toolButtonNormalMapMode->setChecked(true); + hideMagicWaypointControls(); + break; + } + + m_widget->labelUAVPos->setText("---"); + m_widget->labelMapPos->setText("---"); + m_widget->labelMousePos->setText("---"); + m_widget->labelMapZoom->setText("---"); + + + // Splitter is not used at the moment: + // m_widget->splitter->setCollapsible(1, false); + + // set the size of the collapsable widgets + //QList m_SizeList; + //m_SizeList << 0 << 0 << 0; + //m_widget->splitter->setSizes(m_SizeList); + + m_widget->progressBarMap->setMaximum(1); + +/* + #if defined(Q_OS_MAC) + #elif defined(Q_OS_WIN) + m_widget->comboBoxFindPlace->clear(); + loadComboBoxLines(m_widget->comboBoxFindPlace, QCoreApplication::applicationDirPath() + "/opmap_find_place_history.txt"); + m_widget->comboBoxFindPlace->setCurrentIndex(-1); + #else + #endif +*/ + + + // ************** + // map stuff + + connect(m_map, SIGNAL(zoomChanged(double, double, double)), this, SLOT(zoomChanged(double, double, double))); // map zoom change signals + connect(m_map, SIGNAL(OnCurrentPositionChanged(internals::PointLatLng)), this, SLOT(OnCurrentPositionChanged(internals::PointLatLng))); // map poisition change signals + connect(m_map, SIGNAL(OnTileLoadComplete()), this, SLOT(OnTileLoadComplete())); // tile loading stop signals + connect(m_map, SIGNAL(OnTileLoadStart()), this, SLOT(OnTileLoadStart())); // tile loading start signals + connect(m_map, SIGNAL(OnMapDrag()), this, SLOT(OnMapDrag())); // map drag signals + connect(m_map, SIGNAL(OnMapZoomChanged()), this, SLOT(OnMapZoomChanged())); // map zoom changed + connect(m_map, SIGNAL(OnMapTypeChanged(MapType::Types)), this, SLOT(OnMapTypeChanged(MapType::Types))); // map type changed + connect(m_map, SIGNAL(OnEmptyTileError(int, core::Point)), this, SLOT(OnEmptyTileError(int, core::Point))); // tile error + connect(m_map, SIGNAL(OnTilesStillToLoad(int)), this, SLOT(OnTilesStillToLoad(int))); // tile loading signals + connect(m_map, SIGNAL(WPNumberChanged(int const&,int const&,WayPointItem*)), this, SLOT(WPNumberChanged(int const&,int const&,WayPointItem*))); + connect(m_map, SIGNAL(WPValuesChanged(WayPointItem*)), this, SLOT(WPValuesChanged(WayPointItem*))); + connect(m_map, SIGNAL(WPInserted(int const&, WayPointItem*)), this, SLOT(WPInserted(int const&, WayPointItem*))); + connect(m_map, SIGNAL(WPDeleted(int const&)), this, SLOT(WPDeleted(int const&))); + + m_map->SetCurrentPosition(m_home_position.coord); // set the map position + m_map->Home->SetCoord(m_home_position.coord); // set the HOME position + m_map->UAV->SetUAVPos(m_home_position.coord, 0.0); // set the UAV position + m_map->GPS->SetUAVPos(m_home_position.coord, 0.0); // set the UAV position + + // ************** + // create various context menu (mouse right click menu) actions + + createActions(); + + // ************** + // connect to the UAVObject updates we require to become a bit aware of our environment: + + if (pm) + { + // Register for Home Location state changes + if (obm) + { + UAVDataObject *obj = dynamic_cast(obm->getObject(QString("HomeLocation"))); + if (obj) + { + connect(obj, SIGNAL(objectUpdated(UAVObject *)), this , SLOT(homePositionUpdated(UAVObject *))); + } + } + + // Listen to telemetry connection events + TelemetryManager *telMngr = pm->getObject(); + if (telMngr) + { + connect(telMngr, SIGNAL(connected()), this, SLOT(onTelemetryConnect())); + connect(telMngr, SIGNAL(disconnected()), this, SLOT(onTelemetryDisconnect())); + } + } + + // ************** + // create the desired timers + + m_updateTimer = new QTimer(); + m_updateTimer->setInterval(m_maxUpdateRate); + connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(updatePosition())); + m_updateTimer->start(); + + m_statusUpdateTimer = new QTimer(); + m_statusUpdateTimer->setInterval(200); +// m_statusUpdateTimer->setInterval(m_maxUpdateRate); + connect(m_statusUpdateTimer, SIGNAL(timeout()), this, SLOT(updateMousePos())); + m_statusUpdateTimer->start(); + + // ************** + + m_map->setFocus(); +} + +// destructor +OPMapGadgetWidget::~OPMapGadgetWidget() +{ + if (m_map) + { + disconnect(m_map, 0, 0, 0); + m_map->SetShowHome(false); // doing this appears to stop the map lib crashing on exit + m_map->SetShowUAV(false); // " " + } + + + // this destructor doesn't appear to be called at shutdown??? + +// #if defined(Q_OS_MAC) +// #elif defined(Q_OS_WIN) +// saveComboBoxLines(m_widget->comboBoxFindPlace, QCoreApplication::applicationDirPath() + "/opmap_find_place_history.txt"); +// #else +// #endif + + m_waypoint_list_mutex.lock(); + foreach (t_waypoint *wp, m_waypoint_list) + { + if (!wp) continue; + + + // todo: + + + delete wp->map_wp_item; + } + m_waypoint_list_mutex.unlock(); + m_waypoint_list.clear(); + + if (m_map) + { + delete m_map; + m_map = NULL; + } +} + +// ************************************************************************************* +// widget signals .. the mouseMoveEvent does not get called - don't yet know why + +void OPMapGadgetWidget::resizeEvent(QResizeEvent *event) +{ + qDebug("opmap: resizeEvent"); + + QWidget::resizeEvent(event); +} + +void OPMapGadgetWidget::mouseMoveEvent(QMouseEvent *event) +{ + qDebug("opmap: mouseMoveEvent"); + + if (m_widget && m_map) + { + } + + if (event->buttons() & Qt::LeftButton) + { +// QPoint pos = event->pos(); + } + + QWidget::mouseMoveEvent(event); +} + +void OPMapGadgetWidget::contextMenuEvent(QContextMenuEvent *event) +{ // the user has right clicked on the map - create the pop-up context menu and display it + + QString s; + + if (!m_widget || !m_map) + return; + + if (event->reason() != QContextMenuEvent::Mouse) + return; // not a mouse click event + + // current mouse position + QPoint p = m_map->mapFromGlobal(event->globalPos()); + m_context_menu_lat_lon = m_map->GetFromLocalToLatLng(p); +// m_context_menu_lat_lon = m_map->currentMousePosition(); + + if (!m_map->contentsRect().contains(p)) + return; // the mouse click was not on the map + + // show the mouse position + s = QString::number(m_context_menu_lat_lon.Lat(), 'f', 7) + " " + QString::number(m_context_menu_lat_lon.Lng(), 'f', 7); + m_widget->labelMousePos->setText(s); + + // find out if we have a waypoint under the mouse cursor + QGraphicsItem *item = m_map->itemAt(p); + m_mouse_waypoint = qgraphicsitem_cast(item); + + // find out if the waypoint is locked (or not) + bool waypoint_locked = false; + if (m_mouse_waypoint) + waypoint_locked = (m_mouse_waypoint->flags() & QGraphicsItem::ItemIsMovable) == 0; + + // **************** + // Dynamically create the popup menu + + QMenu menu(this); + + menu.addAction(closeAct1); + + menu.addSeparator(); + + menu.addAction(reloadAct); + + menu.addSeparator(); + + QMenu maxUpdateRateSubMenu(tr("&Max Update Rate ") + "(" + QString::number(m_maxUpdateRate) + " ms)", this); + for (int i = 0; i < maxUpdateRateAct.count(); i++) + maxUpdateRateSubMenu.addAction(maxUpdateRateAct.at(i)); + menu.addMenu(&maxUpdateRateSubMenu); + + menu.addSeparator(); + + switch (m_map_mode) + { + case Normal_MapMode: s = tr(" (Normal)"); break; + case MagicWaypoint_MapMode: s = tr(" (Magic Waypoint)"); break; + default: s = tr(" (Unknown)"); break; + } + for (int i = 0; i < mapModeAct.count(); i++) + { // set the menu to checked (or not) + QAction *act = mapModeAct.at(i); + if (!act) continue; + if (act->data().toInt() == (int)m_map_mode) + act->setChecked(true); + } + QMenu mapModeSubMenu(tr("Map mode") + s, this); + for (int i = 0; i < mapModeAct.count(); i++) + mapModeSubMenu.addAction(mapModeAct.at(i)); + menu.addMenu(&mapModeSubMenu); + + menu.addSeparator(); + + QMenu copySubMenu(tr("Copy"), this); + copySubMenu.addAction(copyMouseLatLonToClipAct); + copySubMenu.addAction(copyMouseLatToClipAct); + copySubMenu.addAction(copyMouseLonToClipAct); + menu.addMenu(©SubMenu); + + menu.addSeparator(); + + /* + menu.addAction(findPlaceAct); + + menu.addSeparator(); + */ + + menu.addAction(showSafeAreaAct); + QMenu safeAreaSubMenu(tr("Safe Area Radius") + " (" + QString::number(m_map->Home->SafeArea()) + "m)", this); + for (int i = 0; i < safeAreaAct.count(); i++) + safeAreaSubMenu.addAction(safeAreaAct.at(i)); + menu.addMenu(&safeAreaSubMenu); + + menu.addSeparator(); + + menu.addAction(showCompassAct); + + menu.addAction(showDiagnostics); + + menu.addSeparator()->setText(tr("Zoom")); + + menu.addAction(zoomInAct); + menu.addAction(zoomOutAct); + + QMenu zoomSubMenu(tr("&Zoom ") + "(" + QString::number(m_map->ZoomTotal()) + ")", this); + for (int i = 0; i < zoomAct.count(); i++) + zoomSubMenu.addAction(zoomAct.at(i)); + menu.addMenu(&zoomSubMenu); + + menu.addSeparator(); + + menu.addAction(goMouseClickAct); + + menu.addSeparator()->setText(tr("HOME")); + + menu.addAction(setHomeAct); + menu.addAction(showHomeAct); + menu.addAction(goHomeAct); + + // **** + // uav trails + + menu.addSeparator()->setText(tr("UAV Trail")); + + QMenu uavTrailTypeSubMenu(tr("UAV trail type") + " (" + mapcontrol::Helper::StrFromUAVTrailType(m_map->UAV->GetTrailType()) + ")", this); + for (int i = 0; i < uavTrailTypeAct.count(); i++) + uavTrailTypeSubMenu.addAction(uavTrailTypeAct.at(i)); + menu.addMenu(&uavTrailTypeSubMenu); + + QMenu uavTrailTimeSubMenu(tr("UAV trail time") + " (" + QString::number(m_map->UAV->TrailTime()) + " sec)", this); + for (int i = 0; i < uavTrailTimeAct.count(); i++) + uavTrailTimeSubMenu.addAction(uavTrailTimeAct.at(i)); + menu.addMenu(&uavTrailTimeSubMenu); + + QMenu uavTrailDistanceSubMenu(tr("UAV trail distance") + " (" + QString::number(m_map->UAV->TrailDistance()) + " meters)", this); + for (int i = 0; i < uavTrailDistanceAct.count(); i++) + uavTrailDistanceSubMenu.addAction(uavTrailDistanceAct.at(i)); + menu.addMenu(&uavTrailDistanceSubMenu); + + menu.addAction(showTrailAct); + + menu.addAction(showTrailLineAct); + + menu.addAction(clearUAVtrailAct); + + // **** + + menu.addSeparator()->setText(tr("UAV")); + + menu.addAction(showUAVAct); + menu.addAction(followUAVpositionAct); + menu.addAction(followUAVheadingAct); + menu.addAction(goUAVAct); + + // ********* + + switch (m_map_mode) + { + case Normal_MapMode: + // only show the waypoint stuff if not in 'magic waypoint' mode + /* + menu.addSeparator()->setText(tr("Waypoints")); + + menu.addAction(wayPointEditorAct); + menu.addAction(addWayPointAct); + + if (m_mouse_waypoint) + { // we have a waypoint under the mouse + menu.addAction(editWayPointAct); + + lockWayPointAct->setChecked(waypoint_locked); + menu.addAction(lockWayPointAct); + + if (!waypoint_locked) + menu.addAction(deleteWayPointAct); + } + + m_waypoint_list_mutex.lock(); + if (m_waypoint_list.count() > 0) + menu.addAction(clearWayPointsAct); // we have waypoints + m_waypoint_list_mutex.unlock(); + */ + + break; + + case MagicWaypoint_MapMode: + menu.addSeparator()->setText(tr("Waypoints")); + menu.addAction(homeMagicWaypointAct); + break; + } + + // ********* + + menu.addSeparator(); + + menu.addAction(closeAct2); + + menu.exec(event->globalPos()); // popup the menu + + // **************** +} + +void OPMapGadgetWidget::keyPressEvent(QKeyEvent* event) +{ + qDebug() << "opmap: keyPressEvent, key =" << event->key() << endl; + + switch (event->key()) + { + case Qt::Key_Escape: + break; + + case Qt::Key_F1: + break; + + case Qt::Key_F2: + break; + + case Qt::Key_Up: + break; + + case Qt::Key_Down: + break; + + case Qt::Key_Left: + break; + + case Qt::Key_Right: + break; + + case Qt::Key_PageUp: + break; + + case Qt::Key_PageDown: + break; + } +} + +// ************************************************************************************* +// timer signals + +/** + Updates the UAV position on the map. It is called every 200ms + by a timer. + + TODO: consider updating upon object update, not timer. + + from Pip: No don't update on object update - had reports that peoples PC's can't cope with high update rates - have had to allow user to set map update from 100ms to 5 seconds (depending on their PC's graphics processing ability), so this needs to be kept on a timer. + */ +void OPMapGadgetWidget::updatePosition() +{ + double uav_latitude, uav_longitude, uav_altitude, uav_yaw; + double gps_latitude, gps_longitude, gps_altitude, gps_heading; + + internals::PointLatLng uav_pos; + internals::PointLatLng gps_pos; + + if (!m_widget || !m_map) + return; + + QMutexLocker locker(&m_map_mutex); +// Pip I'm sorry, I know this was here with a purpose vvv +// from Pip: let you off :) + //if (!telemetry_connected) + // return; + + // ************* + // get the current UAV details + + // get current UAV position + if (!getUAVPosition(uav_latitude, uav_longitude, uav_altitude)) + return; + + // get current UAV heading + uav_yaw = getUAV_Yaw(); + + uav_pos = internals::PointLatLng(uav_latitude, uav_longitude); + + // ************* + // get the current GPS details + + // get current GPS position + if (!getGPSPosition(gps_latitude, gps_longitude, gps_altitude)) + return; + + // get current GPS heading +// gps_heading = getGPS_Heading(); + gps_heading = 0; + + gps_pos = internals::PointLatLng(gps_latitude, gps_longitude); + + // ************* + // display the UAV position + + QString str = + "lat: " + QString::number(uav_pos.Lat(), 'f', 7) + + " lon: " + QString::number(uav_pos.Lng(), 'f', 7) + + " " + QString::number(uav_yaw, 'f', 1) + "deg" + + " " + QString::number(uav_altitude, 'f', 1) + "m"; +// " " + QString::number(uav_ground_speed_meters_per_second, 'f', 1) + "m/s"; + m_widget->labelUAVPos->setText(str); + + // ************* + // set the UAV icon position on the map + + m_map->UAV->SetUAVPos(uav_pos, uav_altitude); // set the maps UAV position +// qDebug()<<"UAVPOSITION"<UAV->SetUAVHeading(uav_yaw); // set the maps UAV heading + + // ************* + // set the GPS icon position on the map + + m_map->GPS->SetUAVPos(gps_pos, gps_altitude); // set the maps GPS position + m_map->GPS->SetUAVHeading(gps_heading); // set the maps GPS heading + + // ************* +} + +/** + Update plugin behaviour based on mouse position; Called every few ms by a + timer. + */ +void OPMapGadgetWidget::updateMousePos() +{ + if (!m_widget || !m_map) + return; + + QMutexLocker locker(&m_map_mutex); + + QPoint p = m_map->mapFromGlobal(QCursor::pos()); + internals::PointLatLng lat_lon = m_map->GetFromLocalToLatLng(p); // fetch the current lat/lon mouse position + + if (!m_map->contentsRect().contains(p)) + return; // the mouse is not on the map + +// internals::PointLatLng lat_lon = m_map->currentMousePosition(); // fetch the current lat/lon mouse position + + QGraphicsItem *item = m_map->itemAt(p); + + // find out if we are over the home position + mapcontrol::HomeItem *home = qgraphicsitem_cast(item); + + // find out if we are over the UAV + mapcontrol::UAVItem *uav = qgraphicsitem_cast(item); + + // find out if we have a waypoint under the mouse cursor + mapcontrol::WayPointItem *wp = qgraphicsitem_cast(item); + + if (m_mouse_lat_lon == lat_lon) + return; // the mouse has not moved + + m_mouse_lat_lon = lat_lon; // yes it has! + + internals::PointLatLng home_lat_lon = m_map->Home->Coord(); + + QString s = QString::number(m_mouse_lat_lon.Lat(), 'f', 7) + " " + QString::number(m_mouse_lat_lon.Lng(), 'f', 7); + if (wp) + { + s += " wp[" + QString::number(wp->Number()) + "]"; + + double dist = distance(home_lat_lon, wp->Coord()); + double bear = bearing(home_lat_lon, wp->Coord()); + s += " " + QString::number(dist * 1000, 'f', 1) + "m"; + s += " " + QString::number(bear, 'f', 1) + "deg"; + } + else + if (home) + { + s += " home"; + + double dist = distance(home_lat_lon, m_mouse_lat_lon); + double bear = bearing(home_lat_lon, m_mouse_lat_lon); + s += " " + QString::number(dist * 1000, 'f', 1) + "m"; + s += " " + QString::number(bear, 'f', 1) + "deg"; + } + else + if (uav) + { + s += " uav"; + + double latitude; + double longitude; + double altitude; + if (getUAVPosition(latitude, longitude, altitude)) // get current UAV position + { + internals::PointLatLng uav_pos = internals::PointLatLng(latitude, longitude); + +// double dist = distance(home_lat_lon, uav_pos); +// double bear = bearing(home_lat_lon, uav_pos); +// s += " " + QString::number(dist * 1000, 'f', 1) + "m"; +// s += " " + QString::number(bear, 'f', 1) + "deg"; + } + } + m_widget->labelMousePos->setText(s); +} + +// ************************************************************************************* +// map signals + + +/** + Update the Plugin UI to reflect a change in zoom level + */ +void OPMapGadgetWidget::zoomChanged(double zoomt, double zoom, double zoomd) +{ + if (!m_widget || !m_map) + return; + + QString s = "tot:" + QString::number(zoomt, 'f', 1) + " rea:" + QString::number(zoom, 'f', 1) + " dig:" + QString::number(zoomd, 'f', 1); + m_widget->labelMapZoom->setText(s); + + int i_zoom = (int)(zoomt + 0.5); + + if (i_zoom < m_min_zoom) i_zoom = m_min_zoom; + else + if (i_zoom > m_max_zoom) i_zoom = m_max_zoom; + + if (m_widget->horizontalSliderZoom->value() != i_zoom) + m_widget->horizontalSliderZoom->setValue(i_zoom); // set the GUI zoom slider position + + int index0_zoom = i_zoom - m_min_zoom; // zoom level starting at index level '0' + if (index0_zoom < zoomAct.count()) + zoomAct.at(index0_zoom)->setChecked(true); // set the right-click context menu zoom level +} + +void OPMapGadgetWidget::OnMapDrag() +{ +} + +void OPMapGadgetWidget::OnCurrentPositionChanged(internals::PointLatLng point) +{ + if (!m_widget || !m_map) + return; + + QString coord_str = QString::number(point.Lat(), 'f', 7) + " " + QString::number(point.Lng(), 'f', 7) + " "; + m_widget->labelMapPos->setText(coord_str); +} + +/** + Update the progress bar while there are still tiles to load + */ +void OPMapGadgetWidget::OnTilesStillToLoad(int number) +{ + if (!m_widget || !m_map) + return; + +// if (prev_tile_number < number || m_widget->progressBarMap->maximum() < number) +// m_widget->progressBarMap->setMaximum(number); + + if (m_widget->progressBarMap->maximum() < number) + m_widget->progressBarMap->setMaximum(number); + + m_widget->progressBarMap->setValue(m_widget->progressBarMap->maximum() - number); // update the progress bar + +// m_widget->labelNumTilesToLoad->setText(QString::number(number)); + + m_prev_tile_number = number; +} + +/** + Show the progress bar as soon as the map lib starts downloading + */ +void OPMapGadgetWidget::OnTileLoadStart() +{ + if (!m_widget || !m_map) + return; + + m_widget->progressBarMap->setVisible(true); +} + +/** + Hide the progress bar once the map lib has finished downloading + + TODO: somehow this gets called before tile load is actually complete? + */ + +void OPMapGadgetWidget::OnTileLoadComplete() +{ + if (!m_widget || !m_map) + return; + + m_widget->progressBarMap->setVisible(false); +} + +void OPMapGadgetWidget::OnMapZoomChanged() +{ +} + +void OPMapGadgetWidget::OnMapTypeChanged(MapType::Types type) +{ + Q_UNUSED(type); +} + +void OPMapGadgetWidget::OnEmptyTileError(int zoom, core::Point pos) +{ + Q_UNUSED(zoom); + Q_UNUSED(pos); +} + +void OPMapGadgetWidget::WPNumberChanged(int const &oldnumber, int const &newnumber, WayPointItem *waypoint) +{ + Q_UNUSED(oldnumber); + Q_UNUSED(newnumber); + Q_UNUSED(waypoint); +} + +void OPMapGadgetWidget::WPValuesChanged(WayPointItem *waypoint) +{ +// qDebug("opmap: WPValuesChanged"); + + switch (m_map_mode) + { + case Normal_MapMode: + m_waypoint_list_mutex.lock(); + foreach (t_waypoint *wp, m_waypoint_list) + { // search for the waypoint in our own waypoint list and update it + if (!wp) continue; + if (!wp->map_wp_item) continue; + if (wp->map_wp_item != waypoint) continue; + // found the waypoint in our list + wp->coord = waypoint->Coord(); + wp->altitude = waypoint->Altitude(); + wp->description = waypoint->Description(); + break; + } + m_waypoint_list_mutex.unlock(); + break; + + case MagicWaypoint_MapMode: + // update our copy of the magic waypoint + if (m_magic_waypoint.map_wp_item && m_magic_waypoint.map_wp_item == waypoint) + { + m_magic_waypoint.coord = waypoint->Coord(); + m_magic_waypoint.altitude = waypoint->Altitude(); + m_magic_waypoint.description = waypoint->Description(); + + // move the UAV to the magic waypoint position + // moveToMagicWaypointPosition(); + } + break; + } + +} + +/** + TODO: slot to do something upon Waypoint insertion + */ +void OPMapGadgetWidget::WPInserted(int const &number, WayPointItem *waypoint) +{ + Q_UNUSED(number); + Q_UNUSED(waypoint); +} + +/** + TODO: slot to do something upon Waypoint deletion + */ +void OPMapGadgetWidget::WPDeleted(int const &number) +{ + Q_UNUSED(number); +} + + +void OPMapGadgetWidget::on_toolButtonZoomP_clicked() +{ + QMutexLocker locker(&m_map_mutex); + zoomIn(); +} + +void OPMapGadgetWidget::on_toolButtonZoomM_clicked() +{ + QMutexLocker locker(&m_map_mutex); + zoomOut(); +} + +void OPMapGadgetWidget::on_toolButtonMapHome_clicked() +{ + QMutexLocker locker(&m_map_mutex); + goHome(); +} + +void OPMapGadgetWidget::on_toolButtonMapUAV_clicked() +{ + if (!m_widget || !m_map) + return; + + QMutexLocker locker(&m_map_mutex); + + followUAVpositionAct->toggle(); +} + +void OPMapGadgetWidget::on_toolButtonMapUAVheading_clicked() +{ + if (!m_widget || !m_map) + return; + + followUAVheadingAct->toggle(); +} + +void OPMapGadgetWidget::on_horizontalSliderZoom_sliderMoved(int position) +{ + if (!m_widget || !m_map) + return; + + QMutexLocker locker(&m_map_mutex); + + setZoom(position); +} + + +void OPMapGadgetWidget::on_toolButtonNormalMapMode_clicked() +{ + setMapMode(Normal_MapMode); +} + +void OPMapGadgetWidget::on_toolButtonMagicWaypointMapMode_clicked() +{ + setMapMode(MagicWaypoint_MapMode); +} + +void OPMapGadgetWidget::on_toolButtonHomeWaypoint_clicked() +{ + homeMagicWaypoint(); +} + +void OPMapGadgetWidget::on_toolButtonMoveToWP_clicked() +{ + moveToMagicWaypointPosition(); +} + +// ************************************************************************************* +// public slots + +void OPMapGadgetWidget::onTelemetryConnect() +{ + m_telemetry_connected = true; + + if (!obum) return; + + bool set; + double LLA[3]; + + // *********************** + // fetch the home location + + if (obum->getHomeLocation(set, LLA) < 0) + return; // error + + setHome(internals::PointLatLng(LLA[0], LLA[1])); + + if (m_map) + m_map->SetCurrentPosition(m_home_position.coord); // set the map position + + // *********************** +} + +void OPMapGadgetWidget::onTelemetryDisconnect() +{ + m_telemetry_connected = false; +} + +// Updates the Home position icon whenever the HomePosition object is updated +void OPMapGadgetWidget::homePositionUpdated(UAVObject *hp) +{ + if (!hp) + return; + + double lat = hp->getField("Latitude")->getDouble() * 1e-7; + double lon = hp->getField("Longitude")->getDouble() * 1e-7; + setHome(internals::PointLatLng(lat, lon)); +} + +// ************************************************************************************* +// public functions + +/** + Sets the home position on the map widget + */ +void OPMapGadgetWidget::setHome(QPointF pos) +{ + if (!m_widget || !m_map) + return; + + double latitude = pos.x(); + double longitude = pos.y(); + + if (latitude > 90) latitude = 90; + else + if (latitude < -90) latitude = -90; + + if (longitude != longitude) longitude = 0; // nan detection + else + if (longitude > 180) longitude = 180; + else + if (longitude < -180) longitude = -180; + + setHome(internals::PointLatLng(latitude, longitude)); +} + +/** + Sets the home position on the map widget + */ +void OPMapGadgetWidget::setHome(internals::PointLatLng pos_lat_lon) +{ + if (!m_widget || !m_map) + return; + + if (pos_lat_lon.Lat() != pos_lat_lon.Lat() || pos_lat_lon.Lng() != pos_lat_lon.Lng()) + return;; // nan prevention + + double latitude = pos_lat_lon.Lat(); + double longitude = pos_lat_lon.Lng(); + + if (latitude != latitude) latitude = 0; // nan detection + else + if (latitude > 90) latitude = 90; + else + if (latitude < -90) latitude = -90; + + if (longitude != longitude) longitude = 0; // nan detection + else + if (longitude > 180) longitude = 180; + else + if (longitude < -180) longitude = -180; + + // ********* + + m_home_position.coord = internals::PointLatLng(latitude, longitude); + + m_map->Home->SetCoord(m_home_position.coord); + m_map->Home->RefreshPos(); + + // move the magic waypoint to keep it within the safe area boundry + keepMagicWaypointWithInSafeArea(); +} + + +/** + Centers the map over the home position + */ +void OPMapGadgetWidget::goHome() +{ + if (!m_widget || !m_map) + return; + + followUAVpositionAct->setChecked(false); + + internals::PointLatLng home_pos = m_home_position.coord; // get the home location + m_map->SetCurrentPosition(home_pos); // center the map onto the home location +} + + +void OPMapGadgetWidget::zoomIn() +{ + if (!m_widget || !m_map) + return; + + int zoom = m_map->ZoomTotal() + 1; + + if (zoom < m_min_zoom) zoom = m_min_zoom; + else + if (zoom > m_max_zoom) zoom = m_max_zoom; + + m_map->SetZoom(zoom); +} + +void OPMapGadgetWidget::zoomOut() +{ + if (!m_widget || !m_map) + return; + + int zoom = m_map->ZoomTotal() - 1; + + if (zoom < m_min_zoom) zoom = m_min_zoom; + else + if (zoom > m_max_zoom) zoom = m_max_zoom; + + m_map->SetZoom(zoom); +} + +void OPMapGadgetWidget::setMaxUpdateRate(int update_rate) +{ + if (!m_widget || !m_map) + return; + + int list_size = sizeof(max_update_rate_list) / sizeof(max_update_rate_list[0]); + int min_rate = max_update_rate_list[0]; + int max_rate = max_update_rate_list[list_size - 1]; + + if (update_rate < min_rate) update_rate = min_rate; + else + if (update_rate > max_rate) update_rate = max_rate; + + m_maxUpdateRate = update_rate; + + if (m_updateTimer) + m_updateTimer->setInterval(m_maxUpdateRate); + +// if (m_statusUpdateTimer) +// m_statusUpdateTimer->setInterval(m_maxUpdateRate); +} + +void OPMapGadgetWidget::setZoom(int zoom) +{ + if (!m_widget || !m_map) + return; + + if (zoom < m_min_zoom) zoom = m_min_zoom; + else + if (zoom > m_max_zoom) zoom = m_max_zoom; + + internals::MouseWheelZoomType::Types zoom_type = m_map->GetMouseWheelZoomType(); + m_map->SetMouseWheelZoomType(internals::MouseWheelZoomType::ViewCenter); + + m_map->SetZoom(zoom); + + m_map->SetMouseWheelZoomType(zoom_type); +} + +void OPMapGadgetWidget::setPosition(QPointF pos) +{ + if (!m_widget || !m_map) + return; + + double latitude = pos.y(); + double longitude = pos.x(); + + if (latitude != latitude || longitude != longitude) + return; // nan prevention + + if (latitude > 90) latitude = 90; + else + if (latitude < -90) latitude = -90; + + if (longitude > 180) longitude = 180; + else + if (longitude < -180) longitude = -180; + + m_map->SetCurrentPosition(internals::PointLatLng(latitude, longitude)); +} + +void OPMapGadgetWidget::setMapProvider(QString provider) +{ + if (!m_widget || !m_map) + return; + + m_map->SetMapType(mapcontrol::Helper::MapTypeFromString(provider)); +} + +void OPMapGadgetWidget::setAccessMode(QString accessMode) +{ + if (!m_widget || !m_map) + return; + + m_map->configuration->SetAccessMode(mapcontrol::Helper::AccessModeFromString(accessMode)); +} + +void OPMapGadgetWidget::setUseOpenGL(bool useOpenGL) +{ + if (!m_widget || !m_map) + return; + + m_map->SetUseOpenGL(useOpenGL); +} + +void OPMapGadgetWidget::setShowTileGridLines(bool showTileGridLines) +{ + if (!m_widget || !m_map) + return; + + m_map->SetShowTileGridLines(showTileGridLines); +} + +void OPMapGadgetWidget::setUseMemoryCache(bool useMemoryCache) +{ + if (!m_widget || !m_map) + return; + + m_map->configuration->SetUseMemoryCache(useMemoryCache); +} + +void OPMapGadgetWidget::setCacheLocation(QString cacheLocation) +{ + if (!m_widget || !m_map) + return; + + cacheLocation = cacheLocation.simplified(); // remove any surrounding spaces + + if (cacheLocation.isEmpty()) return; + +// #if defined(Q_WS_WIN) +// if (!cacheLocation.endsWith('\\')) cacheLocation += '\\'; +// #elif defined(Q_WS_X11) + if (!cacheLocation.endsWith(QDir::separator())) cacheLocation += QDir::separator(); +// #elif defined(Q_WS_MAC) +// if (!cacheLocation.endsWith(QDir::separator())) cacheLocation += QDir::separator(); +// #endif + + QDir dir; + if (!dir.exists(cacheLocation)) + if (!dir.mkpath(cacheLocation)) + return; + +// qDebug() << "opmap: map cache dir: " << cacheLocation; + + m_map->configuration->SetCacheLocation(cacheLocation); +} + +void OPMapGadgetWidget::setMapMode(opMapModeType mode) +{ + if (!m_widget || !m_map) + return; + + if (mode != Normal_MapMode && mode != MagicWaypoint_MapMode) + mode = Normal_MapMode; // fix error + + if (m_map_mode == mode) + { // no change in map mode + switch (mode) + { // make sure the UI buttons are set correctly + case Normal_MapMode: + m_widget->toolButtonMagicWaypointMapMode->setChecked(false); + m_widget->toolButtonNormalMapMode->setChecked(true); + break; + case MagicWaypoint_MapMode: + m_widget->toolButtonNormalMapMode->setChecked(false); + m_widget->toolButtonMagicWaypointMapMode->setChecked(true); + break; + } + return; + } + + switch (mode) + { + case Normal_MapMode: + m_map_mode = Normal_MapMode; + + m_widget->toolButtonMagicWaypointMapMode->setChecked(false); + m_widget->toolButtonNormalMapMode->setChecked(true); + + hideMagicWaypointControls(); + + // delete the magic waypoint from the map + if (m_magic_waypoint.map_wp_item) + { + m_magic_waypoint.coord = m_magic_waypoint.map_wp_item->Coord(); + m_magic_waypoint.altitude = m_magic_waypoint.map_wp_item->Altitude(); + m_magic_waypoint.description = m_magic_waypoint.map_wp_item->Description(); + m_magic_waypoint.map_wp_item = NULL; + } + m_map->WPDeleteAll(); + + // restore the normal waypoints on the map + m_waypoint_list_mutex.lock(); + foreach (t_waypoint *wp, m_waypoint_list) + { + if (!wp) continue; + wp->map_wp_item = m_map->WPCreate(wp->coord, wp->altitude, wp->description); + if (!wp->map_wp_item) continue; + wp->map_wp_item->setZValue(10 + wp->map_wp_item->Number()); + wp->map_wp_item->setFlag(QGraphicsItem::ItemIsMovable, !wp->locked); + if (!wp->locked) + wp->map_wp_item->picture.load(QString::fromUtf8(":/opmap/images/waypoint_marker1.png")); + else + wp->map_wp_item->picture.load(QString::fromUtf8(":/opmap/images/waypoint_marker2.png")); + wp->map_wp_item->update(); + } + m_waypoint_list_mutex.unlock(); + + break; + + case MagicWaypoint_MapMode: + m_map_mode = MagicWaypoint_MapMode; + + m_widget->toolButtonNormalMapMode->setChecked(false); + m_widget->toolButtonMagicWaypointMapMode->setChecked(true); + + showMagicWaypointControls(); + + // delete the normal waypoints from the map + m_waypoint_list_mutex.lock(); + foreach (t_waypoint *wp, m_waypoint_list) + { + if (!wp) continue; + if (!wp->map_wp_item) continue; + wp->coord = wp->map_wp_item->Coord(); + wp->altitude = wp->map_wp_item->Altitude(); + wp->description = wp->map_wp_item->Description(); + wp->locked = (wp->map_wp_item->flags() & QGraphicsItem::ItemIsMovable) == 0; + wp->map_wp_item = NULL; + } + m_map->WPDeleteAll(); + m_waypoint_list_mutex.unlock(); + + // restore the magic waypoint on the map + m_magic_waypoint.map_wp_item = m_map->WPCreate(m_magic_waypoint.coord, m_magic_waypoint.altitude, m_magic_waypoint.description); + m_magic_waypoint.map_wp_item->setZValue(10 + m_magic_waypoint.map_wp_item->Number()); + m_magic_waypoint.map_wp_item->SetShowNumber(false); + m_magic_waypoint.map_wp_item->picture.load(QString::fromUtf8(":/opmap/images/waypoint_marker3.png")); + + break; + } +} + +// ************************************************************************************* +// Context menu stuff + +void OPMapGadgetWidget::createActions() +{ + int list_size; + + if (!m_widget || !m_map) + return; + + // *********************** + // create menu actions + + closeAct1 = new QAction(tr("Close menu"), this); + closeAct1->setStatusTip(tr("Close the context menu")); + + closeAct2 = new QAction(tr("Close menu"), this); + closeAct2->setStatusTip(tr("Close the context menu")); + + reloadAct = new QAction(tr("&Reload map"), this); + reloadAct->setShortcut(tr("F5")); + reloadAct->setStatusTip(tr("Reload the map tiles")); + connect(reloadAct, SIGNAL(triggered()), this, SLOT(onReloadAct_triggered())); + + copyMouseLatLonToClipAct = new QAction(tr("Mouse latitude and longitude"), this); + copyMouseLatLonToClipAct->setStatusTip(tr("Copy the mouse latitude and longitude to the clipboard")); + connect(copyMouseLatLonToClipAct, SIGNAL(triggered()), this, SLOT(onCopyMouseLatLonToClipAct_triggered())); + + copyMouseLatToClipAct = new QAction(tr("Mouse latitude"), this); + copyMouseLatToClipAct->setStatusTip(tr("Copy the mouse latitude to the clipboard")); + connect(copyMouseLatToClipAct, SIGNAL(triggered()), this, SLOT(onCopyMouseLatToClipAct_triggered())); + + copyMouseLonToClipAct = new QAction(tr("Mouse longitude"), this); + copyMouseLonToClipAct->setStatusTip(tr("Copy the mouse longitude to the clipboard")); + connect(copyMouseLonToClipAct, SIGNAL(triggered()), this, SLOT(onCopyMouseLonToClipAct_triggered())); + + /* + findPlaceAct = new QAction(tr("&Find place"), this); + findPlaceAct->setShortcut(tr("Ctrl+F")); + findPlaceAct->setStatusTip(tr("Find a location")); + connect(findPlaceAct, SIGNAL(triggered()), this, SLOT(onFindPlaceAct_triggered())); + */ + + showCompassAct = new QAction(tr("Show compass"), this); + showCompassAct->setStatusTip(tr("Show/Hide the compass")); + showCompassAct->setCheckable(true); + showCompassAct->setChecked(true); + connect(showCompassAct, SIGNAL(toggled(bool)), this, SLOT(onShowCompassAct_toggled(bool))); + + showDiagnostics = new QAction(tr("Show Diagnostics"), this); + showDiagnostics->setStatusTip(tr("Show/Hide the diagnostics")); + showDiagnostics->setCheckable(true); + showDiagnostics->setChecked(false); + connect(showDiagnostics, SIGNAL(toggled(bool)), this, SLOT(onShowDiagnostics_toggled(bool))); + + showHomeAct = new QAction(tr("Show Home"), this); + showHomeAct->setStatusTip(tr("Show/Hide the Home location")); + showHomeAct->setCheckable(true); + showHomeAct->setChecked(true); + connect(showHomeAct, SIGNAL(toggled(bool)), this, SLOT(onShowHomeAct_toggled(bool))); + + showUAVAct = new QAction(tr("Show UAV"), this); + showUAVAct->setStatusTip(tr("Show/Hide the UAV")); + showUAVAct->setCheckable(true); + showUAVAct->setChecked(true); + connect(showUAVAct, SIGNAL(toggled(bool)), this, SLOT(onShowUAVAct_toggled(bool))); + + zoomInAct = new QAction(tr("Zoom &In"), this); + zoomInAct->setShortcut(Qt::Key_PageUp); + zoomInAct->setStatusTip(tr("Zoom the map in")); + connect(zoomInAct, SIGNAL(triggered()), this, SLOT(onGoZoomInAct_triggered())); + + zoomOutAct = new QAction(tr("Zoom &Out"), this); + zoomOutAct->setShortcut(Qt::Key_PageDown); + zoomOutAct->setStatusTip(tr("Zoom the map out")); + connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(onGoZoomOutAct_triggered())); + + goMouseClickAct = new QAction(tr("Go to where you right clicked the mouse"), this); + goMouseClickAct->setStatusTip(tr("Center the map onto where you right clicked the mouse")); + connect(goMouseClickAct, SIGNAL(triggered()), this, SLOT(onGoMouseClickAct_triggered())); + + setHomeAct = new QAction(tr("Set the home location"), this); + setHomeAct->setStatusTip(tr("Set the home location to where you clicked")); + #if !defined(allow_manual_home_location_move) + setHomeAct->setEnabled(false); + #endif + connect(setHomeAct, SIGNAL(triggered()), this, SLOT(onSetHomeAct_triggered())); + + goHomeAct = new QAction(tr("Go to &Home location"), this); + goHomeAct->setShortcut(tr("Ctrl+H")); + goHomeAct->setStatusTip(tr("Center the map onto the home location")); + connect(goHomeAct, SIGNAL(triggered()), this, SLOT(onGoHomeAct_triggered())); + + goUAVAct = new QAction(tr("Go to &UAV location"), this); + goUAVAct->setShortcut(tr("Ctrl+U")); + goUAVAct->setStatusTip(tr("Center the map onto the UAV location")); + connect(goUAVAct, SIGNAL(triggered()), this, SLOT(onGoUAVAct_triggered())); + + followUAVpositionAct = new QAction(tr("Follow UAV position"), this); + followUAVpositionAct->setShortcut(tr("Ctrl+F")); + followUAVpositionAct->setStatusTip(tr("Keep the map centered onto the UAV")); + followUAVpositionAct->setCheckable(true); + followUAVpositionAct->setChecked(false); + connect(followUAVpositionAct, SIGNAL(toggled(bool)), this, SLOT(onFollowUAVpositionAct_toggled(bool))); + + followUAVheadingAct = new QAction(tr("Follow UAV heading"), this); + followUAVheadingAct->setShortcut(tr("Ctrl+F")); + followUAVheadingAct->setStatusTip(tr("Keep the map rotation to the UAV heading")); + followUAVheadingAct->setCheckable(true); + followUAVheadingAct->setChecked(false); + connect(followUAVheadingAct, SIGNAL(toggled(bool)), this, SLOT(onFollowUAVheadingAct_toggled(bool))); + + /* + TODO: Waypoint support is disabled for v1.0 + */ + + /* + wayPointEditorAct = new QAction(tr("&Waypoint editor"), this); + wayPointEditorAct->setShortcut(tr("Ctrl+W")); + wayPointEditorAct->setStatusTip(tr("Open the waypoint editor")); + wayPointEditorAct->setEnabled(false); // temporary + connect(wayPointEditorAct, SIGNAL(triggered()), this, SLOT(onOpenWayPointEditorAct_triggered())); + + addWayPointAct = new QAction(tr("&Add waypoint"), this); + addWayPointAct->setShortcut(tr("Ctrl+A")); + addWayPointAct->setStatusTip(tr("Add waypoint")); + connect(addWayPointAct, SIGNAL(triggered()), this, SLOT(onAddWayPointAct_triggered())); + + editWayPointAct = new QAction(tr("&Edit waypoint"), this); + editWayPointAct->setShortcut(tr("Ctrl+E")); + editWayPointAct->setStatusTip(tr("Edit waypoint")); + connect(editWayPointAct, SIGNAL(triggered()), this, SLOT(onEditWayPointAct_triggered())); + + lockWayPointAct = new QAction(tr("&Lock waypoint"), this); + lockWayPointAct->setStatusTip(tr("Lock/Unlock a waypoint")); + lockWayPointAct->setCheckable(true); + lockWayPointAct->setChecked(false); + connect(lockWayPointAct, SIGNAL(triggered()), this, SLOT(onLockWayPointAct_triggered())); + + deleteWayPointAct = new QAction(tr("&Delete waypoint"), this); + deleteWayPointAct->setShortcut(tr("Ctrl+D")); + deleteWayPointAct->setStatusTip(tr("Delete waypoint")); + connect(deleteWayPointAct, SIGNAL(triggered()), this, SLOT(onDeleteWayPointAct_triggered())); + + clearWayPointsAct = new QAction(tr("&Clear waypoints"), this); + clearWayPointsAct->setShortcut(tr("Ctrl+C")); + clearWayPointsAct->setStatusTip(tr("Clear waypoints")); + connect(clearWayPointsAct, SIGNAL(triggered()), this, SLOT(onClearWayPointsAct_triggered())); + */ + + homeMagicWaypointAct = new QAction(tr("Home magic waypoint"), this); + homeMagicWaypointAct->setStatusTip(tr("Move the magic waypoint to the home position")); + connect(homeMagicWaypointAct, SIGNAL(triggered()), this, SLOT(onHomeMagicWaypointAct_triggered())); + + mapModeActGroup = new QActionGroup(this); + connect(mapModeActGroup, SIGNAL(triggered(QAction *)), this, SLOT(onMapModeActGroup_triggered(QAction *))); + mapModeAct.clear(); + { + QAction *map_mode_act; + + map_mode_act = new QAction(tr("Normal"), mapModeActGroup); + map_mode_act->setCheckable(true); + map_mode_act->setChecked(m_map_mode == Normal_MapMode); + map_mode_act->setData((int)Normal_MapMode); + mapModeAct.append(map_mode_act); + + map_mode_act = new QAction(tr("Magic Waypoint"), mapModeActGroup); + map_mode_act->setCheckable(true); + map_mode_act->setChecked(m_map_mode == MagicWaypoint_MapMode); + map_mode_act->setData((int)MagicWaypoint_MapMode); + mapModeAct.append(map_mode_act); + } + + zoomActGroup = new QActionGroup(this); + connect(zoomActGroup, SIGNAL(triggered(QAction *)), this, SLOT(onZoomActGroup_triggered(QAction *))); + zoomAct.clear(); + for (int i = m_min_zoom; i <= m_max_zoom; i++) + { + QAction *zoom_act = new QAction(QString::number(i), zoomActGroup); + zoom_act->setCheckable(true); + zoom_act->setData(i); + zoomAct.append(zoom_act); + } + + maxUpdateRateActGroup = new QActionGroup(this); + connect(maxUpdateRateActGroup, SIGNAL(triggered(QAction *)), this, SLOT(onMaxUpdateRateActGroup_triggered(QAction *))); + maxUpdateRateAct.clear(); + list_size = sizeof(max_update_rate_list) / sizeof(max_update_rate_list[0]); + for (int i = 0; i < list_size; i++) + { + QAction *maxUpdateRate_act; + int j = max_update_rate_list[i]; + maxUpdateRate_act = new QAction(QString::number(j), maxUpdateRateActGroup); + maxUpdateRate_act->setCheckable(true); + maxUpdateRate_act->setData(j); + maxUpdateRate_act->setChecked(j == m_maxUpdateRate); + maxUpdateRateAct.append(maxUpdateRate_act); + } + + // ***** + // safe area + + showSafeAreaAct = new QAction(tr("Show Safe Area"), this); + showSafeAreaAct->setStatusTip(tr("Show/Hide the Safe Area around the home location")); + showSafeAreaAct->setCheckable(true); + showSafeAreaAct->setChecked(m_map->Home->ShowSafeArea()); + connect(showSafeAreaAct, SIGNAL(toggled(bool)), this, SLOT(onShowSafeAreaAct_toggled(bool))); + + safeAreaActGroup = new QActionGroup(this); + connect(safeAreaActGroup, SIGNAL(triggered(QAction *)), this, SLOT(onSafeAreaActGroup_triggered(QAction *))); + safeAreaAct.clear(); + list_size = sizeof(safe_area_radius_list) / sizeof(safe_area_radius_list[0]); + for (int i = 0; i < list_size; i++) + { + int safeArea = safe_area_radius_list[i]; + QAction *safeArea_act = new QAction(QString::number(safeArea) + "m", safeAreaActGroup); + safeArea_act->setCheckable(true); + safeArea_act->setChecked(safeArea == m_map->Home->SafeArea()); + safeArea_act->setData(safeArea); + safeAreaAct.append(safeArea_act); + } + + // ***** + // UAV trail + + uavTrailTypeActGroup = new QActionGroup(this); + connect(uavTrailTypeActGroup, SIGNAL(triggered(QAction *)), this, SLOT(onUAVTrailTypeActGroup_triggered(QAction *))); + uavTrailTypeAct.clear(); + QStringList uav_trail_type_list = mapcontrol::Helper::UAVTrailTypes(); + for (int i = 0; i < uav_trail_type_list.count(); i++) + { + mapcontrol::UAVTrailType::Types uav_trail_type = mapcontrol::Helper::UAVTrailTypeFromString(uav_trail_type_list[i]); + QAction *uavTrailType_act = new QAction(mapcontrol::Helper::StrFromUAVTrailType(uav_trail_type), uavTrailTypeActGroup); + uavTrailType_act->setCheckable(true); + uavTrailType_act->setChecked(uav_trail_type == m_map->UAV->GetTrailType()); + uavTrailType_act->setData(i); + uavTrailTypeAct.append(uavTrailType_act); + } + + showTrailAct = new QAction(tr("Show Trail dots"), this); + showTrailAct->setStatusTip(tr("Show/Hide the Trail dots")); + showTrailAct->setCheckable(true); + showTrailAct->setChecked(true); + connect(showTrailAct, SIGNAL(toggled(bool)), this, SLOT(onShowTrailAct_toggled(bool))); + + showTrailLineAct = new QAction(tr("Show Trail lines"), this); + showTrailLineAct->setStatusTip(tr("Show/Hide the Trail lines")); + showTrailLineAct->setCheckable(true); + showTrailLineAct->setChecked(true); + connect(showTrailLineAct, SIGNAL(toggled(bool)), this, SLOT(onShowTrailLineAct_toggled(bool))); + + clearUAVtrailAct = new QAction(tr("Clear UAV trail"), this); + clearUAVtrailAct->setStatusTip(tr("Clear the UAV trail")); + connect(clearUAVtrailAct, SIGNAL(triggered()), this, SLOT(onClearUAVtrailAct_triggered())); + + uavTrailTimeActGroup = new QActionGroup(this); + connect(uavTrailTimeActGroup, SIGNAL(triggered(QAction *)), this, SLOT(onUAVTrailTimeActGroup_triggered(QAction *))); + uavTrailTimeAct.clear(); + list_size = sizeof(uav_trail_time_list) / sizeof(uav_trail_time_list[0]); + for (int i = 0; i < list_size; i++) + { + int uav_trail_time = uav_trail_time_list[i]; + QAction *uavTrailTime_act = new QAction(QString::number(uav_trail_time) + " sec", uavTrailTimeActGroup); + uavTrailTime_act->setCheckable(true); + uavTrailTime_act->setChecked(uav_trail_time == m_map->UAV->TrailTime()); + uavTrailTime_act->setData(uav_trail_time); + uavTrailTimeAct.append(uavTrailTime_act); + } + + uavTrailDistanceActGroup = new QActionGroup(this); + connect(uavTrailDistanceActGroup, SIGNAL(triggered(QAction *)), this, SLOT(onUAVTrailDistanceActGroup_triggered(QAction *))); + uavTrailDistanceAct.clear(); + list_size = sizeof(uav_trail_distance_list) / sizeof(uav_trail_distance_list[0]); + for (int i = 0; i < list_size; i++) + { + int uav_trail_distance = uav_trail_distance_list[i]; + QAction *uavTrailDistance_act = new QAction(QString::number(uav_trail_distance) + " meters", uavTrailDistanceActGroup); + uavTrailDistance_act->setCheckable(true); + uavTrailDistance_act->setChecked(uav_trail_distance == m_map->UAV->TrailDistance()); + uavTrailDistance_act->setData(uav_trail_distance); + uavTrailDistanceAct.append(uavTrailDistance_act); + } + + // ***** + + // *********************** +} + +void OPMapGadgetWidget::onReloadAct_triggered() +{ + if (!m_widget || !m_map) + return; + + m_map->ReloadMap(); +} + +void OPMapGadgetWidget::onCopyMouseLatLonToClipAct_triggered() +{ + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(QString::number(m_context_menu_lat_lon.Lat(), 'f', 7) + ", " + QString::number(m_context_menu_lat_lon.Lng(), 'f', 7), QClipboard::Clipboard); +} + +void OPMapGadgetWidget::onCopyMouseLatToClipAct_triggered() +{ + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(QString::number(m_context_menu_lat_lon.Lat(), 'f', 7), QClipboard::Clipboard); +} + +void OPMapGadgetWidget::onCopyMouseLonToClipAct_triggered() +{ + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(QString::number(m_context_menu_lat_lon.Lng(), 'f', 7), QClipboard::Clipboard); +} + + +void OPMapGadgetWidget::onShowCompassAct_toggled(bool show) +{ + if (!m_widget || !m_map) + return; + + m_map->SetShowCompass(show); +} + +void OPMapGadgetWidget::onShowDiagnostics_toggled(bool show) +{ + if (!m_widget || !m_map) + return; + + m_map->SetShowDiagnostics(show); +} + +void OPMapGadgetWidget::onShowHomeAct_toggled(bool show) +{ + if (!m_widget || !m_map) + return; + + m_map->Home->setVisible(show); +} + +void OPMapGadgetWidget::onShowUAVAct_toggled(bool show) +{ + if (!m_widget || !m_map) + return; + + m_map->UAV->setVisible(show); + m_map->GPS->setVisible(show); +} + +void OPMapGadgetWidget::onShowTrailAct_toggled(bool show) +{ + if (!m_widget || !m_map) + return; + + m_map->UAV->SetShowTrail(show); + m_map->GPS->SetShowTrail(show); +} + +void OPMapGadgetWidget::onShowTrailLineAct_toggled(bool show) +{ + if (!m_widget || !m_map) + return; + + m_map->UAV->SetShowTrailLine(show); + m_map->GPS->SetShowTrailLine(show); +} + +void OPMapGadgetWidget::onMapModeActGroup_triggered(QAction *action) +{ + if (!m_widget || !m_map || !action) + return; + + opMapModeType mode = (opMapModeType)action->data().toInt(); + + setMapMode(mode); +} + +void OPMapGadgetWidget::onGoZoomInAct_triggered() +{ + zoomIn(); +} + +void OPMapGadgetWidget::onGoZoomOutAct_triggered() +{ + zoomOut(); +} + +void OPMapGadgetWidget::onZoomActGroup_triggered(QAction *action) +{ + if (!m_widget || !m_map || !action) + return; + + setZoom(action->data().toInt()); +} + +void OPMapGadgetWidget::onMaxUpdateRateActGroup_triggered(QAction *action) +{ + if (!m_widget || !m_map || !action) + return; + + setMaxUpdateRate(action->data().toInt()); +} + +void OPMapGadgetWidget::onGoMouseClickAct_triggered() +{ + if (!m_widget || !m_map) + return; + + m_map->SetCurrentPosition(m_map->currentMousePosition()); // center the map onto the mouse position +} + +void OPMapGadgetWidget::onSetHomeAct_triggered() +{ + if (!m_widget || !m_map) + return; + + setHome(m_context_menu_lat_lon); + + setHomeLocationObject(); // update the HomeLocation UAVObject +} + +void OPMapGadgetWidget::onGoHomeAct_triggered() +{ + if (!m_widget || !m_map) + return; + + goHome(); +} + +void OPMapGadgetWidget::onGoUAVAct_triggered() +{ + if (!m_widget || !m_map) + return; + + double latitude; + double longitude; + double altitude; + if (getUAVPosition(latitude, longitude, altitude)) // get current UAV position + { + internals::PointLatLng uav_pos = internals::PointLatLng(latitude, longitude); // current UAV position + internals::PointLatLng map_pos = m_map->CurrentPosition(); // current MAP position + if (map_pos != uav_pos) m_map->SetCurrentPosition(uav_pos); // center the map onto the UAV + } +} + +void OPMapGadgetWidget::onFollowUAVpositionAct_toggled(bool checked) +{ + if (!m_widget || !m_map) + return; + + if (m_widget->toolButtonMapUAV->isChecked() != checked) + m_widget->toolButtonMapUAV->setChecked(checked); + + setMapFollowingMode(); +} + +void OPMapGadgetWidget::onFollowUAVheadingAct_toggled(bool checked) +{ + if (!m_widget || !m_map) + return; + + if (m_widget->toolButtonMapUAVheading->isChecked() != checked) + m_widget->toolButtonMapUAVheading->setChecked(checked); + + setMapFollowingMode(); +} + +void OPMapGadgetWidget::onUAVTrailTypeActGroup_triggered(QAction *action) +{ + if (!m_widget || !m_map || !action) + return; + + int trail_type_idx = action->data().toInt(); + + QStringList uav_trail_type_list = mapcontrol::Helper::UAVTrailTypes(); + mapcontrol::UAVTrailType::Types uav_trail_type = mapcontrol::Helper::UAVTrailTypeFromString(uav_trail_type_list[trail_type_idx]); + + m_map->UAV->SetTrailType(uav_trail_type); +} + +void OPMapGadgetWidget::onClearUAVtrailAct_triggered() +{ + if (!m_widget || !m_map) + return; + + m_map->UAV->DeleteTrail(); + m_map->GPS->DeleteTrail(); +} + +void OPMapGadgetWidget::onUAVTrailTimeActGroup_triggered(QAction *action) +{ + if (!m_widget || !m_map || !action) + return; + + int trail_time = (double)action->data().toInt(); + + m_map->UAV->SetTrailTime(trail_time); +} + +void OPMapGadgetWidget::onUAVTrailDistanceActGroup_triggered(QAction *action) +{ + if (!m_widget || !m_map || !action) + return; + + int trail_distance = action->data().toInt(); + + m_map->UAV->SetTrailDistance(trail_distance); +} + +/** + * TODO: unused for v1.0 + **/ +/* +void OPMapGadgetWidget::onAddWayPointAct_triggered() +{ + if (!m_widget || !m_map) + return; + + if (m_map_mode != Normal_MapMode) + return; + + m_waypoint_list_mutex.lock(); + + // create a waypoint on the map at the last known mouse position + t_waypoint *wp = new t_waypoint; + wp->map_wp_item = NULL; + wp->coord = context_menu_lat_lon; + wp->altitude = 0; + wp->description = ""; + wp->locked = false; + wp->time_seconds = 0; + wp->hold_time_seconds = 0; + wp->map_wp_item = m_map->WPCreate(wp->coord, wp->altitude, wp->description); + + wp->map_wp_item->setZValue(10 + wp->map_wp_item->Number()); + + wp->map_wp_item->setFlag(QGraphicsItem::ItemIsMovable, !wp->locked); + + if (wp->map_wp_item) + { + if (!wp->locked) + wp->map_wp_item->picture.load(QString::fromUtf8(":/opmap/images/waypoint_marker1.png")); + else + wp->map_wp_item->picture.load(QString::fromUtf8(":/opmap/images/waypoint_marker2.png")); + wp->map_wp_item->update(); + } + + // and remember it in our own local waypoint list + m_waypoint_list.append(wp); + + m_waypoint_list_mutex.unlock(); +} +*/ + +/** + * Called when the user asks to edit a waypoint from the map + * + * TODO: should open an interface to edit waypoint properties, or + * propagate the signal to a specific WP plugin (tbd). + **/ +/* +void OPMapGadgetWidget::onEditWayPointAct_triggered() +{ + if (!m_widget || !m_map) + return; + + if (m_map_mode != Normal_MapMode) + return; + + if (!m_mouse_waypoint) + return; + + //waypoint_edit_dialog.editWaypoint(m_mouse_waypoint); + + m_mouse_waypoint = NULL; +} +*/ + +/** + * TODO: unused for v1.0 + */ +/* +void OPMapGadgetWidget::onLockWayPointAct_triggered() +{ + if (!m_widget || !m_map || !m_mouse_waypoint) + return; + + if (m_map_mode != Normal_MapMode) + return; + + bool locked = (m_mouse_waypoint->flags() & QGraphicsItem::ItemIsMovable) == 0; + m_mouse_waypoint->setFlag(QGraphicsItem::ItemIsMovable, locked); + + if (!locked) + m_mouse_waypoint->picture.load(QString::fromUtf8(":/opmap/images/waypoint_marker2.png")); + else + m_mouse_waypoint->picture.load(QString::fromUtf8(":/opmap/images/waypoint_marker1.png")); + m_mouse_waypoint->update(); + + m_mouse_waypoint = NULL; +} +*/ + +/** + * TODO: unused for v1.0 + */ +/* +void OPMapGadgetWidget::onDeleteWayPointAct_triggered() +{ + if (!m_widget || !m_map) + return; + + if (m_map_mode != Normal_MapMode) + return; + + if (!m_mouse_waypoint) + return; + + bool locked = (m_mouse_waypoint->flags() & QGraphicsItem::ItemIsMovable) == 0; + + if (locked) return; // waypoint is locked + + QMutexLocker locker(&m_waypoint_list_mutex); + + for (int i = 0; i < m_waypoint_list.count(); i++) + { + t_waypoint *wp = m_waypoint_list.at(i); + if (!wp) continue; + if (!wp->map_wp_item || wp->map_wp_item != m_mouse_waypoint) continue; + + // delete the waypoint from the map + m_map->WPDelete(wp->map_wp_item); + + // delete the waypoint from our local waypoint list + m_waypoint_list.removeAt(i); + + delete wp; + + break; + } +// +// foreach (t_waypoint *wp, m_waypoint_list) +// { +// if (!wp) continue; +// if (!wp->map_wp_item || wp->map_wp_item != m_mouse_waypoint) continue; +// +// // delete the waypoint from the map +// m_map->WPDelete(wp->map_wp_item); +// +// // delete the waypoint from our local waypoint list +// m_waypoint_list.removeOne(wp); +// +// delete wp; +// +// break; +// } + + m_mouse_waypoint = NULL; +} +*/ + +/** + * TODO: No Waypoint support in v1.0 + */ +/* +void OPMapGadgetWidget::onClearWayPointsAct_triggered() +{ + if (!m_widget || !m_map) + return; + + if (m_map_mode != Normal_MapMode) + return; + + QMutexLocker locker(&m_waypoint_list_mutex); + + m_map->WPDeleteAll(); + + foreach (t_waypoint *wp, m_waypoint_list) + { + if (wp) + { + delete wp; + wp = NULL; + } + } + + m_waypoint_list.clear(); +} +*/ + +void OPMapGadgetWidget::onHomeMagicWaypointAct_triggered() +{ + // center the magic waypoint on the home position + homeMagicWaypoint(); +} + +void OPMapGadgetWidget::onShowSafeAreaAct_toggled(bool show) +{ + if (!m_widget || !m_map) + return; + + m_map->Home->SetShowSafeArea(show); // show the safe area + m_map->Home->RefreshPos(); +} + +void OPMapGadgetWidget::onSafeAreaActGroup_triggered(QAction *action) +{ + if (!m_widget || !m_map || !action) + return; + + int radius = action->data().toInt(); + + m_map->Home->SetSafeArea(radius); // set the radius (meters) + m_map->Home->RefreshPos(); + + // move the magic waypoint if need be to keep it within the safe area around the home position + keepMagicWaypointWithInSafeArea(); +} + +/** +* move the magic waypoint to the home position +**/ +void OPMapGadgetWidget::homeMagicWaypoint() +{ + if (!m_widget || !m_map) + return; + + if (m_map_mode != MagicWaypoint_MapMode) + return; + + m_magic_waypoint.coord = m_home_position.coord; + + if (m_magic_waypoint.map_wp_item) + m_magic_waypoint.map_wp_item->SetCoord(m_magic_waypoint.coord); +} + +// ************************************************************************************* +// move the UAV to the magic waypoint position + +void OPMapGadgetWidget::moveToMagicWaypointPosition() +{ + if (!m_widget || !m_map) + return; + + if (m_map_mode != MagicWaypoint_MapMode) + return; + +// internals::PointLatLng coord = magic_waypoint.coord; +// double altitude = magic_waypoint.altitude; + + + // ToDo: + +} + +// ************************************************************************************* +// temporary until an object is created for managing the save/restore + +// load the contents of a simple text file into a combobox +void OPMapGadgetWidget::loadComboBoxLines(QComboBox *comboBox, QString filename) +{ + if (!comboBox) return; + if (filename.isNull() || filename.isEmpty()) return; + + QFile file(filename); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + + QTextStream in(&file); + + while (!in.atEnd()) + { + QString line = in.readLine().simplified(); + if (line.isNull() || line.isEmpty()) continue; + comboBox->addItem(line); + } + + file.close(); +} + +// save a combobox text contents to a simple text file +void OPMapGadgetWidget::saveComboBoxLines(QComboBox *comboBox, QString filename) +{ + if (!comboBox) return; + if (filename.isNull() || filename.isEmpty()) return; + + QFile file(filename); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) + return; + + QTextStream out(&file); + + for (int i = 0; i < comboBox->count(); i++) + { + QString line = comboBox->itemText(i).simplified(); + if (line.isNull() || line.isEmpty()) continue; + out << line << "\n"; + } + + file.close(); +} + +// ************************************************************************************* +// show/hide the magic waypoint controls + +void OPMapGadgetWidget::hideMagicWaypointControls() +{ + m_widget->lineWaypoint->setVisible(false); + m_widget->toolButtonHomeWaypoint->setVisible(false); + m_widget->toolButtonMoveToWP->setVisible(false); +} + +void OPMapGadgetWidget::showMagicWaypointControls() +{ + m_widget->lineWaypoint->setVisible(true); + m_widget->toolButtonHomeWaypoint->setVisible(true); + + #if defined(allow_manual_home_location_move) + m_widget->toolButtonMoveToWP->setVisible(true); + #else + m_widget->toolButtonMoveToWP->setVisible(false); + #endif +} + +// ************************************************************************************* +// move the magic waypoint to keep it within the safe area boundry + +void OPMapGadgetWidget::keepMagicWaypointWithInSafeArea() +{ + + // calcute the bearing and distance from the home position to the magic waypoint + double dist = distance(m_home_position.coord, m_magic_waypoint.coord); + double bear = bearing(m_home_position.coord, m_magic_waypoint.coord); + + // get the maximum safe distance - in kilometers + double boundry_dist = (double)m_map->Home->SafeArea() / 1000; + +// if (dist <= boundry_dist) +// return; // the magic waypoint is still within the safe area, don't move it + + if (dist > boundry_dist) dist = boundry_dist; + + // move the magic waypoint + + m_magic_waypoint.coord = destPoint(m_home_position.coord, bear, dist); + + if (m_map_mode == MagicWaypoint_MapMode) + { // move the on-screen waypoint + if (m_magic_waypoint.map_wp_item) + m_magic_waypoint.map_wp_item->SetCoord(m_magic_waypoint.coord); + } +} + +// ************************************************************************************* +// return the distance between two points .. in kilometers + +double OPMapGadgetWidget::distance(internals::PointLatLng from, internals::PointLatLng to) +{ + double lat1 = from.Lat() * deg_to_rad; + double lon1 = from.Lng() * deg_to_rad; + + double lat2 = to.Lat() * deg_to_rad; + double lon2 = to.Lng() * deg_to_rad; + + // *********************** + // Haversine formula +/* + double delta_lat = lat2 - lat1; + double delta_lon = lon2 - lon1; + + double t1 = sin(delta_lat / 2); + double t2 = sin(delta_lon / 2); + double a = (t1 * t1) + cos(lat1) * cos(lat2) * (t2 * t2); + double c = 2 * atan2(sqrt(a), sqrt(1 - a)); + + return (earth_mean_radius * c); +*/ + // *********************** + // Spherical Law of Cosines + + return (acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon2 - lon1)) * earth_mean_radius); + + // *********************** +} + +// ************************************************************************************* +// return the bearing from one point to another .. in degrees + +double OPMapGadgetWidget::bearing(internals::PointLatLng from, internals::PointLatLng to) +{ + double lat1 = from.Lat() * deg_to_rad; + double lon1 = from.Lng() * deg_to_rad; + + double lat2 = to.Lat() * deg_to_rad; + double lon2 = to.Lng() * deg_to_rad; + +// double delta_lat = lat2 - lat1; + double delta_lon = lon2 - lon1; + + double y = sin(delta_lon) * cos(lat2); + double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(delta_lon); + double bear = atan2(y, x) * rad_to_deg; + + bear += 360; + while (bear < 0) bear += 360; + while (bear >= 360) bear -= 360; + + return bear; +} + +// ************************************************************************************* +// return a destination lat/lon point given a source lat/lon point and the bearing and distance from the source point + +internals::PointLatLng OPMapGadgetWidget::destPoint(internals::PointLatLng source, double bear, double dist) +{ + double lat1 = source.Lat() * deg_to_rad; + double lon1 = source.Lng() * deg_to_rad; + + bear *= deg_to_rad; + + double ad = dist / earth_mean_radius; + + double lat2 = asin(sin(lat1) * cos(ad) + cos(lat1) * sin(ad) * cos(bear)); + double lon2 = lon1 + atan2(sin(bear) * sin(ad) * cos(lat1), cos(ad) - sin(lat1) * sin(lat2)); + + return internals::PointLatLng(lat2 * rad_to_deg, lon2 * rad_to_deg); +} + +// ************************************************************************************* + +bool OPMapGadgetWidget::getUAVPosition(double &latitude, double &longitude, double &altitude) +{ + double BaseECEF[3]; + double NED[3]; + double LLA[3]; + UAVObject *obj; + + if (!obm) + return false; + + obj = dynamic_cast(obm->getObject(QString("HomeLocation"))); + if (!obj) return false; + BaseECEF[0] = obj->getField(QString("ECEF"))->getDouble(0) / 100; + BaseECEF[1] = obj->getField(QString("ECEF"))->getDouble(1) / 100; + BaseECEF[2] = obj->getField(QString("ECEF"))->getDouble(2) / 100; + + obj = dynamic_cast(obm->getObject(QString("PositionActual"))); + if (!obj) return false; + NED[0] = obj->getField(QString("North"))->getDouble() / 100; + NED[1] = obj->getField(QString("East"))->getDouble() / 100; + NED[2] = obj->getField(QString("Down"))->getDouble() / 100; + +// obj = dynamic_cast(om->getObject(QString("PositionDesired"))); + +// obj = dynamic_cast(objManager->getObject("VelocityActual")); // air speed + + Utils::CoordinateConversions().GetLLA(BaseECEF, NED, LLA); + + latitude = LLA[0]; + longitude = LLA[1]; + altitude = LLA[2]; + + if (latitude != latitude) latitude = 0; // nan detection +// if (isNan(latitude)) latitude = 0; // nan detection + else +// if (!isFinite(latitude)) latitude = 0; +// else + if (latitude > 90) latitude = 90; + else + if (latitude < -90) latitude = -90; + + if (longitude != longitude) longitude = 0; // nan detection + else +// if (longitude > std::numeric_limits::max()) longitude = 0; // +infinite +// else +// if (longitude < -std::numeric_limits::max()) longitude = 0; // -infinite +// else + if (longitude > 180) longitude = 180; + else + if (longitude < -180) longitude = -180; + + if (altitude != altitude) altitude = 0; // nan detection + + return true; +} + +double OPMapGadgetWidget::getUAV_Yaw() +{ + if (!obm) + return 0; + + UAVObject *obj = dynamic_cast(obm->getObject(QString("AttitudeActual"))); + double yaw = obj->getField(QString("Yaw"))->getDouble(); + + if (yaw != yaw) yaw = 0; // nan detection + + while (yaw < 0) yaw += 360; + while (yaw >= 360) yaw -= 360; + + return yaw; +} + +bool OPMapGadgetWidget::getGPSPosition(double &latitude, double &longitude, double &altitude) +{ + double LLA[3]; + + if (!obum) + return false; + + if (obum->getGPSPosition(LLA) < 0) + return false; // error + + latitude = LLA[0]; + longitude = LLA[1]; + altitude = LLA[2]; + + return true; +} + +// ************************************************************************************* + +void OPMapGadgetWidget::setMapFollowingMode() +{ + if (!m_widget || !m_map) + return; + + if (!followUAVpositionAct->isChecked()) + { + m_map->UAV->SetMapFollowType(UAVMapFollowType::None); + m_map->SetRotate(0); // reset map rotation to 0deg + } + else + if (!followUAVheadingAct->isChecked()) + { + m_map->UAV->SetMapFollowType(UAVMapFollowType::CenterMap); + m_map->SetRotate(0); // reset map rotation to 0deg + } + else + { + m_map->UAV->SetMapFollowType(UAVMapFollowType::CenterMap); // the map library won't let you reset the uav rotation if it's already in rotate mode + + m_map->UAV->SetUAVHeading(0); // reset the UAV heading to 0deg + m_map->UAV->SetMapFollowType(UAVMapFollowType::CenterAndRotateMap); + } +} + +// ************************************************************************************* +// update the HomeLocation UAV Object + +bool OPMapGadgetWidget::setHomeLocationObject() +{ + if (!obum) + return false; + + double LLA[3] = {m_home_position.coord.Lat(), m_home_position.coord.Lng(), m_home_position.altitude}; + return (obum->setHomeLocation(LLA, true) >= 0); +} + +// ************************************************************************************* + +void OPMapGadgetWidget::SetUavPic(QString UAVPic) +{ + m_map->SetUavPic(UAVPic); +} diff --git a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetwidget.h b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetwidget.h index 15eddf93d..24f638a80 100644 --- a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetwidget.h +++ b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetwidget.h @@ -1,347 +1,361 @@ -/** - ****************************************************************************** - * - * @file opmapgadgetwidget.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup OPMapPlugin OpenPilot Map Plugin - * @{ - * @brief The OpenPilot Map plugin - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OPMAP_GADGETWIDGET_H_ -#define OPMAP_GADGETWIDGET_H_ - -// ****************************************************** - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "opmapcontrol/opmapcontrol.h" - -#include "opmap_overlay_widget.h" -#include "opmap_zoom_slider_widget.h" -#include "opmap_statusbar_widget.h" - -#include "utils/coordinateconversions.h" - -#include "extensionsystem/pluginmanager.h" -#include "uavobjectutilmanager.h" -#include "uavobjectmanager.h" -#include "uavobject.h" -#include "objectpersistence.h" - -// ****************************************************** - -namespace Ui -{ - class OPMap_Widget; -} - -using namespace mapcontrol; - -// ****************************************************** - -typedef struct t_home -{ - internals::PointLatLng coord; - double altitude; - bool locked; -} t_home; - -// local waypoint list item structure -typedef struct t_waypoint -{ - mapcontrol::WayPointItem *map_wp_item; - internals::PointLatLng coord; - double altitude; - QString description; - bool locked; - int time_seconds; - int hold_time_seconds; -} t_waypoint; - -// ****************************************************** - -enum opMapModeType { Normal_MapMode = 0, - MagicWaypoint_MapMode = 1}; - -// ****************************************************** - -class OPMapGadgetWidget : public QWidget -{ - Q_OBJECT - -public: - OPMapGadgetWidget(QWidget *parent = 0); - ~OPMapGadgetWidget(); - - /** - * @brief public functions - * - * @param - */ - void setHome(QPointF pos); - void setHome(internals::PointLatLng pos_lat_lon); - void goHome(); - void setZoom(int zoom); - void setPosition(QPointF pos); - void setMapProvider(QString provider); - void setUseOpenGL(bool useOpenGL); - void setShowTileGridLines(bool showTileGridLines); - void setAccessMode(QString accessMode); - void setUseMemoryCache(bool useMemoryCache); - void setCacheLocation(QString cacheLocation); - void setMapMode(opMapModeType mode); - void SetUavPic(QString UAVPic); - -public slots: - void homePositionUpdated(UAVObject *); - void onTelemetryConnect(); - void onTelemetryDisconnect(); - -protected: - void resizeEvent(QResizeEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void contextMenuEvent(QContextMenuEvent *event); - void keyPressEvent(QKeyEvent* event); - -private slots: - void updatePosition(); - - void updateMousePos(); - - void zoomIn(); - void zoomOut(); - - /** - * @brief signals received from the various map plug-in widget user controls - * - * Some are currently disabled for the v1.0 plugin version. - */ -// void comboBoxFindPlace_returnPressed(); -// void on_toolButtonFindPlace_clicked(); - void on_toolButtonZoomM_clicked(); - void on_toolButtonZoomP_clicked(); - void on_toolButtonMapHome_clicked(); - void on_toolButtonMapUAV_clicked(); - void on_toolButtonMapUAVheading_clicked(); - void on_horizontalSliderZoom_sliderMoved(int position); -// void on_toolButtonAddWaypoint_clicked(); -// void on_treeViewWaypoints_clicked(QModelIndex index); -// void on_toolButtonHome_clicked(); -// void on_toolButtonNextWaypoint_clicked(); -// void on_toolButtonPrevWaypoint_clicked(); -// void on_toolButtonHoldPosition_clicked(); -// void on_toolButtonGo_clicked(); - void on_toolButtonMagicWaypointMapMode_clicked(); - void on_toolButtonNormalMapMode_clicked(); - void on_toolButtonHomeWaypoint_clicked(); - void on_toolButtonMoveToWP_clicked(); - - /** - * @brief signals received from the map object - */ - void zoomChanged(double zoomt,double zoom, double zoomd); - void OnCurrentPositionChanged(internals::PointLatLng point); - void OnTileLoadComplete(); - void OnTileLoadStart(); - void OnMapDrag(); - void OnMapZoomChanged(); - void OnMapTypeChanged(MapType::Types type); - void OnEmptyTileError(int zoom, core::Point pos); - void OnTilesStillToLoad(int number); - - /** - * Unused for now, hooks for future waypoint support - */ - void WPNumberChanged(int const& oldnumber,int const& newnumber, WayPointItem* waypoint); - void WPValuesChanged(WayPointItem* waypoint); - void WPInserted(int const& number, WayPointItem* waypoint); - void WPDeleted(int const& number); - - /** - * @brief mouse right click context menu signals - */ - void onReloadAct_triggered(); - void onCopyMouseLatLonToClipAct_triggered(); - void onCopyMouseLatToClipAct_triggered(); - void onCopyMouseLonToClipAct_triggered(); -// void onFindPlaceAct_triggered(); - void onShowCompassAct_toggled(bool show); - void onShowDiagnostics_toggled(bool show); - void onShowUAVAct_toggled(bool show); - void onShowHomeAct_toggled(bool show); - void onShowTrailLineAct_toggled(bool show); - void onShowTrailAct_toggled(bool show); - void onGoZoomInAct_triggered(); - void onGoZoomOutAct_triggered(); - void onGoMouseClickAct_triggered(); - void onSetHomeAct_triggered(); - void onGoHomeAct_triggered(); - void onGoUAVAct_triggered(); - void onFollowUAVpositionAct_toggled(bool checked); - void onFollowUAVheadingAct_toggled(bool checked); -/* - void onOpenWayPointEditorAct_triggered(); - void onAddWayPointAct_triggered(); - void onEditWayPointAct_triggered(); - void onLockWayPointAct_triggered(); - void onDeleteWayPointAct_triggered(); - void onClearWayPointsAct_triggered(); -*/ - void onMapModeActGroup_triggered(QAction *action); - void onZoomActGroup_triggered(QAction *action); - void onHomeMagicWaypointAct_triggered(); - void onShowSafeAreaAct_toggled(bool show); - void onSafeAreaActGroup_triggered(QAction *action); - void onUAVTrailTypeActGroup_triggered(QAction *action); - void onClearUAVtrailAct_triggered(); - void onUAVTrailTimeActGroup_triggered(QAction *action); - void onUAVTrailDistanceActGroup_triggered(QAction *action); - -private: - int min_zoom; - int max_zoom; - - double m_heading; // uav heading - - internals::PointLatLng mouse_lat_lon; - internals::PointLatLng context_menu_lat_lon; - - int prev_tile_number; - - opMapModeType m_map_mode; - - t_home home_position; - - t_waypoint magic_waypoint; - - QStringList findPlaceWordList; - QCompleter *findPlaceCompleter; - - QTimer *m_updateTimer; - QTimer *m_statusUpdateTimer; - - Ui::OPMap_Widget *m_widget; - - mapcontrol::OPMapWidget *m_map; - - ExtensionSystem::PluginManager *pm; - UAVObjectManager *obm; - UAVObjectUtilManager *obum; - - //opmap_waypointeditor_dialog waypoint_editor_dialog; - - //opmap_edit_waypoint_dialog waypoint_edit_dialog; - - QStandardItemModel wayPoint_treeView_model; - - mapcontrol::WayPointItem *m_mouse_waypoint; - - QList m_waypoint_list; - QMutex m_waypoint_list_mutex; - - QMutex m_map_mutex; - - bool telemetry_connected; - - void createActions(); - - QAction *closeAct1; - QAction *closeAct2; - QAction *reloadAct; - QAction *copyMouseLatLonToClipAct; - QAction *copyMouseLatToClipAct; - QAction *copyMouseLonToClipAct; - QAction *findPlaceAct; - QAction *showCompassAct; - QAction *showDiagnostics; - QAction *showHomeAct; - QAction *showUAVAct; - QAction *zoomInAct; - QAction *zoomOutAct; - QAction *goMouseClickAct; - QAction *setHomeAct; - QAction *goHomeAct; - QAction *goUAVAct; - QAction *followUAVpositionAct; - QAction *followUAVheadingAct; - /* - QAction *wayPointEditorAct; - QAction *addWayPointAct; - QAction *editWayPointAct; - QAction *lockWayPointAct; - QAction *deleteWayPointAct; - QAction *clearWayPointsAct; - */ - QAction *homeMagicWaypointAct; - - QAction *showSafeAreaAct; - QActionGroup *safeAreaActGroup; - QList safeAreaAct; - - QActionGroup *uavTrailTypeActGroup; - QList uavTrailTypeAct; - QAction *clearUAVtrailAct; - QActionGroup *uavTrailTimeActGroup; - QAction *showTrailLineAct; - QAction *showTrailAct; - QList uavTrailTimeAct; - QActionGroup *uavTrailDistanceActGroup; - QList uavTrailDistanceAct; - - QActionGroup *mapModeActGroup; - QList mapModeAct; - - QActionGroup *zoomActGroup; - QList zoomAct; - - void homeMagicWaypoint(); - - void moveToMagicWaypointPosition(); - - void loadComboBoxLines(QComboBox *comboBox, QString filename); - void saveComboBoxLines(QComboBox *comboBox, QString filename); - - void hideMagicWaypointControls(); - void showMagicWaypointControls(); - - void keepMagicWaypointWithInSafeArea(); - - double distance(internals::PointLatLng from, internals::PointLatLng to); - double bearing(internals::PointLatLng from, internals::PointLatLng to); - internals::PointLatLng destPoint(internals::PointLatLng source, double bear, double dist); - - bool getUAVPosition(double &latitude, double &longitude, double &altitude); - bool getGPSPosition(double &latitude, double &longitude, double &altitude); - double getUAV_Yaw(); - - void setMapFollowingMode(); - - bool setHomeLocationObject(); -}; - -#endif /* OPMAP_GADGETWIDGET_H_ */ +/** + ****************************************************************************** + * + * @file opmapgadgetwidget.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup OPMapPlugin OpenPilot Map Plugin + * @{ + * @brief The OpenPilot Map plugin + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OPMAP_GADGETWIDGET_H_ +#define OPMAP_GADGETWIDGET_H_ + +// ****************************************************** + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "opmapcontrol/opmapcontrol.h" + +#include "opmap_overlay_widget.h" +#include "opmap_zoom_slider_widget.h" +#include "opmap_statusbar_widget.h" + +#include "utils/coordinateconversions.h" + +#include "extensionsystem/pluginmanager.h" +#include "uavobjectutilmanager.h" +#include "uavobjectmanager.h" +#include "uavobject.h" +#include "objectpersistence.h" + +// ****************************************************** + +namespace Ui +{ + class OPMap_Widget; +} + +using namespace mapcontrol; + +// ****************************************************** + +typedef struct t_home +{ + internals::PointLatLng coord; + double altitude; + bool locked; +} t_home; + +// local waypoint list item structure +typedef struct t_waypoint +{ + mapcontrol::WayPointItem *map_wp_item; + internals::PointLatLng coord; + double altitude; + QString description; + bool locked; + int time_seconds; + int hold_time_seconds; +} t_waypoint; + +// ****************************************************** + +enum opMapModeType { Normal_MapMode = 0, + MagicWaypoint_MapMode = 1}; + +// ****************************************************** + +class OPMapGadgetWidget : public QWidget +{ + Q_OBJECT + +public: + OPMapGadgetWidget(QWidget *parent = 0); + ~OPMapGadgetWidget(); + + /** + * @brief public functions + * + * @param + */ + void setHome(QPointF pos); + void setHome(internals::PointLatLng pos_lat_lon); + void goHome(); + void setZoom(int zoom); + void setPosition(QPointF pos); + void setMapProvider(QString provider); + void setUseOpenGL(bool useOpenGL); + void setShowTileGridLines(bool showTileGridLines); + void setAccessMode(QString accessMode); + void setUseMemoryCache(bool useMemoryCache); + void setCacheLocation(QString cacheLocation); + void setMapMode(opMapModeType mode); + void SetUavPic(QString UAVPic); + void setMaxUpdateRate(int update_rate); + +public slots: + void homePositionUpdated(UAVObject *); + void onTelemetryConnect(); + void onTelemetryDisconnect(); + +protected: + void resizeEvent(QResizeEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void contextMenuEvent(QContextMenuEvent *event); + void keyPressEvent(QKeyEvent* event); + +private slots: + void updatePosition(); + + void updateMousePos(); + + void zoomIn(); + void zoomOut(); + + /** + * @brief signals received from the various map plug-in widget user controls + * + * Some are currently disabled for the v1.0 plugin version. + */ +// void comboBoxFindPlace_returnPressed(); +// void on_toolButtonFindPlace_clicked(); + void on_toolButtonZoomM_clicked(); + void on_toolButtonZoomP_clicked(); + void on_toolButtonMapHome_clicked(); + void on_toolButtonMapUAV_clicked(); + void on_toolButtonMapUAVheading_clicked(); + void on_horizontalSliderZoom_sliderMoved(int position); +// void on_toolButtonAddWaypoint_clicked(); +// void on_treeViewWaypoints_clicked(QModelIndex index); +// void on_toolButtonHome_clicked(); +// void on_toolButtonNextWaypoint_clicked(); +// void on_toolButtonPrevWaypoint_clicked(); +// void on_toolButtonHoldPosition_clicked(); +// void on_toolButtonGo_clicked(); + void on_toolButtonMagicWaypointMapMode_clicked(); + void on_toolButtonNormalMapMode_clicked(); + void on_toolButtonHomeWaypoint_clicked(); + void on_toolButtonMoveToWP_clicked(); + + /** + * @brief signals received from the map object + */ + void zoomChanged(double zoomt,double zoom, double zoomd); + void OnCurrentPositionChanged(internals::PointLatLng point); + void OnTileLoadComplete(); + void OnTileLoadStart(); + void OnMapDrag(); + void OnMapZoomChanged(); + void OnMapTypeChanged(MapType::Types type); + void OnEmptyTileError(int zoom, core::Point pos); + void OnTilesStillToLoad(int number); + + /** + * Unused for now, hooks for future waypoint support + */ + void WPNumberChanged(int const& oldnumber,int const& newnumber, WayPointItem* waypoint); + void WPValuesChanged(WayPointItem* waypoint); + void WPInserted(int const& number, WayPointItem* waypoint); + void WPDeleted(int const& number); + + /** + * @brief mouse right click context menu signals + */ + void onReloadAct_triggered(); + void onCopyMouseLatLonToClipAct_triggered(); + void onCopyMouseLatToClipAct_triggered(); + void onCopyMouseLonToClipAct_triggered(); +// void onFindPlaceAct_triggered(); + void onShowCompassAct_toggled(bool show); + void onShowDiagnostics_toggled(bool show); + void onShowUAVAct_toggled(bool show); + void onShowHomeAct_toggled(bool show); + void onShowTrailLineAct_toggled(bool show); + void onShowTrailAct_toggled(bool show); + void onGoZoomInAct_triggered(); + void onGoZoomOutAct_triggered(); + void onGoMouseClickAct_triggered(); + void onSetHomeAct_triggered(); + void onGoHomeAct_triggered(); + void onGoUAVAct_triggered(); + void onFollowUAVpositionAct_toggled(bool checked); + void onFollowUAVheadingAct_toggled(bool checked); +/* + void onOpenWayPointEditorAct_triggered(); + void onAddWayPointAct_triggered(); + void onEditWayPointAct_triggered(); + void onLockWayPointAct_triggered(); + void onDeleteWayPointAct_triggered(); + void onClearWayPointsAct_triggered(); +*/ + void onMapModeActGroup_triggered(QAction *action); + void onZoomActGroup_triggered(QAction *action); + void onHomeMagicWaypointAct_triggered(); + void onShowSafeAreaAct_toggled(bool show); + void onSafeAreaActGroup_triggered(QAction *action); + void onUAVTrailTypeActGroup_triggered(QAction *action); + void onClearUAVtrailAct_triggered(); + void onUAVTrailTimeActGroup_triggered(QAction *action); + void onUAVTrailDistanceActGroup_triggered(QAction *action); + void onMaxUpdateRateActGroup_triggered(QAction *action); + +private: + + // ***** + + int m_min_zoom; + int m_max_zoom; + + double m_heading; // uav heading + + internals::PointLatLng m_mouse_lat_lon; + internals::PointLatLng m_context_menu_lat_lon; + + int m_prev_tile_number; + + opMapModeType m_map_mode; + + int m_maxUpdateRate; + + t_home m_home_position; + + t_waypoint m_magic_waypoint; + + QStringList findPlaceWordList; + QCompleter *findPlaceCompleter; + + QTimer *m_updateTimer; + QTimer *m_statusUpdateTimer; + + Ui::OPMap_Widget *m_widget; + + mapcontrol::OPMapWidget *m_map; + + ExtensionSystem::PluginManager *pm; + UAVObjectManager *obm; + UAVObjectUtilManager *obum; + + //opmap_waypointeditor_dialog waypoint_editor_dialog; + + //opmap_edit_waypoint_dialog waypoint_edit_dialog; + + QStandardItemModel wayPoint_treeView_model; + + mapcontrol::WayPointItem *m_mouse_waypoint; + + QList m_waypoint_list; + QMutex m_waypoint_list_mutex; + + QMutex m_map_mutex; + + bool m_telemetry_connected; + + // ***** + + void createActions(); + + QAction *closeAct1; + QAction *closeAct2; + QAction *reloadAct; + QAction *copyMouseLatLonToClipAct; + QAction *copyMouseLatToClipAct; + QAction *copyMouseLonToClipAct; + QAction *findPlaceAct; + QAction *showCompassAct; + QAction *showDiagnostics; + QAction *showHomeAct; + QAction *showUAVAct; + QAction *zoomInAct; + QAction *zoomOutAct; + QAction *goMouseClickAct; + QAction *setHomeAct; + QAction *goHomeAct; + QAction *goUAVAct; + QAction *followUAVpositionAct; + QAction *followUAVheadingAct; + /* + QAction *wayPointEditorAct; + QAction *addWayPointAct; + QAction *editWayPointAct; + QAction *lockWayPointAct; + QAction *deleteWayPointAct; + QAction *clearWayPointsAct; + */ + QAction *homeMagicWaypointAct; + + QAction *showSafeAreaAct; + QActionGroup *safeAreaActGroup; + QList safeAreaAct; + + QActionGroup *uavTrailTypeActGroup; + QList uavTrailTypeAct; + QAction *clearUAVtrailAct; + QActionGroup *uavTrailTimeActGroup; + QAction *showTrailLineAct; + QAction *showTrailAct; + QList uavTrailTimeAct; + QActionGroup *uavTrailDistanceActGroup; + QList uavTrailDistanceAct; + + QActionGroup *mapModeActGroup; + QList mapModeAct; + + QActionGroup *zoomActGroup; + QList zoomAct; + + QActionGroup *maxUpdateRateActGroup; + QList maxUpdateRateAct; + + // ***** + + void homeMagicWaypoint(); + + void moveToMagicWaypointPosition(); + + void loadComboBoxLines(QComboBox *comboBox, QString filename); + void saveComboBoxLines(QComboBox *comboBox, QString filename); + + void hideMagicWaypointControls(); + void showMagicWaypointControls(); + + void keepMagicWaypointWithInSafeArea(); + + double distance(internals::PointLatLng from, internals::PointLatLng to); + double bearing(internals::PointLatLng from, internals::PointLatLng to); + internals::PointLatLng destPoint(internals::PointLatLng source, double bear, double dist); + + bool getUAVPosition(double &latitude, double &longitude, double &altitude); + bool getGPSPosition(double &latitude, double &longitude, double &altitude); + double getUAV_Yaw(); + + void setMapFollowingMode(); + + bool setHomeLocationObject(); +}; + +#endif /* OPMAP_GADGETWIDGET_H_ */ diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetfactory.cpp b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetfactory.cpp index 82932cf62..b76b87361 100644 --- a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetfactory.cpp +++ b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetfactory.cpp @@ -33,7 +33,7 @@ PFDGadgetFactory::PFDGadgetFactory(QObject *parent) : IUAVGadgetFactory(QString("PFDGadget"), - tr("Primary Flight Display Gadget"), + tr("Primary Flight Display"), parent) { } diff --git a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.ui b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.ui index 4086d1a5a..f9a2808b3 100644 --- a/ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.ui +++ b/ground/openpilotgcs/src/plugins/pfd/pfdgadgetoptionspage.ui @@ -7,7 +7,7 @@ 0 0 529 - 346 + 271 @@ -19,131 +19,99 @@ Form - - - - -1 - -1 - 504 - 331 - - - - - QLayout::SetMinimumSize - - - 10 - - - 5 - - - 10 - - - 10 - - - - - 10 - - - QLayout::SetMaximumSize - - - 10 - - - - - PFD SVG: - - - - - - - - 0 - 0 - - - - - - - - - - Qt::Horizontal - - - - - - - - - true - - - Use OpenGL for rendering - - - true - - - - - - - High Quality text (OpenGL) - - - - - - - - - - - Smooth updates - - - true - - - - - - - - - Qt::Vertical - - - QSizePolicy::Minimum - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - - - + + + + + 10 + + + QLayout::SetMaximumSize + + + 10 + + + + + PFD SVG: + + + + + + + + 0 + 0 + + + + + + + + + + Qt::Horizontal + + + + + + + + + true + + + Use OpenGL for rendering + + + true + + + + + + + High Quality text (OpenGL) + + + + + + + + + + + Smooth updates + + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 40 + + + + + diff --git a/ground/openpilotgcs/src/plugins/pipxtreme/pipxtremegadgetfactory.cpp b/ground/openpilotgcs/src/plugins/pipxtreme/pipxtremegadgetfactory.cpp index 42ce2ec91..4574913d5 100644 --- a/ground/openpilotgcs/src/plugins/pipxtreme/pipxtremegadgetfactory.cpp +++ b/ground/openpilotgcs/src/plugins/pipxtreme/pipxtremegadgetfactory.cpp @@ -31,7 +31,7 @@ #include PipXtremeGadgetFactory::PipXtremeGadgetFactory(QObject *parent) : - IUAVGadgetFactory(QString("PipXtreme"), tr("PipXtreme Gadget"), parent) + IUAVGadgetFactory(QString("PipXtreme"), tr("PipXtreme"), parent) { } @@ -49,8 +49,3 @@ IUAVGadgetConfiguration * PipXtremeGadgetFactory::createConfiguration(QSettings { return new PipXtremeGadgetConfiguration(QString("PipXtreme"), qSettings); } - -IOptionsPage * PipXtremeGadgetFactory::createOptionsPage(IUAVGadgetConfiguration *config) -{ - return new PipXtremeGadgetOptionsPage(qobject_cast(config)); -} diff --git a/ground/openpilotgcs/src/plugins/pipxtreme/pipxtremegadgetfactory.h b/ground/openpilotgcs/src/plugins/pipxtreme/pipxtremegadgetfactory.h index d6d2bf736..8bd48f46b 100644 --- a/ground/openpilotgcs/src/plugins/pipxtreme/pipxtremegadgetfactory.h +++ b/ground/openpilotgcs/src/plugins/pipxtreme/pipxtremegadgetfactory.h @@ -45,7 +45,6 @@ public: Core::IUAVGadget * createGadget(QWidget *parent); IUAVGadgetConfiguration * createConfiguration(QSettings *qSettings); - IOptionsPage * createOptionsPage(IUAVGadgetConfiguration *config); }; #endif diff --git a/ground/openpilotgcs/src/plugins/plugins.pro b/ground/openpilotgcs/src/plugins/plugins.pro index e58608301..7a86f53be 100644 --- a/ground/openpilotgcs/src/plugins/plugins.pro +++ b/ground/openpilotgcs/src/plugins/plugins.pro @@ -64,12 +64,20 @@ plugin_uavobjectbrowser.depends = plugin_coreplugin plugin_uavobjectbrowser.depends += plugin_uavobjects SUBDIRS += plugin_uavobjectbrowser +!contains(QT_VERSION, ^4\\.8\\..*) { # ModelView UAVGadget plugin_modelview.subdir = modelview plugin_modelview.depends = plugin_coreplugin plugin_modelview.depends += plugin_uavobjects SUBDIRS += plugin_modelview +#Notify gadget +plugin_notify.subdir = notify +plugin_notify.depends = plugin_coreplugin +plugin_notify.depends += plugin_uavobjects +SUBDIRS += plugin_notify +} + #Uploader gadget plugin_uploader.subdir = uploader plugin_uploader.depends = plugin_coreplugin @@ -95,12 +103,6 @@ plugin_systemhealth.depends = plugin_coreplugin plugin_systemhealth.depends += plugin_uavobjects SUBDIRS += plugin_systemhealth -#Notify gadget -plugin_notify.subdir = notify -plugin_notify.depends = plugin_coreplugin -plugin_notify.depends += plugin_uavobjects -SUBDIRS += plugin_notify - #Config gadget plugin_config.subdir = config plugin_config.depends = plugin_coreplugin diff --git a/ground/openpilotgcs/src/plugins/rawhid/rawhid.pri b/ground/openpilotgcs/src/plugins/rawhid/rawhid.pri index 2761db5be..4982d3408 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/rawhid.pri +++ b/ground/openpilotgcs/src/plugins/rawhid/rawhid.pri @@ -1,3 +1,3 @@ include(rawhid_dependencies.pri) -LIBS *= -l$$qtLibraryTarget(RawHID) +LIBS *= -l$$qtLibraryName(RawHID) diff --git a/ground/openpilotgcs/src/plugins/rawhid/usbmonitor_win.cpp b/ground/openpilotgcs/src/plugins/rawhid/usbmonitor_win.cpp index 6681b8363..4eded8e7c 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/usbmonitor_win.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/usbmonitor_win.cpp @@ -177,6 +177,7 @@ bool USBMonitor::matchAndDispatchChangedDevice(const QString & deviceID, const G info.devicePath=deviceID; if( wParam == DBT_DEVICEARRIVAL ) { + qDebug()<<"INSERTION"; if(infoFromHandle(guid,info,devInfo,i)==0) break; knowndevices.append(info); @@ -186,19 +187,19 @@ bool USBMonitor::matchAndDispatchChangedDevice(const QString & deviceID, const G } else if( wParam == DBT_DEVICEREMOVECOMPLETE ) { + bool found=false; for(int x=0;xbtnColor->text()), options_page->widget); + QColor color = QColorDialog::getColor( QColor(options_page->btnColor->text())); if (color.isValid()) { setButtonColor(color); } diff --git a/ground/openpilotgcs/src/plugins/scope/scopegadgetoptionspage.ui b/ground/openpilotgcs/src/plugins/scope/scopegadgetoptionspage.ui index 4ba44b242..2aaee1942 100644 --- a/ground/openpilotgcs/src/plugins/scope/scopegadgetoptionspage.ui +++ b/ground/openpilotgcs/src/plugins/scope/scopegadgetoptionspage.ui @@ -1,329 +1,315 @@ - - - ScopeGadgetOptionsPage - - - - 0 - 0 - 550 - 290 - - - - Form - - - - - 10 - 10 - 541 - 271 - - - - - - 0 - 0 - 531 - 272 - - - - - 3 - - - - - QLayout::SetDefaultConstraint - - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - - Bitstream Charter - 75 - true - - - - X-Axis - - - - - - - Plot Type: - - - - - - - - - - Data Size: - - - - - - - seconds - - - 5000 - - - 30 - - - 300 - - - - - - - Update Interval: - - - - - - - ms - - - 10 - - - 30000 - - - 500 - - - 1000 - - - - - - - - Bitstream Charter - 75 - true - - - - Plot curves - - - - - - - UAVObject: - - - - - - - - - - UAVField: - - - - - - - - - - Color: - - - - - - - Choose - - - - - - - Scale: - - - - - - - false - - - - - - - - - QLayout::SetFixedSize - - - - - Qt::Vertical - - - - 20 - 100 - - - - - - - - Add a new curve to the scope, or update it if the UAVObject and UAVField is the same. - - - Add -Update - - - - - - - Remove the curve from the scope. - - - Remove - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 15 - - - - - - - - - - - - Qt::Vertical - - - - 0 - 200 - - - - - - - - QAbstractItemView::SelectItems - - - 100 - - - - - - - - - - - - - - - - - Log data to csv file - - - - - - - New file on connect - - - - - - - - - Logging path - - - - - - - - 0 - 0 - - - - - - - - - - - - - - - Utils::PathChooser - QWidget -
utils/pathchooser.h
- 1 -
-
- - -
+ + + ScopeGadgetOptionsPage + + + + 0 + 0 + 550 + 405 + + + + Form + + + + + + QLayout::SetDefaultConstraint + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + + Bitstream Charter + 75 + true + + + + X-Axis + + + + + + + Plot Type: + + + + + + + + + + Data Size: + + + + + + + seconds + + + 5000 + + + 30 + + + 300 + + + + + + + Update Interval: + + + + + + + ms + + + 10 + + + 30000 + + + 500 + + + 1000 + + + + + + + + Bitstream Charter + 75 + true + + + + Plot curves + + + + + + + UAVObject: + + + + + + + + + + UAVField: + + + + + + + + + + Color: + + + + + + + Choose + + + + + + + Scale: + + + + + + + false + + + + + + + + + QLayout::SetFixedSize + + + + + Qt::Vertical + + + + 20 + 100 + + + + + + + + Add a new curve to the scope, or update it if the UAVObject and UAVField is the same. + + + Add +Update + + + + + + + Remove the curve from the scope. + + + Remove + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 15 + + + + + + + + + + + + Qt::Vertical + + + + 0 + 200 + + + + + + + + QAbstractItemView::SelectItems + + + 100 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Log data to csv file + + + + + + + New file on connect + + + + + + + + + Logging path + + + + + + + + 0 + 0 + + + + + + + + + + + Utils::PathChooser + QWidget +
utils/pathchooser.h
+ 1 +
+
+ + +
diff --git a/ground/openpilotgcs/src/plugins/serialconnection/serial.pri b/ground/openpilotgcs/src/plugins/serialconnection/serial.pri index d14f80e74..2b5291336 100644 --- a/ground/openpilotgcs/src/plugins/serialconnection/serial.pri +++ b/ground/openpilotgcs/src/plugins/serialconnection/serial.pri @@ -1,3 +1,3 @@ include(serial_dependencies.pri) -LIBS *= -l$$qtLibraryTarget(Serial) +LIBS *= -l$$qtLibraryName(Serial) diff --git a/ground/openpilotgcs/src/plugins/serialconnection/serialplugin.cpp b/ground/openpilotgcs/src/plugins/serialconnection/serialplugin.cpp index 408b9e1ae..e62afb44a 100644 --- a/ground/openpilotgcs/src/plugins/serialconnection/serialplugin.cpp +++ b/ground/openpilotgcs/src/plugins/serialconnection/serialplugin.cpp @@ -165,8 +165,7 @@ void SerialConnection::closeDevice(const QString &deviceName) Q_UNUSED(deviceName); //we have to delete the serial connection we created if (serialHandle){ - serialHandle->close (); - delete(serialHandle); + serialHandle->deleteLater(); serialHandle = NULL; m_deviceOpened = false; } diff --git a/ground/openpilotgcs/src/plugins/systemhealth/systemhealthgadgetfactory.cpp b/ground/openpilotgcs/src/plugins/systemhealth/systemhealthgadgetfactory.cpp index 80abb1be7..41e068c17 100644 --- a/ground/openpilotgcs/src/plugins/systemhealth/systemhealthgadgetfactory.cpp +++ b/ground/openpilotgcs/src/plugins/systemhealth/systemhealthgadgetfactory.cpp @@ -33,7 +33,7 @@ SystemHealthGadgetFactory::SystemHealthGadgetFactory(QObject *parent) : IUAVGadgetFactory(QString("SystemHealthGadget"), - tr("System Health Gadget"), + tr("System Health"), parent) { } diff --git a/ground/openpilotgcs/src/plugins/systemhealth/systemhealthgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/systemhealth/systemhealthgadgetwidget.cpp index 7a0d5066f..440ff58df 100644 --- a/ground/openpilotgcs/src/plugins/systemhealth/systemhealthgadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/systemhealth/systemhealthgadgetwidget.cpp @@ -151,6 +151,16 @@ void SystemHealthGadgetWidget::setSystemFile(QString dfn) QGraphicsScene *l_scene = scene(); l_scene->setSceneRect(background->boundingRect()); fitInView(background, Qt::KeepAspectRatio ); + + // Check whether the autopilot is connected already, by the way: + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager *objManager = pm->getObject(); + TelemetryManager* telMngr = pm->getObject(); + if (telMngr->isConnected()) { + onAutopilotConnect(); + SystemAlarms* obj = dynamic_cast(objManager->getObject(QString("SystemAlarms"))); + updateAlarms(obj); + } } } else diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobject.cpp b/ground/openpilotgcs/src/plugins/uavobjects/uavobject.cpp index e72f468df..c7161bc64 100644 --- a/ground/openpilotgcs/src/plugins/uavobjects/uavobject.cpp +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobject.cpp @@ -27,6 +27,7 @@ */ #include "uavobject.h" #include +#include /** * Constructor @@ -224,7 +225,7 @@ UAVObjectField* UAVObject::getField(const QString& name) } } // If this point is reached then the field was not found - Q_ASSERT_X(0,"UAVObject::getField",QString("Non existant field " + name + " requested. This indicates a bug. Make sure you also have null checking for non-debug code.").toAscii()); + qWarning()<<"UAVObject::getField Non existant field "< +struct deviceDescriptorStruct +{ +public: + QString gitTag; + QString buildDate; + QString description; + int boardType; + int boardRevision; + static QString idToBoardName(int id) + { + switch (id | 0x0011) { + case 0x0111://MB + return QString("OpenPilot MainBoard"); + break; + case 0x0311://PipX + return QString("PipXtreame"); + break; + case 0x0411://Coptercontrol + return QString("CopterControl"); + break; + case 0x0211://INS + return QString("OpenPilot INS"); + break; + default: + return QString(""); + break; + } + } + deviceDescriptorStruct(){} +}; + +#endif // DEVICEDESCRIPTORSTRUCT_H diff --git a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutil.pri b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutil.pri index fde2f6de0..3890b284a 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutil.pri +++ b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutil.pri @@ -1,6 +1,6 @@ -include(uavobjectutil_dependencies.pri) - -# Add the include path to the built-in uavobject include files. -INCLUDEPATH += $$PWD - -LIBS *= -l$$qtLibraryTarget(UAVObjectUtil) +include(uavobjectutil_dependencies.pri) + +# Add the include path to the built-in uavobject include files. +INCLUDEPATH += $$PWD + +LIBS *= -l$$qtLibraryName(UAVObjectUtil) diff --git a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutil.pro b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutil.pro index 2776a2d25..92e490542 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutil.pro +++ b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutil.pro @@ -6,7 +6,8 @@ include(uavobjectutil_dependencies.pri) HEADERS += uavobjectutil_global.h \ uavobjectutilmanager.h \ - uavobjectutilplugin.h + uavobjectutilplugin.h \ + devicedescriptorstruct.h SOURCES += uavobjectutilmanager.cpp \ uavobjectutilplugin.cpp diff --git a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp index 856fc6159..b5070c269 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp +++ b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp @@ -41,6 +41,11 @@ UAVObjectUtilManager::UAVObjectUtilManager() { mutex = new QMutex(QMutex::Recursive); + saveState = IDLE; + failureTimer.stop(); + failureTimer.setSingleShot(true); + failureTimer.setInterval(1000); + connect(&failureTimer, SIGNAL(timeout()),this,SLOT(objectPersistenceOperationFailed())); } UAVObjectUtilManager::~UAVObjectUtilManager() @@ -58,64 +63,154 @@ UAVObjectUtilManager::~UAVObjectUtilManager() } } + +UAVObjectManager* UAVObjectUtilManager::getObjectManager() { + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager * objMngr = pm->getObject(); + Q_ASSERT(objMngr); + return objMngr; +} + + // ****************************** // SD card saving +// +/* + Add a new object to save in the queue + */ void UAVObjectUtilManager::saveObjectToSD(UAVObject *obj) { - QMutexLocker locker(mutex); + // Add to queue + queue.enqueue(obj); + qDebug() << "Enqueue object: " << obj->getName(); - if (!obj) return; - // Add to queue - queue.enqueue(obj); + // If queue length is one, then start sending (call sendNextObject) + // Otherwise, do nothing, it's sending anyway + if (queue.length()==1) + saveNextObject(); + - // If queue length is one, then start sending (call sendNextObject) - // Otherwise, do nothing, it's sending anyway - if (queue.length() <= 1) - saveNextObject(); } void UAVObjectUtilManager::saveNextObject() { - if (queue.isEmpty()) return; + if ( queue.isEmpty() ) + { + return; + } - // Get next object from the queue - UAVObject *obj = queue.head(); - if (!obj) return; + Q_ASSERT(saveState == IDLE); - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - if (!pm) return; + // Get next object from the queue + UAVObject* obj = queue.head(); + qDebug() << "Request board to save object " << obj->getName(); - UAVObjectManager *om = pm->getObject(); - if (!om) return; - - ObjectPersistence *objper = dynamic_cast(om->getObject(ObjectPersistence::NAME)); - connect(objper, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(transactionCompleted(UAVObject *, bool))); - - ObjectPersistence::DataFields data; - data.Operation = ObjectPersistence::OPERATION_SAVE; - data.Selection = ObjectPersistence::SELECTION_SINGLEOBJECT; - data.ObjectID = obj->getObjID(); - data.InstanceID = obj->getInstID(); - objper->setData(data); - objper->updated(); + ObjectPersistence* objper = dynamic_cast( getObjectManager()->getObject(ObjectPersistence::NAME) ); + connect(objper, SIGNAL(transactionCompleted(UAVObject*,bool)), this, SLOT(objectPersistenceTransactionCompleted(UAVObject*,bool))); + connect(objper, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(objectPersistenceUpdated(UAVObject *))); + saveState = AWAITING_ACK; + if (obj != NULL) + { + ObjectPersistence::DataFields data; + data.Operation = ObjectPersistence::OPERATION_SAVE; + data.Selection = ObjectPersistence::SELECTION_SINGLEOBJECT; + data.ObjectID = obj->getObjID(); + data.InstanceID = obj->getInstID(); + objper->setData(data); + objper->updated(); + } + // Now: we are going to get two "objectUpdated" messages (one coming from GCS, one coming from Flight, which + // will confirm the object was properly received by both sides) and then one "transactionCompleted" indicating + // that the Flight side did not only receive the object but it did receive it without error. Last we will get + // a last "objectUpdated" message coming from flight side, where we'll get the results of the objectPersistence + // operation we asked for (saved, other). } -void UAVObjectUtilManager::transactionCompleted(UAVObject *obj, bool success) +/** + * @brief Process the transactionCompleted message from Telemetry indicating request sent successfully + * @param[in] The object just transsacted. Must be ObjectPersistance + * @param[in] success Indicates that the transaction did not time out + * + * After a failed transaction (usually timeout) resends the save request. After a succesful + * transaction will then wait for a save completed update from the autopilot. + */ +void UAVObjectUtilManager::objectPersistenceTransactionCompleted(UAVObject* obj, bool success) { - Q_UNUSED(success); - - QMutexLocker locker(mutex); - - if (!obj) return; - - // Disconnect from sending object - obj->disconnect(this); - queue.dequeue(); // We can now remove the object, it's done. - saveNextObject(); + if(success) { + Q_ASSERT(obj->getName().compare("ObjectPersistence") == 0); + Q_ASSERT(saveState == AWAITING_ACK); + // Two things can happen: + // Either the Object Save Request did actually go through, and then we should get in + // "AWAITING_COMPLETED" mode, or the Object Save Request did _not_ go through, for example + // because the object does not exist and then we will never get a subsequent update. + // For this reason, we will arm a 1 second timer to make provision for this and not block + // the queue: + saveState = AWAITING_COMPLETED; + disconnect(obj, SIGNAL(transactionCompleted(UAVObject*,bool)), this, SLOT(objectPersistenceTransactionCompleted(UAVObject*,bool))); + failureTimer.start(1000); // Create a timeout + } else { + // Can be caused by timeout errors on sending. Forget it and send next. + qDebug() << "objectPersistenceTranscationCompleted (error)"; + UAVObject *obj = getObjectManager()->getObject(ObjectPersistence::NAME); + obj->disconnect(this); + queue.dequeue(); // We can now remove the object, it failed anyway. + saveState = IDLE; + emit saveCompleted(obj->getField("ObjectID")->getValue().toInt(), false); + saveNextObject(); + } } +/** + * @brief Object persistence operation failed, i.e. we never got an update + * from the board saying "completed". + */ +void UAVObjectUtilManager::objectPersistenceOperationFailed() +{ + qDebug() << "objectPersistenceOperationFailed"; + if(saveState == AWAITING_COMPLETED) { + //TODO: some warning that this operation failed somehow + // We have to disconnect the object persistence 'updated' signal + // and ask to save the next object: + UAVObject *obj = getObjectManager()->getObject(ObjectPersistence::NAME); + obj->disconnect(this); + queue.dequeue(); // We can now remove the object, it failed anyway. + saveState = IDLE; + emit saveCompleted(obj->getField("ObjectID")->getValue().toInt(), false); + saveNextObject(); + } +} + + + +/** + * @brief Process the ObjectPersistence updated message to confirm the right object saved + * then requests next object be saved. + * @param[in] The object just received. Must be ObjectPersistance + */ +void UAVObjectUtilManager::objectPersistenceUpdated(UAVObject * obj) +{ + qDebug() << "objectPersistenceUpdated: " << obj->getField("Operation")->getValue().toString(); + Q_ASSERT(obj->getName().compare("ObjectPersistence") == 0); + if(saveState == AWAITING_COMPLETED) { + failureTimer.stop(); + // Check flight is saying it completed. This is the only thing flight should do to trigger an update. + Q_ASSERT( obj->getField("Operation")->getValue().toString().compare(QString("Completed")) == 0 ); + + // Check right object saved + UAVObject* savingObj = queue.head(); + Q_ASSERT( obj->getField("ObjectID")->getValue() == savingObj->getObjID() ); + + obj->disconnect(this); + queue.dequeue(); // We can now remove the object, it's done. + saveState = IDLE; + emit saveCompleted(obj->getField("ObjectID")->getValue().toInt(), true); + saveNextObject(); + } +} + + /** * Get the UAV Board model, for anyone interested. Return format is: * (Board Type << 8) + BoardRevision. @@ -143,6 +238,93 @@ int UAVObjectUtilManager::getBoardModel() return boardType; } +/** + * Get the UAV Board CPU Serial Number, for anyone interested. Return format is a byte array + */ +QByteArray UAVObjectUtilManager::getBoardCPUSerial() +{ + QByteArray cpuSerial; + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + if (!pm) + return 0; + UAVObjectManager *om = pm->getObject(); + if (!om) + return 0; + + UAVDataObject *obj = dynamic_cast(om->getObject(QString("FirmwareIAPObj"))); + // The code below will ask for the object update and wait for the updated to be received, + // or the timeout of the timer, set to 1 second. + QEventLoop loop; + connect(obj, SIGNAL(objectUpdated(UAVObject*)), &loop, SLOT(quit())); + QTimer::singleShot(1000, &loop, SLOT(quit())); // Create a timeout + obj->requestUpdate(); + loop.exec(); + + UAVObjectField* cpuField = obj->getField("CPUSerial"); + for (uint i = 0; i < cpuField->getNumElements(); ++i) { + cpuSerial.append(cpuField->getValue(i).toUInt()); + } + return cpuSerial; +} + +quint32 UAVObjectUtilManager::getFirmwareCRC() +{ + quint32 fwCRC; + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + if (!pm) + return 0; + UAVObjectManager *om = pm->getObject(); + if (!om) + return 0; + + UAVDataObject *obj = dynamic_cast(om->getObject(QString("FirmwareIAPObj"))); + obj->getField("crc")->setValue(0); + obj->updated(); + // The code below will ask for the object update and wait for the updated to be received, + // or the timeout of the timer, set to 1 second. + QEventLoop loop; + connect(obj, SIGNAL(objectUpdated(UAVObject*)), &loop, SLOT(quit())); + QTimer::singleShot(1000, &loop, SLOT(quit())); // Create a timeout + obj->requestUpdate(); + loop.exec(); + + UAVObjectField* fwCRCField = obj->getField("crc"); + + fwCRC=(quint32)fwCRCField->getValue().toLongLong(); + return fwCRC; +} + +/** + * Get the UAV Board Description, for anyone interested. + */ +QByteArray UAVObjectUtilManager::getBoardDescription() +{ + QByteArray ret; + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + if (!pm) + return 0; + UAVObjectManager *om = pm->getObject(); + if (!om) + return 0; + + UAVDataObject *obj = dynamic_cast(om->getObject(QString("FirmwareIAPObj"))); + // The code below will ask for the object update and wait for the updated to be received, + // or the timeout of the timer, set to 1 second. + QEventLoop loop; + connect(obj, SIGNAL(objectUpdated(UAVObject*)), &loop, SLOT(quit())); + QTimer::singleShot(1000, &loop, SLOT(quit())); // Create a timeout + obj->requestUpdate(); + loop.exec(); + + UAVObjectField* descriptionField = obj->getField("Description"); + // Description starts with an offset of + for (uint i = 0; i < descriptionField->getNumElements(); ++i) { + ret.append(descriptionField->getValue(i).toInt()); + } + return ret; +} + + // ****************************** // HomeLocation @@ -470,4 +652,51 @@ int UAVObjectUtilManager::getTelemetrySerialPortSpeeds(QComboBox *comboBox) return 0; // OK } +deviceDescriptorStruct UAVObjectUtilManager::getBoardDescriptionStruct() +{ + deviceDescriptorStruct ret; + descriptionToStructure(getBoardDescription(),&ret); + return ret; +} + +bool UAVObjectUtilManager::descriptionToStructure(QByteArray desc, deviceDescriptorStruct *struc) +{ + if (desc.startsWith("OpFw")) { + // This looks like a binary with a description at the end + /* + # 4 bytes: header: "OpFw" + # 4 bytes: GIT commit tag (short version of SHA1) + # 4 bytes: Unix timestamp of compile time + # 2 bytes: target platform. Should follow same rule as BOARD_TYPE and BOARD_REVISION in board define files. + # 26 bytes: commit tag if it is there, otherwise "Unreleased". Zero-padded + # ---- 40 bytes limit --- + # 20 bytes: SHA1 sum of the firmware. + # 40 bytes: free for now. + */ + + // Note: the ARM binary is big-endian: + quint32 gitCommitTag = desc.at(7)&0xFF; + for (int i=1;i<4;i++) { + gitCommitTag = gitCommitTag<<8; + gitCommitTag += desc.at(7-i) & 0xFF; + } + struc->gitTag=QString::number(gitCommitTag,16); + quint32 buildDate = desc.at(11)&0xFF; + for (int i=1;i<4;i++) { + buildDate = buildDate<<8; + buildDate += desc.at(11-i) & 0xFF; + } + struc->buildDate= QDateTime::fromTime_t(buildDate).toUTC().toString("yyyyMMdd HH:mm"); + QByteArray targetPlatform = desc.mid(12,2); + // TODO: check platform compatibility + QString dscText = QString(desc.mid(14,26)); + struc->boardType=(int)targetPlatform.at(0); + struc->boardRevision=(int)targetPlatform.at(1); + struc->description=dscText; + return true; + } + return false; + +} + // ****************************** diff --git a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.h b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.h index 8a97b60dd..6c7782b25 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.h +++ b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.h @@ -35,13 +35,14 @@ #include "uavobjectmanager.h" #include "uavobject.h" #include "objectpersistence.h" - +#include "devicedescriptorstruct.h" #include #include +#include #include #include #include - +#include class UAVOBJECTUTIL_EXPORT UAVObjectUtilManager: public QObject { Q_OBJECT @@ -61,17 +62,30 @@ public: int getTelemetrySerialPortSpeeds(QComboBox *comboBox); int getBoardModel(); + QByteArray getBoardCPUSerial(); + quint32 getFirmwareCRC(); + QByteArray getBoardDescription(); + deviceDescriptorStruct getBoardDescriptionStruct(); + static bool descriptionToStructure(QByteArray desc,deviceDescriptorStruct * struc); + UAVObjectManager* getObjectManager(); + void saveObjectToSD(UAVObject *obj); + +signals: + void saveCompleted(int objectID, bool status); private: QMutex *mutex; - QQueue queue; - + enum {IDLE, AWAITING_ACK, AWAITING_COMPLETED} saveState; void saveNextObject(); - void saveObjectToSD(UAVObject *obj); + QTimer failureTimer; private slots: - void transactionCompleted(UAVObject *obj, bool success); + //void transactionCompleted(UAVObject *obj, bool success); + void objectPersistenceTransactionCompleted(UAVObject* obj, bool success); + void objectPersistenceUpdated(UAVObject * obj); + void objectPersistenceOperationFailed(); + }; diff --git a/ground/openpilotgcs/src/plugins/uavsettingsimportexport/importsummary.cpp b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/importsummary.cpp new file mode 100644 index 000000000..a7bf6f367 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/importsummary.cpp @@ -0,0 +1,137 @@ +/** + ****************************************************************************** + * + * @file importsummary.cpp + * @author (C) 2011 The OpenPilot Team, http://www.openpilot.org + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup UAVSettingsImportExport UAVSettings Import/Export Plugin + * @{ + * @brief UAVSettings Import/Export Plugin + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "importsummary.h" + +ImportSummaryDialog::ImportSummaryDialog( QWidget *parent) : + QDialog(parent), + ui(new Ui::ImportSummaryDialog) +{ + ui->setupUi(this); + setWindowTitle(tr("Import Summary")); + + ui->importSummaryList->setColumnCount(3); + ui->importSummaryList->setRowCount(0); + QStringList header; + header.append("Save"); + header.append("Name"); + header.append("Status"); + ui->importSummaryList->setHorizontalHeaderLabels(header); + ui->progressBar->setValue(0); + + connect( ui->closeButton, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->saveToFlash, SIGNAL(clicked()), this, SLOT(doTheSaving())); + + // Connect the help button + connect(ui->helpButton, SIGNAL(clicked()), this, SLOT(openHelp())); + +} + +ImportSummaryDialog::~ImportSummaryDialog() +{ + delete ui; +} + +/* + Open the right page on the wiki + */ +void ImportSummaryDialog::openHelp() +{ + QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/UAV+Settings+import-export", QUrl::StrictMode) ); +} + +/* + Adds a new line about a UAVObject along with its status + (whether it got saved OK or not) + */ +void ImportSummaryDialog::addLine(QString uavObjectName, QString text, bool status) +{ + ui->importSummaryList->setRowCount(ui->importSummaryList->rowCount()+1); + int row = ui->importSummaryList->rowCount()-1; + ui->progressBar->setMaximum(row); + ui->importSummaryList->setCellWidget(row,0,new QCheckBox(ui->importSummaryList)); + QTableWidgetItem *objName = new QTableWidgetItem(uavObjectName); + ui->importSummaryList->setItem(row, 1, objName); + QCheckBox *box = dynamic_cast(ui->importSummaryList->cellWidget(row,0)); + ui->importSummaryList->setItem(row,2,new QTableWidgetItem(text)); + if (status) { + box->setChecked(true); + } else { + box->setChecked(false); + box->setEnabled(false); + } + this->repaint(); + this->showEvent(NULL); +} + +/* + Saves every checked UAVObjet in the list to Flash + */ +void ImportSummaryDialog::doTheSaving() +{ + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager *objManager = pm->getObject(); + UAVObjectUtilManager *utilManager = pm->getObject(); + connect(utilManager, SIGNAL(saveCompleted(int,bool)), this, SLOT(updateSaveCompletion())); + + for(int i=0; i < ui->importSummaryList->rowCount(); i++) { + QString uavObjectName = ui->importSummaryList->item(i,1)->text(); + QCheckBox *box = dynamic_cast(ui->importSummaryList->cellWidget(i,0)); + if (box->isChecked()) { + UAVObject* obj = objManager->getObject(uavObjectName); + utilManager->saveObjectToSD(obj); + this->repaint(); + } + } +} + + +void ImportSummaryDialog::updateSaveCompletion() +{ + ui->progressBar->setValue(ui->progressBar->value()+1); +} + +void ImportSummaryDialog::changeEvent(QEvent *e) +{ + QDialog::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +void ImportSummaryDialog::showEvent(QShowEvent *event) +{ + Q_UNUSED(event) + ui->importSummaryList->resizeColumnsToContents(); + int width = ui->importSummaryList->width()-(ui->importSummaryList->columnWidth(0)+ + ui->importSummaryList->columnWidth(2)); + ui->importSummaryList->setColumnWidth(1,width-15); +} + diff --git a/ground/openpilotgcs/src/plugins/uavsettingsimportexport/importsummary.h b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/importsummary.h new file mode 100644 index 000000000..ab88eb835 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/importsummary.h @@ -0,0 +1,71 @@ +/** + ****************************************************************************** + * + * @file importsummary.h + * @author (C) 2011 The OpenPilot Team, http://www.openpilot.org + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup UAVSettingsImportExport UAVSettings Import/Export Plugin + * @{ + * @brief UAVSettings Import/Export Plugin + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef IMPORTSUMMARY_H +#define IMPORTSUMMARY_H + +#include +#include +#include +#include +#include "ui_importsummarydialog.h" +#include "uavdataobject.h" +#include "uavobjectmanager.h" +#include "extensionsystem/pluginmanager.h" +#include "uavobjectutil/uavobjectutilmanager.h" + + + +namespace Ui { + class ImportSummaryDialog; +} + +class ImportSummaryDialog : public QDialog +{ + Q_OBJECT + +public: + ImportSummaryDialog(QWidget *parent=0); + ~ImportSummaryDialog(); + void addLine(QString objectName, QString text, bool status); + +protected: + void showEvent(QShowEvent *event); + void changeEvent(QEvent *e); + +private: + Ui::ImportSummaryDialog *ui; + +public slots: + void updateSaveCompletion(); + +private slots: + void doTheSaving(); + void openHelp(); + +}; + +#endif // IMPORTSUMMARY_H diff --git a/ground/openpilotgcs/src/plugins/uavsettingsimportexport/importsummarydialog.ui b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/importsummarydialog.ui new file mode 100644 index 000000000..7c7212eb0 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/importsummarydialog.ui @@ -0,0 +1,126 @@ + + + ImportSummaryDialog + + + + 0 + 0 + 400 + 377 + + + + Dialog + + + true + + + + + + UAV Settings import summary + + + + + + + Qt::ScrollBarAlwaysOff + + + true + + + 10 + + + true + + + false + + + false + + + + + + + 24 + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 32 + 32 + + + + + + + + :/core/images/helpicon.svg:/core/images/helpicon.svg + + + + 32 + 32 + + + + true + + + + + + + Save all settings checked above to persistent board storage, +then close the dialog. + + + Save to Board Flash/SD + + + + + + + Close this dialog without saving to persistent storage + + + Close + + + + + + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.cpp b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.cpp index 7bd6b3e5b..342b845e9 100644 --- a/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.cpp +++ b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.cpp @@ -25,17 +25,12 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - * TODO: - * - write import functions - * - split formats into different files/classes - * - better error handling (not a lot of QMessageBoxes) - */ - #include "uavsettingsimportexport.h" #include #include +#include +#include // for menu item #include @@ -74,22 +69,32 @@ bool UAVSettingsImportExportPlugin::initialize(const QStringList& args, QString Core::ActionManager* am = Core::ICore::instance()->actionManager(); Core::ActionContainer* ac = am->actionContainer(Core::Constants::M_FILE); Core::Command* cmd = am->registerAction(new QAction(this), - "UAVSettingsImportExportPlugin.UAVSettingsImportExport", + "UAVSettingsImportExportPlugin.UAVSettingsExport", QList() << Core::Constants::C_GLOBAL_ID); - cmd->setDefaultKeySequence(QKeySequence("Ctrl+E")); + cmd->setDefaultKeySequence(QKeySequence("Ctrl+E")); + cmd->action()->setText(tr("Export UAV Settings...")); + ac->addAction(cmd, Core::Constants::G_FILE_SAVE); + connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(exportUAVSettings())); -// cmd->action()->setText(tr("UAV Settings Import/Export...")); - cmd->action()->setText(tr("UAV Settings Export...")); + cmd = am->registerAction(new QAction(this), + "UAVSettingsImportExportPlugin.UAVSettingsImport", + QList() << + Core::Constants::C_GLOBAL_ID); + cmd->setDefaultKeySequence(QKeySequence("Ctrl+I")); + cmd->action()->setText(tr("Import UAV Settings...")); + ac->addAction(cmd, Core::Constants::G_FILE_SAVE); + connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(importUAVSettings())); -// ac->menu()->addSeparator(); -// ac->appendGroup("ImportExport"); -// ac->addAction(cmd, "ImportExport"); - ac->addAction(cmd, Core::Constants::G_FILE_SAVE); + cmd = am->registerAction(new QAction(this), + "UAVSettingsImportExportPlugin.UAVDataExport", + QList() << + Core::Constants::C_GLOBAL_ID); + cmd->action()->setText(tr("Export UAV Data...")); + ac->addAction(cmd, Core::Constants::G_FILE_SAVE); + connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(exportUAVData())); - connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(importExport())); - - return true; + return true; } void UAVSettingsImportExportPlugin::extensionsInitialized() @@ -97,62 +102,146 @@ void UAVSettingsImportExportPlugin::extensionsInitialized() // Do nothing } + // Slot called by the menu manager on user action -// TODO: import function is not implemented yet -void UAVSettingsImportExportPlugin::importExport() +void UAVSettingsImportExportPlugin::importUAVSettings() { - // available formats - enum { UNDEF, UAV, XML, INI } fileFormat = UNDEF; - - // ask for file name and export format + // ask for file name QString fileName; - QString filters = tr("UAV Settings files (*.uav)") - + ";;" + tr("Simple XML files (*.xml)") - + ";;" + tr("INI files (*.ini)"); - - fileName = QFileDialog::getSaveFileName(0, tr("Save UAV Settings File As"), "", filters); + QString filters = tr("UAVSettings XML files (*.uav);; XML files (*.xml)"); + fileName = QFileDialog::getOpenFileName(0, tr("Import UAV Settings"), "", filters); if (fileName.isEmpty()) { return; } - // check export file format - QFileInfo fileInfo(fileName); - QString fileType = fileInfo.suffix().toLower(); + // Now open the file + QFile file(fileName); + QDomDocument doc("UAVSettings"); + file.open(QFile::ReadOnly|QFile::Text); + if (!doc.setContent(file.readAll())) { + QMessageBox msgBox; + msgBox.setText(tr("File Parsing Failed.")); + msgBox.setInformativeText(tr("This file is not a correct XML file")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); + return; + } + file.close(); - if (fileType == "uav") { - fileFormat = UAV; - } else if (fileType == "xml") { - fileFormat = XML; - } else if (fileType == "ini") { - fileFormat = INI; - } else { - QMessageBox::critical(0, - tr("UAV Settings Export"), - tr("Unsupported export file format: ") + fileType, - QMessageBox::Ok); + QDomElement root = doc.documentElement(); + if (root.tagName() != "settings") { + QMessageBox msgBox; + msgBox.setText(tr("Wrong file contents.")); + msgBox.setInformativeText(tr("This file is not a correct UAVSettings file")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); return; } + // We are now ok: setup the import summary dialog & update it as we + // go along. + ImportSummaryDialog swui; + + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager *objManager = pm->getObject(); + swui.show(); + + QDomNode node = root.firstChild(); + while (!node.isNull()) { + QDomElement e = node.toElement(); + if (e.tagName() == "object") { + // - Read each object + QString uavObjectName = e.attribute("name"); + uint uavObjectID = e.attribute("id").toUInt(NULL,16); + + // Sanity Check: + UAVObject* obj = objManager->getObject(uavObjectName); + if (obj == NULL) { + // This object is unknown! + qDebug() << "Object unknown:" << uavObjectName << uavObjectID; + swui.addLine(uavObjectName, "Error (Object unknown)", false); + + } else { + // - Update each field + // - Issue and "updated" command + bool error=false; + QDomNode field = node.firstChild(); + while(!field.isNull()) { + QDomElement f = field.toElement(); + if (f.tagName() == "field") { + UAVObjectField *uavfield = obj->getField(f.attribute("name")); + if (uavfield) { + QStringList list = f.attribute("values").split(","); + if (list.length() == 1) { + uavfield->setValue(f.attribute("values")); + } else { + // This is an enum: + int i=0; + QStringList list = f.attribute("values").split(","); + foreach (QString element, list) { + uavfield->setValue(element,i++); + } + } + error = false; + } else { + error = true; + } + } + field = field.nextSibling(); + } + obj->updated(); + if (error) { + swui.addLine(uavObjectName, "Warning (Object field unknown)", true); + } else if (uavObjectID != obj->getObjID()) { + qDebug() << "Mismatch for Object " << uavObjectName << uavObjectID << " - " << obj->getObjID(); + swui.addLine(uavObjectName, "Warning (ObjectID mismatch)", true); + } else + swui.addLine(uavObjectName, "OK", true); + } + } + node = node.nextSibling(); + } + swui.exec(); + + + +} + +// Create an XML document from UAVObject database +QString UAVSettingsImportExportPlugin::createXMLDocument( + const QString docName, const bool isSettings, const bool fullExport) +{ // generate an XML first (used for all export formats as a formatted data source) ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); UAVObjectManager *objManager = pm->getObject(); - QDomDocument doc("UAVSettings"); - QDomElement root = doc.createElement("settings"); + QDomDocument doc(docName); + QDomElement root = doc.createElement(isSettings ? "settings" : "data"); doc.appendChild(root); + QDomElement versionInfo =doc.createElement("versionInfo"); + root.appendChild(versionInfo); + QDomElement fw=doc.createElement("Embedded"); + UAVObjectUtilManager* utilMngr = pm->getObject(); + fw.setAttribute("gitcommittag",utilMngr->getBoardDescriptionStruct().gitTag); + fw.setAttribute("fwtag",utilMngr->getBoardDescriptionStruct().description); + fw.setAttribute("cpuSerial",QString(utilMngr->getBoardCPUSerial().toHex())); + + versionInfo.appendChild(fw); + QDomElement gcs=doc.createElement("GCS"); + gcs.setAttribute("revision",QString::fromLatin1(Core::Constants::GCS_REVISION_STR)); + versionInfo.appendChild(gcs); // iterate over settings objects QList< QList > objList = objManager->getDataObjects(); - foreach (QList list, objList) { foreach (UAVDataObject* obj, list) { - if (obj->isSettings()) { + if (obj->isSettings() == isSettings) { // add each object to the XML QDomElement o = doc.createElement("object"); o.setAttribute("name", obj->getName()); o.setAttribute("id", QString("0x")+ QString().setNum(obj->getObjID(),16).toUpper()); - if (fileFormat == UAV) { + if (fullExport) { QDomElement d = doc.createElement("description"); QDomText t = doc.createTextNode(obj->getDescription().remove("@Ref ", Qt::CaseInsensitive)); d.appendChild(t); @@ -175,7 +264,7 @@ void UAVSettingsImportExportPlugin::importExport() f.setAttribute("name", field->getName()); f.setAttribute("values", vals); - if (fileFormat == UAV) { + if (fullExport) { f.setAttribute("type", field->getTypeAsString()); f.setAttribute("units", field->getUnits()); f.setAttribute("elements", nelem); @@ -190,50 +279,103 @@ void UAVSettingsImportExportPlugin::importExport() } } - // save file - if ((fileFormat == UAV) || (fileFormat == XML)) { - QFile file(fileName); - if (file.open(QIODevice::WriteOnly) && - (file.write(doc.toString(4).toAscii()) != -1)) { - file.close(); - } else { - QMessageBox::critical(0, - tr("UAV Settings Export"), - tr("Unable to save settings: ") + fileName, - QMessageBox::Ok); - return; - } - } else if (fileFormat == INI) { - if (QFile::exists(fileName) && !QFile::remove(fileName)) { - QMessageBox::critical(0, - tr("UAV Settings Export"), - tr("Unable to remove existing file: ") + fileName, - QMessageBox::Ok); - return; - } - - QSettings ini(fileName, QSettings::IniFormat); - QDomElement docElem = doc.documentElement(); - QDomNodeList nodeList = docElem.elementsByTagName("object"); - for (int i = 0; i < nodeList.count(); i++) { - QDomElement e = nodeList.at(i).toElement(); - if (!e.isNull()) { - ini.beginGroup(e.attribute("name", "undefined")); - ini.setValue("id", e.attribute("id")); - QDomNodeList n = e.elementsByTagName("field"); - for (int j = 0; j < n.count(); j++) { - QDomElement f = n.at(j).toElement(); - if (!f.isNull()) { - ini.setValue(f.attribute("name", "unknown"), f.attribute("values")); - } - } - ini.endGroup(); - } - } - } + return doc.toString(4); } -void UAVSettingsImportExportPlugin::shutdown() +// Slot called by the menu manager on user action +void UAVSettingsImportExportPlugin::exportUAVSettings() +{ + // ask for file name + QString fileName; + QString filters = tr("UAVSettings XML files (*.uav)"); + + fileName = QFileDialog::getSaveFileName(0, tr("Save UAV Settings File As"), "", filters); + if (fileName.isEmpty()) { + return; + } + + bool fullExport = false; + // If the filename ends with .xml, we will do a full export, otherwise, a simple export + if (fileName.endsWith(".xml")) { + fullExport = true; + } else if (!fileName.endsWith(".uav")) { + fileName.append(".uav"); + } + + // generate an XML first (used for all export formats as a formatted data source) + QString xml = createXMLDocument("UAVSettings", true, fullExport); + + // save file + QFile file(fileName); + if (file.open(QIODevice::WriteOnly) && + (file.write(xml.toAscii()) != -1)) { + file.close(); + } else { + QMessageBox::critical(0, + tr("UAV Settings Export"), + tr("Unable to save settings: ") + fileName, + QMessageBox::Ok); + return; + } + + QMessageBox msgBox; + msgBox.setText(tr("Settings saved.")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); +} + +// Slot called by the menu manager on user action +void UAVSettingsImportExportPlugin::exportUAVData() +{ + if (QMessageBox::question(0, tr("Are you sure?"), + tr("This option is only useful for passing your current " + "system data to the technical support staff. " + "Do you really want to export?"), + QMessageBox::Ok | QMessageBox::Cancel, + QMessageBox::Ok) != QMessageBox::Ok) { + return; + } + + // ask for file name + QString fileName; + QString filters = tr("UAVData XML files (*.uav)"); + + fileName = QFileDialog::getSaveFileName(0, tr("Save UAV Data File As"), "", filters); + if (fileName.isEmpty()) { + return; + } + + bool fullExport = false; + // If the filename ends with .xml, we will do a full export, otherwise, a simple export + if (fileName.endsWith(".xml")) { + fullExport = true; + } else if (!fileName.endsWith(".uav")) { + fileName.append(".uav"); + } + + // generate an XML first (used for all export formats as a formatted data source) + QString xml = createXMLDocument("UAVData", false, fullExport); + + // save file + QFile file(fileName); + if (file.open(QIODevice::WriteOnly) && + (file.write(xml.toAscii()) != -1)) { + file.close(); + } else { + QMessageBox::critical(0, + tr("UAV Data Export"), + tr("Unable to save data: ") + fileName, + QMessageBox::Ok); + return; + } + + QMessageBox msgBox; + msgBox.setText(tr("Data saved.")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); +} + +void UAVSettingsImportExportPlugin::shutdown() { // Do nothing } diff --git a/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.h b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.h index 60b0efd6a..ff8972227 100644 --- a/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.h +++ b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.h @@ -28,7 +28,9 @@ #define UAVSETTINGSIMPORTEXPORT_H #include - +#include "uavobjectutil/uavobjectutilmanager.h" +#include "importsummary.h" +#include "../../../../../build/ground/openpilotgcs/gcsversioninfo.h" class UAVSettingsImportExportPlugin : public ExtensionSystem::IPlugin { Q_OBJECT @@ -41,8 +43,15 @@ public: bool initialize(const QStringList & arguments, QString * errorString); void shutdown(); +private: + QString createXMLDocument(const QString docName, + const bool isSettings, + const bool fullExport); + private slots: - void importExport(); + void importUAVSettings(); + void exportUAVSettings(); + void exportUAVData(); }; diff --git a/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.pluginspec b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.pluginspec index 7b64a8e60..b40dc5b60 100644 --- a/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.pluginspec +++ b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.pluginspec @@ -7,5 +7,6 @@ + diff --git a/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.pro b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.pro index 5f2b18103..fcdc11ae6 100644 --- a/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.pro +++ b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport.pro @@ -1,13 +1,18 @@ - -TEMPLATE = lib -QT += xml - -TARGET = UAVSettingsImportExport - -include(../../openpilotgcsplugin.pri) -include(uavsettingsimportexport_dependencies.pri) - -HEADERS += uavsettingsimportexport.h -SOURCES += uavsettingsimportexport.cpp - -OTHER_FILES += uavsettingsimportexport.pluginspec + +TEMPLATE = lib +QT += xml + +TARGET = UAVSettingsImportExport + +include(../../openpilotgcsplugin.pri) +include(uavsettingsimportexport_dependencies.pri) + +HEADERS += uavsettingsimportexport.h \ + importsummary.h +SOURCES += uavsettingsimportexport.cpp \ + importsummary.cpp + +OTHER_FILES += uavsettingsimportexport.pluginspec + +FORMS += \ + importsummarydialog.ui diff --git a/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport_dependencies.pri b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport_dependencies.pri index 4bb362f98..2bf87c3be 100644 --- a/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport_dependencies.pri +++ b/ground/openpilotgcs/src/plugins/uavsettingsimportexport/uavsettingsimportexport_dependencies.pri @@ -1,2 +1,3 @@ include(../../plugins/coreplugin/coreplugin.pri) include(../../plugins/uavobjects/uavobjects.pri) +include(../../plugins/uavobjectutil/uavobjectutil.pri) diff --git a/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.cpp b/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.cpp index 3cfe6dfe7..6a9d22d5f 100644 --- a/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.cpp +++ b/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.cpp @@ -295,7 +295,7 @@ bool UAVTalk::processInputByte(quint8 rxbyte) } // Check the lengths match - if ((rxPacketLength + rxLength) != packetSize) + if ((rxPacketLength + rxLength + (rxObj->isSingleInstance() ? 0 : 2)) != packetSize) { // packet error - mismatched packet size stats.rxErrors++; rxState = STATE_SYNC; @@ -805,17 +805,3 @@ quint8 UAVTalk::updateCRC(quint8 crc, const quint8* data, qint32 length) crc = crc_table[crc ^ *data++]; return crc; } - - - - - - - - - - - - - - diff --git a/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.pri b/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.pri index addc16a2a..aeb4173aa 100644 --- a/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.pri +++ b/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.pri @@ -1,3 +1,3 @@ -include(uavtalk_dependencies.pri) - -LIBS *= -l$$qtLibraryTarget(UAVTalk) +include(uavtalk_dependencies.pri) + +LIBS *= -l$$qtLibraryName(UAVTalk) diff --git a/ground/openpilotgcs/src/plugins/uploader/Uploader.pluginspec b/ground/openpilotgcs/src/plugins/uploader/Uploader.pluginspec index b2c9a8777..6b24fe1e7 100755 --- a/ground/openpilotgcs/src/plugins/uploader/Uploader.pluginspec +++ b/ground/openpilotgcs/src/plugins/uploader/Uploader.pluginspec @@ -9,5 +9,6 @@ + diff --git a/ground/openpilotgcs/src/plugins/uploader/devicewidget.cpp b/ground/openpilotgcs/src/plugins/uploader/devicewidget.cpp index 771bb5241..e2300bdcd 100644 --- a/ground/openpilotgcs/src/plugins/uploader/devicewidget.cpp +++ b/ground/openpilotgcs/src/plugins/uploader/devicewidget.cpp @@ -34,14 +34,18 @@ deviceWidget::deviceWidget(QWidget *parent) : devicePic = NULL; // Initialize pointer to null // Initialization of the Device icon display - myDevice->devicePicture->setScene(new QGraphicsScene(this)); - - connect(myDevice->verifyButton, SIGNAL(clicked()), this, SLOT(verifyFirmware())); + myDevice->verticalGroupBox_loaded->setVisible(false); + myDevice->groupCustom->setVisible(false); + myDevice->youdont->setVisible(false); + myDevice->gVDevice->setScene(new QGraphicsScene(this)); connect(myDevice->retrieveButton, SIGNAL(clicked()), this, SLOT(downloadFirmware())); connect(myDevice->updateButton, SIGNAL(clicked()), this, SLOT(uploadFirmware())); - + connect(myDevice->pbLoad, SIGNAL(clicked()), this, SLOT(loadFirmware())); + connect(myDevice->youdont, SIGNAL(stateChanged(int)), this, SLOT(confirmCB(int))); QPixmap pix = QPixmap(QString(":uploader/images/view-refresh.svg")); myDevice->statusIcon->setPixmap(pix); + + myDevice->lblCertified->setText(""); } @@ -52,14 +56,16 @@ void deviceWidget::showEvent(QShowEvent *event) // widget is shown, otherwise it cannot compute its values and // the result is usually a ahrsbargraph that is way too small. if (devicePic) - myDevice->devicePicture->fitInView(devicePic,Qt::KeepAspectRatio); + { + myDevice->gVDevice->fitInView(devicePic,Qt::KeepAspectRatio); + } } void deviceWidget::resizeEvent(QResizeEvent* event) { Q_UNUSED(event); if (devicePic) - myDevice->devicePicture->fitInView(devicePic, Qt::KeepAspectRatio); + myDevice->gVDevice->fitInView(devicePic, Qt::KeepAspectRatio); } @@ -72,21 +78,43 @@ void deviceWidget::setDfu(DFUObject *dfu) m_dfu = dfu; } +QString deviceWidget::idToBoardName(int id) +{ + switch (id | 0x0011) { + case 0x0111://MB + return QString("OpenPilot MainBoard"); + break; + case 0x0311://PipX + return QString("PipXtreme"); + break; + case 0x0411://Coptercontrol + return QString("CopterControl"); + break; + case 0x0211://INS + return QString("OpenPilot INS"); + break; + default: + return QString(""); + break; + } +} + /** Fills the various fields for the device */ void deviceWidget::populate() { + int id = m_dfu->devices[deviceID].ID; - myDevice->deviceID->setText(QString("Device ID: ") + QString::number(id, 16)); + myDevice->lbldevID->setText(QString("Device ID: ") + QString::number(id, 16)); // DeviceID tells us what sort of HW we have detected: // display a nice icon: - myDevice->devicePicture->scene()->clear(); - if (devicePic) - delete devicePic; + myDevice->gVDevice->scene()->clear(); + myDevice->lblDevName->setText(deviceDescriptorStruct::idToBoardName(id)); + myDevice->lblHWRev->setText(QString(tr("HW Revision: "))+QString::number(id & 0x0011, 16)); + devicePic = new QGraphicsSvgItem(); devicePic->setSharedRenderer(new QSvgRenderer()); - switch (id) { case 0x0101: devicePic->renderer()->load(QString(":/uploader/images/deviceID-0101.svg")); @@ -104,32 +132,35 @@ void deviceWidget::populate() break; } devicePic->setElementId("device"); - myDevice->devicePicture->scene()->addItem(devicePic); - myDevice->devicePicture->setSceneRect(devicePic->boundingRect()); - myDevice->devicePicture->fitInView(devicePic,Qt::KeepAspectRatio); + myDevice->gVDevice->scene()->addItem(devicePic); + myDevice->gVDevice->setSceneRect(devicePic->boundingRect()); + myDevice->gVDevice->fitInView(devicePic,Qt::KeepAspectRatio); bool r = m_dfu->devices[deviceID].Readable; bool w = m_dfu->devices[deviceID].Writable; - myDevice->deviceACL->setText(QString("Access: ") + QString(r ? "R" : "-") + QString(w ? "W" : "-")); - myDevice->maxCodeSize->setText(QString("Max code size: ") +QString::number(m_dfu->devices[deviceID].SizeOfCode)); - myDevice->fwCRC->setText(QString("FW CRC: ") + QString::number(m_dfu->devices[deviceID].FW_CRC)); - myDevice->BLVersion->setText(QString("BL Version: ") + QString::number(m_dfu->devices[deviceID].BL_Version)); + myDevice->lblAccess->setText(QString("Flash access: ") + QString(r ? "R" : "-") + QString(w ? "W" : "-")); + myDevice->lblMaxCode->setText(QString("Max code size: ") +QString::number(m_dfu->devices[deviceID].SizeOfCode)); + myDevice->lblCRC->setText(QString::number(m_dfu->devices[deviceID].FW_CRC)); + myDevice->lblBLVer->setText(QString("BL version: ") + QString::number(m_dfu->devices[deviceID].BL_Version)); int size=((OP_DFU::device)m_dfu->devices[deviceID]).SizeOfDesc; m_dfu->enterDFU(deviceID); QByteArray desc = m_dfu->DownloadDescriptionAsBA(size); - if (! populateStructuredDescription(desc)) { + + if (! populateBoardStructuredDescription(desc)) { + //TODO // desc was not a structured description QString str = m_dfu->DownloadDescription(size); - myDevice->description->setMaxLength(size); - myDevice->description->setText(str.left(str.indexOf(QChar(255)))); - myDevice->buildDate->setText("Warning: development firmware"); - myDevice->commitTag->setText(""); + myDevice->lblDescription->setText(QString("Firmware custom description: ")+str.left(str.indexOf(QChar(255)))); + QPixmap pix = QPixmap(QString(":uploader/images/warning.svg")); + myDevice->lblCertified->setPixmap(pix); + myDevice->lblCertified->setToolTip(tr("Custom Firmware Build")); + myDevice->lblBuildDate->setText("Warning: development firmware"); + myDevice->lblGitTag->setText(""); + myDevice->lblBrdName->setText(""); } - status("Ready...", STATUSICON_INFO); - } /** @@ -138,49 +169,38 @@ void deviceWidget::populate() */ void deviceWidget::freeze() { - myDevice->description->setEnabled(false); - myDevice->updateButton->setEnabled(false); - myDevice->verifyButton->setEnabled(false); - myDevice->retrieveButton->setEnabled(false); + myDevice->description->setEnabled(false); + myDevice->updateButton->setEnabled(false); + myDevice->retrieveButton->setEnabled(false); } - /** Populates the widget field with the description in case it is structured properly */ -bool deviceWidget::populateStructuredDescription(QByteArray desc) +bool deviceWidget::populateBoardStructuredDescription(QByteArray desc) { - if (desc.startsWith("OpFw")) { - // This looks like a binary with a description at the end - /* - # 4 bytes: header: "OpFw" - # 4 bytes: GIT commit tag (short version of SHA1) - # 4 bytes: Unix timestamp of compile time - # 2 bytes: target platform. Should follow same rule as BOARD_TYPE and BOARD_REVISION in board define files. - # 26 bytes: commit tag if it is there, otherwise "Unreleased". Zero-padded - # ---- 40 bytes limit --- - # 20 bytes: SHA1 sum of the firmware. - # 40 bytes: free for now. - */ - // I don't want to use structs, ok ? - quint32 gitCommitTag = desc.at(4)&0xFF; - for (int i=1;i<4;i++) { - gitCommitTag = gitCommitTag<<8; - gitCommitTag += desc.at(4+i) & 0xFF; + if(UAVObjectUtilManager::descriptionToStructure(desc,&onBoardDescrition)) + { + myDevice->lblGitTag->setText(onBoardDescrition.gitTag); + myDevice->lblBuildDate->setText(onBoardDescrition.buildDate); + if(onBoardDescrition.description.startsWith("release",Qt::CaseInsensitive)) + { + myDevice->lblDescription->setText(QString("Firmware tag: ")+onBoardDescrition.description); + QPixmap pix = QPixmap(QString(":uploader/images/application-certificate.svg")); + myDevice->lblCertified->setPixmap(pix); + myDevice->lblCertified->setToolTip(tr("Tagged officially released firmware build")); + } - myDevice->commitTag->setText("GIT tag 0x" + QString::number(gitCommitTag,16)); - quint32 buildDate = desc.at(8)&0xFF; - for (int i=1;i<4;i++) { - buildDate = buildDate<<8; - buildDate += desc.at(8+i) & 0xFF; + else + { + myDevice->lblDescription->setText(onBoardDescrition.description); + QPixmap pix = QPixmap(QString(":uploader/images/warning.svg")); + myDevice->lblCertified->setPixmap(pix); + myDevice->lblCertified->setToolTip(tr("Untagged or custom firmware build")); } - myDevice->buildDate->setText(QString("Build time: ") + QDateTime::fromTime_t(buildDate).toString()); - QByteArray targetPlatform = desc.mid(12,2); - // TODO: check platform compatibility - QString dscText = QString(desc.mid(14,26)); - myDevice->description->setText(dscText); + myDevice->lblBrdName->setText(idToBoardName(onBoardDescrition.boardType<<8)); return true; } @@ -188,7 +208,36 @@ bool deviceWidget::populateStructuredDescription(QByteArray desc) return false; } +bool deviceWidget::populateLoadedStructuredDescription(QByteArray desc) +{ + if(UAVObjectUtilManager::descriptionToStructure(desc,&LoadedDescrition)) + { + myDevice->lblGitTagL->setText(LoadedDescrition.gitTag); + myDevice->lblBuildDateL->setText( LoadedDescrition.buildDate); + if(LoadedDescrition.description.startsWith("release",Qt::CaseInsensitive)) + { + myDevice->lblDescritpionL->setText(LoadedDescrition.description); + myDevice->description->setText(LoadedDescrition.description); + QPixmap pix = QPixmap(QString(":uploader/images/application-certificate.svg")); + myDevice->lblCertifiedL->setPixmap(pix); + myDevice->lblCertifiedL->setToolTip(tr("Tagged officially released firmware build")); + } + else + { + myDevice->lblDescritpionL->setText(LoadedDescrition.description); + myDevice->description->setText(LoadedDescrition.description); + QPixmap pix = QPixmap(QString(":uploader/images/warning.svg")); + myDevice->lblCertifiedL->setPixmap(pix); + myDevice->lblCertifiedL->setToolTip(tr("Untagged or custom firmware build")); + } + myDevice->lblBrdNameL->setText(deviceDescriptorStruct::idToBoardName(LoadedDescrition.boardType<<8)); + return true; + } + + return false; + +} /** Updates status message for messages coming from DFU */ @@ -197,6 +246,16 @@ void deviceWidget::dfuStatus(QString str) status(str, STATUSICON_RUNNING); } +void deviceWidget::confirmCB(int value) +{ + if(value==Qt::Checked) + { + myDevice->updateButton->setEnabled(true); + } + else + myDevice->updateButton->setEnabled(false); +} + /** Updates status message */ @@ -220,11 +279,74 @@ void deviceWidget::status(QString str, StatusIcon ic) myDevice->statusIcon->setPixmap(px); } -/** - Verifies the firmware CRC - */ -void deviceWidget::verifyFirmware() + +void deviceWidget::loadFirmware() { + myDevice->verticalGroupBox_loaded->setVisible(false); + myDevice->groupCustom->setVisible(false); + + filename = setOpenFileName(); + + if (filename.isEmpty()) { + status("Empty filename", STATUSICON_FAIL); + return; + } + + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + status("Can't open file", STATUSICON_FAIL); + return; + } + + loadedFW = file.readAll(); + myDevice->youdont->setVisible(false); + myDevice->youdont->setChecked(false); + QByteArray desc = loadedFW.right(100); + QPixmap px; + myDevice->lblCRCL->setText( QString::number(DFUObject::CRCFromQBArray(loadedFW,m_dfu->devices[deviceID].SizeOfCode))); + //myDevice->lblFirmwareSizeL->setText(QString("Firmware size: ")+QVariant(loadedFW.length()).toString()+ QString(" bytes")); + if (populateLoadedStructuredDescription(desc)) + { + myDevice->youdont->setChecked(true); + myDevice->verticalGroupBox_loaded->setVisible(true); + myDevice->groupCustom->setVisible(false); + if(myDevice->lblCRC->text()==myDevice->lblCRCL->text()) + { + myDevice->statusLabel->setText(tr("The board has the same firmware as loaded. No need to update")); + px.load(QString(":/uploader/images/warning.svg")); + } + else if(myDevice->lblDevName->text()!=myDevice->lblBrdNameL->text()) + { + myDevice->statusLabel->setText(tr("WARNING: the loaded firmware is for different hardware. Do not update!")); + px.load(QString(":/uploader/images/error.svg")); + } + else if(QDateTime::fromString(onBoardDescrition.buildDate)>QDateTime::fromString(LoadedDescrition.buildDate)) + { + myDevice->statusLabel->setText(tr("The board has newer firmware than loaded. Are you sure you want to update?")); + px.load(QString(":/uploader/images/warning.svg")); + } + else if(!LoadedDescrition.description.startsWith("release",Qt::CaseInsensitive)) + { + myDevice->statusLabel->setText(tr("The loaded firmware is untagged or custom build. Update only if it was received from a trusted source (official website or your own build)")); + px.load(QString(":/uploader/images/warning.svg")); + } + else + { + myDevice->statusLabel->setText(tr("This is the tagged officially released OpenPilot firmware")); + px.load(QString(":/uploader/images/gtk-info.svg")); + } + } + else + { + myDevice->statusLabel->setText(tr("WARNING: the loaded firmware was not packaged with the OpenPilot format. Do not update unless you know what you are doing")); + px.load(QString(":/uploader/images/error.svg")); + myDevice->youdont->setChecked(false); + myDevice->youdont->setVisible(true); + myDevice->verticalGroupBox_loaded->setVisible(false); + myDevice->groupCustom->setVisible(true); + } + myDevice->statusIcon->setPixmap(px); + //myDevice->updateButton->setEnabled(true); } @@ -244,22 +366,8 @@ void deviceWidget::uploadFirmware() verify = true; */ - QString filename = setOpenFileName(); - - if (filename.isEmpty()) { - status("Empty filename", STATUSICON_FAIL); - return; - } - - QFile file(filename); - if (!file.open(QIODevice::ReadOnly)) { - status("Can't open file", STATUSICON_FAIL); - return; - } - - QByteArray arr = file.readAll(); - QByteArray desc = arr.right(100); - if (populateStructuredDescription(desc)) { + QByteArray desc = loadedFW.right(100); + if (desc.startsWith("OpFw")) { descriptionArray = desc; // Now do sanity checking: // - Check whether board type matches firmware: @@ -269,17 +377,13 @@ void deviceWidget::uploadFirmware() status("Error: firmware does not match board", STATUSICON_FAIL); return; } - // Check the firmware embedded in the file: QByteArray firmwareHash = desc.mid(40,20); - QByteArray fileHash = QCryptographicHash::hash(arr.left(arr.length()-100), QCryptographicHash::Sha1); + QByteArray fileHash = QCryptographicHash::hash(loadedFW.left(loadedFW.length()-100), QCryptographicHash::Sha1); if (firmwareHash != fileHash) { status("Error: firmware file corrupt", STATUSICON_FAIL); return; } - - - } else { // The firmware is not packaged, just upload the text in the description field // if it is there. @@ -287,8 +391,6 @@ void deviceWidget::uploadFirmware() } - - status("Starting firmware upload", STATUSICON_RUNNING); // We don't know which device was used previously, so we // are cautious and reenter DFU for this deviceID: @@ -304,7 +406,7 @@ void deviceWidget::uploadFirmware() connect(m_dfu, SIGNAL(progressUpdated(int)), this, SLOT(setProgress(int))); connect(m_dfu, SIGNAL(operationProgress(QString)), this, SLOT(dfuStatus(QString))); connect(m_dfu, SIGNAL(uploadFinished(OP_DFU::Status)), this, SLOT(uploadFinished(OP_DFU::Status))); - bool retstatus = m_dfu->UploadFirmware(filename.toAscii(),verify, deviceID); + bool retstatus = m_dfu->UploadFirmware(filename,verify, deviceID); if(!retstatus ) { status("Could not start upload", STATUSICON_FAIL); return; @@ -367,27 +469,27 @@ void deviceWidget::uploadFinished(OP_DFU::Status retstatus) status(QString("Upload failed with code: ") + m_dfu->StatusToString(retstatus).toLatin1().data(), STATUSICON_FAIL); return; } else - if (!descriptionArray.isEmpty()) { - // We have a structured array to save - status(QString("Updating description"), STATUSICON_RUNNING); - repaint(); // Make sure the text above shows right away - retstatus = m_dfu->UploadDescription(descriptionArray); - if( retstatus != OP_DFU::Last_operation_Success) { - status(QString("Upload failed with code: ") + m_dfu->StatusToString(retstatus).toLatin1().data(), STATUSICON_FAIL); - return; + if (!descriptionArray.isEmpty()) { + // We have a structured array to save + status(QString("Updating description"), STATUSICON_RUNNING); + repaint(); // Make sure the text above shows right away + retstatus = m_dfu->UploadDescription(descriptionArray); + if( retstatus != OP_DFU::Last_operation_Success) { + status(QString("Upload failed with code: ") + m_dfu->StatusToString(retstatus).toLatin1().data(), STATUSICON_FAIL); + return; + } + + } else if (!myDevice->description->text().isEmpty()) { + // Fallback: we save the description field: + status(QString("Updating description"), STATUSICON_RUNNING); + repaint(); // Make sure the text above shows right away + retstatus = m_dfu->UploadDescription(myDevice->description->text()); + if( retstatus != OP_DFU::Last_operation_Success) { + status(QString("Upload failed with code: ") + m_dfu->StatusToString(retstatus).toLatin1().data(), STATUSICON_FAIL); + return; + } } - - } else if (!myDevice->description->text().isEmpty()) { - // Fallback: we save the description field: - status(QString("Updating description"), STATUSICON_RUNNING); - repaint(); // Make sure the text above shows right away - retstatus = m_dfu->UploadDescription(myDevice->description->text()); - if( retstatus != OP_DFU::Last_operation_Success) { - status(QString("Upload failed with code: ") + m_dfu->StatusToString(retstatus).toLatin1().data(), STATUSICON_FAIL); - return; - } - } - + populate(); status("Upload successful", STATUSICON_OK); } @@ -412,7 +514,7 @@ QString deviceWidget::setOpenFileName() QString fileName = QFileDialog::getOpenFileName(this, tr("Select firmware file"), "", - tr("Firmware Files (*.bin)"), + tr("Firmware Files (*.opfw *.bin)"), &selectedFilter, options); return fileName; diff --git a/ground/openpilotgcs/src/plugins/uploader/devicewidget.h b/ground/openpilotgcs/src/plugins/uploader/devicewidget.h index 68905c0c2..772216e3b 100644 --- a/ground/openpilotgcs/src/plugins/uploader/devicewidget.h +++ b/ground/openpilotgcs/src/plugins/uploader/devicewidget.h @@ -38,9 +38,9 @@ #include #include #include - +#include "uavobjectutilmanager.h" +#include "devicedescriptorstruct.h" using namespace OP_DFU; - class deviceWidget : public QWidget { Q_OBJECT @@ -54,6 +54,10 @@ public: QString setOpenFileName(); QString setSaveFileName(); private: + deviceDescriptorStruct onBoardDescrition; + deviceDescriptorStruct LoadedDescrition; + QByteArray loadedFW; + QString idToBoardName(int id); Ui_deviceWidget *myDevice; int deviceID; DFUObject *m_dfu; @@ -62,19 +66,20 @@ private: QGraphicsSvgItem *devicePic; QByteArray descriptionArray; void status(QString str, StatusIcon ic); - bool populateStructuredDescription(QByteArray arr); - + bool populateBoardStructuredDescription(QByteArray arr); + bool populateLoadedStructuredDescription(QByteArray arr); signals: public slots: - void verifyFirmware(); void uploadFirmware(); + void loadFirmware(); void downloadFirmware(); void setProgress(int); void downloadFinished(); void uploadFinished(OP_DFU::Status); void dfuStatus(QString); + void confirmCB(int); protected: void showEvent(QShowEvent *event); diff --git a/ground/openpilotgcs/src/plugins/uploader/devicewidget.ui b/ground/openpilotgcs/src/plugins/uploader/devicewidget.ui index 5d09b3d1a..c5c7a807e 100644 --- a/ground/openpilotgcs/src/plugins/uploader/devicewidget.ui +++ b/ground/openpilotgcs/src/plugins/uploader/devicewidget.ui @@ -6,8 +6,8 @@ 0 0 - 516 - 253 + 576 + 500
@@ -15,144 +15,394 @@ - - - - - - - - DeviceID + + + Device Information + + + + + + + + + 160 + 160 + + + + background: transparent + + + QFrame::NoFrame + + + + + + + + + + + + + lblDevName + + + + + + + DeviceID + + + + + + + lblHWRev + + + + + + + RW + + + + + + + BL Version + + + + + + + MaxCodeSize + + + + + + + + + + + Open a file with new firmware image to be flashed + + + Open... + + + + + + + I know what I'm doing + + + true + + + + + + + false + + + Write loaded firmware image to the board + + + Flash + + + + + + + Read and save current board firmware to a file + + + Retrieve... + + + + + + + + + + + 0 + + + + + + + + + + + + + ic + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Status + + + true + + + + + + + + + + + + + + Firmware: + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + Board name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Description: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Build date: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Git tag: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + CRC: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + - - - - 0 + + + + On Device + + + + + + + + + lblBrdName + + + + + + + lblDescription + + + + + + + lblBuildDate + + + + + + + lblGitTag + + + + + + + lblCRC + + + + + + + + + lblCertified + + + false + + + + + + - - - - ReadWrite + + + + true + + Loaded + + + + + + + + + + lblBrdName + + + + + + + lblDescritpionL + + + + + + + lblBuildDate + + + + + + + lblGitTag + + + + + + + lblCRC + + + + + + + + + lblCertifiedL + + + + + + - - - + + + + Qt::Horizontal + + - 160 - 160 + 40 + 20 - - background: transparent - - - QFrame::NoFrame - - - - - - - false - - - Verify... - - - - - - - Update the firmware on this board. - - - Update... - - - - - - - Download the current board firmware to your computer - - - Retrieve... - - - - - - - BootLoaderVersion - - - - - - - fwCRC - - - - - - - MaxCodeSize - - - - - - - - - ic - - - - - - - - 0 - 0 - - - - - 75 - true - - - - Status - - - - - - - - - Build Date - - - - - - - Commit tag - - + + + + + + + + Custom description: + + + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/uploader/images/application-certificate.svg b/ground/openpilotgcs/src/plugins/uploader/images/application-certificate.svg new file mode 100644 index 000000000..077f741d8 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/uploader/images/application-certificate.svg @@ -0,0 +1,443 @@ + + + + + + image/svg+xml + + + + + + CertificateJakub Steinercertificate + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ground/openpilotgcs/src/plugins/uploader/images/error.svg b/ground/openpilotgcs/src/plugins/uploader/images/error.svg new file mode 100644 index 000000000..8de454769 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/uploader/images/error.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/uploader/images/warning.svg b/ground/openpilotgcs/src/plugins/uploader/images/warning.svg new file mode 100644 index 000000000..697b80a56 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/uploader/images/warning.svg @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/uploader/op_dfu.cpp b/ground/openpilotgcs/src/plugins/uploader/op_dfu.cpp index efd7aa87d..8a9045233 100644 --- a/ground/openpilotgcs/src/plugins/uploader/op_dfu.cpp +++ b/ground/openpilotgcs/src/plugins/uploader/op_dfu.cpp @@ -100,7 +100,7 @@ DFUObject::DFUObject(bool _debug,bool _use_serial,QString portname): if (devices.length()==1) { hidHandle.open(1,devices.first().vendorID,devices.first().productID,0,0); } else { - qDebug() << "More than one device, don't know what to do!"; + qDebug() << devices.length() << " device(s) detected, don't know what to do!"; mready = false; } @@ -718,7 +718,7 @@ OP_DFU::Status DFUObject::UploadFirmwareT(const QString &sfile, const bool &veri return OP_DFU::abort;; } - quint32 crc=CRCFromQBArray(arr,devices[device].SizeOfCode); + quint32 crc=DFUObject::CRCFromQBArray(arr,devices[device].SizeOfCode); if (debug) qDebug() << "NEW FIRMWARE CRC=" << crc; @@ -817,7 +817,7 @@ OP_DFU::Status DFUObject::CompareFirmware(const QString &sfile, const CompareTyp } if(type==OP_DFU::crccompare) { - quint32 crc=CRCFromQBArray(arr,devices[device].SizeOfCode); + quint32 crc=DFUObject::CRCFromQBArray(arr,devices[device].SizeOfCode); if(crc==devices[device].FW_CRC) { cout<<"Compare Successfull CRC MATCH!\n"; @@ -971,7 +971,7 @@ quint32 DFUObject::CRCFromQBArray(QByteArray array, quint32 Size) aux+=(char)array[x*4+0]&0xFF; t[x]=aux; } - return CRC32WideFast(0xFFFFFFFF,Size/4,(quint32*)t); + return DFUObject::CRC32WideFast(0xFFFFFFFF,Size/4,(quint32*)t); } diff --git a/ground/openpilotgcs/src/plugins/uploader/op_dfu.h b/ground/openpilotgcs/src/plugins/uploader/op_dfu.h index c58621f67..420e0a3ea 100644 --- a/ground/openpilotgcs/src/plugins/uploader/op_dfu.h +++ b/ground/openpilotgcs/src/plugins/uploader/op_dfu.h @@ -108,7 +108,7 @@ namespace OP_DFU { Q_OBJECT; public: - + static quint32 CRCFromQBArray(QByteArray array, quint32 Size); //DFUObject(bool debug); DFUObject(bool debug,bool use_serial,QString port); @@ -152,7 +152,7 @@ namespace OP_DFU { // Helper functions: QString StatusToString(OP_DFU::Status const & status); - quint32 CRC32WideFast(quint32 Crc, quint32 Size, quint32 *Buffer); + static quint32 CRC32WideFast(quint32 Crc, quint32 Size, quint32 *Buffer); @@ -179,7 +179,7 @@ namespace OP_DFU { // USB Bootloader: pjrc_rawhid hidHandle; int setStartBit(int command){ return command|0x20; } - quint32 CRCFromQBArray(QByteArray array, quint32 Size); + void CopyWords(char * source, char* destination, int count); void printProgBar( int const & percent,QString const& label); bool StartUpload(qint32 const &numberOfBytes, TransferTypes const & type,quint32 crc); diff --git a/ground/openpilotgcs/src/plugins/uploader/runningdevicewidget.cpp b/ground/openpilotgcs/src/plugins/uploader/runningdevicewidget.cpp new file mode 100644 index 000000000..2cb513344 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/uploader/runningdevicewidget.cpp @@ -0,0 +1,170 @@ +/** + ****************************************************************************** + * + * @file runningdevicewidget.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup Uploader Serial and USB Uploader Plugin + * @{ + * @brief The USB and Serial protocol uploader plugin + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "runningdevicewidget.h" +#include "devicedescriptorstruct.h" +#include "uploadergadgetwidget.h" +runningDeviceWidget::runningDeviceWidget(QWidget *parent) : + QWidget(parent) +{ + myDevice = new Ui_runningDeviceWidget(); + myDevice->setupUi(this); + devicePic = NULL; // Initialize pointer to null + + // Initialization of the Device icon display + myDevice->devicePicture->setScene(new QGraphicsScene(this)); + + /* + QPixmap pix = QPixmap(QString(":uploader/images/view-refresh.svg")); + myDevice->statusIcon->setPixmap(pix); + */ +} + + +void runningDeviceWidget::showEvent(QShowEvent *event) +{ + Q_UNUSED(event) + // Thit fitInView method should only be called now, once the + // widget is shown, otherwise it cannot compute its values and + // the result is usually a ahrsbargraph that is way too small. + if (devicePic) + myDevice->devicePicture->fitInView(devicePic,Qt::KeepAspectRatio); +} + +void runningDeviceWidget::resizeEvent(QResizeEvent* event) +{ + Q_UNUSED(event); + if (devicePic) + myDevice->devicePicture->fitInView(devicePic, Qt::KeepAspectRatio); +} + +/** + Fills the various fields for the device + */ +void runningDeviceWidget::populate() +{ + + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectUtilManager* utilMngr = pm->getObject(); + int id = utilMngr->getBoardModel(); + + myDevice->lblDeviceID->setText(QString("Device ID: ") + QString::number(id, 16)); + myDevice->lblBoardName->setText(deviceDescriptorStruct::idToBoardName(id)); + myDevice->lblHWRev->setText(QString(tr("HW Revision: "))+QString::number(id & 0x0011, 16)); + qDebug()<<"CRC"<getFirmwareCRC(); + myDevice->lblCRC->setText(QString(tr("Firmware CRC: "))+QVariant(utilMngr->getFirmwareCRC()).toString()); + // DeviceID tells us what sort of HW we have detected: + // display a nice icon: + myDevice->devicePicture->scene()->clear(); + if (devicePic) + delete devicePic; + devicePic = new QGraphicsSvgItem(); + devicePic->setSharedRenderer(new QSvgRenderer()); + + switch (id) { + case 0x0101: + devicePic->renderer()->load(QString(":/uploader/images/deviceID-0101.svg")); + break; + case 0x0301: + devicePic->renderer()->load(QString(":/uploader/images/deviceID-0301.svg")); + break; + case 0x0401: + devicePic->renderer()->load(QString(":/uploader/images/deviceID-0401.svg")); + break; + case 0x0201: + devicePic->renderer()->load(QString(":/uploader/images/deviceID-0201.svg")); + break; + default: + break; + } + devicePic->setElementId("device"); + myDevice->devicePicture->scene()->addItem(devicePic); + myDevice->devicePicture->setSceneRect(devicePic->boundingRect()); + myDevice->devicePicture->fitInView(devicePic,Qt::KeepAspectRatio); + + QString serial = utilMngr->getBoardCPUSerial().toHex(); + myDevice->CPUSerial->setText(serial); + + QByteArray description = utilMngr->getBoardDescription(); + deviceDescriptorStruct devDesc; + if(UAVObjectUtilManager::descriptionToStructure(description,&devDesc)) + { + if(devDesc.description.startsWith("release",Qt::CaseInsensitive)) + { + myDevice->lblFWTag->setText(QString("Firmware tag: ")+devDesc.description); + QPixmap pix = QPixmap(QString(":uploader/images/application-certificate.svg")); + myDevice->lblCertified->setPixmap(pix); + myDevice->lblCertified->setToolTip(tr("Tagged officially released firmware build")); + + } + else + { + myDevice->lblFWTag->setText(QString("Firmware tag: ")+devDesc.description); + QPixmap pix = QPixmap(QString(":uploader/images/warning.svg")); + myDevice->lblCertified->setPixmap(pix); + myDevice->lblCertified->setToolTip(tr("Untagged or custom firmware build")); + } + myDevice->lblGitCommitTag->setText("Git commit tag: "+devDesc.gitTag); + myDevice->lblFWDate->setText(QString("Firmware date: ") + devDesc.buildDate); + } + else + { + + myDevice->lblFWTag->setText(QString("Firmware tag: ")+QString(description).left(QString(description).indexOf(QChar(255)))); + myDevice->lblGitCommitTag->setText("Git commit tag: Unknown"); + myDevice->lblFWDate->setText(QString("Firmware date: Unknown")); + QPixmap pix = QPixmap(QString(":uploader/images/warning.svg")); + myDevice->lblCertified->setPixmap(pix); + myDevice->lblCertified->setToolTip(tr("Custom Firmware Build")); + } + //status("Ready...", STATUSICON_INFO); +} + + +/** + Updates status message + */ +/* +void runningDeviceWidget::status(QString str, StatusIcon ic) +{ + QPixmap px; + myDevice->statusLabel->setText(str); + switch (ic) { + case STATUSICON_RUNNING: + px.load(QString(":/uploader/images/system-run.svg")); + break; + case STATUSICON_OK: + px.load(QString(":/uploader/images/dialog-apply.svg")); + break; + case STATUSICON_FAIL: + px.load(QString(":/uploader/images/process-stop.svg")); + break; + default: + px.load(QString(":/uploader/images/gtk-info.svg")); + } + myDevice->statusIcon->setPixmap(px); +} +*/ diff --git a/ground/openpilotgcs/src/plugins/uploader/runningdevicewidget.h b/ground/openpilotgcs/src/plugins/uploader/runningdevicewidget.h new file mode 100644 index 000000000..05dd7f0dc --- /dev/null +++ b/ground/openpilotgcs/src/plugins/uploader/runningdevicewidget.h @@ -0,0 +1,69 @@ +/** + ****************************************************************************** + * + * @file devicewidget.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup YModemUploader YModem Serial Uploader Plugin + * @{ + * @brief The YModem protocol serial uploader plugin + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef RUNNINGDEVICEWIDGET_H +#define RUNNINGDEVICEWIDGET_H + +#include "ui_runningdevicewidget.h" + +#include +#include +#include +#include +#include "uavtalk/telemetrymanager.h" +#include "extensionsystem/pluginmanager.h" +#include "uavobjectmanager.h" +#include "uavobject.h" +#include "uavobjectutilmanager.h" + +class runningDeviceWidget : public QWidget +{ + Q_OBJECT +public: + runningDeviceWidget( QWidget *parent = 0); + void populate(); + void freeze(); + QString setOpenFileName(); + QString setSaveFileName(); + typedef enum { STATUSICON_OK, STATUSICON_RUNNING, STATUSICON_FAIL, STATUSICON_INFO} StatusIcon; + +private: + Ui_runningDeviceWidget *myDevice; + int deviceID; + QGraphicsSvgItem *devicePic; + //void status(QString str, StatusIcon ic); + + +signals: + +protected: + void showEvent(QShowEvent *event); + void resizeEvent(QResizeEvent *event); + +}; + +#endif // RUNNINGDEVICEWIDGET_H diff --git a/ground/openpilotgcs/src/plugins/uploader/runningdevicewidget.ui b/ground/openpilotgcs/src/plugins/uploader/runningdevicewidget.ui new file mode 100644 index 000000000..c01332629 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/uploader/runningdevicewidget.ui @@ -0,0 +1,146 @@ + + + runningDeviceWidget + + + + 0 + 0 + 516 + 299 + + + + Form + + + + + + Device Information + + + + + + + 160 + 160 + + + + background: transparent + + + QFrame::NoFrame + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + CPU Serial: + + + + + + + true + + + + + + + + + + + + + + Firmware Information + + + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + TextLabel + + + + + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/uploader/uploader.pro b/ground/openpilotgcs/src/plugins/uploader/uploader.pro index fac544066..05742868d 100755 --- a/ground/openpilotgcs/src/plugins/uploader/uploader.pro +++ b/ground/openpilotgcs/src/plugins/uploader/uploader.pro @@ -6,6 +6,7 @@ include(../../plugins/coreplugin/coreplugin.pri) include(../../plugins/uavobjects/uavobjects.pri) include(../../plugins/uavtalk/uavtalk.pri) include(../../plugins/rawhid/rawhid.pri) +include(../../plugins/uavobjectutil/uavobjectutil.pri) INCLUDEPATH += ../../libs/qextserialport/src HEADERS += uploadergadget.h \ @@ -20,7 +21,8 @@ HEADERS += uploadergadget.h \ SSP/port.h \ SSP/qssp.h \ SSP/qsspt.h \ - SSP/common.h + SSP/common.h \ + runningdevicewidget.h SOURCES += uploadergadget.cpp \ uploadergadgetconfiguration.cpp \ uploadergadgetfactory.cpp \ @@ -32,12 +34,14 @@ SOURCES += uploadergadget.cpp \ devicewidget.cpp \ SSP/port.cpp \ SSP/qssp.cpp \ - SSP/qsspt.cpp + SSP/qsspt.cpp \ + runningdevicewidget.cpp OTHER_FILES += Uploader.pluginspec FORMS += \ uploader.ui \ - devicewidget.ui + devicewidget.ui \ + runningdevicewidget.ui RESOURCES += \ uploader.qrc diff --git a/ground/openpilotgcs/src/plugins/uploader/uploader.qrc b/ground/openpilotgcs/src/plugins/uploader/uploader.qrc index c4dd1b347..7d2677927 100644 --- a/ground/openpilotgcs/src/plugins/uploader/uploader.qrc +++ b/ground/openpilotgcs/src/plugins/uploader/uploader.qrc @@ -9,5 +9,8 @@ images/deviceID-0301.svg images/deviceID-0201.svg images/deviceID-0101.svg + images/application-certificate.svg + images/warning.svg + images/error.svg diff --git a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetfactory.cpp b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetfactory.cpp index 4099b936b..692985e5c 100755 --- a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetfactory.cpp +++ b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetfactory.cpp @@ -33,7 +33,7 @@ #include UploaderGadgetFactory::UploaderGadgetFactory(QObject *parent) : - IUAVGadgetFactory(QString("Uploader"), tr("Uploader Gadget"), parent) + IUAVGadgetFactory(QString("Uploader"), tr("Uploader"), parent) { } @@ -52,8 +52,3 @@ IUAVGadgetConfiguration *UploaderGadgetFactory::createConfiguration(QSettings* q return new UploaderGadgetConfiguration(QString("Uploader"), qSettings); } -IOptionsPage *UploaderGadgetFactory::createOptionsPage(IUAVGadgetConfiguration *config) -{ - return new UploaderGadgetOptionsPage(qobject_cast(config)); -} - diff --git a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetfactory.h b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetfactory.h index fb44be6cc..c836287b1 100755 --- a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetfactory.h +++ b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetfactory.h @@ -46,7 +46,6 @@ public: Core::IUAVGadget *createGadget(QWidget *parent); IUAVGadgetConfiguration *createConfiguration(QSettings* qSettings); - IOptionsPage *createOptionsPage(IUAVGadgetConfiguration *config); }; #endif // UPLOADERGADGETFACTORY_H diff --git a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp index dcbbb8fbd..397533c2b 100755 --- a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp @@ -33,9 +33,10 @@ UploaderGadgetWidget::UploaderGadgetWidget(QWidget *parent) : QWidget(parent) m_config = new Ui_UploaderWidget(); m_config->setupUi(this); currentStep = IAP_STATE_READY; - rescueStep = RESCUE_STEP0; resetOnly=false; dfu = NULL; + m_timer = 0; + m_progress = 0; // Listen to autopilot connection events ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); @@ -115,6 +116,18 @@ void UploaderGadgetWidget::onAutopilotConnect(){ m_config->bootButton->setEnabled(false); m_config->rescueButton->setEnabled(false); m_config->telemetryLink->setEnabled(false); + + // Add a very simple widget with Board model & serial number + // Delete all previous tabs: + while (m_config->systemElements->count()) { + QWidget *qw = m_config->systemElements->widget(0); + m_config->systemElements->removeTab(0); + delete qw; + } + runningDeviceWidget* dw = new runningDeviceWidget(this); + dw->populate(); + m_config->systemElements->addTab(dw, QString("Connected Device")); + } /** @@ -149,6 +162,7 @@ void UploaderGadgetWidget::goToBootloader(UAVObject* callerObj, bool success) switch (currentStep) { case IAP_STATE_READY: + m_config->haltButton->setEnabled(false); getSerialPorts(); // Useful in case a new serial port appeared since the initial list, // otherwise we won't find it when we stop the board. // The board is running, send the 1st IAP Reset order: @@ -167,6 +181,7 @@ void UploaderGadgetWidget::goToBootloader(UAVObject* callerObj, bool success) log("Reset did NOT happen"); currentStep = IAP_STATE_READY; disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject*,bool)),this,SLOT(goToBootloader(UAVObject*, bool))); + m_config->haltButton->setEnabled(true); break; } delay::msleep(600); @@ -181,6 +196,7 @@ void UploaderGadgetWidget::goToBootloader(UAVObject* callerObj, bool success) log("Reset did NOT happen"); currentStep = IAP_STATE_READY; disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject*,bool)),this,SLOT(goToBootloader(UAVObject*, bool))); + m_config->haltButton->setEnabled(true); break; } delay::msleep(600); @@ -196,6 +212,7 @@ void UploaderGadgetWidget::goToBootloader(UAVObject* callerObj, bool success) log("Oops, failure step 3"); log("Reset did NOT happen"); disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject*,bool)),this,SLOT(goToBootloader(UAVObject*, bool))); + m_config->haltButton->setEnabled(true); break; } @@ -235,6 +252,7 @@ void UploaderGadgetWidget::goToBootloader(UAVObject* callerObj, bool success) cm->resumePolling(); currentStep = IAP_STATE_READY; m_config->boardStatus->setText("Bootloader?"); + m_config->haltButton->setEnabled(true); return; } dfu->AbortOperation(); @@ -274,7 +292,10 @@ void UploaderGadgetWidget::goToBootloader(UAVObject* callerObj, bool success) /* m_config->haltButton->setEnabled(false); m_config->resetButton->setEnabled(false); + */ + // Need to re-enable in case we were not connected m_config->bootButton->setEnabled(true); + /* m_config->telemetryLink->setEnabled(false); m_config->rescueButton->setEnabled(false); */ @@ -342,13 +363,13 @@ void UploaderGadgetWidget::systemBoot() delete dfu; dfu = NULL; m_config->bootButton->setEnabled(true); + m_config->rescueButton->setEnabled(true); // Boot not possible, maybe Rescue OK? return; } log("Booting system..."); dfu->JumpToApp(); // Restart the polling thread cm->resumePolling(); - m_config->bootButton->setEnabled(true); m_config->rescueButton->setEnabled(true); m_config->telemetryLink->setEnabled(true); m_config->boardStatus->setText("Running"); @@ -373,89 +394,93 @@ void UploaderGadgetWidget::systemBoot() void UploaderGadgetWidget::systemRescue() { Core::ConnectionManager *cm = Core::ICore::instance()->connectionManager(); - switch (rescueStep) { - case RESCUE_STEP0: { - cm->disconnectDevice(); - // stop the polling thread: otherwise it will mess up DFU - cm->suspendPolling(); - // Delete all previous tabs: - while (m_config->systemElements->count()) { - QWidget *qw = m_config->systemElements->widget(0); - m_config->systemElements->removeTab(0); - delete qw; - } - // Existing DFU objects will have a handle over USB and will - // disturb everything for the rescue process: - if (dfu) { - delete dfu; - dfu = NULL; - } - // Avoid dumb users pressing Rescue twice. It can happen. - m_config->rescueButton->setEnabled(false); - - // Now we're good to go: - clearLog(); - log("**********************************************************"); - log("** Follow those instructions to attempt a system rescue **"); - log("**********************************************************"); - log("You will be prompted to first connect USB, then system power"); - log ("Connect USB in 2 seconds..."); - rescueStep = RESCUE_STEP1; - QTimer::singleShot(1000, this, SLOT(systemRescue())); + cm->disconnectDevice(); + // stop the polling thread: otherwise it will mess up DFU + cm->suspendPolling(); + // Delete all previous tabs: + while (m_config->systemElements->count()) { + QWidget *qw = m_config->systemElements->widget(0); + m_config->systemElements->removeTab(0); + delete qw; } - break; - case RESCUE_STEP1: - rescueStep = RESCUE_STEP2; - log (" ...1..."); - QTimer::singleShot(1000, this, SLOT(systemRescue())); - break; - case RESCUE_STEP2: - rescueStep = RESCUE_STEP3; - log(" ...Now!"); - QTimer::singleShot(1000, this, SLOT(systemRescue())); - break; - case RESCUE_STEP3: - log("... Detecting First Board..."); - repaint(); - dfu = new DFUObject(DFU_DEBUG, false, QString()); - dfu->AbortOperation(); - if(!dfu->enterDFU(0)) + // Existing DFU objects will have a handle over USB and will + // disturb everything for the rescue process: + if (dfu) { + delete dfu; + dfu = NULL; + } + // Avoid dumb users pressing Rescue twice. It can happen. + m_config->rescueButton->setEnabled(false); + + // Now we're good to go: + clearLog(); + log("**********************************************************"); + log("** Follow those instructions to attempt a system rescue **"); + log("**********************************************************"); + log("You will be prompted to first connect USB, then system power"); + if(USBMonitor::instance()->availableDevices(0x20a0,-1,-1,-1).length()>0) + { + if(QMessageBox::warning(this,tr("OpenPilot Uploader"),tr("Please disconnect all openpilot boards"),QMessageBox::Ok,QMessageBox::Cancel)==QMessageBox::Cancel) { - rescueStep = RESCUE_STEP0; - log("Could not enter DFU mode."); - delete dfu; - dfu = NULL; - cm->resumePolling(); m_config->rescueButton->setEnabled(true); return; } - if(!dfu->findDevices() || (dfu->numberOfDevices != 1)) - { - rescueStep = RESCUE_STEP0; - log("Could not detect a board, aborting!"); - delete dfu; - dfu = NULL; - cm->resumePolling(); - m_config->rescueButton->setEnabled(true); - return; - } - rescueStep = RESCUE_POWER1; - log("Connect Power in 2 second..."); - log("(not required on CopterControl)"); - QTimer::singleShot(1000, this, SLOT(systemRescue())); - break; - case RESCUE_POWER1: - rescueStep = RESCUE_POWER2; - log(" ...1..."); - QTimer::singleShot(1000, this, SLOT(systemRescue())); - break; - case RESCUE_POWER2: - log("... NOW!\n***\nWaiting..."); - rescueStep = RESCUE_DETECT; - QTimer::singleShot(5000, this, SLOT(systemRescue())); - break; - case RESCUE_DETECT: - rescueStep = RESCUE_STEP0; + } + // Now we're good to go: + clearLog(); + log("**********************************************************"); + log("** Follow those instructions to attempt a system rescue **"); + log("**********************************************************"); + log("You will be prompted to first connect USB, then system power"); + m_progress = new QProgressDialog(tr("Please connect the board (USB only!)"), tr("Cancel"), 0, 20); + QProgressBar * bar=new QProgressBar(m_progress); + bar->setFormat("Timeout"); + m_progress->setBar(bar); + m_progress->setMinimumDuration(0); + m_progress->setRange(0,20); + connect(m_progress, SIGNAL(canceled()), this, SLOT(cancel())); + m_timer = new QTimer(this); + connect(m_timer, SIGNAL(timeout()), this, SLOT(perform())); + m_timer->start(1000); + connect(USBMonitor::instance(), SIGNAL(deviceDiscovered(USBPortInfo)),&m_eventloop, SLOT(quit())); + m_eventloop.exec(); + if(!m_timer->isActive()) + { + m_progress->close(); + m_timer->stop(); + QMessageBox::warning(this,tr("Openpilot Uploader"),tr("No board connection was detected!")); + m_config->rescueButton->setEnabled(true); + return; + } + m_progress->close(); + m_timer->stop(); + log("... Detecting First Board..."); + repaint(); + dfu = new DFUObject(DFU_DEBUG, false, QString()); + dfu->AbortOperation(); + if(!dfu->enterDFU(0)) + { + log("Could not enter DFU mode."); + delete dfu; + dfu = NULL; + cm->resumePolling(); + m_config->rescueButton->setEnabled(true); + return; + } + if(!dfu->findDevices() || (dfu->numberOfDevices != 1)) + { + log("Could not detect a board, aborting!"); + delete dfu; + dfu = NULL; + cm->resumePolling(); + m_config->rescueButton->setEnabled(true); + return; + } + if(QMessageBox::question(this,tr("OpenPilot Uploader"),tr("If you want to search for other boards connect power now and press Yes"),QMessageBox::Yes,QMessageBox::No)==QMessageBox::Yes) + { + log("\nWaiting..."); + QTimer::singleShot(3000, &m_eventloop, SLOT(quit())); + m_eventloop.exec(); log("Detecting second board..."); repaint(); if(!dfu->findDevices()) @@ -469,28 +494,42 @@ void UploaderGadgetWidget::systemRescue() m_config->rescueButton->setEnabled(true); return; } - log(QString("Found ") + QString::number(dfu->numberOfDevices) + QString(" device(s).")); - if (dfu->numberOfDevices > 5) { - log("Inconsistent number of devices, aborting!"); - delete dfu; - dfu = NULL; - cm->resumePolling(); - m_config->rescueButton->setEnabled(true); - return; - } - for(int i=0;inumberOfDevices;i++) { - deviceWidget* dw = new deviceWidget(this); - dw->setDeviceID(i); - dw->setDfu(dfu); - dw->populate(); - m_config->systemElements->addTab(dw, QString("Device") + QString::number(i)); - } - m_config->haltButton->setEnabled(false); - m_config->resetButton->setEnabled(false); - //m_config->bootButton->setEnabled(true); - m_config->rescueButton->setEnabled(false); - currentStep = IAP_STATE_BOOTLOADER; // So that we can boot from the GUI afterwards. } + log(QString("Found ") + QString::number(dfu->numberOfDevices) + QString(" device(s).")); + if (dfu->numberOfDevices > 5) { + log("Inconsistent number of devices, aborting!"); + delete dfu; + dfu = NULL; + cm->resumePolling(); + m_config->rescueButton->setEnabled(true); + return; + } + for(int i=0;inumberOfDevices;i++) { + deviceWidget* dw = new deviceWidget(this); + dw->setDeviceID(i); + dw->setDfu(dfu); + dw->populate(); + m_config->systemElements->addTab(dw, QString("Device") + QString::number(i)); + } + m_config->haltButton->setEnabled(false); + m_config->resetButton->setEnabled(false); + m_config->bootButton->setEnabled(true); + m_config->rescueButton->setEnabled(false); + currentStep = IAP_STATE_BOOTLOADER; // So that we can boot from the GUI afterwards. +} +void UploaderGadgetWidget::perform() +{ + if(m_progress->value()==19) + { + m_timer->stop(); + m_eventloop.exit(); + } + m_progress->setValue(m_progress->value()+1); +} +void UploaderGadgetWidget::cancel() +{ + m_timer->stop(); + m_eventloop.exit(); } /** @@ -517,6 +556,15 @@ UploaderGadgetWidget::~UploaderGadgetWidget() QWidget *qw = m_config->systemElements->widget(0); m_config->systemElements->removeTab(0); delete qw; + qw = 0; + } + if (m_progress) { + delete m_progress; + m_progress = 0; + } + if (m_timer) { + delete m_timer; + m_timer = 0; } } diff --git a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.h b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.h index c0274668b..075dc18a0 100755 --- a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.h +++ b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.h @@ -31,6 +31,7 @@ #include "ui_uploader.h" #include "delay.h" #include "devicewidget.h" +#include "runningdevicewidget.h" #include "op_dfu.h" #include #include @@ -51,19 +52,21 @@ #include #include #include - +#include "devicedescriptorstruct.h" +#include using namespace OP_DFU; + class UploaderGadgetWidget : public QWidget { Q_OBJECT + public: UploaderGadgetWidget(QWidget *parent = 0); ~UploaderGadgetWidget(); typedef enum { IAP_STATE_READY, IAP_STATE_STEP_1, IAP_STATE_STEP_2, IAP_STEP_RESET, IAP_STATE_BOOTLOADER} IAPStep; - typedef enum { RESCUE_STEP0, RESCUE_STEP1, RESCUE_STEP2, RESCUE_STEP3, RESCUE_POWER1, RESCUE_POWER2, RESCUE_DETECT } RescueStep; void log(QString str); public slots: @@ -74,13 +77,13 @@ private: Ui_UploaderWidget *m_config; DFUObject *dfu; IAPStep currentStep; - RescueStep rescueStep; bool resetOnly; void clearLog(); QString getPortDevice(const QString &friendName); - + QProgressDialog* m_progress; + QTimer* m_timer; QLineEdit* openFileNameLE; - + QEventLoop m_eventloop; private slots: void error(QString errorString,int errorNumber); void info(QString infoString,int infoNumber); @@ -89,6 +92,8 @@ private slots: void systemBoot(); void systemRescue(); void getSerialPorts(); + void perform(); + void cancel(); }; diff --git a/ground/openpilotgcs/src/plugins/welcome/welcome.pri b/ground/openpilotgcs/src/plugins/welcome/welcome.pri index 2edd8a4df..41e3d85b1 100644 --- a/ground/openpilotgcs/src/plugins/welcome/welcome.pri +++ b/ground/openpilotgcs/src/plugins/welcome/welcome.pri @@ -1,3 +1,3 @@ include(welcome_dependencies.pri) -LIBS *= -l$$qtLibraryTarget(Welcome) +LIBS *= -l$$qtLibraryName(Welcome) diff --git a/ground/openpilotgcs/src/plugins/welcome/welcomemode.cpp b/ground/openpilotgcs/src/plugins/welcome/welcomemode.cpp index c5f67a5c8..8da08ba35 100644 --- a/ground/openpilotgcs/src/plugins/welcome/welcomemode.cpp +++ b/ground/openpilotgcs/src/plugins/welcome/welcomemode.cpp @@ -77,7 +77,8 @@ WelcomeModePrivate::WelcomeModePrivate() // --- WelcomeMode WelcomeMode::WelcomeMode() : - m_d(new WelcomeModePrivate) + m_d(new WelcomeModePrivate), + m_priority(Core::Constants::P_MODE_WELCOME) { m_d->m_widget = new QWidget; QVBoxLayout *l = new QVBoxLayout(m_d->m_widget); @@ -122,7 +123,7 @@ QIcon WelcomeMode::icon() const int WelcomeMode::priority() const { - return Core::Constants::P_MODE_WELCOME; + return m_priority; } QWidget* WelcomeMode::widget() diff --git a/ground/openpilotgcs/src/plugins/welcome/welcomemode.h b/ground/openpilotgcs/src/plugins/welcome/welcomemode.h index 8898e7cee..33c6a1ab5 100644 --- a/ground/openpilotgcs/src/plugins/welcome/welcomemode.h +++ b/ground/openpilotgcs/src/plugins/welcome/welcomemode.h @@ -61,6 +61,7 @@ public: void activated(); QString contextHelpId() const { return QLatin1String("OpenPilot GCS"); } void initPlugins(); + void setPriority(int priority) { m_priority = priority; } private slots: void slotFeedback(); @@ -69,6 +70,7 @@ private slots: private: WelcomeModePrivate *m_d; + int m_priority; }; } // namespace Welcome diff --git a/ground/openpilotgcs/src/rpath.pri b/ground/openpilotgcs/src/rpath.pri index 6d769360e..693d0e908 100644 --- a/ground/openpilotgcs/src/rpath.pri +++ b/ground/openpilotgcs/src/rpath.pri @@ -1,5 +1,5 @@ macx { - QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../PlugIns/ + QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../Plugins/ } else:linux-* { #do the rpath by hand since it's not possible to use ORIGIN in QMAKE_RPATHDIR # this expands to $ORIGIN (after qmake and make), it does NOT read a qmake var diff --git a/ground/uavobjgenerator/generators/flight/uavobjectgeneratorflight.cpp b/ground/uavobjgenerator/generators/flight/uavobjectgeneratorflight.cpp index 400a8fa00..3d9fd12b6 100644 --- a/ground/uavobjgenerator/generators/flight/uavobjectgeneratorflight.cpp +++ b/ground/uavobjgenerator/generators/flight/uavobjectgeneratorflight.cpp @@ -34,6 +34,7 @@ bool UAVObjectGeneratorFlight::generate(UAVObjectParser* parser,QString template <<"uint16_t" << "uint32_t" << "float" << "uint8_t"; QString flightObjInit,objInc,objFileNames,objNames; + qint32 sizeCalc; flightCodePath = QDir( templatepath + QString("flight/UAVObjects")); flightOutputPath = QDir( outputpath + QString("flight") ); flightOutputPath.mkpath(flightOutputPath.absolutePath()); @@ -41,6 +42,7 @@ bool UAVObjectGeneratorFlight::generate(UAVObjectParser* parser,QString template flightCodeTemplate = readFile( flightCodePath.absoluteFilePath("uavobjecttemplate.c") ); flightIncludeTemplate = readFile( flightCodePath.absoluteFilePath("inc/uavobjecttemplate.h") ); flightInitTemplate = readFile( flightCodePath.absoluteFilePath("uavobjectsinittemplate.c") ); + flightInitIncludeTemplate = readFile( flightCodePath.absoluteFilePath("inc/uavobjectsinittemplate.h") ); flightMakeTemplate = readFile( flightCodePath.absoluteFilePath("Makefiletemplate.inc") ); if ( flightCodeTemplate.isNull() || flightIncludeTemplate.isNull() || flightInitTemplate.isNull()) { @@ -48,6 +50,7 @@ bool UAVObjectGeneratorFlight::generate(UAVObjectParser* parser,QString template return false; } + sizeCalc = 0; for (int objidx = 0; objidx < parser->getNumObjects(); ++objidx) { ObjectInfo* info=parser->getObjectByIndex(objidx); process_object(info); @@ -57,6 +60,9 @@ bool UAVObjectGeneratorFlight::generate(UAVObjectParser* parser,QString template objInc.append("#include \"" + info->namelc + ".h\"\r\n"); objFileNames.append(" " + info->namelc); objNames.append(" " + info->name); + if (parser->getNumBytes(objidx)>sizeCalc) { + sizeCalc = parser->getNumBytes(objidx); + } } // Write the flight object inialization files @@ -65,7 +71,16 @@ bool UAVObjectGeneratorFlight::generate(UAVObjectParser* parser,QString template bool res = writeFileIfDiffrent( flightOutputPath.absolutePath() + "/uavobjectsinit.c", flightInitTemplate ); if (!res) { - cout << "Error: Could not write flight object init files" << endl; + cout << "Error: Could not write flight object init file" << endl; + return false; + } + + // Write the flight object initialization header + flightInitIncludeTemplate.replace( QString("$(SIZECALCULATION)"), QString().setNum(sizeCalc)); + res = writeFileIfDiffrent( flightOutputPath.absolutePath() + "/uavobjectsinit.h", + flightInitIncludeTemplate ); + if (!res) { + cout << "Error: Could not write flight object init header file" << endl; return false; } @@ -237,6 +252,96 @@ bool UAVObjectGeneratorFlight::process_object(ObjectInfo* info) } outCode.replace(QString("$(INITFIELDS)"), initfields); + // Replace the $(SETGETFIELDS) tag + QString setgetfields; + for (int n = 0; n < info->fields.length(); ++n) + { + //if (!info->fields[n]->defaultValues.isEmpty() ) + { + // For non-array fields + if ( info->fields[n]->numElements == 1) + { + + /* Set */ + setgetfields.append( QString("void %2%3Set( %1 *New%3 )\r\n") + .arg( fieldTypeStrC[info->fields[n]->type] ) + .arg( info->name ) + .arg( info->fields[n]->name ) ); + setgetfields.append( QString("{\r\n") ); + setgetfields.append( QString("\tUAVObjSetDataField(%1Handle(), (void*)New%2, offsetof( %1Data, %2), sizeof(%3));\r\n") + .arg( info->name ) + .arg( info->fields[n]->name ) + .arg( fieldTypeStrC[info->fields[n]->type] ) ); + setgetfields.append( QString("}\r\n") ); + + /* GET */ + setgetfields.append( QString("void %2%3Get( %1 *New%3 )\r\n") + .arg( fieldTypeStrC[info->fields[n]->type] ) + .arg( info->name ) + .arg( info->fields[n]->name )); + setgetfields.append( QString("{\r\n") ); + setgetfields.append( QString("\tUAVObjGetDataField(%1Handle(), (void*)New%2, offsetof( %1Data, %2), sizeof(%3));\r\n") + .arg( info->name ) + .arg( info->fields[n]->name ) + .arg( fieldTypeStrC[info->fields[n]->type] ) ); + setgetfields.append( QString("}\r\n") ); + + } + else + { + + /* SET */ + setgetfields.append( QString("void %2%3Set( %1 *New%3 )\r\n") + .arg( fieldTypeStrC[info->fields[n]->type] ) + .arg( info->name ) + .arg( info->fields[n]->name ) ); + setgetfields.append( QString("{\r\n") ); + setgetfields.append( QString("\tUAVObjSetDataField(%1Handle(), (void*)New%2, offsetof( %1Data, %2), %3*sizeof(%4));\r\n") + .arg( info->name ) + .arg( info->fields[n]->name ) + .arg( info->fields[n]->numElements ) + .arg( fieldTypeStrC[info->fields[n]->type] ) ); + setgetfields.append( QString("}\r\n") ); + + /* GET */ + setgetfields.append( QString("void %2%3Get( %1 *New%3 )\r\n") + .arg( fieldTypeStrC[info->fields[n]->type] ) + .arg( info->name ) + .arg( info->fields[n]->name ) ); + setgetfields.append( QString("{\r\n") ); + setgetfields.append( QString("\tUAVObjGetDataField(%1Handle(), (void*)New%2, offsetof( %1Data, %2), %3*sizeof(%4));\r\n") + .arg( info->name ) + .arg( info->fields[n]->name ) + .arg( info->fields[n]->numElements ) + .arg( fieldTypeStrC[info->fields[n]->type] ) ); + setgetfields.append( QString("}\r\n") ); + } + } + } + outCode.replace(QString("$(SETGETFIELDS)"), setgetfields); + + // Replace the $(SETGETFIELDSEXTERN) tag + QString setgetfieldsextern; + for (int n = 0; n < info->fields.length(); ++n) + { + //if (!info->fields[n]->defaultValues.isEmpty() ) + { + + /* SET */ + setgetfieldsextern.append( QString("extern void %2%3Set( %1 *New%3 );\r\n") + .arg( fieldTypeStrC[info->fields[n]->type] ) + .arg( info->name ) + .arg( info->fields[n]->name ) ); + + /* GET */ + setgetfieldsextern.append( QString("extern void %2%3Get( %1 *New%3 );\r\n") + .arg( fieldTypeStrC[info->fields[n]->type] ) + .arg( info->name ) + .arg( info->fields[n]->name ) ); + } + } + outInclude.replace(QString("$(SETGETFIELDSEXTERN)"), setgetfieldsextern); + // Write the flight code bool res = writeFileIfDiffrent( flightOutputPath.absolutePath() + "/" + info->namelc + ".c", outCode ); if (!res) { diff --git a/ground/uavobjgenerator/generators/flight/uavobjectgeneratorflight.h b/ground/uavobjgenerator/generators/flight/uavobjectgeneratorflight.h index 1050b2943..db728374b 100644 --- a/ground/uavobjgenerator/generators/flight/uavobjectgeneratorflight.h +++ b/ground/uavobjgenerator/generators/flight/uavobjectgeneratorflight.h @@ -34,7 +34,7 @@ class UAVObjectGeneratorFlight public: bool generate(UAVObjectParser* gen,QString templatepath,QString outputpath); QStringList fieldTypeStrC; - QString flightCodeTemplate, flightIncludeTemplate, flightInitTemplate, flightMakeTemplate; + QString flightCodeTemplate, flightIncludeTemplate, flightInitTemplate, flightInitIncludeTemplate, flightMakeTemplate; QDir flightCodePath; QDir flightOutputPath; diff --git a/ground/uavobjgenerator/uavobjectparser.cpp b/ground/uavobjgenerator/uavobjectparser.cpp index 149520cbf..cba02f8ee 100644 --- a/ground/uavobjgenerator/uavobjectparser.cpp +++ b/ground/uavobjgenerator/uavobjectparser.cpp @@ -43,7 +43,7 @@ UAVObjectParser::UAVObjectParser() int(4) << int(1); accessModeStrXML << "readwrite" << "readonly"; - + } /** @@ -228,7 +228,7 @@ QString UAVObjectParser::parseXML(QString& xml, QString& filename) node = node.nextSibling(); } - all_units.removeDuplicates(); + all_units.removeDuplicates(); // Done, return null string return QString(); } @@ -237,6 +237,7 @@ QString UAVObjectParser::parseXML(QString& xml, QString& filename) * Calculate the unique object ID based on the object information. * The ID will change if the object definition changes, this is intentional * and is used to avoid connecting objects with incompatible configurations. + * The LSB is set to zero and is reserved for metadata */ void UAVObjectParser::calculateID(ObjectInfo* info) { @@ -250,9 +251,14 @@ void UAVObjectParser::calculateID(ObjectInfo* info) hash = updateHash(info->fields[n]->name, hash); hash = updateHash(info->fields[n]->numElements, hash); hash = updateHash(info->fields[n]->type, hash); + if(info->fields[n]->type == FIELDTYPE_ENUM) { + QStringList options = info->fields[n]->options; + for (int m = 0; m < options.length(); m++) + hash = updateHash(options[m], hash); + } } // Done - info->id = hash; + info->id = hash & 0xFFFFFFFE; } /** @@ -263,7 +269,7 @@ void UAVObjectParser::calculateID(ObjectInfo* info) */ quint32 UAVObjectParser::updateHash(quint32 value, quint32 hash) { - return (hash ^ ((hash<<5) + (hash>>2) + value)) & 0xFFFFFFFE; + return (hash ^ ((hash<<5) + (hash>>2) + value)); } /** @@ -376,7 +382,7 @@ QString UAVObjectParser::processObjectFields(QDomNode& childNode, ObjectInfo* in return QString("Object:field:units attribute is missing"); field->units = elemAttr.nodeValue(); - all_units << field->units; + all_units << field->units; // Get type attribute elemAttr = elemAttributes.namedItem("type"); @@ -384,14 +390,14 @@ QString UAVObjectParser::processObjectFields(QDomNode& childNode, ObjectInfo* in return QString("Object:field:type attribute is missing"); int index = fieldTypeStrXML.indexOf(elemAttr.nodeValue()); - if (index >= 0) { + if (index >= 0) { field->type = (FieldType)index; field->numBytes = fieldTypeNumBytes[index]; - } - else { + } + else { return QString("Object:field:type attribute value is invalid"); - } - + } + // Get numelements or elementnames attribute elemAttr = elemAttributes.namedItem("elementnames"); if ( !elemAttr.isNull() ) { diff --git a/hardware/Production/CC Spektrum Adapter/Assembly/Spektrum Adapter 3D Bottom.pdf b/hardware/Production/CC Spektrum Adapter/Assembly/Spektrum Adapter 3D Bottom.pdf new file mode 100644 index 000000000..c070f6433 Binary files /dev/null and b/hardware/Production/CC Spektrum Adapter/Assembly/Spektrum Adapter 3D Bottom.pdf differ diff --git a/hardware/Production/CC Spektrum Adapter/Assembly/Spektrum Adapter 3D Top.pdf b/hardware/Production/CC Spektrum Adapter/Assembly/Spektrum Adapter 3D Top.pdf new file mode 100644 index 000000000..f20a1c230 Binary files /dev/null and b/hardware/Production/CC Spektrum Adapter/Assembly/Spektrum Adapter 3D Top.pdf differ diff --git a/hardware/Production/CC Spektrum Adapter/Assembly/Spektrum Adapter Assembly.pdf b/hardware/Production/CC Spektrum Adapter/Assembly/Spektrum Adapter Assembly.pdf new file mode 100644 index 000000000..9ceef7d5b Binary files /dev/null and b/hardware/Production/CC Spektrum Adapter/Assembly/Spektrum Adapter Assembly.pdf differ diff --git a/hardware/Production/CC Spektrum Adapter/BOM/Spektrum Adapter BOM.xls b/hardware/Production/CC Spektrum Adapter/BOM/Spektrum Adapter BOM.xls new file mode 100644 index 000000000..546c66343 Binary files /dev/null and b/hardware/Production/CC Spektrum Adapter/BOM/Spektrum Adapter BOM.xls differ diff --git a/hardware/Production/CC Spektrum Adapter/Gerbers/Gerbers for Spektrum Adapter - outline inc.zip b/hardware/Production/CC Spektrum Adapter/Gerbers/Gerbers for Spektrum Adapter - outline inc.zip new file mode 100644 index 000000000..55504cf78 Binary files /dev/null and b/hardware/Production/CC Spektrum Adapter/Gerbers/Gerbers for Spektrum Adapter - outline inc.zip differ diff --git a/hardware/Production/CC Spektrum Adapter/Spektrum Adapter Schematic.pdf b/hardware/Production/CC Spektrum Adapter/Spektrum Adapter Schematic.pdf new file mode 100644 index 000000000..8438016fe Binary files /dev/null and b/hardware/Production/CC Spektrum Adapter/Spektrum Adapter Schematic.pdf differ diff --git a/hardware/Production/CC Spektrum Adapter/Spektrum Adapter.PcbDoc b/hardware/Production/CC Spektrum Adapter/Spektrum Adapter.PcbDoc new file mode 100644 index 000000000..b7abfdc41 Binary files /dev/null and b/hardware/Production/CC Spektrum Adapter/Spektrum Adapter.PcbDoc differ diff --git a/hardware/Production/CC Spektrum Adapter/Spektrum Adapter.PrjPCB b/hardware/Production/CC Spektrum Adapter/Spektrum Adapter.PrjPCB new file mode 100644 index 000000000..933d16783 --- /dev/null +++ b/hardware/Production/CC Spektrum Adapter/Spektrum Adapter.PrjPCB @@ -0,0 +1,890 @@ +[Design] +Version=1.0 +HierarchyMode=0 +ChannelRoomNamingStyle=0 +OutputPath=Project Outputs for Spektrum Adapter +LogFolderPath= +ChannelDesignatorFormatString=$Component_$RoomName +ChannelRoomLevelSeperator=_ +OpenOutputs=1 +ArchiveProject=0 +TimestampOutput=0 +SeparateFolders=0 +PinSwapBy_Netlabel=1 +PinSwapBy_Pin=1 +AllowPortNetNames=0 +AllowSheetEntryNetNames=1 +AppendSheetNumberToLocalNets=0 +NetlistSinglePinNets=0 +DefaultConfiguration= +UserID=0xFFFFFFFF +DefaultPcbProtel=1 +DefaultPcbPcad=0 +ReorderDocumentsOnCompile=1 +NameNetsHierarchically=0 +PowerPortNamesTakePriority=0 +PushECOToAnnotationFile=1 +DItemRevisionGUID= + +[Document1] +DocumentPath=..\Altium\OpenPilot.SchLib +AnnotationEnabled=1 +AnnotateStartValue=1 +AnnotationIndexControlEnabled=0 +AnnotateSuffix= +AnnotateScope=All +AnnotateOrder=-1 +DoLibraryUpdate=1 +DoDatabaseUpdate=1 +ClassGenCCAutoEnabled=1 +ClassGenCCAutoRoomEnabled=1 +ClassGenNCAutoScope=None +DItemRevisionGUID= + +[Document2] +DocumentPath=..\Altium\OpenPilot.PcbLib +AnnotationEnabled=1 +AnnotateStartValue=1 +AnnotationIndexControlEnabled=0 +AnnotateSuffix= +AnnotateScope=All +AnnotateOrder=-1 +DoLibraryUpdate=1 +DoDatabaseUpdate=1 +ClassGenCCAutoEnabled=1 +ClassGenCCAutoRoomEnabled=1 +ClassGenNCAutoScope=None +DItemRevisionGUID= + +[Document3] +DocumentPath=Spektrum Adapter.SchDoc +AnnotationEnabled=1 +AnnotateStartValue=1 +AnnotationIndexControlEnabled=0 +AnnotateSuffix= +AnnotateScope=All +AnnotateOrder=-1 +DoLibraryUpdate=1 +DoDatabaseUpdate=1 +ClassGenCCAutoEnabled=1 +ClassGenCCAutoRoomEnabled=0 +ClassGenNCAutoScope=None +DItemRevisionGUID= + +[Document4] +DocumentPath=Spektrum Adapter.PcbDoc +AnnotationEnabled=1 +AnnotateStartValue=1 +AnnotationIndexControlEnabled=0 +AnnotateSuffix= +AnnotateScope=All +AnnotateOrder=-1 +DoLibraryUpdate=1 +DoDatabaseUpdate=1 +ClassGenCCAutoEnabled=1 +ClassGenCCAutoRoomEnabled=1 +ClassGenNCAutoScope=None +DItemRevisionGUID= + +[OutputGroup1] +Name=Netlist Outputs +Description= +TargetPrinter=Microsoft XPS Document Writer +PrinterOptions=Record=PrinterOptions|Copies=1|Duplex=1|TrueTypeOptions=3|Collate=1|PrintWhat=1 +OutputType1=CadnetixNetlist +OutputName1=Cadnetix Netlist +OutputDocumentPath1= +OutputVariantName1= +OutputDefault1=0 +OutputType2=CalayNetlist +OutputName2=Calay Netlist +OutputDocumentPath2= +OutputVariantName2= +OutputDefault2=0 +OutputType3=EDIF +OutputName3=EDIF for PCB +OutputDocumentPath3= +OutputVariantName3= +OutputDefault3=0 +OutputType4=EESofNetlist +OutputName4=EESof Netlist +OutputDocumentPath4= +OutputVariantName4= +OutputDefault4=0 +OutputType5=IntergraphNetlist +OutputName5=Intergraph Netlist +OutputDocumentPath5= +OutputVariantName5= +OutputDefault5=0 +OutputType6=MentorBoardStationNetlist +OutputName6=Mentor BoardStation Netlist +OutputDocumentPath6= +OutputVariantName6= +OutputDefault6=0 +OutputType7=MultiWire +OutputName7=MultiWire +OutputDocumentPath7= +OutputVariantName7= +OutputDefault7=0 +OutputType8=OrCadPCB2Netlist +OutputName8=Orcad/PCB2 Netlist +OutputDocumentPath8= +OutputVariantName8= +OutputDefault8=0 +OutputType9=PADSNetlist +OutputName9=PADS ASCII Netlist +OutputDocumentPath9= +OutputVariantName9= +OutputDefault9=0 +OutputType10=Pcad +OutputName10=Pcad for PCB +OutputDocumentPath10= +OutputVariantName10= +OutputDefault10=0 +OutputType11=PCADNetlist +OutputName11=PCAD Netlist +OutputDocumentPath11= +OutputVariantName11= +OutputDefault11=0 +OutputType12=PCADnltNetlist +OutputName12=PCADnlt Netlist +OutputDocumentPath12= +OutputVariantName12= +OutputDefault12=0 +OutputType13=Protel2Netlist +OutputName13=Protel2 Netlist +OutputDocumentPath13= +OutputVariantName13= +OutputDefault13=0 +OutputType14=ProtelNetlist +OutputName14=Protel +OutputDocumentPath14= +OutputVariantName14= +OutputDefault14=0 +OutputType15=RacalNetlist +OutputName15=Racal Netlist +OutputDocumentPath15= +OutputVariantName15= +OutputDefault15=0 +OutputType16=RINFNetlist +OutputName16=RINF Netlist +OutputDocumentPath16= +OutputVariantName16= +OutputDefault16=0 +OutputType17=SciCardsNetlist +OutputName17=SciCards Netlist +OutputDocumentPath17= +OutputVariantName17= +OutputDefault17=0 +OutputType18=SIMetrixNetlist +OutputName18=SIMetrix +OutputDocumentPath18= +OutputVariantName18= +OutputDefault18=0 +OutputType19=SIMPLISNetlist +OutputName19=SIMPLIS +OutputDocumentPath19= +OutputVariantName19= +OutputDefault19=0 +OutputType20=TangoNetlist +OutputName20=Tango Netlist +OutputDocumentPath20= +OutputVariantName20= +OutputDefault20=0 +OutputType21=TelesisNetlist +OutputName21=Telesis Netlist +OutputDocumentPath21= +OutputVariantName21= +OutputDefault21=0 +OutputType22=Verilog +OutputName22=Verilog File +OutputDocumentPath22= +OutputVariantName22= +OutputDefault22=0 +OutputType23=VHDL +OutputName23=VHDL File +OutputDocumentPath23= +OutputVariantName23= +OutputDefault23=0 +OutputType24=WireListNetlist +OutputName24=WireList Netlist +OutputDocumentPath24= +OutputVariantName24= +OutputDefault24=0 +OutputType25=XSpiceNetlist +OutputName25=XSpice Netlist +OutputDocumentPath25= +OutputVariantName25= +OutputDefault25=0 + +[OutputGroup2] +Name=Simulator Outputs +Description= +TargetPrinter=Microsoft XPS Document Writer +PrinterOptions=Record=PrinterOptions|Copies=1|Duplex=1|TrueTypeOptions=3|Collate=1|PrintWhat=1 +OutputType1=AdvSimNetlist +OutputName1=Mixed Sim +OutputDocumentPath1= +OutputVariantName1= +OutputDefault1=0 +OutputType2=SIMetrix_Sim +OutputName2=SIMetrix +OutputDocumentPath2= +OutputVariantName2= +OutputDefault2=0 +OutputType3=SIMPLIS_Sim +OutputName3=SIMPLIS +OutputDocumentPath3= +OutputVariantName3= +OutputDefault3=0 + +[OutputGroup3] +Name=Documentation Outputs +Description= +TargetPrinter=Microsoft XPS Document Writer +PrinterOptions=Record=PrinterOptions|Copies=1|Duplex=1|TrueTypeOptions=3|Collate=1|PrintWhat=1 +OutputType1=Composite +OutputName1=Composite Drawing +OutputDocumentPath1= +OutputVariantName1= +OutputDefault1=0 +PageOptions1=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType2=Logic Analyser Print +OutputName2=Logic Analyser Prints +OutputDocumentPath2= +OutputVariantName2= +OutputDefault2=0 +PageOptions2=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType3=OpenBus Print +OutputName3=OpenBus Prints +OutputDocumentPath3= +OutputVariantName3= +OutputDefault3=0 +PageOptions3=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType4=PCB 3D Print +OutputName4=PCB 3D Prints +OutputDocumentPath4= +OutputVariantName4= +OutputDefault4=0 +PageOptions4=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType5=PCB Print +OutputName5=PCB Prints +OutputDocumentPath5= +OutputVariantName5= +OutputDefault5=0 +PageOptions5=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType6=Schematic Print +OutputName6=Schematic Prints +OutputDocumentPath6= +OutputVariantName6= +OutputDefault6=0 +PageOptions6=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType7=SimView Print +OutputName7=SimView Prints +OutputDocumentPath7= +OutputVariantName7= +OutputDefault7=0 +PageOptions7=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType8=Wave Print +OutputName8=Wave Prints +OutputDocumentPath8= +OutputVariantName8= +OutputDefault8=0 +PageOptions8=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType9=WaveSim Print +OutputName9=WaveSim Prints +OutputDocumentPath9= +OutputVariantName9= +OutputDefault9=0 +PageOptions9=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 + +[OutputGroup4] +Name=Assembly Outputs +Description= +TargetPrinter=Microsoft XPS Document Writer +PrinterOptions=Record=PrinterOptions|Copies=1|Duplex=1|TrueTypeOptions=3|Collate=1|PrintWhat=1 +OutputType1=Assembly +OutputName1=Assembly Drawings +OutputDocumentPath1= +OutputVariantName1= +OutputDefault1=0 +PageOptions1=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType2=Pick Place +OutputName2=Generates pick and place files +OutputDocumentPath2= +OutputVariantName2= +OutputDefault2=0 +OutputType3=Test Points For Assembly +OutputName3=Test Point Report +OutputDocumentPath3= +OutputVariantName3= +OutputDefault3=0 + +[OutputGroup5] +Name=Fabrication Outputs +Description= +TargetPrinter=Microsoft XPS Document Writer +PrinterOptions=Record=PrinterOptions|Copies=1|Duplex=1|TrueTypeOptions=3|Collate=1|PrintWhat=1 +OutputType1=ODB +OutputName1=ODB++ Files +OutputDocumentPath1= +OutputVariantName1= +OutputDefault1=0 +OutputType2=NC Drill +OutputName2=NC Drill Files +OutputDocumentPath2= +OutputVariantName2= +OutputDefault2=0 +Configuration2_Name1=OutputConfigurationParameter1 +Configuration2_Item1=BoardEdgeRoutToolDia=2000000|GenerateBoardEdgeRout=False|GenerateDrilledSlotsG85=False|GenerateSeparatePlatedNonPlatedFiles=False|NumberOfDecimals=5|NumberOfUnits=2|OptimizeChangeLocationCommands=True|OriginPosition=Relative|Record=DrillView|Units=Imperial|ZeroesMode=SuppressTrailingZeroes +OutputType3=Test Points +OutputName3=Test Point Report +OutputDocumentPath3= +OutputVariantName3= +OutputDefault3=0 +OutputType4=Plane +OutputName4=Power-Plane Prints +OutputDocumentPath4= +OutputVariantName4= +OutputDefault4=0 +PageOptions4=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType5=Mask +OutputName5=Solder/Paste Mask Prints +OutputDocumentPath5= +OutputVariantName5= +OutputDefault5=0 +PageOptions5=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType6=Drill +OutputName6=Drill Drawing/Guides +OutputDocumentPath6= +OutputVariantName6= +OutputDefault6=0 +PageOptions6=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType7=CompositeDrill +OutputName7=Composite Drill Drawing +OutputDocumentPath7= +OutputVariantName7= +OutputDefault7=0 +PageOptions7=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType8=Final +OutputName8=Final Artwork Prints +OutputDocumentPath8= +OutputVariantName8= +OutputDefault8=0 +PageOptions8=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType9=Gerber +OutputName9=Gerber Files +OutputDocumentPath9= +OutputVariantName9= +OutputDefault9=0 +Configuration9_Name1=OutputConfigurationParameter1 +Configuration9_Item1=AddToAllPlots.Set=SerializeLayerHash.Version~2,ClassName~TLayerToBoolean,16908293~1|CentrePlots=False|DrillDrawingSymbol=GraphicsSymbol|DrillDrawingSymbolSize=500000|EmbeddedApertures=True|FilmBorderSize=10000000|FilmXSize=200000000|FilmYSize=160000000|FlashAllFills=False|FlashPadShapes=True|G54OnApertureChange=False|GenerateDRCRulesFile=True|GenerateReliefShapes=True|GerberUnit=Imperial|IncludeUnconnectedMidLayerPads=False|LeadingAndTrailingZeroesMode=SuppressLeadingZeroes|MaxApertureSize=2500000|MinusApertureTolerance=50|Mirror.Set=SerializeLayerHash.Version~2,ClassName~TLayerToBoolean|MirrorDrillDrawingPlots=False|MirrorDrillGuidePlots=False|NumberOfDecimals=5|OptimizeChangeLocationCommands=True|OriginPosition=Relative|Panelize=False|Plot.Set=SerializeLayerHash.Version~2,ClassName~TLayerToBoolean,16973830~1,16973832~1,16973834~1,16777217~1,16842751~1,16973835~1,16973833~1,16973831~1,16973848~1,16973849~1|PlotPositivePlaneLayers=False|PlotUsedDrillDrawingLayerPairs=True|PlotUsedDrillGuideLayerPairs=True|PlusApertureTolerance=50|Record=GerberView|SoftwareArcs=False|Sorted=False + +[OutputGroup6] +Name=Report Outputs +Description= +TargetPrinter=Microsoft XPS Document Writer +PrinterOptions=Record=PrinterOptions|Copies=1|Duplex=1|TrueTypeOptions=3|Collate=1|PrintWhat=1 +OutputType1=BOM_PartType +OutputName1=Bill of Materials +OutputDocumentPath1= +OutputVariantName1= +OutputDefault1=0 +PageOptions1=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +Configuration1_Name1=Filter +Configuration1_Item1=545046300E5446696C74657257726170706572000D46696C7465722E416374697665090F46696C7465722E43726974657269610A04000000000000000000 +Configuration1_Name2=General +Configuration1_Item2=OpenExported=True|AddToProject=False|ForceFit=False|NotFitted=False|Database=False|IncludePCBData=False|ShowExportOptions=True|TemplateFilename=..\Altium\BOM OpenPilot.xlt|BatchMode=5|FormWidth=1226|FormHeight=598|SupplierProdQty=1|SupplierAutoQty=True|SupplierUseCachedPricing=False|SupplierCurrency= +Configuration1_Name3=GroupOrder +Configuration1_Item3=Comment=True|Footprint=True +Configuration1_Name4=OutputConfigurationParameter1 +Configuration1_Item4=Record=BOMPrintView|ShowNoERC=True|ShowParamSet=True|ShowProbe=True|ShowBlanket=True|ExpandDesignator=True|ExpandNetLabel=False|ExpandPort=False|ExpandSheetNum=False|ExpandDocNum=False +Configuration1_Name5=SortOrder +Configuration1_Item5=Designator=Up|Comment=Up|Footprint=Up +Configuration1_Name6=VisibleOrder +Configuration1_Item6=Comment=100|Description=100|Designator=100|Value=100|Footprint=100|LibRef=100|Quantity=100|Supplier 1=100|Supplier Part Number 1=100|Supplier Stock 1=100|Supplier Unit Price 1=100|Supplier Order Qty 1=100|Supplier Subtotal 1=100|Manufacturer 1=100|Manufacturer Part Number 1=100 +OutputType2=ComponentCrossReference +OutputName2=Component Cross Reference Report +OutputDocumentPath2= +OutputVariantName2= +OutputDefault2=0 +OutputType3=Design Rules Check +OutputName3=Design Rules Check +OutputDocumentPath3= +OutputVariantName3= +OutputDefault3=0 +PageOptions3=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType4=Electrical Rules Check +OutputName4=Electrical Rules Check +OutputDocumentPath4= +OutputVariantName4= +OutputDefault4=0 +PageOptions4=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType5=ReportHierarchy +OutputName5=Report Project Hierarchy +OutputDocumentPath5= +OutputVariantName5= +OutputDefault5=0 +OutputType6=Script +OutputName6=Script Output +OutputDocumentPath6= +OutputVariantName6= +OutputDefault6=0 +OutputType7=SimpleBOM +OutputName7=Simple BOM +OutputDocumentPath7= +OutputVariantName7= +OutputDefault7=0 +OutputType8=SinglePinNetReporter +OutputName8=Report Single Pin Nets +OutputDocumentPath8= +OutputVariantName8= +OutputDefault8=0 + +[OutputGroup7] +Name=Other Outputs +Description= +TargetPrinter=Microsoft XPS Document Writer +PrinterOptions=Record=PrinterOptions|Copies=1|Duplex=1|TrueTypeOptions=3|Collate=1|PrintWhat=1 +OutputType1=Text Print +OutputName1=Text Print +OutputDocumentPath1= +OutputVariantName1= +OutputDefault1=0 +PageOptions1=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType2=Text Print +OutputName2=Text Print +OutputDocumentPath2= +OutputVariantName2= +OutputDefault2=0 +PageOptions2=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType3=Text Print +OutputName3=Text Print +OutputDocumentPath3= +OutputVariantName3= +OutputDefault3=0 +PageOptions3=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType4=Text Print +OutputName4=Text Print +OutputDocumentPath4= +OutputVariantName4= +OutputDefault4=0 +PageOptions4=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType5=Text Print +OutputName5=Text Print +OutputDocumentPath5= +OutputVariantName5= +OutputDefault5=0 +PageOptions5=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType6=Text Print +OutputName6=Text Print +OutputDocumentPath6= +OutputVariantName6= +OutputDefault6=0 +PageOptions6=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType7=Text Print +OutputName7=Text Print +OutputDocumentPath7= +OutputVariantName7= +OutputDefault7=0 +PageOptions7=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType8=Text Print +OutputName8=Text Print +OutputDocumentPath8= +OutputVariantName8= +OutputDefault8=0 +PageOptions8=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType9=Text Print +OutputName9=Text Print +OutputDocumentPath9= +OutputVariantName9= +OutputDefault9=0 +PageOptions9=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType10=Text Print +OutputName10=Text Print +OutputDocumentPath10= +OutputVariantName10= +OutputDefault10=0 +PageOptions10=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType11=Text Print +OutputName11=Text Print +OutputDocumentPath11= +OutputVariantName11= +OutputDefault11=0 +PageOptions11=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType12=Text Print +OutputName12=Text Print +OutputDocumentPath12= +OutputVariantName12= +OutputDefault12=0 +PageOptions12=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType13=Text Print +OutputName13=Text Print +OutputDocumentPath13= +OutputVariantName13= +OutputDefault13=0 +PageOptions13=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType14=Text Print +OutputName14=Text Print +OutputDocumentPath14= +OutputVariantName14= +OutputDefault14=0 +PageOptions14=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType15=Text Print +OutputName15=Text Print +OutputDocumentPath15= +OutputVariantName15= +OutputDefault15=0 +PageOptions15=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType16=Text Print +OutputName16=Text Print +OutputDocumentPath16= +OutputVariantName16= +OutputDefault16=0 +PageOptions16=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType17=Text Print +OutputName17=Text Print +OutputDocumentPath17= +OutputVariantName17= +OutputDefault17=0 +PageOptions17=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType18=Text Print +OutputName18=Text Print +OutputDocumentPath18= +OutputVariantName18= +OutputDefault18=0 +PageOptions18=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType19=Text Print +OutputName19=Text Print +OutputDocumentPath19= +OutputVariantName19= +OutputDefault19=0 +PageOptions19=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType20=Text Print +OutputName20=Text Print +OutputDocumentPath20= +OutputVariantName20= +OutputDefault20=0 +PageOptions20=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType21=Text Print +OutputName21=Text Print +OutputDocumentPath21= +OutputVariantName21= +OutputDefault21=0 +PageOptions21=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType22=Text Print +OutputName22=Text Print +OutputDocumentPath22= +OutputVariantName22= +OutputDefault22=0 +PageOptions22=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType23=Text Print +OutputName23=Text Print +OutputDocumentPath23= +OutputVariantName23= +OutputDefault23=0 +PageOptions23=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType24=Text Print +OutputName24=Text Print +OutputDocumentPath24= +OutputVariantName24= +OutputDefault24=0 +PageOptions24=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType25=Text Print +OutputName25=Text Print +OutputDocumentPath25= +OutputVariantName25= +OutputDefault25=0 +PageOptions25=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType26=Text Print +OutputName26=Text Print +OutputDocumentPath26= +OutputVariantName26= +OutputDefault26=0 +PageOptions26=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType27=Text Print +OutputName27=Text Print +OutputDocumentPath27= +OutputVariantName27= +OutputDefault27=0 +PageOptions27=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 +OutputType28=Text Print +OutputName28=Text Print +OutputDocumentPath28= +OutputVariantName28= +OutputDefault28=0 +PageOptions28=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 + +[Modification Levels] +Type1=1 +Type2=1 +Type3=1 +Type4=1 +Type5=1 +Type6=1 +Type7=1 +Type8=1 +Type9=1 +Type10=1 +Type11=1 +Type12=1 +Type13=1 +Type14=1 +Type15=1 +Type16=1 +Type17=1 +Type18=1 +Type19=1 +Type20=1 +Type21=1 +Type22=1 +Type23=1 +Type24=1 +Type25=1 +Type26=1 +Type27=1 +Type28=1 +Type29=1 +Type30=1 +Type31=1 +Type32=1 +Type33=1 +Type34=1 +Type35=1 +Type36=1 +Type37=1 +Type38=1 +Type39=1 +Type40=1 +Type41=1 +Type42=1 +Type43=1 +Type44=1 +Type45=1 +Type46=1 +Type47=1 +Type48=1 +Type49=1 +Type50=1 +Type51=1 +Type52=1 +Type53=1 +Type54=1 +Type55=1 +Type56=1 +Type57=1 +Type58=1 +Type59=1 +Type60=1 +Type61=1 +Type62=1 +Type63=1 +Type64=1 +Type65=1 +Type66=1 +Type67=1 +Type68=1 + +[Difference Levels] +Type1=1 +Type2=1 +Type3=1 +Type4=1 +Type5=1 +Type6=1 +Type7=1 +Type8=1 +Type9=1 +Type10=1 +Type11=1 +Type12=1 +Type13=1 +Type14=1 +Type15=1 +Type16=1 +Type17=1 +Type18=1 +Type19=1 +Type20=1 +Type21=1 +Type22=1 +Type23=1 +Type24=1 +Type25=1 +Type26=1 +Type27=1 +Type28=1 +Type29=1 +Type30=1 +Type31=1 +Type32=1 +Type33=1 +Type34=1 +Type35=1 +Type36=1 + +[Electrical Rules Check] +Type1=1 +Type2=1 +Type3=2 +Type4=1 +Type5=2 +Type6=2 +Type7=1 +Type8=1 +Type9=1 +Type10=1 +Type11=2 +Type12=2 +Type13=2 +Type14=1 +Type15=1 +Type16=1 +Type17=1 +Type18=1 +Type19=1 +Type20=1 +Type21=1 +Type22=1 +Type23=1 +Type24=1 +Type25=2 +Type26=2 +Type27=2 +Type28=1 +Type29=1 +Type30=1 +Type31=1 +Type32=2 +Type33=2 +Type34=2 +Type35=1 +Type36=2 +Type37=1 +Type38=2 +Type39=2 +Type40=2 +Type41=0 +Type42=2 +Type43=1 +Type44=1 +Type45=2 +Type46=1 +Type47=2 +Type48=2 +Type49=1 +Type50=2 +Type51=1 +Type52=1 +Type53=1 +Type54=1 +Type55=1 +Type56=2 +Type57=1 +Type58=1 +Type59=0 +Type60=1 +Type61=2 +Type62=2 +Type63=1 +Type64=0 +Type65=2 +Type66=3 +Type67=2 +Type68=2 +Type69=1 +Type70=2 +Type71=2 +Type72=2 +Type73=2 +Type74=1 +Type75=2 +Type76=1 +Type77=1 +Type78=1 +Type79=1 +Type80=2 +Type81=3 +Type82=3 +Type83=3 +Type84=3 +Type85=3 +Type86=2 +Type87=2 +Type88=2 +Type89=1 +Type90=1 +Type91=3 +Type92=3 +Type93=2 +Type94=2 +Type95=2 +Type96=2 +Type97=2 +Type98=0 + +[ERC Connection Matrix] +L1=NNNNNNNNNNNWNNNWW +L2=NNWNNNNWWWNWNWNWN +L3=NWEENEEEENEWNEEWN +L4=NNENNNWEENNWNENWN +L5=NNNNNNNNNNNNNNNNN +L6=NNENNNNEENNWNENWN +L7=NNEWNNWEENNWNENWN +L8=NWEENEENEEENNEENN +L9=NWEENEEEENEWNEEWW +L10=NWNNNNNENNEWNNEWN +L11=NNENNNNEEENWNENWN +L12=WWWWNWWNWWWNWWWNN +L13=NNNNNNNNNNNWNNNWW +L14=NWEENEEEENEWNEEWW +L15=NNENNNNEEENWNENWW +L16=WWWWNWWNWWWNWWWNW +L17=WNNNNNNNWNNNWWWWN + +[Annotate] +SortOrder=3 +MatchParameter1=Comment +MatchStrictly1=1 +MatchParameter2=Library Reference +MatchStrictly2=1 +PhysicalNamingFormat=$Component_$RoomName +GlobalIndexSortOrder=3 + +[PrjClassGen] +CompClassManualEnabled=0 +CompClassManualRoomEnabled=0 +NetClassAutoBusEnabled=1 +NetClassAutoCompEnabled=0 +NetClassAutoNamedHarnessEnabled=0 +NetClassManualEnabled=1 + +[LibraryUpdateOptions] +SelectedOnly=0 +PartTypes=0 +FullReplace=1 +UpdateDesignatorLock=1 +UpdatePartIDLock=1 +DoGraphics=1 +DoParameters=1 +DoModels=1 +AddParameters=0 +RemoveParameters=0 +AddModels=1 +RemoveModels=1 +UpdateCurrentModels=1 + +[DatabaseUpdateOptions] +SelectedOnly=0 +PartTypes=0 + +[Comparison Options] +ComparisonOptions0=Kind=Net|MinPercent=75|MinMatch=3|ShowMatch=-1|Confirm=-1|UseName=-1|InclAllRules=0 +ComparisonOptions1=Kind=Net Class|MinPercent=75|MinMatch=3|ShowMatch=-1|Confirm=-1|UseName=-1|InclAllRules=0 +ComparisonOptions2=Kind=Component Class|MinPercent=75|MinMatch=3|ShowMatch=-1|Confirm=-1|UseName=-1|InclAllRules=0 +ComparisonOptions3=Kind=Rule|MinPercent=75|MinMatch=3|ShowMatch=-1|Confirm=-1|UseName=-1|InclAllRules=0 +ComparisonOptions4=Kind=Differential Pair|MinPercent=50|MinMatch=1|ShowMatch=0|Confirm=0|UseName=0|InclAllRules=0 + +[SmartPDF] +PageOptions=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-4|MediaType=1|DitherType=10|PaperKind=A4|PrintScaleMode=1 + diff --git a/hardware/Production/CC Spektrum Adapter/Spektrum Adapter.SchDoc b/hardware/Production/CC Spektrum Adapter/Spektrum Adapter.SchDoc new file mode 100644 index 000000000..bf4b6f6cd Binary files /dev/null and b/hardware/Production/CC Spektrum Adapter/Spektrum Adapter.SchDoc differ diff --git a/make/boards/ahrs/board-info.mk b/make/boards/ahrs/board-info.mk new file mode 100644 index 000000000..2103357ba --- /dev/null +++ b/make/boards/ahrs/board-info.mk @@ -0,0 +1,18 @@ +BOARD_TYPE := 0x02 +BOARD_REVISION := 0x01 +BOOTLOADER_VERSION := 0x00 +HW_TYPE := 0x00 + +MCU := cortex-m3 +CHIP := STM32F103CBT +BOARD := STM32103CB_AHRS +MODEL := MD +MODEL_SUFFIX := + +# Note: These must match the values in link_$(BOARD)_memory.ld +BL_BANK_BASE := 0x08000000 # Start of bootloader flash +BL_BANK_SIZE := 0x00002000 # Should include BD_INFO region +FW_BANK_BASE := 0x08002000 # Start of firmware flash +FW_BANK_SIZE := 0x0001E000 # Should include FW_DESC_SIZE + +FW_DESC_SIZE := 0x00000064 diff --git a/make/boards/coptercontrol/board-info.mk b/make/boards/coptercontrol/board-info.mk new file mode 100644 index 000000000..012c6ef16 --- /dev/null +++ b/make/boards/coptercontrol/board-info.mk @@ -0,0 +1,18 @@ +BOARD_TYPE := 0x04 +BOARD_REVISION := 0x01 +BOOTLOADER_VERSION := 0x01 +HW_TYPE := 0x01 + +MCU := cortex-m3 +CHIP := STM32F103CBT +BOARD := STM32103CB_CC_Rev1 +MODEL := MD +MODEL_SUFFIX := _CC + +# Note: These must match the values in link_$(BOARD)_memory.ld +BL_BANK_BASE := 0x08000000 # Start of bootloader flash +BL_BANK_SIZE := 0x00003000 # Should include BD_INFO region +FW_BANK_BASE := 0x08003000 # Start of firmware flash +FW_BANK_SIZE := 0x0001D000 # Should include FW_DESC_SIZE + +FW_DESC_SIZE := 0x00000064 diff --git a/make/boards/ins/board-info.mk b/make/boards/ins/board-info.mk new file mode 100644 index 000000000..8a57661bf --- /dev/null +++ b/make/boards/ins/board-info.mk @@ -0,0 +1,18 @@ +BOARD_TYPE := 0x05 +BOARD_REVISION := 0x01 +BOOTLOADER_VERSION := 0x00 +HW_TYPE := 0x00 + +MCU := cortex-m3 +CHIP := STM32F103RET +BOARD := STM3210E_INS +MODEL := HD +MODEL_SUFFIX := _OP + +# Note: These must match the values in link_$(BOARD)_memory.ld +BL_BANK_BASE := 0x08000000 # Start of bootloader flash +BL_BANK_SIZE := 0x00002000 # Should include BD_INFO region +FW_BANK_BASE := 0x08002000 # Start of firmware flash +FW_BANK_SIZE := 0x0001E000 # Should include FW_DESC_SIZE + +FW_DESC_SIZE := 0x00000064 diff --git a/make/boards/openpilot/board-info.mk b/make/boards/openpilot/board-info.mk new file mode 100644 index 000000000..f1e35505c --- /dev/null +++ b/make/boards/openpilot/board-info.mk @@ -0,0 +1,18 @@ +BOARD_TYPE := 0x01 +BOARD_REVISION := 0x01 +BOOTLOADER_VERSION := 0x00 +HW_TYPE := 0x00 + +MCU := cortex-m3 +CHIP := STM32F103RET +BOARD := STM3210E_OP +MODEL := HD +MODEL_SUFFIX := _OP + +# Note: These must match the values in link_$(BOARD)_memory.ld +BL_BANK_BASE := 0x08000000 # Start of bootloader flash +BL_BANK_SIZE := 0x00005000 # Should include BD_INFO region +FW_BANK_BASE := 0x08005000 # Start of firmware flash +FW_BANK_SIZE := 0x0007B000 # Should include FW_DESC_SIZE + +FW_DESC_SIZE := 0x00000064 diff --git a/make/boards/pipxtreme/board-info.mk b/make/boards/pipxtreme/board-info.mk new file mode 100644 index 000000000..f9635109e --- /dev/null +++ b/make/boards/pipxtreme/board-info.mk @@ -0,0 +1,20 @@ +BOARD_TYPE := 0x03 +BOARD_REVISION := 0x01 +BOOTLOADER_VERSION := 0x00 +HW_TYPE := 0x01 + +MCU := cortex-m3 +CHIP := STM32F103CBT +BOARD := STM32103CB_PIPXTREME +MODEL := MD +MODEL_SUFFIX := + +# Note: These must match the values in link_$(BOARD)_memory.ld +BL_BANK_BASE := 0x08000000 # Start of bootloader flash +BL_BANK_SIZE := 0x00003000 # Should include BD_INFO region +FW_BANK_BASE := 0x08003000 # Start of firmware flash +FW_BANK_SIZE := 0x0001CC00 # Should include FW_DESC_SIZE +EE_BANK_BASE := 0x0801FC00 # EEPROM storage area +EE_BANK_SIZE := 0x00000400 # Size of EEPROM storage area + +FW_DESC_SIZE := 0x00000064 diff --git a/make/firmware-defs.mk b/make/firmware-defs.mk index f42211c4c..901a6c454 100644 --- a/make/firmware-defs.mk +++ b/make/firmware-defs.mk @@ -10,6 +10,7 @@ OBJDUMP = $(TCHAIN_PREFIX)objdump SIZE = $(TCHAIN_PREFIX)size NM = $(TCHAIN_PREFIX)nm STRIP = $(TCHAIN_PREFIX)strip +INSTALL = install THUMB = -mthumb @@ -43,6 +44,11 @@ MSG_CLEANING := ${quote} CLEAN ${quote} MSG_ASMFROMC := ${quote} AS(C) ${quote} MSG_ASMFROMC_ARM := ${quote} AS(C)-ARM ${quote} MSG_PYMITEINIT := ${quote} PY ${quote} +MSG_INSTALLING := ${quote} INSTALL ${quote} +MSG_OPFIRMWARE := ${quote} OPFW ${quote} +MSG_FWINFO := ${quote} FWINFO ${quote} +MSG_JTAG_PROGRAM := ${quote} JTAG-PGM ${quote} +MSG_JTAG_WIPE := ${quote} JTAG-WIPE ${quote} toprel = $(subst $(realpath $(TOP))/,,$(abspath $(1))) @@ -66,6 +72,10 @@ gccversion : @echo $(MSG_LOAD_FILE) $(call toprel, $@) $(V1) $(OBJCOPY) -O binary $< $@ +%.bin: %.o + @echo $(MSG_LOAD_FILE) $(call toprel, $@) + $(V1) $(OBJCOPY) -O binary $< $@ + %.bin.o: %.bin @echo $(MSG_BIN_OBJ) $(call toprel, $@) $(V1) $(OBJCOPY) -I binary -O elf32-littlearm --binary-architecture arm \ @@ -88,12 +98,39 @@ gccversion : $(V1) $(NM) -n $< > $@ define SIZE_TEMPLATE +.PHONY: size +size: $(1)_size + .PHONY: $(1)_size $(1)_size: $(1) @echo $(MSG_SIZE) $$(call toprel, $$<) $(V1) $(SIZE) -A $$< endef +# OpenPilot firmware image template +# $(1) = path to bin file +# $(2) = boardtype in hex +# $(3) = board revision in hex +define OPFW_TEMPLATE +FORCE: + +$(1).firmwareinfo.c: $(1) $(TOP)/make/templates/firmwareinfotemplate.c FORCE + @echo $(MSG_FWINFO) $$(call toprel, $$@) + $(V1) python $(TOP)/make/scripts/version-info.py \ + --path=$(TOP) \ + --template=$(TOP)/make/templates/firmwareinfotemplate.c \ + --outfile=$$@ \ + --image=$(1) \ + --type=$(2) \ + --revision=$(3) + +$(eval $(call COMPILE_C_TEMPLATE, $(1).firmwareinfo.c)) + +$(OUTDIR)/$(notdir $(basename $(1))).opfw : $(1) $(1).firmwareinfo.bin + @echo $(MSG_OPFIRMWARE) $$(call toprel, $$@) + $(V1) cat $(1) $(1).firmwareinfo.bin > $$@ +endef + # Assemble: create object files from assembler source files. define ASSEMBLE_TEMPLATE $(OUTDIR)/$(notdir $(basename $(1))).o : $(1) @@ -161,21 +198,48 @@ $($(1):.c=.s) : %.s : %.c $(V1) $(CC) -S $$(CFLAGS) $$(CONLYFLAGS) $$< -o $$@ endef +# $(1) = Name of binary image to write +# $(2) = Base of flash region to write/wipe +# $(3) = Size of flash region to write/wipe +define JTAG_TEMPLATE # --------------------------------------------------------------------------- # Options for OpenOCD flash-programming # see openocd.pdf/openocd.texi for further information # if OpenOCD is in the $PATH just set OPENOCDEXE=openocd -OOCD_EXE=openocd +OOCD_EXE ?= openocd + # debug level -OOCD_CL=-d0 +OOCD_JTAG_SETUP = -d0 # interface and board/target settings (using the OOCD target-library here) -OOCD_CL+=-s $(TOP)/flight/Project/OpenOCD -OOCD_CL+=-f foss-jtag.revb.cfg -f stm32.cfg +OOCD_JTAG_SETUP += -s $(TOP)/flight/Project/OpenOCD +OOCD_JTAG_SETUP += -f foss-jtag.revb.cfg -f stm32.cfg # initialize -OOCD_CL+=-c init +OOCD_BOARD_RESET = -c init # show the targets -OOCD_CL+=-c targets +#OOCD_BOARD_RESET += -c targets # commands to prepare flash-write -OOCD_CL+= -c "reset halt" +OOCD_BOARD_RESET += -c "reset halt" + +.PHONY: program +program: $(1) + @echo $(MSG_JTAG_PROGRAM) $$(call toprel, $$<) + $(V1) $(OOCD_EXE) \ + $$(OOCD_JTAG_SETUP) \ + $$(OOCD_BOARD_RESET) \ + -c "flash write_image erase $$< $(2) bin" \ + -c "verify_image $$< $(2) bin" \ + -c "reset run" \ + -c "shutdown" + +.PHONY: wipe +wipe: + @echo $(MSG_JTAG_WIPE) wiping $(3) bytes starting from $(2) + $(V1) $(OOCD_EXE) \ + $$(OOCD_JTAG_SETUP) \ + $$(OOCD_BOARD_RESET) \ + -c "flash erase_address pad $(2) $(3)" \ + -c "reset run" \ + -c "shutdown" +endef \ No newline at end of file diff --git a/make/scripts/version-info.py b/make/scripts/version-info.py new file mode 100644 index 000000000..8c4fe901e --- /dev/null +++ b/make/scripts/version-info.py @@ -0,0 +1,345 @@ +#!/usr/bin/env python +# +# Utility functions to access git repository info and +# generate source files and binary objects using templates. +# +# (c) 2011, The OpenPilot Team, http://www.openpilot.org +# See also: The GNU Public License (GPL) Version 3 +# + +from subprocess import Popen, PIPE +from re import search, MULTILINE +from datetime import datetime +from string import Template +import optparse +import hashlib +import sys + +class Repo: + """A simple git repository HEAD commit info class + + This simple class provides object notation to access + the git repository current commit info. If one needs + better access one can try the GitPython class available + here: + http://packages.python.org/GitPython + It is not installed by default, so we cannot rely on it. + + Example: + r = Repo('/path/to/git/repository') + print "path: ", r.path() + print "origin: ", r.origin() + print "hash: ", r.hash() + print "short hash: ", r.hash(8) + print "Unix time: ", r.time() + print "commit date:", r.time("%Y%m%d") + print "commit tag: ", r.tag() + print "branch: ", r.branch() + print "release tag:", r.reltag() + """ + + def _exec(self, cmd): + """Execute git using cmd as arguments""" + self._git = 'git' + git = Popen(self._git + " " + cmd, cwd=self._path, + shell=True, stdout=PIPE, stderr=PIPE) + self._out, self._err = git.communicate() + self._rc = git.poll() + + def _get_origin(self): + """Get and store the repository fetch origin path""" + self._origin = None + self._exec('remote -v') + if self._rc == 0: + m = search(r"^origin\s+(.+)\s+\(fetch\)$", self._out, MULTILINE) + if m: + self._origin = m.group(1) + + def _get_time(self): + """Get and store HEAD commit timestamp in Unix format + + We use commit timestamp rather than the build time, + so it always is the same for the current commit or tag. + """ + self._time = None + self._exec('log -n1 --no-color --format=format:%ct HEAD') + if self._rc == 0: + self._time = self._out + + def _get_tag(self): + """Get and store git tag for the HEAD commit""" + self._tag = None + self._exec('describe --tags --exact-match HEAD') + if self._rc == 0: + self._tag = self._out.strip(' \t\n\r') + + def _get_branch(self): + """Get and store current branch containing the HEAD commit""" + self._branch = None + self._exec('branch --contains HEAD') + if self._rc == 0: + m = search(r"^\*\s+(.+)$", self._out, MULTILINE) + if m: + self._branch = m.group(1) + + def _get_dirty(self): + """Check for dirty state of repository""" + self._dirty = False + self._exec('update-index --refresh --unmerged') + self._exec('diff-index --name-only --exit-code --quiet HEAD') + if self._rc: + self._dirty = True + + def __init__(self, path = "."): + """Initialize object instance and read repo info""" + self._path = path + self._exec('rev-parse --verify HEAD') + if self._rc == 0: + self._hash = self._out.strip(' \t\n\r') + self._get_origin() + self._get_time() + self._get_tag() + self._get_branch() + self._get_dirty() + else: + self._hash = None + self._origin = None + self._time = None + self._tag = None + self._branch = None + self._dirty = None + + def path(self): + """Return the repository path""" + return self._path + + def origin(self, none = None): + """Return fetch origin of the repository""" + if self._origin == None: + return none + else: + return self._origin + + def hash(self, n = 40, none = None): + """Return hash of the HEAD commit""" + if self._hash == None: + return none + else: + return self._hash[:n] + + def time(self, format = None, none = None): + """Return Unix or formatted time of the HEAD commit""" + if self._time == None: + return none + else: + if format == None: + return self._time + else: + return datetime.utcfromtimestamp(float(self._time)).strftime(format) + + def tag(self, none = None): + """Return git tag for the HEAD commit or given string if none""" + if self._tag == None: + return none + else: + return self._tag + + def branch(self, none = None): + """Return git branch containing the HEAD or given string if none""" + if self._branch == None: + return none + else: + return self._branch + + def dirty(self, dirty = "-dirty", clean = ""): + """Return git repository dirty state or empty string""" + if self._dirty: + return dirty + else: + return clean + + def info(self): + """Print some repository info""" + print "path: ", self.path() + print "origin: ", self.origin() + print "Unix time: ", self.time() + print "commit date:", self.time("%Y%m%d") + print "hash: ", self.hash() + print "short hash: ", self.hash(8) + print "branch: ", self.branch() + print "commit tag: ", self.tag() + print "dirty: ", self.dirty('yes', 'no') + +def file_from_template(tpl_name, out_name, dict): + """Create or update file from template using dictionary + + This function reads the template, performs placeholder replacement + using the dictionary and checks if output file with such content + already exists. If no such file or file data is different from + expected then it will be ovewritten with new data. Otherwise it + will not be updated so make will not update dependent targets. + + Example: + # template.c: + # char source[] = "${OUTFILENAME}"; + # uint32_t timestamp = ${UNIXTIME}; + # uint32_t hash = 0x${HASH8}; + + r = Repo('/path/to/git/repository') + tpl_name = "template.c" + out_name = "output.c" + + dictionary = dict( + HASH8 = r.hash(8), + UNIXTIME = r.time(), + OUTFILENAME = out_name, + ) + + file_from_template(tpl_name, out_name, dictionary) + """ + + # Read template first + tf = open(tpl_name, "rb") + tpl = tf.read() + tf.close() + + # Replace placeholders using dictionary + out = Template(tpl).substitute(dict) + + # Check if output file already exists + try: + of = open(out_name, "rb") + except IOError: + # No file - create new + of = open(out_name, "wb") + of.write(out) + of.close() + else: + # File exists - overwite only if content is different + inp = of.read() + of.close() + if inp != out: + of = open(out_name, "wb") + of.write(out) + of.close() + +def sha1(file): + """Provides C source representation of sha1 sum of file""" + if file == None: + return "" + else: + sha1 = hashlib.sha1() + with open(file, 'rb') as f: + for chunk in iter(lambda: f.read(8192), ''): + sha1.update(chunk) + hex_stream = lambda s:",".join(['0x'+hex(ord(c))[2:].zfill(2) for c in s]) + return hex_stream(sha1.digest()) + +def xtrim(string, suffix, length): + """Return string+suffix concatenated and trimmed up to length characters + + This function appends suffix to the end of string and returns the result + up to length characters. If it does not fit then the string will be + truncated and the '+' will be put between it and the suffix. + """ + + if len(string) + len(suffix) <= length: + return ''.join([string, suffix]) + else: + n = length-1-len(suffix) + assert n > 0, "length of truncated string+suffix exceeds maximum length" + return ''.join([string[:n], '+', suffix]) + +def main(): + """This utility uses git repository in the current working directory +or from the given path to extract some info about it and HEAD commit. +Then some variables in the form of ${VARIABLE} could be replaced by +collected data. Optional board type, board revision and sha1 sum +of given image file could be applied as well or will be replaced by +empty strings if not defined. + +If --info option is given, some repository info will be printed to +stdout. + +If --format option is given then utility prints the format string +after substitution to the standard output. + +If --outfile option is given then the --template option should be +defined too. In that case the utility reads a template file, performs +variable substitution and writes the result into output file. Output +file will be overwritten only if its content differs from expected. +Otherwise it will not be touched, so make utility will not remake +dependent targets. + """ + + # Parse command line. + class RawDescriptionHelpFormatter(optparse.IndentedHelpFormatter): + """optparse formatter function to pretty print raw epilog""" + def format_epilog(self, epilog): + if epilog: + return "\n" + epilog + "\n" + else: + return "" + + parser = optparse.OptionParser( + formatter=RawDescriptionHelpFormatter(), + description = "Performs variable substitution in template file or string.", + epilog = main.__doc__); + + parser.add_option('--path', default='.', + help='path to the git repository'); + parser.add_option('--info', action='store_true', + help='print repository info to stdout'); + parser.add_option('--format', + help='format string to print to stdout'); + parser.add_option('--template', + help='name of template file'); + parser.add_option('--outfile', + help='name of output file'); + parser.add_option('--image', + help='name of image file for sha1 calculation'); + parser.add_option('--type', default="", + help='board type, for example, 0x04 for CopterControl'); + parser.add_option('--revision', default = "", + help='board revision, for example, 0x01'); + + (args, positional_args) = parser.parse_args() + if len(positional_args) != 0: + parser.error("incorrect number of arguments, try --help for help") + + # Process arguments. No advanced error handling is here. + # Any error will raise an exception and terminate process + # with non-zero exit code. + r = Repo(args.path) + + dictionary = dict( + TEMPLATE = args.template, + OUTFILENAME = args.outfile, + ORIGIN = r.origin(), + HASH = r.hash(), + HASH8 = r.hash(8), + TAG_OR_BRANCH = r.tag(r.branch('unreleased')), + TAG_OR_HASH8 = r.tag(r.hash(8, 'untagged')), + DIRTY = r.dirty(), + FWTAG = xtrim(r.tag(r.branch('unreleased')), r.dirty(), 25), + UNIXTIME = r.time(), + DATE = r.time('%Y%m%d'), + DATETIME = r.time('%Y%m%d %H:%M'), + BOARD_TYPE = args.type, + BOARD_REVISION = args.revision, + SHA1 = sha1(args.image), + ) + + if args.info: + r.info() + + if args.format != None: + print Template(args.format).substitute(dictionary) + + if args.outfile != None: + file_from_template(args.template, args.outfile, dictionary) + + return 0 + +if __name__ == "__main__": + sys.exit(main()) diff --git a/make/templates/firmwareinfotemplate.c b/make/templates/firmwareinfotemplate.c new file mode 100644 index 000000000..b9297273e --- /dev/null +++ b/make/templates/firmwareinfotemplate.c @@ -0,0 +1,71 @@ +/** + ****************************************************************************** + * + * @file ${OUTFILENAME} + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. + * @brief Firmware version info file autogenerated using template + * ${TEMPLATE} + * + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +/** + * We have 100 bytes for the whole description. + * + * Only the first 40 are visible on the FirmwareIAP uavobject, the remaining + * 60 are ok to use for packaging and will be saved in the flash. + * + * Structure is: + * 4 bytes: header: "OpFw". + * 4 bytes: GIT commit tag (short version of SHA1). + * 4 bytes: Unix timestamp of compile time. + * 2 bytes: target platform. Should follow same rule as BOARD_TYPE and BOARD_REVISION in board define files. + * 26 bytes: commit tag if it is there, otherwise branch name. '-dirty' may be added if needed. Zero-padded. + * ---- 40 bytes limit --- + * 20 bytes: SHA1 sum of the firmware. + * 40 bytes: free for now. + * + */ + +struct __attribute__((packed)) fw_version_info { + uint8_t magic[4]; + uint32_t commit_hash_prefix; + uint32_t timestamp; + uint8_t board_type; + uint8_t board_revision; + uint8_t commit_tag_name[26]; + uint8_t sha1sum[20]; + uint8_t pad[40]; +}; + +const struct fw_version_info fw_version_blob __attribute__((used)) __attribute__((__section__(".fw_version_blob"))) = { + .magic = { 'O','p','F','w' }, + .commit_hash_prefix = 0x${HASH8}, + .timestamp = ${UNIXTIME}, + .board_type = ${BOARD_TYPE}, + .board_revision = ${BOARD_REVISION}, + .commit_tag_name = "${FWTAG}", + .sha1sum = { ${SHA1} }, +}; + +/** + * @} + */ diff --git a/make/templates/gcsversioninfotemplate.h b/make/templates/gcsversioninfotemplate.h new file mode 100644 index 000000000..2130f59bf --- /dev/null +++ b/make/templates/gcsversioninfotemplate.h @@ -0,0 +1,32 @@ +/** + ****************************************************************************** + * + * @file ${OUTFILENAME} + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. + * @brief GCS revision info file autogenerated using template + * ${TEMPLATE} + * + * @see The GNU Public License (GPL) Version 3 + * + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define GCS_REVISION ${TAG_OR_BRANCH}:${HASH8}${DIRTY} ${DATETIME} + +/** + * @} + */ diff --git a/make/winx86/README.txt b/make/winx86/README.txt index 9677e9368..17477d098 100644 --- a/make/winx86/README.txt +++ b/make/winx86/README.txt @@ -33,27 +33,35 @@ It is expected that you have the following tools installed into the listed locations (but any other locations are fine as well): - Python in C:\Python27 - - CodeSourcery G++ in C:\CodeSourcery - - QtSDK in C:\Qt\2010.05 + - QtSDK in C:\Qt\2010.05 or C:\QtSDK (depending on SDK version) + - CodeSourcery G++ in %ProgramFiles%\CodeSourcery\Sourcery G++ Lite - msysGit in %ProgramFiles%\Git - Unicode NSIS in %ProgramFiles%\NSIS\Unicode + - OpenOCD in C:\OpenOCD\0.4.0\bin (optional) + +The SDL library and headers should be installed into Qt directories to build +the GCS. Check the wiki or ground/openpilotgcs/copydata.pro for details. Also it is assumed that you have the C:\Program Files\Git\cmd\ directory in the PATH. Usually this is the case for msysGit installation if you have chosen the 2nd option: put only git and gitk in the PATH (it is recommended option). -Now you need to copy two files to your msysGit installation folders. +Now you need to copy few files to your msysGit installation folders. Assuming that you installed the msysGit into C:\Program Files\Git\, you have to copy: - make\winx86\make -> C:\Program Files\Git\bin\ - make\winx86\sh.cmd -> C:\Program Files\Git\cmd\ + make\winx86\bin\* -> C:\Program Files\Git\bin\ + make\winx86\cmd\* -> C:\Program Files\Git\cmd\ If you have msysGit installed into another directory, you need to update paths accordingly. Also if you have tools installed into different directories and they are not in the PATH, then you may want to update paths in the sh.cmd script too (it is self-documented). +Note for Windows 64-bit users: 64-bit systems use %ProgramFiles(x86)% folder +as default for program files instead of %ProgramFiles%. You have to check where +your tools are installed and update paths above accordingly. + 3. How to use it? ----------------- @@ -93,7 +101,7 @@ software and flight firmware built in the end. 4) To build parts of the system you can use, for example, such commands: user@pc /d/Work/OpenPilot/git (master) - $ make -j2 USE_BOOTLOADER=YES GCS_BUIL_CONF=release gcs coptercontrol bl_coptercontrol + $ make -j2 GCS_BUILD_CONF=release gcs coptercontrol or to completely remove the build directory: @@ -109,7 +117,7 @@ or to completely remove the build directory: #!/bin/sh # This is the cc_make_release.sh file used to build CC release software cd D:/Work/OpenPilot/git - make -j2 USE_BOOTLOADER=YES GCS_BUIL_CONF=release gcs coptercontrol bl_coptercontrol + make -j2 GCS_BUILD_CONF=release gcs coptercontrol echo RC=$? 2) Run it typing: @@ -170,7 +178,7 @@ to get rid of git bash welcome message on every script invocation. Currently there may be some problems running scripts which contain spaces in file names or located in directories which contain spaces in full paths. -It results in in strange "file not found" or other errors. +It results in strange "file not found" or other errors. It is recommended to avoid using such names with spaces. diff --git a/make/winx86/bin/install b/make/winx86/bin/install new file mode 100644 index 000000000..fae28bf23 --- /dev/null +++ b/make/winx86/bin/install @@ -0,0 +1,15 @@ +#!/bin/sh +# +# simple install command replacement for Windows +# +# This file should be put into C:\Program Files\Git\bin\ subdirectory +# (or similar, depeding on where the msysGit package was installed) +# to provide a make command to unix-like build environment on Windows. +# +# See also: +# README.txt +# http://wiki.openpilot.org/display/Doc/GCS+Development+on+Windows +# http://wiki.openpilot.org/display/Doc/Firmware+Development+on+Windows +# + +cp -f $* diff --git a/make/winx86/make b/make/winx86/bin/make similarity index 73% rename from make/winx86/make rename to make/winx86/bin/make index 4d475bff6..d4bf11224 100644 --- a/make/winx86/make +++ b/make/winx86/bin/make @@ -1,6 +1,8 @@ #!/bin/sh # -# This file is to be put into C:\Program Files\Git\bin\ subdirectory +# make command replacement for Windows +# +# This file should be put into C:\Program Files\Git\bin\ subdirectory # (or similar, depeding on where the msysGit package was installed) # to provide a make command to unix-like build environment on Windows. # diff --git a/make/winx86/cmd/make.sh b/make/winx86/cmd/make.sh new file mode 100644 index 000000000..a2ae771d5 --- /dev/null +++ b/make/winx86/cmd/make.sh @@ -0,0 +1,9 @@ +# +# make command replacement to run from command prompt under bash +# +# This file should be put into C:\Program Files\Git\cmd\ subdirectory +# (or similar, depeding on where the msysGit package was installed) +# to provide a shell prompt in the unix-like build environment on Windows. +# + +exec /bin/make $* diff --git a/make/winx86/sh.cmd b/make/winx86/cmd/sh.cmd similarity index 85% rename from make/winx86/sh.cmd rename to make/winx86/cmd/sh.cmd index b3b276fb2..480044ab7 100644 --- a/make/winx86/sh.cmd +++ b/make/winx86/cmd/sh.cmd @@ -1,6 +1,6 @@ @echo off rem -rem This file is to be put into C:\Program Files\Git\cmd\ subdirectory +rem This file should be put into C:\Program Files\Git\cmd\ subdirectory rem (or similar, depeding on where the msysGit package was installed) rem to provide a shell prompt in the unix-like build environment on Windows. rem @@ -38,6 +38,9 @@ rem As a result, the SDL headers will not be found, if they were copied into rem QtSDK's MinGW directory. In that case make sure that you have correct rem directories specified here. rem +rem Also the SDL should be installed into Qt directories to build the GCS. +rem Check the wiki or ground/openpilotgcs/copydata.pro for details. +rem rem Also you can add any paths below just by adding extra 'call :which' rem lines with the following parameters: rem - environment variable which will be set to the tool location, if found; @@ -51,11 +54,16 @@ set NOT_FOUND= set PATH_DIRS= call :which MSYSGIT "%ProgramFiles%\Git\bin" git.exe +rem These two lines for qt-sdk-win-opensource-2010.05.exe: call :which QTMINGW "C:\Qt\2010.05\mingw\bin" mingw32-make.exe call :which QTSDK "C:\Qt\2010.05\qt\bin" qmake.exe -call :which CODESOURCERY "C:\CodeSourcery\bin" cs-make.exe +rem These two lines for Qt_SDK_Win_offline_v1_1_1_en.exe: +rem call :which QTMINGW "C:\QtSDK\mingw\bin" mingw32-make.exe +rem call :which QTSDK "C:\QtSDK\Desktop\Qt\4.7.3\mingw\bin" qmake.exe +call :which CODESOURCERY "%ProgramFiles%\CodeSourcery\Sourcery G++ Lite\bin" cs-make.exe call :which PYTHON "C:\Python27" python.exe call :which UNSIS "%ProgramFiles%\NSIS\Unicode" makensis.exe +call :which OPENOCDBIN "C:\OpenOCD\0.4.0\bin" openocd.exe if "%NOT_FOUND%" == "" goto set_path diff --git a/package/Makefile b/package/Makefile new file mode 100644 index 000000000..0a197844a --- /dev/null +++ b/package/Makefile @@ -0,0 +1,131 @@ +# Set up a default goal +.DEFAULT_GOAL := help + +# Tried the best to support parallel (-j) builds. But since this Makefile +# uses other Makefiles to build few targets which in turn have similar +# dependencies on uavobjects and other generated files, it is difficult +# to support parallel builds perfectly. But at least it was tested with +# -j (unlimited job number) on Windows and Linux. + +# Locate the root of the tree +WHEREAMI := $(dir $(lastword $(MAKEFILE_LIST))) +ROOT_DIR := $(realpath $(WHEREAMI)/../) + +# Set up some macros +BUILD_DIR := $(ROOT_DIR)/build +VERSION_CMD := python $(ROOT_DIR)/make/scripts/version-info.py --path="$(ROOT_DIR)" +PACKAGE_LBL := $(shell $(VERSION_CMD) --format=\$${DATE}-\$${TAG_OR_HASH8}\$${DIRTY}) +PACKAGE_DIR := $(BUILD_DIR)/package-$(PACKAGE_LBL) +FW_DIR := $(PACKAGE_DIR)/firmware-$(PACKAGE_LBL) +BL_DIR := $(FW_DIR)/bootloaders +BU_DIR := $(FW_DIR)/bootloader-updaters + +# Clean build options (recommended for package testing only) +ifeq ($(CLEAN_BUILD), NO) +CLEAN_GROUND := NO +CLEAN_FLIGHT := NO +else +CLEAN_GROUND := YES +CLEAN_FLIGHT := YES +endif + +# Set up targets (PPM target seems to be broken at the moment) +FW_TARGETS := $(addprefix fw_, ahrs pipxtreme coptercontrol openpilot) +FW_TARGETS_TOOLS := $(addprefix fw_, coptercontrol) +BL_TARGETS := $(addprefix bl_, coptercontrol openpilot ahrs pipxtreme) +BU_TARGETS := $(addprefix bu_, coptercontrol openpilot ahrs pipxtreme) + +help: + @echo + @echo " This Makefile is known to work on Linux and Mac in a standard shell environment." + @echo " It also works on Windows by following the instructions in ../make/winx86/README.txt." + @echo + @echo " Here is a summary of the available targets:" + @echo + @echo " [Packaging]" + @echo " package - Build and package the OpenPilot distributable" + @echo " package_flight - Build and package the OpenPilot flight firmware only" + @echo + @echo " Notes:" + @echo " - package will be placed in $(PACKAGE_DIR)" + @echo + @echo " - the build directory will be removed first on every run unless" + @echo " CLEAN_BUILD=NO is defined. It means no clean before build." + @echo " This usually is safe." + @echo + +# Clean and build uavobjects since all parts depend on them +uavobjects: all_clean + $(V1) $(MAKE) -C $(ROOT_DIR) $@ + +all_clean: +ifneq ($(CLEAN_GROUND), NO) + $(V1) $(MAKE) -C $(ROOT_DIR) $@ +endif + +# Install template: +# $1 = target +# $2 = dependencies +# $3 = install directory (must be defined) +# $4 = installed file name prefix (optional) +# $5 = installed file name suffix (optional) +# $6 = extra make options (for instance, USE_SPEKTRUM=YES) +# $7 = optional 'clean' string to clean target before rebuild +# $8 = list of targets to install (without _install suffix) +# $9 = inner make target (usually install, but can be other to just build) +define INSTALL_TEMPLATE +$(1): $(2) +ifeq ($(7),clean) +ifneq ($$(CLEAN_FLIGHT), NO) + $$(V1) +$(MAKE) -C $(ROOT_DIR) $(6) $(addsuffix _$(7), $(8)) +endif +endif + $$(V1) +$(MAKE) -C $(ROOT_DIR) INSTALL_DIR=$(3) INSTALL_PFX=$(4) INSTALL_SFX=$(5) $(6) $(addsuffix _$(9), $(8)) +.PHONY: $(1) +endef + +# Firmware +$(eval $(call INSTALL_TEMPLATE,all_fw,uavobjects,$(FW_DIR),,-$(PACKAGE_LBL),,,$(FW_TARGETS),install)) + +# Bootloaders (change 'install' to 'bin' if you don't want to install bootloaders) +$(eval $(call INSTALL_TEMPLATE,all_bl,uavobjects,$(BL_DIR),,-$(PACKAGE_LBL),,,$(BL_TARGETS),install)) + +# Bootloader updaters +$(eval $(call INSTALL_TEMPLATE,all_bu,all_bl,$(BU_DIR),,-$(PACKAGE_LBL),,,$(BU_TARGETS),install)) + +# Order-only dependencies +package_flight: | all_fw all_bu + +package_ground: | ground_package + +package: | package_flight package_ground + +.PHONY: help uavobjects all_clean package_flight package_ground package + +# Decide on a verbosity level based on the V= parameter +export AT := @ + +ifndef V +export V0 := +export V1 := $(AT) +else ifeq ($(V), 0) +export V0 := $(AT) +export V1 := $(AT) +else ifeq ($(V), 1) +endif + +ifneq ($(V),1) +MAKEFLAGS += --no-print-directory +endif + +# Platform-dependent stuff +PLATFORM := winx86 +UNAME := $(shell uname) +ifeq ($(UNAME), Linux) + PLATFORM := linux +endif +ifeq ($(UNAME), Darwin) + PLATFORM := osx +endif + +include $(WHEREAMI)/Makefile.$(PLATFORM) diff --git a/package/Makefile.linux b/package/Makefile.linux new file mode 100644 index 000000000..c966ff6f2 --- /dev/null +++ b/package/Makefile.linux @@ -0,0 +1,10 @@ +# +# Linux-specific packaging +# + +gcs: uavobjects + $(V1) $(MAKE) -C $(ROOT_DIR) GCS_BUILD_CONF=release $@ + +ground_package: | gcs + +.PHONY: gcs ground_package diff --git a/package/Makefile.osx b/package/Makefile.osx new file mode 100644 index 000000000..e2b3c62ba --- /dev/null +++ b/package/Makefile.osx @@ -0,0 +1,20 @@ +# +# MacOSX-specific packaging +# + +osx_package: gcs package_flight + ( \ + ROOT_DIR="$(ROOT_DIR)" \ + BUILD_DIR="$(BUILD_DIR)" \ + PACKAGE_LBL="$(PACKAGE_LBL)" \ + PACKAGE_DIR="$(PACKAGE_DIR)" \ + FW_DIR="$(FW_DIR)" \ + "$(ROOT_DIR)/package/osx/package" \ + ) + +gcs: uavobjects + $(V1) $(MAKE) -C $(ROOT_DIR) GCS_BUILD_CONF=release $@ + +ground_package: | osx_package + +.PHONY: gcs ground_package osx_package diff --git a/package/Makefile.winx86 b/package/Makefile.winx86 new file mode 100644 index 000000000..5ff65a97d --- /dev/null +++ b/package/Makefile.winx86 @@ -0,0 +1,25 @@ +# +# Windows-specific packaging +# + +NSIS_CMD := makensis.exe +NSIS_OPTS := /V3 +NSIS_DIR := $(ROOT_DIR)/package/winx86 +NSIS_SCRIPT := $(NSIS_DIR)/openpilotgcs.nsi +NSIS_TEMPLATE := $(NSIS_DIR)/openpilotgcs.tpl +NSIS_HEADER := $(BUILD_DIR)/ground/openpilotgcs/openpilotgcs.nsh + +win_package: gcs package_flight + $(V1) mkdir -p "$(dir $(NSIS_HEADER))" + $(VERSION_CMD) --template="$(NSIS_TEMPLATE)" --outfile="$(NSIS_HEADER)" + $(V1) echo "Building Windows installer, please wait..." + $(V1) echo "If you have a script error in line 1 - use Unicode NSIS 2.46+" + $(V1) echo " http://www.scratchpaper.com" + $(NSIS_CMD) $(NSIS_OPTS) $(NSIS_SCRIPT) + +gcs: uavobjects + $(V1) $(MAKE) -C $(ROOT_DIR) GCS_BUILD_CONF=release $@ + +ground_package: | win_package + +.PHONY: gcs ground_package win_package diff --git a/package/osx/OpenPilot.dmg b/package/osx/OpenPilot.dmg new file mode 100644 index 000000000..c8e1056fb Binary files /dev/null and b/package/osx/OpenPilot.dmg differ diff --git a/package/osx/libraries b/package/osx/libraries new file mode 100755 index 000000000..5c87ba15b --- /dev/null +++ b/package/osx/libraries @@ -0,0 +1,71 @@ +#!/bin/bash + +APP="${1?}" +PLUGINS="${APP}/Contents/Plugins" +OP_PLUGINS="${APP}/Contents/Plugins/OpenPilot" +QT_LIBS="QtGui QtTest QtCore QtSvg QtSql QtOpenGL QtNetwork QtXml QtDBus QtScript phonon" +QT_DIR=$(otool -L "${APP}/Contents/MacOS/OpenPilot GCS" | sed -n -e 's/\/QtCore\.framework.*//p' | sed -n -E 's:^.::p') +QT_EXTRA="accessible/libqtaccessiblewidgets.dylib bearer/libqgenericbearer.dylib codecs/libqcncodecs.dylib codecs/libqjpcodecs.dylib codecs/libqkrcodecs.dylib codecs/libqtwcodecs.dylib graphicssystems/libqtracegraphicssystem.dylib imageformats/libqgif.dylib imageformats/libqico.dylib imageformats/libqjpeg.dylib imageformats/libqmng.dylib imageformats/libqtiff.dylib qmltooling/libqmldbg_inspector.dylib qmltooling/libqmldbg_tcp.dylib" + + +echo "Qt library directory is \"${QT_DIR}\"" + +echo "Processing Qt libraries in $1" +macdeployqt "${APP}" + +for f in "${PLUGINS}/"*.dylib "${OP_PLUGINS}/"*.dylib +do + for g in $QT_LIBS + do + install_name_tool -change \ + "${QT_DIR}/${g}.framework/Versions/4/${g}" \ + @executable_path/../Frameworks/${g}.framework/Versions/4/${g} \ + "${f}" + done +done + + +# should be redundant but some libs missed by main app and macdeployqt +for f in ${QT_LIBS} +do + echo "Copying ${f}" + cp -r "${QT_DIR}/${f}.framework" "${APP}/Contents/Frameworks/" + + echo "Changing package identification of ${f}" + install_name_tool -id \ + @executable_path/../Frameworks/${f}.framework/Versions/4/${f} \ + "${APP}/Contents/Frameworks/${f}.framework/Versions/4/${f}" + + rm "${APP}/Contents/Frameworks/${f}.framework/${f}" + + echo "Changing package linkages" + for g in $QT_LIBS + do + install_name_tool -change \ + "${QT_DIR}/${g}.framework/Versions/4/${g}" \ + @executable_path/../Frameworks/${g}.framework/Versions/4/${g} \ + "${APP}/Contents/Frameworks/${f}.framework/Versions/4/${f}" + done +done + +for f in ${QT_EXTRA} +do + echo "Changing package identification of ${f}" + install_name_tool -id \ + @executable_path/../Plugins/${f} \ + "${PLUGINS}/${f}" +done + +echo "Copying SDL" +cp -r "/Library/Frameworks/SDL.framework" "${APP}/Contents/Frameworks/" + +echo "Changing package identification of SDL" +install_name_tool -id \ + @executable_path/../Frameworks/SDL.framework/Versions/A/SDL \ + "${APP}/Contents/Frameworks/SDL.framework/Versions/A/SDL" + +# deleting unnecessary files +echo "Deleting unnecessary files" +find "${APP}/Contents/Frameworks" -iname "current" -exec rm -rf \{\} \; +find "${APP}/Contents/Frameworks" -iname "4.0" -exec rm -rf \{\} \; +find "${APP}/Contents/Frameworks" -iname "*_debug" -exec rm -rf \{\} \; diff --git a/package/osx/package b/package/osx/package new file mode 100755 index 000000000..e481353ff --- /dev/null +++ b/package/osx/package @@ -0,0 +1,38 @@ +#!/bin/bash + +# the following environment variables must be set +: ${ROOT_DIR?} ${BUILD_DIR?} ${PACKAGE_LBL?} ${PACKAGE_DIR?} ${FW_DIR?} + +# more variables +APP_PATH="${BUILD_DIR}/ground/openpilotgcs/bin/OpenPilot GCS.app" +TEMP_FILE="${PACKAGE_DIR}/OpenPilot-temp.dmg" +OUT_FILE="${PACKAGE_DIR}/OpenPilot-${PACKAGE_LBL}.dmg" +VOL_NAME="OpenPilot" + +# prepare the stage +rm -f "${TEMP_FILE}" +rm -f "${OUT_FILE}" + +hdiutil convert "${ROOT_DIR}/package/osx/OpenPilot.dmg" \ + -format UDRW -o "${TEMP_FILE}" +device=$(hdiutil attach "${TEMP_FILE}" | \ + egrep '^/dev/' | sed 1q | awk '{print $1}') + +# packaging goes here +cp -r "${APP_PATH}" "/Volumes/${VOL_NAME}" +#cp -r "${FW_DIR}" "/Volumes/${VOL_NAME}/firmware" +cp "${FW_DIR}/fw_coptercontrol-${PACKAGE_LBL}.opfw" "/Volumes/${VOL_NAME}/firmware" + +cp "${ROOT_DIR}/HISTORY.txt" "/Volumes/${VOL_NAME}" + +"${ROOT_DIR}/package/osx/libraries" \ + "/Volumes/${VOL_NAME}/OpenPilot GCS.app" || exit 1 + +hdiutil detach ${device} + +echo "Resizing dmg" +hdiutil resize -size 250m ${TEMP_FILE} +hdiutil convert "${TEMP_FILE}" -format UDZO -o "${OUT_FILE}" + +# cleanup +rm "${TEMP_FILE}" diff --git a/ground/openpilotgcs/packaging/winx86/licenses/GPLv3_de.rtf b/package/winx86/licenses/GPLv3_de.rtf similarity index 100% rename from ground/openpilotgcs/packaging/winx86/licenses/GPLv3_de.rtf rename to package/winx86/licenses/GPLv3_de.rtf diff --git a/ground/openpilotgcs/packaging/winx86/licenses/GPLv3_en.rtf b/package/winx86/licenses/GPLv3_en.rtf similarity index 100% rename from ground/openpilotgcs/packaging/winx86/licenses/GPLv3_en.rtf rename to package/winx86/licenses/GPLv3_en.rtf diff --git a/ground/openpilotgcs/packaging/winx86/licenses/GPLv3_es.rtf b/package/winx86/licenses/GPLv3_es.rtf similarity index 100% rename from ground/openpilotgcs/packaging/winx86/licenses/GPLv3_es.rtf rename to package/winx86/licenses/GPLv3_es.rtf diff --git a/ground/openpilotgcs/packaging/winx86/licenses/GPLv3_fr.rtf b/package/winx86/licenses/GPLv3_fr.rtf similarity index 100% rename from ground/openpilotgcs/packaging/winx86/licenses/GPLv3_fr.rtf rename to package/winx86/licenses/GPLv3_fr.rtf diff --git a/ground/openpilotgcs/packaging/winx86/licenses/GPLv3_ru.rtf b/package/winx86/licenses/GPLv3_ru.rtf similarity index 100% rename from ground/openpilotgcs/packaging/winx86/licenses/GPLv3_ru.rtf rename to package/winx86/licenses/GPLv3_ru.rtf diff --git a/ground/openpilotgcs/packaging/winx86/licenses/GPLv3_zh_CN.rtf b/package/winx86/licenses/GPLv3_zh_CN.rtf similarity index 100% rename from ground/openpilotgcs/packaging/winx86/licenses/GPLv3_zh_CN.rtf rename to package/winx86/licenses/GPLv3_zh_CN.rtf diff --git a/ground/openpilotgcs/packaging/winx86/openpilotgcs.nsi b/package/winx86/openpilotgcs.nsi similarity index 82% rename from ground/openpilotgcs/packaging/winx86/openpilotgcs.nsi rename to package/winx86/openpilotgcs.nsi index 47037b59b..9e3fa2ec3 100644 --- a/ground/openpilotgcs/packaging/winx86/openpilotgcs.nsi +++ b/package/winx86/openpilotgcs.nsi @@ -33,9 +33,9 @@ ; Paths ; Tree root locations (relative to this script location) + !define PROJECT_ROOT "..\.." !define NSIS_DATA_TREE "." - !define GCS_BUILD_TREE "..\..\..\..\build\ground\openpilotgcs" - !define WINX86_PATH "packaging\winx86" + !define GCS_BUILD_TREE "..\..\build\ground\openpilotgcs" ; Default installation folder InstallDir "$LOCALAPPDATA\OpenPilot" @@ -51,14 +51,17 @@ !define INSTALLER_NAME "OpenPilot GCS Installer" ; Read automatically generated version info -; !define OUT_FILE "OpenPilotGCS-XXXX-install.exe" +; !define PACKAGE_LBL "${DATE}-${TAG_OR_HASH8}" +; !define PACKAGE_DIR "..\..\build\package-$${PACKAGE_LBL}" +; !define OUT_FILE "OpenPilotGCS-$${PACKAGE_LBL}-install.exe" +; !define FIRMWARE_DIR "firmware-$${PACKAGE_LBL}" ; !define PRODUCT_VERSION "0.0.0.0" -; !define FILE_VERSION "0.0.0.0" -; !define BUILD_DESCRIPTION "Unknown revision." - !include "${GCS_BUILD_TREE}\${WINX86_PATH}\openpilotgcs.nsh" +; !define FILE_VERSION "${TAG_OR_BRANCH}:${HASH8} ${DATETIME}" +; !define BUILD_DESCRIPTION "${TAG_OR_BRANCH}:${HASH8} built using ${ORIGIN} as origin, committed ${DATETIME} as ${HASH}" + !include "${GCS_BUILD_TREE}\openpilotgcs.nsh" Name "${PRODUCT_NAME}" - OutFile "${GCS_BUILD_TREE}\${WINX86_PATH}\${OUT_FILE}" + OutFile "${PACKAGE_DIR}\${OUT_FILE}" VIProductVersion ${PRODUCT_VERSION} VIAddVersionKey "ProductName" "${INSTALLER_NAME}" @@ -149,6 +152,8 @@ Section "Core files" InSecCore SectionIn RO SetOutPath "$INSTDIR\bin" File /r "${GCS_BUILD_TREE}\bin\*" + SetOutPath "$INSTDIR" + File "${PROJECT_ROOT}\HISTORY.txt" SectionEnd Section "Plugins" InSecPlugins @@ -178,7 +183,15 @@ SectionEnd Section "Localization" InSecLocalization SetOutPath "$INSTDIR\share\openpilotgcs\translations" - File /r "${GCS_BUILD_TREE}\share\openpilotgcs\translations\*.qm" +; File /r "${GCS_BUILD_TREE}\share\openpilotgcs\translations\openpilotgcs_*.qm" + File /r "${GCS_BUILD_TREE}\share\openpilotgcs\translations\qt_*.qm" +SectionEnd + +Section "Firmware" InSecFirmware +; SetOutPath "$INSTDIR\firmware\${FIRMWARE_DIR}" +; File /r "${PACKAGE_DIR}\${FIRMWARE_DIR}\*" + SetOutPath "$INSTDIR\firmware" + File /r "${PACKAGE_DIR}\${FIRMWARE_DIR}\fw_coptercontrol-${PACKAGE_LBL}.opfw" SectionEnd Section "Shortcuts" InSecShortcuts @@ -187,6 +200,14 @@ Section "Shortcuts" InSecShortcuts CreateDirectory "$SMPROGRAMS\OpenPilot" CreateShortCut "$SMPROGRAMS\OpenPilot\OpenPilot GCS.lnk" "$INSTDIR\bin\openpilotgcs.exe" \ "" "$INSTDIR\bin\openpilotgcs.exe" 0 "" "" "${PRODUCT_NAME} ${PRODUCT_VERSION}. ${BUILD_DESCRIPTION}" + CreateShortCut "$SMPROGRAMS\OpenPilot\OpenPilot ChangeLog.lnk" "$INSTDIR\HISTORY.txt" \ + "" "$INSTDIR\bin\openpilotgcs.exe" 0 + CreateShortCut "$SMPROGRAMS\OpenPilot\OpenPilot Website.lnk" "http://www.openpilot.org" \ + "" "$INSTDIR\bin\openpilotgcs.exe" 0 + CreateShortCut "$SMPROGRAMS\OpenPilot\OpenPilot Wiki.lnk" "http://wiki.openpilot.org" \ + "" "$INSTDIR\bin\openpilotgcs.exe" 0 + CreateShortCut "$SMPROGRAMS\OpenPilot\OpenPilot Forums.lnk" "http://forums.openpilot.org" \ + "" "$INSTDIR\bin\openpilotgcs.exe" 0 CreateShortCut "$DESKTOP\OpenPilot GCS.lnk" "$INSTDIR\bin\openpilotgcs.exe" \ "" "$INSTDIR\bin\openpilotgcs.exe" 0 "" "" "${PRODUCT_NAME} ${PRODUCT_VERSION}. ${BUILD_DESCRIPTION}" CreateShortCut "$SMPROGRAMS\OpenPilot\Uninstall.lnk" "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0 @@ -215,6 +236,7 @@ SectionEnd !insertmacro MUI_DESCRIPTION_TEXT ${InSecResources} $(DESC_InSecResources) !insertmacro MUI_DESCRIPTION_TEXT ${InSecSounds} $(DESC_InSecSounds) !insertmacro MUI_DESCRIPTION_TEXT ${InSecLocalization} $(DESC_InSecLocalization) + !insertmacro MUI_DESCRIPTION_TEXT ${InSecFirmware} $(DESC_InSecFirmware) !insertmacro MUI_DESCRIPTION_TEXT ${InSecShortcuts} $(DESC_InSecShortcuts) !insertmacro MUI_FUNCTION_DESCRIPTION_END @@ -235,6 +257,8 @@ Section "un.OpenPilot GCS" UnSecProgram RMDir /r /rebootok "$INSTDIR\bin" RMDir /r /rebootok "$INSTDIR\lib" RMDir /r /rebootok "$INSTDIR\share" + RMDir /r /rebootok "$INSTDIR\firmware" + Delete /rebootok "$INSTDIR\HISTORY.txt" Delete /rebootok "$INSTDIR\Uninstall.exe" ; Remove directory diff --git a/package/winx86/openpilotgcs.tpl b/package/winx86/openpilotgcs.tpl new file mode 100644 index 000000000..bb0adc452 --- /dev/null +++ b/package/winx86/openpilotgcs.tpl @@ -0,0 +1,23 @@ +# +# ***************************************************************************** +# +# @file ${OUTFILENAME} +# @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. +# @brief Autogenerated NSIS header file, built using template +# ${TEMPLATE} +# +# @see The GNU Public License (GPL) Version 3 +# +# ***************************************************************************** +# + +; Some names, paths and constants +!define PACKAGE_LBL "${DATE}-${TAG_OR_HASH8}${DIRTY}" +!define PACKAGE_DIR "..\..\build\package-$${PACKAGE_LBL}" +!define OUT_FILE "OpenPilot-$${PACKAGE_LBL}-install.exe" +!define FIRMWARE_DIR "firmware-$${PACKAGE_LBL}" + +; Installer version info +!define PRODUCT_VERSION "0.0.0.0" +!define FILE_VERSION "${TAG_OR_BRANCH}:${HASH8}${DIRTY} ${DATETIME}" +!define BUILD_DESCRIPTION "${TAG_OR_BRANCH}:${HASH8}${DIRTY} built using ${ORIGIN} as origin, committed ${DATETIME} as ${HASH}" diff --git a/ground/openpilotgcs/packaging/winx86/resources/header.bmp b/package/winx86/resources/header.bmp similarity index 100% rename from ground/openpilotgcs/packaging/winx86/resources/header.bmp rename to package/winx86/resources/header.bmp diff --git a/ground/openpilotgcs/packaging/winx86/resources/openpilot.ico b/package/winx86/resources/openpilot.ico similarity index 100% rename from ground/openpilotgcs/packaging/winx86/resources/openpilot.ico rename to package/winx86/resources/openpilot.ico diff --git a/ground/openpilotgcs/packaging/winx86/resources/welcome.bmp b/package/winx86/resources/welcome.bmp similarity index 100% rename from ground/openpilotgcs/packaging/winx86/resources/welcome.bmp rename to package/winx86/resources/welcome.bmp diff --git a/ground/openpilotgcs/packaging/winx86/translations/languages.nsh b/package/winx86/translations/languages.nsh similarity index 100% rename from ground/openpilotgcs/packaging/winx86/translations/languages.nsh rename to package/winx86/translations/languages.nsh diff --git a/ground/openpilotgcs/packaging/winx86/translations/strings_de.nsh b/package/winx86/translations/strings_de.nsh similarity index 94% rename from ground/openpilotgcs/packaging/winx86/translations/strings_de.nsh rename to package/winx86/translations/strings_de.nsh index 8722192aa..8a0f3d6fa 100644 --- a/ground/openpilotgcs/packaging/winx86/translations/strings_de.nsh +++ b/package/winx86/translations/strings_de.nsh @@ -30,6 +30,7 @@ LangString DESC_InSecResources ${LANG_GERMAN} "GCS Resourcen (Diagramme, Ziffernblätter, Kartensymbole, 3d-Modelle, PFD)." LangString DESC_InSecSounds ${LANG_GERMAN} "GCS Sounddateien (benötigt für akustische Ereignisbenachrichtigungen)." LangString DESC_InSecLocalization ${LANG_GERMAN} "GCS Lokalisierung (für unterstützte Sprachen)." + LangString DESC_InSecFirmware ${LANG_GERMAN} "OpenPilot firmware binaries." LangString DESC_InSecShortcuts ${LANG_GERMAN} "Installiere Verknüpfungen unter Startmenü->Anwendungen." ;-------------------------------- diff --git a/ground/openpilotgcs/packaging/winx86/translations/strings_en.nsh b/package/winx86/translations/strings_en.nsh similarity index 93% rename from ground/openpilotgcs/packaging/winx86/translations/strings_en.nsh rename to package/winx86/translations/strings_en.nsh index 224e018b7..3e0fbb401 100644 --- a/ground/openpilotgcs/packaging/winx86/translations/strings_en.nsh +++ b/package/winx86/translations/strings_en.nsh @@ -30,6 +30,7 @@ LangString DESC_InSecResources ${LANG_ENGLISH} "GCS resources (diagrams, dials, mapicons, 3d-models, PFD)." LangString DESC_InSecSounds ${LANG_ENGLISH} "GCS sound files (used for audible event notifications)." LangString DESC_InSecLocalization ${LANG_ENGLISH} "GCS localization (for supported languages)." + LangString DESC_InSecFirmware ${LANG_ENGLISH} "OpenPilot firmware binaries." LangString DESC_InSecShortcuts ${LANG_ENGLISH} "Install application start menu shortcuts." ;-------------------------------- diff --git a/ground/openpilotgcs/packaging/winx86/translations/strings_es.nsh b/package/winx86/translations/strings_es.nsh similarity index 94% rename from ground/openpilotgcs/packaging/winx86/translations/strings_es.nsh rename to package/winx86/translations/strings_es.nsh index 12bc8c920..aa43b06bd 100644 --- a/ground/openpilotgcs/packaging/winx86/translations/strings_es.nsh +++ b/package/winx86/translations/strings_es.nsh @@ -30,6 +30,7 @@ LangString DESC_InSecResources ${LANG_SPANISH} "Recursos del GCS (diagramas, marcadores, iconos del mapa, modelos, PFD)." LangString DESC_InSecSounds ${LANG_SPANISH} "Archivos de sonido del GCS (usados para los eventos y notificaciones audibles)." LangString DESC_InSecLocalization ${LANG_SPANISH} "Localización GCS (idiomas soportados)." + LangString DESC_InSecFirmware ${LANG_SPANISH} "OpenPilot firmware binaries." LangString DESC_InSecShortcuts ${LANG_SPANISH} "Instalar accesos directos de la aplicación (menú inicio y escritorio)." ;-------------------------------- diff --git a/ground/openpilotgcs/packaging/winx86/translations/strings_fr.nsh b/package/winx86/translations/strings_fr.nsh similarity index 94% rename from ground/openpilotgcs/packaging/winx86/translations/strings_fr.nsh rename to package/winx86/translations/strings_fr.nsh index 4c14b50aa..7c831590c 100644 --- a/ground/openpilotgcs/packaging/winx86/translations/strings_fr.nsh +++ b/package/winx86/translations/strings_fr.nsh @@ -30,6 +30,7 @@ LangString DESC_InSecResources ${LANG_FRENCH} "Ressources GCS (diagrammes, cadrans, modèles 3d, PFD)." LangString DESC_InSecSounds ${LANG_FRENCH} "Fichiers son GCS (pour les notifications sonores)." LangString DESC_InSecLocalization ${LANG_FRENCH} "Fichiers de localisation (langues supportées)." + LangString DESC_InSecFirmware ${LANG_FRENCH} "OpenPilot firmware binaries." LangString DESC_InSecShortcuts ${LANG_FRENCH} "Installer les raccourcis dans le menu démarrer." ;-------------------------------- diff --git a/ground/openpilotgcs/packaging/winx86/translations/strings_ru.nsh b/package/winx86/translations/strings_ru.nsh similarity index 94% rename from ground/openpilotgcs/packaging/winx86/translations/strings_ru.nsh rename to package/winx86/translations/strings_ru.nsh index c6bc6e557..4b5a380dd 100644 --- a/ground/openpilotgcs/packaging/winx86/translations/strings_ru.nsh +++ b/package/winx86/translations/strings_ru.nsh @@ -30,6 +30,7 @@ LangString DESC_InSecResources ${LANG_RUSSIAN} "Ресурсы GCS (диаграммы, приборы, пиктограммы, 3d-модели, PFD)." LangString DESC_InSecSounds ${LANG_RUSSIAN} "Звуковые файлы (используются для звуковых уведомлений о событиях)." LangString DESC_InSecLocalization ${LANG_RUSSIAN} "Файлы языковой поддержки (для поддерживаемых языков)." + LangString DESC_InSecFirmware ${LANG_RUSSIAN} "Файлы прошивок OpenPilot." LangString DESC_InSecShortcuts ${LANG_RUSSIAN} "Установка ярлыков для приложения." ;-------------------------------- diff --git a/ground/openpilotgcs/packaging/winx86/translations/strings_zh_CN.nsh b/package/winx86/translations/strings_zh_CN.nsh similarity index 94% rename from ground/openpilotgcs/packaging/winx86/translations/strings_zh_CN.nsh rename to package/winx86/translations/strings_zh_CN.nsh index 6cf4b9b12..5dad290a8 100644 --- a/ground/openpilotgcs/packaging/winx86/translations/strings_zh_CN.nsh +++ b/package/winx86/translations/strings_zh_CN.nsh @@ -30,6 +30,7 @@ LangString DESC_InSecResources ${LANG_TRADCHINESE} "地面站资源库(图表,地图,模型,PFD(主要飞行数据图))." LangString DESC_InSecSounds ${LANG_TRADCHINESE} "地面站音频文件(用于对于特定事件的提醒)." LangString DESC_InSecLocalization ${LANG_TRADCHINESE} "地面站本土化(适用于它所支持的语言)." + LangString DESC_InSecFirmware ${LANG_TRADCHINESE} "OpenPilot firmware binaries." LangString DESC_InSecShortcuts ${LANG_TRADCHINESE} "安装开始菜单的快捷方式." ;-------------------------------- diff --git a/shared/uavobjectdefinition/accessorydesired.xml b/shared/uavobjectdefinition/accessorydesired.xml new file mode 100644 index 000000000..d0a7b0ed8 --- /dev/null +++ b/shared/uavobjectdefinition/accessorydesired.xml @@ -0,0 +1,10 @@ + + + Desired Auxillary actuator settings. Comes from @ref ManualControlModule. + + + + + + + diff --git a/shared/uavobjectdefinition/attitudesettings.xml b/shared/uavobjectdefinition/attitudesettings.xml index 085c1a123..677493d68 100644 --- a/shared/uavobjectdefinition/attitudesettings.xml +++ b/shared/uavobjectdefinition/attitudesettings.xml @@ -2,12 +2,14 @@ Settings for the @ref Attitude module used on CopterControl - + + - + - + + diff --git a/shared/uavobjectdefinition/cameradesired.xml b/shared/uavobjectdefinition/cameradesired.xml new file mode 100644 index 000000000..022728f7e --- /dev/null +++ b/shared/uavobjectdefinition/cameradesired.xml @@ -0,0 +1,12 @@ + + + Desired camera outputs. Comes from @ref CameraStabilization module. + + + + + + + + + diff --git a/shared/uavobjectdefinition/camerastabsettings.xml b/shared/uavobjectdefinition/camerastabsettings.xml new file mode 100644 index 000000000..09199b77a --- /dev/null +++ b/shared/uavobjectdefinition/camerastabsettings.xml @@ -0,0 +1,12 @@ + + + Settings for the @ref CameraStab mmodule + + + + + + + + + diff --git a/shared/uavobjectdefinition/hwsettings.xml b/shared/uavobjectdefinition/hwsettings.xml new file mode 100644 index 000000000..63c2a745a --- /dev/null +++ b/shared/uavobjectdefinition/hwsettings.xml @@ -0,0 +1,12 @@ + + + Selection of optional hardware configurations. + + + + + + + + + diff --git a/shared/uavobjectdefinition/manualcontrolcommand.xml b/shared/uavobjectdefinition/manualcontrolcommand.xml index 58d6d9330..ef74c2576 100644 --- a/shared/uavobjectdefinition/manualcontrolcommand.xml +++ b/shared/uavobjectdefinition/manualcontrolcommand.xml @@ -6,11 +6,7 @@ - - - - - + diff --git a/shared/uavobjectdefinition/manualcontrolsettings.xml b/shared/uavobjectdefinition/manualcontrolsettings.xml index 63488deee..bfd692f91 100644 --- a/shared/uavobjectdefinition/manualcontrolsettings.xml +++ b/shared/uavobjectdefinition/manualcontrolsettings.xml @@ -1,25 +1,25 @@ Settings to indicate how to decode receiver input by @ref ManualControlModule. - - - - - - + + + + + + + - - + - - - - + + + + - + diff --git a/shared/uavobjectdefinition/mixersettings.xml b/shared/uavobjectdefinition/mixersettings.xml index efe48d090..e070814c5 100644 --- a/shared/uavobjectdefinition/mixersettings.xml +++ b/shared/uavobjectdefinition/mixersettings.xml @@ -5,23 +5,24 @@ - + + - + - + - + - + - + - + - + - + diff --git a/shared/uavobjectdefinition/stabilizationdesired.xml b/shared/uavobjectdefinition/stabilizationdesired.xml index c3bda9a2b..c1e013be3 100644 --- a/shared/uavobjectdefinition/stabilizationdesired.xml +++ b/shared/uavobjectdefinition/stabilizationdesired.xml @@ -6,7 +6,7 @@ - + diff --git a/shared/uavobjectdefinition/stabilizationsettings.xml b/shared/uavobjectdefinition/stabilizationsettings.xml index bc339fdcd..653c7cce8 100644 --- a/shared/uavobjectdefinition/stabilizationsettings.xml +++ b/shared/uavobjectdefinition/stabilizationsettings.xml @@ -7,13 +7,23 @@ - - - + + + - + + + + + + + + + + + diff --git a/shared/uavobjectdefinition/systemsettings.xml b/shared/uavobjectdefinition/systemsettings.xml index c8342a753..22c0e8fd4 100644 --- a/shared/uavobjectdefinition/systemsettings.xml +++ b/shared/uavobjectdefinition/systemsettings.xml @@ -1,10 +1,11 @@ - - - Select airframe type. Currently used by @ref ActuatorModule to choose mixing from @ref ActuatorDesired to @ref ActuatorCommand - - - - - - - + + + Select airframe type. Currently used by @ref ActuatorModule to choose mixing from @ref ActuatorDesired to @ref ActuatorCommand + + + + + + + + diff --git a/shared/uavobjectdefinition/systemstats.xml b/shared/uavobjectdefinition/systemstats.xml index a34541858..3e6bc1547 100644 --- a/shared/uavobjectdefinition/systemstats.xml +++ b/shared/uavobjectdefinition/systemstats.xml @@ -3,6 +3,7 @@ CPU and memory usage from OpenPilot computer. +