mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-01-17 02:52:12 +01:00
Merge remote-tracking branch 'origin/Brian-PipXtreme-V2' into Brian-PipXtreme-V2
This commit is contained in:
commit
16c9c145ff
24
Makefile
24
Makefile
@ -68,7 +68,7 @@ help:
|
||||
@echo " Here is a summary of the available targets:"
|
||||
@echo
|
||||
@echo " [Tool Installers]"
|
||||
@echo " qt_sdk_install - Install the QT v4.6.2 tools"
|
||||
@echo " qt_sdk_install - Install the QT v4.7.3 tools"
|
||||
@echo " arm_sdk_install - Install the Code Sourcery ARM gcc toolchain"
|
||||
@echo " openocd_install - Install the OpenOCD JTAG daemon"
|
||||
@echo " stm32flash_install - Install the stm32flash tool for unbricking boards"
|
||||
@ -160,20 +160,30 @@ $(BUILD_DIR):
|
||||
###############################################################
|
||||
|
||||
# Set up QT toolchain
|
||||
QT_SDK_DIR := $(TOOLS_DIR)/qtsdk-2010.02
|
||||
QT_SDK_DIR := $(TOOLS_DIR)/qtsdk-v1.2
|
||||
|
||||
.PHONY: qt_sdk_install
|
||||
qt_sdk_install: QT_SDK_URL := http://get.qt.nokia.com/qtsdk/qt-sdk-linux-x86-opensource-2010.02.bin
|
||||
qt_sdk_install: QT_SDK_FILE := $(notdir $(QT_SDK_URL))
|
||||
qt_sdk_install: QT_SDK_URL := http://www.developer.nokia.com/dp?uri=http://sw.nokia.com/id/8ea74da4-fec1-4277-8b26-c58cc82e204b/Qt_SDK_Lin32_offline
|
||||
qt_sdk_install: QT_SDK_FILE := Qt_SDK_Lin32_offline_v1_2_en.run
|
||||
#qt_sdk_install: QT_SDK_URL := http://www.developer.nokia.com/dp?uri=http://sw.nokia.com/id/c365bbf5-c2b9-4dda-9c1f-34b2c8d07785/Qt_SDK_Lin32_offline_v1_1_2
|
||||
#qt_sdk_install: QT_SDK_FILE := Qt_SDK_Lin32_offline_v1_1_2_en.run
|
||||
# order-only prereq on directory existance:
|
||||
qt_sdk_install : | $(DL_DIR) $(TOOLS_DIR)
|
||||
qt_sdk_install: qt_sdk_clean
|
||||
# download the source only if it's newer than what we already have
|
||||
$(V1) wget -N -P "$(DL_DIR)" "$(QT_SDK_URL)"
|
||||
$(V1) wget -N --content-disposition -P "$(DL_DIR)" "$(QT_SDK_URL)"
|
||||
|
||||
# tell the user exactly which path they should select in the GUI
|
||||
$(V1) echo "*** NOTE NOTE NOTE ***"
|
||||
$(V1) echo "*"
|
||||
$(V1) echo "* In the GUI, please use exactly this path as the installation path:"
|
||||
$(V1) echo "* $(QT_SDK_DIR)"
|
||||
$(V1) echo "*"
|
||||
$(V1) echo "*** NOTE NOTE NOTE ***"
|
||||
|
||||
#installer is an executable, make it executable and run it
|
||||
$(V1) chmod u+x "$(DL_DIR)/$(QT_SDK_FILE)"
|
||||
"$(DL_DIR)/$(QT_SDK_FILE)" --installdir "$(QT_SDK_DIR)"
|
||||
$(V1) "$(DL_DIR)/$(QT_SDK_FILE)" -style cleanlooks
|
||||
|
||||
.PHONY: qt_sdk_clean
|
||||
qt_sdk_clean:
|
||||
@ -257,7 +267,7 @@ stm32flash_clean:
|
||||
##############################
|
||||
|
||||
ifeq ($(shell [ -d "$(QT_SDK_DIR)" ] && echo "exists"), exists)
|
||||
QMAKE=$(QT_SDK_DIR)/qt/bin/qmake
|
||||
QMAKE=$(QT_SDK_DIR)/Desktop/Qt/4.8.0/gcc/bin/qmake
|
||||
else
|
||||
# not installed, hope it's in the path...
|
||||
QMAKE=qmake
|
||||
|
@ -60,7 +60,8 @@ typedef struct {
|
||||
uint8_t data_size;
|
||||
} PHPacketHeader;
|
||||
|
||||
#define PH_MAX_DATA (PH_MAX_PACKET - sizeof(PHPacketHeader) - RS_ECC_NPARITY)
|
||||
#define PH_MAX_DATA (PIOS_PH_MAX_PACKET - sizeof(PHPacketHeader) - RS_ECC_NPARITY)
|
||||
#define PH_PACKET_SIZE(p) (p->data + p->header.data_size - (uint8_t*)p + RS_ECC_NPARITY)
|
||||
typedef struct {
|
||||
PHPacketHeader header;
|
||||
uint8_t data[PH_MAX_DATA + RS_ECC_NPARITY];
|
||||
@ -70,24 +71,20 @@ typedef struct {
|
||||
uint8_t txWinSize;
|
||||
uint16_t maxConnections;
|
||||
uint32_t id;
|
||||
void *dev;
|
||||
uint8_t (*output_stream)(void *dev, PHPacketHandle packet);
|
||||
void (*set_baud)(uint32_t baud);
|
||||
void (*data_handler)(void *dev, uint8_t *data, uint8_t len);
|
||||
void (*receiver_handler)(void *dev, uint8_t *data, uint8_t len);
|
||||
} PacketHandlerConfig;
|
||||
|
||||
typedef int32_t (*PHOutputStream)(PHPacketHandle packet);
|
||||
typedef void (*PHDataHandler)(uint8_t *data, uint8_t len);
|
||||
|
||||
typedef void* PHInstHandle;
|
||||
|
||||
// Public functions
|
||||
PHInstHandle PHInitialize(PacketHandlerConfig *cfg);
|
||||
void PHRegisterOutputStream(PHInstHandle h, PHOutputStream f);
|
||||
void PHRegisterDataHandler(PHInstHandle h, PHDataHandler f);
|
||||
uint32_t PHConnect(PHInstHandle h, uint32_t dest_id);
|
||||
PHPacketHandle PHGetRXPacket(PHInstHandle h);
|
||||
PHPacketHandle PHGetTXPacket(PHInstHandle h);
|
||||
PHPacketHandle PHReserveTXPacket(PHInstHandle h);
|
||||
void PHReleaseLock(PHInstHandle h, bool keep_packet);
|
||||
void PHReleaseTXPacket(PHInstHandle h, PHPacketHandle p);
|
||||
uint8_t PHTransmitPacket(PHInstHandle h, PHPacketHandle p);
|
||||
uint8_t PHReceivePacket(PHInstHandle h, PHPacketHandle p);
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include "aes.h"
|
||||
#include "ecc.h"
|
||||
|
||||
extern char *debug_msg;
|
||||
|
||||
// Private types and constants
|
||||
typedef struct {
|
||||
PacketHandlerConfig cfg;
|
||||
@ -42,6 +44,8 @@ typedef struct {
|
||||
PHPacket rx_packet;
|
||||
PHOutputStream stream;
|
||||
xSemaphoreHandle lock;
|
||||
PHOutputStream output_stream;
|
||||
PHDataHandler data_handler;
|
||||
} PHPacketData, *PHPacketDataHandle;
|
||||
|
||||
// Private functions
|
||||
@ -49,14 +53,6 @@ static uint8_t PHLSendAck(PHPacketDataHandle data, PHPacketHandle p);
|
||||
static uint8_t PHLSendNAck(PHPacketDataHandle data, PHPacketHandle p);
|
||||
static uint8_t PHLTransmitPacket(PHPacketDataHandle data, PHPacketHandle p);
|
||||
|
||||
/*
|
||||
static void
|
||||
byte_err (int err, int loc, unsigned char *dst)
|
||||
{
|
||||
dst[loc-1] ^= err;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initialize the Packet Handler library
|
||||
* \param[in] txWinSize The transmission window size (number of tx packet buffers).
|
||||
@ -92,6 +88,30 @@ PHInstHandle PHInitialize(PacketHandlerConfig *cfg)
|
||||
return (PHInstHandle)data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an output stream handler
|
||||
* \param[in] h The packet handler instance data pointer.
|
||||
* \param[in] f The output stream handler function
|
||||
*/
|
||||
void PHRegisterOutputStream(PHInstHandle h, PHOutputStream f)
|
||||
{
|
||||
PHPacketDataHandle data = (PHPacketDataHandle)h;
|
||||
|
||||
data->output_stream = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a data handler
|
||||
* \param[in] h The packet handler instance data pointer.
|
||||
* \param[in] f The data handler function
|
||||
*/
|
||||
void PHRegisterDataHandler(PHInstHandle h, PHDataHandler f)
|
||||
{
|
||||
PHPacketDataHandle data = (PHPacketDataHandle)h;
|
||||
|
||||
data->data_handler = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a packet out of the transmit buffer.
|
||||
* \param[in] h The packet handler instance data pointer.
|
||||
@ -104,58 +124,6 @@ uint32_t PHConnect(PHInstHandle h, uint32_t dest_id)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily reserve the next packet in the TX packet window.
|
||||
* This function places a tempoary hold on the next TX packet and
|
||||
* retains the packet handler lock.
|
||||
*
|
||||
* NOTE: PHReleaseLock must be called to release the lock and retain
|
||||
* or release the reserved packet.
|
||||
*
|
||||
* \param[in] h The packet handler instance data pointer.
|
||||
* \return PHPacketHandle A pointer to the packet buffer.
|
||||
* \return 0 No packets buffers avaiable in the transmit window.
|
||||
*/
|
||||
PHPacketHandle PHReserveTXPacket(PHInstHandle h)
|
||||
{
|
||||
PHPacketDataHandle data = (PHPacketDataHandle)h;
|
||||
|
||||
// Lock
|
||||
xSemaphoreTakeRecursive(data->lock, portMAX_DELAY);
|
||||
|
||||
// Is the window full?
|
||||
uint8_t next_end = (data->tx_win_end + 1) % data->cfg.txWinSize;
|
||||
if(next_end == data->tx_win_start) {
|
||||
|
||||
// Release the lock
|
||||
xSemaphoreGiveRecursive(data->lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return a pointer to the packet at the end of the TX window.
|
||||
return data->tx_packets + data->tx_win_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a packet out of the transmit buffer and keep the lock.
|
||||
* NOTE: PHReleaseLock must be called to release the lock.
|
||||
* \param[in] h The packet handler instance data pointer.
|
||||
* \param[in] keep_packet Maintain a permanent (until released) lock on the packet.
|
||||
*/
|
||||
void PHReleaseLock(PHInstHandle h, bool keep_packet)
|
||||
{
|
||||
PHPacketDataHandle data = (PHPacketDataHandle)h;
|
||||
uint8_t next_end = (data->tx_win_end + 1) % data->cfg.txWinSize;
|
||||
|
||||
// Increment the end index if packet is being kept.
|
||||
if (keep_packet)
|
||||
data->tx_win_end = next_end;
|
||||
|
||||
// Release lock
|
||||
xSemaphoreGiveRecursive(data->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a packet out of the transmit buffer.
|
||||
* \param[in] h The packet handler instance data pointer.
|
||||
@ -164,8 +132,22 @@ void PHReleaseLock(PHInstHandle h, bool keep_packet)
|
||||
*/
|
||||
PHPacketHandle PHGetTXPacket(PHInstHandle h)
|
||||
{
|
||||
PHPacketHandle p = PHReserveTXPacket(h);
|
||||
PHReleaseLock(p, 1);
|
||||
PHPacketDataHandle data = (PHPacketDataHandle)h;
|
||||
|
||||
// Lock
|
||||
xSemaphoreTakeRecursive(data->lock, portMAX_DELAY);
|
||||
PHPacketHandle p = data->tx_packets + data->tx_win_end;
|
||||
|
||||
// Is the window full?
|
||||
uint8_t next_end = (data->tx_win_end + 1) % data->cfg.txWinSize;
|
||||
if(next_end == data->tx_win_start)
|
||||
return NULL;
|
||||
data->tx_win_end = next_end;
|
||||
|
||||
// Release lock
|
||||
xSemaphoreGiveRecursive(data->lock);
|
||||
|
||||
// Return a pointer to the packet at the end of the TX window.
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -268,8 +250,8 @@ uint8_t PHReceivePacket(PHInstHandle h, PHPacketHandle p)
|
||||
PHLSendAck(data, p);
|
||||
|
||||
// Pass on the data.
|
||||
if(data->cfg.data_handler)
|
||||
data->cfg.data_handler(data->cfg.dev, p->data, p->header.data_size);
|
||||
if(data->data_handler)
|
||||
data->data_handler(p->data, p->header.data_size);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -307,15 +289,18 @@ uint8_t PHReceivePacket(PHInstHandle h, PHPacketHandle p)
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
case PACKET_TYPE_DATA:
|
||||
|
||||
if (!rx_error)
|
||||
|
||||
// Pass on the data to the receiver handler.
|
||||
if(data->cfg.data_handler)
|
||||
data->cfg.data_handler(data->cfg.dev, p->data, p->header.data_size);
|
||||
if(data->data_handler)
|
||||
data->data_handler(p->data, p->header.data_size);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -331,14 +316,17 @@ uint8_t PHReceivePacket(PHInstHandle h, PHPacketHandle p)
|
||||
static uint8_t PHLTransmitPacket(PHPacketDataHandle data, PHPacketHandle p)
|
||||
{
|
||||
|
||||
if(!data->output_stream)
|
||||
return 0;
|
||||
|
||||
// Set the sequence ID to the current ID.
|
||||
p->header.tx_seq = data->tx_seq_id++;
|
||||
|
||||
// Add the error correcting code.
|
||||
encode_data((unsigned char*)p, PHPacketSize(p), (unsigned char*)p);
|
||||
|
||||
|
||||
// Transmit the packet using the output stream.
|
||||
if(!data->cfg.output_stream(data->cfg.dev, p))
|
||||
if(data->output_stream(p) == -1)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@ -362,10 +350,8 @@ static uint8_t PHLSendAck(PHPacketDataHandle data, PHPacketHandle p)
|
||||
ack.rx_seq = p->header.tx_seq;
|
||||
ack.data_size = 0;
|
||||
|
||||
// Set the packet.
|
||||
PHLTransmitPacket(data, (PHPacketHandle)&ack);
|
||||
|
||||
return 1;
|
||||
// Send the packet.
|
||||
return PHLTransmitPacket(data, (PHPacketHandle)&ack);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -387,7 +373,5 @@ static uint8_t PHLSendNAck(PHPacketDataHandle data, PHPacketHandle p)
|
||||
ack.data_size = 0;
|
||||
|
||||
// Set the packet.
|
||||
PHLTransmitPacket(data, (PHPacketHandle)&ack);
|
||||
|
||||
return 1;
|
||||
return PHLTransmitPacket(data, (PHPacketHandle)&ack);
|
||||
}
|
||||
|
@ -30,28 +30,34 @@
|
||||
|
||||
// ****************
|
||||
|
||||
#include "openpilot.h"
|
||||
#include "hwsettings.h"
|
||||
#include "radiocombridge.h"
|
||||
#include <openpilot.h>
|
||||
#include <hwsettings.h>
|
||||
#include <radiocombridge.h>
|
||||
#include <packet_handler.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "ecc.h"
|
||||
|
||||
extern char *debug_msg;
|
||||
|
||||
// ****************
|
||||
// Private functions
|
||||
|
||||
static void radio2ComBridgeTask(void *parameters);
|
||||
static void com2RadioBridgeTask(void *parameters);
|
||||
static int32_t transmitData(uint8_t * data, int32_t length);
|
||||
static int32_t transmitPacket(PHPacketHandle packet);
|
||||
static void receiveData(uint8_t *buf, uint8_t len);
|
||||
static void updateSettings();
|
||||
|
||||
// ****************
|
||||
// Private constants
|
||||
|
||||
//#define STACK_SIZE_BYTES 280
|
||||
#define STACK_SIZE_BYTES 350
|
||||
#define STACK_SIZE_BYTES 300
|
||||
#define TASK_PRIORITY (tskIDLE_PRIORITY + 1)
|
||||
|
||||
#define BRIDGE_BUF_LEN 10
|
||||
#define BRIDGE_BUF_LEN 128
|
||||
|
||||
// ****************
|
||||
// Private types
|
||||
@ -76,6 +82,13 @@ typedef struct {
|
||||
uint32_t com_tx_errors;
|
||||
uint32_t radio_tx_errors;
|
||||
|
||||
// The packet handler.
|
||||
PHInstHandle packet_handler;
|
||||
portTickType send_timeout;
|
||||
uint16_t min_packet_size;
|
||||
|
||||
PHPacket packet;
|
||||
|
||||
} RadioComBridgeData;
|
||||
|
||||
// ****************
|
||||
@ -92,8 +105,8 @@ static int32_t RadioComBridgeStart(void)
|
||||
{
|
||||
if(data) {
|
||||
// Start the tasks
|
||||
xTaskCreate(radio2ComBridgeTask, (signed char *)"Radio2ComBridge", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &(data->radio2ComBridgeTaskHandle));
|
||||
xTaskCreate(com2RadioBridgeTask, (signed char *)"Com2RadioBridge", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &(data->com2RadioBridgeTaskHandle));
|
||||
xTaskCreate(radio2ComBridgeTask, (signed char *)"Radio2ComBridge", STACK_SIZE_BYTES/2, NULL, TASK_PRIORITY, &(data->radio2ComBridgeTaskHandle));
|
||||
xTaskCreate(com2RadioBridgeTask, (signed char *)"Com2RadioBridge", STACK_SIZE_BYTES/2, NULL, TASK_PRIORITY, &(data->com2RadioBridgeTaskHandle));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -122,7 +135,7 @@ static int32_t RadioComBridgeInitialize(void)
|
||||
PIOS_Assert(data->radio2com_buf);
|
||||
data->com2radio_buf = pvPortMalloc(BRIDGE_BUF_LEN);
|
||||
PIOS_Assert(data->com2radio_buf);
|
||||
|
||||
|
||||
// Initialise UAVTalk
|
||||
data->uavTalkCon = UAVTalkInitialize(&transmitData);
|
||||
|
||||
@ -130,6 +143,22 @@ static int32_t RadioComBridgeInitialize(void)
|
||||
data->com_tx_errors = 0;
|
||||
data->radio_tx_errors = 0;
|
||||
|
||||
// Initialize the packet handler
|
||||
PacketHandlerConfig phcfg = {
|
||||
.txWinSize = PIOS_PH_TX_WIN_SIZE,
|
||||
.maxConnections = PIOS_PH_MAX_CONNECTIONS,
|
||||
.id = 0x36249acb,
|
||||
};
|
||||
data->packet_handler = PHInitialize(&phcfg);
|
||||
|
||||
// Register the callbacks with the packet handler
|
||||
PHRegisterOutputStream(data->packet_handler, transmitPacket);
|
||||
PHRegisterDataHandler(data->packet_handler, receiveData);
|
||||
|
||||
// Initialize the packet send timeout
|
||||
data->send_timeout = 25; // ms
|
||||
data->min_packet_size = 50;
|
||||
|
||||
updateSettings();
|
||||
|
||||
return 0;
|
||||
@ -148,11 +177,7 @@ static void radio2ComBridgeTask(void *parameters)
|
||||
// Receive data from the radio port
|
||||
rx_bytes = PIOS_COM_ReceiveBuffer(data->radio_port, data->radio2com_buf, BRIDGE_BUF_LEN, 500);
|
||||
if (rx_bytes > 0) {
|
||||
/* Send the received data to the com port */
|
||||
if (PIOS_COM_SendBuffer(data->com_port, data->radio2com_buf, rx_bytes) != rx_bytes) {
|
||||
/* Error on transmit */
|
||||
data->com_tx_errors++;
|
||||
}
|
||||
PHReceivePacket(data->packet_handler, (PHPacketHandle)data->radio2com_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -162,22 +187,69 @@ static void radio2ComBridgeTask(void *parameters)
|
||||
*/
|
||||
static void com2RadioBridgeTask(void * parameters)
|
||||
{
|
||||
uint32_t rx_bytes = 0;
|
||||
portTickType packet_start_time = 0;
|
||||
uint32_t timeout = 500;
|
||||
|
||||
/* Handle usart/usb -> radio direction */
|
||||
while (1) {
|
||||
uint32_t rx_bytes;
|
||||
|
||||
// Receive data from the com port
|
||||
rx_bytes = PIOS_COM_ReceiveBuffer(data->com_port, data->com2radio_buf, BRIDGE_BUF_LEN, 500);
|
||||
//debug_msg = "COM receive";
|
||||
uint32_t cur_rx_bytes = PIOS_COM_ReceiveBuffer(data->com_port, data->com2radio_buf +
|
||||
rx_bytes, BRIDGE_BUF_LEN - rx_bytes, timeout);
|
||||
//debug_msg = "COM receive done";
|
||||
rx_bytes += cur_rx_bytes;
|
||||
|
||||
// Do we have an data to send?
|
||||
if (rx_bytes > 0) {
|
||||
|
||||
/* Send the received data to the radio port */
|
||||
if (PIOS_COM_SendBuffer(data->radio_port, data->com2radio_buf, rx_bytes) != rx_bytes) {
|
||||
/* Error on transmit */
|
||||
data->radio_tx_errors++;
|
||||
// Check how long since last update
|
||||
portTickType cur_sys_time = xTaskGetTickCount();
|
||||
|
||||
// Is this the start of a packet?
|
||||
if(packet_start_time == 0)
|
||||
packet_start_time = cur_sys_time;
|
||||
|
||||
// Just send the packet on wraparound
|
||||
bool send_packet = (cur_sys_time < packet_start_time);
|
||||
if (!send_packet)
|
||||
{
|
||||
portTickType dT = (cur_sys_time - packet_start_time) / portTICK_RATE_MS;
|
||||
if (dT > data->send_timeout)
|
||||
send_packet = true;
|
||||
else
|
||||
timeout = data->send_timeout - dT;
|
||||
}
|
||||
|
||||
// Also send the packet if the size is over the minimum.
|
||||
send_packet |= (rx_bytes > data->min_packet_size);
|
||||
|
||||
// Should we send this packet?
|
||||
if (send_packet)
|
||||
{
|
||||
// Get a TX packet from the packet handler
|
||||
PHPacketHandle p = PHGetTXPacket(data->packet_handler);
|
||||
|
||||
// Initialize the packet.
|
||||
//p->header.type = PACKET_TYPE_ACKED_DATA;
|
||||
p->header.type = PACKET_TYPE_DATA;
|
||||
p->header.data_size = rx_bytes;
|
||||
|
||||
// Copy the data into the packet.
|
||||
memcpy(p->data, data->com2radio_buf, rx_bytes);
|
||||
|
||||
// Transmit the packet
|
||||
PHTransmitPacket(data->packet_handler, p);
|
||||
|
||||
// Reset the timeout
|
||||
timeout = 500;
|
||||
rx_bytes = 0;
|
||||
packet_start_time = 0;
|
||||
}
|
||||
|
||||
// Pass the data through UAVTalk
|
||||
//for (uint8_t i = 0; i < rx_bytes; i++)
|
||||
//for (uint8_t i = 0; i < cur_rx_bytes; i++)
|
||||
//UAVTalkProcessInputStream(data->uavTalkCon, data->com2radio_buf[i]);
|
||||
}
|
||||
}
|
||||
@ -196,6 +268,35 @@ static int32_t transmitData(uint8_t *buf, int32_t length)
|
||||
return PIOS_COM_SendBuffer(data->com_port, buf, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit a packet to the radio port.
|
||||
* \param[in] buf Data buffer to send
|
||||
* \param[in] length Length of buffer
|
||||
* \return -1 on failure
|
||||
* \return number of bytes transmitted on success
|
||||
*/
|
||||
static int32_t transmitPacket(PHPacketHandle p)
|
||||
{
|
||||
static uint32_t cntr = 0;
|
||||
DEBUG_PRINTF(2, "Sending: %d %d\n\r", p->header.data_size, cntr++);
|
||||
int32_t ret = PIOS_COM_SendBuffer(data->radio_port, (uint8_t*)p, PH_PACKET_SIZE(p));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive a packet
|
||||
* \param[in] buf The received data buffer
|
||||
* \param[in] length Length of buffer
|
||||
*/
|
||||
static void receiveData(uint8_t *buf, uint8_t len)
|
||||
{
|
||||
DEBUG_PRINTF(2, "Received: %d\n\r", len);
|
||||
/* Send the received data to the com port */
|
||||
if (PIOS_COM_SendBuffer(data->com_port, buf, len) != len)
|
||||
/* Error on transmit */
|
||||
data->com_tx_errors++;
|
||||
}
|
||||
|
||||
static void updateSettings()
|
||||
{
|
||||
if (data->com_port) {
|
||||
|
@ -166,9 +166,10 @@ extern uint32_t pios_com_rfm22b_id;
|
||||
*/
|
||||
#define PIOS_COM_DEBUG PIOS_COM_FLEXI
|
||||
#define PIOS_COM_BRIDGE_COM PIOS_COM_TELEM_SERIAL
|
||||
//#define PIOS_COM_BRIDGE_COM PIOS_COM_FLEXI
|
||||
#define PIOS_COM_BRIDGE_RADIO PIOS_COM_RFM22B_RF
|
||||
|
||||
#define DEBUG_LEVEL 1
|
||||
#define DEBUG_LEVEL 2
|
||||
#if DEBUG_LEVEL > 0
|
||||
#define DEBUG_PRINTF(level, ...) if(level <= DEBUG_LEVEL) { PIOS_COM_SendFormattedStringNonBlocking(PIOS_COM_DEBUG, __VA_ARGS__); }
|
||||
#else
|
||||
@ -229,26 +230,28 @@ extern uint32_t pios_com_rfm22b_id;
|
||||
// RFM22
|
||||
//-------------------------
|
||||
|
||||
//#define RFM22_EXT_INT_USE
|
||||
#define RFM22_EXT_INT_USE
|
||||
|
||||
#define RFM22_PIOS_SPI PIOS_SPI_PORT // SPIx
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
#define RFM22_EXT_INT_PORT_SOURCE GPIO_PortSourceGPIOA
|
||||
#define RFM22_EXT_INT_PIN_SOURCE GPIO_PinSource2
|
||||
|
||||
#define RFM22_EXT_INT_LINE EXTI_Line2
|
||||
#define RFM22_EXT_INT_IRQn EXTI2_IRQn
|
||||
#define RFM22_EXT_INT_FUNC EXTI2_IRQHandler
|
||||
|
||||
#define RFM22_EXT_INT_PRIORITY 1
|
||||
#define PIOS_RFM22_EXTI_GPIO_PORT GPIOA
|
||||
#define PIOS_RFM22_EXTI_GPIO_PIN GPIO_Pin_2
|
||||
#define PIOS_RFM22_EXTI_PORT_SOURCE GPIO_PortSourceGPIOA
|
||||
#define PIOS_RFM22_EXTI_PIN_SOURCE GPIO_PinSource2
|
||||
#define PIOS_RFM22_EXTI_CLK RCC_APB2Periph_GPIOA
|
||||
#define PIOS_RFM22_EXTI_LINE EXTI_Line2
|
||||
#define PIOS_RFM22_EXTI_IRQn EXTI2_IRQn
|
||||
#define PIOS_RFM22_EXTI_PRIO PIOS_IRQ_PRIO_LOW
|
||||
#endif
|
||||
|
||||
//-------------------------
|
||||
// Packet Handler
|
||||
//-------------------------
|
||||
|
||||
#define PH_MAX_PACKET 255
|
||||
#define PIOS_PH_MAX_PACKET 255
|
||||
#define PIOS_PH_TX_WIN_SIZE 3
|
||||
#define PIOS_PH_MAX_CONNECTIONS 1
|
||||
|
||||
//-------------------------
|
||||
// Reed-Solomon ECC
|
||||
|
@ -79,7 +79,10 @@
|
||||
#define TX_PREAMBLE_NIBBLES 12 // 7 to 511 (number of nibbles)
|
||||
#define RX_PREAMBLE_NIBBLES 6 // 5 to 31 (number of nibbles)
|
||||
|
||||
#define FIFO_SIZE 64 // the size of the rf modules internal FIFO buffers
|
||||
// the size of the rf modules internal transmit buffers.
|
||||
#define TX_BUFFER_SIZE 256
|
||||
// the size of the rf modules internal FIFO buffers
|
||||
#define FIFO_SIZE 64
|
||||
|
||||
#define TX_FIFO_HI_WATERMARK 62 // 0-63
|
||||
#define TX_FIFO_LO_WATERMARK 32 // 0-63
|
||||
@ -137,8 +140,6 @@
|
||||
// 10-nibble tx preamble length
|
||||
// AFC enabled
|
||||
|
||||
#define LOOKUP_SIZE 14
|
||||
|
||||
/* Local type definitions */
|
||||
enum pios_rfm22b_dev_magic {
|
||||
PIOS_RFM22B_DEV_MAGIC = 0x68e971b6,
|
||||
@ -148,8 +149,6 @@ struct pios_rfm22b_dev {
|
||||
enum pios_rfm22b_dev_magic magic;
|
||||
const struct pios_rfm22b_cfg *cfg;
|
||||
|
||||
xTaskHandle taskHandle;
|
||||
|
||||
uint32_t countdownTimer;
|
||||
|
||||
pios_com_callback rx_in_cb;
|
||||
@ -157,18 +156,32 @@ struct pios_rfm22b_dev {
|
||||
pios_com_callback tx_out_cb;
|
||||
uint32_t tx_out_context;
|
||||
|
||||
PHInstHandle packet_handler;
|
||||
PHPacketHandle cur_tx_packet;
|
||||
};
|
||||
|
||||
uint32_t random32 = 0x459ab8d8;
|
||||
|
||||
/* Local function forwared declarations */
|
||||
static uint8_t PIOS_RFM22B_send_packet(void *rfm22b, PHPacketHandle packet);
|
||||
static void PIOS_RFM22B_receive_data(void *rfm22b, uint8_t *data, uint8_t len);
|
||||
static void PIOS_RFM22B_Task(void *parameters);
|
||||
|
||||
void rfm22_processInt(void);
|
||||
void PIOS_RFM22_EXT_Int(void);
|
||||
void rfm22_setTxMode(uint8_t mode);
|
||||
|
||||
// SPI read/write functions
|
||||
void rfm22_startBurstWrite(uint8_t addr);
|
||||
inline void rfm22_burstWrite(uint8_t data)
|
||||
{
|
||||
PIOS_SPI_TransferByte(RFM22_PIOS_SPI, data);
|
||||
}
|
||||
void rfm22_endBurstWrite(void);
|
||||
void rfm22_write(uint8_t addr, uint8_t data);
|
||||
void rfm22_startBurstRead(uint8_t addr);
|
||||
inline uint8_t rfm22_burstRead(void)
|
||||
{
|
||||
return PIOS_SPI_TransferByte(RFM22_PIOS_SPI, 0xff);
|
||||
}
|
||||
void rfm22_endBurstRead(void);
|
||||
uint8_t rfm22_read(uint8_t addr);
|
||||
uint8_t rfm22_txStart();
|
||||
|
||||
/* Provide a COM driver */
|
||||
static void PIOS_RFM22B_ChangeBaud(uint32_t rfm22b_id, uint32_t baud);
|
||||
@ -186,35 +199,65 @@ const struct pios_com_driver pios_rfm22b_com_driver = {
|
||||
.bind_rx_cb = PIOS_RFM22B_RegisterRxCallback,
|
||||
};
|
||||
|
||||
// External interrupt configuration
|
||||
static const struct pios_exti_cfg pios_exti_rfm22b_cfg __exti_config = {
|
||||
.vector = PIOS_RFM22_EXT_Int,
|
||||
.line = PIOS_RFM22_EXTI_LINE,
|
||||
.pin = {
|
||||
.gpio = PIOS_RFM22_EXTI_GPIO_PORT,
|
||||
.init = {
|
||||
.GPIO_Pin = PIOS_RFM22_EXTI_GPIO_PIN,
|
||||
.GPIO_Mode = GPIO_Mode_IN_FLOATING,
|
||||
},
|
||||
},
|
||||
.irq = {
|
||||
.init = {
|
||||
.NVIC_IRQChannel = PIOS_RFM22_EXTI_IRQn,
|
||||
.NVIC_IRQChannelPreemptionPriority = PIOS_RFM22_EXTI_PRIO,
|
||||
.NVIC_IRQChannelSubPriority = 0,
|
||||
.NVIC_IRQChannelCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
.exti = {
|
||||
.init = {
|
||||
.EXTI_Line = PIOS_RFM22_EXTI_LINE,
|
||||
.EXTI_Mode = EXTI_Mode_Interrupt,
|
||||
.EXTI_Trigger = EXTI_Trigger_Falling,
|
||||
.EXTI_LineCmd = ENABLE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// xtal 10 ppm, 434MHz
|
||||
const uint32_t data_rate[LOOKUP_SIZE] = { 500, 1000, 2000, 4000, 8000, 9600, 16000, 19200, 24000, 32000, 64000, 128000, 192000, 256000};
|
||||
const uint8_t modulation_index[LOOKUP_SIZE] = { 16, 8, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
const uint32_t freq_deviation[LOOKUP_SIZE] = { 4000, 4000, 4000, 4000, 4000, 4800, 8000, 9600, 12000, 16000, 32000, 64000, 96000, 128000};
|
||||
const uint32_t rx_bandwidth[LOOKUP_SIZE] = { 17500, 17500, 17500, 17500, 17500, 19400, 32200, 38600, 51200, 64100, 137900, 269300, 420200, 518800};
|
||||
const int8_t est_rx_sens_dBm[LOOKUP_SIZE] = { -118, -118, -117, -116, -115, -115, -112, -112, -110, -109, -106, -103, -101, -100}; // estimated receiver sensitivity for BER = 1E-3
|
||||
#define LOOKUP_SIZE 14
|
||||
const uint32_t data_rate[] = { 500, 1000, 2000, 4000, 8000, 9600, 16000, 19200, 24000, 32000, 64000, 128000, 192000, 256000};
|
||||
const uint8_t modulation_index[] = { 16, 8, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
const uint32_t freq_deviation[] = { 4000, 4000, 4000, 4000, 4000, 4800, 8000, 9600, 12000, 16000, 32000, 64000, 96000, 128000};
|
||||
const uint32_t rx_bandwidth[] = { 17500, 17500, 17500, 17500, 17500, 19400, 32200, 38600, 51200, 64100, 137900, 269300, 420200, 518800};
|
||||
const int8_t est_rx_sens_dBm[] = { -118, -118, -117, -116, -115, -115, -112, -112, -110, -109, -106, -103, -101, -100}; // estimated receiver sensitivity for BER = 1E-3
|
||||
|
||||
const uint8_t reg_1C[LOOKUP_SIZE] = { 0x37, 0x37, 0x37, 0x37, 0x3A, 0x3B, 0x26, 0x28, 0x2E, 0x16, 0x07, 0x83, 0x8A, 0x8C}; // rfm22_if_filter_bandwidth
|
||||
const uint8_t reg_1C[] = { 0x37, 0x37, 0x37, 0x37, 0x3A, 0x3B, 0x26, 0x28, 0x2E, 0x16, 0x07, 0x83, 0x8A, 0x8C}; // rfm22_if_filter_bandwidth
|
||||
|
||||
const uint8_t reg_1D[LOOKUP_SIZE] = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44}; // rfm22_afc_loop_gearshift_override
|
||||
const uint8_t reg_1E[LOOKUP_SIZE] = { 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x02}; // rfm22_afc_timing_control
|
||||
const uint8_t reg_1D[] = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44}; // rfm22_afc_loop_gearshift_override
|
||||
const uint8_t reg_1E[] = { 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x02}; // rfm22_afc_timing_control
|
||||
|
||||
const uint8_t reg_1F[LOOKUP_SIZE] = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03}; // rfm22_clk_recovery_gearshift_override
|
||||
const uint8_t reg_20[LOOKUP_SIZE] = { 0xE8, 0xF4, 0xFA, 0x70, 0x3F, 0x34, 0x3F, 0x34, 0x2A, 0x3F, 0x3F, 0x5E, 0x3F, 0x2F}; // rfm22_clk_recovery_oversampling_ratio
|
||||
const uint8_t reg_21[LOOKUP_SIZE] = { 0x60, 0x20, 0x00, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 0x01, 0x02, 0x02}; // rfm22_clk_recovery_offset2
|
||||
const uint8_t reg_22[LOOKUP_SIZE] = { 0x20, 0x41, 0x83, 0x06, 0x0C, 0x75, 0x0C, 0x75, 0x12, 0x0C, 0x0C, 0x5D, 0x0C, 0xBB}; // rfm22_clk_recovery_offset1
|
||||
const uint8_t reg_23[LOOKUP_SIZE] = { 0xC5, 0x89, 0x12, 0x25, 0x4A, 0x25, 0x4A, 0x25, 0x6F, 0x4A, 0x4A, 0x86, 0x4A, 0x0D}; // rfm22_clk_recovery_offset0
|
||||
const uint8_t reg_24[LOOKUP_SIZE] = { 0x00, 0x00, 0x00, 0x02, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07}; // rfm22_clk_recovery_timing_loop_gain1
|
||||
const uint8_t reg_25[LOOKUP_SIZE] = { 0x0A, 0x23, 0x85, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x74, 0xFF, 0xFF}; // rfm22_clk_recovery_timing_loop_gain0
|
||||
const uint8_t reg_1F[] = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03}; // rfm22_clk_recovery_gearshift_override
|
||||
const uint8_t reg_20[] = { 0xE8, 0xF4, 0xFA, 0x70, 0x3F, 0x34, 0x3F, 0x34, 0x2A, 0x3F, 0x3F, 0x5E, 0x3F, 0x2F}; // rfm22_clk_recovery_oversampling_ratio
|
||||
const uint8_t reg_21[] = { 0x60, 0x20, 0x00, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 0x01, 0x02, 0x02}; // rfm22_clk_recovery_offset2
|
||||
const uint8_t reg_22[] = { 0x20, 0x41, 0x83, 0x06, 0x0C, 0x75, 0x0C, 0x75, 0x12, 0x0C, 0x0C, 0x5D, 0x0C, 0xBB}; // rfm22_clk_recovery_offset1
|
||||
const uint8_t reg_23[] = { 0xC5, 0x89, 0x12, 0x25, 0x4A, 0x25, 0x4A, 0x25, 0x6F, 0x4A, 0x4A, 0x86, 0x4A, 0x0D}; // rfm22_clk_recovery_offset0
|
||||
const uint8_t reg_24[] = { 0x00, 0x00, 0x00, 0x02, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07}; // rfm22_clk_recovery_timing_loop_gain1
|
||||
const uint8_t reg_25[] = { 0x0A, 0x23, 0x85, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x74, 0xFF, 0xFF}; // rfm22_clk_recovery_timing_loop_gain0
|
||||
|
||||
const uint8_t reg_2A[LOOKUP_SIZE] = { 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0E, 0x12, 0x17, 0x31, 0x50, 0x50, 0x50}; // rfm22_afc_limiter .. AFC_pull_in_range = ±AFCLimiter[7:0] x (hbsel+1) x 625 Hz
|
||||
const uint8_t reg_2A[] = { 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0E, 0x12, 0x17, 0x31, 0x50, 0x50, 0x50}; // rfm22_afc_limiter .. AFC_pull_in_range = ±AFCLimiter[7:0] x (hbsel+1) x 625 Hz
|
||||
|
||||
const uint8_t reg_6E[LOOKUP_SIZE] = { 0x04, 0x08, 0x10, 0x20, 0x41, 0x4E, 0x83, 0x9D, 0xC4, 0x08, 0x10, 0x20, 0x31, 0x41}; // rfm22_tx_data_rate1
|
||||
const uint8_t reg_6F[LOOKUP_SIZE] = { 0x19, 0x31, 0x62, 0xC5, 0x89, 0xA5, 0x12, 0x49, 0x9C, 0x31, 0x62, 0xC5, 0x27, 0x89}; // rfm22_tx_data_rate0
|
||||
const uint8_t reg_6E[] = { 0x04, 0x08, 0x10, 0x20, 0x41, 0x4E, 0x83, 0x9D, 0xC4, 0x08, 0x10, 0x20, 0x31, 0x41}; // rfm22_tx_data_rate1
|
||||
const uint8_t reg_6F[] = { 0x19, 0x31, 0x62, 0xC5, 0x89, 0xA5, 0x12, 0x49, 0x9C, 0x31, 0x62, 0xC5, 0x27, 0x89}; // rfm22_tx_data_rate0
|
||||
|
||||
const uint8_t reg_70[LOOKUP_SIZE] = { 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D}; // rfm22_modulation_mode_control1
|
||||
const uint8_t reg_71[LOOKUP_SIZE] = { 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23}; // rfm22_modulation_mode_control2
|
||||
const uint8_t reg_70[] = { 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D}; // rfm22_modulation_mode_control1
|
||||
const uint8_t reg_71[] = { 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23}; // rfm22_modulation_mode_control2
|
||||
|
||||
const uint8_t reg_72[LOOKUP_SIZE] = { 0x06, 0x06, 0x06, 0x06, 0x06, 0x08, 0x0D, 0x0F, 0x13, 0x1A, 0x33, 0x66, 0x9A, 0xCD}; // rfm22_frequency_deviation
|
||||
const uint8_t reg_72[] = { 0x06, 0x06, 0x06, 0x06, 0x06, 0x08, 0x0D, 0x0F, 0x13, 0x1A, 0x33, 0x66, 0x9A, 0xCD}; // rfm22_frequency_deviation
|
||||
|
||||
// ************************************
|
||||
// Scan Spectrum settings
|
||||
@ -224,27 +267,25 @@ const uint8_t reg_72[LOOKUP_SIZE] = { 0x06, 0x06, 0x06, 0x06,
|
||||
// FIFO mode
|
||||
// 5-nibble rx preamble length detection
|
||||
// 10-nibble tx preamble length
|
||||
// AFC disabled
|
||||
|
||||
#define SS_LOOKUP_SIZE 2
|
||||
|
||||
// xtal 1 ppm, 434MHz
|
||||
const uint32_t ss_rx_bandwidth[SS_LOOKUP_SIZE] = { 2600, 10600};
|
||||
const uint32_t ss_rx_bandwidth[] = { 2600, 10600};
|
||||
|
||||
const uint8_t ss_reg_1C[SS_LOOKUP_SIZE] = { 0x51, 0x32}; // rfm22_if_filter_bandwidth
|
||||
const uint8_t ss_reg_1D[SS_LOOKUP_SIZE] = { 0x00, 0x00}; // rfm22_afc_loop_gearshift_override
|
||||
const uint8_t ss_reg_1C[] = { 0x51, 0x32}; // rfm22_if_filter_bandwidth
|
||||
const uint8_t ss_reg_1D[] = { 0x00, 0x00}; // rfm22_afc_loop_gearshift_override
|
||||
|
||||
const uint8_t ss_reg_20[SS_LOOKUP_SIZE] = { 0xE8, 0x38}; // rfm22_clk_recovery_oversampling_ratio
|
||||
const uint8_t ss_reg_21[SS_LOOKUP_SIZE] = { 0x60, 0x02}; // rfm22_clk_recovery_offset2
|
||||
const uint8_t ss_reg_22[SS_LOOKUP_SIZE] = { 0x20, 0x4D}; // rfm22_clk_recovery_offset1
|
||||
const uint8_t ss_reg_23[SS_LOOKUP_SIZE] = { 0xC5, 0xD3}; // rfm22_clk_recovery_offset0
|
||||
const uint8_t ss_reg_24[SS_LOOKUP_SIZE] = { 0x00, 0x07}; // rfm22_clk_recovery_timing_loop_gain1
|
||||
const uint8_t ss_reg_25[SS_LOOKUP_SIZE] = { 0x0F, 0xFF}; // rfm22_clk_recovery_timing_loop_gain0
|
||||
const uint8_t ss_reg_20[] = { 0xE8, 0x38}; // rfm22_clk_recovery_oversampling_ratio
|
||||
const uint8_t ss_reg_21[] = { 0x60, 0x02}; // rfm22_clk_recovery_offset2
|
||||
const uint8_t ss_reg_22[] = { 0x20, 0x4D}; // rfm22_clk_recovery_offset1
|
||||
const uint8_t ss_reg_23[] = { 0xC5, 0xD3}; // rfm22_clk_recovery_offset0
|
||||
const uint8_t ss_reg_24[] = { 0x00, 0x07}; // rfm22_clk_recovery_timing_loop_gain1
|
||||
const uint8_t ss_reg_25[] = { 0x0F, 0xFF}; // rfm22_clk_recovery_timing_loop_gain0
|
||||
|
||||
const uint8_t ss_reg_2A[SS_LOOKUP_SIZE] = { 0xFF, 0xFF}; // rfm22_afc_limiter .. AFC_pull_in_range = ±AFCLimiter[7:0] x (hbsel+1) x 625 Hz
|
||||
const uint8_t ss_reg_2A[] = { 0xFF, 0xFF}; // rfm22_afc_limiter .. AFC_pull_in_range = ±AFCLimiter[7:0] x (hbsel+1) x 625 Hz
|
||||
|
||||
const uint8_t ss_reg_70[SS_LOOKUP_SIZE] = { 0x24, 0x2D}; // rfm22_modulation_mode_control1
|
||||
const uint8_t ss_reg_71[SS_LOOKUP_SIZE] = { 0x2B, 0x23}; // rfm22_modulation_mode_control2
|
||||
const uint8_t ss_reg_70[] = { 0x24, 0x2D}; // rfm22_modulation_mode_control1
|
||||
const uint8_t ss_reg_71[] = { 0x2B, 0x23}; // rfm22_modulation_mode_control2
|
||||
|
||||
// ************************************
|
||||
|
||||
@ -252,7 +293,6 @@ volatile bool initialized = false;
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
volatile bool exec_using_spi; // set this if you want to access the SPI bus outside of the interrupt
|
||||
volatile bool inside_ext_int; // this is set whenever we are inside the interrupt
|
||||
#endif
|
||||
|
||||
uint8_t device_type; // the RF chips device ID number
|
||||
@ -294,7 +334,9 @@ volatile uint8_t prev_int_status1; // " "
|
||||
volatile uint8_t prev_int_status2; // " "
|
||||
volatile uint8_t prev_ezmac_status; // " "
|
||||
|
||||
bool debug_outputted;
|
||||
const char *debug_msg = NULL;
|
||||
const char *error_msg = NULL;
|
||||
static uint32_t debug_val = 0;
|
||||
#endif
|
||||
|
||||
volatile uint8_t osc_load_cap; // xtal frequency calibration value
|
||||
@ -302,29 +344,36 @@ volatile uint8_t osc_load_cap; // xtal frequency calibration value
|
||||
volatile uint8_t rssi; // the current RSSI (register value)
|
||||
volatile int16_t rssi_dBm; // dBm value
|
||||
|
||||
uint8_t tx_power; // the transmit power to use for data transmissions
|
||||
volatile uint8_t tx_pwr; // the tx power register read back
|
||||
// the transmit power to use for data transmissions
|
||||
uint8_t tx_power;
|
||||
// the tx power register read back
|
||||
volatile uint8_t tx_pwr;
|
||||
|
||||
volatile uint8_t rx_buffer_current; // the current receive buffer in use (double buffer)
|
||||
volatile uint8_t rx_buffer[256] __attribute__ ((aligned(4))); // the receive buffer .. received packet data is saved here
|
||||
volatile uint16_t rx_buffer_wr; // the receive buffer write index
|
||||
// The transmit buffer. Holds data that is being transmitted.
|
||||
uint8_t tx_buffer[TX_BUFFER_SIZE] __attribute__ ((aligned(4)));
|
||||
// The transmit buffer. Hosts data that is wating to be transmitted.
|
||||
uint8_t tx_pre_buffer[TX_BUFFER_SIZE] __attribute__ ((aligned(4)));
|
||||
// The tx pre-buffer write index.
|
||||
uint16_t tx_pre_buffer_size;
|
||||
// the tx data read index
|
||||
volatile uint16_t tx_data_rd;
|
||||
// the tx data write index
|
||||
volatile uint16_t tx_data_wr;
|
||||
|
||||
volatile uint8_t rx_packet_buf[256] __attribute__ ((aligned(4))); // the received packet
|
||||
// the current receive buffer in use (double buffer)
|
||||
volatile uint8_t rx_buffer_current;
|
||||
// the receive buffer .. received packet data is saved here
|
||||
volatile uint8_t rx_buffer[256] __attribute__ ((aligned(4)));
|
||||
// the receive buffer write index
|
||||
volatile uint16_t rx_buffer_wr;
|
||||
|
||||
// the received packet
|
||||
volatile uint16_t rx_packet_wr; // the receive packet write index
|
||||
volatile int16_t rx_packet_start_rssi_dBm; //
|
||||
volatile int32_t rx_packet_start_afc_Hz; //
|
||||
volatile int16_t rx_packet_rssi_dBm; // the received packet signal strength
|
||||
volatile int32_t rx_packet_afc_Hz; // the receive packet frequency offset
|
||||
|
||||
volatile uint8_t *tx_data_addr; // the address of the data we send in the transmitted packets
|
||||
volatile uint16_t tx_data_rd; // the tx data read index
|
||||
volatile uint16_t tx_data_wr; // the tx data write index
|
||||
|
||||
//volatile uint8_t tx_fifo[FIFO_SIZE]; //
|
||||
|
||||
volatile uint8_t rx_fifo[FIFO_SIZE]; //
|
||||
volatile uint8_t rx_fifo_wr; //
|
||||
|
||||
int lookup_index;
|
||||
int ss_lookup_index;
|
||||
|
||||
@ -334,14 +383,11 @@ volatile uint16_t rfm22_int_timer; // used to detect if the RF module stops
|
||||
volatile uint16_t rfm22_int_time_outs; // counter
|
||||
volatile uint16_t prev_rfm22_int_time_outs; //
|
||||
|
||||
uint32_t clear_channel_count = (TX_PREAMBLE_NIBBLES + 4) * 2; // minimum clear channel time before allowing transmit
|
||||
|
||||
uint16_t timeout_ms = 20000; //
|
||||
uint16_t timeout_sync_ms = 3; //
|
||||
uint16_t timeout_data_ms = 20; //
|
||||
|
||||
t_rfm22_TxDataByteCallback tx_data_byte_callback_function = NULL;
|
||||
t_rfm22_RxDataCallback rx_data_callback_function = NULL;
|
||||
struct pios_rfm22b_dev * rfm22b_dev_g;
|
||||
|
||||
|
||||
static bool PIOS_RFM22B_validate(struct pios_rfm22b_dev * rfm22b_dev)
|
||||
@ -356,6 +402,7 @@ static struct pios_rfm22b_dev * PIOS_RFM22B_alloc(void)
|
||||
|
||||
rfm22b_dev = (struct pios_rfm22b_dev *)pvPortMalloc(sizeof(*rfm22b_dev));
|
||||
if (!rfm22b_dev) return(NULL);
|
||||
rfm22b_dev_g = rfm22b_dev;
|
||||
|
||||
rfm22b_dev->magic = PIOS_RFM22B_DEV_MAGIC;
|
||||
return(rfm22b_dev);
|
||||
@ -394,25 +441,14 @@ int32_t PIOS_RFM22B_Init(uint32_t *rfm22b_id, const struct pios_rfm22b_cfg *cfg)
|
||||
|
||||
// Bind the configuration to the device instance
|
||||
rfm22b_dev->cfg = cfg;
|
||||
|
||||
// Configure the packet handler.
|
||||
PacketHandlerConfig phcfg = {
|
||||
.txWinSize = cfg->txWinSize,
|
||||
.maxConnections = cfg->maxConnections,
|
||||
.id = cfg->id,
|
||||
.dev = (void*) rfm22b_dev,
|
||||
.output_stream = PIOS_RFM22B_send_packet,
|
||||
.set_baud = 0,
|
||||
.data_handler = PIOS_RFM22B_receive_data,
|
||||
.receiver_handler = 0,
|
||||
};
|
||||
rfm22b_dev->packet_handler = PHInitialize(&phcfg);
|
||||
rfm22b_dev->cur_tx_packet = 0;
|
||||
|
||||
*rfm22b_id = (uint32_t)rfm22b_dev;
|
||||
|
||||
tx_pre_buffer_size = 0;
|
||||
|
||||
// Initialize the radio device.
|
||||
PIOS_COM_SendString(PIOS_COM_DEBUG, "Init Radio\n\r");
|
||||
DEBUG_PRINTF(2, "Init Radio\n\r");
|
||||
int initval = rfm22_init_normal(cfg->minFrequencyHz, cfg->maxFrequencyHz, 50000);
|
||||
|
||||
if (initval < 0)
|
||||
@ -459,9 +495,6 @@ int32_t PIOS_RFM22B_Init(uint32_t *rfm22b_id, const struct pios_rfm22b_cfg *cfg)
|
||||
DEBUG_PRINTF(2, "RF frequency: %dHz\n\r", rfm22_getNominalCarrierFrequency());
|
||||
DEBUG_PRINTF(2, "RF TX power: %d\n\r", rfm22_getTxPower());
|
||||
|
||||
// Start the data handeling task.
|
||||
xTaskCreate(PIOS_RFM22B_Task, (signed char *)"RFM22BTask", STACK_SIZE_BYTES, (void*)rfm22b_dev, tskIDLE_PRIORITY + 2, &(rfm22b_dev->taskHandle));
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
@ -480,6 +513,31 @@ static void PIOS_RFM22B_TxStart(uint32_t rfm22b_id, uint16_t tx_bytes_avail)
|
||||
bool valid = PIOS_RFM22B_validate(rfm22b_dev);
|
||||
PIOS_Assert(valid);
|
||||
|
||||
// Get some data to send
|
||||
bool need_yield = false;
|
||||
if(tx_pre_buffer_size== 0)
|
||||
tx_pre_buffer_size = (rfm22b_dev->tx_out_cb)(rfm22b_dev->tx_out_context, tx_pre_buffer,
|
||||
TX_BUFFER_SIZE, NULL, &need_yield);
|
||||
|
||||
if(tx_pre_buffer_size > 0)
|
||||
{
|
||||
|
||||
// already have data to be sent
|
||||
if (tx_data_wr > 0)
|
||||
return;
|
||||
|
||||
// we are currently transmitting or scanning the spectrum
|
||||
if (rf_mode == TX_DATA_MODE || rf_mode == TX_STREAM_MODE || rf_mode == TX_CARRIER_MODE ||
|
||||
rf_mode == TX_PN_MODE || rf_mode == RX_SCAN_SPECTRUM)
|
||||
return;
|
||||
|
||||
// is the channel clear to transmit on?
|
||||
if (!rfm22_channelIsClear())
|
||||
return;
|
||||
|
||||
// Start the transmit
|
||||
rfm22_txStart();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -526,132 +584,14 @@ static void PIOS_RFM22B_RegisterTxCallback(uint32_t rfm22b_id, pios_com_callback
|
||||
rfm22b_dev->tx_out_cb = tx_out_cb;
|
||||
}
|
||||
|
||||
static uint8_t PIOS_RFM22B_send_packet(void *rfm22b, PHPacketHandle packet)
|
||||
void rfm22_setDebug(const char* msg)
|
||||
{
|
||||
//struct pios_rfm22b_dev * rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b;
|
||||
uint16_t len = PHPacketSizeECC(packet);
|
||||
DEBUG_PRINTF(2, "Sending: %d %d %x\n\r", len, packet->header.data_size, (int)(packet->data[0]));
|
||||
return rfm22_sendData(packet, len, 1);
|
||||
debug_msg = msg;
|
||||
}
|
||||
|
||||
static void PIOS_RFM22B_receive_data(void *rfm22b, uint8_t *data, uint8_t len)
|
||||
void rfm22_setError(const char* msg)
|
||||
{
|
||||
struct pios_rfm22b_dev * rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b;
|
||||
|
||||
DEBUG_PRINTF(2, "Data: %d %x\n\r", len, (int)(data[0]));
|
||||
// Pass the received data the the receive callback.
|
||||
bool need_yield = false;
|
||||
if (rfm22b_dev->rx_in_cb)
|
||||
(rfm22b_dev->rx_in_cb)(rfm22b_dev->rx_in_context, data, len, NULL, &need_yield);
|
||||
|
||||
#if defined(PIOS_INCLUDE_FREERTOS)
|
||||
if (need_yield)
|
||||
vPortYieldFromISR();
|
||||
#endif /* PIOS_INCLUDE_FREERTOS */
|
||||
}
|
||||
|
||||
static void PIOS_RFM22B_Task(void *parameters)
|
||||
{
|
||||
struct pios_rfm22b_dev * rfm22b_dev = (struct pios_rfm22b_dev *)parameters;
|
||||
bool valid = PIOS_RFM22B_validate(rfm22b_dev);
|
||||
PIOS_Assert(valid);
|
||||
|
||||
// Loop forever
|
||||
while (1)
|
||||
{
|
||||
|
||||
// Recieve data to transmit if it's available.
|
||||
|
||||
// Reserve a TX packet if necessary
|
||||
PHPacketHandle p = rfm22b_dev->cur_tx_packet;
|
||||
bool reserve = (p == NULL);
|
||||
if (reserve)
|
||||
{
|
||||
if((p = PHReserveTXPacket(rfm22b_dev->packet_handler)))
|
||||
p->header.data_size = 0;
|
||||
}
|
||||
|
||||
// Do we have a packet to receive into?
|
||||
if (p != NULL)
|
||||
{
|
||||
|
||||
// Try to get some data.
|
||||
bool need_yield = false;
|
||||
uint16_t bytes_to_send = (rfm22b_dev->tx_out_cb)(rfm22b_dev->tx_out_context, p->data + p->header.data_size, PH_MAX_DATA + RS_ECC_NPARITY - p->header.data_size, NULL, &need_yield);
|
||||
p->header.data_size += bytes_to_send;
|
||||
|
||||
// Did we just reserve this packet?
|
||||
if (reserve)
|
||||
{
|
||||
|
||||
if(bytes_to_send == 0)
|
||||
{
|
||||
|
||||
// If there's no data available, just unlock our reserve on the packet.
|
||||
PHReleaseLock(p, 0);
|
||||
p = NULL;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Keep the packet and release the lock.
|
||||
PHReleaseLock(p, 1);
|
||||
|
||||
// Set the time so that we will send this data at least by the send timout.
|
||||
rfm22b_dev->countdownTimer = rfm22b_dev->cfg->sendTimeout;
|
||||
|
||||
// Initialize the packet.
|
||||
p->header.type = PACKET_TYPE_ACKED_DATA;
|
||||
rfm22b_dev->cur_tx_packet = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do we have data to send?
|
||||
if (p != NULL)
|
||||
{
|
||||
|
||||
// Send the packet if the data size is over the minimum threshold
|
||||
// or if this packet is older than the send timeout.
|
||||
if((p->header.data_size >= rfm22b_dev->cfg->minPacketSize) || (rfm22b_dev->countdownTimer == 0))
|
||||
{
|
||||
|
||||
// Transmit the packet
|
||||
PHTransmitPacket(rfm22b_dev->packet_handler, p);
|
||||
|
||||
// Clear our link to the old packet.
|
||||
rfm22b_dev->cur_tx_packet = NULL;
|
||||
|
||||
}
|
||||
else
|
||||
|
||||
// Decrement the packet timer if we didn't send the packet.
|
||||
rfm22b_dev->countdownTimer--;
|
||||
}
|
||||
|
||||
rfm22_process();
|
||||
|
||||
// See if a packet was received.
|
||||
uint16_t packet_size = rfm22_receivedLength();
|
||||
if (packet_size != 0)
|
||||
{
|
||||
// copy the received packet into our own buffer
|
||||
|
||||
// Get the receive packet buffer.
|
||||
PHPacketHandle p = PHGetRXPacket(rfm22b_dev->packet_handler);
|
||||
memmove(p, rfm22_receivedPointer(), packet_size);
|
||||
DEBUG_PRINTF(2, "Received: %d %d\n\r", packet_size, p->header.data_size);
|
||||
|
||||
// Process the received packet with the packet handler.
|
||||
PHReceivePacket(rfm22b_dev->packet_handler, p);
|
||||
|
||||
// the received packet has been saved
|
||||
rfm22_receivedDone();
|
||||
}
|
||||
|
||||
vTaskDelay(1);
|
||||
}
|
||||
error_msg = msg;
|
||||
}
|
||||
|
||||
// ************************************
|
||||
@ -668,11 +608,6 @@ void rfm22_startBurstWrite(uint8_t addr)
|
||||
PIOS_SPI_TransferByte(RFM22_PIOS_SPI, 0x80 | addr);
|
||||
}
|
||||
|
||||
inline void rfm22_burstWrite(uint8_t data)
|
||||
{
|
||||
PIOS_SPI_TransferByte(RFM22_PIOS_SPI, data);
|
||||
}
|
||||
|
||||
void rfm22_endBurstWrite(void)
|
||||
{
|
||||
// chip select line HIGH
|
||||
@ -705,11 +640,6 @@ void rfm22_startBurstRead(uint8_t addr)
|
||||
PIOS_SPI_TransferByte(RFM22_PIOS_SPI, addr & 0x7f);
|
||||
}
|
||||
|
||||
inline uint8_t rfm22_burstRead(void)
|
||||
{
|
||||
return PIOS_SPI_TransferByte(RFM22_PIOS_SPI, 0xff);
|
||||
}
|
||||
|
||||
void rfm22_endBurstRead(void)
|
||||
{
|
||||
// chip select line HIGH
|
||||
@ -738,69 +668,40 @@ uint8_t rfm22_read(uint8_t addr)
|
||||
// ************************************
|
||||
// external interrupt
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
|
||||
void RFM22_EXT_INT_FUNC(void)
|
||||
void PIOS_RFM22_EXT_Int(void)
|
||||
{
|
||||
inside_ext_int = TRUE;
|
||||
|
||||
if (EXTI_GetITStatus(RFM22_EXT_INT_LINE) != RESET)
|
||||
{
|
||||
// Clear the EXTI line pending bit
|
||||
EXTI_ClearITPendingBit(RFM22_EXT_INT_LINE);
|
||||
|
||||
// USB_LED_TOGGLE; // TEST ONLY
|
||||
|
||||
if (!exec_using_spi)
|
||||
{
|
||||
// while (!GPIO_IN(RF_INT_PIN) && !exec_using_spi)
|
||||
{
|
||||
// stay here until the interrupt line returns HIGH
|
||||
rfm22_processInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inside_ext_int = FALSE;
|
||||
rfm22_setDebug("Ext Int");
|
||||
if (!exec_using_spi)
|
||||
rfm22_processInt();
|
||||
rfm22_setDebug("Ext Done");
|
||||
}
|
||||
|
||||
void rfm22_disableExtInt(void)
|
||||
{
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
rfm22_setDebug("Disable Int");
|
||||
// Configure the external interrupt
|
||||
GPIO_EXTILineConfig(RFM22_EXT_INT_PORT_SOURCE, RFM22_EXT_INT_PIN_SOURCE);
|
||||
EXTI_InitTypeDef EXTI_InitStructure;
|
||||
EXTI_InitStructure.EXTI_Line = RFM22_EXT_INT_LINE;
|
||||
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
|
||||
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
|
||||
GPIO_EXTILineConfig(PIOS_RFM22_EXTI_PORT_SOURCE, PIOS_RFM22_EXTI_PIN_SOURCE);
|
||||
EXTI_InitTypeDef EXTI_InitStructure = pios_exti_rfm22b_cfg.exti.init;
|
||||
EXTI_InitStructure.EXTI_LineCmd = DISABLE;
|
||||
EXTI_Init(&EXTI_InitStructure);
|
||||
|
||||
EXTI_ClearFlag(RFM22_EXT_INT_LINE);
|
||||
EXTI_ClearFlag(PIOS_RFM22_EXTI_LINE);
|
||||
rfm22_setDebug("Disable Int done");
|
||||
#endif
|
||||
}
|
||||
|
||||
void rfm22_enableExtInt(void)
|
||||
{
|
||||
// Configure the external interrupt
|
||||
GPIO_EXTILineConfig(RFM22_EXT_INT_PORT_SOURCE, RFM22_EXT_INT_PIN_SOURCE);
|
||||
EXTI_InitTypeDef EXTI_InitStructure;
|
||||
EXTI_InitStructure.EXTI_Line = RFM22_EXT_INT_LINE;
|
||||
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
|
||||
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
|
||||
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
|
||||
EXTI_Init(&EXTI_InitStructure);
|
||||
|
||||
EXTI_ClearFlag(RFM22_EXT_INT_LINE);
|
||||
|
||||
// Enable and set the external interrupt
|
||||
NVIC_InitTypeDef NVIC_InitStructure;
|
||||
NVIC_InitStructure.NVIC_IRQChannel = RFM22_EXT_INT_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = RFM22_EXT_INT_PRIORITY;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
rfm22_setDebug("Ensable Int");
|
||||
if (PIOS_EXTI_Init(&pios_exti_rfm22b_cfg))
|
||||
PIOS_Assert(0);
|
||||
rfm22_setDebug("Ensable Int done");
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************
|
||||
// set/get the current tx power setting
|
||||
@ -840,9 +741,7 @@ uint32_t rfm22_maxFrequency(void)
|
||||
void rfm22_setNominalCarrierFrequency(uint32_t frequency_hz)
|
||||
{
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = TRUE;
|
||||
#endif
|
||||
|
||||
// *******
|
||||
|
||||
@ -887,9 +786,7 @@ void rfm22_setNominalCarrierFrequency(uint32_t frequency_hz)
|
||||
// DEBUG_PRINTF(2, "rf setFreq frequency_step_size: %0.2f\n\r", frequency_step_size);
|
||||
#endif
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t rfm22_getNominalCarrierFrequency(void)
|
||||
@ -934,10 +831,7 @@ uint32_t rfm22_freqHopSize(void)
|
||||
void rfm22_setDatarate(uint32_t datarate_bps, bool data_whitening)
|
||||
{
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = TRUE;
|
||||
#endif
|
||||
// *******
|
||||
|
||||
lookup_index = 0;
|
||||
while (lookup_index < (LOOKUP_SIZE - 1) && data_rate[lookup_index] < datarate_bps)
|
||||
@ -1049,9 +943,7 @@ void rfm22_setDatarate(uint32_t datarate_bps, bool data_whitening)
|
||||
|
||||
// *******
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t rfm22_getDatarate(void)
|
||||
@ -1064,10 +956,7 @@ uint32_t rfm22_getDatarate(void)
|
||||
void rfm22_setSSBandwidth(uint32_t bandwidth_index)
|
||||
{
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = TRUE;
|
||||
#endif
|
||||
// *******
|
||||
|
||||
ss_lookup_index = bandwidth_index;
|
||||
|
||||
@ -1103,57 +992,41 @@ void rfm22_setSSBandwidth(uint32_t bandwidth_index)
|
||||
|
||||
// *******
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ************************************
|
||||
|
||||
void rfm22_setRxMode(uint8_t mode, bool multi_packet_mode)
|
||||
{
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = TRUE;
|
||||
#endif
|
||||
|
||||
// disable interrupts
|
||||
rfm22_write(RFM22_interrupt_enable1, 0x00);
|
||||
rfm22_write(RFM22_interrupt_enable2, 0x00);
|
||||
|
||||
// disable the receiver and transmitter
|
||||
// rfm22_write(RFM22_op_and_func_ctrl1, RFM22_opfc1_xton); // READY mode
|
||||
rfm22_write(RFM22_op_and_func_ctrl1, RFM22_opfc1_pllon); // TUNE mode
|
||||
// Switch to TUNE mode
|
||||
rfm22_write(RFM22_op_and_func_ctrl1, RFM22_opfc1_pllon);
|
||||
|
||||
RX_LED_OFF;
|
||||
TX_LED_OFF;
|
||||
|
||||
// rfm22_write(RFM22_rx_fifo_control, RX_FIFO_HI_WATERMARK); // RX FIFO Almost Full Threshold (0 - 63)
|
||||
|
||||
if (rf_mode == TX_CARRIER_MODE || rf_mode == TX_PN_MODE)
|
||||
{
|
||||
// FIFO mode, GFSK modulation
|
||||
uint8_t fd_bit = rfm22_read(RFM22_modulation_mode_control2) & RFM22_mmc2_fd;
|
||||
rfm22_write(RFM22_modulation_mode_control2, fd_bit | RFM22_mmc2_dtmod_fifo | RFM22_mmc2_modtyp_gfsk);
|
||||
rfm22_write(RFM22_modulation_mode_control2, fd_bit | RFM22_mmc2_dtmod_fifo |
|
||||
RFM22_mmc2_modtyp_gfsk);
|
||||
}
|
||||
|
||||
rx_buffer_wr = 0; // empty the rx buffer
|
||||
|
||||
rfm22_int_timer = 0; // reset the timer
|
||||
|
||||
// empty the rx buffer
|
||||
rx_buffer_wr = 0;
|
||||
// reset the timer
|
||||
rfm22_int_timer = 0;
|
||||
rf_mode = mode;
|
||||
|
||||
if (mode != RX_SCAN_SPECTRUM)
|
||||
{
|
||||
//STOPWATCH_reset(); // reset clear channel detect timer
|
||||
|
||||
// enable RX interrupts
|
||||
rfm22_write(RFM22_interrupt_enable1, RFM22_ie1_encrcerror | RFM22_ie1_enpkvalid | RFM22_ie1_enrxffafull | RFM22_ie1_enfferr);
|
||||
rfm22_write(RFM22_interrupt_enable2, RFM22_ie2_enpreainval | RFM22_ie2_enpreaval | RFM22_ie2_enswdet);
|
||||
}
|
||||
|
||||
// read interrupt status - clear interrupts
|
||||
rfm22_read(RFM22_interrupt_status1);
|
||||
rfm22_read(RFM22_interrupt_status2);
|
||||
// Clear the TX buffer.
|
||||
tx_data_rd = tx_data_wr = 0;
|
||||
|
||||
// clear FIFOs
|
||||
if (!multi_packet_mode)
|
||||
@ -1161,21 +1034,22 @@ void rfm22_setRxMode(uint8_t mode, bool multi_packet_mode)
|
||||
rfm22_write(RFM22_op_and_func_ctrl2, RFM22_opfc2_ffclrrx | RFM22_opfc2_ffclrtx);
|
||||
rfm22_write(RFM22_op_and_func_ctrl2, 0x00);
|
||||
} else {
|
||||
rfm22_write(RFM22_op_and_func_ctrl2, RFM22_opfc2_rxmpk | RFM22_opfc2_ffclrrx | RFM22_opfc2_ffclrtx);
|
||||
rfm22_write(RFM22_op_and_func_ctrl2, RFM22_opfc2_rxmpk | RFM22_opfc2_ffclrrx |
|
||||
RFM22_opfc2_ffclrtx);
|
||||
rfm22_write(RFM22_op_and_func_ctrl2, RFM22_opfc2_rxmpk);
|
||||
}
|
||||
|
||||
// enable RX interrupts
|
||||
rfm22_write(RFM22_interrupt_enable1, RFM22_ie1_encrcerror | RFM22_ie1_enpkvalid |
|
||||
RFM22_ie1_enrxffafull | RFM22_ie1_enfferr);
|
||||
rfm22_write(RFM22_interrupt_enable2, RFM22_ie2_enpreainval | RFM22_ie2_enpreaval |
|
||||
RFM22_ie2_enswdet);
|
||||
|
||||
// enable the receiver
|
||||
// rfm22_write(RFM22_op_and_func_ctrl1, RFM22_opfc1_xton | RFM22_opfc1_rxon);
|
||||
rfm22_write(RFM22_op_and_func_ctrl1, RFM22_opfc1_pllon | RFM22_opfc1_rxon);
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = FALSE;
|
||||
#endif
|
||||
|
||||
#if defined(RFM22_DEBUG)
|
||||
DEBUG_PRINTF(2, " RX Mode\n\r");
|
||||
#endif
|
||||
}
|
||||
|
||||
// ************************************
|
||||
@ -1197,14 +1071,96 @@ uint16_t rfm22_addHeader()
|
||||
|
||||
// ************************************
|
||||
|
||||
uint8_t rfm22_txStart()
|
||||
{
|
||||
if((tx_pre_buffer_size == 0) || (exec_using_spi == TRUE))
|
||||
{
|
||||
// Clear the TX buffer.
|
||||
tx_data_rd = tx_data_wr = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
exec_using_spi = TRUE;
|
||||
|
||||
// Disable interrrupts.
|
||||
PIOS_IRQ_Disable();
|
||||
|
||||
// disable interrupts
|
||||
rfm22_write(RFM22_interrupt_enable1, 0x00);
|
||||
rfm22_write(RFM22_interrupt_enable2, 0x00);
|
||||
|
||||
// TUNE mode
|
||||
rfm22_write(RFM22_op_and_func_ctrl1, RFM22_opfc1_pllon);
|
||||
|
||||
// Queue the data up for sending
|
||||
memcpy(tx_buffer, tx_pre_buffer, tx_pre_buffer_size);
|
||||
tx_data_rd = 0;
|
||||
tx_data_wr = tx_pre_buffer_size;
|
||||
tx_pre_buffer_size = 0;
|
||||
|
||||
RX_LED_OFF;
|
||||
|
||||
// FIFO mode, GFSK modulation
|
||||
uint8_t fd_bit = rfm22_read(RFM22_modulation_mode_control2) & RFM22_mmc2_fd;
|
||||
rfm22_write(RFM22_modulation_mode_control2, fd_bit | RFM22_mmc2_dtmod_fifo |
|
||||
RFM22_mmc2_modtyp_gfsk);
|
||||
|
||||
// set the tx power
|
||||
rfm22_write(RFM22_tx_power, RFM22_tx_pwr_papeaken | RFM22_tx_pwr_papeaklvl_1 |
|
||||
RFM22_tx_pwr_papeaklvl_0 | RFM22_tx_pwr_lna_sw | tx_power);
|
||||
|
||||
// clear FIFOs
|
||||
rfm22_write(RFM22_op_and_func_ctrl2, RFM22_opfc2_ffclrrx | RFM22_opfc2_ffclrtx);
|
||||
rfm22_write(RFM22_op_and_func_ctrl2, 0x00);
|
||||
|
||||
// *******************
|
||||
// add some data to the chips TX FIFO before enabling the transmitter
|
||||
|
||||
// set the total number of data bytes we are going to transmit
|
||||
rfm22_write(RFM22_transmit_packet_length, tx_data_wr);
|
||||
|
||||
// add some data
|
||||
rfm22_startBurstWrite(RFM22_fifo_access);
|
||||
for (uint16_t i = 0; (tx_data_rd < tx_data_wr) && (i < FIFO_SIZE); ++tx_data_rd, ++i)
|
||||
rfm22_burstWrite(tx_buffer[tx_data_rd]);
|
||||
rfm22_endBurstWrite();
|
||||
|
||||
// *******************
|
||||
|
||||
// reset the timer
|
||||
rfm22_int_timer = 0;
|
||||
|
||||
rf_mode = TX_DATA_MODE;
|
||||
|
||||
// enable TX interrupts
|
||||
// rfm22_write(RFM22_interrupt_enable1, RFM22_ie1_enpksent | RFM22_ie1_entxffaem | RFM22_ie1_enfferr);
|
||||
rfm22_write(RFM22_interrupt_enable1, RFM22_ie1_enpksent | RFM22_ie1_entxffaem);
|
||||
|
||||
// read interrupt status - clear interrupts
|
||||
//rfm22_read(RFM22_interrupt_status1);
|
||||
//rfm22_read(RFM22_interrupt_status2);
|
||||
|
||||
// enable the transmitter
|
||||
// rfm22_write(RFM22_op_and_func_ctrl1, RFM22_opfc1_xton | RFM22_opfc1_txon);
|
||||
rfm22_write(RFM22_op_and_func_ctrl1, RFM22_opfc1_pllon | RFM22_opfc1_txon);
|
||||
|
||||
// Re-ensable interrrupts.
|
||||
PIOS_IRQ_Enable();
|
||||
|
||||
TX_LED_ON;
|
||||
|
||||
exec_using_spi = FALSE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void rfm22_setTxMode(uint8_t mode)
|
||||
{
|
||||
rfm22_setDebug("setTxMode");
|
||||
if (mode != TX_DATA_MODE && mode != TX_STREAM_MODE && mode != TX_CARRIER_MODE && mode != TX_PN_MODE)
|
||||
return; // invalid mode
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = TRUE;
|
||||
#endif
|
||||
|
||||
// *******************
|
||||
|
||||
@ -1218,20 +1174,23 @@ void rfm22_setTxMode(uint8_t mode)
|
||||
RX_LED_OFF;
|
||||
|
||||
// set the tx power
|
||||
// rfm22_write(RFM22_tx_power, RFM22_tx_pwr_lna_sw | tx_power);
|
||||
// rfm22_write(RFM22_tx_power, RFM22_tx_pwr_papeaken | RFM22_tx_pwr_papeaklvl_0 | RFM22_tx_pwr_lna_sw | tx_power);
|
||||
rfm22_write(RFM22_tx_power, RFM22_tx_pwr_papeaken | RFM22_tx_pwr_papeaklvl_1 | RFM22_tx_pwr_papeaklvl_0 | RFM22_tx_pwr_lna_sw | tx_power);
|
||||
rfm22_write(RFM22_tx_power, RFM22_tx_pwr_papeaken | RFM22_tx_pwr_papeaklvl_1 |
|
||||
RFM22_tx_pwr_papeaklvl_0 | RFM22_tx_pwr_lna_sw | tx_power);
|
||||
|
||||
uint8_t fd_bit = rfm22_read(RFM22_modulation_mode_control2) & RFM22_mmc2_fd;
|
||||
if (mode == TX_CARRIER_MODE)
|
||||
// blank carrier mode - for testing
|
||||
rfm22_write(RFM22_modulation_mode_control2, fd_bit | RFM22_mmc2_dtmod_pn9 | RFM22_mmc2_modtyp_none); // FIFO mode, Blank carrier
|
||||
rfm22_write(RFM22_modulation_mode_control2, fd_bit | RFM22_mmc2_dtmod_pn9 |
|
||||
RFM22_mmc2_modtyp_none); // FIFO mode, Blank carrier
|
||||
else if (mode == TX_PN_MODE)
|
||||
// psuedo random data carrier mode - for testing
|
||||
rfm22_write(RFM22_modulation_mode_control2, fd_bit | RFM22_mmc2_dtmod_pn9 | RFM22_mmc2_modtyp_gfsk); // FIFO mode, PN9 carrier
|
||||
rfm22_write(RFM22_modulation_mode_control2, fd_bit | RFM22_mmc2_dtmod_pn9 |
|
||||
RFM22_mmc2_modtyp_gfsk); // FIFO mode, PN9 carrier
|
||||
else
|
||||
// data transmission
|
||||
rfm22_write(RFM22_modulation_mode_control2, fd_bit | RFM22_mmc2_dtmod_fifo | RFM22_mmc2_modtyp_gfsk); // FIFO mode, GFSK modulation
|
||||
// FIFO mode, GFSK modulation
|
||||
rfm22_write(RFM22_modulation_mode_control2, fd_bit | RFM22_mmc2_dtmod_fifo |
|
||||
RFM22_mmc2_modtyp_gfsk);
|
||||
|
||||
// rfm22_write(0x72, reg_72[lookup_index]); // rfm22_frequency_deviation
|
||||
|
||||
@ -1244,17 +1203,14 @@ void rfm22_setTxMode(uint8_t mode)
|
||||
{
|
||||
uint16_t rd = 0;
|
||||
uint16_t wr = tx_data_wr;
|
||||
if (!tx_data_addr) wr = 0;
|
||||
|
||||
if (mode == TX_DATA_MODE)
|
||||
rfm22_write(RFM22_transmit_packet_length, wr); // set the total number of data bytes we are going to transmit
|
||||
// set the total number of data bytes we are going to transmit
|
||||
rfm22_write(RFM22_transmit_packet_length, wr);
|
||||
|
||||
uint16_t max_bytes = FIFO_SIZE - 1;
|
||||
|
||||
uint16_t i = 0;
|
||||
|
||||
rfm22_startBurstWrite(RFM22_fifo_access);
|
||||
|
||||
if (mode == TX_STREAM_MODE) {
|
||||
if (rd >= wr) {
|
||||
// no data to send - yet .. just send preamble pattern
|
||||
@ -1268,7 +1224,7 @@ void rfm22_setTxMode(uint8_t mode)
|
||||
|
||||
// add some data
|
||||
for (uint16_t j = wr - rd; j > 0; j--) {
|
||||
rfm22_burstWrite(tx_data_addr[rd++]);
|
||||
rfm22_burstWrite(tx_buffer[rd++]);
|
||||
if (++i >= max_bytes)
|
||||
break;
|
||||
}
|
||||
@ -1280,7 +1236,8 @@ void rfm22_setTxMode(uint8_t mode)
|
||||
|
||||
// *******************
|
||||
|
||||
rfm22_int_timer = 0; // reset the timer
|
||||
// reset the timer
|
||||
rfm22_int_timer = 0;
|
||||
|
||||
rf_mode = mode;
|
||||
|
||||
@ -1299,34 +1256,10 @@ void rfm22_setTxMode(uint8_t mode)
|
||||
TX_LED_ON;
|
||||
|
||||
// *******************
|
||||
// create new slightly random clear channel detector count value
|
||||
|
||||
uint32_t ccc = (TX_PREAMBLE_NIBBLES + 8) + 4; // minimum clear channel time before allowing transmit
|
||||
clear_channel_count = ccc + (random32 % (ccc * 2)); // plus a some randomness
|
||||
|
||||
// *******************
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = FALSE;
|
||||
#endif
|
||||
|
||||
#if defined(RFM22_DEBUG)
|
||||
switch (rf_mode)
|
||||
{
|
||||
case TX_DATA_MODE:
|
||||
DEBUG_PRINTF(2, " TX_Data_Mode\n\r");
|
||||
break;
|
||||
case TX_STREAM_MODE:
|
||||
DEBUG_PRINTF(2, " TX_Stream_Mode\n\r");
|
||||
break;
|
||||
case TX_CARRIER_MODE:
|
||||
DEBUG_PRINTF(2, " TX_Carrier_Mode\n\r");
|
||||
break;
|
||||
case TX_PN_MODE:
|
||||
DEBUG_PRINTF(2, " TX_PN_Mode\n\r");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
rfm22_setDebug("setTxMode end");
|
||||
}
|
||||
|
||||
// ************************************
|
||||
@ -1336,129 +1269,119 @@ void rfm22_processRxInt(void)
|
||||
{
|
||||
register uint8_t int_stat1 = int_status1;
|
||||
register uint8_t int_stat2 = int_status2;
|
||||
rfm22_setDebug("processRxInt");
|
||||
|
||||
// FIFO under/over flow error. Restart RX mode.
|
||||
if (device_status & (RFM22_ds_ffunfl | RFM22_ds_ffovfl))
|
||||
{
|
||||
rfm22_setError("R_UNDER/OVERRUN");
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Sync timeout. Restart RX mode.
|
||||
if (rf_mode == RX_WAIT_SYNC_MODE && rfm22_int_timer >= timeout_sync_ms)
|
||||
{
|
||||
rfm22_int_time_outs++;
|
||||
rfm22_setError("R_SYNC_TIMEOUT");
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// RX timeout. Restart RX mode.
|
||||
if (rf_mode == RX_DATA_MODE && rfm22_int_timer >= timeout_data_ms)
|
||||
{
|
||||
rfm22_setError("MISSING_INTERRUPTS");
|
||||
rfm22_int_time_outs++;
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// The module is not in RX mode. Restart RX mode.
|
||||
if ((device_status & RFM22_ds_cps_mask) != RFM22_ds_cps_rx)
|
||||
{
|
||||
// the rf module is not in rx mode
|
||||
if (rfm22_int_timer >= 100)
|
||||
{
|
||||
rfm22_int_time_outs++;
|
||||
// reset the receiver
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Valid preamble detected
|
||||
if (int_stat2 & RFM22_is2_ipreaval)
|
||||
{ // Valid preamble detected
|
||||
|
||||
{
|
||||
if (rf_mode == RX_WAIT_PREAMBLE_MODE)
|
||||
{
|
||||
rfm22_int_timer = 0; // reset the timer
|
||||
rf_mode = RX_WAIT_SYNC_MODE;
|
||||
RX_LED_ON;
|
||||
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, " pream_det");
|
||||
debug_outputted = true;
|
||||
#endif
|
||||
rfm22_setDebug("pream_det");
|
||||
}
|
||||
}
|
||||
/* else
|
||||
if (int_stat2 & RFM22_is2_ipreainval)
|
||||
{ // Invalid preamble detected
|
||||
|
||||
if (rf_mode == RX_WAIT_SYNC_MODE)
|
||||
{
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, " invalid_preamble");
|
||||
debug_outputted = true;
|
||||
#endif
|
||||
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
*/
|
||||
// Sync word detected
|
||||
if (int_stat2 & RFM22_is2_iswdet)
|
||||
{ // Sync word detected
|
||||
|
||||
//STOPWATCH_reset(); // reset timer
|
||||
|
||||
{
|
||||
if (rf_mode == RX_WAIT_PREAMBLE_MODE || rf_mode == RX_WAIT_SYNC_MODE)
|
||||
{
|
||||
rfm22_int_timer = 0; // reset the timer
|
||||
rf_mode = RX_DATA_MODE;
|
||||
RX_LED_ON;
|
||||
rfm22_setDebug("sync_det");
|
||||
|
||||
#ifdef NEVER
|
||||
// read the 10-bit signed afc correction value
|
||||
afc_correction = (uint16_t)rfm22_read(RFM22_afc_correction_read) << 8; // bits 9 to 2
|
||||
afc_correction |= (uint16_t)rfm22_read(RFM22_ook_counter_value1) & 0x00c0; // bits 1 & 0
|
||||
// bits 9 to 2
|
||||
afc_correction = (uint16_t)rfm22_read(RFM22_afc_correction_read) << 8;
|
||||
// bits 1 & 0
|
||||
afc_correction |= (uint16_t)rfm22_read(RFM22_ook_counter_value1) & 0x00c0;
|
||||
afc_correction >>= 6;
|
||||
afc_correction_Hz = (int32_t)(frequency_step_size * afc_correction + 0.5f); // convert the afc value to Hz
|
||||
// convert the afc value to Hz
|
||||
afc_correction_Hz = (int32_t)(frequency_step_size * afc_correction + 0.5f);
|
||||
|
||||
rx_packet_start_rssi_dBm = rssi_dBm; // remember the rssi for this packet
|
||||
rx_packet_start_afc_Hz = afc_correction_Hz; // remember the afc value for this packet
|
||||
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, " sync_det");
|
||||
DEBUG_PRINTF(2, " AFC_%d_%dHz", afc_correction, afc_correction_Hz);
|
||||
debug_outputted = true;
|
||||
// remember the rssi for this packet
|
||||
rx_packet_start_rssi_dBm = rssi_dBm;
|
||||
// remember the afc value for this packet
|
||||
rx_packet_start_afc_Hz = afc_correction_Hz;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// RX FIFO almost full, it needs emptying
|
||||
if (int_stat1 & RFM22_is1_irxffafull)
|
||||
{ // RX FIFO almost full, it needs emptying
|
||||
|
||||
{
|
||||
if (rf_mode == RX_DATA_MODE)
|
||||
{ // read data from the rf chips FIFO buffer
|
||||
{
|
||||
// read data from the rf chips FIFO buffer
|
||||
rfm22_int_timer = 0; // reset the timer
|
||||
|
||||
register uint16_t len = rfm22_read(RFM22_received_packet_length); // read the total length of the packet data
|
||||
|
||||
register uint16_t wr = rx_buffer_wr;
|
||||
|
||||
if ((wr + RX_FIFO_HI_WATERMARK) > len)
|
||||
{ // some kind of error in the RF module
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, " r_size_error1");
|
||||
debug_outputted = true;
|
||||
#endif
|
||||
// read the total length of the packet data
|
||||
uint16_t len = rfm22_read(RFM22_received_packet_length);
|
||||
|
||||
// The received packet is going to be larger than the specified length
|
||||
if ((rx_buffer_wr + RX_FIFO_HI_WATERMARK) > len)
|
||||
{
|
||||
rfm22_setError("r_size_error1");
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (((wr + RX_FIFO_HI_WATERMARK) >= len) && !(int_stat1 & RFM22_is1_ipkvalid))
|
||||
{ // some kind of error in the RF module
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, " r_size_error2");
|
||||
debug_outputted = true;
|
||||
#endif
|
||||
|
||||
// Another packet length error.
|
||||
if (((rx_buffer_wr + RX_FIFO_HI_WATERMARK) >= len) && !(int_stat1 & RFM22_is1_ipkvalid))
|
||||
{
|
||||
rfm22_setError("r_size_error2");
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// fetch the rx'ed data from the rf chips RX FIFO
|
||||
// Fetch the data from the RX FIFO
|
||||
rfm22_startBurstRead(RFM22_fifo_access);
|
||||
rx_fifo_wr = 0;
|
||||
for (register uint8_t i = RX_FIFO_HI_WATERMARK; i > 0; i--)
|
||||
rx_fifo[rx_fifo_wr++] = rfm22_burstRead(); // read a byte from the rf modules RX FIFO buffer
|
||||
for (uint8_t i = 0; i < RX_FIFO_HI_WATERMARK; ++i)
|
||||
rx_buffer[rx_buffer_wr++] = rfm22_burstRead();
|
||||
rfm22_endBurstRead();
|
||||
|
||||
uint16_t i = rx_fifo_wr;
|
||||
if (wr + i > sizeof(rx_buffer)) i = sizeof(rx_buffer) - wr;
|
||||
memcpy((void *)(rx_buffer + wr), (void *)rx_fifo, i); // save the new bytes into our rx buffer
|
||||
wr += i;
|
||||
|
||||
rx_buffer_wr = wr;
|
||||
|
||||
if (rx_data_callback_function)
|
||||
{ // pass the new data onto whoever wanted it
|
||||
if (!rx_data_callback_function((void *)rx_fifo, rx_fifo_wr))
|
||||
{
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
// DEBUG_PRINTF(2, " r_data_%u/%u", rx_buffer_wr, len);
|
||||
// debug_outputted = true;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{ // just clear the RX FIFO
|
||||
@ -1469,21 +1392,13 @@ void rfm22_processRxInt(void)
|
||||
}
|
||||
}
|
||||
|
||||
// CRC error .. discard the received data
|
||||
if (int_stat1 & RFM22_is1_icrerror)
|
||||
{ // CRC error .. discard the received data
|
||||
|
||||
if (rf_mode == RX_DATA_MODE)
|
||||
{
|
||||
rfm22_int_timer = 0; // reset the timer
|
||||
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, " CRC_ERR");
|
||||
debug_outputted = true;
|
||||
#endif
|
||||
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false); // reset the receiver
|
||||
return;
|
||||
}
|
||||
{
|
||||
rfm22_int_timer = 0; // reset the timer
|
||||
rfm22_setError("CRC_ERR");
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// if (int_stat2 & RFM22_is2_irssi)
|
||||
@ -1498,235 +1413,159 @@ void rfm22_processRxInt(void)
|
||||
// { // Header check error
|
||||
// }
|
||||
|
||||
// Valid packet received
|
||||
if (int_stat1 & RFM22_is1_ipkvalid)
|
||||
{ // Valid packet received
|
||||
|
||||
if (rf_mode == RX_DATA_MODE)
|
||||
{
|
||||
rfm22_int_timer = 0; // reset the timer
|
||||
|
||||
// disable the receiver
|
||||
// rfm22_write(RFM22_op_and_func_ctrl1, RFM22_opfc1_xton); // READY mode
|
||||
rfm22_write(RFM22_op_and_func_ctrl1, RFM22_opfc1_pllon); // TUNE mode
|
||||
|
||||
register uint16_t len = rfm22_read(RFM22_received_packet_length); // read the total length of the packet data
|
||||
|
||||
register uint16_t wr = rx_buffer_wr;
|
||||
|
||||
if (wr < len)
|
||||
{ // their must still be data in the RX FIFO we need to get
|
||||
|
||||
// fetch the rx'ed data from the rf chips RX FIFO
|
||||
rfm22_startBurstRead(RFM22_fifo_access);
|
||||
rx_fifo_wr = 0;
|
||||
for (register uint8_t i = len - wr; i > 0; i--)
|
||||
rx_fifo[rx_fifo_wr++] = rfm22_burstRead(); // read a byte from the rf modules RX FIFO buffer
|
||||
rfm22_endBurstRead();
|
||||
|
||||
uint16_t i = rx_fifo_wr;
|
||||
if (wr + i > sizeof(rx_buffer)) i = sizeof(rx_buffer) - wr;
|
||||
memcpy((void *)(rx_buffer + wr), (void *)rx_fifo, i); // save the new bytes into our rx buffer
|
||||
wr += i;
|
||||
|
||||
rx_buffer_wr = wr;
|
||||
|
||||
if (rx_data_callback_function)
|
||||
{ // pass the new data onto whoever wanted it
|
||||
if (!rx_data_callback_function((void *)rx_fifo, rx_fifo_wr))
|
||||
{
|
||||
// rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
// return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false); // reset the receiver
|
||||
|
||||
if (wr != len)
|
||||
{ // we have a packet length error .. discard the packet
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, " r_pack_len_error_%u_%u", len, wr);
|
||||
debug_outputted = true;
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// we have a valid received packet
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, " VALID_R_PACKET_%u", wr);
|
||||
debug_outputted = true;
|
||||
#endif
|
||||
|
||||
if (rx_packet_wr == 0)
|
||||
{ // save the received packet for further processing
|
||||
rx_packet_rssi_dBm = rx_packet_start_rssi_dBm; // remember the rssi for this packet
|
||||
rx_packet_afc_Hz = rx_packet_start_afc_Hz; // remember the afc offset for this packet
|
||||
memmove((void *)rx_packet_buf, (void *)rx_buffer, wr); // copy the packet data
|
||||
rx_packet_wr = wr; // save the length of the data
|
||||
}
|
||||
else
|
||||
{ // the save buffer is still in use .. nothing we can do but to drop the packet
|
||||
}
|
||||
|
||||
// return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false); // reset the receiver
|
||||
// return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t rfm22_topUpRFTxFIFO(void)
|
||||
{
|
||||
rfm22_int_timer = 0; // reset the timer
|
||||
|
||||
uint16_t rd = tx_data_rd;
|
||||
uint16_t wr = tx_data_wr;
|
||||
|
||||
if (rf_mode == TX_DATA_MODE && (!tx_data_addr || rd >= wr))
|
||||
return 0; // no more data to send
|
||||
|
||||
uint16_t max_bytes = FIFO_SIZE - TX_FIFO_LO_WATERMARK - 1;
|
||||
|
||||
uint16_t i = 0;
|
||||
|
||||
// top-up the rf chips TX FIFO buffer
|
||||
rfm22_startBurstWrite(RFM22_fifo_access);
|
||||
|
||||
// add some data
|
||||
for (uint16_t j = wr - rd; j > 0; j--)
|
||||
{
|
||||
// int16_t b = -1;
|
||||
// if (tx_data_byte_callback_function)
|
||||
// b = tx_data_byte_callback_function();
|
||||
// reset the timer
|
||||
rfm22_int_timer = 0;
|
||||
|
||||
rfm22_burstWrite(tx_data_addr[rd++]);
|
||||
if (++i >= max_bytes) break;
|
||||
}
|
||||
tx_data_rd = rd;
|
||||
// read the total length of the packet data
|
||||
register uint16_t len = rfm22_read(RFM22_received_packet_length);
|
||||
|
||||
if (rf_mode == TX_STREAM_MODE && rd >= wr)
|
||||
{ // all data sent .. need to start sending RF header again
|
||||
|
||||
tx_data_addr = NULL;
|
||||
tx_data_rd = tx_data_wr = 0;
|
||||
|
||||
while (i < max_bytes)
|
||||
// their must still be data in the RX FIFO we need to get
|
||||
if (rx_buffer_wr < len)
|
||||
{
|
||||
rfm22_burstWrite(PREAMBLE_BYTE); // preamble byte
|
||||
i++;
|
||||
// Fetch the data from the RX FIFO
|
||||
rfm22_startBurstRead(RFM22_fifo_access);
|
||||
while (rx_buffer_wr < len)
|
||||
rx_buffer[rx_buffer_wr++] = rfm22_burstRead();
|
||||
rfm22_endBurstRead();
|
||||
}
|
||||
|
||||
// todo:
|
||||
if (rx_buffer_wr != len)
|
||||
{
|
||||
// we have a packet length error .. discard the packet
|
||||
rfm22_setError("r_pack_len_error");
|
||||
debug_val = len;
|
||||
return;
|
||||
}
|
||||
|
||||
// add the RF heaader
|
||||
// i += rfm22_addHeader();
|
||||
// we have a valid received packet
|
||||
rfm22_setDebug("VALID_R_PACKET");
|
||||
|
||||
if (rx_packet_wr == 0)
|
||||
{
|
||||
// remember the rssi for this packet
|
||||
rx_packet_rssi_dBm = rx_packet_start_rssi_dBm;
|
||||
// remember the afc offset for this packet
|
||||
rx_packet_afc_Hz = rx_packet_start_afc_Hz;
|
||||
// Pass this packet on
|
||||
bool need_yield = false;
|
||||
if (rfm22b_dev_g->rx_in_cb)
|
||||
(rfm22b_dev_g->rx_in_cb)(rfm22b_dev_g->rx_in_context, (uint8_t*)rx_buffer,
|
||||
rx_buffer_wr, NULL, &need_yield);
|
||||
rx_buffer_wr = 0;
|
||||
}
|
||||
|
||||
// Send a packet if it's available.
|
||||
if(!rfm22_txStart())
|
||||
{
|
||||
// Switch to RX mode
|
||||
rfm22_setDebug(" Set RX");
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
}
|
||||
}
|
||||
|
||||
rfm22_endBurstWrite();
|
||||
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
// DEBUG_PRINTF(2, " added_%d_bytes", i);
|
||||
// debug_outputted = true;
|
||||
#endif
|
||||
|
||||
return i;
|
||||
rfm22_setDebug("processRxInt end");
|
||||
}
|
||||
|
||||
void rfm22_processTxInt(void)
|
||||
{
|
||||
register uint8_t int_stat1 = int_status1;
|
||||
// register uint8_t int_stat2 = int_status2;
|
||||
|
||||
/*
|
||||
if (int_stat1 & RFM22_is1_ifferr)
|
||||
{ // FIFO underflow/overflow error
|
||||
// reset the timer
|
||||
rfm22_int_timer = 0;
|
||||
|
||||
// FIFO under/over flow error. Back to RX mode.
|
||||
if (device_status & (RFM22_ds_ffunfl | RFM22_ds_ffovfl))
|
||||
{
|
||||
rfm22_setError("T_UNDER/OVERRUN");
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
tx_data_addr = NULL;
|
||||
tx_data_rd = tx_data_wr = 0;
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
if (int_stat1 & RFM22_is1_ixtffaem)
|
||||
{ // TX FIFO almost empty, it needs filling up
|
||||
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
// DEBUG_PRINTF(2, " T_FIFO_AE");
|
||||
// debug_outputted = true;
|
||||
#endif
|
||||
|
||||
// uint8_t bytes_added = rfm22_topUpRFTxFIFO();
|
||||
rfm22_topUpRFTxFIFO();
|
||||
}
|
||||
|
||||
if (int_stat1 & RFM22_is1_ipksent)
|
||||
{ // Packet has been sent
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, " T_Sent");
|
||||
debug_outputted = true;
|
||||
#endif
|
||||
// Transmit timeout. Abort the transmit.
|
||||
if (rfm22_int_timer >= timeout_data_ms)
|
||||
{
|
||||
rfm22_int_time_outs++;
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rf_mode == TX_DATA_MODE)
|
||||
// the rf module is not in tx mode
|
||||
if ((device_status & RFM22_ds_cps_mask) != RFM22_ds_cps_tx)
|
||||
{
|
||||
if (rfm22_int_timer >= 100)
|
||||
{
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false); // back to receive mode
|
||||
|
||||
tx_data_addr = NULL;
|
||||
tx_data_rd = tx_data_wr = 0;
|
||||
rfm22_int_time_outs++;
|
||||
rfm22_setError("T_TIMEOUT");
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false); // back to rx mode
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (rf_mode == TX_STREAM_MODE)
|
||||
{
|
||||
tx_data_addr = NULL;
|
||||
tx_data_rd = tx_data_wr = 0;
|
||||
|
||||
rfm22_setTxMode(TX_STREAM_MODE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if (int_stat1 & RFM22_is1_itxffafull)
|
||||
// { // TX FIFO almost full, it needs to be transmitted
|
||||
// }
|
||||
// TX FIFO almost empty, it needs filling up
|
||||
if (int_stat1 & RFM22_is1_ixtffaem)
|
||||
{
|
||||
// top-up the rf chips TX FIFO buffer
|
||||
uint16_t max_bytes = FIFO_SIZE - TX_FIFO_LO_WATERMARK - 1;
|
||||
rfm22_startBurstWrite(RFM22_fifo_access);
|
||||
for (uint16_t i = 0; (tx_data_rd < tx_data_wr) && (i < max_bytes); ++i, ++tx_data_rd)
|
||||
rfm22_burstWrite(tx_buffer[tx_data_rd]);
|
||||
rfm22_endBurstWrite();
|
||||
}
|
||||
|
||||
// Packet has been sent
|
||||
if (int_stat1 & RFM22_is1_ipksent)
|
||||
{
|
||||
rfm22_setDebug(" T_Sent");
|
||||
|
||||
// Send another packet if it's available.
|
||||
if(!rfm22_txStart())
|
||||
{
|
||||
// Switch to RX mode
|
||||
rfm22_setDebug(" Set RX");
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rfm22_setDebug("ProcessTxInt done");
|
||||
}
|
||||
|
||||
void rfm22_processInt(void)
|
||||
{
|
||||
rfm22_setDebug("ProcessInt");
|
||||
// this is called from the external interrupt handler
|
||||
|
||||
#if !defined(RFM22_EXT_INT_USE)
|
||||
// if (GPIO_IN(RF_INT_PIN))
|
||||
//return; // the external int line is high (no signalled interrupt)
|
||||
#endif
|
||||
|
||||
if (!initialized || power_on_reset)
|
||||
return; // we haven't yet been initialized
|
||||
// we haven't yet been initialized
|
||||
return;
|
||||
|
||||
#if defined(RFM22_DEBUG)
|
||||
debug_outputted = false;
|
||||
#endif
|
||||
exec_using_spi = TRUE;
|
||||
|
||||
// ********************************
|
||||
// read the RF modules current status registers
|
||||
|
||||
// read device status register
|
||||
device_status = rfm22_read(RFM22_device_status);
|
||||
|
||||
// read ezmac status register
|
||||
ezmac_status = rfm22_read(RFM22_ezmac_status);
|
||||
|
||||
// read interrupt status registers - clears the interrupt line
|
||||
int_status1 = rfm22_read(RFM22_interrupt_status1);
|
||||
int_status2 = rfm22_read(RFM22_interrupt_status2);
|
||||
|
||||
if (rf_mode != TX_DATA_MODE && rf_mode != TX_STREAM_MODE && rf_mode != TX_CARRIER_MODE && rf_mode != TX_PN_MODE)
|
||||
// read device status register
|
||||
device_status = rfm22_read(RFM22_device_status);
|
||||
|
||||
#ifdef NEVER
|
||||
// read ezmac status register
|
||||
ezmac_status = rfm22_read(RFM22_ezmac_status);
|
||||
|
||||
// Read the RSSI if we're in RX mode
|
||||
if (rf_mode != TX_DATA_MODE && rf_mode != TX_STREAM_MODE &&
|
||||
rf_mode != TX_CARRIER_MODE && rf_mode != TX_PN_MODE)
|
||||
{
|
||||
rssi = rfm22_read(RFM22_rssi); // read rx signal strength .. 45 = -100dBm, 205 = -20dBm
|
||||
rssi_dBm = ((int16_t)rssi / 2) - 122; // convert to dBm
|
||||
// read rx signal strength .. 45 = -100dBm, 205 = -20dBm
|
||||
rssi = rfm22_read(RFM22_rssi);
|
||||
// convert to dBm
|
||||
rssi_dBm = ((int16_t)rssi / 2) - 122;
|
||||
|
||||
// calibrate the RSSI value (rf bandwidth appears to affect it)
|
||||
// if (rf_bandwidth_used > 0)
|
||||
@ -1734,64 +1573,20 @@ void rfm22_processInt(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
tx_pwr = rfm22_read(RFM22_tx_power); // read the tx power register
|
||||
}
|
||||
|
||||
if (int_status2 & RFM22_is2_ipor)
|
||||
{ // the RF module has gone and done a reset - we need to re-initialize the rf module
|
||||
initialized = FALSE;
|
||||
power_on_reset = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
// ********************************
|
||||
// debug stuff
|
||||
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
if (prev_device_status != device_status || prev_int_status1 != int_status1 || prev_int_status2 != int_status2 || prev_ezmac_status != ezmac_status)
|
||||
{
|
||||
DEBUG_PRINTF(2, "%02x %02x %02x %02x %dC", device_status, int_status1, int_status2, ezmac_status, temperature_reg);
|
||||
|
||||
if ((device_status & RFM22_ds_cps_mask) == RFM22_ds_cps_rx)
|
||||
{
|
||||
DEBUG_PRINTF(2, " %ddBm", rssi_dBm); // rx mode
|
||||
}
|
||||
else
|
||||
if ((device_status & RFM22_ds_cps_mask) == RFM22_ds_cps_tx)
|
||||
{
|
||||
DEBUG_PRINTF(2, " %s", (tx_pwr & RFM22_tx_pwr_papeakval) ? "ANT_MISMATCH" : "ant_ok"); // tx mode
|
||||
}
|
||||
|
||||
debug_outputted = true;
|
||||
|
||||
prev_device_status = device_status;
|
||||
prev_int_status1 = int_status1;
|
||||
prev_int_status2 = int_status2;
|
||||
prev_ezmac_status = ezmac_status;
|
||||
// read the tx power register
|
||||
tx_pwr = rfm22_read(RFM22_tx_power);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ********************************
|
||||
// read the ADC - temperature sensor .. this can only be used in IDLE mode
|
||||
/*
|
||||
if (!(rfm22_read(RFM22_adc_config) & RFM22_ac_adcstartbusy))
|
||||
{ // the ADC has completed it's conversion
|
||||
|
||||
// read the ADC sample
|
||||
temperature_reg = (int16_t)rfm22_read(RFM22_adc_value) * 0.5f - 64;
|
||||
|
||||
// start a new ADC conversion
|
||||
rfm22_write(RFM22_adc_config, adc_config | RFM22_ac_adcstartbusy);
|
||||
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, ", %dC", temperature_reg);
|
||||
debug_outputted = true;
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
// ********************************
|
||||
|
||||
register uint16_t timer_ms = rfm22_int_timer;
|
||||
// the RF module has gone and done a reset - we need to re-initialize the rf module
|
||||
if (int_status2 & RFM22_is2_ipor)
|
||||
{
|
||||
initialized = FALSE;
|
||||
power_on_reset = TRUE;
|
||||
rfm22_setError("Reset");
|
||||
// Need to do something here!
|
||||
return;
|
||||
}
|
||||
|
||||
switch (rf_mode)
|
||||
{
|
||||
@ -1802,115 +1597,19 @@ void rfm22_processInt(void)
|
||||
case RX_WAIT_SYNC_MODE:
|
||||
case RX_DATA_MODE:
|
||||
|
||||
if (device_status & (RFM22_ds_ffunfl | RFM22_ds_ffovfl))
|
||||
{ // FIFO under/over flow error
|
||||
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, " R_UNDER/OVERRUN");
|
||||
debug_outputted = true;
|
||||
#endif
|
||||
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false); // reset the receiver
|
||||
tx_data_rd = tx_data_wr = 0; // wipe TX buffer
|
||||
break;
|
||||
}
|
||||
|
||||
if (rf_mode == RX_WAIT_SYNC_MODE && timer_ms >= timeout_sync_ms)
|
||||
{
|
||||
rfm22_int_time_outs++;
|
||||
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, " R_SYNC_TIMEOUT");
|
||||
debug_outputted = true;
|
||||
#endif
|
||||
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false); // reset the receiver
|
||||
tx_data_rd = tx_data_wr = 0; // wipe TX buffer
|
||||
break;
|
||||
}
|
||||
|
||||
if (rf_mode == RX_DATA_MODE && timer_ms >= timeout_data_ms)
|
||||
{ // missing interrupts
|
||||
rfm22_int_time_outs++;
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false); // reset the receiver
|
||||
tx_data_rd = tx_data_wr = 0; // wipe TX buffer
|
||||
break;
|
||||
}
|
||||
|
||||
if ((device_status & RFM22_ds_cps_mask) != RFM22_ds_cps_rx)
|
||||
{ // the rf module is not in rx mode
|
||||
if (timer_ms >= 100)
|
||||
{
|
||||
rfm22_int_time_outs++;
|
||||
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, " R_TIMEOUT");
|
||||
debug_outputted = true;
|
||||
#endif
|
||||
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false); // reset the receiver
|
||||
tx_data_rd = tx_data_wr = 0; // wipe TX buffer
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rfm22_processRxInt(); // process the interrupt
|
||||
rfm22_processRxInt();
|
||||
break;
|
||||
|
||||
case TX_DATA_MODE:
|
||||
|
||||
if (device_status & (RFM22_ds_ffunfl | RFM22_ds_ffovfl))
|
||||
{ // FIFO under/over flow error
|
||||
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, " T_UNDER/OVERRUN");
|
||||
debug_outputted = true;
|
||||
#endif
|
||||
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false); // back to rx mode
|
||||
tx_data_rd = tx_data_wr = 0; // wipe TX buffer
|
||||
break;
|
||||
}
|
||||
|
||||
if (timer_ms >= timeout_data_ms)
|
||||
{
|
||||
rfm22_int_time_outs++;
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false); // back to rx mode
|
||||
tx_data_rd = tx_data_wr = 0; // wipe TX buffer
|
||||
break;
|
||||
}
|
||||
|
||||
if ((device_status & RFM22_ds_cps_mask) != RFM22_ds_cps_tx)
|
||||
{ // the rf module is not in tx mode
|
||||
if (timer_ms >= 100)
|
||||
{
|
||||
rfm22_int_time_outs++;
|
||||
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
DEBUG_PRINTF(2, " T_TIMEOUT");
|
||||
debug_outputted = true;
|
||||
#endif
|
||||
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false); // back to rx mode
|
||||
tx_data_rd = tx_data_wr = 0; // wipe TX buffer
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rfm22_processTxInt(); // process the interrupt
|
||||
break;
|
||||
|
||||
case TX_STREAM_MODE:
|
||||
|
||||
// todo:
|
||||
rfm22_processTxInt(); // process the interrupt
|
||||
|
||||
rfm22_processTxInt();
|
||||
break;
|
||||
|
||||
case TX_CARRIER_MODE:
|
||||
case TX_PN_MODE:
|
||||
|
||||
// if (timer_ms >= TX_TEST_MODE_TIMELIMIT_MS) // 'nn'ms limit
|
||||
// if (rfm22_int_timer >= TX_TEST_MODE_TIMELIMIT_MS) // 'nn'ms limit
|
||||
// {
|
||||
// rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false); // back to rx mode
|
||||
// tx_data_rd = tx_data_wr = 0; // wipe TX buffer
|
||||
@ -1921,66 +1620,24 @@ void rfm22_processInt(void)
|
||||
|
||||
default: // unknown mode - this should NEVER happen, maybe we should do a complete CPU reset here
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false); // to rx mode
|
||||
tx_data_rd = tx_data_wr = 0; // wipe TX buffer
|
||||
break;
|
||||
}
|
||||
|
||||
// ********************************
|
||||
exec_using_spi = FALSE;
|
||||
|
||||
#if defined(RFM22_DEBUG) && !defined(RFM22_EXT_INT_USE)
|
||||
if (debug_outputted)
|
||||
{
|
||||
switch (rf_mode)
|
||||
{
|
||||
case RX_SCAN_SPECTRUM:
|
||||
DEBUG_PRINTF(2, " R_SCAN_SPECTRUM\n\r");
|
||||
break;
|
||||
case RX_WAIT_PREAMBLE_MODE:
|
||||
DEBUG_PRINTF(2, " R_WAIT_PREAMBLE\n\r");
|
||||
break;
|
||||
case RX_WAIT_SYNC_MODE:
|
||||
DEBUG_PRINTF(2, " R_WAIT_SYNC\n\r");
|
||||
break;
|
||||
case RX_DATA_MODE:
|
||||
DEBUG_PRINTF(2, " R_DATA\n\r");
|
||||
break;
|
||||
case TX_DATA_MODE:
|
||||
DEBUG_PRINTF(2, " T_DATA\n\r");
|
||||
break;
|
||||
case TX_STREAM_MODE:
|
||||
DEBUG_PRINTF(2, " T_STREAM\n\r");
|
||||
break;
|
||||
case TX_CARRIER_MODE:
|
||||
DEBUG_PRINTF(2, " T_CARRIER\n\r");
|
||||
break;
|
||||
case TX_PN_MODE:
|
||||
DEBUG_PRINTF(2, " T_PN\n\r");
|
||||
break;
|
||||
default:
|
||||
DEBUG_PRINTF(2, " UNKNOWN_MODE\n\r");
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// ********************************
|
||||
rfm22_setDebug("ProcessInt done");
|
||||
}
|
||||
|
||||
// ************************************
|
||||
|
||||
int16_t rfm22_getRSSI(void)
|
||||
{
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = TRUE;
|
||||
#endif
|
||||
|
||||
rssi = rfm22_read(RFM22_rssi); // read rx signal strength .. 45 = -100dBm, 205 = -20dBm
|
||||
rssi_dBm = ((int16_t)rssi / 2) - 122; // convert to dBm
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = FALSE;
|
||||
#endif
|
||||
|
||||
return rssi_dBm;
|
||||
}
|
||||
|
||||
@ -2000,57 +1657,8 @@ int32_t rfm22_receivedAFCHz(void)
|
||||
return rx_packet_afc_Hz;
|
||||
}
|
||||
|
||||
uint16_t rfm22_receivedLength(void)
|
||||
{ // return the size of the data received
|
||||
if (!initialized)
|
||||
return 0;
|
||||
else
|
||||
return rx_packet_wr;
|
||||
}
|
||||
|
||||
uint8_t * rfm22_receivedPointer(void)
|
||||
{ // return the address of the data
|
||||
return (uint8_t *)&rx_packet_buf;
|
||||
}
|
||||
|
||||
void rfm22_receivedDone(void)
|
||||
{ // empty the rx packet buffer
|
||||
rx_packet_wr = 0;
|
||||
}
|
||||
|
||||
// ************************************
|
||||
|
||||
int32_t rfm22_sendData(void *data, uint16_t length, bool send_immediately)
|
||||
{
|
||||
if (!initialized)
|
||||
return -1; // we are not yet initialized
|
||||
|
||||
if (length == 0)
|
||||
return -2; // no data to send
|
||||
|
||||
if (!data || length > 255)
|
||||
return -3; // no data or too much data to send
|
||||
|
||||
if (tx_data_wr > 0)
|
||||
return -4; // already have data to be sent
|
||||
|
||||
if (rf_mode == TX_DATA_MODE || rf_mode == TX_STREAM_MODE || rf_mode == TX_CARRIER_MODE || rf_mode == TX_PN_MODE || rf_mode == RX_SCAN_SPECTRUM)
|
||||
return -5; // we are currently transmitting or scanning the spectrum
|
||||
|
||||
tx_data_addr = data;
|
||||
tx_data_rd = 0;
|
||||
tx_data_wr = length;
|
||||
|
||||
#if defined(RFM22_DEBUG)
|
||||
DEBUG_PRINTF(2, "rf sendData(0x%08x %u)\n\r", (uint32_t)tx_data_addr, tx_data_wr);
|
||||
#endif
|
||||
|
||||
if (send_immediately || rfm22_channelIsClear()) // is the channel clear to transmit on?
|
||||
rfm22_setTxMode(TX_DATA_MODE); // transmit NOW
|
||||
|
||||
return tx_data_wr;
|
||||
}
|
||||
|
||||
// ************************************
|
||||
|
||||
void rfm22_setTxStream(void) // TEST ONLY
|
||||
@ -2122,10 +1730,12 @@ bool rfm22_transmitting(void)
|
||||
bool rfm22_channelIsClear(void)
|
||||
{
|
||||
if (!initialized)
|
||||
return FALSE; // we haven't yet been initialized
|
||||
// we haven't yet been initialized
|
||||
return FALSE;
|
||||
|
||||
if (rf_mode != RX_WAIT_PREAMBLE_MODE && rf_mode != RX_WAIT_SYNC_MODE)
|
||||
return FALSE; // we are receiving something or we are transmitting or we are scanning the spectrum
|
||||
// we are receiving something or we are transmitting or we are scanning the spectrum
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -2134,9 +1744,12 @@ bool rfm22_channelIsClear(void)
|
||||
bool rfm22_txReady(void)
|
||||
{
|
||||
if (!initialized)
|
||||
return FALSE; // we haven't yet been initialized
|
||||
// we haven't yet been initialized
|
||||
return FALSE;
|
||||
|
||||
return (tx_data_rd == 0 && tx_data_wr == 0 && rf_mode != TX_DATA_MODE && rf_mode != TX_STREAM_MODE && rf_mode != TX_CARRIER_MODE && rf_mode != TX_PN_MODE && rf_mode != RX_SCAN_SPECTRUM);
|
||||
return (tx_data_rd == 0 && tx_data_wr == 0 && rf_mode != TX_DATA_MODE &&
|
||||
rf_mode != TX_STREAM_MODE && rf_mode != TX_CARRIER_MODE && rf_mode != TX_PN_MODE &&
|
||||
rf_mode != RX_SCAN_SPECTRUM);
|
||||
}
|
||||
|
||||
// ************************************
|
||||
@ -2157,15 +1770,11 @@ void rfm22_setFreqCalibration(uint8_t value)
|
||||
tx_data_rd = tx_data_wr = 0;
|
||||
}
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = TRUE;
|
||||
#endif
|
||||
|
||||
rfm22_write(RFM22_xtal_osc_load_cap, osc_load_cap);
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = FALSE;
|
||||
#endif
|
||||
|
||||
if (prev_rf_mode == TX_CARRIER_MODE || prev_rf_mode == TX_PN_MODE)
|
||||
rfm22_setTxMode(prev_rf_mode);
|
||||
@ -2202,7 +1811,7 @@ void rfm22_process(void)
|
||||
|
||||
{
|
||||
static int cntr = 0;
|
||||
if (cntr >= 500) {
|
||||
if (cntr >= 5000) {
|
||||
DEBUG_PRINTF(2, "Process\n\r");
|
||||
cntr = 0;
|
||||
} else
|
||||
@ -2334,18 +1943,6 @@ void rfm22_process(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
// ************************************
|
||||
|
||||
void rfm22_TxDataByte_SetCallback(t_rfm22_TxDataByteCallback new_function)
|
||||
{
|
||||
tx_data_byte_callback_function = new_function;
|
||||
}
|
||||
|
||||
void rfm22_RxData_SetCallback(t_rfm22_RxDataCallback new_function)
|
||||
{
|
||||
rx_data_callback_function = new_function;
|
||||
}
|
||||
|
||||
// ************************************
|
||||
// reset the RF module
|
||||
|
||||
@ -2361,9 +1958,7 @@ int rfm22_resetModule(uint8_t mode, uint32_t min_frequency_hz, uint32_t max_freq
|
||||
|
||||
// ****************
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = TRUE;
|
||||
#endif
|
||||
|
||||
// ****************
|
||||
// setup the SPI port
|
||||
@ -2410,16 +2005,10 @@ int rfm22_resetModule(uint8_t mode, uint32_t min_frequency_hz, uint32_t max_freq
|
||||
|
||||
// ****************
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
exec_using_spi = FALSE;
|
||||
#endif
|
||||
|
||||
// ****************
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
inside_ext_int = FALSE;
|
||||
#endif
|
||||
|
||||
rf_mode = mode;
|
||||
|
||||
device_status = int_status1 = int_status2 = ezmac_status = 0;
|
||||
@ -2427,16 +2016,12 @@ int rfm22_resetModule(uint8_t mode, uint32_t min_frequency_hz, uint32_t max_freq
|
||||
rssi = 0;
|
||||
rssi_dBm = -200;
|
||||
|
||||
tx_data_byte_callback_function = NULL;
|
||||
rx_data_callback_function = NULL;
|
||||
|
||||
rx_buffer_current = 0;
|
||||
rx_buffer_wr = 0;
|
||||
rx_packet_wr = 0;
|
||||
rx_packet_rssi_dBm = -200;
|
||||
rx_packet_afc_Hz = 0;
|
||||
|
||||
tx_data_addr = NULL;
|
||||
tx_data_rd = tx_data_wr = 0;
|
||||
|
||||
lookup_index = 0;
|
||||
@ -2584,11 +2169,14 @@ int rfm22_init_scan_spectrum(uint32_t min_frequency_hz, uint32_t max_frequency_h
|
||||
rfm22_write(RFM22_header_enable1, 0xff);
|
||||
rfm22_write(RFM22_header_enable0, 0xff);
|
||||
|
||||
// rfm22_write(RFM22_frequency_hopping_step_size, 0); // set frequency hopping channel step size (multiples of 10kHz)
|
||||
// set frequency hopping channel step size (multiples of 10kHz)
|
||||
// rfm22_write(RFM22_frequency_hopping_step_size, 0);
|
||||
|
||||
rfm22_setNominalCarrierFrequency(min_frequency_hz); // set our nominal carrier frequency
|
||||
// set our nominal carrier frequency
|
||||
rfm22_setNominalCarrierFrequency(min_frequency_hz);
|
||||
|
||||
rfm22_write(RFM22_tx_power, RFM22_tx_pwr_lna_sw | 0); // set minimum tx power
|
||||
// set minimum tx power
|
||||
rfm22_write(RFM22_tx_power, RFM22_tx_pwr_lna_sw | 0);
|
||||
|
||||
rfm22_write(RFM22_agc_override1, RFM22_agc_ovr1_sgi | RFM22_agc_ovr1_agcen);
|
||||
|
||||
@ -2596,10 +2184,8 @@ int rfm22_init_scan_spectrum(uint32_t min_frequency_hz, uint32_t max_frequency_h
|
||||
// rfm22_write(RFM22_vco_calibration_override, 0x40);
|
||||
// rfm22_write(RFM22_chargepump_current_trimming_override, 0x80);
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
// Enable RF module external interrupt
|
||||
rfm22_enableExtInt();
|
||||
#endif
|
||||
|
||||
rfm22_setRxMode(RX_SCAN_SPECTRUM, true);
|
||||
|
||||
@ -2660,10 +2246,8 @@ int rfm22_init_tx_stream(uint32_t min_frequency_hz, uint32_t max_frequency_hz)
|
||||
rfm22_write(RFM22_tx_fifo_control1, TX_FIFO_HI_WATERMARK); // TX FIFO Almost Full Threshold (0 - 63)
|
||||
rfm22_write(RFM22_tx_fifo_control2, TX_FIFO_LO_WATERMARK); // TX FIFO Almost Empty Threshold (0 - 63)
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
// Enable RF module external interrupt
|
||||
rfm22_enableExtInt();
|
||||
#endif
|
||||
|
||||
initialized = true;
|
||||
|
||||
@ -2722,12 +2306,11 @@ int rfm22_init_rx_stream(uint32_t min_frequency_hz, uint32_t max_frequency_hz)
|
||||
// rfm22_write(RFM22_vco_calibration_override, 0x40);
|
||||
// rfm22_write(RFM22_chargepump_current_trimming_override, 0x80);
|
||||
|
||||
rfm22_write(RFM22_rx_fifo_control, RX_FIFO_HI_WATERMARK); // RX FIFO Almost Full Threshold (0 - 63)
|
||||
// RX FIFO Almost Full Threshold (0 - 63)
|
||||
rfm22_write(RFM22_rx_fifo_control, RX_FIFO_HI_WATERMARK);
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
// Enable RF module external interrupt
|
||||
rfm22_enableExtInt();
|
||||
#endif
|
||||
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
|
||||
@ -2745,15 +2328,11 @@ int rfm22_init_normal(uint32_t min_frequency_hz, uint32_t max_frequency_hz, uint
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
// ****************
|
||||
|
||||
// initialize the frequency hopping step size
|
||||
freq_hop_step_size /= 10000; // in 10kHz increments
|
||||
if (freq_hop_step_size > 255) freq_hop_step_size = 255;
|
||||
|
||||
frequency_hop_step_size_reg = freq_hop_step_size;
|
||||
|
||||
// ****************
|
||||
|
||||
// set the RF datarate
|
||||
rfm22_setDatarate(RFM22_DEFAULT_RF_DATARATE, TRUE);
|
||||
|
||||
@ -2762,77 +2341,76 @@ int rfm22_init_normal(uint32_t min_frequency_hz, uint32_t max_frequency_hz, uint
|
||||
rfm22_write(RFM22_modulation_mode_control2, RFM22_mmc2_trclk_clk_none | RFM22_mmc2_dtmod_fifo | fd_bit | RFM22_mmc2_modtyp_gfsk);
|
||||
|
||||
// setup to read the internal temperature sensor
|
||||
adc_config = RFM22_ac_adcsel_temp_sensor | RFM22_ac_adcref_bg; // ADC used to sample the temperature sensor
|
||||
rfm22_write(RFM22_adc_config, adc_config); //
|
||||
rfm22_write(RFM22_adc_sensor_amp_offset, 0); // adc offset
|
||||
rfm22_write(RFM22_temp_sensor_calib, RFM22_tsc_tsrange0 | RFM22_tsc_entsoffs); // temp sensor calibration .. –40C to +64C 0.5C resolution
|
||||
rfm22_write(RFM22_temp_value_offset, 0); // temp sensor offset
|
||||
rfm22_write(RFM22_adc_config, adc_config | RFM22_ac_adcstartbusy); // start an ADC conversion
|
||||
|
||||
rfm22_write(RFM22_rssi_threshold_clear_chan_indicator, (-90 + 122) * 2); // set the RSSI threshold interrupt to about -90dBm
|
||||
// ADC used to sample the temperature sensor
|
||||
adc_config = RFM22_ac_adcsel_temp_sensor | RFM22_ac_adcref_bg;
|
||||
rfm22_write(RFM22_adc_config, adc_config);
|
||||
|
||||
// adc offset
|
||||
rfm22_write(RFM22_adc_sensor_amp_offset, 0);
|
||||
|
||||
// temp sensor calibration .. –40C to +64C 0.5C resolution
|
||||
rfm22_write(RFM22_temp_sensor_calib, RFM22_tsc_tsrange0 | RFM22_tsc_entsoffs);
|
||||
|
||||
// temp sensor offset
|
||||
rfm22_write(RFM22_temp_value_offset, 0);
|
||||
|
||||
// start an ADC conversion
|
||||
rfm22_write(RFM22_adc_config, adc_config | RFM22_ac_adcstartbusy);
|
||||
|
||||
// set the RSSI threshold interrupt to about -90dBm
|
||||
rfm22_write(RFM22_rssi_threshold_clear_chan_indicator, (-90 + 122) * 2);
|
||||
|
||||
// enable the internal Tx & Rx packet handlers (with CRC)
|
||||
// rfm22_write(RFM22_data_access_control, RFM22_dac_enpacrx | RFM22_dac_enpactx | RFM22_dac_encrc | RFM22_dac_crc_crc16);
|
||||
// enable the internal Tx & Rx packet handlers (without CRC)
|
||||
rfm22_write(RFM22_data_access_control, RFM22_dac_enpacrx | RFM22_dac_enpactx);
|
||||
|
||||
rfm22_write(RFM22_preamble_length, TX_PREAMBLE_NIBBLES); // x-nibbles tx preamble
|
||||
rfm22_write(RFM22_preamble_detection_ctrl1, RX_PREAMBLE_NIBBLES << 3); // x-nibbles rx preamble detection
|
||||
// x-nibbles tx preamble
|
||||
rfm22_write(RFM22_preamble_length, TX_PREAMBLE_NIBBLES);
|
||||
// x-nibbles rx preamble detection
|
||||
rfm22_write(RFM22_preamble_detection_ctrl1, RX_PREAMBLE_NIBBLES << 3);
|
||||
|
||||
rfm22_write(RFM22_header_control1, RFM22_header_cntl1_bcen_none | RFM22_header_cntl1_hdch_none); // header control - we are not using the header
|
||||
rfm22_write(RFM22_header_control2, RFM22_header_cntl2_hdlen_none | RFM22_header_cntl2_synclen_3210 | ((TX_PREAMBLE_NIBBLES >> 8) & 0x01)); // no header bytes, synchronization word length 3, 2, 1 & 0 used, packet length included in header.
|
||||
// header control - we are not using the header
|
||||
rfm22_write(RFM22_header_control1, RFM22_header_cntl1_bcen_none | RFM22_header_cntl1_hdch_none);
|
||||
|
||||
rfm22_write(RFM22_sync_word3, SYNC_BYTE_1); // sync word
|
||||
rfm22_write(RFM22_sync_word2, SYNC_BYTE_2); //
|
||||
rfm22_write(RFM22_sync_word1, SYNC_BYTE_3); //
|
||||
rfm22_write(RFM22_sync_word0, SYNC_BYTE_4); //
|
||||
/*
|
||||
rfm22_write(RFM22_transmit_header3, 'p'); // set tx header
|
||||
rfm22_write(RFM22_transmit_header2, 'i'); //
|
||||
rfm22_write(RFM22_transmit_header1, 'p'); //
|
||||
rfm22_write(RFM22_transmit_header0, ' '); //
|
||||
// no header bytes, synchronization word length 3, 2, 1 & 0 used, packet length included in header.
|
||||
rfm22_write(RFM22_header_control2, RFM22_header_cntl2_hdlen_none |
|
||||
RFM22_header_cntl2_synclen_3210 | ((TX_PREAMBLE_NIBBLES >> 8) & 0x01));
|
||||
|
||||
rfm22_write(RFM22_check_header3, 'p'); // set expected rx header
|
||||
rfm22_write(RFM22_check_header2, 'i'); //
|
||||
rfm22_write(RFM22_check_header1, 'p'); //
|
||||
rfm22_write(RFM22_check_header0, ' '); //
|
||||
// sync word
|
||||
rfm22_write(RFM22_sync_word3, SYNC_BYTE_1);
|
||||
rfm22_write(RFM22_sync_word2, SYNC_BYTE_2);
|
||||
rfm22_write(RFM22_sync_word1, SYNC_BYTE_3);
|
||||
rfm22_write(RFM22_sync_word0, SYNC_BYTE_4);
|
||||
|
||||
// all the bits to be checked
|
||||
rfm22_write(RFM22_header_enable3, 0xff);
|
||||
rfm22_write(RFM22_header_enable2, 0xff);
|
||||
rfm22_write(RFM22_header_enable1, 0xff);
|
||||
rfm22_write(RFM22_header_enable0, 0xff);
|
||||
*/ // no bits to be checked
|
||||
// no bits to be checked
|
||||
rfm22_write(RFM22_header_enable3, 0x00);
|
||||
rfm22_write(RFM22_header_enable2, 0x00);
|
||||
rfm22_write(RFM22_header_enable1, 0x00);
|
||||
rfm22_write(RFM22_header_enable0, 0x00);
|
||||
|
||||
// rfm22_write(RFM22_modem_test, 0x01);
|
||||
|
||||
rfm22_write(RFM22_agc_override1, RFM22_agc_ovr1_agcen);
|
||||
// rfm22_write(RFM22_agc_override1, RFM22_agc_ovr1_sgi | RFM22_agc_ovr1_agcen);
|
||||
|
||||
rfm22_write(RFM22_frequency_hopping_step_size, frequency_hop_step_size_reg); // set frequency hopping channel step size (multiples of 10kHz)
|
||||
// set frequency hopping channel step size (multiples of 10kHz)
|
||||
rfm22_write(RFM22_frequency_hopping_step_size, frequency_hop_step_size_reg);
|
||||
|
||||
rfm22_setNominalCarrierFrequency((min_frequency_hz + max_frequency_hz) / 2); // set our nominal carrier frequency
|
||||
// set our nominal carrier frequency
|
||||
rfm22_setNominalCarrierFrequency((min_frequency_hz + max_frequency_hz) / 2);
|
||||
|
||||
rfm22_write(RFM22_tx_power, RFM22_tx_pwr_papeaken | RFM22_tx_pwr_papeaklvl_0 | RFM22_tx_pwr_lna_sw | tx_power); // set the tx power
|
||||
// rfm22_write(RFM22_tx_power, RFM22_tx_pwr_lna_sw | tx_power); // set the tx power
|
||||
// set the tx power
|
||||
rfm22_write(RFM22_tx_power, RFM22_tx_pwr_papeaken | RFM22_tx_pwr_papeaklvl_0 |
|
||||
RFM22_tx_pwr_lna_sw | tx_power);
|
||||
|
||||
// rfm22_write(RFM22_vco_current_trimming, 0x7f);
|
||||
// rfm22_write(RFM22_vco_calibration_override, 0x40);
|
||||
// rfm22_write(RFM22_chargepump_current_trimming_override, 0x80);
|
||||
// TX FIFO Almost Full Threshold (0 - 63)
|
||||
rfm22_write(RFM22_tx_fifo_control1, TX_FIFO_HI_WATERMARK);
|
||||
|
||||
rfm22_write(RFM22_tx_fifo_control1, TX_FIFO_HI_WATERMARK); // TX FIFO Almost Full Threshold (0 - 63)
|
||||
rfm22_write(RFM22_tx_fifo_control2, TX_FIFO_LO_WATERMARK); // TX FIFO Almost Empty Threshold (0 - 63)
|
||||
// TX FIFO Almost Empty Threshold (0 - 63)
|
||||
rfm22_write(RFM22_tx_fifo_control2, TX_FIFO_LO_WATERMARK);
|
||||
|
||||
rfm22_write(RFM22_rx_fifo_control, RX_FIFO_HI_WATERMARK); // RX FIFO Almost Full Threshold (0 - 63)
|
||||
// RX FIFO Almost Full Threshold (0 - 63)
|
||||
rfm22_write(RFM22_rx_fifo_control, RX_FIFO_HI_WATERMARK);
|
||||
|
||||
#if defined(RFM22_EXT_INT_USE)
|
||||
// Enable RF module external interrupt
|
||||
rfm22_enableExtInt();
|
||||
#endif
|
||||
|
||||
rfm22_setRxMode(RX_WAIT_PREAMBLE_MODE, false);
|
||||
|
||||
|
@ -490,4 +490,5 @@ const struct pios_rfm22b_cfg pios_rfm22b_cfg = {
|
||||
.maxConnections = 1,
|
||||
.id = 0x36249acb
|
||||
};
|
||||
|
||||
#endif /* PIOS_INCLUDE_RFM22B */
|
||||
|
@ -38,7 +38,7 @@
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Aircraft type:</string>
|
||||
<string>Vehicle type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -173,7 +173,7 @@ QGroupBox::title {
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="fwEngineChannel">
|
||||
<widget class="QComboBox" name="fwEngineChannelBox">
|
||||
<property name="toolTip">
|
||||
<string>Select output channel for the engine</string>
|
||||
</property>
|
||||
@ -193,7 +193,7 @@ QGroupBox::title {
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="fwAileron1Channel">
|
||||
<widget class="QComboBox" name="fwAileron1ChannelBox">
|
||||
<property name="toolTip">
|
||||
<string>Select output channel for the first aileron (or elevon)</string>
|
||||
</property>
|
||||
@ -216,7 +216,7 @@ QGroupBox::title {
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="fwAileron2Channel">
|
||||
<widget class="QComboBox" name="fwAileron2ChannelBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
@ -239,7 +239,7 @@ QGroupBox::title {
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="fwElevator1Channel">
|
||||
<widget class="QComboBox" name="fwElevator1ChannelBox">
|
||||
<property name="toolTip">
|
||||
<string>Select output channel for the first elevator</string>
|
||||
</property>
|
||||
@ -262,12 +262,12 @@ QGroupBox::title {
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="fwElevator2Channel">
|
||||
<widget class="QComboBox" name="fwElevator2ChannelBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Select output channel for a secondry elevator</string>
|
||||
<string>Select output channel for a secondary elevator</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -279,7 +279,7 @@ QGroupBox::title {
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="fwRudder1Channel">
|
||||
<widget class="QComboBox" name="fwRudder1ChannelBox">
|
||||
<property name="toolTip">
|
||||
<string>Select output channel for the first rudder</string>
|
||||
</property>
|
||||
@ -293,7 +293,7 @@ QGroupBox::title {
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QComboBox" name="fwRudder2Channel">
|
||||
<widget class="QComboBox" name="fwRudder2ChannelBox">
|
||||
<property name="toolTip">
|
||||
<string>Select output channel for a secondary rudder</string>
|
||||
</property>
|
||||
@ -390,7 +390,7 @@ margin:1px;</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_18">
|
||||
<widget class="QLabel" name="elevonSliderLabel1">
|
||||
<property name="text">
|
||||
<string>50</string>
|
||||
</property>
|
||||
@ -446,7 +446,7 @@ margin:1px;</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_25">
|
||||
<widget class="QLabel" name="elevonSliderLabel2">
|
||||
<property name="text">
|
||||
<string>50</string>
|
||||
</property>
|
||||
@ -533,6 +533,12 @@ margin:1px;</string>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="fwThrottleReset">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
@ -681,7 +687,13 @@ margin:1px;</string>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_22">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_43">
|
||||
<widget class="QLabel" name="mrRollMixValue">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>100</string>
|
||||
</property>
|
||||
@ -692,6 +704,12 @@ margin:1px;</string>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="mrRollMixLevel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>35</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Weight of Roll mixing in percent.
|
||||
Typical values are 100% for + configuration and 50% for X configuration on quads.</string>
|
||||
@ -729,7 +747,13 @@ margin:1px;</string>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_23">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_44">
|
||||
<widget class="QLabel" name="mrYawPitchValue">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>100</string>
|
||||
</property>
|
||||
@ -740,6 +764,12 @@ margin:1px;</string>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="mrPitchMixLevel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>35</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Weight of Pitch mixing in percent.
|
||||
Typical values are 100% for + configuration and 50% for X configuration on quads.</string>
|
||||
@ -777,7 +807,13 @@ margin:1px;</string>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_21">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_45">
|
||||
<widget class="QLabel" name="mrYawMixValue">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>50</string>
|
||||
</property>
|
||||
@ -788,6 +824,12 @@ margin:1px;</string>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="mrYawMixLevel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Weight of Yaw mixing in percent.
|
||||
Typical value is 50% for + or X configuration on quads.</string>
|
||||
@ -923,6 +965,12 @@ margin:1px;</string>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
@ -992,7 +1040,7 @@ margin:1px;</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="triYawChannel">
|
||||
<widget class="QComboBox" name="triYawChannelBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
@ -1046,7 +1094,7 @@ margin:1px;</string>
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<widget class="QLabel" name="MotorOutputLabel1">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255));
|
||||
color: rgb(255, 255, 255);
|
||||
@ -1060,7 +1108,7 @@ margin:1px;</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="multiMotor1">
|
||||
<widget class="QComboBox" name="multiMotorChannelBox1">
|
||||
<property name="toolTip">
|
||||
<string>Assign your motor output channels using the drawing above as a reference. Respect propeller rotation.</string>
|
||||
</property>
|
||||
@ -1081,7 +1129,7 @@ margin:1px;</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="multiMotor2">
|
||||
<widget class="QComboBox" name="multiMotorChannelBox2">
|
||||
<property name="toolTip">
|
||||
<string>Assign your motor output channels using the drawing above as a reference. Respect propeller rotation.</string>
|
||||
</property>
|
||||
@ -1102,7 +1150,7 @@ margin:1px;</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="multiMotor3">
|
||||
<widget class="QComboBox" name="multiMotorChannelBox3">
|
||||
<property name="toolTip">
|
||||
<string>Assign your motor output channels using the drawing above as a reference. Respect propeller rotation.</string>
|
||||
</property>
|
||||
@ -1123,7 +1171,7 @@ margin:1px;</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="multiMotor4">
|
||||
<widget class="QComboBox" name="multiMotorChannelBox4">
|
||||
<property name="toolTip">
|
||||
<string>Assign your motor output channels using the drawing above as a reference. Respect propeller rotation.</string>
|
||||
</property>
|
||||
@ -1170,7 +1218,7 @@ margin:1px;</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="multiMotor5">
|
||||
<widget class="QComboBox" name="multiMotorChannelBox5">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
@ -1200,7 +1248,7 @@ margin:1px;</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="multiMotor6">
|
||||
<widget class="QComboBox" name="multiMotorChannelBox6">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
@ -1224,7 +1272,7 @@ margin:1px;</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="multiMotor7">
|
||||
<widget class="QComboBox" name="multiMotorChannelBox7">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
@ -1248,7 +1296,7 @@ margin:1px;</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="multiMotor8">
|
||||
<widget class="QComboBox" name="multiMotorChannelBox8">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
@ -1334,6 +1382,520 @@ margin:1px;</string>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="groundVehicle">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3" stretch="0">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Vehicle type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="groundVehicleType"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_23">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Channel Assignment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_15">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Output channel asignmets</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="gvEngineLabel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>77</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Engine</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="gvEngineChannelBox">
|
||||
<property name="toolTip">
|
||||
<string>Select output channel for the engine</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="gvAileron1Label">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Aileron 1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="gvAileron1ChannelBox">
|
||||
<property name="toolTip">
|
||||
<string>Select output channel for the first aileron (or elevon)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="gvAileron2Label">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Aileron 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="gvAileron2ChannelBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Select output channel for the second aileron (or elevon)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="gvMotor1Label">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Motor</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="gvMotor1ChannelBox">
|
||||
<property name="toolTip">
|
||||
<string>Select output channel for the first motor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="gvMotor2Label">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>47</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Motor 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="gvMotor2ChannelBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Select output channel for a second motor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="gvSteering1Label">
|
||||
<property name="text">
|
||||
<string>Front Steering</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="gvSteering1ChannelBox">
|
||||
<property name="toolTip">
|
||||
<string>Select output channel for the first steering actuator</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="gvSteering2Label">
|
||||
<property name="text">
|
||||
<string>Rear Steering</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="gvSteering2ChannelBox">
|
||||
<property name="toolTip">
|
||||
<string>Select output channel for a second steering actuator</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="differentialSteeringMixBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Differential Steering Mix</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_14">
|
||||
<item>
|
||||
<widget class="QLabel" name="differentialSteeringLabel1">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>65</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Left %</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="differentialSteeringSlider1">
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>50</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="gvDiffSteering1Label">
|
||||
<property name="text">
|
||||
<string>50</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_15">
|
||||
<item>
|
||||
<widget class="QLabel" name="differentialSteeringLabel2">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Right %</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="differentialSteeringSlider2">
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>50</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="gvDiffSteering2Label">
|
||||
<property name="text">
|
||||
<string>50</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gvThrottleCurve1GroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>100</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Front throttle curve</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||
<item>
|
||||
<widget class="MixerCurveWidget" name="groundVehicleThrottle1" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeIncrement">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="gvThrottleCurve1Reset">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="gvThrottleCurve1ItemValue">
|
||||
<property name="text">
|
||||
<string>Val: 0.00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gvThrottleCurve2GroupBox">
|
||||
<property name="title">
|
||||
<string>Rear throttle curve</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_17">
|
||||
<item>
|
||||
<widget class="MixerCurveWidget" name="groundVehicleThrottle2" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="gvThrottleCurve2Reset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="gvThrottleCurve2ItemValue">
|
||||
<property name="text">
|
||||
<string>Val: 0.00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_13">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_11">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="gvStatusLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Mixer OK</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="custom">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_15">
|
||||
<item>
|
||||
@ -1990,7 +2552,7 @@ margin:1px;</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="feedForwardValue">
|
||||
<widget class="QLabel" name="feedForwardSliderValue">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
@ -2095,7 +2657,7 @@ Do it after accel time is setup.</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_33">
|
||||
<widget class="QLabel" name="maxAccelSliderValue">
|
||||
<property name="text">
|
||||
<string>1000</string>
|
||||
</property>
|
||||
@ -2329,7 +2891,7 @@ p, li { white-space: pre-wrap; }
|
||||
<customwidget>
|
||||
<class>ConfigccpmWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>configccpmwidget.h</header>
|
||||
<header>cfg_vehicletypes/configccpmwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
@ -2340,7 +2902,7 @@ p, li { white-space: pre-wrap; }
|
||||
<connection>
|
||||
<sender>feedForwardSlider</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>feedForwardValue</receiver>
|
||||
<receiver>feedForwardSliderValue</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
@ -2356,7 +2918,7 @@ p, li { white-space: pre-wrap; }
|
||||
<connection>
|
||||
<sender>maxAccelSlider</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>label_33</receiver>
|
||||
<receiver>maxAccelSliderValue</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
@ -2372,7 +2934,7 @@ p, li { white-space: pre-wrap; }
|
||||
<connection>
|
||||
<sender>elevonSlider1</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>label_18</receiver>
|
||||
<receiver>elevonSliderLabel1</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
@ -2388,12 +2950,12 @@ p, li { white-space: pre-wrap; }
|
||||
<connection>
|
||||
<sender>elevonSlider2</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>label_25</receiver>
|
||||
<receiver>elevonSliderLabel2</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>124</x>
|
||||
<y>126</y>
|
||||
<x>362</x>
|
||||
<y>299</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>124</x>
|
||||
@ -2401,10 +2963,42 @@ p, li { white-space: pre-wrap; }
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>differentialSteeringSlider1</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>gvDiffSteering1Label</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>124</x>
|
||||
<y>126</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>315</x>
|
||||
<y>391</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>differentialSteeringSlider2</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>gvDiffSteering2Label</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>124</x>
|
||||
<y>126</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>390</x>
|
||||
<y>391</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>mrPitchMixLevel</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>label_44</receiver>
|
||||
<receiver>mrPitchMixValue</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
@ -2420,7 +3014,7 @@ p, li { white-space: pre-wrap; }
|
||||
<connection>
|
||||
<sender>mrRollMixLevel</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>label_43</receiver>
|
||||
<receiver>mrRollMixValue</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
@ -2436,7 +3030,7 @@ p, li { white-space: pre-wrap; }
|
||||
<connection>
|
||||
<sender>mrYawMixLevel</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>label_45</receiver>
|
||||
<receiver>mrYawMixValue</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
|
@ -81,7 +81,7 @@ public:
|
||||
ConfigccpmWidget(QWidget *parent = 0);
|
||||
~ConfigccpmWidget();
|
||||
|
||||
friend class ConfigAirframeWidget;
|
||||
friend class ConfigVehicleTypeWidget;
|
||||
|
||||
private:
|
||||
Ui_ccpmWidget *m_ccpm;
|
@ -0,0 +1,699 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file configfixedwidget.cpp
|
||||
* @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup ConfigPlugin Config Plugin
|
||||
* @{
|
||||
* @brief ccpm configuration panel
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
//#include "configfixedwingwidget.h"
|
||||
#include "configvehicletypewidget.h"
|
||||
#include "mixersettings.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStringList>
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtGui/QTextEdit>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
#include <QtGui/QPushButton>
|
||||
#include <QBrush>
|
||||
#include <math.h>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "mixersettings.h"
|
||||
#include "systemsettings.h"
|
||||
#include "actuatorcommand.h"
|
||||
|
||||
|
||||
/**
|
||||
Helper function to setup the UI
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::setupFixedWingUI(QString frameType)
|
||||
{
|
||||
if (frameType == "FixedWing" || frameType == "Elevator aileron rudder") {
|
||||
// Setup the UI
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
|
||||
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevator aileron rudder"));
|
||||
m_aircraft->fwRudder1ChannelBox->setEnabled(true);
|
||||
m_aircraft->fwRudder1Label->setEnabled(true);
|
||||
m_aircraft->fwRudder2ChannelBox->setEnabled(true);
|
||||
m_aircraft->fwRudder2Label->setEnabled(true);
|
||||
m_aircraft->fwElevator1ChannelBox->setEnabled(true);
|
||||
m_aircraft->fwElevator1Label->setEnabled(true);
|
||||
m_aircraft->fwElevator2ChannelBox->setEnabled(true);
|
||||
m_aircraft->fwElevator2Label->setEnabled(true);
|
||||
m_aircraft->fwAileron1ChannelBox->setEnabled(true);
|
||||
m_aircraft->fwAileron1Label->setEnabled(true);
|
||||
m_aircraft->fwAileron2ChannelBox->setEnabled(true);
|
||||
m_aircraft->fwAileron2Label->setEnabled(true);
|
||||
|
||||
m_aircraft->fwAileron1Label->setText("Aileron 1");
|
||||
m_aircraft->fwAileron2Label->setText("Aileron 2");
|
||||
m_aircraft->fwElevator1Label->setText("Elevator 1");
|
||||
m_aircraft->fwElevator2Label->setText("Elevator 2");
|
||||
m_aircraft->elevonMixBox->setHidden(true);
|
||||
|
||||
} else if (frameType == "FixedWingElevon" || frameType == "Elevon") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
|
||||
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevon"));
|
||||
m_aircraft->fwAileron1Label->setText("Elevon 1");
|
||||
m_aircraft->fwAileron2Label->setText("Elevon 2");
|
||||
m_aircraft->fwElevator1ChannelBox->setEnabled(false);
|
||||
m_aircraft->fwElevator1Label->setEnabled(false);
|
||||
m_aircraft->fwElevator2ChannelBox->setEnabled(false);
|
||||
m_aircraft->fwElevator2Label->setEnabled(false);
|
||||
m_aircraft->fwRudder1ChannelBox->setEnabled(true);
|
||||
m_aircraft->fwRudder1Label->setEnabled(true);
|
||||
m_aircraft->fwRudder2ChannelBox->setEnabled(true);
|
||||
m_aircraft->fwRudder2Label->setEnabled(true);
|
||||
m_aircraft->fwElevator1Label->setText("Elevator 1");
|
||||
m_aircraft->fwElevator2Label->setText("Elevator 2");
|
||||
m_aircraft->elevonMixBox->setHidden(false);
|
||||
m_aircraft->elevonLabel1->setText("Roll");
|
||||
m_aircraft->elevonLabel2->setText("Pitch");
|
||||
|
||||
} else if (frameType == "FixedWingVtail" || frameType == "Vtail") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
|
||||
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Vtail"));
|
||||
m_aircraft->fwRudder1ChannelBox->setEnabled(false);
|
||||
m_aircraft->fwRudder1Label->setEnabled(false);
|
||||
m_aircraft->fwRudder2ChannelBox->setEnabled(false);
|
||||
m_aircraft->fwRudder2Label->setEnabled(false);
|
||||
m_aircraft->fwElevator1ChannelBox->setEnabled(true);
|
||||
m_aircraft->fwElevator1Label->setEnabled(true);
|
||||
m_aircraft->fwElevator1Label->setText("Vtail 1");
|
||||
m_aircraft->fwElevator2Label->setText("Vtail 2");
|
||||
m_aircraft->elevonMixBox->setHidden(false);
|
||||
m_aircraft->fwElevator2ChannelBox->setEnabled(true);
|
||||
m_aircraft->fwElevator2Label->setEnabled(true);
|
||||
m_aircraft->fwAileron1Label->setText("Aileron 1");
|
||||
m_aircraft->fwAileron2Label->setText("Aileron 2");
|
||||
m_aircraft->elevonLabel1->setText("Rudder");
|
||||
m_aircraft->elevonLabel2->setText("Pitch");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Helper function to update the UI widget objects
|
||||
*/
|
||||
QString ConfigVehicleTypeWidget::updateFixedWingObjectsFromWidgets()
|
||||
{
|
||||
QString airframeType = "FixedWing";
|
||||
|
||||
// Save the curve (common to all Fixed wing frames)
|
||||
UAVDataObject *obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
|
||||
// Remove Feed Forward, it is pointless on a plane:
|
||||
UAVObjectField* field = obj->getField(QString("FeedForward"));
|
||||
field->setDouble(0);
|
||||
|
||||
field = obj->getField("ThrottleCurve1");
|
||||
QList<double> curve = m_aircraft->fixedWingThrottle->getCurve();
|
||||
for (int i=0;i<curve.length();i++) {
|
||||
field->setValue(curve.at(i),i);
|
||||
}
|
||||
|
||||
//All airframe types must start with "FixedWing"
|
||||
if (m_aircraft->fixedWingType->currentText() == "Elevator aileron rudder" ) {
|
||||
airframeType = "FixedWing";
|
||||
setupFrameFixedWing( airframeType );
|
||||
} else if (m_aircraft->fixedWingType->currentText() == "Elevon") {
|
||||
airframeType = "FixedWingElevon";
|
||||
setupFrameElevon( airframeType );
|
||||
} else { // "Vtail"
|
||||
airframeType = "FixedWingVtail";
|
||||
setupFrameVtail( airframeType );
|
||||
}
|
||||
|
||||
// Now reflect those settings in the "Custom" panel as well
|
||||
updateCustomAirframeUI();
|
||||
|
||||
return airframeType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Helper function to refresh the UI widget values
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::refreshFixedWingWidgetsValues(QString frameType)
|
||||
{
|
||||
|
||||
UAVDataObject* obj;
|
||||
UAVObjectField *field;
|
||||
|
||||
// Then retrieve how channels are setup
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
field = obj->getField(QString("FixedWingThrottle"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwEngineChannelBox->setCurrentIndex(m_aircraft->fwEngineChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingRoll1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwAileron1ChannelBox->setCurrentIndex(m_aircraft->fwAileron1ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingRoll2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwAileron2ChannelBox->setCurrentIndex(m_aircraft->fwAileron2ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingPitch1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwElevator1ChannelBox->setCurrentIndex(m_aircraft->fwElevator1ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingPitch2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwElevator2ChannelBox->setCurrentIndex(m_aircraft->fwElevator2ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingYaw1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwRudder1ChannelBox->setCurrentIndex(m_aircraft->fwRudder1ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingYaw2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwRudder2ChannelBox->setCurrentIndex(m_aircraft->fwRudder2ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
if (frameType == "FixedWingElevon") {
|
||||
// If the airframe is elevon, restore the slider setting
|
||||
// Find the channel number for Elevon1 (FixedWingRoll1)
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
int chMixerNumber = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
|
||||
if (chMixerNumber >= 0) { // If for some reason the actuators were incoherent, we might fail here, hence the check.
|
||||
field = obj->getField(mixerVectors.at(chMixerNumber));
|
||||
int ti = field->getElementNames().indexOf("Roll");
|
||||
m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100);
|
||||
}
|
||||
}
|
||||
if (frameType == "FixedWingVtail") {
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
int chMixerNumber = m_aircraft->fwElevator1ChannelBox->currentIndex()-1;
|
||||
if (chMixerNumber >=0) {
|
||||
field = obj->getField(mixerVectors.at(chMixerNumber));
|
||||
int ti = field->getElementNames().indexOf("Yaw");
|
||||
m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Setup Elevator/Aileron/Rudder airframe.
|
||||
|
||||
If both Aileron channels are set to 'None' (EasyStar), do Pitch/Rudder mixing
|
||||
|
||||
Returns False if impossible to create the mixer.
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupFrameFixedWing(QString airframeType)
|
||||
{
|
||||
// Check coherence:
|
||||
//Show any config errors in GUI
|
||||
throwFixedWingChannelConfigError(airframeType);
|
||||
|
||||
// - At least Pitch and either Roll or Yaw
|
||||
if (m_aircraft->fwEngineChannelBox->currentText() == "None" ||
|
||||
m_aircraft->fwElevator1ChannelBox->currentText() == "None" ||
|
||||
((m_aircraft->fwAileron1ChannelBox->currentText() == "None") &&
|
||||
(m_aircraft->fwRudder1ChannelBox->currentText() == "None"))) {
|
||||
// TODO: explain the problem in the UI
|
||||
// m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment");
|
||||
return false;
|
||||
}
|
||||
// Now setup the channels:
|
||||
resetActuators();
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Elevator
|
||||
UAVObjectField *field = obj->getField("FixedWingPitch1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwElevator1ChannelBox->currentText());
|
||||
field = obj->getField("FixedWingPitch2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwElevator2ChannelBox->currentText());
|
||||
|
||||
// Aileron
|
||||
field = obj->getField("FixedWingRoll1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
|
||||
field = obj->getField("FixedWingRoll2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
|
||||
|
||||
// Rudder
|
||||
field = obj->getField("FixedWingYaw1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwRudder1ChannelBox->currentText());
|
||||
|
||||
// Throttle
|
||||
field = obj->getField("FixedWingThrottle");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwEngineChannelBox->currentText());
|
||||
|
||||
obj->updated();
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
// Disable all
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
field->setValue("Disabled");
|
||||
}
|
||||
// and set only the relevant channels:
|
||||
// Engine
|
||||
int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Motor");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
// First of all reset the vector
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(127, ti);
|
||||
|
||||
// Rudder
|
||||
tmpVal = m_aircraft->fwRudder1ChannelBox->currentIndex()-1;
|
||||
// tmpVal will be -1 if rudder is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(127, ti);
|
||||
} // Else: we have no rudder, only ailerons, we're fine with it.
|
||||
|
||||
// Ailerons
|
||||
tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(127, ti);
|
||||
// Only set Aileron 2 if Aileron 1 is defined
|
||||
tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(127, ti);
|
||||
}
|
||||
} // Else we have no ailerons. Our consistency check guarantees we have
|
||||
// rudder in this case, so we're fine with it too.
|
||||
|
||||
// Elevator
|
||||
tmpVal = m_aircraft->fwElevator1ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(127, ti);
|
||||
// Only set Elevator 2 if it is defined
|
||||
tmpVal = m_aircraft->fwElevator2ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(127, ti);
|
||||
}
|
||||
|
||||
obj->updated();
|
||||
m_aircraft->fwStatusLabel->setText("Mixer generated");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Setup Elevon
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupFrameElevon(QString airframeType)
|
||||
{
|
||||
// Check coherence:
|
||||
//Show any config errors in GUI
|
||||
throwFixedWingChannelConfigError(airframeType);
|
||||
|
||||
// - At least Aileron1 and Aileron 2, and engine
|
||||
if (m_aircraft->fwEngineChannelBox->currentText() == "None" ||
|
||||
m_aircraft->fwAileron1ChannelBox->currentText() == "None" ||
|
||||
m_aircraft->fwAileron2ChannelBox->currentText() == "None") {
|
||||
// TODO: explain the problem in the UI
|
||||
// m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment");
|
||||
return false;
|
||||
}
|
||||
|
||||
resetActuators();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Elevons
|
||||
UAVObjectField *field = obj->getField("FixedWingRoll1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
|
||||
field = obj->getField("FixedWingRoll2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
|
||||
// Rudder 1 (can be None)
|
||||
field = obj->getField("FixedWingYaw1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwRudder1ChannelBox->currentText());
|
||||
// Rudder 2 (can be None)
|
||||
field = obj->getField("FixedWingYaw2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwRudder2ChannelBox->currentText());
|
||||
// Throttle
|
||||
field = obj->getField("FixedWingThrottle");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwEngineChannelBox->currentText());
|
||||
|
||||
obj->updated();
|
||||
|
||||
// Save the curve:
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
// Disable all
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
field->setValue("Disabled");
|
||||
}
|
||||
// and set only the relevant channels:
|
||||
// Engine
|
||||
int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Motor");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
// First of all reset the vector
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(127, ti);
|
||||
|
||||
// Rudder 1
|
||||
tmpVal = m_aircraft->fwRudder1ChannelBox->currentIndex()-1;
|
||||
// tmpVal will be -1 if rudder 1 is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(127, ti);
|
||||
} // Else: we have no rudder, only elevons, we're fine with it.
|
||||
|
||||
// Rudder 2
|
||||
tmpVal = m_aircraft->fwRudder2ChannelBox->currentIndex()-1;
|
||||
// tmpVal will be -1 if rudder 2 is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(-127, ti);
|
||||
} // Else: we have no rudder, only elevons, we're fine with it.
|
||||
|
||||
tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti);
|
||||
}
|
||||
|
||||
tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti);
|
||||
}
|
||||
|
||||
obj->updated();
|
||||
m_aircraft->fwStatusLabel->setText("Mixer generated");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Setup VTail
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupFrameVtail(QString airframeType)
|
||||
{
|
||||
// Check coherence:
|
||||
//Show any config errors in GUI
|
||||
throwFixedWingChannelConfigError(airframeType);
|
||||
|
||||
// - At least Pitch1 and Pitch2, and engine
|
||||
if (m_aircraft->fwEngineChannelBox->currentText() == "None" ||
|
||||
m_aircraft->fwElevator1ChannelBox->currentText() == "None" ||
|
||||
m_aircraft->fwElevator2ChannelBox->currentText() == "None") {
|
||||
// TODO: explain the problem in the UI
|
||||
// m_aircraft->fwStatusLabel->setText("WARNING: check channel assignment");
|
||||
return false;
|
||||
}
|
||||
|
||||
resetActuators();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Elevons
|
||||
UAVObjectField *field = obj->getField("FixedWingPitch1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwElevator1ChannelBox->currentText());
|
||||
field = obj->getField("FixedWingPitch2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwElevator2ChannelBox->currentText());
|
||||
field = obj->getField("FixedWingRoll1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
|
||||
field = obj->getField("FixedWingRoll2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
|
||||
|
||||
// Throttle
|
||||
field = obj->getField("FixedWingThrottle");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwEngineChannelBox->currentText());
|
||||
|
||||
obj->updated();
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
// Disable all
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
field->setValue("Disabled");
|
||||
}
|
||||
// and set only the relevant channels:
|
||||
// Engine
|
||||
int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Motor");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
// First of all reset the vector
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(127, ti);
|
||||
|
||||
tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(127,ti);
|
||||
}
|
||||
|
||||
tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(-127,ti);
|
||||
}
|
||||
|
||||
// Now compute the VTail
|
||||
tmpVal = m_aircraft->fwElevator1ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti);
|
||||
|
||||
tmpVal = m_aircraft->fwElevator2ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti);
|
||||
|
||||
obj->updated();
|
||||
m_aircraft->fwStatusLabel->setText("Mixer generated");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
This function displays text and color formatting in order to help the user understand what channels have not yet been configured.
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::throwFixedWingChannelConfigError(QString airframeType)
|
||||
{
|
||||
//Initialize configuration error flag
|
||||
bool error=false;
|
||||
|
||||
//Create a red block. All combo boxes are the same size, so any one should do as a model
|
||||
int size = m_aircraft->fwEngineChannelBox->style()->pixelMetric(QStyle::PM_SmallIconSize);
|
||||
QPixmap pixmap(size,size);
|
||||
pixmap.fill(QColor("red"));
|
||||
|
||||
if (airframeType == "FixedWing" ) {
|
||||
if (m_aircraft->fwEngineChannelBox->currentText() == "None"){
|
||||
m_aircraft->fwEngineChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
error=true;
|
||||
}
|
||||
else{
|
||||
m_aircraft->fwEngineChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
}
|
||||
|
||||
if (m_aircraft->fwElevator1ChannelBox->currentText() == "None"){
|
||||
m_aircraft->fwElevator1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
error=true;
|
||||
}
|
||||
else{
|
||||
m_aircraft->fwElevator1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
}
|
||||
|
||||
if ((m_aircraft->fwAileron1ChannelBox->currentText() == "None") && (m_aircraft->fwRudder1ChannelBox->currentText() == "None")) {
|
||||
pixmap.fill(QColor("green"));
|
||||
m_aircraft->fwAileron1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
m_aircraft->fwRudder1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
error=true;
|
||||
}
|
||||
else{
|
||||
m_aircraft->fwAileron1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
m_aircraft->fwRudder1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
}
|
||||
} else if (airframeType == "FixedWingElevon"){
|
||||
if (m_aircraft->fwEngineChannelBox->currentText() == "None"){
|
||||
m_aircraft->fwEngineChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
error=true;
|
||||
}
|
||||
else{
|
||||
m_aircraft->fwEngineChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
}
|
||||
|
||||
if(m_aircraft->fwAileron1ChannelBox->currentText() == "None"){
|
||||
m_aircraft->fwAileron1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
error=true;
|
||||
}
|
||||
else{
|
||||
m_aircraft->fwAileron1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
}
|
||||
|
||||
if (m_aircraft->fwAileron2ChannelBox->currentText() == "None"){
|
||||
m_aircraft->fwAileron2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
error=true;
|
||||
}
|
||||
else{
|
||||
m_aircraft->fwAileron2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
}
|
||||
|
||||
} else if ( airframeType == "FixedWingVtail"){
|
||||
if (m_aircraft->fwEngineChannelBox->currentText() == "None"){
|
||||
m_aircraft->fwEngineChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
error=true;
|
||||
}
|
||||
else{
|
||||
m_aircraft->fwEngineChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
}
|
||||
|
||||
if(m_aircraft->fwElevator1ChannelBox->currentText() == "None"){
|
||||
m_aircraft->fwElevator1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
error=true;
|
||||
}
|
||||
else{
|
||||
m_aircraft->fwElevator1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
}
|
||||
|
||||
if(m_aircraft->fwElevator2ChannelBox->currentText() == "None"){
|
||||
m_aircraft->fwElevator2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
error=true;
|
||||
}
|
||||
else{
|
||||
m_aircraft->fwElevator2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (error){
|
||||
m_aircraft->fwStatusLabel->setText(QString("<font color='red'>ERROR: Assign all necessary channels</font>"));
|
||||
}
|
||||
}
|
@ -0,0 +1,751 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file configgroundvehiclemwidget.cpp
|
||||
* @author K. Sebesta & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup ConfigPlugin Config Plugin
|
||||
* @{
|
||||
* @brief ccpm configuration panel
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
//#include "configgroundvehiclewidget.h"
|
||||
#include "configvehicletypewidget.h"
|
||||
#include "mixersettings.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStringList>
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtGui/QTextEdit>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
#include <QtGui/QPushButton>
|
||||
#include <QBrush>
|
||||
#include <math.h>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "mixersettings.h"
|
||||
#include "systemsettings.h"
|
||||
#include "actuatorcommand.h"
|
||||
|
||||
|
||||
/**
|
||||
Helper function to setup the UI
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::setupGroundVehicleUI(QString frameType)
|
||||
{
|
||||
m_aircraft->differentialSteeringMixBox->setHidden(true);
|
||||
//STILL NEEDS WORK
|
||||
// Setup the UI
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Ground"));
|
||||
|
||||
m_aircraft->gvEngineChannelBox->setEnabled(false);
|
||||
m_aircraft->gvEngineLabel->setEnabled(false);
|
||||
|
||||
|
||||
m_aircraft->gvAileron1ChannelBox->setEnabled(false);
|
||||
m_aircraft->gvAileron1Label->setEnabled(false);
|
||||
|
||||
m_aircraft->gvAileron2ChannelBox->setEnabled(false);
|
||||
m_aircraft->gvAileron2Label->setEnabled(false);
|
||||
|
||||
if (frameType == "GroundVehicleDifferential" || frameType == "Differential (tank)"){ //Tank
|
||||
m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Differential (tank)"));
|
||||
m_aircraft->gvMotor1ChannelBox->setEnabled(true);
|
||||
m_aircraft->gvMotor1Label->setEnabled(true);
|
||||
|
||||
m_aircraft->gvMotor2ChannelBox->setEnabled(true);
|
||||
m_aircraft->gvMotor2Label->setEnabled(true);
|
||||
|
||||
m_aircraft->gvMotor1Label->setText("Left motor");
|
||||
m_aircraft->gvMotor2Label->setText("Right motor");
|
||||
|
||||
m_aircraft->gvSteering1ChannelBox->setEnabled(false);
|
||||
m_aircraft->gvSteering1Label->setEnabled(false);
|
||||
|
||||
m_aircraft->gvSteering2ChannelBox->setEnabled(false);
|
||||
m_aircraft->gvSteering2Label->setEnabled(false);
|
||||
|
||||
m_aircraft->gvSteering2Label->setText("Rear steering");
|
||||
|
||||
m_aircraft->differentialSteeringMixBox->setHidden(false);
|
||||
|
||||
m_aircraft->gvThrottleCurve1GroupBox->setTitle("Left throttle curve");
|
||||
m_aircraft->gvThrottleCurve2GroupBox->setTitle("Right throttle curve");
|
||||
|
||||
}
|
||||
else if (frameType == "GroundVehicleMotorcycle" || frameType == "Motorcycle"){ //Motorcycle
|
||||
m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Motorcycle"));
|
||||
m_aircraft->gvMotor1ChannelBox->setEnabled(false);
|
||||
m_aircraft->gvMotor1Label->setEnabled(false);
|
||||
|
||||
m_aircraft->gvMotor2ChannelBox->setEnabled(true);
|
||||
m_aircraft->gvMotor2Label->setEnabled(true);
|
||||
|
||||
m_aircraft->gvMotor1Label->setText("Front motor");
|
||||
m_aircraft->gvMotor2Label->setText("Rear motor");
|
||||
|
||||
m_aircraft->gvSteering1ChannelBox->setEnabled(true);
|
||||
m_aircraft->gvSteering1Label->setEnabled(true);
|
||||
|
||||
m_aircraft->gvSteering2ChannelBox->setEnabled(true);
|
||||
m_aircraft->gvSteering2Label->setEnabled(true);
|
||||
|
||||
m_aircraft->gvSteering2Label->setText("Balancing");
|
||||
|
||||
m_aircraft->differentialSteeringMixBox->setHidden(true);
|
||||
|
||||
m_aircraft->gvThrottleCurve1GroupBox->setTitle("Front throttle curve");
|
||||
m_aircraft->gvThrottleCurve2GroupBox->setTitle("Rear throttle curve");
|
||||
}
|
||||
else {//Car
|
||||
m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Turnable (car)"));
|
||||
|
||||
m_aircraft->gvMotor1ChannelBox->setEnabled(true);
|
||||
m_aircraft->gvMotor1Label->setEnabled(true);
|
||||
|
||||
m_aircraft->gvMotor2ChannelBox->setEnabled(true);
|
||||
m_aircraft->gvMotor2Label->setEnabled(true);
|
||||
|
||||
m_aircraft->gvMotor1Label->setText("Front motor");
|
||||
m_aircraft->gvMotor2Label->setText("Rear motor");
|
||||
|
||||
m_aircraft->gvSteering1ChannelBox->setEnabled(true);
|
||||
m_aircraft->gvSteering1Label->setEnabled(true);
|
||||
|
||||
m_aircraft->gvSteering2ChannelBox->setEnabled(true);
|
||||
m_aircraft->gvSteering2Label->setEnabled(true);
|
||||
|
||||
m_aircraft->differentialSteeringMixBox->setHidden(true);
|
||||
|
||||
m_aircraft->gvThrottleCurve1GroupBox->setTitle("Front throttle curve");
|
||||
m_aircraft->gvThrottleCurve2GroupBox->setTitle("Rear throttle curve");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Helper function to update the UI widget objects
|
||||
*/
|
||||
QString ConfigVehicleTypeWidget::updateGroundVehicleObjectsFromWidgets()
|
||||
{
|
||||
QString airframeType = "GroundVehicleCar";
|
||||
|
||||
// Save the curve (common to all ground vehicle frames)
|
||||
UAVDataObject *obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
|
||||
// Remove Feed Forward, it is pointless on a ground vehicle:
|
||||
UAVObjectField* field = obj->getField(QString("FeedForward"));
|
||||
field->setDouble(0);
|
||||
|
||||
field = obj->getField("ThrottleCurve1");
|
||||
QList<double> curve = m_aircraft->groundVehicleThrottle1->getCurve();
|
||||
for (int i=0;i<curve.length();i++) {
|
||||
field->setValue(curve.at(i),i);
|
||||
}
|
||||
|
||||
field = obj->getField("ThrottleCurve2");
|
||||
curve = m_aircraft->groundVehicleThrottle2->getCurve();
|
||||
for (int i=0;i<curve.length();i++) {
|
||||
field->setValue(curve.at(i),i);
|
||||
}
|
||||
|
||||
//All airframe types must start with "GroundVehicle"
|
||||
if (m_aircraft->groundVehicleType->currentText() == "Turnable (car)" ) {
|
||||
airframeType = "GroundVehicleCar";
|
||||
setupGroundVehicleCar(airframeType);
|
||||
} else if (m_aircraft->groundVehicleType->currentText() == "Differential (tank)") {
|
||||
airframeType = "GroundVehicleDifferential";
|
||||
setupGroundVehicleDifferential(airframeType);
|
||||
} else { // "Motorcycle"
|
||||
airframeType = "GroundVehicleMotorcycle";
|
||||
setupGroundVehicleMotorcycle(airframeType);
|
||||
}
|
||||
|
||||
// Now reflect those settings in the "Custom" panel as well
|
||||
updateCustomAirframeUI();
|
||||
|
||||
return airframeType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Helper function to refresh the UI widget values
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::refreshGroundVehicleWidgetsValues(QString frameType)
|
||||
{
|
||||
|
||||
UAVDataObject* obj;
|
||||
UAVObjectField *field;
|
||||
|
||||
//THIS SECTION STILL NEEDS WORK. FOR THE MOMENT, USE THE FIXED-WING ONBOARD SETTING IN ORDER TO MINIMIZE CHANCES OF BOLLOXING REAL CODE
|
||||
// Retrieve channel setup values
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
field = obj->getField(QString("FixedWingThrottle"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->gvEngineChannelBox->setCurrentIndex(m_aircraft->gvEngineChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingRoll1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->gvAileron1ChannelBox->setCurrentIndex(m_aircraft->gvAileron1ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingRoll2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->gvAileron2ChannelBox->setCurrentIndex(m_aircraft->gvAileron2ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("GroundVehicleThrottle1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->gvMotor1ChannelBox->setCurrentIndex(m_aircraft->gvMotor1ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("GroundVehicleThrottle2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->gvMotor2ChannelBox->setCurrentIndex(m_aircraft->gvMotor2ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("GroundVehicleSteering1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->gvSteering1ChannelBox->setCurrentIndex(m_aircraft->gvSteering1ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("GroundVehicleSteering2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->gvSteering2ChannelBox->setCurrentIndex(m_aircraft->gvSteering2ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
if (frameType == "GroundVehicleDifferential") {
|
||||
//CURRENTLY BROKEN UNTIL WE DECIDE HOW DIFFERENTIAL SHOULD BEHAVE
|
||||
// If the vehicle type is "differential", restore the slider setting
|
||||
|
||||
// Find the channel number for Motor1
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
int chMixerNumber = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
|
||||
if (chMixerNumber >= 0) { // If for some reason the actuators were incoherent, we might fail here, hence the check.
|
||||
field = obj->getField(mixerVectors.at(chMixerNumber));
|
||||
int ti = field->getElementNames().indexOf("Roll");
|
||||
m_aircraft->differentialSteeringSlider1->setValue(field->getDouble(ti)*100);
|
||||
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
m_aircraft->differentialSteeringSlider2->setValue(field->getDouble(ti)*100);
|
||||
}
|
||||
}
|
||||
if (frameType == "GroundVehicleMotorcycle") {
|
||||
//CURRENTLY BROKEN UNTIL WE DECIDE HOW MOTORCYCLE SHOULD BEHAVE
|
||||
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
// Q_ASSERT(obj);
|
||||
// int chMixerNumber = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
|
||||
// if (chMixerNumber >=0) {
|
||||
// field = obj->getField(mixerVectors.at(chMixerNumber));
|
||||
// int ti = field->getElementNames().indexOf("Yaw");
|
||||
// m_aircraft->differentialSteeringSlider1->setValue(field->getDouble(ti)*100);
|
||||
//
|
||||
// ti = field->getElementNames().indexOf("Pitch");
|
||||
// m_aircraft->differentialSteeringSlider2->setValue(field->getDouble(ti)*100);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Setup balancing ground vehicle.
|
||||
|
||||
Returns False if impossible to create the mixer.
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupGroundVehicleMotorcycle(QString airframeType){
|
||||
// Check coherence:
|
||||
//Show any config errors in GUI
|
||||
throwGroundVehicleChannelConfigError(airframeType);
|
||||
|
||||
// - Motor, steering, and balance
|
||||
if (m_aircraft->gvMotor1ChannelBox->currentText() == "None" ||
|
||||
(m_aircraft->gvSteering1ChannelBox->currentText() == "None" ||
|
||||
m_aircraft->gvSteering2ChannelBox->currentText() == "None") )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Now setup the channels:
|
||||
resetActuators();
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Left motor
|
||||
UAVObjectField *field = obj->getField("GroundVehicleThrottle1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvMotor1ChannelBox->currentText());
|
||||
|
||||
// Right motor
|
||||
field = obj->getField("GroundVehicleThrottle2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvMotor2ChannelBox->currentText());
|
||||
|
||||
obj->updated();
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
|
||||
int tmpVal, ti;
|
||||
|
||||
// Disable all output channels
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
|
||||
//Disable output channel
|
||||
field->setValue("Disabled");
|
||||
|
||||
}
|
||||
|
||||
// Set all mixer values to zero
|
||||
foreach(QString mixer, mixerVectors) {
|
||||
field = obj->getField(mixer);
|
||||
resetField(field);
|
||||
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(0, ti);
|
||||
}
|
||||
|
||||
// Motor
|
||||
// Setup motor
|
||||
tmpVal = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo"); //Set motor mixer type to Servo
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve1"); //Set motor to full forward
|
||||
field->setValue(127, ti);
|
||||
|
||||
//Steering
|
||||
// Setup steering
|
||||
tmpVal = m_aircraft->gvSteering1ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo"); //Set motor mixer type to Servo
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw"); //Set steering response to roll
|
||||
field->setValue(-127, ti);
|
||||
ti = field->getElementNames().indexOf("Roll"); //Set steering response to roll
|
||||
field->setValue(-127, ti);
|
||||
|
||||
//Balancing
|
||||
// Setup balancing servo
|
||||
tmpVal = m_aircraft->gvSteering2ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo"); //Set motor mixer type to Servo
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw"); //Set balance response to yaw
|
||||
field->setValue(127, ti);
|
||||
ti = field->getElementNames().indexOf("Roll"); //Set balance response to roll
|
||||
field->setValue(127, ti);
|
||||
|
||||
obj->updated();
|
||||
|
||||
//Output success message
|
||||
m_aircraft->gvStatusLabel->setText("Mixer generated");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Setup differentially steered ground vehicle.
|
||||
|
||||
Returns False if impossible to create the mixer.
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupGroundVehicleDifferential(QString airframeType){
|
||||
// Check coherence:
|
||||
//Show any config errors in GUI
|
||||
throwGroundVehicleChannelConfigError(airframeType);
|
||||
|
||||
// - Left and right steering
|
||||
if ( m_aircraft->gvMotor2ChannelBox->currentText() == "None" ||
|
||||
m_aircraft->gvSteering1ChannelBox->currentText() == "None")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Now setup the channels:
|
||||
resetActuators();
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Left motor
|
||||
UAVObjectField *field = obj->getField("GroundVehicleThrottle1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvMotor1ChannelBox->currentText());
|
||||
|
||||
// Right motor
|
||||
field = obj->getField("GroundVehicleThrottle2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvMotor2ChannelBox->currentText());
|
||||
|
||||
obj->updated();
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
|
||||
int tmpVal, ti;
|
||||
|
||||
// Disable all output channels
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
|
||||
//Disable output channel
|
||||
field->setValue("Disabled");
|
||||
|
||||
}
|
||||
|
||||
// Set all mixer values to zero
|
||||
foreach(QString mixer, mixerVectors) {
|
||||
field = obj->getField(mixer);
|
||||
resetField(field);
|
||||
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(0, ti);
|
||||
}
|
||||
|
||||
// Motor
|
||||
// Setup left motor
|
||||
tmpVal = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo"); //Set motor mixer type to Servo
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve1"); //Set motor to full forward
|
||||
field->setValue(127, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw"); //Set motor to turn right with increasing throttle
|
||||
field->setValue(127, ti);
|
||||
|
||||
// Setup right motor
|
||||
tmpVal = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo"); //Set motor mixer type to Servo
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2"); //Set motor to full forward
|
||||
field->setValue(127, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw"); //Set motor to turn left with increasing throttle
|
||||
field->setValue(-127, ti);
|
||||
|
||||
obj->updated();
|
||||
|
||||
//Output success message
|
||||
m_aircraft->gvStatusLabel->setText("Mixer generated");
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Setup steerable ground vehicle.
|
||||
|
||||
Returns False if impossible to create the mixer.
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupGroundVehicleCar(QString airframeType)
|
||||
{
|
||||
// Check coherence:
|
||||
//Show any config errors in GUI
|
||||
throwGroundVehicleChannelConfigError(airframeType);
|
||||
|
||||
// - At least one motor and one steering servo
|
||||
if ((m_aircraft->gvMotor1ChannelBox->currentText() == "None" &&
|
||||
m_aircraft->gvMotor2ChannelBox->currentText() == "None") ||
|
||||
(m_aircraft->gvSteering1ChannelBox->currentText() == "None" &&
|
||||
m_aircraft->gvSteering2ChannelBox->currentText() == "None"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// else{
|
||||
// // m_aircraft->gvStatusLabel->setText("Mixer generated");
|
||||
// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvSteering1Label->text()); // HtmlText is any QString with html tags.
|
||||
// m_aircraft->gvSteering1Label->setText(htmlText->toPlainText());
|
||||
// delete htmlText;
|
||||
//
|
||||
// htmlText=new QTextEdit(m_aircraft->gvSteering2Label->text()); // HtmlText is any QString with html tags.
|
||||
// m_aircraft->gvSteering2Label->setText(htmlText->toPlainText());
|
||||
// delete htmlText;
|
||||
//
|
||||
// htmlText=new QTextEdit(m_aircraft->gvMotor1Label->text()); // HtmlText is any QString with html tags.
|
||||
// m_aircraft->gvMotor1Label->setText(htmlText->toPlainText());
|
||||
// delete htmlText;
|
||||
//
|
||||
// htmlText=new QTextEdit(m_aircraft->gvMotor2Label->text()); // HtmlText is any QString with html tags.
|
||||
// m_aircraft->gvMotor2Label->setText(htmlText->toPlainText());
|
||||
// }
|
||||
|
||||
// Now setup the channels:
|
||||
resetActuators();
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Front motor
|
||||
UAVObjectField *field = obj->getField("GroundVehicleThrottle1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvMotor1ChannelBox->currentText());
|
||||
|
||||
// Rear motor
|
||||
field = obj->getField("GroundVehicleThrottle2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvMotor2ChannelBox->currentText());
|
||||
|
||||
// // Aileron
|
||||
// field = obj->getField("FixedWingRoll1");
|
||||
// Q_ASSERT(field);
|
||||
// field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
|
||||
//
|
||||
// field = obj->getField("FixedWingRoll2");
|
||||
// Q_ASSERT(field);
|
||||
// field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
|
||||
|
||||
// Front steering
|
||||
field = obj->getField("GroundVehicleSteering1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvSteering1ChannelBox->currentText());
|
||||
|
||||
// Rear steering
|
||||
field = obj->getField("GroundVehicleSteering2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvSteering2ChannelBox->currentText());
|
||||
|
||||
obj->updated();
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
|
||||
int tmpVal, ti;
|
||||
|
||||
// Disable all output channels
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
|
||||
//Disable output channel
|
||||
field->setValue("Disabled");
|
||||
|
||||
}
|
||||
|
||||
// Set all mixer values to zero
|
||||
foreach(QString mixer, mixerVectors) {
|
||||
field = obj->getField(mixer);
|
||||
resetField(field);
|
||||
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(0, ti);
|
||||
}
|
||||
|
||||
// Steering
|
||||
// Only set front steering if it is defined
|
||||
tmpVal = m_aircraft->gvSteering1ChannelBox->currentIndex()-1;
|
||||
// tmpVal will be -1 if steering is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(127, ti);
|
||||
} // Else: we have no front steering. We're fine with it as long as we have rear steering
|
||||
|
||||
// Only set rear steering if it is defined
|
||||
tmpVal = m_aircraft->gvSteering2ChannelBox->currentIndex()-1;
|
||||
// tmpVal will be -1 if steering is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(-127, ti);
|
||||
} // Else: we have no rear steering. We're fine with it as long as we have front steering
|
||||
|
||||
// Motor
|
||||
// Only set front motor if it is defined
|
||||
tmpVal = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(127, ti);
|
||||
}
|
||||
|
||||
// Only set rear motor if it is defined
|
||||
tmpVal = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2");
|
||||
field->setValue(127, ti);
|
||||
}
|
||||
|
||||
obj->updated();
|
||||
|
||||
//Output success message
|
||||
m_aircraft->gvStatusLabel->setText("Mixer generated");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
This function displays text and color formatting in order to help the user understand what channels have not yet been configured.
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::throwGroundVehicleChannelConfigError(QString airframeType)
|
||||
{
|
||||
//Initialize configuration error flag
|
||||
bool error=false;
|
||||
|
||||
|
||||
//Create a red block. All combo boxes are the same size, so any one should do as a model
|
||||
int size = m_aircraft->gvEngineChannelBox->style()->pixelMetric(QStyle::PM_SmallIconSize);
|
||||
QPixmap pixmap(size,size);
|
||||
pixmap.fill(QColor("red"));
|
||||
|
||||
if (airframeType == "GroundVehicleCar" ) { //Car
|
||||
if(m_aircraft->gvMotor1ChannelBox->currentText() == "None" && m_aircraft->gvMotor2ChannelBox->currentText() == "None"){
|
||||
pixmap.fill(QColor("green"));
|
||||
m_aircraft->gvMotor1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
m_aircraft->gvMotor2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
// m_aircraft->gvMotor1Label->setText("<font color='red'>" + m_aircraft->gvMotor1Label->text() + "</font>");
|
||||
// m_aircraft->gvMotor2Label->setText("<font color='red'>" + m_aircraft->gvMotor2Label->text() + "</font>");
|
||||
error=true;
|
||||
|
||||
}
|
||||
else{
|
||||
m_aircraft->gvMotor1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
m_aircraft->gvMotor2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvMotor1Label->text()); // HtmlText is any QString with html tags.
|
||||
// m_aircraft->gvMotor1Label->setText(htmlText->toPlainText());
|
||||
// delete htmlText;
|
||||
//
|
||||
// htmlText=new QTextEdit(m_aircraft->gvMotor2Label->text()); // HtmlText is any QString with html tags.
|
||||
// m_aircraft->gvMotor2Label->setText(htmlText->toPlainText());
|
||||
}
|
||||
|
||||
if (m_aircraft->gvSteering1ChannelBox->currentText() == "None" && m_aircraft->gvSteering2ChannelBox->currentText() == "None") {
|
||||
m_aircraft->gvSteering1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
m_aircraft->gvSteering2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
// m_aircraft->gvStatusLabel->setText("<font color='red'>ERROR: check steering channel assignment</font>");
|
||||
// m_aircraft->gvSteering1Label->setText("<font color='red'>" + m_aircraft->gvSteering1Label->text() + "</font>");
|
||||
// m_aircraft->gvSteering2Label->setText("<font color='red'>" + m_aircraft->gvSteering2Label->text() + "</font>");
|
||||
error=true;
|
||||
}
|
||||
else{
|
||||
m_aircraft->gvSteering1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
m_aircraft->gvSteering2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvSteering1Label->text()); // HtmlText is any QString with html tags.
|
||||
// m_aircraft->gvSteering1Label->setText(htmlText->toPlainText());
|
||||
// delete htmlText;
|
||||
//
|
||||
// htmlText=new QTextEdit(m_aircraft->gvSteering2Label->text()); // HtmlText is any QString with html tags.
|
||||
// m_aircraft->gvSteering2Label->setText(htmlText->toPlainText());
|
||||
}
|
||||
|
||||
} else if (airframeType == "GroundVehicleDifferential"){ //Tank
|
||||
if(m_aircraft->gvMotor1ChannelBox->currentText() == "None" || m_aircraft->gvMotor2ChannelBox->currentText() == "None"){
|
||||
m_aircraft->gvMotor1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
m_aircraft->gvMotor2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
error=true;
|
||||
}
|
||||
else{
|
||||
m_aircraft->gvMotor1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
m_aircraft->gvMotor2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
}
|
||||
|
||||
//Always reset
|
||||
m_aircraft->gvSteering1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
m_aircraft->gvSteering2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
} else if ( airframeType == "GroundVehicleMotorcycle"){ //Motorcycle
|
||||
if(m_aircraft->gvMotor1ChannelBox->currentText() == "None" && m_aircraft->gvMotor2ChannelBox->currentText() == "None"){
|
||||
m_aircraft->gvMotor2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
error=true;
|
||||
}
|
||||
else{
|
||||
m_aircraft->gvMotor2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
}
|
||||
|
||||
if (m_aircraft->gvSteering1ChannelBox->currentText() == "None" && m_aircraft->gvSteering2ChannelBox->currentText() == "None") {
|
||||
m_aircraft->gvSteering1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
error=true;
|
||||
}
|
||||
else{
|
||||
m_aircraft->gvSteering1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
}
|
||||
|
||||
//Always reset
|
||||
m_aircraft->gvMotor1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
m_aircraft->gvSteering2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
}
|
||||
|
||||
if (error){
|
||||
m_aircraft->gvStatusLabel->setText(QString("<font color='red'>ERROR: Assign all necessary channels</font>"));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,1146 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file configmultirotorwidget.cpp
|
||||
* @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup ConfigPlugin Config Plugin
|
||||
* @{
|
||||
* @brief ccpm configuration panel
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
//#include "configmultirotorwidget.h"
|
||||
#include "configvehicletypewidget.h"
|
||||
#include "mixersettings.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStringList>
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtGui/QTextEdit>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
#include <QtGui/QPushButton>
|
||||
#include <QBrush>
|
||||
#include <math.h>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "mixersettings.h"
|
||||
#include "systemsettings.h"
|
||||
#include "actuatorcommand.h"
|
||||
|
||||
//#define Pi 3.14159265358979323846
|
||||
|
||||
|
||||
/**
|
||||
Helper function to setup the UI
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::setupMultiRotorUI(QString frameType)
|
||||
{
|
||||
if (frameType == "Tri" || frameType == "Tricopter Y") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Tricopter Y"));
|
||||
quad->setElementId("tri");
|
||||
|
||||
//Enable all necessary motor channel boxes...
|
||||
for (int i=1; i <=3; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
}
|
||||
//and grey out all unused motor channel boxes
|
||||
for (int i=4; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(false);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(true);
|
||||
} else if (frameType == "QuadX" || frameType == "Quad X") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad X"));
|
||||
quad->setElementId("quad-X");
|
||||
|
||||
//Enable all necessary motor channel boxes...
|
||||
for (int i=1; i <=4; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
}
|
||||
//and grey out all unused motor channel boxes
|
||||
for (int i=5; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(false);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(50);
|
||||
m_aircraft->mrPitchMixLevel->setValue(50);
|
||||
m_aircraft->mrYawMixLevel->setValue(50);
|
||||
} else if (frameType == "QuadP" || frameType == "Quad +") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad +"));
|
||||
quad->setElementId("quad-plus");
|
||||
|
||||
//Enable all necessary motor channel boxes...
|
||||
for (int i=1; i <=4; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
}
|
||||
//and grey out all unused motor channel boxes
|
||||
for (int i=5; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(false);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(100);
|
||||
m_aircraft->mrPitchMixLevel->setValue(100);
|
||||
m_aircraft->mrYawMixLevel->setValue(50);
|
||||
} else if (frameType == "Hexa" || frameType == "Hexacopter") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter"));
|
||||
quad->setElementId("quad-hexa");
|
||||
|
||||
//Enable all necessary motor channel boxes...
|
||||
for (int i=1; i <=6; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
}
|
||||
//and grey out all unused motor channel boxes
|
||||
for (int i=7; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(false);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(50);
|
||||
m_aircraft->mrPitchMixLevel->setValue(33);
|
||||
m_aircraft->mrYawMixLevel->setValue(33);
|
||||
} else if (frameType == "HexaX" || frameType == "Hexacopter X" ) {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter X"));
|
||||
quad->setElementId("quad-hexa-H");
|
||||
|
||||
//Enable all necessary motor channel boxes...
|
||||
for (int i=1; i <=6; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
}
|
||||
//and grey out all unused motor channel boxes
|
||||
for (int i=7; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(false);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(33);
|
||||
m_aircraft->mrPitchMixLevel->setValue(50);
|
||||
m_aircraft->mrYawMixLevel->setValue(33);
|
||||
|
||||
} else if (frameType == "HexaCoax" || frameType == "Hexacopter Y6") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter Y6"));
|
||||
quad->setElementId("hexa-coax");
|
||||
|
||||
//Enable all necessary motor channel boxes...
|
||||
for (int i=1; i <=6; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
}
|
||||
//and grey out all unused motor channel boxes
|
||||
for (int i=7; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(false);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(100);
|
||||
m_aircraft->mrPitchMixLevel->setValue(50);
|
||||
m_aircraft->mrYawMixLevel->setValue(66);
|
||||
|
||||
} else if (frameType == "Octo" || frameType == "Octocopter") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter"));
|
||||
quad->setElementId("quad-octo");
|
||||
|
||||
//Enable all necessary motor channel boxes
|
||||
for (int i=1; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(33);
|
||||
m_aircraft->mrPitchMixLevel->setValue(33);
|
||||
m_aircraft->mrYawMixLevel->setValue(25);
|
||||
} else if (frameType == "OctoV" || frameType == "Octocopter V") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter V"));
|
||||
quad->setElementId("quad-octo-v");
|
||||
|
||||
//Enable all necessary motor channel boxes
|
||||
for (int i=1; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(25);
|
||||
m_aircraft->mrPitchMixLevel->setValue(25);
|
||||
m_aircraft->mrYawMixLevel->setValue(25);
|
||||
|
||||
} else if (frameType == "OctoCoaxP" || frameType == "Octo Coax +") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax +"));
|
||||
quad->setElementId("octo-coax-P");
|
||||
|
||||
//Enable all necessary motor channel boxes
|
||||
for (int i=1; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(100);
|
||||
m_aircraft->mrPitchMixLevel->setValue(100);
|
||||
m_aircraft->mrYawMixLevel->setValue(50);
|
||||
|
||||
} else if (frameType == "OctoCoaxX" || frameType == "Octo Coax X") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax X"));
|
||||
quad->setElementId("octo-coax-X");
|
||||
|
||||
//Enable all necessary motor channel boxes
|
||||
for (int i=1; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(50);
|
||||
m_aircraft->mrPitchMixLevel->setValue(50);
|
||||
m_aircraft->mrYawMixLevel->setValue(50);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Helper function to update the UI widget objects
|
||||
*/
|
||||
QString ConfigVehicleTypeWidget::updateMultiRotorObjectsFromWidgets()
|
||||
{
|
||||
QString airframeType;
|
||||
QList<QString> motorList;
|
||||
|
||||
// We can already setup the feedforward here, as it is common to all platforms
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("FeedForward"));
|
||||
field->setDouble((double)m_aircraft->feedForwardSlider->value()/100);
|
||||
field = obj->getField(QString("AccelTime"));
|
||||
field->setDouble(m_aircraft->accelTime->value());
|
||||
field = obj->getField(QString("DecelTime"));
|
||||
field->setDouble(m_aircraft->decelTime->value());
|
||||
field = obj->getField(QString("MaxAccel"));
|
||||
field->setDouble(m_aircraft->maxAccelSlider->value());
|
||||
|
||||
// Curve is also common to all quads:
|
||||
field = obj->getField("ThrottleCurve1");
|
||||
QList<double> curve = m_aircraft->multiThrottleCurve->getCurve();
|
||||
for (int i=0;i<curve.length();i++) {
|
||||
field->setValue(curve.at(i),i);
|
||||
}
|
||||
|
||||
if (m_aircraft->multirotorFrameType->currentText() == "Quad +") {
|
||||
airframeType = "QuadP";
|
||||
setupQuad(true);
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Quad X") {
|
||||
airframeType = "QuadX";
|
||||
setupQuad(false);
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter") {
|
||||
airframeType = "Hexa";
|
||||
setupHexa(true);
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter X") {
|
||||
airframeType = "HexaX";
|
||||
setupHexa(false);
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter Y6") {
|
||||
airframeType = "HexaCoax";
|
||||
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(6);
|
||||
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox4->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox5->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox6->currentText() == "None" ) {
|
||||
|
||||
return airframeType;
|
||||
}
|
||||
motorList << "VTOLMotorNW" << "VTOLMotorW" << "VTOLMotorNE" << "VTOLMotorE"
|
||||
<< "VTOLMotorS" << "VTOLMotorSE";
|
||||
setupMotors(motorList);
|
||||
|
||||
// Motor 1 to 6, Y6 Layout:
|
||||
// pitch roll yaw
|
||||
double mixer [8][3] = {
|
||||
{ 0.5, 1, -1},
|
||||
{ 0.5, 1, 1},
|
||||
{ 0.5, -1, -1},
|
||||
{ 0.5, -1, 1},
|
||||
{ -1, 0, -1},
|
||||
{ -1, 0, 1},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
setupMultiRotorMixer(mixer);
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter") {
|
||||
airframeType = "Octo";
|
||||
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(8);
|
||||
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox4->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox5->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox6->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox7->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox8->currentText() == "None") {
|
||||
|
||||
return airframeType;
|
||||
}
|
||||
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
|
||||
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
|
||||
setupMotors(motorList);
|
||||
// Motor 1 to 8:
|
||||
// pitch roll yaw
|
||||
double mixer [8][3] = {
|
||||
{ 1, 0, -1},
|
||||
{ 1, -1, 1},
|
||||
{ 0, -1, -1},
|
||||
{ -1, -1, 1},
|
||||
{ -1, 0, -1},
|
||||
{ -1, 1, 1},
|
||||
{ 0, 1, -1},
|
||||
{ 1, 1, 1}
|
||||
};
|
||||
setupMultiRotorMixer(mixer);
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter V") {
|
||||
airframeType = "OctoV";
|
||||
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(8);
|
||||
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox4->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox5->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox6->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox7->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox8->currentText() == "None") {
|
||||
|
||||
return airframeType;
|
||||
}
|
||||
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
|
||||
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
|
||||
setupMotors(motorList);
|
||||
// Motor 1 to 8:
|
||||
// IMPORTANT: Assumes evenly spaced engines
|
||||
// pitch roll yaw
|
||||
double mixer [8][3] = {
|
||||
{ 0.33, -1, -1},
|
||||
{ 1 , -1, 1},
|
||||
{ -1 , -1, -1},
|
||||
{ -0.33, -1, 1},
|
||||
{ -0.33, 1, -1},
|
||||
{ -1 , 1, 1},
|
||||
{ 1 , 1, -1},
|
||||
{ 0.33, 1, 1}
|
||||
};
|
||||
setupMultiRotorMixer(mixer);
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax +") {
|
||||
airframeType = "OctoCoaxP";
|
||||
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(8);
|
||||
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox4->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox5->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox6->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox7->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox8->currentText() == "None") {
|
||||
|
||||
return airframeType;
|
||||
}
|
||||
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
|
||||
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
|
||||
setupMotors(motorList);
|
||||
// Motor 1 to 8:
|
||||
// pitch roll yaw
|
||||
double mixer [8][3] = {
|
||||
{ 1, 0, -1},
|
||||
{ 1, 0, 1},
|
||||
{ 0, -1, -1},
|
||||
{ 0, -1, 1},
|
||||
{ -1, 0, -1},
|
||||
{ -1, 0, 1},
|
||||
{ 0, 1, -1},
|
||||
{ 0, 1, 1}
|
||||
};
|
||||
setupMultiRotorMixer(mixer);
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax X") {
|
||||
airframeType = "OctoCoaxX";
|
||||
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(8);
|
||||
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox4->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox5->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox6->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox7->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox8->currentText() == "None") {
|
||||
|
||||
return airframeType;
|
||||
}
|
||||
motorList << "VTOLMotorNW" << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE"
|
||||
<< "VTOLMotorSE" << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW";
|
||||
setupMotors(motorList);
|
||||
// Motor 1 to 8:
|
||||
// pitch roll yaw
|
||||
double mixer [8][3] = {
|
||||
{ 1, 1, -1},
|
||||
{ 1, 1, 1},
|
||||
{ 1, -1, -1},
|
||||
{ 1, -1, 1},
|
||||
{ -1, -1, -1},
|
||||
{ -1, -1, 1},
|
||||
{ -1, 1, -1},
|
||||
{ -1, 1, 1}
|
||||
};
|
||||
setupMultiRotorMixer(mixer);
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Tricopter Y") {
|
||||
airframeType = "Tri";
|
||||
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(3);
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ) {
|
||||
|
||||
return airframeType;
|
||||
}
|
||||
if (m_aircraft->triYawChannelBox->currentText() == "None") {
|
||||
m_aircraft->mrStatusLabel->setText("<font color='red'>Error: Assign a Yaw channel</font>");
|
||||
return airframeType;
|
||||
}
|
||||
motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorS";
|
||||
setupMotors(motorList);
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
field = obj->getField("FixedWingYaw1");
|
||||
field->setValue(m_aircraft->triYawChannelBox->currentText());
|
||||
|
||||
// Motor 1 to 6, Y6 Layout:
|
||||
// pitch roll yaw
|
||||
double mixer [8][3] = {
|
||||
{ 0.5, 1, 0},
|
||||
{ 0.5, -1, 0},
|
||||
{ -1, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
setupMultiRotorMixer(mixer);
|
||||
|
||||
int tmpVal = m_aircraft->triYawChannelBox->currentIndex()-1;
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(127,ti);
|
||||
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
|
||||
}
|
||||
// Now reflect those settings in the "Custom" panel as well
|
||||
updateCustomAirframeUI();
|
||||
|
||||
return airframeType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Helper function to refresh the UI widget values
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::refreshMultiRotorWidgetsValues(QString frameType)
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Retrieve settings
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
UAVObjectField *field;
|
||||
|
||||
if (frameType == "QuadP") {
|
||||
// Motors 1/2/3/4 are: N / E / S / W
|
||||
field = obj->getField(QString("VTOLMotorN"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
|
||||
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
|
||||
// This assumes that all vectors are identical - if not, the user should use the
|
||||
// "custom" setting.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = field->getDouble(i)/1.27;
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = (1-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = -field->getDouble(i)/1.27;
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
} else if (frameType == "QuadX") {
|
||||
// Motors 1/2/3/4 are: NW / NE / SE / SW
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
|
||||
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
|
||||
// This assumes that all vectors are identical - if not, the user should use the
|
||||
// "custom" setting.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = field->getDouble(i)/1.27;
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = 1-field->getDouble(i)/1.27;
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = field->getDouble(i)/1.27;
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
} else if (frameType == "Hexa") {
|
||||
// Motors 1/2/3 4/5/6 are: N / NE / SE / S / SW / NW
|
||||
field = obj->getField(QString("VTOLMotorN"));
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
|
||||
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
|
||||
// This assumes that all vectors are identical - if not, the user should use the
|
||||
// "custom" setting.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
|
||||
if(tmpVal>-1)
|
||||
{
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(1-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
}
|
||||
} else if (frameType == "HexaX") {
|
||||
// Motors 1/2/3 4/5/6 are: NE / E / SE / SW / W / NW
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
|
||||
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
|
||||
// This assumes that all vectors are identical - if not, the user should use the
|
||||
// "custom" setting.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(1-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
} else if (frameType == "HexaCoax") {
|
||||
// Motors 1/2/3 4/5/6 are: NW/W NE/E S/SE
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
|
||||
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
|
||||
// This assumes that all vectors are identical - if not, the user should use the
|
||||
// "custom" setting.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(2*field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
} else if (frameType == "Octo" || frameType == "OctoV" ||
|
||||
frameType == "OctoCoaxP") {
|
||||
// Motors 1 to 8 are N / NE / E / etc
|
||||
field = obj->getField(QString("VTOLMotorN"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox7->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox8->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
|
||||
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
|
||||
// This assumes that all vectors are identical - if not, the user should use the
|
||||
// "custom" setting.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
if (frameType == "Octo") {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
} else if (frameType == "OctoV") {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Yaw");
|
||||
double val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
i = field->getElementNames().indexOf("Pitch");
|
||||
val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
|
||||
} else if (frameType == "OctoCoaxP") {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
tmpVal = m_aircraft->multiMotorChannelBox3->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
|
||||
}
|
||||
}
|
||||
} else if (frameType == "OctoCoaxX") {
|
||||
// Motors 1 to 8 are N / NE / E / etc
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorN"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox7->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox8->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
|
||||
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
|
||||
// This assumes that all vectors are identical - if not, the user should use the
|
||||
// "custom" setting.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
} else if (frameType == "Tri") {
|
||||
// Motors 1 to 8 are N / NE / E / etc
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("FixedWingYaw1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->triYawChannelBox->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(2*field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Helper function: setupQuadMotor
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::setupQuadMotor(int channel, double pitch, double roll, double yaw)
|
||||
{
|
||||
qDebug()<<QString("Setup quad motor channel=%0 pitch=%1 roll=%2 yaw=%3").arg(channel).arg(pitch).arg(roll).arg(yaw);
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
UAVObjectField *field = obj->getField(mixerTypes.at(channel));
|
||||
field->setValue("Motor");
|
||||
field = obj->getField(mixerVectors.at(channel));
|
||||
// First of all reset the vector
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(127, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(roll*127,ti);
|
||||
qDebug()<<"Set roll="<<roll*127;
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(pitch*127,ti);
|
||||
qDebug()<<"Set pitch="<<pitch*127;
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(yaw*127,ti);
|
||||
qDebug()<<"Set yaw="<<yaw*127;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Helper function: setup motors. Takes a list of channel names in input.
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::setupMotors(QList<QString> motorList)
|
||||
{
|
||||
resetActuators();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
UAVObjectField *field;
|
||||
QList<QComboBox*> mmList;
|
||||
mmList << m_aircraft->multiMotorChannelBox1 << m_aircraft->multiMotorChannelBox2 << m_aircraft->multiMotorChannelBox3
|
||||
<< m_aircraft->multiMotorChannelBox4 << m_aircraft->multiMotorChannelBox5 << m_aircraft->multiMotorChannelBox6
|
||||
<< m_aircraft->multiMotorChannelBox7 << m_aircraft->multiMotorChannelBox8;
|
||||
foreach (QString motor, motorList) {
|
||||
field = obj->getField(motor);
|
||||
field->setValue(mmList.takeFirst()->currentText());
|
||||
}
|
||||
//obj->updated(); // Save...
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Set up a Quad-X or Quad-P mixer
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupQuad(bool pLayout)
|
||||
{
|
||||
// Check coherence:
|
||||
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(4);
|
||||
|
||||
// - Four engines have to be defined
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox4->currentText() == "None") {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
QList<QString> motorList;
|
||||
if (pLayout) {
|
||||
motorList << "VTOLMotorN" << "VTOLMotorE" << "VTOLMotorS"
|
||||
<< "VTOLMotorW";
|
||||
} else {
|
||||
motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorSE"
|
||||
<< "VTOLMotorSW";
|
||||
}
|
||||
setupMotors(motorList);
|
||||
|
||||
// Now, setup the mixer:
|
||||
// Motor 1 to 4, X Layout:
|
||||
// pitch roll yaw
|
||||
// {0.5 ,0.5 ,-0.5 //Front left motor (CW)
|
||||
// {0.5 ,-0.5 ,0.5 //Front right motor(CCW)
|
||||
// {-0.5 ,-0.5 ,-0.5 //rear right motor (CW)
|
||||
// {-0.5 ,0.5 ,0.5 //Rear left motor (CCW)
|
||||
double xMixer [8][3] = {
|
||||
{ 1, 1, -1},
|
||||
{ 1, -1, 1},
|
||||
{-1, -1, -1},
|
||||
{-1, 1, 1},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
//
|
||||
// Motor 1 to 4, P Layout:
|
||||
// pitch roll yaw
|
||||
// {1 ,0 ,-0.5 //Front motor (CW)
|
||||
// {0 ,-1 ,0.5 //Right motor(CCW)
|
||||
// {-1 ,0 ,-0.5 //Rear motor (CW)
|
||||
// {0 ,1 ,0.5 //Left motor (CCW)
|
||||
double pMixer [8][3] = {
|
||||
{ 1, 0, -1},
|
||||
{ 0, -1, 1},
|
||||
{-1, 0, -1},
|
||||
{ 0, 1, 1},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
|
||||
if (pLayout) {
|
||||
setupMultiRotorMixer(pMixer);
|
||||
} else {
|
||||
setupMultiRotorMixer(xMixer);
|
||||
}
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Set up a Hexa-X or Hexa-P mixer
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupHexa(bool pLayout)
|
||||
{
|
||||
// Check coherence:
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(6);
|
||||
|
||||
// - Four engines have to be defined
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox4->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox5->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox6->currentText() == "None") {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<QString> motorList;
|
||||
if (pLayout) {
|
||||
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorSE"
|
||||
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorNW";
|
||||
} else {
|
||||
motorList << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
|
||||
<< "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
|
||||
}
|
||||
setupMotors(motorList);
|
||||
|
||||
// and set only the relevant channels:
|
||||
|
||||
// Motor 1 to 6, P Layout:
|
||||
// pitch roll yaw
|
||||
// 1 { 0.3 , 0 ,-0.3 // N CW
|
||||
// 2 { 0.3 ,-0.5 , 0.3 // NE CCW
|
||||
// 3 {-0.3 ,-0.5 ,-0.3 // SE CW
|
||||
// 4 {-0.3 , 0 , 0.3 // S CCW
|
||||
// 5 {-0.3 , 0.5 ,-0.3 // SW CW
|
||||
// 6 { 0.3 , 0.5 , 0.3 // NW CCW
|
||||
|
||||
double pMixer [8][3] = {
|
||||
{ 1, 0, -1},
|
||||
{ 1, -1, 1},
|
||||
{-1, -1, -1},
|
||||
{-1, 0, 1},
|
||||
{-1, 1, -1},
|
||||
{ 1, 1, 1},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
|
||||
//
|
||||
// Motor 1 to 6, X Layout:
|
||||
// 1 [ 0.5, -0.3, -0.3 ] NE
|
||||
// 2 [ 0 , -0.3, 0.3 ] E
|
||||
// 3 [ -0.5, -0.3, -0.3 ] SE
|
||||
// 4 [ -0.5, 0.3, 0.3 ] SW
|
||||
// 5 [ 0 , 0.3, -0.3 ] W
|
||||
// 6 [ 0.5, 0.3, 0.3 ] NW
|
||||
double xMixer [8][3] = {
|
||||
{ 1, -1, -1},
|
||||
{ 0, -1, 1},
|
||||
{ -1, -1, -1},
|
||||
{ -1, 1, 1},
|
||||
{ 0, 1, -1},
|
||||
{ 1, 1, 1},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
|
||||
if (pLayout) {
|
||||
setupMultiRotorMixer(pMixer);
|
||||
} else {
|
||||
setupMultiRotorMixer(xMixer);
|
||||
}
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This function sets up the multirotor mixer values.
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupMultiRotorMixer(double mixerFactors[8][3])
|
||||
{
|
||||
qDebug()<<"Mixer factors";
|
||||
qDebug()<<mixerFactors[0][0]<<" "<<mixerFactors[0][1]<<" "<<mixerFactors[0][2];
|
||||
qDebug()<<mixerFactors[1][0]<<" "<<mixerFactors[1][1]<<" "<<mixerFactors[1][2];
|
||||
qDebug()<<mixerFactors[2][0]<<" "<<mixerFactors[2][1]<<" "<<mixerFactors[2][2];
|
||||
qDebug()<<mixerFactors[3][0]<<" "<<mixerFactors[3][1]<<" "<<mixerFactors[3][2];
|
||||
qDebug()<<mixerFactors[4][0]<<" "<<mixerFactors[4][1]<<" "<<mixerFactors[4][2];
|
||||
qDebug()<<mixerFactors[5][0]<<" "<<mixerFactors[5][1]<<" "<<mixerFactors[5][2];
|
||||
qDebug()<<mixerFactors[6][0]<<" "<<mixerFactors[6][1]<<" "<<mixerFactors[6][2];
|
||||
qDebug()<<mixerFactors[7][0]<<" "<<mixerFactors[7][1]<<" "<<mixerFactors[7][2];
|
||||
|
||||
UAVObjectField *field;
|
||||
QList<QComboBox*> mmList;
|
||||
mmList << m_aircraft->multiMotorChannelBox1 << m_aircraft->multiMotorChannelBox2 << m_aircraft->multiMotorChannelBox3
|
||||
<< m_aircraft->multiMotorChannelBox4 << m_aircraft->multiMotorChannelBox5 << m_aircraft->multiMotorChannelBox6
|
||||
<< m_aircraft->multiMotorChannelBox7 << m_aircraft->multiMotorChannelBox8;
|
||||
UAVDataObject *obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
// Disable all
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
field->setValue("Disabled");
|
||||
}
|
||||
// and enable only the relevant channels:
|
||||
double pFactor = (double)m_aircraft->mrPitchMixLevel->value()/100;
|
||||
double rFactor = (double)m_aircraft->mrRollMixLevel->value()/100;
|
||||
double yFactor = (double)m_aircraft->mrYawMixLevel->value()/100;
|
||||
qDebug()<<QString("pFactor=%0 rFactor=%1 yFactor=%2").arg(pFactor).arg(rFactor).arg(yFactor);
|
||||
for (int i=0 ; i<8; i++) {
|
||||
if(mmList.at(i)->isEnabled())
|
||||
{
|
||||
int channel = mmList.at(i)->currentIndex()-1;
|
||||
if (channel > -1)
|
||||
setupQuadMotor(channel, mixerFactors[i][0]*pFactor,
|
||||
rFactor*mixerFactors[i][1], yFactor*mixerFactors[i][2]);
|
||||
}
|
||||
}
|
||||
// obj->updated();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This function displays text and color formatting in order to help the user understand what channels have not yet been configured.
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::throwMultiRotorChannelConfigError(int numMotors)
|
||||
{
|
||||
//Initialize configuration error flag
|
||||
bool error=false;
|
||||
|
||||
//Iterate through all instances of multiMotorChannelBox
|
||||
for (int i=0; i<numMotors; i++) {
|
||||
//Fine widgets with text "multiMotorChannelBox.x", where x is an integer
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i+1));
|
||||
if (combobox){ //if QLabel exists
|
||||
QLabel *label = qFindChild<QLabel*>(this, "MotorOutputLabel" + QString::number(i+1));
|
||||
if (combobox->currentText() == "None") {
|
||||
|
||||
// label->setText("<font color='red'>" + label->text() + "</font>");
|
||||
|
||||
int size = combobox->style()->pixelMetric(QStyle::PM_SmallIconSize);
|
||||
QPixmap pixmap(size,size);
|
||||
pixmap.fill(QColor("red"));
|
||||
combobox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
// combobox->setStyleSheet("QComboBox { color: red}");
|
||||
error=true;
|
||||
|
||||
}
|
||||
else {
|
||||
combobox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
// combobox->setStyleSheet("color: black;");
|
||||
// QTextEdit* htmlText=new QTextEdit(label->text()); // htmlText is any QString with html tags.
|
||||
// label->setText(htmlText->toPlainText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (error){
|
||||
m_aircraft->mrStatusLabel->setText(QString("<font color='red'>ERROR: Assign all %1 motor channels</font>").arg(numMotors));
|
||||
}
|
||||
}
|
@ -4,7 +4,9 @@ DEFINES += CONFIG_LIBRARY
|
||||
QT += svg
|
||||
include(config_dependencies.pri)
|
||||
INCLUDEPATH += ../../libs/eigen
|
||||
|
||||
OTHER_FILES += Config.pluginspec
|
||||
|
||||
HEADERS += configplugin.h \
|
||||
configgadgetconfiguration.h \
|
||||
configgadgetwidget.h \
|
||||
@ -14,12 +16,12 @@ HEADERS += configplugin.h \
|
||||
fancytabwidget.h \
|
||||
configinputwidget.h \
|
||||
configoutputwidget.h \
|
||||
configairframewidget.h \
|
||||
configvehicletypewidget.h \
|
||||
config_pro_hw_widget.h \
|
||||
config_cc_hw_widget.h \
|
||||
configahrswidget.h \
|
||||
configccattitudewidget.h \
|
||||
configccpmwidget.h \
|
||||
cfg_vehicletypes/configccpmwidget.h \
|
||||
configstabilizationwidget.h \
|
||||
assertions.h \
|
||||
calibration.h \
|
||||
@ -39,12 +41,11 @@ SOURCES += configplugin.cpp \
|
||||
fancytabwidget.cpp \
|
||||
configinputwidget.cpp \
|
||||
configoutputwidget.cpp \
|
||||
configairframewidget.cpp \
|
||||
configvehicletypewidget.cpp \
|
||||
config_pro_hw_widget.cpp \
|
||||
config_cc_hw_widget.cpp \
|
||||
configahrswidget.cpp \
|
||||
configccattitudewidget.cpp \
|
||||
configccpmwidget.cpp \
|
||||
configstabilizationwidget.cpp \
|
||||
twostep.cpp \
|
||||
legacy-calibration.cpp \
|
||||
@ -55,6 +56,10 @@ SOURCES += configplugin.cpp \
|
||||
inputchannelform.cpp \
|
||||
configcamerastabilizationwidget.cpp \
|
||||
configtxpidwidget.cpp \
|
||||
cfg_vehicletypes/configmultirotorwidget.cpp \
|
||||
cfg_vehicletypes/configgroundvehiclewidget.cpp \
|
||||
cfg_vehicletypes/configfixedwingwidget.cpp \
|
||||
cfg_vehicletypes/configccpmwidget.cpp \
|
||||
outputchannelform.cpp
|
||||
FORMS += airframe.ui \
|
||||
cc_hw_settings.ui \
|
||||
|
@ -1,2221 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file configairframewidget.cpp
|
||||
* @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup ConfigPlugin Config Plugin
|
||||
* @{
|
||||
* @brief Airframe configuration panel
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "configairframewidget.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtGui/QTextEdit>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
#include <QtGui/QPushButton>
|
||||
#include <math.h>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include "systemsettings.h"
|
||||
#include "mixersettings.h"
|
||||
#include "actuatorsettings.h"
|
||||
#include <QEventLoop>
|
||||
|
||||
/**
|
||||
Helper delegate for the custom mixer editor table.
|
||||
Taken straight from Qt examples, thanks!
|
||||
*/
|
||||
SpinBoxDelegate::SpinBoxDelegate(QObject *parent)
|
||||
: QItemDelegate(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem &/* option */,
|
||||
const QModelIndex &/* index */) const
|
||||
{
|
||||
QSpinBox *editor = new QSpinBox(parent);
|
||||
editor->setMinimum(-127);
|
||||
editor->setMaximum(127);
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
void SpinBoxDelegate::setEditorData(QWidget *editor,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
int value = index.model()->data(index, Qt::EditRole).toInt();
|
||||
|
||||
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
|
||||
spinBox->setValue(value);
|
||||
}
|
||||
|
||||
void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
|
||||
spinBox->interpretText();
|
||||
int value = spinBox->value();
|
||||
|
||||
model->setData(index, value, Qt::EditRole);
|
||||
}
|
||||
|
||||
void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
|
||||
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
|
||||
{
|
||||
editor->setGeometry(option.rect);
|
||||
}
|
||||
|
||||
/**********************************************************************************/
|
||||
|
||||
|
||||
|
||||
ConfigAirframeWidget::ConfigAirframeWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
{
|
||||
m_aircraft = new Ui_AircraftWidget();
|
||||
m_aircraft->setupUi(this);
|
||||
|
||||
addApplySaveButtons(m_aircraft->saveAircraftToRAM,m_aircraft->saveAircraftToSD);
|
||||
|
||||
addUAVObject("SystemSettings");
|
||||
addUAVObject("MixerSettings");
|
||||
addUAVObject("ActuatorSettings");
|
||||
|
||||
|
||||
ffTuningInProgress = false;
|
||||
ffTuningPhase = false;
|
||||
|
||||
QStringList channels;
|
||||
channels << "None";
|
||||
for (int i = 0; i < ActuatorSettings::CHANNELADDR_NUMELEM; i++) {
|
||||
mixerTypes << QString("Mixer%1Type").arg(i+1);
|
||||
mixerVectors << QString("Mixer%1Vector").arg(i+1);
|
||||
channels << QString("Channel%1").arg(i+1);
|
||||
}
|
||||
|
||||
QStringList airframeTypes;
|
||||
airframeTypes << "Fixed Wing" << "Multirotor" << "Helicopter" << "Custom";
|
||||
m_aircraft->aircraftType->addItems(airframeTypes);
|
||||
m_aircraft->aircraftType->setCurrentIndex(1);
|
||||
|
||||
QStringList fixedWingTypes;
|
||||
fixedWingTypes << "Elevator aileron rudder" << "Elevon" << "Vtail";
|
||||
m_aircraft->fixedWingType->addItems(fixedWingTypes);
|
||||
|
||||
QStringList multiRotorTypes;
|
||||
multiRotorTypes << "Quad +" << "Quad X" << "Hexacopter" << "Octocopter" << "Hexacopter X" << "Octocopter V" << "Octo Coax +"
|
||||
<< "Octo Coax X" << "Hexacopter Y6" << "Tricopter Y";
|
||||
m_aircraft->multirotorFrameType->addItems(multiRotorTypes);
|
||||
|
||||
// Now load all the channel assignements for fixed wing
|
||||
m_aircraft->fwElevator1Channel->addItems(channels);
|
||||
m_aircraft->fwElevator2Channel->addItems(channels);
|
||||
m_aircraft->fwEngineChannel->addItems(channels);
|
||||
m_aircraft->fwRudder1Channel->addItems(channels);
|
||||
m_aircraft->fwRudder2Channel->addItems(channels);
|
||||
m_aircraft->fwAileron1Channel->addItems(channels);
|
||||
m_aircraft->fwAileron2Channel->addItems(channels);
|
||||
m_aircraft->multiMotor1->addItems(channels);
|
||||
m_aircraft->multiMotor2->addItems(channels);
|
||||
m_aircraft->multiMotor3->addItems(channels);
|
||||
m_aircraft->multiMotor4->addItems(channels);
|
||||
m_aircraft->multiMotor5->addItems(channels);
|
||||
m_aircraft->multiMotor6->addItems(channels);
|
||||
m_aircraft->multiMotor7->addItems(channels);
|
||||
m_aircraft->multiMotor8->addItems(channels);
|
||||
m_aircraft->triYawChannel->addItems(channels);
|
||||
|
||||
// Setup the Multirotor picture in the Quad settings interface
|
||||
m_aircraft->quadShape->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_aircraft->quadShape->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
QSvgRenderer *renderer = new QSvgRenderer();
|
||||
renderer->load(QString(":/configgadget/images/quad-shapes.svg"));
|
||||
quad = new QGraphicsSvgItem();
|
||||
quad->setSharedRenderer(renderer);
|
||||
quad->setElementId("quad-plus");
|
||||
QGraphicsScene *scene = new QGraphicsScene(this);
|
||||
scene->addItem(quad);
|
||||
scene->setSceneRect(quad->boundingRect());
|
||||
m_aircraft->quadShape->setScene(scene);
|
||||
|
||||
// Put combo boxes in line one of the custom mixer table:
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("Mixer1Type"));
|
||||
QStringList list = field->getOptions();
|
||||
for (int i=0;i<8;i++) {
|
||||
QComboBox* qb = new QComboBox(m_aircraft->customMixerTable);
|
||||
qb->addItems(list);
|
||||
m_aircraft->customMixerTable->setCellWidget(0,i,qb);
|
||||
}
|
||||
|
||||
SpinBoxDelegate *sbd = new SpinBoxDelegate();
|
||||
for (int i=1;i<8; i++) {
|
||||
m_aircraft->customMixerTable->setItemDelegateForRow(i, sbd);
|
||||
}
|
||||
|
||||
connect(m_aircraft->fixedWingType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString)));
|
||||
connect(m_aircraft->multirotorFrameType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString)));
|
||||
connect(m_aircraft->aircraftType, SIGNAL(currentIndexChanged(int)), this, SLOT(switchAirframeType(int)));
|
||||
|
||||
connect(m_aircraft->fwThrottleReset, SIGNAL(clicked()), this, SLOT(resetFwMixer()));
|
||||
connect(m_aircraft->mrThrottleCurveReset, SIGNAL(clicked()), this, SLOT(resetMrMixer()));
|
||||
connect(m_aircraft->customReset1, SIGNAL(clicked()), this, SLOT(resetCt1Mixer()));
|
||||
connect(m_aircraft->customReset2, SIGNAL(clicked()), this, SLOT(resetCt2Mixer()));
|
||||
connect(m_aircraft->fixedWingThrottle, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateFwThrottleCurveValue(QList<double>,double)));
|
||||
connect(m_aircraft->multiThrottleCurve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateMrThrottleCurveValue(QList<double>,double)));
|
||||
connect(m_aircraft->customThrottle1Curve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateCustomThrottle1CurveValue(QList<double>,double)));
|
||||
connect(m_aircraft->customThrottle2Curve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateCustomThrottle2CurveValue(QList<double>,double)));
|
||||
|
||||
// connect(m_aircraft->fwAileron1Channel, SIGNAL(currentIndexChanged(int)), this, SLOT(toggleAileron2(int)));
|
||||
// connect(m_aircraft->fwElevator1Channel, SIGNAL(currentIndexChanged(int)), this, SLOT(toggleElevator2(int)));
|
||||
|
||||
// Now connect the three feed forward test checkboxes
|
||||
connect(m_aircraft->ffTestBox1, SIGNAL(clicked(bool)), this, SLOT(enableFFTest()));
|
||||
connect(m_aircraft->ffTestBox2, SIGNAL(clicked(bool)), this, SLOT(enableFFTest()));
|
||||
connect(m_aircraft->ffTestBox3, SIGNAL(clicked(bool)), this, SLOT(enableFFTest()));
|
||||
|
||||
enableControls(false);
|
||||
refreshWidgetsValues();
|
||||
|
||||
|
||||
// Connect the help button
|
||||
connect(m_aircraft->airframeHelp, SIGNAL(clicked()), this, SLOT(openHelp()));
|
||||
addToDirtyMonitor();
|
||||
}
|
||||
|
||||
ConfigAirframeWidget::~ConfigAirframeWidget()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
Slot for switching the airframe type. We do it explicitely
|
||||
rather than a signal in the UI, because we want to force a fitInView of the quad shapes.
|
||||
This is because this method (fitinview) only works when the widget is shown.
|
||||
*/
|
||||
void ConfigAirframeWidget::switchAirframeType(int index){
|
||||
m_aircraft->airframesWidget->setCurrentIndex(index);
|
||||
m_aircraft->quadShape->setSceneRect(quad->boundingRect());
|
||||
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
|
||||
if (m_aircraft->aircraftType->findText("Custom")) {
|
||||
m_aircraft->customMixerTable->resizeColumnsToContents();
|
||||
for (int i=0;i<8;i++) {
|
||||
m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()-
|
||||
m_aircraft->customMixerTable->verticalHeader()->width())/8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigAirframeWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
// Thit fitInView method should only be called now, once the
|
||||
// widget is shown, otherwise it cannot compute its values and
|
||||
// the result is usually a ahrsbargraph that is way too small.
|
||||
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
|
||||
m_aircraft->customMixerTable->resizeColumnsToContents();
|
||||
for (int i=0;i<8;i++) {
|
||||
m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()-
|
||||
m_aircraft->customMixerTable->verticalHeader()->width())/8);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigAirframeWidget::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
|
||||
// Make the custom table columns autostretch:
|
||||
m_aircraft->customMixerTable->resizeColumnsToContents();
|
||||
for (int i=0;i<8;i++) {
|
||||
m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()-
|
||||
m_aircraft->customMixerTable->verticalHeader()->width())/8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ConfigAirframeWidget::toggleAileron2(int index)
|
||||
{
|
||||
if (index) {
|
||||
m_aircraft->fwAileron2Channel->setEnabled(true);
|
||||
m_aircraft->fwAileron2Label->setEnabled(true);
|
||||
} else {
|
||||
m_aircraft->fwAileron2Channel->setEnabled(false);
|
||||
m_aircraft->fwAileron2Label->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigAirframeWidget::toggleElevator2(int index)
|
||||
{
|
||||
if (index) {
|
||||
m_aircraft->fwElevator2Channel->setEnabled(true);
|
||||
m_aircraft->fwElevator2Label->setEnabled(true);
|
||||
} else {
|
||||
m_aircraft->fwElevator2Channel->setEnabled(false);
|
||||
m_aircraft->fwElevator2Label->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigAirframeWidget::toggleRudder2(int index)
|
||||
{
|
||||
if (index) {
|
||||
m_aircraft->fwRudder2Channel->setEnabled(true);
|
||||
m_aircraft->fwRudder2Label->setEnabled(true);
|
||||
} else {
|
||||
m_aircraft->fwRudder2Channel->setEnabled(false);
|
||||
m_aircraft->fwRudder2Label->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
/// Feed Forward Testing
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
Enables and runs feed forward testing
|
||||
*/
|
||||
void ConfigAirframeWidget::enableFFTest()
|
||||
{
|
||||
// Role:
|
||||
// - Check if all three checkboxes are checked
|
||||
// - Every other timer event: toggle engine from 45% to 55%
|
||||
// - Every other time event: send FF settings to flight FW
|
||||
if (m_aircraft->ffTestBox1->isChecked() &&
|
||||
m_aircraft->ffTestBox2->isChecked() &&
|
||||
m_aircraft->ffTestBox3->isChecked()) {
|
||||
if (!ffTuningInProgress)
|
||||
{
|
||||
// Initiate tuning:
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlCommand")));
|
||||
UAVObject::Metadata mdata = obj->getMetadata();
|
||||
accInitialData = mdata;
|
||||
mdata.flightAccess = UAVObject::ACCESS_READONLY;
|
||||
obj->setMetadata(mdata);
|
||||
}
|
||||
// Depending on phase, either move actuator or send FF settings:
|
||||
if (ffTuningPhase) {
|
||||
// Send FF settings to the board
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("FeedForward"));
|
||||
field->setDouble((double)m_aircraft->feedForwardSlider->value()/100);
|
||||
field = obj->getField(QString("AccelTime"));
|
||||
field->setDouble(m_aircraft->accelTime->value());
|
||||
field = obj->getField(QString("DecelTime"));
|
||||
field->setDouble(m_aircraft->decelTime->value());
|
||||
field = obj->getField(QString("MaxAccel"));
|
||||
field->setDouble(m_aircraft->maxAccelSlider->value());
|
||||
obj->updated();
|
||||
} else {
|
||||
// Toggle motor state
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlCommand")));
|
||||
double value = obj->getField("Throttle")->getDouble();
|
||||
double target = (value < 0.5) ? 0.55 : 0.45;
|
||||
obj->getField("Throttle")->setValue(target);
|
||||
obj->updated();
|
||||
}
|
||||
ffTuningPhase = !ffTuningPhase;
|
||||
ffTuningInProgress = true;
|
||||
QTimer::singleShot(1000, this, SLOT(enableFFTest()));
|
||||
} else {
|
||||
// - If no: disarm timer, restore actuatorcommand metadata
|
||||
// Disarm!
|
||||
if (ffTuningInProgress) {
|
||||
ffTuningInProgress = false;
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlCommand")));
|
||||
UAVObject::Metadata mdata = obj->getMetadata();
|
||||
mdata = accInitialData; // Restore metadata
|
||||
obj->setMetadata(mdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Resets Fixed wing throttle mixer
|
||||
*/
|
||||
void ConfigAirframeWidget::resetFwMixer()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
||||
resetMixer(m_aircraft->fixedWingThrottle, field->getNumElements(),1);
|
||||
}
|
||||
|
||||
/**
|
||||
Resets Multirotor throttle mixer
|
||||
*/
|
||||
void ConfigAirframeWidget::resetMrMixer()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
||||
resetMixer(m_aircraft->multiThrottleCurve, field->getNumElements(),0.9);
|
||||
}
|
||||
|
||||
/**
|
||||
Resets Custom throttle 1 mixer
|
||||
*/
|
||||
void ConfigAirframeWidget::resetCt1Mixer()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
||||
resetMixer(m_aircraft->customThrottle1Curve, field->getNumElements(),1);
|
||||
}
|
||||
|
||||
/**
|
||||
Resets Custom throttle 2 mixer
|
||||
*/
|
||||
void ConfigAirframeWidget::resetCt2Mixer()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("ThrottleCurve2"));
|
||||
resetMixer(m_aircraft->customThrottle2Curve, field->getNumElements(),1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Resets a mixer curve
|
||||
*/
|
||||
void ConfigAirframeWidget::resetMixer(MixerCurveWidget *mixer, int numElements, double maxvalue)
|
||||
{
|
||||
// Setup all Throttle1 curves for all types of airframes
|
||||
mixer->initLinearCurve((quint32)numElements,maxvalue);
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the currently moved throttle curve item value
|
||||
*/
|
||||
void ConfigAirframeWidget::updateFwThrottleCurveValue(QList<double> list, double value)
|
||||
{
|
||||
Q_UNUSED(list);
|
||||
m_aircraft->fwThrottleCurveItemValue->setText(QString().sprintf("Val: %.2f",value));
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the currently moved throttle curve item value
|
||||
*/
|
||||
void ConfigAirframeWidget::updateMrThrottleCurveValue(QList<double> list, double value)
|
||||
{
|
||||
Q_UNUSED(list);
|
||||
m_aircraft->mrThrottleCurveItemValue->setText(QString().sprintf("Val: %.2f",value));
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the currently moved throttle curve item value (Custom throttle 1)
|
||||
*/
|
||||
void ConfigAirframeWidget::updateCustomThrottle1CurveValue(QList<double> list, double value)
|
||||
{
|
||||
Q_UNUSED(list);
|
||||
m_aircraft->customThrottleCurve1Value->setText(QString().sprintf("Val: %.2f",value));
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the currently moved throttle curve item value (Custom throttle 2)
|
||||
*/
|
||||
void ConfigAirframeWidget::updateCustomThrottle2CurveValue(QList<double> list, double value)
|
||||
{
|
||||
Q_UNUSED(list);
|
||||
m_aircraft->customThrottleCurve2Value->setText(QString().sprintf("Val: %.2f",value));
|
||||
}
|
||||
|
||||
|
||||
/**************************
|
||||
* Aircraft settings
|
||||
**************************/
|
||||
/**
|
||||
Refreshes the current value of the SystemSettings which holds the aircraft type
|
||||
*/
|
||||
void ConfigAirframeWidget::refreshWidgetsValues()
|
||||
{
|
||||
if(!allObjectsUpdated())
|
||||
return;
|
||||
bool dirty=isDirty();
|
||||
// Get the Airframe type from the system settings:
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("SystemSettings")));
|
||||
Q_ASSERT(obj);
|
||||
UAVObjectField *field = obj->getField(QString("AirframeType"));
|
||||
Q_ASSERT(field);
|
||||
// At this stage, we will need to have some hardcoded settings in this code, this
|
||||
// is not ideal, but here you go.
|
||||
QString frameType = field->getValue().toString();
|
||||
setupAirframeUI(frameType);
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
field = obj->getField(QString("ThrottleCurve1"));
|
||||
Q_ASSERT(field);
|
||||
QList<double> curveValues;
|
||||
// If the 1st element of the curve is <= -10, then the curve
|
||||
// is a straight line (that's how the mixer works on the mainboard):
|
||||
if (field->getValue(0).toInt() <= -10) {
|
||||
m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),(double)1);
|
||||
m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1);
|
||||
}
|
||||
else {
|
||||
double temp=0;
|
||||
double value;
|
||||
for (unsigned int i=0; i < field->getNumElements(); i++) {
|
||||
value=field->getValue(i).toDouble();
|
||||
temp+=value;
|
||||
curveValues.append(value);
|
||||
}
|
||||
if(temp==0)
|
||||
{
|
||||
m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),0.9);;
|
||||
m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_aircraft->multiThrottleCurve->initCurve(curveValues);
|
||||
m_aircraft->fixedWingThrottle->initCurve(curveValues);
|
||||
}
|
||||
}
|
||||
// Setup all Throttle1 curves for all types of airframes
|
||||
// Load the Settings for fixed wing frames:
|
||||
if (frameType.startsWith("FixedWing")) {
|
||||
// Then retrieve how channels are setup
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
field = obj->getField(QString("FixedWingThrottle"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwEngineChannel->setCurrentIndex(m_aircraft->fwEngineChannel->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("FixedWingRoll1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwAileron1Channel->setCurrentIndex(m_aircraft->fwAileron1Channel->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("FixedWingRoll2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwAileron2Channel->setCurrentIndex(m_aircraft->fwAileron2Channel->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("FixedWingPitch1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwElevator1Channel->setCurrentIndex(m_aircraft->fwElevator1Channel->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("FixedWingPitch2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwElevator2Channel->setCurrentIndex(m_aircraft->fwElevator2Channel->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("FixedWingYaw1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwRudder1Channel->setCurrentIndex(m_aircraft->fwRudder1Channel->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("FixedWingYaw2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwRudder2Channel->setCurrentIndex(m_aircraft->fwRudder2Channel->findText(field->getValue().toString()));
|
||||
|
||||
if (frameType == "FixedWingElevon") {
|
||||
// If the airframe is elevon, restore the slider setting
|
||||
// Find the channel number for Elevon1 (FixedWingRoll1)
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
int chMixerNumber = m_aircraft->fwAileron1Channel->currentIndex()-1;
|
||||
if (chMixerNumber >= 0) { // If for some reason the actuators were incoherent, we might fail here, hence the check.
|
||||
field = obj->getField(mixerVectors.at(chMixerNumber));
|
||||
int ti = field->getElementNames().indexOf("Roll");
|
||||
m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100);
|
||||
}
|
||||
}
|
||||
if (frameType == "FixedWingVtail") {
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
int chMixerNumber = m_aircraft->fwElevator1Channel->currentIndex()-1;
|
||||
if (chMixerNumber >=0) {
|
||||
field = obj->getField(mixerVectors.at(chMixerNumber));
|
||||
int ti = field->getElementNames().indexOf("Yaw");
|
||||
m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (frameType == "QuadX" || frameType == "QuadP" ||
|
||||
frameType == "Hexa" || frameType == "Octo" ||
|
||||
frameType == "HexaCoax" || frameType == "OctoV" ||
|
||||
frameType == "HexaX" || frameType == "OctoCoaxP" ||
|
||||
frameType == "OctoCoaxX" || frameType == "Tri") {
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Retrieve Multirotor settings
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
if (frameType == "QuadP") {
|
||||
// Motors 1/2/3/4 are: N / E / S / W
|
||||
field = obj->getField(QString("VTOLMotorN"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
|
||||
// This assumes that all vectors are identical - if not, the user should use the
|
||||
// "custom" setting.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
int eng= m_aircraft->multiMotor1->currentIndex()-1;
|
||||
// eng will be -1 if value is set to "None"
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = field->getDouble(i)/1.27;
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = (1-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
eng = m_aircraft->multiMotor2->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = -field->getDouble(i)/1.27;
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
} else if (frameType == "QuadX") {
|
||||
// Motors 1/2/3/4 are: NW / NE / SE / SW
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
|
||||
// This assumes that all vectors are identical - if not, the user should use the
|
||||
// "custom" setting.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
int eng= m_aircraft->multiMotor1->currentIndex()-1;
|
||||
// eng will be -1 if value is set to "None"
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = field->getDouble(i)/1.27;
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = 1-field->getDouble(i)/1.27;
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = field->getDouble(i)/1.27;
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
} else if (frameType == "Hexa") {
|
||||
// Motors 1/2/3 4/5/6 are: N / NE / SE / S / SW / NW
|
||||
field = obj->getField(QString("VTOLMotorN"));
|
||||
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
|
||||
// This assumes that all vectors are identical - if not, the user should use the
|
||||
// "custom" setting.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int eng= m_aircraft->multiMotor1->currentIndex()-1;
|
||||
// eng will be -1 if value is set to "None"
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
eng = m_aircraft->multiMotor2->currentIndex()-1;
|
||||
if(eng>-1)
|
||||
{
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(1-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
}
|
||||
} else if (frameType == "HexaX") {
|
||||
// Motors 1/2/3 4/5/6 are: NE / E / SE / SW / W / NW
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
|
||||
// This assumes that all vectors are identical - if not, the user should use the
|
||||
// "custom" setting.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int eng= m_aircraft->multiMotor1->currentIndex()-1;
|
||||
// eng will be -1 if value is set to "None"
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
eng = m_aircraft->multiMotor2->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(1-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
} else if (frameType == "HexaCoax") {
|
||||
// Motors 1/2/3 4/5/6 are: NW/W NE/E S/SE
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
|
||||
// This assumes that all vectors are identical - if not, the user should use the
|
||||
// "custom" setting.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int eng= m_aircraft->multiMotor1->currentIndex()-1;
|
||||
// eng will be -1 if value is set to "None"
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(2*field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
} else if (frameType == "Octo" || frameType == "OctoV" ||
|
||||
frameType == "OctoCoaxP") {
|
||||
// Motors 1 to 8 are N / NE / E / etc
|
||||
field = obj->getField(QString("VTOLMotorN"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor7->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor8->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
|
||||
// This assumes that all vectors are identical - if not, the user should use the
|
||||
// "custom" setting.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int eng= m_aircraft->multiMotor1->currentIndex()-1;
|
||||
// eng will be -1 if value is set to "None"
|
||||
if (eng > -1) {
|
||||
if (frameType == "Octo") {
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
eng = m_aircraft->multiMotor2->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
} else if (frameType == "OctoV") {
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
int i = field->getElementNames().indexOf("Yaw");
|
||||
double val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
eng = m_aircraft->multiMotor2->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
i = field->getElementNames().indexOf("Pitch");
|
||||
val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
|
||||
} else if (frameType == "OctoCoaxP") {
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
eng = m_aircraft->multiMotor3->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
|
||||
}
|
||||
}
|
||||
} else if (frameType == "OctoCoaxX") {
|
||||
// Motors 1 to 8 are N / NE / E / etc
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorN"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor7->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor8->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
|
||||
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
|
||||
// This assumes that all vectors are identical - if not, the user should use the
|
||||
// "custom" setting.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int eng= m_aircraft->multiMotor1->currentIndex()-1;
|
||||
// eng will be -1 if value is set to "None"
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
} else if (frameType == "Tri") {
|
||||
// Motors 1 to 8 are N / NE / E / etc
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("FixedWingYaw1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->triYawChannel->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int eng= m_aircraft->multiMotor1->currentIndex()-1;
|
||||
// eng will be -1 if value is set to "None"
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(2*field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
|
||||
}
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// Now, retrieve the Feedforward values:
|
||||
field = obj->getField(QString("FeedForward"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->feedForwardSlider->setValue(field->getDouble()*100);
|
||||
field = obj->getField(QString("AccelTime"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->accelTime->setValue(field->getDouble());
|
||||
field = obj->getField(QString("DecelTime"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->decelTime->setValue(field->getDouble());
|
||||
field = obj->getField(QString("MaxAccel"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->maxAccelSlider->setValue(field->getDouble());
|
||||
|
||||
} else if (frameType == "HeliCP") {
|
||||
m_aircraft->widget_3->requestccpmUpdate();
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Helicopter"));//"Helicopter"
|
||||
} else if (frameType == "Custom") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Custom"));
|
||||
}
|
||||
|
||||
updateCustomAirframeUI();
|
||||
setDirty(dirty);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Sets up the mixer depending on Airframe type. Accepts either system settings or
|
||||
combo box entry from airframe type, as those do not overlap.
|
||||
*/
|
||||
void ConfigAirframeWidget::setupAirframeUI(QString frameType)
|
||||
{
|
||||
bool dirty=isDirty();
|
||||
if (frameType == "FixedWing" || frameType == "Elevator aileron rudder") {
|
||||
// Setup the UI
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
|
||||
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevator aileron rudder"));
|
||||
m_aircraft->fwRudder1Channel->setEnabled(true);
|
||||
m_aircraft->fwRudder1Label->setEnabled(true);
|
||||
m_aircraft->fwRudder2Channel->setEnabled(true);
|
||||
m_aircraft->fwRudder2Label->setEnabled(true);
|
||||
m_aircraft->fwElevator1Channel->setEnabled(true);
|
||||
m_aircraft->fwElevator1Label->setEnabled(true);
|
||||
m_aircraft->fwElevator2Channel->setEnabled(true);
|
||||
m_aircraft->fwElevator2Label->setEnabled(true);
|
||||
m_aircraft->fwAileron1Channel->setEnabled(true);
|
||||
m_aircraft->fwAileron1Label->setEnabled(true);
|
||||
m_aircraft->fwAileron2Channel->setEnabled(true);
|
||||
m_aircraft->fwAileron2Label->setEnabled(true);
|
||||
|
||||
m_aircraft->fwAileron1Label->setText("Aileron 1");
|
||||
m_aircraft->fwAileron2Label->setText("Aileron 2");
|
||||
m_aircraft->fwElevator1Label->setText("Elevator 1");
|
||||
m_aircraft->fwElevator2Label->setText("Elevator 2");
|
||||
m_aircraft->elevonMixBox->setHidden(true);
|
||||
|
||||
} else if (frameType == "FixedWingElevon" || frameType == "Elevon") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
|
||||
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevon"));
|
||||
m_aircraft->fwAileron1Label->setText("Elevon 1");
|
||||
m_aircraft->fwAileron2Label->setText("Elevon 2");
|
||||
m_aircraft->fwElevator1Channel->setEnabled(false);
|
||||
m_aircraft->fwElevator1Label->setEnabled(false);
|
||||
m_aircraft->fwElevator2Channel->setEnabled(false);
|
||||
m_aircraft->fwElevator2Label->setEnabled(false);
|
||||
m_aircraft->fwRudder1Channel->setEnabled(true);
|
||||
m_aircraft->fwRudder1Label->setEnabled(true);
|
||||
m_aircraft->fwRudder2Channel->setEnabled(true);
|
||||
m_aircraft->fwRudder2Label->setEnabled(true);
|
||||
m_aircraft->fwElevator1Label->setText("Elevator 1");
|
||||
m_aircraft->fwElevator2Label->setText("Elevator 2");
|
||||
m_aircraft->elevonMixBox->setHidden(false);
|
||||
m_aircraft->elevonLabel1->setText("Roll");
|
||||
m_aircraft->elevonLabel2->setText("Pitch");
|
||||
|
||||
} else if (frameType == "FixedWingVtail" || frameType == "Vtail") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
|
||||
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Vtail"));
|
||||
m_aircraft->fwRudder1Channel->setEnabled(false);
|
||||
m_aircraft->fwRudder1Label->setEnabled(false);
|
||||
m_aircraft->fwRudder2Channel->setEnabled(false);
|
||||
m_aircraft->fwRudder2Label->setEnabled(false);
|
||||
m_aircraft->fwElevator1Channel->setEnabled(true);
|
||||
m_aircraft->fwElevator1Label->setEnabled(true);
|
||||
m_aircraft->fwElevator1Label->setText("Vtail 1");
|
||||
m_aircraft->fwElevator2Label->setText("Vtail 2");
|
||||
m_aircraft->elevonMixBox->setHidden(false);
|
||||
m_aircraft->fwElevator2Channel->setEnabled(true);
|
||||
m_aircraft->fwElevator2Label->setEnabled(true);
|
||||
m_aircraft->fwAileron1Label->setText("Aileron 1");
|
||||
m_aircraft->fwAileron2Label->setText("Aileron 2");
|
||||
m_aircraft->elevonLabel1->setText("Rudder");
|
||||
m_aircraft->elevonLabel2->setText("Pitch");
|
||||
|
||||
} else if (frameType == "QuadX" || frameType == "Quad X") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad X"));
|
||||
quad->setElementId("quad-X");
|
||||
m_aircraft->multiMotor4->setEnabled(true);
|
||||
m_aircraft->multiMotor5->setEnabled(false);
|
||||
m_aircraft->multiMotor6->setEnabled(false);
|
||||
m_aircraft->multiMotor7->setEnabled(false);
|
||||
m_aircraft->multiMotor8->setEnabled(false);
|
||||
m_aircraft->triYawChannel->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(50);
|
||||
m_aircraft->mrPitchMixLevel->setValue(50);
|
||||
m_aircraft->mrYawMixLevel->setValue(50);
|
||||
} else if (frameType == "QuadP" || frameType == "Quad +") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad +"));
|
||||
quad->setElementId("quad-plus");
|
||||
m_aircraft->multiMotor4->setEnabled(true);
|
||||
m_aircraft->multiMotor5->setEnabled(false);
|
||||
m_aircraft->multiMotor6->setEnabled(false);
|
||||
m_aircraft->multiMotor7->setEnabled(false);
|
||||
m_aircraft->multiMotor8->setEnabled(false);
|
||||
m_aircraft->triYawChannel->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(100);
|
||||
m_aircraft->mrPitchMixLevel->setValue(100);
|
||||
m_aircraft->mrYawMixLevel->setValue(50);
|
||||
} else if (frameType == "Hexa" || frameType == "Hexacopter") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter"));
|
||||
quad->setElementId("quad-hexa");
|
||||
m_aircraft->multiMotor4->setEnabled(true);
|
||||
m_aircraft->multiMotor5->setEnabled(true);
|
||||
m_aircraft->multiMotor6->setEnabled(true);
|
||||
m_aircraft->multiMotor7->setEnabled(false);
|
||||
m_aircraft->multiMotor8->setEnabled(false);
|
||||
m_aircraft->triYawChannel->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(50);
|
||||
m_aircraft->mrPitchMixLevel->setValue(33);
|
||||
m_aircraft->mrYawMixLevel->setValue(33);
|
||||
} else if (frameType == "Octo" || frameType == "Octocopter") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter"));
|
||||
quad->setElementId("quad-octo");
|
||||
m_aircraft->multiMotor4->setEnabled(true);
|
||||
m_aircraft->multiMotor5->setEnabled(true);
|
||||
m_aircraft->multiMotor6->setEnabled(true);
|
||||
m_aircraft->multiMotor7->setEnabled(true);
|
||||
m_aircraft->multiMotor8->setEnabled(true);
|
||||
m_aircraft->triYawChannel->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(33);
|
||||
m_aircraft->mrPitchMixLevel->setValue(33);
|
||||
m_aircraft->mrYawMixLevel->setValue(25);
|
||||
} else if (frameType == "HexaX" || frameType == "Hexacopter X" ) {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter X"));
|
||||
quad->setElementId("quad-hexa-H");
|
||||
m_aircraft->multiMotor4->setEnabled(true);
|
||||
m_aircraft->multiMotor5->setEnabled(true);
|
||||
m_aircraft->multiMotor6->setEnabled(true);
|
||||
m_aircraft->multiMotor7->setEnabled(false);
|
||||
m_aircraft->multiMotor8->setEnabled(false);
|
||||
m_aircraft->triYawChannel->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(33);
|
||||
m_aircraft->mrPitchMixLevel->setValue(50);
|
||||
m_aircraft->mrYawMixLevel->setValue(33);
|
||||
|
||||
} else if (frameType == "OctoV" || frameType == "Octocopter V") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter V"));
|
||||
quad->setElementId("quad-octo-v");
|
||||
m_aircraft->multiMotor4->setEnabled(true);
|
||||
m_aircraft->multiMotor5->setEnabled(true);
|
||||
m_aircraft->multiMotor6->setEnabled(true);
|
||||
m_aircraft->multiMotor7->setEnabled(true);
|
||||
m_aircraft->multiMotor8->setEnabled(true);
|
||||
m_aircraft->triYawChannel->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(25);
|
||||
m_aircraft->mrPitchMixLevel->setValue(25);
|
||||
m_aircraft->mrYawMixLevel->setValue(25);
|
||||
|
||||
} else if (frameType == "OctoCoaxP" || frameType == "Octo Coax +") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax +"));
|
||||
quad->setElementId("octo-coax-P");
|
||||
m_aircraft->multiMotor4->setEnabled(true);
|
||||
m_aircraft->multiMotor5->setEnabled(true);
|
||||
m_aircraft->multiMotor6->setEnabled(true);
|
||||
m_aircraft->multiMotor7->setEnabled(true);
|
||||
m_aircraft->multiMotor8->setEnabled(true);
|
||||
m_aircraft->triYawChannel->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(100);
|
||||
m_aircraft->mrPitchMixLevel->setValue(100);
|
||||
m_aircraft->mrYawMixLevel->setValue(50);
|
||||
|
||||
} else if (frameType == "OctoCoaxX" || frameType == "Octo Coax X") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax X"));
|
||||
quad->setElementId("octo-coax-X");
|
||||
m_aircraft->multiMotor4->setEnabled(true);
|
||||
m_aircraft->multiMotor5->setEnabled(true);
|
||||
m_aircraft->multiMotor6->setEnabled(true);
|
||||
m_aircraft->multiMotor7->setEnabled(true);
|
||||
m_aircraft->multiMotor8->setEnabled(true);
|
||||
m_aircraft->triYawChannel->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(50);
|
||||
m_aircraft->mrPitchMixLevel->setValue(50);
|
||||
m_aircraft->mrYawMixLevel->setValue(50);
|
||||
|
||||
} else if (frameType == "HexaCoax" || frameType == "Hexacopter Y6") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter Y6"));
|
||||
quad->setElementId("hexa-coax");
|
||||
m_aircraft->multiMotor4->setEnabled(true);
|
||||
m_aircraft->multiMotor5->setEnabled(true);
|
||||
m_aircraft->multiMotor6->setEnabled(true);
|
||||
m_aircraft->multiMotor7->setEnabled(false);
|
||||
m_aircraft->multiMotor8->setEnabled(false);
|
||||
m_aircraft->triYawChannel->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(100);
|
||||
m_aircraft->mrPitchMixLevel->setValue(50);
|
||||
m_aircraft->mrYawMixLevel->setValue(66);
|
||||
|
||||
} else if (frameType == "Tri" || frameType == "Tricopter Y") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Tricopter Y"));
|
||||
quad->setElementId("tri");
|
||||
m_aircraft->multiMotor4->setEnabled(false);
|
||||
m_aircraft->multiMotor5->setEnabled(false);
|
||||
m_aircraft->multiMotor6->setEnabled(false);
|
||||
m_aircraft->multiMotor7->setEnabled(false);
|
||||
m_aircraft->multiMotor8->setEnabled(false);
|
||||
m_aircraft->triYawChannel->setEnabled(true);
|
||||
|
||||
}
|
||||
m_aircraft->quadShape->setSceneRect(quad->boundingRect());
|
||||
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
|
||||
setDirty(dirty);
|
||||
}
|
||||
|
||||
/**
|
||||
Reset the contents of a field
|
||||
*/
|
||||
void ConfigAirframeWidget::resetField(UAVObjectField * field)
|
||||
{
|
||||
for (unsigned int i=0;i<field->getNumElements();i++) {
|
||||
field->setValue(0,i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Reset actuator values
|
||||
*/
|
||||
void ConfigAirframeWidget::resetActuators()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
QList<UAVObjectField*> fieldList = obj->getFields();
|
||||
// Reset all assignements first:
|
||||
foreach (UAVObjectField* field, fieldList) {
|
||||
// NOTE: we assume that all options in ActuatorSettings are a channel assignement
|
||||
// except for the options called "ChannelXXX"
|
||||
if (field->getUnits().contains("channel")) {
|
||||
field->setValue(field->getOptions().last());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Setup Elevator/Aileron/Rudder airframe.
|
||||
|
||||
If both Aileron channels are set to 'None' (EasyStar), do Pitch/Rudder mixing
|
||||
|
||||
Returns False if impossible to create the mixer.
|
||||
*/
|
||||
bool ConfigAirframeWidget::setupFrameFixedWing()
|
||||
{
|
||||
// Check coherence:
|
||||
// - At least Pitch and either Roll or Yaw
|
||||
if (m_aircraft->fwEngineChannel->currentText() == "None" ||
|
||||
m_aircraft->fwElevator1Channel->currentText() == "None" ||
|
||||
((m_aircraft->fwAileron1Channel->currentText() == "None") &&
|
||||
(m_aircraft->fwRudder1Channel->currentText() == "None"))) {
|
||||
// TODO: explain the problem in the UI
|
||||
m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment");
|
||||
return false;
|
||||
}
|
||||
// Now setup the channels:
|
||||
resetActuators();
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Elevator
|
||||
UAVObjectField *field = obj->getField("FixedWingPitch1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwElevator1Channel->currentText());
|
||||
field = obj->getField("FixedWingPitch2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwElevator2Channel->currentText());
|
||||
// Aileron
|
||||
field = obj->getField("FixedWingRoll1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron1Channel->currentText());
|
||||
field = obj->getField("FixedWingRoll2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron2Channel->currentText());
|
||||
// Rudder
|
||||
field = obj->getField("FixedWingYaw1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwRudder1Channel->currentText());
|
||||
// Throttle
|
||||
field = obj->getField("FixedWingThrottle");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwEngineChannel->currentText());
|
||||
|
||||
obj->updated();
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
// Disable all
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
field->setValue("Disabled");
|
||||
}
|
||||
// and set only the relevant channels:
|
||||
// Engine
|
||||
int eng = m_aircraft->fwEngineChannel->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Motor");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
// First of all reset the vector
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(127, ti);
|
||||
|
||||
// Rudder
|
||||
eng = m_aircraft->fwRudder1Channel->currentIndex()-1;
|
||||
// eng will be -1 if rudder is set to "None"
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(127, ti);
|
||||
} // Else: we have no rudder, only ailerons, we're fine with it.
|
||||
|
||||
// Ailerons
|
||||
eng = m_aircraft->fwAileron1Channel->currentIndex()-1;
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(127, ti);
|
||||
// Only set Aileron 2 if Aileron 1 is defined
|
||||
eng = m_aircraft->fwAileron2Channel->currentIndex()-1;
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(127, ti);
|
||||
}
|
||||
} // Else we have no ailerons. Our consistency check guarantees we have
|
||||
// rudder in this case, so we're fine with it too.
|
||||
|
||||
// Elevator
|
||||
eng = m_aircraft->fwElevator1Channel->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(127, ti);
|
||||
// Only set Elevator 2 if it is defined
|
||||
eng = m_aircraft->fwElevator2Channel->currentIndex()-1;
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(127, ti);
|
||||
}
|
||||
|
||||
obj->updated();
|
||||
m_aircraft->fwStatusLabel->setText("Mixer generated");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Setup Elevon
|
||||
*/
|
||||
bool ConfigAirframeWidget::setupFrameElevon()
|
||||
{
|
||||
// Check coherence:
|
||||
// - At least Aileron1 and Aileron 2, and engine
|
||||
if (m_aircraft->fwEngineChannel->currentText() == "None" ||
|
||||
m_aircraft->fwAileron1Channel->currentText() == "None" ||
|
||||
m_aircraft->fwAileron2Channel->currentText() == "None") {
|
||||
// TODO: explain the problem in the UI
|
||||
m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment");
|
||||
return false;
|
||||
}
|
||||
|
||||
resetActuators();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Elevons
|
||||
UAVObjectField *field = obj->getField("FixedWingRoll1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron1Channel->currentText());
|
||||
field = obj->getField("FixedWingRoll2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron2Channel->currentText());
|
||||
// Rudder 1 (can be None)
|
||||
field = obj->getField("FixedWingYaw1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwRudder1Channel->currentText());
|
||||
// Rudder 2 (can be None)
|
||||
field = obj->getField("FixedWingYaw2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwRudder2Channel->currentText());
|
||||
// Throttle
|
||||
field = obj->getField("FixedWingThrottle");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwEngineChannel->currentText());
|
||||
|
||||
obj->updated();
|
||||
|
||||
// Save the curve:
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
// Disable all
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
field->setValue("Disabled");
|
||||
}
|
||||
// and set only the relevant channels:
|
||||
// Engine
|
||||
int eng = m_aircraft->fwEngineChannel->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Motor");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
// First of all reset the vector
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(127, ti);
|
||||
|
||||
// Rudder 1
|
||||
eng = m_aircraft->fwRudder1Channel->currentIndex()-1;
|
||||
// eng will be -1 if rudder 1 is set to "None"
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(127, ti);
|
||||
} // Else: we have no rudder, only elevons, we're fine with it.
|
||||
|
||||
// Rudder 2
|
||||
eng = m_aircraft->fwRudder2Channel->currentIndex()-1;
|
||||
// eng will be -1 if rudder 2 is set to "None"
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(-127, ti);
|
||||
} // Else: we have no rudder, only elevons, we're fine with it.
|
||||
|
||||
eng = m_aircraft->fwAileron1Channel->currentIndex()-1;
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti);
|
||||
}
|
||||
|
||||
eng = m_aircraft->fwAileron2Channel->currentIndex()-1;
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti);
|
||||
}
|
||||
|
||||
obj->updated();
|
||||
m_aircraft->fwStatusLabel->setText("Mixer generated");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
Setup VTail
|
||||
*/
|
||||
bool ConfigAirframeWidget::setupFrameVtail()
|
||||
{
|
||||
// Check coherence:
|
||||
// - At least Pitch1 and Pitch2, and engine
|
||||
if (m_aircraft->fwEngineChannel->currentText() == "None" ||
|
||||
m_aircraft->fwElevator1Channel->currentText() == "None" ||
|
||||
m_aircraft->fwElevator2Channel->currentText() == "None") {
|
||||
// TODO: explain the problem in the UI
|
||||
m_aircraft->fwStatusLabel->setText("WARNING: check channel assignment");
|
||||
return false;
|
||||
}
|
||||
|
||||
resetActuators();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Elevons
|
||||
UAVObjectField *field = obj->getField("FixedWingPitch1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwElevator1Channel->currentText());
|
||||
field = obj->getField("FixedWingPitch2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwElevator2Channel->currentText());
|
||||
field = obj->getField("FixedWingRoll1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron1Channel->currentText());
|
||||
field = obj->getField("FixedWingRoll2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron2Channel->currentText());
|
||||
|
||||
// Throttle
|
||||
field = obj->getField("FixedWingThrottle");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwEngineChannel->currentText());
|
||||
|
||||
obj->updated();
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
// Disable all
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
field->setValue("Disabled");
|
||||
}
|
||||
// and set only the relevant channels:
|
||||
// Engine
|
||||
int eng = m_aircraft->fwEngineChannel->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Motor");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
// First of all reset the vector
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(127, ti);
|
||||
|
||||
eng = m_aircraft->fwAileron1Channel->currentIndex()-1;
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(127,ti);
|
||||
}
|
||||
|
||||
eng = m_aircraft->fwAileron2Channel->currentIndex()-1;
|
||||
if (eng > -1) {
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(-127,ti);
|
||||
}
|
||||
|
||||
// Now compute the VTail
|
||||
eng = m_aircraft->fwElevator1Channel->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti);
|
||||
|
||||
eng = m_aircraft->fwElevator2Channel->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti);
|
||||
|
||||
obj->updated();
|
||||
m_aircraft->fwStatusLabel->setText("Mixer generated");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
Set up a complete mixer, taking a table of factors. The factors
|
||||
shoudl mainly be +/- 1 factors, since they will be weighted by the
|
||||
value of the Pitch/Roll/Yaw sliders.
|
||||
|
||||
Example:
|
||||
double xMixer [8][3] = {
|
||||
P R Y
|
||||
{ 1, 1, -1}, Motor 1
|
||||
{ 1, -1, 1}, Motor 2
|
||||
{-1, -1, -1}, Motor 3
|
||||
{-1, 1, 1}, ...
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
*/
|
||||
bool ConfigAirframeWidget::setupMixer(double mixerFactors[8][3])
|
||||
{
|
||||
qDebug()<<"Mixer factors";
|
||||
qDebug()<<mixerFactors[0][0]<<" "<<mixerFactors[0][1]<<" "<<mixerFactors[0][2];
|
||||
qDebug()<<mixerFactors[1][0]<<" "<<mixerFactors[1][1]<<" "<<mixerFactors[1][2];
|
||||
qDebug()<<mixerFactors[2][0]<<" "<<mixerFactors[2][1]<<" "<<mixerFactors[2][2];
|
||||
qDebug()<<mixerFactors[3][0]<<" "<<mixerFactors[3][1]<<" "<<mixerFactors[3][2];
|
||||
qDebug()<<mixerFactors[4][0]<<" "<<mixerFactors[4][1]<<" "<<mixerFactors[4][2];
|
||||
qDebug()<<mixerFactors[5][0]<<" "<<mixerFactors[5][1]<<" "<<mixerFactors[5][2];
|
||||
qDebug()<<mixerFactors[6][0]<<" "<<mixerFactors[6][1]<<" "<<mixerFactors[6][2];
|
||||
qDebug()<<mixerFactors[7][0]<<" "<<mixerFactors[7][1]<<" "<<mixerFactors[7][2];
|
||||
|
||||
UAVObjectField *field;
|
||||
QList<QComboBox*> mmList;
|
||||
mmList << m_aircraft->multiMotor1 << m_aircraft->multiMotor2 << m_aircraft->multiMotor3
|
||||
<< m_aircraft->multiMotor4 << m_aircraft->multiMotor5 << m_aircraft->multiMotor6
|
||||
<< m_aircraft->multiMotor7 << m_aircraft->multiMotor8;
|
||||
UAVDataObject *obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
// Disable all
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
field->setValue("Disabled");
|
||||
}
|
||||
// and enable only the relevant channels:
|
||||
double pFactor = (double)m_aircraft->mrPitchMixLevel->value()/100;
|
||||
double rFactor = (double)m_aircraft->mrRollMixLevel->value()/100;
|
||||
double yFactor = (double)m_aircraft->mrYawMixLevel->value()/100;
|
||||
qDebug()<<QString("pFactor=%0 rFactor=%1 yFactor=%2").arg(pFactor).arg(rFactor).arg(yFactor);
|
||||
for (int i=0 ; i<8; i++) {
|
||||
if(mmList.at(i)->isEnabled())
|
||||
{
|
||||
int channel = mmList.at(i)->currentIndex()-1;
|
||||
if (channel > -1)
|
||||
setupQuadMotor(channel, mixerFactors[i][0]*pFactor,
|
||||
rFactor*mixerFactors[i][1], yFactor*mixerFactors[i][2]);
|
||||
}
|
||||
}
|
||||
// obj->updated();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Help function: setupQuadMotor
|
||||
*/
|
||||
void ConfigAirframeWidget::setupQuadMotor(int channel, double pitch, double roll, double yaw)
|
||||
{
|
||||
qDebug()<<QString("Setup quad motor channel=%0 pitch=%1 roll=%2 yaw=%3").arg(channel).arg(pitch).arg(roll).arg(yaw);
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
UAVObjectField *field = obj->getField(mixerTypes.at(channel));
|
||||
field->setValue("Motor");
|
||||
field = obj->getField(mixerVectors.at(channel));
|
||||
// First of all reset the vector
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(127, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(roll*127,ti);
|
||||
qDebug()<<"Set roll="<<roll*127;
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(pitch*127,ti);
|
||||
qDebug()<<"Set pitch="<<pitch*127;
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(yaw*127,ti);
|
||||
qDebug()<<"Set yaw="<<yaw*127;
|
||||
}
|
||||
|
||||
/**
|
||||
Helper function: setup motors. Takes a list of channel names in input.
|
||||
*/
|
||||
void ConfigAirframeWidget::setupMotors(QList<QString> motorList)
|
||||
{
|
||||
resetActuators();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
UAVObjectField *field;
|
||||
QList<QComboBox*> mmList;
|
||||
mmList << m_aircraft->multiMotor1 << m_aircraft->multiMotor2 << m_aircraft->multiMotor3
|
||||
<< m_aircraft->multiMotor4 << m_aircraft->multiMotor5 << m_aircraft->multiMotor6
|
||||
<< m_aircraft->multiMotor7 << m_aircraft->multiMotor8;
|
||||
foreach (QString motor, motorList) {
|
||||
field = obj->getField(motor);
|
||||
field->setValue(mmList.takeFirst()->currentText());
|
||||
}
|
||||
//obj->updated(); // Save...
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set up a Quad-X or Quad-P
|
||||
*/
|
||||
bool ConfigAirframeWidget::setupQuad(bool pLayout)
|
||||
{
|
||||
// Check coherence:
|
||||
// - Four engines have to be defined
|
||||
if (m_aircraft->multiMotor1->currentText() == "None" ||
|
||||
m_aircraft->multiMotor2->currentText() == "None" ||
|
||||
m_aircraft->multiMotor3->currentText() == "None" ||
|
||||
m_aircraft->multiMotor4->currentText() == "None") {
|
||||
m_aircraft->mrStatusLabel->setText("ERROR: Assign 4 motor channels");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
QList<QString> motorList;
|
||||
if (pLayout) {
|
||||
motorList << "VTOLMotorN" << "VTOLMotorE" << "VTOLMotorS"
|
||||
<< "VTOLMotorW";
|
||||
} else {
|
||||
motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorSE"
|
||||
<< "VTOLMotorSW";
|
||||
}
|
||||
setupMotors(motorList);
|
||||
|
||||
// Now, setup the mixer:
|
||||
// Motor 1 to 4, X Layout:
|
||||
// pitch roll yaw
|
||||
// {0.5 ,0.5 ,-0.5 //Front left motor (CW)
|
||||
// {0.5 ,-0.5 ,0.5 //Front right motor(CCW)
|
||||
// {-0.5 ,-0.5 ,-0.5 //rear right motor (CW)
|
||||
// {-0.5 ,0.5 ,0.5 //Rear left motor (CCW)
|
||||
double xMixer [8][3] = {
|
||||
{ 1, 1, -1},
|
||||
{ 1, -1, 1},
|
||||
{-1, -1, -1},
|
||||
{-1, 1, 1},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
//
|
||||
// Motor 1 to 4, P Layout:
|
||||
// pitch roll yaw
|
||||
// {1 ,0 ,-0.5 //Front motor (CW)
|
||||
// {0 ,-1 ,0.5 //Right motor(CCW)
|
||||
// {-1 ,0 ,-0.5 //Rear motor (CW)
|
||||
// {0 ,1 ,0.5 //Left motor (CCW)
|
||||
double pMixer [8][3] = {
|
||||
{ 1, 0, -1},
|
||||
{ 0, -1, 1},
|
||||
{-1, 0, -1},
|
||||
{ 0, 1, 1},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
|
||||
if (pLayout) {
|
||||
setupMixer(pMixer);
|
||||
} else {
|
||||
setupMixer(xMixer);
|
||||
}
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Set up a Hexa-X or Hexa-P
|
||||
*/
|
||||
bool ConfigAirframeWidget::setupHexa(bool pLayout)
|
||||
{
|
||||
// Check coherence:
|
||||
// - Four engines have to be defined
|
||||
if (m_aircraft->multiMotor1->currentText() == "None" ||
|
||||
m_aircraft->multiMotor2->currentText() == "None" ||
|
||||
m_aircraft->multiMotor3->currentText() == "None" ||
|
||||
m_aircraft->multiMotor4->currentText() == "None" ||
|
||||
m_aircraft->multiMotor5->currentText() == "None" ||
|
||||
m_aircraft->multiMotor6->currentText() == "None") {
|
||||
m_aircraft->mrStatusLabel->setText("ERROR: Assign 6 motor channels");
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<QString> motorList;
|
||||
if (pLayout) {
|
||||
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorSE"
|
||||
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorNW";
|
||||
} else {
|
||||
motorList << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
|
||||
<< "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
|
||||
}
|
||||
setupMotors(motorList);
|
||||
|
||||
// and set only the relevant channels:
|
||||
|
||||
// Motor 1 to 6, P Layout:
|
||||
// pitch roll yaw
|
||||
// 1 { 0.3 , 0 ,-0.3 // N CW
|
||||
// 2 { 0.3 ,-0.5 , 0.3 // NE CCW
|
||||
// 3 {-0.3 ,-0.5 ,-0.3 // SE CW
|
||||
// 4 {-0.3 , 0 , 0.3 // S CCW
|
||||
// 5 {-0.3 , 0.5 ,-0.3 // SW CW
|
||||
// 6 { 0.3 , 0.5 , 0.3 // NW CCW
|
||||
|
||||
double pMixer [8][3] = {
|
||||
{ 1, 0, -1},
|
||||
{ 1, -1, 1},
|
||||
{-1, -1, -1},
|
||||
{-1, 0, 1},
|
||||
{-1, 1, -1},
|
||||
{ 1, 1, 1},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
|
||||
//
|
||||
// Motor 1 to 6, X Layout:
|
||||
// 1 [ 0.5, -0.3, -0.3 ] NE
|
||||
// 2 [ 0 , -0.3, 0.3 ] E
|
||||
// 3 [ -0.5, -0.3, -0.3 ] SE
|
||||
// 4 [ -0.5, 0.3, 0.3 ] SW
|
||||
// 5 [ 0 , 0.3, -0.3 ] W
|
||||
// 6 [ 0.5, 0.3, 0.3 ] NW
|
||||
double xMixer [8][3] = {
|
||||
{ 1, -1, -1},
|
||||
{ 0, -1, 1},
|
||||
{ -1, -1, -1},
|
||||
{ -1, 1, 1},
|
||||
{ 0, 1, -1},
|
||||
{ 1, 1, 1},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
|
||||
if (pLayout) {
|
||||
setupMixer(pMixer);
|
||||
} else {
|
||||
setupMixer(xMixer);
|
||||
}
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the custom airframe settings based on the current airframe.
|
||||
|
||||
Note: does NOT ask for an object refresh itself!
|
||||
*/
|
||||
void ConfigAirframeWidget::updateCustomAirframeUI()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
||||
QList<double> curveValues;
|
||||
// If the 1st element of the curve is <= -10, then the curve
|
||||
// is a straight line (that's how the mixer works on the mainboard):
|
||||
if (field->getValue(0).toInt() <= -10) {
|
||||
m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1);
|
||||
} else {
|
||||
double temp=0;
|
||||
double value;
|
||||
for (unsigned int i=0; i < field->getNumElements(); i++) {
|
||||
value=field->getValue(i).toDouble();
|
||||
temp+=value;
|
||||
curveValues.append(value);
|
||||
}
|
||||
if(temp==0)
|
||||
m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1);
|
||||
else
|
||||
m_aircraft->customThrottle1Curve->initCurve(curveValues);
|
||||
}
|
||||
field = obj->getField(QString("ThrottleCurve2"));
|
||||
curveValues.clear();;
|
||||
// If the 1st element of the curve is <= -10, then the curve
|
||||
// is a straight line (that's how the mixer works on the mainboard):
|
||||
if (field->getValue(0).toInt() <= -10) {
|
||||
m_aircraft->customThrottle2Curve->initLinearCurve(field->getNumElements(),(double)1);
|
||||
} else {
|
||||
for (unsigned int i=0; i < field->getNumElements(); i++) {
|
||||
curveValues.append(field->getValue(i).toDouble());
|
||||
}
|
||||
m_aircraft->customThrottle2Curve->initCurve(curveValues);
|
||||
}
|
||||
|
||||
// Update the table:
|
||||
for (int i=0; i<8; i++) {
|
||||
field = obj->getField(mixerTypes.at(i));
|
||||
QComboBox* q = (QComboBox*)m_aircraft->customMixerTable->cellWidget(0,i);
|
||||
QString s = field->getValue().toString();
|
||||
q->setCurrentIndex(q->findText(s));
|
||||
//bool en = (s != "Disabled");
|
||||
field = obj->getField(mixerVectors.at(i));
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
m_aircraft->customMixerTable->item(1,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2");
|
||||
m_aircraft->customMixerTable->item(2,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
m_aircraft->customMixerTable->item(3,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
m_aircraft->customMixerTable->item(4,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
m_aircraft->customMixerTable->item(5,i)->setText(field->getValue(ti).toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Sends the config to the board (airframe type)
|
||||
|
||||
We do all the tasks common to all airframes, or family of airframes, and
|
||||
we call additional methods for specific frames, so that we do not have a code
|
||||
that is too heavy.
|
||||
*/
|
||||
void ConfigAirframeWidget::updateObjectsFromWidgets()
|
||||
{
|
||||
qDebug()<<"updateObjectsFromWidgets";
|
||||
QString airframeType = "Custom";
|
||||
if (m_aircraft->aircraftType->currentText() == "Fixed Wing") {
|
||||
// Save the curve (common to all Fixed wing frames)
|
||||
UAVDataObject *obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
// Remove Feed Forward, it is pointless on a plane:
|
||||
UAVObjectField* field = obj->getField(QString("FeedForward"));
|
||||
field->setDouble(0);
|
||||
field = obj->getField("ThrottleCurve1");
|
||||
QList<double> curve = m_aircraft->fixedWingThrottle->getCurve();
|
||||
for (int i=0;i<curve.length();i++) {
|
||||
field->setValue(curve.at(i),i);
|
||||
}
|
||||
|
||||
if (m_aircraft->fixedWingType->currentText() == "Elevator aileron rudder" ) {
|
||||
airframeType = "FixedWing";
|
||||
setupFrameFixedWing();
|
||||
} else if (m_aircraft->fixedWingType->currentText() == "Elevon") {
|
||||
airframeType = "FixedWingElevon";
|
||||
setupFrameElevon();
|
||||
} else { // "Vtail"
|
||||
airframeType = "FixedWingVtail";
|
||||
setupFrameVtail();
|
||||
}
|
||||
// Now reflect those settings in the "Custom" panel as well
|
||||
updateCustomAirframeUI();
|
||||
} else if (m_aircraft->aircraftType->currentText() == "Multirotor") {
|
||||
|
||||
QList<QString> motorList;
|
||||
|
||||
// We can already setup the feedforward here, as it is common to all platforms
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("FeedForward"));
|
||||
field->setDouble((double)m_aircraft->feedForwardSlider->value()/100);
|
||||
field = obj->getField(QString("AccelTime"));
|
||||
field->setDouble(m_aircraft->accelTime->value());
|
||||
field = obj->getField(QString("DecelTime"));
|
||||
field->setDouble(m_aircraft->decelTime->value());
|
||||
field = obj->getField(QString("MaxAccel"));
|
||||
field->setDouble(m_aircraft->maxAccelSlider->value());
|
||||
|
||||
// Curve is also common to all quads:
|
||||
field = obj->getField("ThrottleCurve1");
|
||||
QList<double> curve = m_aircraft->multiThrottleCurve->getCurve();
|
||||
for (int i=0;i<curve.length();i++) {
|
||||
field->setValue(curve.at(i),i);
|
||||
}
|
||||
|
||||
if (m_aircraft->multirotorFrameType->currentText() == "Quad +") {
|
||||
airframeType = "QuadP";
|
||||
setupQuad(true);
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Quad X") {
|
||||
airframeType = "QuadX";
|
||||
setupQuad(false);
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter") {
|
||||
airframeType = "Hexa";
|
||||
setupHexa(true);
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter") {
|
||||
airframeType = "Octo";
|
||||
if (m_aircraft->multiMotor1->currentText() == "None" ||
|
||||
m_aircraft->multiMotor2->currentText() == "None" ||
|
||||
m_aircraft->multiMotor3->currentText() == "None" ||
|
||||
m_aircraft->multiMotor4->currentText() == "None" ||
|
||||
m_aircraft->multiMotor5->currentText() == "None" ||
|
||||
m_aircraft->multiMotor6->currentText() == "None" ||
|
||||
m_aircraft->multiMotor7->currentText() == "None" ||
|
||||
m_aircraft->multiMotor8->currentText() == "None") {
|
||||
m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels");
|
||||
return;
|
||||
}
|
||||
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
|
||||
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
|
||||
setupMotors(motorList);
|
||||
// Motor 1 to 8:
|
||||
// pitch roll yaw
|
||||
double mixer [8][3] = {
|
||||
{ 1, 0, -1},
|
||||
{ 1, -1, 1},
|
||||
{ 0, -1, -1},
|
||||
{ -1, -1, 1},
|
||||
{ -1, 0, -1},
|
||||
{ -1, 1, 1},
|
||||
{ 0, 1, -1},
|
||||
{ 1, 1, 1}
|
||||
};
|
||||
setupMixer(mixer);
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter X") {
|
||||
airframeType = "HexaX";
|
||||
setupHexa(false);
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter V") {
|
||||
airframeType = "OctoV";
|
||||
if (m_aircraft->multiMotor1->currentText() == "None" ||
|
||||
m_aircraft->multiMotor2->currentText() == "None" ||
|
||||
m_aircraft->multiMotor3->currentText() == "None" ||
|
||||
m_aircraft->multiMotor4->currentText() == "None" ||
|
||||
m_aircraft->multiMotor5->currentText() == "None" ||
|
||||
m_aircraft->multiMotor6->currentText() == "None" ||
|
||||
m_aircraft->multiMotor7->currentText() == "None" ||
|
||||
m_aircraft->multiMotor8->currentText() == "None") {
|
||||
m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels");
|
||||
return;
|
||||
}
|
||||
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
|
||||
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
|
||||
setupMotors(motorList);
|
||||
// Motor 1 to 8:
|
||||
// IMPORTANT: Assumes evenly spaced engines
|
||||
// pitch roll yaw
|
||||
double mixer [8][3] = {
|
||||
{ 0.33, -1, -1},
|
||||
{ 1 , -1, 1},
|
||||
{ -1 , -1, -1},
|
||||
{ -0.33, -1, 1},
|
||||
{ -0.33, 1, -1},
|
||||
{ -1 , 1, 1},
|
||||
{ 1 , 1, -1},
|
||||
{ 0.33, 1, 1}
|
||||
};
|
||||
setupMixer(mixer);
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax +") {
|
||||
airframeType = "OctoCoaxP";
|
||||
if (m_aircraft->multiMotor1->currentText() == "None" ||
|
||||
m_aircraft->multiMotor2->currentText() == "None" ||
|
||||
m_aircraft->multiMotor3->currentText() == "None" ||
|
||||
m_aircraft->multiMotor4->currentText() == "None" ||
|
||||
m_aircraft->multiMotor5->currentText() == "None" ||
|
||||
m_aircraft->multiMotor6->currentText() == "None" ||
|
||||
m_aircraft->multiMotor7->currentText() == "None" ||
|
||||
m_aircraft->multiMotor8->currentText() == "None") {
|
||||
m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels");
|
||||
return;
|
||||
}
|
||||
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
|
||||
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
|
||||
setupMotors(motorList);
|
||||
// Motor 1 to 8:
|
||||
// pitch roll yaw
|
||||
double mixer [8][3] = {
|
||||
{ 1, 0, -1},
|
||||
{ 1, 0, 1},
|
||||
{ 0, -1, -1},
|
||||
{ 0, -1, 1},
|
||||
{ -1, 0, -1},
|
||||
{ -1, 0, 1},
|
||||
{ 0, 1, -1},
|
||||
{ 0, 1, 1}
|
||||
};
|
||||
setupMixer(mixer);
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax X") {
|
||||
airframeType = "OctoCoaxX";
|
||||
if (m_aircraft->multiMotor1->currentText() == "None" ||
|
||||
m_aircraft->multiMotor2->currentText() == "None" ||
|
||||
m_aircraft->multiMotor3->currentText() == "None" ||
|
||||
m_aircraft->multiMotor4->currentText() == "None" ||
|
||||
m_aircraft->multiMotor5->currentText() == "None" ||
|
||||
m_aircraft->multiMotor6->currentText() == "None" ||
|
||||
m_aircraft->multiMotor7->currentText() == "None" ||
|
||||
m_aircraft->multiMotor8->currentText() == "None") {
|
||||
m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels");
|
||||
return;
|
||||
}
|
||||
motorList << "VTOLMotorNW" << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE"
|
||||
<< "VTOLMotorSE" << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW";
|
||||
setupMotors(motorList);
|
||||
// Motor 1 to 8:
|
||||
// pitch roll yaw
|
||||
double mixer [8][3] = {
|
||||
{ 1, 1, -1},
|
||||
{ 1, 1, 1},
|
||||
{ 1, -1, -1},
|
||||
{ 1, -1, 1},
|
||||
{ -1, -1, -1},
|
||||
{ -1, -1, 1},
|
||||
{ -1, 1, -1},
|
||||
{ -1, 1, 1}
|
||||
};
|
||||
setupMixer(mixer);
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter Y6") {
|
||||
airframeType = "HexaCoax";
|
||||
if (m_aircraft->multiMotor1->currentText() == "None" ||
|
||||
m_aircraft->multiMotor2->currentText() == "None" ||
|
||||
m_aircraft->multiMotor3->currentText() == "None" ||
|
||||
m_aircraft->multiMotor4->currentText() == "None" ||
|
||||
m_aircraft->multiMotor5->currentText() == "None" ||
|
||||
m_aircraft->multiMotor6->currentText() == "None" ) {
|
||||
m_aircraft->mrStatusLabel->setText("ERROR: Assign 6 motor channels");
|
||||
return;
|
||||
}
|
||||
motorList << "VTOLMotorNW" << "VTOLMotorW" << "VTOLMotorNE" << "VTOLMotorE"
|
||||
<< "VTOLMotorS" << "VTOLMotorSE";
|
||||
setupMotors(motorList);
|
||||
|
||||
// Motor 1 to 6, Y6 Layout:
|
||||
// pitch roll yaw
|
||||
double mixer [8][3] = {
|
||||
{ 0.5, 1, -1},
|
||||
{ 0.5, 1, 1},
|
||||
{ 0.5, -1, -1},
|
||||
{ 0.5, -1, 1},
|
||||
{ -1, 0, -1},
|
||||
{ -1, 0, 1},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
setupMixer(mixer);
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
|
||||
} else if (m_aircraft->multirotorFrameType->currentText() == "Tricopter Y") {
|
||||
airframeType = "Tri";
|
||||
if (m_aircraft->multiMotor1->currentText() == "None" ||
|
||||
m_aircraft->multiMotor2->currentText() == "None" ||
|
||||
m_aircraft->multiMotor3->currentText() == "None" ) {
|
||||
m_aircraft->mrStatusLabel->setText("ERROR: Assign 3 motor channels");
|
||||
return;
|
||||
}
|
||||
if (m_aircraft->triYawChannel->currentText() == "None") {
|
||||
m_aircraft->mrStatusLabel->setText("Error: Assign a Yaw channel");
|
||||
return;
|
||||
}
|
||||
motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorS";
|
||||
setupMotors(motorList);
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
field = obj->getField("FixedWingYaw1");
|
||||
field->setValue(m_aircraft->triYawChannel->currentText());
|
||||
|
||||
// Motor 1 to 6, Y6 Layout:
|
||||
// pitch roll yaw
|
||||
double mixer [8][3] = {
|
||||
{ 0.5, 1, 0},
|
||||
{ 0.5, -1, 0},
|
||||
{ -1, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0},
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
setupMixer(mixer);
|
||||
|
||||
int eng = m_aircraft->triYawChannel->currentIndex()-1;
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
field = obj->getField(mixerTypes.at(eng));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(eng));
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(127,ti);
|
||||
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
|
||||
}
|
||||
// Now reflect those settings in the "Custom" panel as well
|
||||
updateCustomAirframeUI();
|
||||
|
||||
} else if (m_aircraft->aircraftType->currentText() == "Helicopter") {
|
||||
airframeType = "HeliCP";
|
||||
m_aircraft->widget_3->sendccpmUpdate();
|
||||
} else {
|
||||
airframeType = "Custom";
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("FeedForward"));
|
||||
|
||||
// Curve is also common to all quads:
|
||||
field = obj->getField("ThrottleCurve1");
|
||||
QList<double> curve = m_aircraft->customThrottle1Curve->getCurve();
|
||||
for (int i=0;i<curve.length();i++) {
|
||||
field->setValue(curve.at(i),i);
|
||||
}
|
||||
|
||||
field = obj->getField("ThrottleCurve2");
|
||||
curve.clear();
|
||||
curve = m_aircraft->customThrottle2Curve->getCurve();
|
||||
for (int i=0;i<curve.length();i++) {
|
||||
field->setValue(curve.at(i),i);
|
||||
}
|
||||
|
||||
// Update the table:
|
||||
for (int i=0; i<8; i++) {
|
||||
field = obj->getField(mixerTypes.at(i));
|
||||
QComboBox* q = (QComboBox*)m_aircraft->customMixerTable->cellWidget(0,i);
|
||||
field->setValue(q->currentText());
|
||||
field = obj->getField(mixerVectors.at(i));
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(m_aircraft->customMixerTable->item(1,i)->text(),ti);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2");
|
||||
field->setValue(m_aircraft->customMixerTable->item(2,i)->text(),ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(m_aircraft->customMixerTable->item(3,i)->text(),ti);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(m_aircraft->customMixerTable->item(4,i)->text(),ti);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(m_aircraft->customMixerTable->item(5,i)->text(),ti);
|
||||
}
|
||||
|
||||
}
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("SystemSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("AirframeType"));
|
||||
field->setValue(airframeType);
|
||||
|
||||
}
|
||||
|
||||
void ConfigAirframeWidget::openHelp()
|
||||
{
|
||||
|
||||
QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Airframe+configuration", QUrl::StrictMode) );
|
||||
}
|
||||
|
||||
void ConfigAirframeWidget::addToDirtyMonitor()
|
||||
{
|
||||
addWidget(m_aircraft->customMixerTable);
|
||||
addWidget(m_aircraft->customThrottle2Curve);
|
||||
addWidget(m_aircraft->customThrottle1Curve);
|
||||
addWidget(m_aircraft->multiThrottleCurve);
|
||||
addWidget(m_aircraft->fixedWingThrottle);
|
||||
addWidget(m_aircraft->fixedWingType);
|
||||
addWidget(m_aircraft->feedForwardSlider);
|
||||
addWidget(m_aircraft->accelTime);
|
||||
addWidget(m_aircraft->decelTime);
|
||||
addWidget(m_aircraft->maxAccelSlider);
|
||||
addWidget(m_aircraft->multirotorFrameType);
|
||||
addWidget(m_aircraft->multiMotor1);
|
||||
addWidget(m_aircraft->multiMotor2);
|
||||
addWidget(m_aircraft->multiMotor3);
|
||||
addWidget(m_aircraft->multiMotor4);
|
||||
addWidget(m_aircraft->multiMotor5);
|
||||
addWidget(m_aircraft->multiMotor6);
|
||||
addWidget(m_aircraft->multiMotor7);
|
||||
addWidget(m_aircraft->multiMotor8);
|
||||
addWidget(m_aircraft->triYawChannel);
|
||||
addWidget(m_aircraft->aircraftType);
|
||||
addWidget(m_aircraft->fwEngineChannel);
|
||||
addWidget(m_aircraft->fwAileron1Channel);
|
||||
addWidget(m_aircraft->fwAileron2Channel);
|
||||
addWidget(m_aircraft->fwElevator1Channel);
|
||||
addWidget(m_aircraft->fwElevator2Channel);
|
||||
addWidget(m_aircraft->fwRudder1Channel);
|
||||
addWidget(m_aircraft->fwRudder2Channel);
|
||||
addWidget(m_aircraft->elevonSlider1);
|
||||
addWidget(m_aircraft->elevonSlider2);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmType);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmTailChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmEngineChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoWChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoXChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoYChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmSingleServo);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoZChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleW);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleX);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCorrectionAngle);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleZ);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleY);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivePassthrough);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkRoll);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkCyclic);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRevoSlider);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmREVOspinBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveSlider);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivespinBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScaleBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCyclicScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScaleBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScaleBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSlider);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSpinBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveType);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->NumCurvePoints);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue1);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue2);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue3);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveToGenerate);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveSettings);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ThrottleCurve);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->PitchCurve);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAdvancedSettingsTable);
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "configahrswidget.h"
|
||||
#include "configgadgetwidget.h"
|
||||
|
||||
#include "configairframewidget.h"
|
||||
#include "configvehicletypewidget.h"
|
||||
#include "configccattitudewidget.h"
|
||||
#include "configinputwidget.h"
|
||||
#include "configoutputwidget.h"
|
||||
@ -68,7 +68,7 @@ ConfigGadgetWidget::ConfigGadgetWidget(QWidget *parent) : QWidget(parent)
|
||||
qwd = new DefaultHwSettingsWidget(this);
|
||||
ftw->insertTab(ConfigGadgetWidget::hardware, qwd, QIcon(":/configgadget/images/hw_config.png"), QString("HW Settings"));
|
||||
|
||||
qwd = new ConfigAirframeWidget(this);
|
||||
qwd = new ConfigVehicleTypeWidget(this);
|
||||
ftw->insertTab(ConfigGadgetWidget::aircraft, qwd, QIcon(":/configgadget/images/Airframe.png"), QString("Aircraft"));
|
||||
|
||||
qwd = new ConfigInputWidget(this);
|
||||
|
@ -56,18 +56,19 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
|
||||
addApplySaveButtons(m_config->saveRCInputToRAM,m_config->saveRCInputToSD);
|
||||
|
||||
//Generate the rows of buttons in the input channel form GUI
|
||||
unsigned int index=0;
|
||||
foreach (QString name, manualSettingsObj->getField("ChannelNumber")->getElementNames())
|
||||
{
|
||||
Q_ASSERT(index < ManualControlSettings::CHANNELGROUPS_NUMELEM);
|
||||
inputChannelForm * inp=new inputChannelForm(this,index==0);
|
||||
m_config->channelSettings->layout()->addWidget(inp);
|
||||
inp->setName(name);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelGroups",inp->ui->channelGroup,index);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelNumber",inp->ui->channelNumber,index);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelMin",inp->ui->channelMin,index);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelNeutral",inp->ui->channelNeutral,index);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelMax",inp->ui->channelMax,index);
|
||||
inputChannelForm * inpForm=new inputChannelForm(this,index==0);
|
||||
m_config->channelSettings->layout()->addWidget(inpForm); //Add the row to the UI
|
||||
inpForm->setName(name);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelGroups",inpForm->ui->channelGroup,index);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelNumber",inpForm->ui->channelNumber,index);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelMin",inpForm->ui->channelMin,index);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelNeutral",inpForm->ui->channelNeutral,index);
|
||||
addUAVObjectToWidgetRelation("ManualControlSettings","ChannelMax",inpForm->ui->channelMax,index);
|
||||
++index;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,926 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file configvehicletypewidget.cpp
|
||||
* @author E. Lafargue, K. Sebesta & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup ConfigPlugin Config Plugin
|
||||
* @{
|
||||
* @brief Airframe configuration panel
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "configvehicletypewidget.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtGui/QTextEdit>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
#include <QtGui/QPushButton>
|
||||
#include <math.h>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include "systemsettings.h"
|
||||
#include "mixersettings.h"
|
||||
#include "actuatorsettings.h"
|
||||
#include <QEventLoop>
|
||||
|
||||
/**
|
||||
Helper delegate for the custom mixer editor table.
|
||||
Taken straight from Qt examples, thanks!
|
||||
*/
|
||||
SpinBoxDelegate::SpinBoxDelegate(QObject *parent)
|
||||
: QItemDelegate(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem &/* option */,
|
||||
const QModelIndex &/* index */) const
|
||||
{
|
||||
QSpinBox *editor = new QSpinBox(parent);
|
||||
editor->setMinimum(-127);
|
||||
editor->setMaximum(127);
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
void SpinBoxDelegate::setEditorData(QWidget *editor,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
int value = index.model()->data(index, Qt::EditRole).toInt();
|
||||
|
||||
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
|
||||
spinBox->setValue(value);
|
||||
}
|
||||
|
||||
void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
|
||||
spinBox->interpretText();
|
||||
int value = spinBox->value();
|
||||
|
||||
model->setData(index, value, Qt::EditRole);
|
||||
}
|
||||
|
||||
void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
|
||||
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
|
||||
{
|
||||
editor->setGeometry(option.rect);
|
||||
}
|
||||
|
||||
/**********************************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
Constructor
|
||||
*/
|
||||
ConfigVehicleTypeWidget::ConfigVehicleTypeWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
{
|
||||
m_aircraft = new Ui_AircraftWidget();
|
||||
m_aircraft->setupUi(this);
|
||||
|
||||
addApplySaveButtons(m_aircraft->saveAircraftToRAM,m_aircraft->saveAircraftToSD);
|
||||
|
||||
addUAVObject("SystemSettings");
|
||||
addUAVObject("MixerSettings");
|
||||
addUAVObject("ActuatorSettings");
|
||||
|
||||
|
||||
ffTuningInProgress = false;
|
||||
ffTuningPhase = false;
|
||||
|
||||
//Generate list of channels
|
||||
QStringList channels;
|
||||
channels << "None";
|
||||
for (int i = 0; i < ActuatorSettings::CHANNELADDR_NUMELEM; i++) {
|
||||
mixerTypes << QString("Mixer%1Type").arg(i+1);
|
||||
mixerVectors << QString("Mixer%1Vector").arg(i+1);
|
||||
channels << QString("Channel%1").arg(i+1);
|
||||
}
|
||||
|
||||
QStringList airframeTypes;
|
||||
airframeTypes << "Fixed Wing" << "Multirotor" << "Helicopter" << "Ground" << "Custom";
|
||||
m_aircraft->aircraftType->addItems(airframeTypes);
|
||||
m_aircraft->aircraftType->setCurrentIndex(1);
|
||||
|
||||
QStringList fixedWingTypes;
|
||||
fixedWingTypes << "Elevator aileron rudder" << "Elevon" << "Vtail";
|
||||
m_aircraft->fixedWingType->addItems(fixedWingTypes);
|
||||
m_aircraft->fixedWingType->setCurrentIndex(0); //Set default model to "Elevator aileron rudder"
|
||||
|
||||
QStringList groundVehicleTypes;
|
||||
groundVehicleTypes << "Turnable (car)" << "Differential (tank)" << "Motorcycle";
|
||||
m_aircraft->groundVehicleType->addItems(groundVehicleTypes);
|
||||
m_aircraft->groundVehicleType->setCurrentIndex(0); //Set default model to "Turnable (car)"
|
||||
|
||||
QStringList multiRotorTypes;
|
||||
multiRotorTypes << "Tricopter Y"<< "Quad +" << "Quad X" <<
|
||||
"Hexacopter" << "Hexacopter X" << "Hexacopter Y6" <<
|
||||
"Octocopter" << "Octocopter V" << "Octo Coax +" << "Octo Coax X" ;
|
||||
m_aircraft->multirotorFrameType->addItems(multiRotorTypes);
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(1); //Set default model to "Quad +"
|
||||
|
||||
// Now load all the channel assignements
|
||||
//OLD STYLE: DO IT MANUALLY
|
||||
// m_aircraft->triYawChannelBox->addItems(channels);
|
||||
// m_aircraft->gvMotor1ChannelBox->addItems(channels);
|
||||
// m_aircraft->gvMotor2ChannelBox->addItems(channels);
|
||||
// m_aircraft->gvSteering1ChannelBox->addItems(channels);
|
||||
// m_aircraft->gvSteering2ChannelBox->addItems(channels);
|
||||
// m_aircraft->fwElevator1ChannelBox->addItems(channels);
|
||||
// m_aircraft->fwElevator2ChannelBox->addItems(channels);
|
||||
// m_aircraft->fwEngineChannelBox->addItems(channels);
|
||||
// m_aircraft->fwRudder1ChannelBox->addItems(channels);
|
||||
// m_aircraft->fwRudder2ChannelBox->addItems(channels);
|
||||
// m_aircraft->fwAileron1ChannelBox->addItems(channels);
|
||||
// m_aircraft->fwAileron2ChannelBox->addItems(channels);
|
||||
|
||||
//NEW STYLE: Loop through the widgets looking for all widgets that have "ChannelBox" in their name
|
||||
// The upshot of this is that ALL new ComboBox widgets for selecting the output channel must have "ChannelBox" in their name
|
||||
foreach(QComboBox *combobox, this->findChildren<QComboBox*>(QRegExp("\\S+ChannelBo\\S+")))//FOR WHATEVER REASON, THIS DOES NOT WORK WITH ChannelBox. ChannelBo is sufficiently accurate
|
||||
{
|
||||
combobox->addItems(channels);
|
||||
}
|
||||
|
||||
// Setup the Multirotor picture in the Quad settings interface
|
||||
m_aircraft->quadShape->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_aircraft->quadShape->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
QSvgRenderer *renderer = new QSvgRenderer();
|
||||
renderer->load(QString(":/configgadget/images/quad-shapes.svg"));
|
||||
quad = new QGraphicsSvgItem();
|
||||
quad->setSharedRenderer(renderer);
|
||||
quad->setElementId("quad-plus");
|
||||
QGraphicsScene *scene = new QGraphicsScene(this);
|
||||
scene->addItem(quad);
|
||||
scene->setSceneRect(quad->boundingRect());
|
||||
m_aircraft->quadShape->setScene(scene);
|
||||
|
||||
// Put combo boxes in line one of the custom mixer table:
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("Mixer1Type"));
|
||||
QStringList list = field->getOptions();
|
||||
for (int i=0;i<8;i++) {
|
||||
QComboBox* qb = new QComboBox(m_aircraft->customMixerTable);
|
||||
qb->addItems(list);
|
||||
m_aircraft->customMixerTable->setCellWidget(0,i,qb);
|
||||
}
|
||||
|
||||
SpinBoxDelegate *sbd = new SpinBoxDelegate();
|
||||
for (int i=1;i<8; i++) {
|
||||
m_aircraft->customMixerTable->setItemDelegateForRow(i, sbd);
|
||||
}
|
||||
|
||||
//Connect aircraft type selection dropbox to callback function
|
||||
connect(m_aircraft->aircraftType, SIGNAL(currentIndexChanged(int)), this, SLOT(switchAirframeType(int)));
|
||||
|
||||
//Connect airframe selection dropbox to callback functions
|
||||
connect(m_aircraft->fixedWingType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString)));
|
||||
connect(m_aircraft->multirotorFrameType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString)));
|
||||
connect(m_aircraft->groundVehicleType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString)));
|
||||
|
||||
//Connect throttle curve reset pushbuttons to reset functions
|
||||
connect(m_aircraft->fwThrottleReset, SIGNAL(clicked()), this, SLOT(resetFwMixer()));
|
||||
connect(m_aircraft->mrThrottleCurveReset, SIGNAL(clicked()), this, SLOT(resetMrMixer()));
|
||||
connect(m_aircraft->gvThrottleCurve1Reset, SIGNAL(clicked()), this, SLOT(resetGvFrontMixer()));
|
||||
connect(m_aircraft->gvThrottleCurve2Reset, SIGNAL(clicked()), this, SLOT(resetGvRearMixer()));
|
||||
connect(m_aircraft->customReset1, SIGNAL(clicked()), this, SLOT(resetCt1Mixer()));
|
||||
connect(m_aircraft->customReset2, SIGNAL(clicked()), this, SLOT(resetCt2Mixer()));
|
||||
|
||||
//Connect throttle curve manipulation points to output text
|
||||
connect(m_aircraft->fixedWingThrottle, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateFwThrottleCurveValue(QList<double>,double)));
|
||||
connect(m_aircraft->multiThrottleCurve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateMrThrottleCurveValue(QList<double>,double)));
|
||||
connect(m_aircraft->groundVehicleThrottle1, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateGvThrottle1CurveValue(QList<double>,double)));
|
||||
connect(m_aircraft->groundVehicleThrottle2, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateGvThrottle2CurveValue(QList<double>,double)));
|
||||
connect(m_aircraft->customThrottle1Curve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateCustomThrottle1CurveValue(QList<double>,double)));
|
||||
connect(m_aircraft->customThrottle2Curve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateCustomThrottle2CurveValue(QList<double>,double)));
|
||||
|
||||
// connect(m_aircraft->fwAileron1Channel, SIGNAL(currentIndexChanged(int)), this, SLOT(toggleAileron2(int)));
|
||||
// connect(m_aircraft->fwElevator1Channel, SIGNAL(currentIndexChanged(int)), this, SLOT(toggleElevator2(int)));
|
||||
|
||||
//Connect the three feed forward test checkboxes
|
||||
connect(m_aircraft->ffTestBox1, SIGNAL(clicked(bool)), this, SLOT(enableFFTest()));
|
||||
connect(m_aircraft->ffTestBox2, SIGNAL(clicked(bool)), this, SLOT(enableFFTest()));
|
||||
connect(m_aircraft->ffTestBox3, SIGNAL(clicked(bool)), this, SLOT(enableFFTest()));
|
||||
|
||||
//WHAT DOES THIS DO?
|
||||
enableControls(false);
|
||||
refreshWidgetsValues();
|
||||
|
||||
// Connect the help pushbutton
|
||||
connect(m_aircraft->airframeHelp, SIGNAL(clicked()), this, SLOT(openHelp()));
|
||||
addToDirtyMonitor();
|
||||
|
||||
//Initialize GUI tabs //MOVING THIS FROM THE END OF THIS FUNCTION CAN CAUSE RUNTIME ERRORS DUE TO setupMultiRotorUI. WHY?
|
||||
setupMultiRotorUI( m_aircraft->multirotorFrameType->currentText() );
|
||||
setupGroundVehicleUI( m_aircraft->groundVehicleType->currentText() );
|
||||
setupFixedWingUI( m_aircraft->fixedWingType->currentText() );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
ConfigVehicleTypeWidget::~ConfigVehicleTypeWidget()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Slot for switching the airframe type. We do it explicitely
|
||||
rather than a signal in the UI, because we want to force a fitInView of the quad shapes.
|
||||
This is because this method (fitinview) only works when the widget is shown.
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::switchAirframeType(int index){
|
||||
m_aircraft->airframesWidget->setCurrentIndex(index);
|
||||
m_aircraft->quadShape->setSceneRect(quad->boundingRect());
|
||||
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
|
||||
if (m_aircraft->aircraftType->findText("Custom")) {
|
||||
m_aircraft->customMixerTable->resizeColumnsToContents();
|
||||
for (int i=0;i<8;i++) {
|
||||
m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()-
|
||||
m_aircraft->customMixerTable->verticalHeader()->width())/8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
WHAT DOES THIS DO???
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
// Thit fitInView method should only be called now, once the
|
||||
// widget is shown, otherwise it cannot compute its values and
|
||||
// the result is usually a ahrsbargraph that is way too small.
|
||||
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
|
||||
m_aircraft->customMixerTable->resizeColumnsToContents();
|
||||
for (int i=0;i<8;i++) {
|
||||
m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()-
|
||||
m_aircraft->customMixerTable->verticalHeader()->width())/8);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Resize the GUI contents when the user changes the window size
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
|
||||
// Make the custom table columns autostretch:
|
||||
m_aircraft->customMixerTable->resizeColumnsToContents();
|
||||
for (int i=0;i<8;i++) {
|
||||
m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()-
|
||||
m_aircraft->customMixerTable->verticalHeader()->width())/8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ConfigVehicleTypeWidget::toggleAileron2(int index)
|
||||
{
|
||||
if (index) {
|
||||
m_aircraft->fwAileron2ChannelBox->setEnabled(true);
|
||||
m_aircraft->fwAileron2Label->setEnabled(true);
|
||||
} else {
|
||||
m_aircraft->fwAileron2ChannelBox->setEnabled(false);
|
||||
m_aircraft->fwAileron2Label->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigVehicleTypeWidget::toggleElevator2(int index)
|
||||
{
|
||||
if (index) {
|
||||
m_aircraft->fwElevator2ChannelBox->setEnabled(true);
|
||||
m_aircraft->fwElevator2Label->setEnabled(true);
|
||||
} else {
|
||||
m_aircraft->fwElevator2ChannelBox->setEnabled(false);
|
||||
m_aircraft->fwElevator2Label->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigVehicleTypeWidget::toggleRudder2(int index)
|
||||
{
|
||||
if (index) {
|
||||
m_aircraft->fwRudder2ChannelBox->setEnabled(true);
|
||||
m_aircraft->fwRudder2Label->setEnabled(true);
|
||||
} else {
|
||||
m_aircraft->fwRudder2ChannelBox->setEnabled(false);
|
||||
m_aircraft->fwRudder2Label->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
/// Feed Forward Testing
|
||||
/////////////////////////////////////////////////////////
|
||||
/**
|
||||
Enables and runs feed forward testing
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::enableFFTest()
|
||||
{
|
||||
// Role:
|
||||
// - Check if all three checkboxes are checked
|
||||
// - Every other timer event: toggle engine from 45% to 55%
|
||||
// - Every other time event: send FF settings to flight FW
|
||||
if (m_aircraft->ffTestBox1->isChecked() &&
|
||||
m_aircraft->ffTestBox2->isChecked() &&
|
||||
m_aircraft->ffTestBox3->isChecked()) {
|
||||
if (!ffTuningInProgress)
|
||||
{
|
||||
// Initiate tuning:
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlCommand")));
|
||||
UAVObject::Metadata mdata = obj->getMetadata();
|
||||
accInitialData = mdata;
|
||||
mdata.flightAccess = UAVObject::ACCESS_READONLY;
|
||||
obj->setMetadata(mdata);
|
||||
}
|
||||
// Depending on phase, either move actuator or send FF settings:
|
||||
if (ffTuningPhase) {
|
||||
// Send FF settings to the board
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("FeedForward"));
|
||||
field->setDouble((double)m_aircraft->feedForwardSlider->value()/100);
|
||||
field = obj->getField(QString("AccelTime"));
|
||||
field->setDouble(m_aircraft->accelTime->value());
|
||||
field = obj->getField(QString("DecelTime"));
|
||||
field->setDouble(m_aircraft->decelTime->value());
|
||||
field = obj->getField(QString("MaxAccel"));
|
||||
field->setDouble(m_aircraft->maxAccelSlider->value());
|
||||
obj->updated();
|
||||
} else {
|
||||
// Toggle motor state
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlCommand")));
|
||||
double value = obj->getField("Throttle")->getDouble();
|
||||
double target = (value < 0.5) ? 0.55 : 0.45;
|
||||
obj->getField("Throttle")->setValue(target);
|
||||
obj->updated();
|
||||
}
|
||||
ffTuningPhase = !ffTuningPhase;
|
||||
ffTuningInProgress = true;
|
||||
QTimer::singleShot(1000, this, SLOT(enableFFTest()));
|
||||
} else {
|
||||
// - If no: disarm timer, restore actuatorcommand metadata
|
||||
// Disarm!
|
||||
if (ffTuningInProgress) {
|
||||
ffTuningInProgress = false;
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlCommand")));
|
||||
UAVObject::Metadata mdata = obj->getMetadata();
|
||||
mdata = accInitialData; // Restore metadata
|
||||
obj->setMetadata(mdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Resets Fixed wing throttle mixer
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::resetFwMixer()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
||||
resetMixer(m_aircraft->fixedWingThrottle, field->getNumElements(),1);
|
||||
}
|
||||
|
||||
/**
|
||||
Resets Multirotor throttle mixer
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::resetMrMixer()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
||||
resetMixer(m_aircraft->multiThrottleCurve, field->getNumElements(),0.9);
|
||||
}
|
||||
|
||||
/**
|
||||
Resets Ground vehicle front throttle mixer
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::resetGvFrontMixer()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
||||
resetMixer(m_aircraft->groundVehicleThrottle1, field->getNumElements(),1);
|
||||
}
|
||||
|
||||
/**
|
||||
Resets Ground vehicle rear throttle mixer
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::resetGvRearMixer()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("ThrottleCurve2"));
|
||||
resetMixer(m_aircraft->groundVehicleThrottle2, field->getNumElements(),1);
|
||||
}
|
||||
|
||||
/**
|
||||
Resets Custom throttle 1 mixer
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::resetCt1Mixer()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
||||
resetMixer(m_aircraft->customThrottle1Curve, field->getNumElements(),1);
|
||||
}
|
||||
|
||||
/**
|
||||
Resets Custom throttle 2 mixer
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::resetCt2Mixer()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("ThrottleCurve2"));
|
||||
resetMixer(m_aircraft->customThrottle2Curve, field->getNumElements(),1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Resets a mixer curve
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::resetMixer(MixerCurveWidget *mixer, int numElements, double maxvalue)
|
||||
{
|
||||
// Setup all Throttle1 curves for all types of airframes
|
||||
mixer->initLinearCurve((quint32)numElements,maxvalue);
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the currently moved fixed wing throttle curve item value
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::updateFwThrottleCurveValue(QList<double> list, double value)
|
||||
{
|
||||
Q_UNUSED(list);
|
||||
m_aircraft->fwThrottleCurveItemValue->setText(QString().sprintf("Val: %.2f",value));
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the currently moved multi-rotor throttle curve item value
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::updateMrThrottleCurveValue(QList<double> list, double value)
|
||||
{
|
||||
Q_UNUSED(list);
|
||||
m_aircraft->mrThrottleCurveItemValue->setText(QString().sprintf("Val: %.2f",value));
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the moved ground vehicle front throttle curve item value
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::updateGvThrottle1CurveValue(QList<double> list, double value)
|
||||
{
|
||||
Q_UNUSED(list);
|
||||
m_aircraft->gvThrottleCurve1ItemValue->setText(QString().sprintf("Val: %.2f",value));
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the moved ground vehicle rear throttle curve item value
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::updateGvThrottle2CurveValue(QList<double> list, double value)
|
||||
{
|
||||
Q_UNUSED(list);
|
||||
m_aircraft->gvThrottleCurve2ItemValue->setText(QString().sprintf("Val: %.2f",value));
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the currently moved custom throttle curve item value (Custom throttle 1)
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::updateCustomThrottle1CurveValue(QList<double> list, double value)
|
||||
{
|
||||
Q_UNUSED(list);
|
||||
m_aircraft->customThrottleCurve1Value->setText(QString().sprintf("Val: %.2f",value));
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the currently moved custom throttle curve item value (Custom throttle 2)
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::updateCustomThrottle2CurveValue(QList<double> list, double value)
|
||||
{
|
||||
Q_UNUSED(list);
|
||||
m_aircraft->customThrottleCurve2Value->setText(QString().sprintf("Val: %.2f",value));
|
||||
}
|
||||
|
||||
|
||||
/**************************
|
||||
* Aircraft settings
|
||||
**************************/
|
||||
/**
|
||||
Refreshes the current value of the SystemSettings which holds the aircraft type
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::refreshWidgetsValues()
|
||||
{
|
||||
if(!allObjectsUpdated())
|
||||
return;
|
||||
|
||||
//WHAT DOES THIS DO?
|
||||
bool dirty=isDirty(); //WHY IS THIS CALLED HERE AND THEN AGAIN SEVERAL LINES LATER IN setupAirframeUI()
|
||||
|
||||
// Get the Airframe type from the system settings:
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("SystemSettings")));
|
||||
Q_ASSERT(obj);
|
||||
UAVObjectField *field = obj->getField(QString("AirframeType"));
|
||||
Q_ASSERT(field);
|
||||
// At this stage, we will need to have some hardcoded settings in this code, this
|
||||
// is not ideal, but here you go.
|
||||
QString frameType = field->getValue().toString();
|
||||
setupAirframeUI(frameType);
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
field = obj->getField(QString("ThrottleCurve1"));
|
||||
Q_ASSERT(field);
|
||||
QList<double> curveValues;
|
||||
// If the 1st element of the curve is <= -10, then the curve
|
||||
// is a straight line (that's how the mixer works on the mainboard):
|
||||
if (field->getValue(0).toInt() <= -10) {
|
||||
m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),(double)1);
|
||||
m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1);
|
||||
m_aircraft->groundVehicleThrottle1->initLinearCurve(field->getNumElements(),(double)1);
|
||||
}
|
||||
else {
|
||||
double temp=0;
|
||||
double value;
|
||||
for (unsigned int i=0; i < field->getNumElements(); i++) {
|
||||
value=field->getValue(i).toDouble();
|
||||
temp+=value;
|
||||
curveValues.append(value);
|
||||
}
|
||||
if(temp==0)
|
||||
{
|
||||
m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),0.9);
|
||||
m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1);
|
||||
m_aircraft->groundVehicleThrottle1->initLinearCurve(field->getNumElements(),(double)1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_aircraft->multiThrottleCurve->initCurve(curveValues);
|
||||
m_aircraft->fixedWingThrottle->initCurve(curveValues);
|
||||
m_aircraft->groundVehicleThrottle1->initCurve(curveValues);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup all Throttle2 curves for all types of airframes //AT THIS MOMENT, THAT MEANS ONLY GROUND VEHICLES
|
||||
Q_ASSERT(obj);
|
||||
field = obj->getField(QString("ThrottleCurve2"));
|
||||
Q_ASSERT(field);
|
||||
curveValues.clear();
|
||||
// If the 1st element of the curve is <= -10, then the curve
|
||||
// is a straight line (that's how the mixer works on the mainboard):
|
||||
if (field->getValue(0).toInt() <= -10) {
|
||||
m_aircraft->groundVehicleThrottle2->initLinearCurve(field->getNumElements(),(double)1);
|
||||
}
|
||||
else {
|
||||
double temp=0;
|
||||
double value;
|
||||
for (unsigned int i=0; i < field->getNumElements(); i++) {
|
||||
value=field->getValue(i).toDouble();
|
||||
temp+=value;
|
||||
curveValues.append(value);
|
||||
}
|
||||
if(temp==0)
|
||||
{
|
||||
m_aircraft->groundVehicleThrottle2->initLinearCurve(field->getNumElements(),(double)1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_aircraft->groundVehicleThrottle2->initCurve(curveValues);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the Settings for fixed wing frames:
|
||||
if (frameType.startsWith("FixedWing")) {
|
||||
|
||||
// Retrieve fixed wing settings
|
||||
refreshFixedWingWidgetsValues(frameType);
|
||||
|
||||
} else if (frameType == "Tri" ||
|
||||
frameType == "QuadX" || frameType == "QuadP" ||
|
||||
frameType == "Hexa" || frameType == "HexaCoax" || frameType == "HexaX" ||
|
||||
frameType == "Octo" || frameType == "OctoV" || frameType == "OctoCoaxP" || frameType == "OctoCoaxX" ) {
|
||||
|
||||
// Retrieve multirotor settings
|
||||
refreshMultiRotorWidgetsValues(frameType);
|
||||
} else if (frameType == "HeliCP") {
|
||||
m_aircraft->widget_3->requestccpmUpdate();
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Helicopter"));//"Helicopter"
|
||||
} else if (frameType.startsWith("GroundVehicle")) {
|
||||
|
||||
// Retrieve ground vehicle settings
|
||||
refreshGroundVehicleWidgetsValues(frameType);
|
||||
|
||||
} else if (frameType == "Custom") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Custom"));
|
||||
}
|
||||
|
||||
|
||||
updateCustomAirframeUI();
|
||||
setDirty(dirty);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Sets up the mixer depending on Airframe type. Accepts either system settings or
|
||||
combo box entry from airframe type, as those do not overlap.
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::setupAirframeUI(QString frameType)
|
||||
{
|
||||
|
||||
bool dirty=isDirty();
|
||||
if(frameType == "FixedWing" || frameType == "Elevator aileron rudder" ||
|
||||
frameType == "FixedWingElevon" || frameType == "Elevon" ||
|
||||
frameType == "FixedWingVtail" || frameType == "Vtail"){
|
||||
setupFixedWingUI(frameType);
|
||||
} else if (frameType == "Tri" || frameType == "Tricopter Y" ||
|
||||
frameType == "QuadX" || frameType == "Quad X" ||
|
||||
frameType == "QuadP" || frameType == "Quad +" ||
|
||||
frameType == "Hexa" || frameType == "Hexacopter" ||
|
||||
frameType == "HexaX" || frameType == "Hexacopter X" ||
|
||||
frameType == "HexaCoax" || frameType == "Hexacopter Y6" ||
|
||||
frameType == "Octo" || frameType == "Octocopter" ||
|
||||
frameType == "OctoV" || frameType == "Octocopter V" ||
|
||||
frameType == "OctoCoaxP" || frameType == "Octo Coax +" ) {
|
||||
|
||||
//Call multi-rotor setup UI
|
||||
setupMultiRotorUI(frameType);
|
||||
}
|
||||
else if (frameType == "GroundVehicleCar" || frameType == "Turnable (car)" ||
|
||||
frameType == "GroundVehicleDifferential" || frameType == "Differential (tank)" ||
|
||||
frameType == "GroundVehicleMotorcyle" || frameType == "Motorcycle") {
|
||||
setupGroundVehicleUI(frameType);
|
||||
}
|
||||
|
||||
//SHOULDN'T THIS BE DONE ONLY IN QUAD SETUP, AND NOT ALL THE REST???
|
||||
m_aircraft->quadShape->setSceneRect(quad->boundingRect());
|
||||
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
|
||||
|
||||
setDirty(dirty);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Reset the contents of a field
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::resetField(UAVObjectField * field)
|
||||
{
|
||||
for (unsigned int i=0;i<field->getNumElements();i++) {
|
||||
field->setValue(0,i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Reset actuator values
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::resetActuators()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
QList<UAVObjectField*> fieldList = obj->getFields();
|
||||
// Reset all assignements first:
|
||||
foreach (UAVObjectField* field, fieldList) {
|
||||
// NOTE: we assume that all options in ActuatorSettings are a channel assignement
|
||||
// except for the options called "ChannelBoxXXX"
|
||||
if (field->getUnits().contains("channel")) {
|
||||
field->setValue(field->getOptions().last());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Updates the custom airframe settings based on the current airframe.
|
||||
|
||||
Note: does NOT ask for an object refresh itself!
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::updateCustomAirframeUI()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
||||
QList<double> curveValues;
|
||||
// If the 1st element of the curve is <= -10, then the curve
|
||||
// is a straight line (that's how the mixer works on the mainboard):
|
||||
if (field->getValue(0).toInt() <= -10) {
|
||||
m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1);
|
||||
} else {
|
||||
double temp=0;
|
||||
double value;
|
||||
for (unsigned int i=0; i < field->getNumElements(); i++) {
|
||||
value=field->getValue(i).toDouble();
|
||||
temp+=value;
|
||||
curveValues.append(value);
|
||||
}
|
||||
if(temp==0)
|
||||
m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1);
|
||||
else
|
||||
m_aircraft->customThrottle1Curve->initCurve(curveValues);
|
||||
}
|
||||
|
||||
field = obj->getField(QString("ThrottleCurve2"));
|
||||
curveValues.clear();
|
||||
// If the 1st element of the curve is <= -10, then the curve
|
||||
// is a straight line (that's how the mixer works on the mainboard):
|
||||
if (field->getValue(0).toInt() <= -10) {
|
||||
m_aircraft->customThrottle2Curve->initLinearCurve(field->getNumElements(),(double)1);
|
||||
} else {
|
||||
for (unsigned int i=0; i < field->getNumElements(); i++) {
|
||||
curveValues.append(field->getValue(i).toDouble());
|
||||
}
|
||||
m_aircraft->customThrottle2Curve->initCurve(curveValues);
|
||||
}
|
||||
|
||||
// Update the table:
|
||||
for (int i=0; i<8; i++) {
|
||||
field = obj->getField(mixerTypes.at(i));
|
||||
QComboBox* q = (QComboBox*)m_aircraft->customMixerTable->cellWidget(0,i);
|
||||
QString s = field->getValue().toString();
|
||||
q->setCurrentIndex(q->findText(s));
|
||||
//bool en = (s != "Disabled");
|
||||
field = obj->getField(mixerVectors.at(i));
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
m_aircraft->customMixerTable->item(1,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2");
|
||||
m_aircraft->customMixerTable->item(2,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
m_aircraft->customMixerTable->item(3,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
m_aircraft->customMixerTable->item(4,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
m_aircraft->customMixerTable->item(5,i)->setText(field->getValue(ti).toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Sends the config to the board (airframe type)
|
||||
|
||||
We do all the tasks common to all airframes, or family of airframes, and
|
||||
we call additional methods for specific frames, so that we do not have a code
|
||||
that is too heavy.
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::updateObjectsFromWidgets()
|
||||
{
|
||||
qDebug()<<"updateObjectsFromWidgets";
|
||||
QString airframeType = "Custom"; //Sets airframe type default to "Custom"
|
||||
if (m_aircraft->aircraftType->currentText() == "Fixed Wing") {
|
||||
airframeType = updateFixedWingObjectsFromWidgets();
|
||||
} else if (m_aircraft->aircraftType->currentText() == "Multirotor") {
|
||||
//update the mixer
|
||||
airframeType = updateMultiRotorObjectsFromWidgets();
|
||||
} else if (m_aircraft->aircraftType->currentText() == "Helicopter") {
|
||||
airframeType = "HeliCP";
|
||||
m_aircraft->widget_3->sendccpmUpdate();
|
||||
} else if (m_aircraft->aircraftType->currentText() == "Ground") {
|
||||
airframeType = updateGroundVehicleObjectsFromWidgets();
|
||||
} else {
|
||||
airframeType = "Custom";
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("FeedForward"));
|
||||
|
||||
// Curve is also common to all quads:
|
||||
field = obj->getField("ThrottleCurve1");
|
||||
QList<double> curve = m_aircraft->customThrottle1Curve->getCurve();
|
||||
for (int i=0;i<curve.length();i++) {
|
||||
field->setValue(curve.at(i),i);
|
||||
}
|
||||
|
||||
field = obj->getField("ThrottleCurve2");
|
||||
curve.clear();
|
||||
curve = m_aircraft->customThrottle2Curve->getCurve();
|
||||
for (int i=0;i<curve.length();i++) {
|
||||
field->setValue(curve.at(i),i);
|
||||
}
|
||||
|
||||
// Update the table:
|
||||
for (int i=0; i<8; i++) {
|
||||
field = obj->getField(mixerTypes.at(i));
|
||||
QComboBox* q = (QComboBox*)m_aircraft->customMixerTable->cellWidget(0,i);
|
||||
field->setValue(q->currentText());
|
||||
field = obj->getField(mixerVectors.at(i));
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(m_aircraft->customMixerTable->item(1,i)->text(),ti);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2");
|
||||
field->setValue(m_aircraft->customMixerTable->item(2,i)->text(),ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(m_aircraft->customMixerTable->item(3,i)->text(),ti);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(m_aircraft->customMixerTable->item(4,i)->text(),ti);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(m_aircraft->customMixerTable->item(5,i)->text(),ti);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//WHAT DOES THIS DO?
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("SystemSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("AirframeType"));
|
||||
field->setValue(airframeType);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Opens the wiki from the user's default browser
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::openHelp()
|
||||
{
|
||||
|
||||
QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Airframe+configuration", QUrl::StrictMode) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
WHAT DOES THIS DO???
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::addToDirtyMonitor()
|
||||
{
|
||||
addWidget(m_aircraft->customMixerTable);
|
||||
addWidget(m_aircraft->customThrottle1Curve);
|
||||
addWidget(m_aircraft->customThrottle2Curve);
|
||||
addWidget(m_aircraft->multiThrottleCurve);
|
||||
addWidget(m_aircraft->fixedWingThrottle);
|
||||
addWidget(m_aircraft->fixedWingType);
|
||||
addWidget(m_aircraft->groundVehicleThrottle1);
|
||||
addWidget(m_aircraft->groundVehicleThrottle2);
|
||||
addWidget(m_aircraft->groundVehicleType);
|
||||
addWidget(m_aircraft->feedForwardSlider);
|
||||
addWidget(m_aircraft->accelTime);
|
||||
addWidget(m_aircraft->decelTime);
|
||||
addWidget(m_aircraft->maxAccelSlider);
|
||||
addWidget(m_aircraft->multirotorFrameType);
|
||||
addWidget(m_aircraft->multiMotorChannelBox1);
|
||||
addWidget(m_aircraft->multiMotorChannelBox2);
|
||||
addWidget(m_aircraft->multiMotorChannelBox3);
|
||||
addWidget(m_aircraft->multiMotorChannelBox4);
|
||||
addWidget(m_aircraft->multiMotorChannelBox5);
|
||||
addWidget(m_aircraft->multiMotorChannelBox6);
|
||||
addWidget(m_aircraft->multiMotorChannelBox7);
|
||||
addWidget(m_aircraft->multiMotorChannelBox8);
|
||||
addWidget(m_aircraft->triYawChannelBox);
|
||||
addWidget(m_aircraft->aircraftType);
|
||||
addWidget(m_aircraft->fwEngineChannelBox);
|
||||
addWidget(m_aircraft->fwAileron1ChannelBox);
|
||||
addWidget(m_aircraft->fwAileron2ChannelBox);
|
||||
addWidget(m_aircraft->fwElevator1ChannelBox);
|
||||
addWidget(m_aircraft->fwElevator2ChannelBox);
|
||||
addWidget(m_aircraft->fwRudder1ChannelBox);
|
||||
addWidget(m_aircraft->fwRudder2ChannelBox);
|
||||
addWidget(m_aircraft->elevonSlider1);
|
||||
addWidget(m_aircraft->elevonSlider2);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmType);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmTailChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmEngineChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoWChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoXChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoYChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmSingleServo);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoZChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleW);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleX);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCorrectionAngle);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleZ);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleY);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivePassthrough);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkRoll);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkCyclic);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRevoSlider);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmREVOspinBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveSlider);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivespinBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScaleBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCyclicScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScaleBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScaleBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSlider);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSpinBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveType);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->NumCurvePoints);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue1);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue2);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue3);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveToGenerate);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveSettings);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ThrottleCurve);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->PitchCurve);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAdvancedSettingsTable);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
*
|
||||
* @file configairframetwidget.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup ConfigPlugin Config Plugin
|
||||
@ -24,8 +24,8 @@
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef CONFIGAIRFRAMEWIDGET_H
|
||||
#define CONFIGAIRFRAMEWIDGET_H
|
||||
#ifndef CONFIGVEHICLETYPEWIDGET_H
|
||||
#define CONFIGVEHICLETYPEWIDGET_H
|
||||
|
||||
#include "ui_airframe.h"
|
||||
#include "../uavobjectwidgetutils/configtaskwidget.h"
|
||||
@ -39,24 +39,27 @@
|
||||
|
||||
class Ui_Widget;
|
||||
|
||||
class ConfigAirframeWidget: public ConfigTaskWidget
|
||||
class ConfigVehicleTypeWidget: public ConfigTaskWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ConfigAirframeWidget(QWidget *parent = 0);
|
||||
~ConfigAirframeWidget();
|
||||
ConfigVehicleTypeWidget(QWidget *parent = 0);
|
||||
~ConfigVehicleTypeWidget();
|
||||
|
||||
private:
|
||||
Ui_AircraftWidget *m_aircraft;
|
||||
bool setupFrameFixedWing();
|
||||
bool setupFrameElevon();
|
||||
bool setupFrameVtail();
|
||||
bool setupFrameFixedWing(QString airframeType);
|
||||
bool setupFrameElevon(QString airframeType);
|
||||
bool setupFrameVtail(QString airframeType);
|
||||
bool setupQuad(bool pLayout);
|
||||
bool setupHexa(bool pLayout);
|
||||
bool setupOcto();
|
||||
bool setupGroundVehicleCar(QString airframeType);
|
||||
bool setupGroundVehicleDifferential(QString airframeType);
|
||||
bool setupGroundVehicleMotorcycle(QString airframeType);
|
||||
void updateCustomAirframeUI();
|
||||
bool setupMixer(double mixerFactors[8][3]);
|
||||
bool setupMultiRotorMixer(double mixerFactors[8][3]);
|
||||
void setupMotors(QList<QString> motorList);
|
||||
void addToDirtyMonitor();
|
||||
void resetField(UAVObjectField * field);
|
||||
@ -74,19 +77,39 @@ private:
|
||||
|
||||
private slots:
|
||||
virtual void refreshWidgetsValues();
|
||||
void refreshFixedWingWidgetsValues(QString frameType);
|
||||
void refreshMultiRotorWidgetsValues(QString frameType);
|
||||
void refreshGroundVehicleWidgetsValues(QString frameType);
|
||||
|
||||
void updateObjectsFromWidgets();
|
||||
QString updateFixedWingObjectsFromWidgets();
|
||||
QString updateMultiRotorObjectsFromWidgets();
|
||||
QString updateGroundVehicleObjectsFromWidgets();
|
||||
// void saveAircraftUpdate();
|
||||
|
||||
void setupAirframeUI(QString type);
|
||||
void setupFixedWingUI(QString frameType);
|
||||
void setupMultiRotorUI(QString frameType);
|
||||
void setupGroundVehicleUI(QString frameType);
|
||||
|
||||
void throwMultiRotorChannelConfigError(int numMotors);
|
||||
void throwFixedWingChannelConfigError(QString airframeType);
|
||||
void throwGroundVehicleChannelConfigError(QString airframeType);
|
||||
|
||||
void toggleAileron2(int index);
|
||||
void toggleElevator2(int index);
|
||||
void toggleRudder2(int index);
|
||||
void switchAirframeType(int index);
|
||||
void resetFwMixer();
|
||||
void resetMrMixer();
|
||||
void resetGvFrontMixer();
|
||||
void resetGvRearMixer();
|
||||
void resetCt1Mixer();
|
||||
void resetCt2Mixer();
|
||||
void updateFwThrottleCurveValue(QList<double> list, double value);
|
||||
void updateMrThrottleCurveValue(QList<double> list, double value);
|
||||
void updateGvThrottle1CurveValue(QList<double> list, double value);
|
||||
void updateGvThrottle2CurveValue(QList<double> list, double value);
|
||||
void updateCustomThrottle1CurveValue(QList<double> list, double value);
|
||||
void updateCustomThrottle2CurveValue(QList<double> list, double value);
|
||||
void enableFFTest();
|
||||
@ -117,4 +140,4 @@ public:
|
||||
const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
};
|
||||
|
||||
#endif // CONFIGAIRFRAMEWIDGET_H
|
||||
#endif // CONFIGVEHICLETYPEWIDGET_H
|
@ -8,6 +8,8 @@ inputChannelForm::inputChannelForm(QWidget *parent,bool showlegend) :
|
||||
ui(new Ui::inputChannelForm)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
//The first time through the loop, keep the legend. All other times, delete it.
|
||||
if(!showlegend)
|
||||
{
|
||||
layout()->removeWidget(ui->legend0);
|
||||
|
@ -37,7 +37,7 @@
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>0</height>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
@ -53,6 +53,12 @@
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
@ -63,6 +69,12 @@
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QSpinBox" name="channelMin">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
@ -76,6 +88,12 @@
|
||||
</item>
|
||||
<item row="2" column="8">
|
||||
<widget class="QSpinBox" name="channelMax">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
@ -93,11 +111,17 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
@ -126,11 +150,17 @@ font:bold;</string>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
@ -159,11 +189,17 @@ font:bold;</string>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
@ -192,11 +228,17 @@ font:bold;</string>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
@ -227,6 +269,12 @@ font:bold;</string>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -240,6 +288,12 @@ font:bold;</string>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
@ -269,6 +323,12 @@ font:bold;</string>
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Rev</string>
|
||||
</property>
|
||||
@ -277,14 +337,14 @@ font:bold;</string>
|
||||
<item row="2" column="9">
|
||||
<widget class="QLabel" name="neutral">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<width>35</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
@ -331,50 +391,23 @@ font:bold;</string>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="legend2">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<italic>false</italic>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255));
|
||||
color: rgb(255, 255, 255);
|
||||
border-radius: 5;
|
||||
margin:5px;
|
||||
font:bold;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Number</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="legend1">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
@ -397,6 +430,45 @@ font:bold;</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="legend2">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<italic>false</italic>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255));
|
||||
color: rgb(255, 255, 255);
|
||||
border-radius: 5;
|
||||
margin:5px;
|
||||
font:bold;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Number</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
@ -1,31 +1,35 @@
|
||||
<xml>
|
||||
<object name="ActuatorSettings" singleinstance="true" settings="true">
|
||||
<description>Settings for the @ref ActuatorModule that controls the channel assignments for the mixer based on AircraftType</description>
|
||||
<field name="FixedWingRoll1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingRoll2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingPitch1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingPitch2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingYaw1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingYaw2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingThrottle" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorN" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorNE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorSE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorS" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorSW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorNW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="ChannelUpdateFreq" units="Hz" type="uint16" elements="4" defaultvalue="50"/>
|
||||
<field name="ChannelMax" units="us" type="int16" elements="10" defaultvalue="1000"/>
|
||||
<field name="ChannelNeutral" units="us" type="int16" elements="10" defaultvalue="1000"/>
|
||||
<field name="ChannelMin" units="us" type="int16" elements="10" defaultvalue="1000"/>
|
||||
<field name="ChannelType" units="" type="enum" elements="10" options="PWM,MK,ASTEC4,PWM Alarm Buzzer" defaultvalue="PWM"/>
|
||||
<field name="ChannelAddr" units="" type="uint8" elements="10" defaultvalue="0,1,2,3,4,5,6,7,8,9"/>
|
||||
<field name="MotorsSpinWhileArmed" units="" type="enum" elements="1" options="FALSE,TRUE" defaultvalue="FALSE"/>
|
||||
<access gcs="readwrite" flight="readwrite"/>
|
||||
<telemetrygcs acked="true" updatemode="onchange" period="0"/>
|
||||
<telemetryflight acked="true" updatemode="onchange" period="0"/>
|
||||
<logging updatemode="never" period="0"/>
|
||||
</object>
|
||||
</xml>
|
||||
<xml>
|
||||
<object name="ActuatorSettings" singleinstance="true" settings="true">
|
||||
<description>Settings for the @ref ActuatorModule that controls the channel assignments for the mixer based on AircraftType</description>
|
||||
<field name="FixedWingRoll1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingRoll2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingPitch1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingPitch2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingYaw1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingYaw2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingThrottle" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorN" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorNE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorSE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorS" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorSW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorNW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="GroundVehicleThrottle1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="GroundVehicleThrottle2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="GroundVehicleSteering1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="GroundVehicleSteering2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="ChannelUpdateFreq" units="Hz" type="uint16" elements="4" defaultvalue="50"/>
|
||||
<field name="ChannelMax" units="us" type="int16" elements="10" defaultvalue="1000"/>
|
||||
<field name="ChannelNeutral" units="us" type="int16" elements="10" defaultvalue="1000"/>
|
||||
<field name="ChannelMin" units="us" type="int16" elements="10" defaultvalue="1000"/>
|
||||
<field name="ChannelType" units="" type="enum" elements="10" options="PWM,MK,ASTEC4,PWM Alarm Buzzer" defaultvalue="PWM"/>
|
||||
<field name="ChannelAddr" units="" type="uint8" elements="10" defaultvalue="0,1,2,3,4,5,6,7,8,9"/>
|
||||
<field name="MotorsSpinWhileArmed" units="" type="enum" elements="1" options="FALSE,TRUE" defaultvalue="FALSE"/>
|
||||
<access gcs="readwrite" flight="readwrite"/>
|
||||
<telemetrygcs acked="true" updatemode="onchange" period="0"/>
|
||||
<telemetryflight acked="true" updatemode="onchange" period="0"/>
|
||||
<logging updatemode="never" period="0"/>
|
||||
</object>
|
||||
</xml>
|
||||
|
@ -9,6 +9,8 @@
|
||||
<field name="Mixer6" units="" type="float" elements="1"/>
|
||||
<field name="Mixer7" units="" type="float" elements="1"/>
|
||||
<field name="Mixer8" units="" type="float" elements="1"/>
|
||||
<field name="Mixer9" units="" type="float" elements="1"/>
|
||||
<field name="Mixer10" units="" type="float" elements="1"/>
|
||||
<access gcs="readwrite" flight="readwrite"/>
|
||||
<telemetrygcs acked="false" updatemode="manual" period="0"/>
|
||||
<telemetryflight acked="false" updatemode="periodic" period="1000"/>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<xml>
|
||||
<object name="SystemSettings" singleinstance="true" settings="true">
|
||||
<description>Select airframe type. Currently used by @ref ActuatorModule to choose mixing from @ref ActuatorDesired to @ref ActuatorCommand</description>
|
||||
<field name="AirframeType" units="" type="enum" elements="1" options="FixedWing,FixedWingElevon,FixedWingVtail,VTOL,HeliCP,QuadX,QuadP,Hexa,Octo,Custom,HexaX,OctoV,OctoCoaxP,OctoCoaxX,HexaCoax,Tri" defaultvalue="FixedWing"/>
|
||||
<field name="AirframeType" units="" type="enum" elements="1" options="FixedWing,FixedWingElevon,FixedWingVtail,VTOL,HeliCP,QuadX,QuadP,Hexa,Octo,Custom,HexaX,OctoV,OctoCoaxP,OctoCoaxX,HexaCoax,Tri,GroundVehicleCar,GroundVehicleDifferential,GroundVehicleMotorcycle" defaultvalue="FixedWing"/>
|
||||
<field name="GUIConfigData" units="bits" type="uint32" elements="2" defaultvalue="0"/>
|
||||
<access gcs="readwrite" flight="readwrite"/>
|
||||
<telemetrygcs acked="true" updatemode="onchange" period="0"/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user