1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-20 10:54:14 +01:00

Merge branch 'next' into abeck/OP-1760-autotakeoff-squashed

This commit is contained in:
abeck70 2015-04-19 17:52:35 +10:00
commit 1e9bd43871
31 changed files with 1320 additions and 585 deletions

169
Makefile
View File

@ -49,6 +49,8 @@ export BUILD_DIR := $(ROOT_DIR)/build
export PACKAGE_DIR := $(ROOT_DIR)/build/package
export DIST_DIR := $(ROOT_DIR)/build/dist
DIRS = $(DL_DIR) $(TOOLS_DIR) $(BUILD_DIR) $(PACKAGE_DIR) $(DIST_DIR)
# Set up default build configurations (debug | release)
GCS_BUILD_CONF := release
UAVOGEN_BUILD_CONF := release
@ -140,20 +142,6 @@ all_clean:
.PONY: clean
clean: all_clean
$(DL_DIR):
$(MKDIR) -p $@
$(TOOLS_DIR):
$(MKDIR) -p $@
$(BUILD_DIR):
$(MKDIR) -p $@
$(PACKAGE_DIR):
$(MKDIR) -p $@
$(DIST_DIR):
$(MKDIR) -p $@
##############################
#
@ -167,10 +155,12 @@ else
UAVOGEN_SILENT := silent
endif
UAVOBJGENERATOR_DIR = $(BUILD_DIR)/uavobjgenerator
DIRS += $(UAVOBJGENERATOR_DIR)
.PHONY: uavobjgenerator
uavobjgenerator:
$(V1) $(MKDIR) -p $(BUILD_DIR)/$@
$(V1) ( cd $(BUILD_DIR)/$@ && \
uavobjgenerator: | $(UAVOBJGENERATOR_DIR)
$(V1) ( cd $(UAVOBJGENERATOR_DIR) && \
$(QMAKE) $(ROOT_DIR)/ground/uavobjgenerator/uavobjgenerator.pro -spec $(QT_SPEC) -r CONFIG+="$(UAVOGEN_BUILD_CONF) $(UAVOGEN_SILENT)" && \
$(MAKE) --no-print-directory -w ; \
)
@ -183,8 +173,7 @@ uavobjects: $(addprefix uavobjects_, $(UAVOBJ_TARGETS))
UAVOBJ_XML_DIR := $(ROOT_DIR)/shared/uavobjectdefinition
UAVOBJ_OUT_DIR := $(BUILD_DIR)/uavobject-synthetics
$(UAVOBJ_OUT_DIR):
$(V1) $(MKDIR) -p $@
DIRS += $(UAVOBJ_OUT_DIR)
uavobjects_%: $(UAVOBJ_OUT_DIR) uavobjgenerator
$(V1) ( cd $(UAVOBJ_OUT_DIR) && \
@ -214,6 +203,8 @@ export OPUAVTALK := $(ROOT_DIR)/flight/uavtalk
export OPUAVSYNTHDIR := $(BUILD_DIR)/uavobject-synthetics/flight
export OPGCSSYNTHDIR := $(BUILD_DIR)/openpilotgcs-synthetics
DIRS += $(OPGCSSYNTHDIR)
# Define supported board lists
ALL_BOARDS := coptercontrol oplinkmini revolution osd revoproto simposix discoveryf4bare gpsplatinum
@ -225,7 +216,7 @@ osd_short := 'osd '
revoproto_short := 'revp'
simposix_short := 'posx'
discoveryf4bare_short := 'df4b'
gpsplatinum_short := 'gps9 '
gpsplatinum_short := 'gps9'
# SimPosix only builds on Linux so drop it from the list for
# all other platforms.
@ -460,8 +451,9 @@ sim_osx_%: uavobjects_flight
all_ground: openpilotgcs uploader
# Convenience target for the GCS
.PHONY: gcs gcs_clean
.PHONY: gcs gcs_qmake gcs_clean
gcs: openpilotgcs
gcs_qmake: openpilotgcs_qmake
gcs_clean: openpilotgcs_clean
ifeq ($(V), 1)
@ -470,32 +462,25 @@ else
GCS_SILENT := silent
endif
.NOTPARALLEL:
.PHONY: openpilotgcs
openpilotgcs: uavobjects_gcs openpilotgcs_qmake openpilotgcs_make
OPENPILOTGCS_DIR := $(BUILD_DIR)/openpilotgcs_$(GCS_BUILD_CONF)
DIRS += $(OPENPILOTGCS_DIR)
OPENPILOTGCS_MAKEFILE := $(OPENPILOTGCS_DIR)/Makefile
.PHONY: openpilotgcs_qmake
openpilotgcs_qmake:
ifeq ($(QMAKE_SKIP),)
$(V1) $(MKDIR) -p $(BUILD_DIR)/openpilotgcs_$(GCS_BUILD_CONF)
$(V1) ( cd $(BUILD_DIR)/openpilotgcs_$(GCS_BUILD_CONF) && \
openpilotgcs_qmake $(OPENPILOTGCS_MAKEFILE): | $(OPENPILOTGCS_DIR)
$(V1) ( cd $(OPENPILOTGCS_DIR) && \
$(QMAKE) $(ROOT_DIR)/ground/openpilotgcs/openpilotgcs.pro -spec $(QT_SPEC) -r CONFIG+="$(GCS_BUILD_CONF) $(GCS_SILENT)" $(GCS_QMAKE_OPTS) \
)
else
@$(ECHO) "skipping qmake"
endif
.PHONY: openpilotgcs_make
openpilotgcs_make:
$(V1) $(MKDIR) -p $(BUILD_DIR)/openpilotgcs_$(GCS_BUILD_CONF)
$(V1) ( cd $(BUILD_DIR)/openpilotgcs_$(GCS_BUILD_CONF)/$(MAKE_DIR) && \
$(MAKE) -w ; \
)
.PHONY: openpilotgcs
openpilotgcs: uavobjects_gcs $(OPENPILOTGCS_MAKEFILE)
$(V1) $(MAKE) -w -C $(OPENPILOTGCS_DIR)/$(MAKE_DIR);
.PHONY: openpilotgcs_clean
openpilotgcs_clean:
@$(ECHO) " CLEAN $(call toprel, $(BUILD_DIR)/openpilotgcs_$(GCS_BUILD_CONF))"
$(V1) [ ! -d "$(BUILD_DIR)/openpilotgcs_$(GCS_BUILD_CONF)" ] || $(RM) -r "$(BUILD_DIR)/openpilotgcs_$(GCS_BUILD_CONF)"
@$(ECHO) " CLEAN $(call toprel, $(OPENPILOTGCS_DIR))"
$(V1) [ ! -d "$(OPENPILOTGCS_DIR)" ] || $(RM) -r "$(OPENPILOTGCS_DIR)"
################################
#
@ -503,77 +488,27 @@ openpilotgcs_clean:
#
################################
.NOTPARALLEL:
.PHONY: uploader
uploader: uploader_qmake uploader_make
UPLOADER_DIR := $(BUILD_DIR)/uploader_$(GCS_BUILD_CONF)
DIRS += $(UPLOADER_DIR)
UPLOADER_MAKEFILE := $(UPLOADER_DIR)/Makefile
.PHONY: uploader_qmake
uploader_qmake:
ifeq ($(QMAKE_SKIP),)
$(V1) $(MKDIR) -p $(BUILD_DIR)/uploader_$(GCS_BUILD_CONF)
$(V1) ( cd $(BUILD_DIR)/uploader_$(GCS_BUILD_CONF) && \
uploader_qmake $(UPLOADER_MAKEFILE): | $(UPLOADER_DIR)
$(V1) ( cd $(UPLOADER_DIR) && \
$(QMAKE) $(ROOT_DIR)/ground/openpilotgcs/src/experimental/USB_UPLOAD_TOOL/upload.pro -spec $(QT_SPEC) -r CONFIG+="$(GCS_BUILD_CONF) $(GCS_SILENT)" $(GCS_QMAKE_OPTS) \
)
else
@$(ECHO) "skipping qmake"
endif
.PHONY: uploader_make
uploader_make:
$(V1) $(MKDIR) -p $(BUILD_DIR)/uploader_$(GCS_BUILD_CONF)
$(V1) ( cd $(BUILD_DIR)/uploader_$(GCS_BUILD_CONF)/$(MAKE_DIR) && \
$(MAKE) -w ; \
)
.PHONY: uploader
uploader: $(UPLOADER_MAKEFILE)
$(V1) $(MAKE) -w -C $(UPLOADER_DIR)
.PHONY: uploader_clean
uploader_clean:
@$(ECHO) " CLEAN $(call toprel, $(BUILD_DIR)/uploader_$(GCS_BUILD_CONF))"
$(V1) [ ! -d "$(BUILD_DIR)/uploader_$(GCS_BUILD_CONF)" ] || $(RM) -r "$(BUILD_DIR)/uploader_$(GCS_BUILD_CONF)"
@$(ECHO) " CLEAN $(call toprel, $(UPLOADER_DIR))"
$(V1) [ ! -d "$(UPLOADER_DIR)" ] || $(RM) -r "$(UPLOADER_DIR)"
################################
#
# Android GCS related components
#
################################
# Build the output directory for the Android GCS build
ANDROIDGCS_OUT_DIR := $(BUILD_DIR)/androidgcs
$(ANDROIDGCS_OUT_DIR):
$(V1) $(MKDIR) -p $@
# Build the asset directory for the android assets
ANDROIDGCS_ASSETS_DIR := $(ANDROIDGCS_OUT_DIR)/assets
$(ANDROIDGCS_ASSETS_DIR)/uavos:
$(V1) $(MKDIR) -p $@
ifeq ($(V), 1)
ANT_QUIET :=
ANDROID_SILENT :=
else
ANT_QUIET := -q
ANDROID_SILENT := -s
endif
.PHONY: androidgcs
androidgcs: uavo-collections_java
$(V0) @$(ECHO) " ANDROID $(call toprel, $(ANDROIDGCS_OUT_DIR))"
$(V1) $(MKDIR) -p $(ANDROIDGCS_OUT_DIR)
$(V1) $(ANDROID) $(ANDROID_SILENT) update project \
--target "Google Inc.:Google APIs:$(GOOGLE_API_VERSION)" \
--name androidgcs \
--path ./androidgcs
$(V1) $(ANT) -f ./androidgcs/build.xml \
$(ANT_QUIET) \
-Dout.dir="../$(call toprel, $(ANDROIDGCS_OUT_DIR)/bin)" \
-Dgen.absolute.dir="$(ANDROIDGCS_OUT_DIR)/gen" \
$(ANDROIDGCS_BUILD_CONF)
.PHONY: androidgcs_clean
androidgcs_clean:
@$(ECHO) " CLEAN $(call toprel, $(ANDROIDGCS_OUT_DIR))"
$(V1) [ ! -d "$(ANDROIDGCS_OUT_DIR)" ] || $(RM) -r "$(ANDROIDGCS_OUT_DIR)"
# We want to take snapshots of the UAVOs at each point that they change
# to allow the GCS to be compatible with as many versions as possible.
# We always include a pseudo collection called "srctree" which represents
@ -695,8 +630,7 @@ ALL_UNITTESTS := logfs math lednotification
# Build the directory for the unit tests
UT_OUT_DIR := $(BUILD_DIR)/unit_tests
$(UT_OUT_DIR):
$(V1) $(MKDIR) -p $@
DIRS += $(UT_OUT_DIR)
.PHONY: all_ut
all_ut: $(addsuffix _elf, $(addprefix ut_, $(ALL_UNITTESTS)))
@ -771,9 +705,8 @@ OPFW_CONTENTS := \
.PHONY: opfw_resource
opfw_resource: $(OPFW_RESOURCE)
$(OPFW_RESOURCE): $(FW_TARGETS)
$(OPFW_RESOURCE): $(FW_TARGETS) | $(OPGCSSYNTHDIR)
@$(ECHO) Generating OPFW resource file $(call toprel, $@)
$(V1) $(MKDIR) -p $(dir $@)
$(V1) $(ECHO) $(QUOTE)$(OPFW_CONTENTS)$(QUOTE) > $@
# If opfw_resource or all firmware are requested, GCS should depend on the resource
@ -864,9 +797,8 @@ docs_all_clean:
##############################
.PHONY: build-info
build-info:
build-info: | $(BUILD_DIR)
@$(ECHO) " BUILD-INFO $(call toprel, $(BUILD_DIR)/$@.txt)"
$(V1) $(MKDIR) -p $(BUILD_DIR)
$(V1) $(VERSION_INFO) \
--uavodir=$(ROOT_DIR)/shared/uavobjectdefinition \
--template="make/templates/$@.txt" \
@ -895,6 +827,17 @@ $(DIST_NAME).gz: $(DIST_VER_INFO) .git/index | $(DIST_DIR)
.PHONY: dist
dist: $(DIST_NAME).gz
##############################
#
# Directories
#
##############################
$(DIRS):
$(V1) $(MKDIR) -p $@
##############################
#
# Help message, the default Makefile goal
@ -928,7 +871,6 @@ help:
@$(ECHO) " openocd_install - Install the OpenOCD JTAG daemon"
@$(ECHO) " stm32flash_install - Install the stm32flash tool for unbricking F1-based boards"
@$(ECHO) " dfuutil_install - Install the dfu-util tool for unbricking F4-based boards"
@$(ECHO) " android_sdk_install - Install the Android SDK tools"
@$(ECHO) " Install all available tools:"
@$(ECHO) " all_sdk_install - Install all of above (platform-dependent)"
@$(ECHO) " build_sdk_install - Install only essential for build tools (platform-dependent)"
@ -1000,26 +942,19 @@ help:
@$(ECHO)
@$(ECHO) " [GCS]"
@$(ECHO) " gcs - Build the Ground Control System (GCS) application (debug|release)"
@$(ECHO) " Skip qmake: QMAKE_SKIP=1"
@$(ECHO) " Compile specific directory: MAKE_DIR=<dir>"
@$(ECHO) " Example: make gcs QMAKE_SKIP=1 MAKE_DIR=src/plugins/coreplugin"
@$(ECHO) " Example: make gcs MAKE_DIR=src/plugins/coreplugin"
@$(ECHO) " gcs_qmake - Run qmake for the Ground Control System (GCS) application (debug|release)"
@$(ECHO) " gcs_clean - Remove the Ground Control System (GCS) application (debug|release)"
@$(ECHO) " Supported build configurations: GCS_BUILD_CONF=debug|release (default is $(GCS_BUILD_CONF))"
@$(ECHO)
@$(ECHO) " [Uploader Tool]"
@$(ECHO) " uploader - Build the serial uploader tool (debug|release)"
@$(ECHO) " Skip qmake: QMAKE_SKIP=1"
@$(ECHO) " Example: make uploader QMAKE_SKIP=1"
@$(ECHO) " uploader_qmake - Run qmake for the serial uploader tool (debug|release)"
@$(ECHO) " uploader_clean - Remove the serial uploader tool (debug|release)"
@$(ECHO) " Supported build configurations: GCS_BUILD_CONF=debug|release (default is $(GCS_BUILD_CONF))"
@$(ECHO)
@$(ECHO)
@$(ECHO) " [AndroidGCS]"
@$(ECHO) " androidgcs - Build the Android Ground Control System (GCS) application"
@$(ECHO) " androidgcs_install - Use ADB to install the Android GCS application"
@$(ECHO) " androidgcs_run - Run the Android GCS application"
@$(ECHO) " androidgcs_clean - Remove the Android GCS application"
@$(ECHO)
@$(ECHO) " [UAVObjects]"
@$(ECHO) " uavobjects - Generate source files from the UAVObject definition XML files"
@$(ECHO) " uavobjects_test - Parse xml-files - check for valid, duplicate ObjId's, ..."

View File

@ -9,7 +9,7 @@
* @{
*
* @file telemetry.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015.
* @brief Telemetry module, handles telemetry and UAVObject updates
* @see The GNU Public License (GPL) Version 3
*
@ -30,6 +30,34 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Telemetry uses four tasks. Two are created for the main telemetry
* stream called "TelTx" and "TelRx". Two are created to handle the OPLink
* radio connection, called "RadioTx" and "RadioRx", the latter being
* overridden by USB if connected.
*
* The following code uses a "local" prefix to refer to the telemetry channel
* associated with a port on the FC and a "radio" prefix to refer to the
* telemetry channel associated with the OPLink/USB.
*
* The "local" telemetry port to use is defined by PIOS_COM_TELEM_RF in
* PIOS_Board_Init().
*
* A UAVTalk connection instance, telemUavTalkCon, is associated with the
* "local" channel and another, radioUavTalkCon, with the "radio" channel.
* Associated with each instance is a transmit routine which will send data
* to the appropriate port.
*
* Data is passed on the telemetry channels using queues. If
* PIOS_TELEM_PRIORITY_QUEUE is defined then two queues are created, one normal
* priority and the other high priority.
*
* The "Tx" tasks read events first from the priority queue and then from
* the normal queue, passing each event to processObjEvent() which ultimately
* passes each event to the UAVTalk library which results in the appropriate
* transmit routine being called to send the data back to the recipient on
* the "local" or "radio" link.
*/
#include <openpilot.h>
#include "telemetry.h"
@ -53,62 +81,74 @@
#ifdef PIOS_TELEM_RADIO_RX_STACK_SIZE
#define STACK_SIZE_RADIO_RX_BYTES PIOS_TELEM_RADIO_RX_STACK_SIZE
#define STACK_SIZE_RADIO_TX_BYTES PIOS_TELEM_RADIO_TX_STACK_SIZE
#else
#define STACK_SIZE_RADIO_RX_BYTES STACK_SIZE_RX_BYTES
#define STACK_SIZE_RADIO_TX_BYTES STACK_SIZE_TX_BYTES
#endif
#define TASK_PRIORITY_RX (tskIDLE_PRIORITY + 2)
#define TASK_PRIORITY_TX (tskIDLE_PRIORITY + 2)
#define TASK_PRIORITY_RADRX (tskIDLE_PRIORITY + 2)
#define TASK_PRIORITY_RADTX (tskIDLE_PRIORITY + 2)
#define REQ_TIMEOUT_MS 250
#define MAX_RETRIES 2
#define STATS_UPDATE_PERIOD_MS 4000
#define CONNECTION_TIMEOUT_MS 8000
// Private types
typedef struct {
// Determine port on which to communicate telemetry information
uint32_t (*getPort)();
// Main telemetry queue
xQueueHandle queue;
#ifdef PIOS_TELEM_PRIORITY_QUEUE
// Priority telemetry queue
xQueueHandle priorityQueue;
#endif /* PIOS_TELEM_PRIORITY_QUEUE */
// Transmit/receive task handles
xTaskHandle txTaskHandle;
xTaskHandle rxTaskHandle;
// Telemetry stream
UAVTalkConnection uavTalkCon;
} channelContext;
// Private variables
static uint32_t telemetryPort;
#ifdef PIOS_INCLUDE_RFM22B
static uint32_t radioPort;
#endif
static xQueueHandle queue;
// Main telemetry channel
static channelContext localChannel;
static int32_t transmitLocalData(uint8_t *data, int32_t length);
static void registerLocalObject(UAVObjHandle obj);
static uint32_t localPort();
#if defined(PIOS_TELEM_PRIORITY_QUEUE)
static xQueueHandle priorityQueue;
#else
#define priorityQueue queue
#endif
// OPLink telemetry channel
static channelContext radioChannel;
static int32_t transmitRadioData(uint8_t *data, int32_t length);
static void registerRadioObject(UAVObjHandle obj);
static uint32_t radioPort();
static xTaskHandle telemetryTxTaskHandle;
static xTaskHandle telemetryRxTaskHandle;
#ifdef PIOS_INCLUDE_RFM22B
static xTaskHandle radioRxTaskHandle;
#endif
// Telemetry stats
static uint32_t txErrors;
static uint32_t txRetries;
static uint32_t timeOfLastObjectUpdate;
static UAVTalkConnection uavTalkCon;
#ifdef PIOS_INCLUDE_RFM22B
static UAVTalkConnection radioUavTalkCon;
#endif
// Private functions
static void telemetryTxTask(void *parameters);
static void telemetryRxTask(void *parameters);
#ifdef PIOS_INCLUDE_RFM22B
static void radioRxTask(void *parameters);
static int32_t transmitRadioData(uint8_t *data, int32_t length);
#endif
static int32_t transmitData(uint8_t *data, int32_t length);
static void registerObject(UAVObjHandle obj);
static void updateObject(UAVObjHandle obj, int32_t eventType);
static int32_t setUpdatePeriod(UAVObjHandle obj, int32_t updatePeriodMs);
static int32_t setLoggingPeriod(UAVObjHandle obj, int32_t updatePeriodMs);
static void processObjEvent(UAVObjEvent *ev);
static void updateObject(
channelContext *channel,
UAVObjHandle obj,
int32_t eventType);
static void processObjEvent(
channelContext *channel,
UAVObjEvent *ev);
static int32_t setUpdatePeriod(
channelContext *channel,
UAVObjHandle obj,
int32_t updatePeriodMs);
static int32_t setLoggingPeriod(
channelContext *channel,
UAVObjHandle obj,
int32_t updatePeriodMs);
static void updateTelemetryStats();
static void gcsTelemetryStatsUpdated();
static void updateSettings();
static uint32_t getComPort(bool input);
static void updateSettings(channelContext *channel);
/**
* Initialise the telemetry module
@ -117,28 +157,94 @@ static uint32_t getComPort(bool input);
*/
int32_t TelemetryStart(void)
{
// Process all registered objects and connect queue for updates
UAVObjIterate(&registerObject);
// Only start the local telemetry tasks if needed
if (localPort()) {
UAVObjIterate(&registerLocalObject);
// Listen to objects of interest
#ifdef PIOS_TELEM_PRIORITY_QUEUE
GCSTelemetryStatsConnectQueue(localChannel.priorityQueue);
#else /* PIOS_TELEM_PRIORITY_QUEUE */
GCSTelemetryStatsConnectQueue(localChannel.queue);
#endif /* PIOS_TELEM_PRIORITY_QUEUE */
// Start telemetry tasks
xTaskCreate(telemetryTxTask,
"TelTx",
STACK_SIZE_TX_BYTES / 4,
&localChannel,
TASK_PRIORITY_TX,
&localChannel.txTaskHandle);
PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_TELEMETRYTX,
localChannel.txTaskHandle);
xTaskCreate(telemetryRxTask,
"TelRx",
STACK_SIZE_RX_BYTES / 4,
&localChannel,
TASK_PRIORITY_RX,
&localChannel.rxTaskHandle);
PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_TELEMETRYRX,
localChannel.rxTaskHandle);
}
// Start the telemetry tasks associated with Radio/USB
UAVObjIterate(&registerRadioObject);
// Listen to objects of interest
GCSTelemetryStatsConnectQueue(priorityQueue);
#ifdef PIOS_TELEM_PRIORITY_QUEUE
GCSTelemetryStatsConnectQueue(radioChannel.priorityQueue);
#else /* PIOS_TELEM_PRIORITY_QUEUE */
GCSTelemetryStatsConnectQueue(radioChannel.queue);
#endif /* PIOS_TELEM_PRIORITY_QUEUE */
// Start telemetry tasks
xTaskCreate(telemetryTxTask, "TelTx", STACK_SIZE_TX_BYTES / 4, NULL, TASK_PRIORITY_TX, &telemetryTxTaskHandle);
PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_TELEMETRYTX, telemetryTxTaskHandle);
xTaskCreate(telemetryRxTask, "TelRx", STACK_SIZE_RX_BYTES / 4, NULL, TASK_PRIORITY_RX, &telemetryRxTaskHandle);
PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_TELEMETRYRX, telemetryRxTaskHandle);
#ifdef PIOS_INCLUDE_RFM22B
if (radioPort) {
xTaskCreate(radioRxTask, "RadioRx", STACK_SIZE_RADIO_RX_BYTES / 4, NULL, TASK_PRIORITY_RADRX, &radioRxTaskHandle);
PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_RADIORX, radioRxTaskHandle);
}
#endif
xTaskCreate(telemetryTxTask,
"RadioTx",
STACK_SIZE_RADIO_TX_BYTES / 4,
&radioChannel,
TASK_PRIORITY_RADTX,
&radioChannel.txTaskHandle);
PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_RADIOTX,
radioChannel.txTaskHandle);
xTaskCreate(telemetryRxTask,
"RadioRx",
STACK_SIZE_RADIO_RX_BYTES / 4,
&radioChannel,
TASK_PRIORITY_RADRX,
&radioChannel.rxTaskHandle);
PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_RADIORX,
radioChannel.rxTaskHandle);
return 0;
}
/* Intialise a telemetry channel */
void TelemetryInitializeChannel(channelContext *channel)
{
// Create object queues
channel->queue = xQueueCreate(MAX_QUEUE_SIZE,
sizeof(UAVObjEvent));
#if defined(PIOS_TELEM_PRIORITY_QUEUE)
channel->priorityQueue = xQueueCreate(MAX_QUEUE_SIZE,
sizeof(UAVObjEvent));
#endif /* PIOS_TELEM_PRIORITY_QUEUE */
// Initialise UAVTalk
channel->uavTalkCon = UAVTalkInitialize(&transmitLocalData);
// Create periodic event that will be used to update the telemetry stats
UAVObjEvent ev;
memset(&ev, 0, sizeof(UAVObjEvent));
#ifdef PIOS_TELEM_PRIORITY_QUEUE
EventPeriodicQueueCreate(&ev,
channel->priorityQueue,
STATS_UPDATE_PERIOD_MS);
#else /* PIOS_TELEM_PRIORITY_QUEUE */
EventPeriodicQueueCreate(&ev,
channel->queue,
STATS_UPDATE_PERIOD_MS);
#endif /* PIOS_TELEM_PRIORITY_QUEUE */
}
/**
* Initialise the telemetry module
* \return -1 if initialisation failed
@ -146,39 +252,37 @@ int32_t TelemetryStart(void)
*/
int32_t TelemetryInitialize(void)
{
HwSettingsInitialize();
FlightTelemetryStatsInitialize();
GCSTelemetryStatsInitialize();
// 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
// Update telemetry settings
telemetryPort = PIOS_COM_TELEM_RF;
#ifdef PIOS_INCLUDE_RFM22B
radioPort = PIOS_COM_RF;
#endif
HwSettingsInitialize();
updateSettings();
// Initialise UAVTalk
uavTalkCon = UAVTalkInitialize(&transmitData);
#ifdef PIOS_INCLUDE_RFM22B
radioUavTalkCon = UAVTalkInitialize(&transmitRadioData);
#endif
// Create periodic event that will be used to update the telemetry stats
// FIXME STATS_UPDATE_PERIOD_MS is 4000ms while FlighTelemetryStats update period is 5000ms...
// Reset link stats
txErrors = 0;
txRetries = 0;
UAVObjEvent ev;
memset(&ev, 0, sizeof(UAVObjEvent));
EventPeriodicQueueCreate(&ev, priorityQueue, STATS_UPDATE_PERIOD_MS);
// Set channel port handlers
localChannel.getPort = localPort;
radioChannel.getPort = radioPort;
// Set the local telemetry baud rate
updateSettings(&localChannel);
// Only initialise local channel if telemetry port enabled
if (localPort()) {
// Initialise channel
TelemetryInitializeChannel(&localChannel);
// Initialise UAVTalk
localChannel.uavTalkCon = UAVTalkInitialize(&transmitLocalData);
}
// Initialise channel
TelemetryInitializeChannel(&radioChannel);
// Initialise UAVTalk
radioChannel.uavTalkCon = UAVTalkInitialize(&transmitRadioData);
return 0;
}
@ -190,22 +294,51 @@ MODULE_INITCALL(TelemetryInitialize, TelemetryStart);
* telemetry settings.
* \param[in] obj Object to connect
*/
static void registerObject(UAVObjHandle obj)
static void registerLocalObject(UAVObjHandle obj)
{
if (UAVObjIsMetaobject(obj)) {
// Only connect change notifications for meta objects. No periodic updates
UAVObjConnectQueue(obj, priorityQueue, EV_MASK_ALL_UPDATES);
#ifdef PIOS_TELEM_PRIORITY_QUEUE
UAVObjConnectQueue(obj, localChannel.priorityQueue, EV_MASK_ALL_UPDATES);
#else /* PIOS_TELEM_PRIORITY_QUEUE */
UAVObjConnectQueue(obj, localChannel.queue, EV_MASK_ALL_UPDATES);
#endif /* PIOS_TELEM_PRIORITY_QUEUE */
} else {
// Setup object for periodic updates
updateObject(obj, EV_NONE);
updateObject(
&localChannel,
obj,
EV_NONE);
}
}
static void registerRadioObject(UAVObjHandle obj)
{
if (UAVObjIsMetaobject(obj)) {
// Only connect change notifications for meta objects. No periodic updates
#ifdef PIOS_TELEM_PRIORITY_QUEUE
UAVObjConnectQueue(obj, radioChannel.priorityQueue, EV_MASK_ALL_UPDATES);
#else /* PIOS_TELEM_PRIORITY_QUEUE */
UAVObjConnectQueue(obj, radioChannel.queue, EV_MASK_ALL_UPDATES);
#endif /* PIOS_TELEM_PRIORITY_QUEUE */
} else {
// Setup object for periodic updates
updateObject(
&radioChannel,
obj,
EV_NONE);
}
}
/**
* Update object's queue connections and timer, depending on object's settings
* \param[in] telemetry channel context
* \param[in] obj Object to updates
*/
static void updateObject(UAVObjHandle obj, int32_t eventType)
static void updateObject(
channelContext *channel,
UAVObjHandle obj,
int32_t eventType)
{
UAVObjMetadata metadata;
UAVObjUpdateMode updateMode, loggingMode;
@ -228,13 +361,15 @@ static void updateObject(UAVObjHandle obj, int32_t eventType)
switch (updateMode) {
case UPDATEMODE_PERIODIC:
// Set update period
setUpdatePeriod(obj, metadata.telemetryUpdatePeriod);
setUpdatePeriod(channel,
obj,
metadata.telemetryUpdatePeriod);
// Connect queue
eventMask |= EV_UPDATED_PERIODIC | EV_UPDATED_MANUAL | EV_UPDATE_REQ;
break;
case UPDATEMODE_ONCHANGE:
// Set update period
setUpdatePeriod(obj, 0);
setUpdatePeriod(channel, obj, 0);
// Connect queue
eventMask |= EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATE_REQ;
break;
@ -244,7 +379,9 @@ static void updateObject(UAVObjHandle obj, int32_t eventType)
eventMask |= EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATE_REQ;
// Set update period on initialization and metadata change
if (eventType == EV_NONE) {
setUpdatePeriod(obj, metadata.telemetryUpdatePeriod);
setUpdatePeriod(channel,
obj,
metadata.telemetryUpdatePeriod);
}
} else {
// Otherwise, we just received an object update, so switch to periodic for the timeout period to prevent more updates
@ -253,7 +390,7 @@ static void updateObject(UAVObjHandle obj, int32_t eventType)
break;
case UPDATEMODE_MANUAL:
// Set update period
setUpdatePeriod(obj, 0);
setUpdatePeriod(channel, obj, 0);
// Connect queue
eventMask |= EV_UPDATED_MANUAL | EV_UPDATE_REQ;
break;
@ -261,13 +398,13 @@ static void updateObject(UAVObjHandle obj, int32_t eventType)
switch (loggingMode) {
case UPDATEMODE_PERIODIC:
// Set update period
setLoggingPeriod(obj, metadata.loggingUpdatePeriod);
setLoggingPeriod(channel, obj, metadata.loggingUpdatePeriod);
// Connect queue
eventMask |= EV_LOGGING_PERIODIC | EV_LOGGING_MANUAL;
break;
case UPDATEMODE_ONCHANGE:
// Set update period
setLoggingPeriod(obj, 0);
setLoggingPeriod(channel, obj, 0);
// Connect queue
eventMask |= EV_UPDATED | EV_LOGGING_MANUAL;
break;
@ -277,7 +414,9 @@ static void updateObject(UAVObjHandle obj, int32_t eventType)
eventMask |= EV_UPDATED | EV_LOGGING_MANUAL;
// Set update period on initialization and metadata change
if (eventType == EV_NONE) {
setLoggingPeriod(obj, metadata.loggingUpdatePeriod);
setLoggingPeriod(channel,
obj,
metadata.loggingUpdatePeriod);
}
} else {
// Otherwise, we just received an object update, so switch to periodic for the timeout period to prevent more updates
@ -286,23 +425,28 @@ static void updateObject(UAVObjHandle obj, int32_t eventType)
break;
case UPDATEMODE_MANUAL:
// Set update period
setLoggingPeriod(obj, 0);
setLoggingPeriod(channel, obj, 0);
// Connect queue
eventMask |= EV_LOGGING_MANUAL;
break;
}
// note that all setting objects have implicitly IsPriority=true
#ifdef PIOS_TELEM_PRIORITY_QUEUE
if (UAVObjIsPriority(obj)) {
UAVObjConnectQueue(obj, priorityQueue, eventMask);
} else {
UAVObjConnectQueue(obj, queue, eventMask);
}
UAVObjConnectQueue(obj, channel->priorityQueue, eventMask);
} else
#endif /* PIOS_TELEM_PRIORITY_QUEUE */
UAVObjConnectQueue(obj, channel->queue, eventMask);
}
/**
* Processes queue events
*/
static void processObjEvent(UAVObjEvent *ev)
static void processObjEvent(
channelContext *channel,
UAVObjEvent *ev)
{
UAVObjMetadata metadata;
UAVObjUpdateMode updateMode;
@ -327,7 +471,10 @@ static void processObjEvent(UAVObjEvent *ev)
// Send update to GCS (with retries)
while (retries < MAX_RETRIES && success == -1) {
// call blocks until ack is received or timeout
success = UAVTalkSendObject(uavTalkCon, ev->obj, ev->instId, UAVObjGetTelemetryAcked(&metadata), REQ_TIMEOUT_MS);
success = UAVTalkSendObject(channel->uavTalkCon,
ev->obj,
ev->instId,
UAVObjGetTelemetryAcked(&metadata), REQ_TIMEOUT_MS);
if (success == -1) {
++retries;
}
@ -341,7 +488,10 @@ static void processObjEvent(UAVObjEvent *ev)
// Request object update from GCS (with retries)
while (retries < MAX_RETRIES && success == -1) {
// call blocks until update is received or timeout
success = UAVTalkSendObjectRequest(uavTalkCon, ev->obj, ev->instId, REQ_TIMEOUT_MS);
success = UAVTalkSendObjectRequest(channel->uavTalkCon,
ev->obj,
ev->instId,
REQ_TIMEOUT_MS);
if (success == -1) {
++retries;
}
@ -355,11 +505,17 @@ static void processObjEvent(UAVObjEvent *ev)
// If this is a metaobject then make necessary telemetry updates
if (UAVObjIsMetaobject(ev->obj)) {
// linked object will be the actual object the metadata are for
updateObject(UAVObjGetLinkedObj(ev->obj), EV_NONE);
updateObject(
channel,
UAVObjGetLinkedObj(ev->obj),
EV_NONE);
} else {
if (updateMode == UPDATEMODE_THROTTLED) {
// If this is UPDATEMODE_THROTTLED, the event mask changes on every event.
updateObject(ev->obj, ev->event);
updateObject(
channel,
ev->obj,
ev->event);
}
}
}
@ -380,7 +536,10 @@ static void processObjEvent(UAVObjEvent *ev)
}
if (updateMode == UPDATEMODE_THROTTLED) {
// If this is UPDATEMODE_THROTTLED, the event mask changes on every event.
updateObject(ev->obj, ev->event);
updateObject(
channel,
ev->obj,
ev->event);
}
}
}
@ -388,37 +547,43 @@ static void processObjEvent(UAVObjEvent *ev)
/**
* Telemetry transmit task, regular priority
*/
static void telemetryTxTask(__attribute__((unused)) void *parameters)
static void telemetryTxTask(void *parameters)
{
channelContext *channel = (channelContext *)parameters;
UAVObjEvent ev;
/* Check for a bad context */
if (!channel) {
return;
}
// Loop forever
while (1) {
/**
* Tries to empty the high priority queue before handling any standard priority item
*/
#if defined(PIOS_TELEM_PRIORITY_QUEUE)
#ifdef PIOS_TELEM_PRIORITY_QUEUE
// empty priority queue, non-blocking
while (xQueueReceive(priorityQueue, &ev, 0) == pdTRUE) {
while (xQueueReceive(channel->priorityQueue, &ev, 0) == pdTRUE) {
// Process event
processObjEvent(&ev);
processObjEvent(channel, &ev);
}
// check regular queue and process update - non-blocking
if (xQueueReceive(queue, &ev, 0) == pdTRUE) {
if (xQueueReceive(channel->queue, &ev, 0) == pdTRUE) {
// Process event
processObjEvent(&ev);
processObjEvent(channel, &ev);
// if both queues are empty, wait on priority queue for updates (1 tick) then repeat cycle
} else if (xQueueReceive(priorityQueue, &ev, 1) == pdTRUE) {
} else if (xQueueReceive(channel->priorityQueue, &ev, 1) == pdTRUE) {
// Process event
processObjEvent(&ev);
processObjEvent(channel, &ev);
}
#else
// wait on queue for updates (1 tick) then repeat cycle
if (xQueueReceive(queue, &ev, 1) == pdTRUE) {
if (xQueueReceive(channel->queue, &ev, 1) == pdTRUE) {
// Process event
processObjEvent(&ev);
processObjEvent(channel, &ev);
}
#endif /* if defined(PIOS_TELEM_PRIORITY_QUEUE) */
#endif /* PIOS_TELEM_PRIORITY_QUEUE */
}
}
@ -426,11 +591,18 @@ static void telemetryTxTask(__attribute__((unused)) void *parameters)
/**
* Telemetry receive task. Processes queue events and periodic updates.
*/
static void telemetryRxTask(__attribute__((unused)) void *parameters)
static void telemetryRxTask(void *parameters)
{
channelContext *channel = (channelContext *)parameters;
/* Check for a bad context */
if (!channel) {
return;
}
// Task loop
while (1) {
uint32_t inputPort = getComPort(true);
uint32_t inputPort = channel->getPort();
if (inputPort) {
// Block until data are available
@ -439,7 +611,7 @@ static void telemetryRxTask(__attribute__((unused)) void *parameters)
bytes_to_process = PIOS_COM_ReceiveBuffer(inputPort, serial_data, sizeof(serial_data), 500);
if (bytes_to_process > 0) {
UAVTalkProcessInputStream(uavTalkCon, serial_data, bytes_to_process);
UAVTalkProcessInputStream(channel->uavTalkCon, serial_data, bytes_to_process);
}
} else {
vTaskDelay(5);
@ -447,28 +619,58 @@ static void telemetryRxTask(__attribute__((unused)) void *parameters)
}
}
#ifdef PIOS_INCLUDE_RFM22B
/**
* Radio telemetry receive task. Processes queue events and periodic updates.
* Determine the port to be used for communication on the telemetry channel
* \return com port number
*/
static void radioRxTask(__attribute__((unused)) void *parameters)
static uint32_t localPort()
{
// Task loop
while (1) {
if (radioPort) {
// Block until data are available
uint8_t serial_data[16];
uint16_t bytes_to_process;
bytes_to_process = PIOS_COM_ReceiveBuffer(radioPort, serial_data, sizeof(serial_data), 500);
if (bytes_to_process > 0) {
UAVTalkProcessInputStream(radioUavTalkCon, serial_data, bytes_to_process);
}
} else {
vTaskDelay(5);
}
}
return PIOS_COM_TELEM_RF;
}
/**
* Determine the port to be used for communication on the radio channel
* \return com port number
*/
static uint32_t radioPort()
{
#ifdef PIOS_INCLUDE_RFM22B
uint32_t port = PIOS_COM_RF;
#else /* PIOS_INCLUDE_RFM22B */
uint32_t port = 0;
#endif /* PIOS_INCLUDE_RFM22B */
#ifdef PIOS_INCLUDE_USB
// if USB is connected, USB takes precedence for telemetry
if (PIOS_COM_Available(PIOS_COM_TELEM_USB)) {
port = PIOS_COM_TELEM_USB;
}
#endif /* PIOS_INCLUDE_USB */
return port;
}
/**
* Transmit data buffer to the modem or USB port.
* \param[in] data Data buffer to send
* \param[in] length Length of buffer
* \return -1 on failure
* \return number of bytes transmitted on success
*/
static int32_t transmitLocalData(uint8_t *data, int32_t length)
{
uint32_t outputPort = localChannel.getPort();
if (outputPort) {
return PIOS_COM_SendBuffer(outputPort, data, length);
}
return -1;
}
/**
* Transmit data buffer to the radioport.
* \param[in] data Data buffer to send
@ -478,24 +680,7 @@ static void radioRxTask(__attribute__((unused)) void *parameters)
*/
static int32_t transmitRadioData(uint8_t *data, int32_t length)
{
if (radioPort) {
return PIOS_COM_SendBuffer(radioPort, data, length);
}
return -1;
}
#endif /* PIOS_INCLUDE_RFM22B */
/**
* Transmit data buffer to the modem or USB port.
* \param[in] data Data buffer to send
* \param[in] length Length of buffer
* \return -1 on failure
* \return number of bytes transmitted on success
*/
static int32_t transmitData(uint8_t *data, int32_t length)
{
uint32_t outputPort = getComPort(false);
uint32_t outputPort = radioChannel.getPort();
if (outputPort) {
return PIOS_COM_SendBuffer(outputPort, data, length);
@ -506,12 +691,16 @@ static int32_t transmitData(uint8_t *data, int32_t length)
/**
* Set update period of object (it must be already setup for periodic updates)
* \param[in] telemetry channel context
* \param[in] obj The object to update
* \param[in] updatePeriodMs The update period in ms, if zero then periodic updates are disabled
* \return 0 Success
* \return -1 Failure
*/
static int32_t setUpdatePeriod(UAVObjHandle obj, int32_t updatePeriodMs)
static int32_t setUpdatePeriod(
channelContext *channel,
UAVObjHandle obj,
int32_t updatePeriodMs)
{
UAVObjEvent ev;
int32_t ret;
@ -522,7 +711,12 @@ static int32_t setUpdatePeriod(UAVObjHandle obj, int32_t updatePeriodMs)
ev.event = EV_UPDATED_PERIODIC;
ev.lowPriority = true;
xQueueHandle targetQueue = UAVObjIsPriority(obj) ? priorityQueue : queue;
#ifdef PIOS_TELEM_PRIORITY_QUEUE
xQueueHandle targetQueue = UAVObjIsPriority(obj) ? channel->priorityQueue :
channel->queue;
#else /* PIOS_TELEM_PRIORITY_QUEUE */
xQueueHandle targetQueue = channel->queue;
#endif /* PIOS_TELEM_PRIORITY_QUEUE */
ret = EventPeriodicQueueUpdate(&ev, targetQueue, updatePeriodMs);
if (ret == -1) {
@ -533,12 +727,16 @@ static int32_t setUpdatePeriod(UAVObjHandle obj, int32_t updatePeriodMs)
/**
* Set logging update period of object (it must be already setup for periodic updates)
* \param[in] telemetry channel context
* \param[in] obj The object to update
* \param[in] updatePeriodMs The update period in ms, if zero then periodic updates are disabled
* \return 0 Success
* \return -1 Failure
*/
static int32_t setLoggingPeriod(UAVObjHandle obj, int32_t updatePeriodMs)
static int32_t setLoggingPeriod(
channelContext *channel,
UAVObjHandle obj,
int32_t updatePeriodMs)
{
UAVObjEvent ev;
int32_t ret;
@ -549,7 +747,12 @@ static int32_t setLoggingPeriod(UAVObjHandle obj, int32_t updatePeriodMs)
ev.event = EV_LOGGING_PERIODIC;
ev.lowPriority = true;
xQueueHandle targetQueue = UAVObjIsPriority(obj) ? priorityQueue : queue;
#ifdef PIOS_TELEM_PRIORITY_QUEUE
xQueueHandle targetQueue = UAVObjIsPriority(obj) ? channel->priorityQueue :
channel->queue;
#else /* PIOS_TELEM_PRIORITY_QUEUE */
xQueueHandle targetQueue = channel->queue;
#endif /* PIOS_TELEM_PRIORITY_QUEUE */
ret = EventPeriodicQueueUpdate(&ev, targetQueue, updatePeriodMs);
if (ret == -1) {
@ -588,10 +791,8 @@ static void updateTelemetryStats()
uint32_t timeNow;
// Get stats
UAVTalkGetStats(uavTalkCon, &utalkStats, true);
#ifdef PIOS_INCLUDE_RFM22B
UAVTalkAddStats(radioUavTalkCon, &utalkStats, true);
#endif
UAVTalkGetStats(localChannel.uavTalkCon, &utalkStats, true);
UAVTalkAddStats(radioChannel.uavTalkCon, &utalkStats, true);
// Get object data
FlightTelemetryStatsGet(&flightStats);
@ -681,9 +882,11 @@ static void updateTelemetryStats()
* settings, etc. Thus the HwSettings object which contains the
* telemetry port speed is used for now.
*/
static void updateSettings()
static void updateSettings(channelContext *channel)
{
if (telemetryPort) {
uint32_t port = channel->getPort();
if (port) {
// Retrieve settings
uint8_t speed;
HwSettingsTelemetrySpeedGet(&speed);
@ -691,58 +894,30 @@ static void updateSettings()
// Set port speed
switch (speed) {
case HWSETTINGS_TELEMETRYSPEED_2400:
PIOS_COM_ChangeBaud(telemetryPort, 2400);
PIOS_COM_ChangeBaud(port, 2400);
break;
case HWSETTINGS_TELEMETRYSPEED_4800:
PIOS_COM_ChangeBaud(telemetryPort, 4800);
PIOS_COM_ChangeBaud(port, 4800);
break;
case HWSETTINGS_TELEMETRYSPEED_9600:
PIOS_COM_ChangeBaud(telemetryPort, 9600);
PIOS_COM_ChangeBaud(port, 9600);
break;
case HWSETTINGS_TELEMETRYSPEED_19200:
PIOS_COM_ChangeBaud(telemetryPort, 19200);
PIOS_COM_ChangeBaud(port, 19200);
break;
case HWSETTINGS_TELEMETRYSPEED_38400:
PIOS_COM_ChangeBaud(telemetryPort, 38400);
PIOS_COM_ChangeBaud(port, 38400);
break;
case HWSETTINGS_TELEMETRYSPEED_57600:
PIOS_COM_ChangeBaud(telemetryPort, 57600);
PIOS_COM_ChangeBaud(port, 57600);
break;
case HWSETTINGS_TELEMETRYSPEED_115200:
PIOS_COM_ChangeBaud(telemetryPort, 115200);
PIOS_COM_ChangeBaud(port, 115200);
break;
}
}
}
/**
* Determine input/output com port as highest priority available
* @param[in] input Returns the approproate input com port if true, else the appropriate output com port
*/
#ifdef PIOS_INCLUDE_RFM22B
static uint32_t getComPort(bool input)
#else
static uint32_t getComPort(__attribute__((unused)) bool input)
#endif
{
#if defined(PIOS_INCLUDE_USB)
// if USB is connected, USB takes precedence for telemetry
if (PIOS_COM_Available(PIOS_COM_TELEM_USB)) {
return PIOS_COM_TELEM_USB;
} else
#endif /* PIOS_INCLUDE_USB */
#ifdef PIOS_INCLUDE_RFM22B
// PIOS_COM_RF input is handled by a separate RX thread and therefore must be ignored
if (input && telemetryPort == PIOS_COM_RF) {
return 0;
} else
#endif /* PIOS_INCLUDE_RFM22B */
if (PIOS_COM_Available(telemetryPort)) {
return telemetryPort;
} else {
return 0;
}
}
/**
* @}

View File

@ -194,13 +194,18 @@ msheap_init(heap_handle_t *heap, void *base, void *limit)
}
void *
msheap_alloc(heap_handle_t *heap, uint32_t size)
msheap_alloc(heap_handle_t *heap, void *ptr, uint32_t size)
{
marker_t cursor;
marker_t best;
uint32_t copy_data = 0;
uint16_t old_size = 0;
ASSERT(3, msheap_check(heap));
if (size == 0)
return 0;
/* convert the passed-in size to the number of marker-size units we need to allocate */
size += marker_size;
size = round_up(size, marker_size);
@ -210,6 +215,39 @@ msheap_alloc(heap_handle_t *heap, uint32_t size)
if (size > heap->heap_free)
return 0;
/* realloc */
if (ptr != 0) {
best = (marker_t)ptr - 1;
ASSERT(0, region_check(heap, best));
ASSERT(3, msheap_check(heap));
#ifdef HEAP_REALLOC_FREE_UNUSED_AREA
if (best->next.size == size)
goto done;
if (best->next.size > size) {
/* this region is free, mark it accordingly */
best->next.free = 1;
(best + best->next.size)->prev.free = 1;
traceFREE( ptr, best->next.size );
/* account for space we are freeing */
heap->heap_free += best->next.size;
goto split;
}
#else
if (best->next.size >= size)
goto done;
#endif
old_size = best->next.size;
msheap_free(heap, ptr);
copy_data = 1;
}
/* simple single-pass best-fit search */
restart:
cursor = heap->free_hint;
@ -242,13 +280,28 @@ restart:
/* no space */
return 0;
}
#ifdef HEAP_REALLOC_FREE_UNUSED_AREA
split:
#endif
/* split the free region to make space */
split_region(heap, best, size);
/* update free space counter */
heap->heap_free -= size;
done:
traceMALLOC( (void *)(best + 1), size );
/* Copy data that might be reused */
if (copy_data && ptr) {
size = old_size;
size = size - 1;
size *= marker_size;
for(uint32_t i=0 ; i < size; i++)
((uint8_t *)(best + 1))[i] = ((uint8_t *)ptr)[i];
}
/* and return a pointer to the allocated region */
return (void *)(best + 1);
}

View File

@ -116,7 +116,7 @@ extern void msheap_init(heap_handle_t *heap, void *base, void *limit);
*
* @param size The number of bytes required (more may be allocated).
*/
extern void *msheap_alloc(heap_handle_t *heap, uint32_t size);
extern void *msheap_alloc(heap_handle_t *heap, void *ptr, uint32_t size);
/**
* Free memory back to the heap.

View File

@ -74,15 +74,15 @@ heap_handle_t fast_heap;
extern void vApplicationMallocFailedHook(void) __attribute__((weak));
void *
pios_general_malloc(size_t s, bool use_fast_heap)
pios_general_malloc(void *ptr, size_t s, bool use_fast_heap)
{
void *p;
vPortEnterCritical();
if(use_fast_heap){
p = msheap_alloc(&fast_heap, s);
p = msheap_alloc(&fast_heap, ptr, s);
} else {
p = msheap_alloc(&sram_heap, s);
p = msheap_alloc(&sram_heap, ptr, s);
}
vPortExitCritical();
@ -95,13 +95,13 @@ pios_general_malloc(size_t s, bool use_fast_heap)
void *
pvPortMalloc(size_t s)
{
return pios_general_malloc(s, true);
return pios_general_malloc(NULL, s, true);
}
void *
pvPortMallocStack(size_t s)
{
return pios_general_malloc(s, false);
return pios_general_malloc(NULL, s, false);
}
void
@ -154,7 +154,7 @@ malloc(size_t size)
heap_init_done = 1;
}
return msheap_alloc(sram_heap, size);
return msheap_alloc(NULL, sram_heap, size);
}
void

View File

@ -29,17 +29,32 @@
#ifdef PIOS_TARGET_PROVIDES_FAST_HEAP
// relies on pios_general_malloc to perform the allocation (i.e. pios_msheap.c)
extern void *pios_general_malloc(size_t size, bool fastheap);
extern void *pios_general_malloc(void *ptr, size_t size, bool fastheap);
void *pios_fastheapmalloc(size_t size)
{
return pios_general_malloc(size, true);
return pios_general_malloc(NULL, size, true);
}
void *pios_malloc(size_t size)
{
return pios_general_malloc(size, false);
return pios_general_malloc(NULL, size, false);
}
void *pios_realloc(__attribute__((unused)) void *ptr, __attribute__((unused)) size_t size)
{
#ifdef PIOS_INCLUDE_REALLOC
return pios_general_malloc(ptr, size, false);
#else
// Not allowed to use realloc without the proper define PIOS_INCLUDE_REALLOC set
while (1) {
;
}
return NULL;
#endif
}
void pios_free(void *p)
@ -47,7 +62,7 @@ void pios_free(void *p)
vPortFree(p);
}
#else
#else /* ifdef PIOS_TARGET_PROVIDES_FAST_HEAP */
// demand to pvPortMalloc implementation
void *pios_fastheapmalloc(size_t size)
{
@ -60,6 +75,21 @@ void *pios_malloc(size_t size)
return pvPortMalloc(size);
}
void *pios_realloc(__attribute__((unused)) void *ptr, __attribute__((unused)) size_t size)
{
#ifdef PIOS_INCLUDE_REALLOC
return pvPortMalloc(size);
#else
// Not allowed to use realloc without the proper define PIOS_INCLUDE_REALLOC set
while (1) {
;
}
return NULL;
#endif
}
void pios_free(void *p)
{
vPortFree(p);

View File

@ -32,6 +32,8 @@ void *pios_fastheapmalloc(size_t size);
void *pios_malloc(size_t size);
void *pios_realloc(void *ptr, size_t size);
void pios_free(void *p);
#endif /* PIOS_MEM_H */

View File

@ -740,10 +740,7 @@ void PIOS_Board_Init(void)
tx_buffer, PIOS_COM_RFM22B_RF_TX_BUF_LEN)) {
PIOS_Assert(0);
}
/* Set Telemetry to use OPLinkMini if no other telemetry is configured (USB always overrides anyway) */
if (!pios_com_telem_rf_id) {
pios_com_telem_rf_id = pios_com_rf_id;
}
oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED;
// Set the RF data rate on the modem to ~2X the selected buad rate because the modem is half duplex.

View File

@ -1,36 +1,10 @@
include(openpilotgcs.pri)
TEMPLATE = subdirs
TEMPLATE = aux
# Copy Qt runtime libraries into the build directory (to run or package)
equals(copyqt, 1) {
# Copy QtQuick2 complete directories
# Some of these directories have a lot of files
# Easier to copy everything
QT_QUICK2_DIRS = QtQuick/Controls \
QtQuick/Dialogs \
QtQuick/Layouts \
QtQuick/LocalStorage \
QtQuick/Particles.2 \
QtQuick/PrivateWidgets \
QtQuick/Window.2 \
QtQuick/XmlListModel \
QtQuick.2
# create QtQuick directory
data_copy.commands += -@$(MKDIR) $$targetPath(\"$$GCS_QT_QML_PATH/QtQuick\") $$addNewline()
for(dir, QT_QUICK2_DIRS) {
data_copy.commands += @rm -rf $$targetPath(\"$$GCS_QT_QML_PATH/$$dir\") $$addNewline()
data_copy.commands += $(COPY_DIR) $$targetPath(\"$$[QT_INSTALL_QML]/$$dir\") $$targetPath(\"$$GCS_QT_QML_PATH/$$dir\") $$addNewline()
}
data_copy.target = FORCE
QMAKE_EXTRA_TARGETS += data_copy
linux {
QT_LIBS = libQt5Core.so.5 \
libQt5Gui.so.5 \
libQt5Widgets.so.5 \
@ -56,35 +30,21 @@ equals(copyqt, 1) {
libicui18n.so.53 \
libicuuc.so.53 \
libicudata.so.53
data_copy.commands += -@$(MKDIR) $$targetPath(\"$$GCS_QT_LIBRARY_PATH\") $$addNewline()
for(lib, QT_LIBS) {
data_copy.commands += $(COPY_FILE) $$targetPath(\"$$[QT_INSTALL_LIBS]/$$lib\") $$targetPath(\"$$GCS_QT_LIBRARY_PATH/$$lib\") $$addNewline()
addCopyFileTarget($${lib},$$[QT_INSTALL_LIBS],$${GCS_QT_LIBRARY_PATH})
}
# create Qt plugin directories
QT_PLUGIN_DIRS = iconengines \
imageformats \
platforms \
mediaservice \
sqldrivers
for(dir, QT_PLUGIN_DIRS) {
data_copy.commands += -@$(MKDIR) $$targetPath(\"$$GCS_QT_PLUGINS_PATH/$$dir\") $$addNewline()
}
QT_PLUGIN_LIBS = iconengines/libqsvgicon.so \
imageformats/libqgif.so \
imageformats/libqico.so \
imageformats/libqjpeg.so \
imageformats/libqmng.so \
imageformats/libqsvg.so \
imageformats/libqtiff.so \
mediaservice/libgstaudiodecoder.so \
mediaservice/libgstmediaplayer.so \
platforms/libqxcb.so \
sqldrivers/libqsqlite.so
for(lib, QT_PLUGIN_LIBS) {
data_copy.commands += $(COPY_FILE) $$targetPath(\"$$[QT_INSTALL_PLUGINS]/$$lib\") $$targetPath(\"$$GCS_QT_PLUGINS_PATH/$$lib\") $$addNewline()
}
QT_PLUGINS = iconengines/libqsvgicon.so \
imageformats/libqgif.so \
imageformats/libqico.so \
imageformats/libqjpeg.so \
imageformats/libqmng.so \
imageformats/libqsvg.so \
imageformats/libqtiff.so \
mediaservice/libgstaudiodecoder.so \
mediaservice/libgstmediaplayer.so \
platforms/libqxcb.so \
sqldrivers/libqsqlite.so
}
win32 {
@ -106,7 +66,6 @@ equals(copyqt, 1) {
Qt5Script$${DS}.dll \
Qt5Concurrent$${DS}.dll \
Qt5PrintSupport$${DS}.dll \
Qt5OpenGL$${DS}.dll \
Qt5SerialPort$${DS}.dll \
Qt5Multimedia$${DS}.dll \
Qt5MultimediaWidgets$${DS}.dll \
@ -120,33 +79,7 @@ equals(copyqt, 1) {
libstdc++-6.dll \
libwinpthread-1.dll
for(dll, QT_DLLS) {
data_copy.commands += $(COPY_FILE) $$targetPath(\"$$[QT_INSTALL_BINS]/$$dll\") $$targetPath(\"$$GCS_APP_PATH/$$dll\") $$addNewline()
}
# create Qt plugin directories
QT_PLUGIN_DIRS = iconengines \
imageformats \
platforms \
mediaservice \
sqldrivers \
opengl32_32
for(dir, QT_PLUGIN_DIRS) {
data_copy.commands += -@$(MKDIR) $$targetPath(\"$$GCS_APP_PATH/$$dir\") $$addNewline()
}
# copy Qt plugin DLLs
QT_PLUGIN_DLLS = iconengines/qsvgicon$${DS}.dll \
imageformats/qgif$${DS}.dll \
imageformats/qico$${DS}.dll \
imageformats/qjpeg$${DS}.dll \
imageformats/qmng$${DS}.dll \
imageformats/qsvg$${DS}.dll \
imageformats/qtiff$${DS}.dll \
platforms/qwindows$${DS}.dll \
mediaservice/dsengine$${DS}.dll \
sqldrivers/qsqlite$${DS}.dll
for(dll, QT_PLUGIN_DLLS) {
data_copy.commands += $(COPY_FILE) $$targetPath(\"$$[QT_INSTALL_PLUGINS]/$$dll\") $$targetPath(\"$$GCS_APP_PATH/$$dll\") $$addNewline()
addCopyFileTarget($${dll},$$[QT_INSTALL_BINS],$${GCS_APP_PATH})
}
# copy OpenSSL DLLs
@ -154,14 +87,45 @@ equals(copyqt, 1) {
ssleay32.dll \
libeay32.dll
for(dll, OPENSSL_DLLS) {
data_copy.commands += $(COPY_FILE) $$targetPath(\"$${OPENSSL_DIR}/$$dll\") $$targetPath(\"$$GCS_APP_PATH/$$dll\") $$addNewline()
addCopyFileTarget($${dll},$${OPENSSL_DIR},$${GCS_APP_PATH})
}
# copy OpenGL DLL
OPENGL_DLLS = \
opengl32_32/opengl32.dll
for(dll, OPENGL_DLLS) {
data_copy.commands += $(COPY_FILE) $$targetPath(\"$${MESAWIN_DIR}/$$dll\") $$targetPath(\"$$GCS_APP_PATH/$$dll\") $$addNewline()
addCopyFileTarget($${dll},$${MESAWIN_DIR},$${GCS_APP_PATH})
}
QT_PLUGINS = iconengines/qsvgicon$${DS}.dll \
imageformats/qgif$${DS}.dll \
imageformats/qico$${DS}.dll \
imageformats/qjpeg$${DS}.dll \
imageformats/qmng$${DS}.dll \
imageformats/qsvg$${DS}.dll \
imageformats/qtiff$${DS}.dll \
platforms/qwindows$${DS}.dll \
mediaservice/dsengine$${DS}.dll \
sqldrivers/qsqlite$${DS}.dll
}
for(plugin, QT_PLUGINS) {
addCopyFileTarget($${plugin},$$[QT_INSTALL_PLUGINS],$${GCS_QT_PLUGINS_PATH})
}
# Copy QtQuick2 complete directories
# Some of these directories have a lot of files
# Easier to copy everything
QT_QUICK2_DIRS = QtQuick/Controls \
QtQuick/Dialogs \
QtQuick/Layouts \
QtQuick/LocalStorage \
QtQuick/Particles.2 \
QtQuick/PrivateWidgets \
QtQuick/Window.2 \
QtQuick/XmlListModel \
QtQuick.2
for(dir, QT_QUICK2_DIRS) {
addCopyDirTarget($${dir},$$[QT_INSTALL_QML],$${GCS_QT_QML_PATH})
}
}

View File

@ -32,6 +32,57 @@ defineReplace(qtLibraryName) {
return($$RET)
}
defineTest(addCopyFileTarget) {
file = $$1
src = $$2/$$1
dest = $$3/$$1
$${file}.target = $$dest
$${file}.depends = $$src
# create directory. Better would be an order only dependency
$${file}.commands = -@$(MKDIR) \"$$targetPath($$dirname(dest))\" $$addNewline()
$${file}.commands += $(COPY_FILE) \"$$targetPath($$src)\" \"$$targetPath($$dest)\"
QMAKE_EXTRA_TARGETS += $$file
POST_TARGETDEPS += $$eval($${file}.target)
export($${file}.target)
export($${file}.depends)
export($${file}.commands)
export(QMAKE_EXTRA_TARGETS)
export(POST_TARGETDEPS)
return(true)
}
defineTest(addCopyDirTarget) {
dir = $$1
src = $$2/$$1
dest = $$3/$$1
$${dir}.target = $$dest
$${dir}.depends = $$src
# Windows does not update directory timestamp if files are modified
win32: $${dir}.depends += FORCE
$${dir}.commands = @rm -rf \"$$targetPath($$dest)\" $$addNewline()
# create directory. Better would be an order only dependency
$${dir}.commands += -@$(MKDIR) \"$$targetPath($$dirname(dest))\" $$addNewline()
$${dir}.commands += $(COPY_DIR) \"$$targetPath($$src)\" \"$$targetPath($$dest)\"
QMAKE_EXTRA_TARGETS += $$dir
POST_TARGETDEPS += $$eval($${dir}.target)
export($${dir}.target)
export($${dir}.depends)
export($${dir}.commands)
export(QMAKE_EXTRA_TARGETS)
export(POST_TARGETDEPS)
return(true)
}
# For use in custom compilers which just copy files
win32:i_flag = i
defineReplace(stripSrcDir) {
@ -119,6 +170,8 @@ macx {
contains(TEMPLATE, vc.*)|contains(TEMPLATE_PREFIX, vc):vcproj = 1
GCS_APP_TARGET = openpilotgcs
GCS_QT_PLUGINS_PATH = $$GCS_APP_PATH
GCS_QT_QML_PATH = $$GCS_APP_PATH
copyqt = $$copydata

View File

@ -0,0 +1,13 @@
include(../openpilotgcs.pri)
TEMPLATE = aux
DATACOLLECTIONS = cloudconfig default_configurations dials models pfd sounds diagrams mapicons stylesheets
equals(copydata, 1) {
for(dir, DATACOLLECTIONS) {
exists($$GCS_SOURCE_TREE/share/openpilotgcs/$$dir) {
addCopyDirTarget($$dir, $$GCS_SOURCE_TREE/share/openpilotgcs, $$GCS_DATA_PATH)
}
}
}

View File

@ -52,7 +52,7 @@
<translation></translation>
</message>
<message>
<location filename="../../../src/plugins/coreplugin/generalsettings.cpp" line="+62"/>
<location filename="../../../src/plugins/coreplugin/generalsettings.cpp" line="+64"/>
<source>General</source>
<translation>Général</translation>
</message>
@ -68,7 +68,7 @@
<translation>&lt;Langue Système&gt;</translation>
</message>
<message>
<location line="+112"/>
<location line="+120"/>
<source>Variables</source>
<translation>Variables</translation>
</message>
@ -103,22 +103,35 @@
<translation>Sélectionner automatiquement un périphérique USB OpenPilot :</translation>
</message>
<message>
<location/>
<source>Use UDP Mirror</source>
<translatorcomment>Typo need &quot;:&quot; or remove on others</translatorcomment>
<translation>Utiliser Miroir UDP</translation>
<translation type="vanished">Utiliser Miroir UDP</translation>
</message>
<message>
<location/>
<source>Expert Mode</source>
<translatorcomment>Typo need &quot;:&quot; or remove on others</translatorcomment>
<translation>Mode Expert</translation>
<translation type="vanished">Mode Expert</translation>
</message>
<message>
<location/>
<source>Language:</source>
<translation>Langue :</translation>
</message>
<message>
<location/>
<source>Expert Mode:</source>
<translation>Mode Expert :</translation>
</message>
<message>
<location/>
<source>Contribute usage statistics:</source>
<translation type="unfinished">Contribuer aux statistiques d&apos;utilisation :</translation>
</message>
<message>
<location/>
<source>Use UDP Mirror:</source>
<translation>Utiliser Miroir UDP :</translation>
</message>
</context>
<context>
<name>Core::Internal::MainWindow</name>
@ -16173,7 +16186,7 @@ IMPORTANT : Ces nouveaux paramètres ne sont pas encore enregistrés sur la cart
<context>
<name>ConfigCcpmWidget</name>
<message>
<location filename="../../../src/plugins/config/cfg_vehicletypes/configccpmwidget.cpp" line="+1081"/>
<location filename="../../../src/plugins/config/cfg_vehicletypes/configccpmwidget.cpp" line="+1080"/>
<source>&lt;h1&gt;Swashplate Leveling Routine&lt;/h1&gt;</source>
<translation type="unfinished"></translation>
</message>
@ -16320,4 +16333,37 @@ Il est suggéré que si cela est une première configuration de votre contrôleu
<translation>Réglages Actuels</translation>
</message>
</context>
<context>
<name>UsageTrackerPlugin</name>
<message>
<location filename="../../../src/plugins/usagetracker/usagetrackerplugin.cpp" line="+80"/>
<source>Usage feedback</source>
<translation>Retour d&apos;utilisation</translation>
</message>
<message>
<location line="+2"/>
<source>Yes, count me in</source>
<translation>Oui, comptez sur moi</translation>
</message>
<message>
<location line="+1"/>
<source>No, I will not help</source>
<translation>Non, je ne souhaite pas aider</translation>
</message>
<message>
<location line="+1"/>
<source>Openpilot GCS has a function to collect limited anonymous information about the usage of the application itself and the OpenPilot hardware connected to it.&lt;p&gt;The intention is to not include anything that can be considered sensitive or a threat to the users integrity. The collected information will be sent using a secure protocol to an OpenPilot web service and stored in a database for later analysis and statistical purposes.&lt;br&gt;No information will be sold or given to any third party. The sole purpose is to collect statistics about the usage of our software and hardware to enable us to make things better for you.&lt;p&gt;The following things are collected:&lt;ul&gt;&lt;li&gt;Bootloader version&lt;/li&gt;&lt;li&gt;Firmware version, tag and git hash&lt;/li&gt;&lt;li&gt;OP Hardware type, revision and mcu serial number&lt;/li&gt;&lt;li&gt;Selected configuration parameters&lt;/li&gt;&lt;li&gt;GCS version&lt;/li&gt;&lt;li&gt;Operating system version and architecture&lt;/li&gt;&lt;li&gt;Current local time&lt;/li&gt;&lt;/ul&gt;The information is collected only at the time when a board is connecting to GCS.&lt;p&gt;It is possible to enable or disable this functionality in the general settings part of the options for the GCS application at any time.&lt;p&gt;We need your help, with your feedback we know where to improve things and what platforms are in use. This is a community project that depends on people being involved.&lt;br&gt;Thank You for helping us making things better and for supporting OpenPilot!</source>
<translation type="unfinished">Openpilot GCS possède une fonction qui permet de collecter les informations de manière anonyme sur l&apos;utilisation de l&apos;application en elle-même ainsi que le matériel OpenPilot connecté dessus.&lt;p&gt;Il n&apos;est pas question de collecter des informations sensibles ou pouvant représenter une menace pour l&apos;intégrité des utilisateurs. Les informations collectées seront envoyées vers un site web OpenPilot en utilisant un protocole sécurisé et stockées dans une base de données pour une analyse et des statistiques ultérieures.&lt;br&gt;Aucune information ne sera vendue ou donnée à une quelconque tierce partie. Le seul but est de collecter des informations à propos de l&apos;utilisation de notre logiciel / matériel pour nous permettre de l&apos;améliorer.&lt;p&gt;Les éléments suivants sont collectés :&lt;ul&gt;&lt;li&gt;Version bootloader&lt;/li&gt;&lt;li&gt;Version firmware, tag et git hash&lt;/li&gt;&lt;li&gt;Type de matériel OP, révision et numéro de série CPU&lt;/li&gt;&lt;li&gt;Paramètres de configuration sélectionnés&lt;/li&gt;&lt;li&gt;Version GCS&lt;/li&gt;&lt;li&gt;Système d&apos;exploitation et architecture&lt;/li&gt;&lt;li&gt;Fuseau horaire&lt;/li&gt;&lt;/ul&gt;Les informations sont collectées au moment de la connexion de la carte avec GCS.&lt;p&gt;Il est possible d&apos;activer ou de désactiver cette fonctionnalité à tout moment dans le menu Options &gt; Paramètres généraux de GCS.&lt;p&gt;Nous avons besoin de votre aide, avec votre participation nous connaîtrons où apporter des améliorations et quelle plateforme vous utilisez. C&apos;est un projet communautaire qui dépend de l&apos;implication des utilisateurs.&lt;br&gt;Merci de nous aider à rendre les choses meilleures et soutenir OpenPilot !</translation>
</message>
<message>
<location line="+23"/>
<source>&amp;Don&apos;t show this message again.</source>
<translation>&amp;Ne pas afficher ce message à nouveau.</translation>
</message>
<message>
<location line="+148"/>
<source>Unknown</source>
<translation>Inconnu</translation>
</message>
</context>
</TS>

View File

@ -1,26 +1,5 @@
include(../openpilotgcs.pri)
TEMPLATE = subdirs
SUBDIRS = openpilotgcs/translations
DATACOLLECTIONS = cloudconfig default_configurations dials models pfd sounds diagrams mapicons stylesheets
SUBDIRS = openpilotgcs/translations copydata
equals(copydata, 1) {
for(dir, DATACOLLECTIONS) {
exists($$GCS_SOURCE_TREE/share/openpilotgcs/$$dir) {
# Qt make macros (CHK_DIR_EXISTS, COPY_DIR, etc) have different syntax. They cannot be used
# reliably to copy subdirectories in two different Windows environments (bash and cmd/QtCreator).
# So undocumented QMAKE_SH variable is used to find out the real environment.
!isEmpty(QMAKE_SH) {
# sh environment (including Windows bash)
data_copy.commands += $(MKDIR) $$targetPath(\"$$GCS_DATA_PATH/$$dir\") $$addNewline()
data_copy.commands += $(COPY_DIR) $$targetPath(\"$$GCS_SOURCE_TREE/share/openpilotgcs/$$dir\") $$targetPath(\"$$GCS_DATA_PATH/\") $$addNewline()
} else {
# native Windows cmd environment
data_copy.commands += $(COPY_DIR) $$targetPath(\"$$GCS_SOURCE_TREE/share/openpilotgcs/$$dir\") $$targetPath(\"$$GCS_DATA_PATH/$$dir\") $$addNewline()
}
}
}
data_copy.target = FORCE
QMAKE_EXTRA_TARGETS += data_copy
}
copydata.file = copydata.pro

View File

@ -1,18 +1,10 @@
equals(copydata, 1) {
win32 {
# copy SDL DLL
SDL_DLLS = \
SDL.dll
for(dll, SDL_DLLS) {
data_copy.commands += $(COPY_FILE) $$targetPath(\"$${SDL_DIR}/bin/$$dll\") $$targetPath(\"$$GCS_APP_PATH/$$dll\") $$addNewline()
addCopyFileTarget($${dll},$${SDL_DIR}/bin,$${GCS_APP_PATH})
}
# add make target
POST_TARGETDEPS += copydata
data_copy.target = copydata
QMAKE_EXTRA_TARGETS += data_copy
}
}

View File

@ -674,7 +674,6 @@ void ConfigCcpmWidget::UpdateMixer()
if (throwConfigError(QString("HeliCP"))) {
return;
}
GUIConfigDataUnion config = getConfigData();
useCCPM = !(config.heli.ccpmCollectivePassthroughState || !config.heli.ccpmLinkCyclicState);
@ -1567,28 +1566,28 @@ bool ConfigCcpmWidget::throwConfigError(QString airframeType)
bool error = false;
if ((m_aircraft->ccpmServoWChannel->currentIndex() == 0) && (m_aircraft->ccpmServoWChannel->isEnabled())) {
if ((m_aircraft->ccpmServoWChannel->currentIndex() == 0) && (m_aircraft->ccpmServoWChannel->isVisible())) {
m_aircraft->ccpmServoWLabel->setText("<font color=red>" + m_aircraft->ccpmServoWLabel->text() + "</font>");
error = true;
} else {
m_aircraft->ccpmServoWLabel->setText(QTextEdit(m_aircraft->ccpmServoWLabel->text()).toPlainText());
}
if ((m_aircraft->ccpmServoXChannel->currentIndex() == 0) && (m_aircraft->ccpmServoXChannel->isEnabled())) {
if ((m_aircraft->ccpmServoXChannel->currentIndex() == 0) && (m_aircraft->ccpmServoXChannel->isVisible())) {
m_aircraft->ccpmServoXLabel->setText("<font color=red>" + m_aircraft->ccpmServoXLabel->text() + "</font>");
error = true;
} else {
m_aircraft->ccpmServoXLabel->setText(QTextEdit(m_aircraft->ccpmServoXLabel->text()).toPlainText());
}
if ((m_aircraft->ccpmServoYChannel->currentIndex() == 0) && (m_aircraft->ccpmServoYChannel->isEnabled())) {
if ((m_aircraft->ccpmServoYChannel->currentIndex() == 0) && (m_aircraft->ccpmServoYChannel->isVisible())) {
m_aircraft->ccpmServoYLabel->setText("<font color=red>" + m_aircraft->ccpmServoYLabel->text() + "</font>");
error = true;
} else {
m_aircraft->ccpmServoYLabel->setText(QTextEdit(m_aircraft->ccpmServoYLabel->text()).toPlainText());
}
if ((m_aircraft->ccpmServoZChannel->currentIndex() == 0) && (m_aircraft->ccpmServoZChannel->isEnabled())) {
if ((m_aircraft->ccpmServoZChannel->currentIndex() == 0) && (m_aircraft->ccpmServoZChannel->isVisible())) {
m_aircraft->ccpmServoZLabel->setText("<font color=red>" + m_aircraft->ccpmServoZLabel->text() + "</font>");
error = true;
} else {

View File

@ -42,10 +42,13 @@
#include <utils/stylehelper.h>
#include <QMessageBox>
#define ACCESS_MIN_MOVE -3
#define ACCESS_MAX_MOVE 3
#define STICK_MIN_MOVE -8
#define STICK_MAX_MOVE 8
#define ACCESS_MIN_MOVE -3
#define ACCESS_MAX_MOVE 3
#define STICK_MIN_MOVE -8
#define STICK_MAX_MOVE 8
#define CHANNEL_NUMBER_NONE 0
#define DEFAULT_FLIGHT_MODE_NUMBER 3
ConfigInputWidget::ConfigInputWidget(QWidget *parent) :
ConfigTaskWidget(parent),
@ -416,18 +419,18 @@ void ConfigInputWidget::goToWizard()
// chooses a different TX type (which could otherwise result in
// unexpected TX channels being enabled)
manualSettingsData = manualSettingsObj->getData();
previousManualSettingsData = manualSettingsData;
memento.manualSettingsData = manualSettingsData;
flightModeSettingsData = flightModeSettingsObj->getData();
previousFlightModeSettingsData = flightModeSettingsData;
memento.flightModeSettingsData = flightModeSettingsData;
flightModeSettingsData.Arming = FlightModeSettings::ARMING_ALWAYSDISARMED;
flightModeSettingsObj->setData(flightModeSettingsData);
// Stash actuatorSettings
actuatorSettingsData = actuatorSettingsObj->getData();
previousActuatorSettingsData = actuatorSettingsData;
memento.actuatorSettingsData = actuatorSettingsData;
// Stash systemSettings
systemSettingsData = systemSettingsObj->getData();
previousSystemSettingsData = systemSettingsData;
memento.systemSettingsData = systemSettingsData;
// Now reset channel and actuator settings (disable outputs)
resetChannelSettings();
@ -469,10 +472,10 @@ void ConfigInputWidget::wzCancel()
ui->stackedWidget->setCurrentIndex(0);
// Load settings back from beginning of wizard
manualSettingsObj->setData(previousManualSettingsData);
flightModeSettingsObj->setData(previousFlightModeSettingsData);
actuatorSettingsObj->setData(previousActuatorSettingsData);
systemSettingsObj->setData(previousSystemSettingsData);
manualSettingsObj->setData(memento.manualSettingsData);
flightModeSettingsObj->setData(memento.flightModeSettingsData);
actuatorSettingsObj->setData(memento.actuatorSettingsData);
systemSettingsObj->setData(memento.systemSettingsData);
}
void ConfigInputWidget::registerControlActivity()
@ -555,7 +558,7 @@ void ConfigInputWidget::wzNext()
restoreMdata();
// Load actuator settings back from beginning of wizard
actuatorSettingsObj->setData(previousActuatorSettingsData);
actuatorSettingsObj->setData(memento.actuatorSettingsData);
// Force flight mode neutral to middle and Throttle neutral at 4%
adjustSpecialNeutrals();
@ -802,6 +805,12 @@ void ConfigInputWidget::wizardTearDownStep(enum wizardSteps step)
disconnect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(identifyControls()));
wizardUi->wzNext->setEnabled(true);
setTxMovement(nothing);
/* If flight mode stick isn't identified, force flight mode number to be 1 */
manualSettingsData = manualSettingsObj->getData();
if (manualSettingsData.ChannelGroups[ManualControlSettings::CHANNELNUMBER_FLIGHTMODE] ==
ManualControlSettings::CHANNELGROUPS_NONE) {
forceOneFlightMode();
}
break;
case wizardIdentifyCenter:
manualCommandData = manualCommandObj->getData();
@ -882,21 +891,32 @@ void ConfigInputWidget::restoreMdata()
*/
void ConfigInputWidget::setChannel(int newChan)
{
bool canBeSkipped = false;
if (newChan == ManualControlSettings::CHANNELGROUPS_COLLECTIVE) {
wizardUi->identifyStickInstructions->setText(QString(tr("Please enable throttle hold mode.\n\nMove the Collective Pitch stick.")));
wizardUi->identifyStickInstructions->setText(QString(tr("<p>Please enable throttle hold mode.</p>"
"<p>Move the Collective Pitch stick.</p>")));
} else if (newChan == ManualControlSettings::CHANNELGROUPS_FLIGHTMODE) {
wizardUi->identifyStickInstructions->setText(QString(tr("Please toggle the Flight Mode switch.\n\nFor switches you may have to repeat this rapidly.")));
wizardUi->identifyStickInstructions->setText(QString(tr("<p>Please toggle the Flight Mode switch.</p>"
"<p>For switches you may have to repeat this rapidly.</p>"
"<p>Alternatively, you can click Next to skip this channel, but you will get only <b>ONE</b> Flight Mode.</p>")));
canBeSkipped = true;
} else if ((transmitterType == heli) && (newChan == ManualControlSettings::CHANNELGROUPS_THROTTLE)) {
wizardUi->identifyStickInstructions->setText(QString(tr("Please disable throttle hold mode.\n\nMove the Throttle stick.")));
wizardUi->identifyStickInstructions->setText(QString(tr("<p>Please disable throttle hold mode.</p>"
"<p>Move the Throttle stick.</p>")));
} else {
wizardUi->identifyStickInstructions->setText(QString(tr("Please move each control one at a time according to the instructions and picture below.\n\n"
"Move the %1 stick.")).arg(manualSettingsObj->getField("ChannelGroups")->getElementNames().at(newChan)));
wizardUi->identifyStickInstructions->setText(QString(tr("<p>Please move each control one at a time according to the instructions and picture below.</p>"
"<p>Move the %1 stick.</p>")).arg(manualSettingsObj->getField("ChannelGroups")->getElementNames().at(newChan)));
}
if (manualSettingsObj->getField("ChannelGroups")->getElementNames().at(newChan).contains("Accessory")) {
wizardUi->identifyStickInstructions->setText(wizardUi->identifyStickInstructions->text() + tr("<p>Alternatively, click Next to skip this channel.</p>"));
canBeSkipped = true;
}
if (canBeSkipped) {
wizardUi->wzNext->setEnabled(true);
wizardUi->wzNext->setText(tr("Next / Skip"));
wizardUi->identifyStickInstructions->setText(wizardUi->identifyStickInstructions->text() + tr(" Alternatively, click Next to skip this channel."));
} else {
wizardUi->wzNext->setEnabled(false);
}
@ -1674,7 +1694,7 @@ void ConfigInputWidget::simpleCalibration(bool enable)
// Stash actuatorSettings
actuatorSettingsData = actuatorSettingsObj->getData();
previousActuatorSettingsData = actuatorSettingsData;
memento.actuatorSettingsData = actuatorSettingsData;
// Disable all actuators
resetActuatorSettings();
@ -1720,7 +1740,7 @@ void ConfigInputWidget::simpleCalibration(bool enable)
manualSettingsObj->setData(manualSettingsData);
// Load actuator settings back from beginning of manual calibration
actuatorSettingsObj->setData(previousActuatorSettingsData);
actuatorSettingsObj->setData(memento.actuatorSettingsData);
ui->configurationWizard->setEnabled(true);
ui->saveRCInputToRAM->setEnabled(true);
@ -1778,9 +1798,10 @@ void ConfigInputWidget::resetChannelSettings()
{
manualSettingsData = manualSettingsObj->getData();
// Clear all channel data : Channel Type (PPM,PWM..) and Number
for (unsigned int channel = 0; channel < 9; channel++) {
for (unsigned int channel = 0; channel < ManualControlSettings::CHANNELNUMBER_NUMELEM; channel++) {
manualSettingsData.ChannelGroups[channel] = ManualControlSettings::CHANNELGROUPS_NONE;
manualSettingsData.ChannelNumber[channel] = 0;
manualSettingsData.ChannelNumber[channel] = CHANNEL_NUMBER_NONE;
manualSettingsData.FlightModeNumber = DEFAULT_FLIGHT_MODE_NUMBER;
manualSettingsObj->setData(manualSettingsData);
}
}
@ -1819,7 +1840,7 @@ void ConfigInputWidget::resetActuatorSettings()
void ConfigInputWidget::forceOneFlightMode()
{
manualCommandData = manualCommandObj->getData();
manualSettingsData = manualSettingsObj->getData();
manualSettingsData.FlightModeNumber = 1;
manualSettingsObj->setData(manualSettingsData);
}

View File

@ -128,21 +128,25 @@ private:
ManualControlSettings *manualSettingsObj;
ManualControlSettings::DataFields manualSettingsData;
ManualControlSettings::DataFields previousManualSettingsData;
ActuatorSettings *actuatorSettingsObj;
ActuatorSettings::DataFields actuatorSettingsData;
ActuatorSettings::DataFields previousActuatorSettingsData;
FlightModeSettings *flightModeSettingsObj;
FlightModeSettings::DataFields flightModeSettingsData;
FlightModeSettings::DataFields previousFlightModeSettingsData;
ReceiverActivity *receiverActivityObj;
ReceiverActivity::DataFields receiverActivityData;
SystemSettings *systemSettingsObj;
SystemSettings::DataFields systemSettingsData;
SystemSettings::DataFields previousSystemSettingsData;
typedef struct {
ManualControlSettings::DataFields manualSettingsData;
ActuatorSettings::DataFields actuatorSettingsData;
FlightModeSettings::DataFields flightModeSettingsData;
SystemSettings::DataFields systemSettingsData;
} Memento;
Memento memento;
QSvgRenderer *m_renderer;

View File

@ -49,6 +49,8 @@ GeneralSettings::GeneralSettings() :
m_autoSelect(true),
m_useUDPMirror(false),
m_useExpertMode(false),
m_collectUsageData(true),
m_showUsageDataDisclaimer(true),
m_dialog(0)
{}
@ -125,6 +127,7 @@ QWidget *GeneralSettings::createPage(QWidget *parent)
m_page->checkAutoSelect->setChecked(m_autoSelect);
m_page->cbUseUDPMirror->setChecked(m_useUDPMirror);
m_page->cbExpertMode->setChecked(m_useExpertMode);
m_page->cbUsageData->setChecked(m_collectUsageData);
m_page->colorButton->setColor(StyleHelper::baseColor());
connect(m_page->resetButton, SIGNAL(clicked()), this, SLOT(resetInterfaceColor()));
@ -145,6 +148,7 @@ void GeneralSettings::apply()
m_useExpertMode = m_page->cbExpertMode->isChecked();
m_autoConnect = m_page->checkAutoConnect->isChecked();
m_autoSelect = m_page->checkAutoSelect->isChecked();
setCollectUsageData(m_page->cbUsageData->isChecked());
}
void GeneralSettings::finish()
@ -155,12 +159,15 @@ void GeneralSettings::finish()
void GeneralSettings::readSettings(QSettings *qs)
{
qs->beginGroup(QLatin1String("General"));
m_language = qs->value(QLatin1String("OverrideLanguage"), QLocale::system().name()).toString();
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();
m_useUDPMirror = qs->value(QLatin1String("UDPMirror"), m_useUDPMirror).toBool();
m_useExpertMode = qs->value(QLatin1String("ExpertMode"), m_useExpertMode).toBool();
m_autoConnect = qs->value(QLatin1String("AutoConnect"), m_autoConnect).toBool();
m_autoSelect = qs->value(QLatin1String("AutoSelect"), m_autoSelect).toBool();
m_useUDPMirror = qs->value(QLatin1String("UDPMirror"), m_useUDPMirror).toBool();
m_useExpertMode = qs->value(QLatin1String("ExpertMode"), m_useExpertMode).toBool();
m_collectUsageData = qs->value(QLatin1String("CollectUsageData"), m_collectUsageData).toBool();
m_showUsageDataDisclaimer = qs->value(QLatin1String("ShowUsageDataDisclaimer"), m_showUsageDataDisclaimer).toBool();
m_lastUsageHash = qs->value(QLatin1String("LastUsageHash"), m_lastUsageHash).toString();
qs->endGroup();
}
@ -179,6 +186,9 @@ void GeneralSettings::saveSettings(QSettings *qs)
qs->setValue(QLatin1String("AutoSelect"), m_autoSelect);
qs->setValue(QLatin1String("UDPMirror"), m_useUDPMirror);
qs->setValue(QLatin1String("ExpertMode"), m_useExpertMode);
qs->setValue(QLatin1String("CollectUsageData"), m_collectUsageData);
qs->setValue(QLatin1String("ShowUsageDataDisclaimer"), m_showUsageDataDisclaimer);
qs->setValue(QLatin1String("LastUsageHash"), m_lastUsageHash);
qs->endGroup();
}
@ -249,11 +259,44 @@ bool GeneralSettings::useUDPMirror() const
return m_useUDPMirror;
}
bool GeneralSettings::collectUsageData() const
{
return m_collectUsageData;
}
bool GeneralSettings::showUsageDataDisclaimer() const
{
return m_showUsageDataDisclaimer;
}
QString GeneralSettings::lastUsageHash() const
{
return m_lastUsageHash;
}
bool GeneralSettings::useExpertMode() const
{
return m_useExpertMode;
}
bool GeneralSettings::setCollectUsageData(bool collect)
{
if (collect && collect != m_collectUsageData) {
setShowUsageDataDisclaimer(true);
}
m_collectUsageData = collect;
}
bool GeneralSettings::setShowUsageDataDisclaimer(bool show)
{
m_showUsageDataDisclaimer = show;
}
void GeneralSettings::setLastUsageHash(QString hash)
{
m_lastUsageHash = hash;
}
void GeneralSettings::slotAutoConnect(int value)
{
if (value == Qt::Checked) {

View File

@ -57,10 +57,15 @@ public:
bool autoConnect() const;
bool autoSelect() const;
bool useUDPMirror() const;
bool collectUsageData() const;
bool showUsageDataDisclaimer() const;
QString lastUsageHash() const;
void readSettings(QSettings *qs);
void saveSettings(QSettings *qs);
bool useExpertMode() const;
signals:
bool setCollectUsageData(bool collect);
bool setShowUsageDataDisclaimer(bool show);
void setLastUsageHash(QString hash);
private slots:
void resetInterfaceColor();
@ -79,6 +84,9 @@ private:
bool m_autoSelect;
bool m_useUDPMirror;
bool m_useExpertMode;
bool m_collectUsageData;
bool m_showUsageDataDisclaimer;
QString m_lastUsageHash;
QPointer<QWidget> m_dialog;
QList<QTextCodec *> m_codecs;
};

View File

@ -11,7 +11,16 @@
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@ -20,17 +29,73 @@
<string>General settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="colorLabel">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>User interface color:</string>
<string>Language:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="14" column="0">
<widget class="QLabel" name="labelExpert">
<property name="text">
<string>Expert Mode:</string>
</property>
</widget>
</item>
<item row="13" column="2">
<widget class="QCheckBox" name="cbUseUDPMirror">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="12" column="2">
<widget class="QCheckBox" name="checkAutoSelect">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Automatically connect an OpenPilot USB device:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="10" column="2">
<widget class="QCheckBox" name="checkBoxSaveOnExit">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QWidget" name="widget" native="true">
<layout class="QGridLayout" name="gridLayout_2">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="1">
@ -82,46 +147,46 @@
</layout>
</widget>
</item>
<item row="9" column="1">
<item row="1" column="0">
<widget class="QLabel" name="colorLabel">
<property name="text">
<string>User interface color:</string>
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QLabel" name="labelExpert_2">
<property name="text">
<string>Contribute usage statistics:</string>
</property>
</widget>
</item>
<item row="9" column="2">
<widget class="QWidget" name="widget_2" native="true">
<layout class="QGridLayout" name="gridLayout_3">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
<item row="10" column="1">
<widget class="QCheckBox" name="checkBoxSaveOnExit">
<item row="14" column="2">
<widget class="QCheckBox" name="cbExpertMode">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Save configuration settings on exit:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Automatically connect an OpenPilot USB device:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="11" column="1">
<item row="11" column="2">
<widget class="QCheckBox" name="checkAutoConnect">
<property name="text">
<string/>
@ -131,58 +196,14 @@
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Automatically select an OpenPilot USB device:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QCheckBox" name="checkAutoSelect">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QCheckBox" name="cbUseUDPMirror">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="labelUDP">
<property name="text">
<string>Use UDP Mirror</string>
<string>Use UDP Mirror:</string>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QLabel" name="labelExpert">
<property name="text">
<string>Expert Mode</string>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QCheckBox" name="cbExpertMode">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="0" column="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QComboBox" name="languageBox"/>
@ -202,10 +223,33 @@
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<item row="10" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Language:</string>
<string>Save configuration settings on exit:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Automatically select an OpenPilot USB device:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="15" column="2">
<widget class="QCheckBox" name="cbUsageData">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>

View File

@ -35,8 +35,6 @@ equals(copydata, 1) {
# Windows release only
win32:CONFIG(release, debug|release) {
data_copy.commands += -@$(MKDIR) $$targetPath(\"$$PLUGIN_DIR\") $$addNewline()
# resources and sample configuration
PLUGIN_RESOURCES = \
cc_off.tga \
@ -46,7 +44,7 @@ equals(copydata, 1) {
cc_plugin.ini \
plugin.txt
for(res, PLUGIN_RESOURCES) {
data_copy.commands += $(COPY_FILE) $$targetPath(\"$$RES_DIR/$$res\") $$targetPath(\"$$PLUGIN_DIR/$$res\") $$addNewline()
addCopyFileTarget($${res},$${RES_DIR},$${PLUGIN_DIR})
}
# Qt DLLs
@ -54,7 +52,7 @@ equals(copydata, 1) {
Qt5Core.dll \
Qt5Network.dll
for(dll, QT_DLLS) {
data_copy.commands += $(COPY_FILE) $$targetPath(\"$$[QT_INSTALL_BINS]/$$dll\") $$targetPath(\"$$SIM_DIR/$$dll\") $$addNewline()
addCopyFileTarget($${dll},$$[QT_INSTALL_BINS],$${SIM_DIR})
}
# MinGW DLLs
@ -62,10 +60,7 @@ equals(copydata, 1) {
# libgcc_s_dw2-1.dll \
# mingwm10.dll
#for(dll, MINGW_DLLS) {
# data_copy.commands += $(COPY_FILE) $$targetPath(\"$$(QTMINGW)/$$dll\") $$targetPath(\"$$SIM_DIR/$$dll\") $$addNewline()
# addCopyFileTarget($${dll},$$(QTMINGW),$${SIM_DIR})
#}
data_copy.target = FORCE
QMAKE_EXTRA_TARGETS += data_copy
}
}

View File

@ -252,3 +252,11 @@ plugin_flightlog.depends += plugin_uavobjects
plugin_flightlog.depends += plugin_uavtalk
SUBDIRS += plugin_flightlog
# Usage Tracker plugin
plugin_usagetracker.subdir = usagetracker
plugin_usagetracker.depends = plugin_coreplugin
plugin_usagetracker.depends += plugin_uavobjects
plugin_usagetracker.depends += plugin_uavtalk
plugin_setupwizard.depends += plugin_uavobjectutil
SUBDIRS += plugin_usagetracker

View File

@ -0,0 +1,12 @@
<plugin name="UsageTracker" version="1.0.0" compatVersion="1.0.0">
<vendor>The OpenPilot Project</vendor>
<copyright>(C) 2015 OpenPilot Project</copyright>
<description>A plugin that tracks GCS usage</description>
<url>http://www.openpilot.org</url>
<dependencyList>
<dependency name="Core" version="1.0.0"/>
<dependency name="UAVTalk" version="1.0.0"/>
<dependency name="UAVObjectUtil" version="1.0.0"/>
<dependency name="UAVObjects" version="1.0.0"/>
</dependencyList>
</plugin>

View File

@ -0,0 +1,16 @@
TEMPLATE = lib
TARGET = UsageTracker
QT += network
include(../../openpilotgcsplugin.pri)
include(../../libs/version_info/version_info.pri)
include(../../plugins/coreplugin/coreplugin.pri)
include(../../plugins/uavobjects/uavobjects.pri)
include(../../plugins/uavobjectutil/uavobjectutil.pri)
include(../../plugins/uavtalk/uavtalk.pri)
HEADERS += usagetrackerplugin.h
SOURCES += usagetrackerplugin.cpp
OTHER_FILES += usagetracker.pluginspec

View File

@ -0,0 +1,280 @@
/**
******************************************************************************
*
* @file usagetrackerplugin.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup UsageTrackerPlugin Usage Tracker Plugin
* @{
* @brief A plugin tracking GCS usage
*****************************************************************************/
/*
* 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 "usagetrackerplugin.h"
#include <QtPlugin>
#include <QStringList>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <extensionsystem/pluginmanager.h>
#include <QCheckBox>
#include <QDebug>
#include <QMessageBox>
#include <uavobjectutil/devicedescriptorstruct.h>
#include <uavobjectutil/uavobjectutilmanager.h>
#include "version_info/version_info.h"
#include "coreplugin/icore.h"
#include <uavtalk/telemetrymanager.h>
UsageTrackerPlugin::UsageTrackerPlugin() :
m_telemetryManager(NULL)
{}
UsageTrackerPlugin::~UsageTrackerPlugin()
{}
bool UsageTrackerPlugin::initialize(const QStringList & args, QString *errMsg)
{
Q_UNUSED(args);
Q_UNUSED(errMsg);
return true;
}
void UsageTrackerPlugin::extensionsInitialized()
{
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
m_telemetryManager = pm->getObject<TelemetryManager>();
connect(m_telemetryManager, SIGNAL(connected()), this, SLOT(onAutopilotConnect()));
}
void UsageTrackerPlugin::shutdown()
{
if (m_telemetryManager != NULL) {
disconnect(m_telemetryManager, SIGNAL(connected()), this, SLOT(onAutopilotConnect()));
}
}
void UsageTrackerPlugin::onAutopilotConnect()
{
Core::Internal::GeneralSettings *settings = getGeneralSettings();
if (settings->collectUsageData()) {
if (settings->showUsageDataDisclaimer()) {
QMessageBox message;
message.setWindowTitle(tr("Usage feedback"));
message.setIcon(QMessageBox::Information);
message.addButton(tr("Yes, count me in"), QMessageBox::AcceptRole);
message.addButton(tr("No, I will not help"), QMessageBox::RejectRole);
message.setText(tr("Openpilot GCS has a function to collect limited anonymous information about "
"the usage of the application itself and the OpenPilot hardware connected to it.<p>"
"The intention is to not include anything that can be considered sensitive "
"or a threat to the users integrity. The collected information will be sent "
"using a secure protocol to an OpenPilot web service and stored in a database "
"for later analysis and statistical purposes.<br>"
"No information will be sold or given to any third party. The sole purpose is "
"to collect statistics about the usage of our software and hardware to enable us "
"to make things better for you.<p>"
"The following things are collected:<ul>"
"<li>Bootloader version</li>"
"<li>Firmware version, tag and git hash</li>"
"<li>OP Hardware type, revision and mcu serial number</li>"
"<li>Selected configuration parameters</li>"
"<li>GCS version</li>"
"<li>Operating system version and architecture</li>"
"<li>Current local time</li></ul>"
"The information is collected only at the time when a board is connecting to GCS.<p>"
"It is possible to enable or disable this functionality in the general "
"settings part of the options for the GCS application at any time.<p>"
"We need your help, with your feedback we know where to improve things and what "
"platforms are in use. This is a community project that depends on people being involved.<br>"
"Thank You for helping us making things better and for supporting OpenPilot!"));
QCheckBox *disclaimerCb = new QCheckBox(tr("&Don't show this message again."));
disclaimerCb->setChecked(true);
message.setCheckBox(disclaimerCb);
if (message.exec() != QMessageBox::AcceptRole) {
settings->setCollectUsageData(false);
settings->setShowUsageDataDisclaimer(!message.checkBox()->isChecked());
return;
} else {
settings->setCollectUsageData(true);
settings->setShowUsageDataDisclaimer(!message.checkBox()->isChecked());
}
}
QTimer::singleShot(1000, this, SLOT(trackUsage()));
}
}
void UsageTrackerPlugin::trackUsage()
{
QMap<QString, QString> parameters;
collectUsageParameters(parameters);
QUrlQuery query;
QMapIterator<QString, QString> iter(parameters);
while (iter.hasNext()) {
iter.next();
query.addQueryItem(iter.key(), iter.value());
}
// Add checksum
QString hash = getQueryHash(query.toString());
if (shouldSend(hash)) {
query.addQueryItem("hash", hash);
QUrl url("https://www.openpilot.org/opver?" + query.toString(QUrl::FullyEncoded));
QNetworkAccessManager *networkAccessManager = new QNetworkAccessManager();
// This will delete the network access manager instance when we're done
connect(networkAccessManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onFinished(QNetworkReply *)));
connect(networkAccessManager, SIGNAL(finished(QNetworkReply *)), networkAccessManager, SLOT(deleteLater()));
qDebug() << "Sending usage tracking as:" << url.toEncoded(QUrl::FullyEncoded);
networkAccessManager->get(QNetworkRequest(QUrl(url.toEncoded(QUrl::FullyEncoded))));
}
}
void UsageTrackerPlugin::collectUsageParameters(QMap<QString, QString> &parameters)
{
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectUtilManager *utilMngr = pm->getObject<UAVObjectUtilManager>();
QByteArray description = utilMngr->getBoardDescription();
deviceDescriptorStruct devDesc;
if (UAVObjectUtilManager::descriptionToStructure(description, devDesc)) {
int boardModel = utilMngr->getBoardModel();
parameters["board_type"] = "0x" + QString::number(boardModel, 16).toLower();
parameters["board_serial"] = utilMngr->getBoardCPUSerial().toHex();
parameters["bl_version"] = QString::number(utilMngr->getBootloaderRevision());
parameters["fw_tag"] = devDesc.gitTag;
parameters["fw_hash"] = devDesc.gitHash;
parameters["os_version"] = QSysInfo::prettyProductName() + " " + QSysInfo::currentCpuArchitecture();
parameters["os_threads"] = QString::number(QThread::idealThreadCount());
parameters["os_timezone"] = QTimeZone::systemTimeZoneId();
parameters["gcs_version"] = VersionInfo::revision();
// Configuration parameters
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
parameters["conf_receiver"] = getUAVFieldValue(objManager, "ManualControlSettings", "ChannelGroups", 0);
parameters["conf_vehicle"] = getUAVFieldValue(objManager, "SystemSettings", "AirframeType");
if ((boardModel & 0xff00) == 0x0400) {
// CopterControl family
parameters["conf_rport"] = getUAVFieldValue(objManager, "HwSettings", "CC_RcvrPort");
parameters["conf_mport"] = getUAVFieldValue(objManager, "HwSettings", "CC_MainPort");
parameters["conf_fport"] = getUAVFieldValue(objManager, "HwSettings", "CC_FlexiPort");
} else if ((boardModel & 0xff00) == 0x0900) {
// Revolution family
parameters["conf_rport"] = getUAVFieldValue(objManager, "HwSettings", "RM_RcvrPort");
parameters["conf_mport"] = getUAVFieldValue(objManager, "HwSettings", "RM_MainPort");
parameters["conf_fport"] = getUAVFieldValue(objManager, "HwSettings", "RM_FlexiPort");
parameters["conf_fusion"] = getUAVFieldValue(objManager, "RevoSettings", "FusionAlgorithm");
}
parameters["conf_uport"] = getUAVFieldValue(objManager, "HwSettings", "USB_HIDPort");
parameters["conf_vport"] = getUAVFieldValue(objManager, "HwSettings", "USB_VCPPort");
parameters["conf_rotation"] = QString("[%1:%2:%3]")
.arg(getUAVFieldValue(objManager, "AttitudeSettings", "BoardRotation", 0))
.arg(getUAVFieldValue(objManager, "AttitudeSettings", "BoardRotation", 1))
.arg(getUAVFieldValue(objManager, "AttitudeSettings", "BoardRotation", 2));
parameters["conf_pidr"] = QString("[%1:%2:%3:%4][%5:%6:%7:%8][%9:%10:%11:%12]")
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "RollRatePID", 0))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "RollRatePID", 1))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "RollRatePID", 2))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "RollRatePID", 3))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "PitchRatePID", 0))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "PitchRatePID", 1))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "PitchRatePID", 2))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "PitchRatePID", 3))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "YawRatePID", 0))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "YawRatePID", 1))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "YawRatePID", 2))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "YawRatePID", 3));
parameters["conf_pia"] = QString("[%1:%2:%3][%4:%5:%6][%7:%8:%9]")
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "RollPI", 0))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "RollPI", 1))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "RollPI", 2))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "PitchPI", 0))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "PitchPI", 1))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "PitchPI", 2))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "YawPI", 0))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "YawPI", 1))
.arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "YawPI", 2));
parameters["conf_tps"] = getUAVFieldValue(objManager, "StabilizationSettingsBank1", "EnableThrustPIDScaling");
parameters["conf_piro"] = getUAVFieldValue(objManager, "StabilizationSettingsBank1", "EnablePiroComp");
parameters["conf_fmcount"] = getUAVFieldValue(objManager, "ManualControlSettings", "FlightModeNumber");
parameters["conf_fmodes"] = QString("[%1:%2:%3]").arg(getUAVFieldValue(objManager, "FlightModeSettings", "FlightModePosition", 0))
.arg(getUAVFieldValue(objManager, "FlightModeSettings", "FlightModePosition", 1))
.arg(getUAVFieldValue(objManager, "FlightModeSettings", "FlightModePosition", 2));
}
}
void UsageTrackerPlugin::onFinished(QNetworkReply *reply)
{
if (reply->error() == QNetworkReply::NoError) {
getGeneralSettings()->setLastUsageHash(m_lastHash);
qDebug() << "Updated last usage hash to:" << m_lastHash;
} else {
qDebug() << "Usage tracking failed with:" << reply->errorString();
}
}
QString UsageTrackerPlugin::getUAVFieldValue(UAVObjectManager *objManager, QString objectName, QString fieldName, int index) const
{
UAVObject *object = objManager->getObject(objectName);
if (object != NULL) {
UAVObjectField *field = object->getField(fieldName);
if (field != NULL) {
return field->getValue(index).toString();
}
}
return tr("Unknown");
}
QString UsageTrackerPlugin::getQueryHash(QString source) const
{
source += "OpenPilot Fuck Yeah!";
return QString(QCryptographicHash::hash(QByteArray(source.toStdString().c_str()), QCryptographicHash::Md5).toHex());
}
Core::Internal::GeneralSettings *UsageTrackerPlugin::getGeneralSettings() const
{
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
Core::Internal::GeneralSettings *settings = pm->getObject<Core::Internal::GeneralSettings>();
return settings;
}
bool UsageTrackerPlugin::shouldSend(const QString &hash)
{
if (getGeneralSettings()->lastUsageHash() == hash) {
return false;
} else {
m_lastHash = hash;
return true;
}
}

View File

@ -0,0 +1,63 @@
/**
******************************************************************************
*
* @file usagetrackerplugin.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup UsageTrackerPlugin Usage Tracker Plugin
* @{
* @brief A plugin tracking GCS usage
*****************************************************************************/
/*
* 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 USAGETRACKERPLUGIN_H
#define USAGETRACKERPLUGIN_H
#include <extensionsystem/iplugin.h>
#include <coreplugin/generalsettings.h>
class TelemetryManager;
class UAVObjectManager;
class QNetworkReply;
class UsageTrackerPlugin : public ExtensionSystem::IPlugin {
Q_OBJECT
Q_PLUGIN_METADATA(IID "OpenPilot.UsageTracker")
public:
UsageTrackerPlugin();
~UsageTrackerPlugin();
void extensionsInitialized();
bool initialize(const QStringList & arguments, QString *errorString);
void shutdown();
private slots:
void onAutopilotConnect();
void trackUsage();
void collectUsageParameters(QMap<QString, QString> &parameters);
void onFinished(QNetworkReply *reply);
private:
TelemetryManager *m_telemetryManager;
QString m_lastHash;
QString getUAVFieldValue(UAVObjectManager *objManager, QString objectName, QString fieldName, int index = 0) const;
QString getQueryHash(QString source) const;
Core::Internal::GeneralSettings *getGeneralSettings() const;
bool shouldSend(const QString &hash);
};
#endif // USAGETRACKERPLUGIN_H

View File

@ -3,7 +3,7 @@
# Copyright (c) 2009-2013, The OpenPilot Team, http://www.openpilot.org
#
TEMPLATE = subdirs
TEMPLATE = aux
# Some handy defines
defineReplace(targetPath) {
@ -64,5 +64,6 @@ win32 {
uavobjects.commands += -spec $$SPEC CONFIG+=$${BUILD_CONFIG} -r $$addNewline()
}
uavobjects.target = FORCE
uavobjects.depends = FORCE
QMAKE_EXTRA_TARGETS += uavobjects
PRE_TARGETDEPS += uavobjects

View File

@ -136,7 +136,7 @@ endef
define OPFW_TEMPLATE
FORCE:
$(1).firmware_info.c: $(1) $(ROOT_DIR)/flight/templates/firmware_info.c.template FORCE
$(1).firmware_info.c: $(1) $(ROOT_DIR)/flight/templates/firmware_info.c.template $(ROOT_DIR)/shared/uavobjectdefinition
@$(ECHO) $(MSG_FWINFO) $$(call toprel, $$@)
$(V1) $(VERSION_INFO) \
--template=$(ROOT_DIR)/flight/templates/firmware_info.c.template \

View File

@ -776,8 +776,8 @@ ifeq ($(UNAME), Windows)
$(eval $(call TOOL_INSTALL_TEMPLATE,openssl,$(OPENSSL_DIR),$(OPENSSL_URL),,$(notdir $(OPENSSL_URL))))
ifeq ($(shell [ -d "$(OPENSSL_DIR)" ] && $(ECHO) "exists"), exists)
export OPENSSL := "$(OPENSSL_DIR)/bin/openssl"
export OPENSSL_DIR := "$(OPENSSL_DIR)"
export OPENSSL := $(OPENSSL_DIR)/bin/openssl
export OPENSSL_DIR
else
# not installed, hope it's in the path...
# $(info $(EMPTY) WARNING $(call toprel, $(OPENSSL_DIR)) not found (make openssl_install), using system PATH)

View File

@ -316,7 +316,6 @@ 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 ${InSecUtilities} $(DESC_InSecUtilities)
!insertmacro MUI_DESCRIPTION_TEXT ${InSecDrivers} $(DESC_InSecDrivers)
!insertmacro MUI_DESCRIPTION_TEXT ${InSecInstallDrivers} $(DESC_InSecInstallDrivers)

View File

@ -23,8 +23,9 @@
<!-- telemetry -->
<elementname>TelemetryTx</elementname>
<elementname>TelemetryRx</elementname>
<!-- com -->
<elementname>RadioTx</elementname>
<elementname>RadioRx</elementname>
<!-- com -->
<elementname>Com2UsbBridge</elementname>
<elementname>Usb2ComBridge</elementname>
<!-- optional -->
@ -54,8 +55,9 @@
<!-- telemetry -->
<elementname>TelemetryTx</elementname>
<elementname>TelemetryRx</elementname>
<!-- com -->
<elementname>RadioTx</elementname>
<elementname>RadioRx</elementname>
<!-- com -->
<elementname>Com2UsbBridge</elementname>
<elementname>Usb2ComBridge</elementname>
<!-- optional -->
@ -89,8 +91,9 @@
<!-- telemetry -->
<elementname>TelemetryTx</elementname>
<elementname>TelemetryRx</elementname>
<!-- com -->
<elementname>RadioTx</elementname>
<elementname>RadioRx</elementname>
<!-- com -->
<elementname>Com2UsbBridge</elementname>
<elementname>Usb2ComBridge</elementname>
<!-- optional -->