Unverified Commit 124f9ec9 authored by Gus Grubba's avatar Gus Grubba Committed by GitHub

Merge pull request #7622 from mavlink/joystickButtons

Joystick Work
parents e71da845 4d3620dc
...@@ -6,6 +6,7 @@ Note: This file only contains high level features or important fixes. ...@@ -6,6 +6,7 @@ Note: This file only contains high level features or important fixes.
### 3.6.0 - Daily Build ### 3.6.0 - Daily Build
* Added ability to set a joystick button to be single action or repeated action while the button is held down.
* Rework joysticks. Fixed several issues and updated setup UI. * Rework joysticks. Fixed several issues and updated setup UI.
* Adding support for UDP RTP h.265 video streams * Adding support for UDP RTP h.265 video streams
* For text to speech engine on Linux to English (all messages are in English) * For text to speech engine on Linux to English (all messages are in English)
......
...@@ -23,14 +23,16 @@ QGC_LOGGING_CATEGORY(JoystickLog, "JoystickLog") ...@@ -23,14 +23,16 @@ QGC_LOGGING_CATEGORY(JoystickLog, "JoystickLog")
QGC_LOGGING_CATEGORY(JoystickValuesLog, "JoystickValuesLog") QGC_LOGGING_CATEGORY(JoystickValuesLog, "JoystickValuesLog")
const char* Joystick::_settingsGroup = "Joysticks"; const char* Joystick::_settingsGroup = "Joysticks";
const char* Joystick::_calibratedSettingsKey = "Calibrated3"; // Increment number to force recalibration const char* Joystick::_calibratedSettingsKey = "Calibrated4"; // Increment number to force recalibration
const char* Joystick::_buttonActionSettingsKey = "ButtonActionName%1"; const char* Joystick::_buttonActionNameKey = "ButtonActionName%1";
const char* Joystick::_buttonActionRepeatKey = "ButtonActionRepeat%1";
const char* Joystick::_throttleModeSettingsKey = "ThrottleMode"; const char* Joystick::_throttleModeSettingsKey = "ThrottleMode";
const char* Joystick::_exponentialSettingsKey = "Exponential"; const char* Joystick::_exponentialSettingsKey = "Exponential";
const char* Joystick::_accumulatorSettingsKey = "Accumulator"; const char* Joystick::_accumulatorSettingsKey = "Accumulator";
const char* Joystick::_deadbandSettingsKey = "Deadband"; const char* Joystick::_deadbandSettingsKey = "Deadband";
const char* Joystick::_circleCorrectionSettingsKey = "Circle_Correction"; const char* Joystick::_circleCorrectionSettingsKey = "Circle_Correction";
const char* Joystick::_frequencySettingsKey = "Frequency"; const char* Joystick::_axisFrequencySettingsKey = "AxisFrequency";
const char* Joystick::_buttonFrequencySettingsKey = "ButtonFrequency";
const char* Joystick::_txModeSettingsKey = nullptr; const char* Joystick::_txModeSettingsKey = nullptr;
const char* Joystick::_fixedWingTXModeSettingsKey = "TXMode_FixedWing"; const char* Joystick::_fixedWingTXModeSettingsKey = "TXMode_FixedWing";
const char* Joystick::_multiRotorTXModeSettingsKey = "TXMode_MultiRotor"; const char* Joystick::_multiRotorTXModeSettingsKey = "TXMode_MultiRotor";
...@@ -39,13 +41,16 @@ const char* Joystick::_vtolTXModeSettingsKey = "TXMode_VTOL"; ...@@ -39,13 +41,16 @@ const char* Joystick::_vtolTXModeSettingsKey = "TXMode_VTOL";
const char* Joystick::_submarineTXModeSettingsKey = "TXMode_Submarine"; const char* Joystick::_submarineTXModeSettingsKey = "TXMode_Submarine";
const char* Joystick::_gimbalSettingsKey = "GimbalEnabled"; const char* Joystick::_gimbalSettingsKey = "GimbalEnabled";
const char* Joystick::_buttonActionNone = QT_TR_NOOP("No Action");
const char* Joystick::_buttonActionArm = QT_TR_NOOP("Arm"); const char* Joystick::_buttonActionArm = QT_TR_NOOP("Arm");
const char* Joystick::_buttonActionDisarm = QT_TR_NOOP("Disarm"); const char* Joystick::_buttonActionDisarm = QT_TR_NOOP("Disarm");
const char* Joystick::_buttonActionToggleArm = QT_TR_NOOP("Toggle Arm"); const char* Joystick::_buttonActionToggleArm = QT_TR_NOOP("Toggle Arm");
const char* Joystick::_buttonActionVTOLFixedWing = QT_TR_NOOP("VTOL: Fixed Wing"); const char* Joystick::_buttonActionVTOLFixedWing = QT_TR_NOOP("VTOL: Fixed Wing");
const char* Joystick::_buttonActionVTOLMultiRotor = QT_TR_NOOP("VTOL: Multi-Rotor"); const char* Joystick::_buttonActionVTOLMultiRotor = QT_TR_NOOP("VTOL: Multi-Rotor");
const char* Joystick::_buttonActionZoomIn = QT_TR_NOOP("Zoom In"); const char* Joystick::_buttonActionContinuousZoomIn = QT_TR_NOOP("Continuous Zoom In");
const char* Joystick::_buttonActionZoomOut = QT_TR_NOOP("Zoom Out"); const char* Joystick::_buttonActionContinuousZoomOut = QT_TR_NOOP("Continuous Zoom Out");
const char* Joystick::_buttonActionStepZoomIn = QT_TR_NOOP("Step Zoom In");
const char* Joystick::_buttonActionStepZoomOut = QT_TR_NOOP("Step Zoom Out");
const char* Joystick::_buttonActionNextStream = QT_TR_NOOP("Next Video Stream"); const char* Joystick::_buttonActionNextStream = QT_TR_NOOP("Next Video Stream");
const char* Joystick::_buttonActionPreviousStream = QT_TR_NOOP("Previous Video Stream"); const char* Joystick::_buttonActionPreviousStream = QT_TR_NOOP("Previous Video Stream");
const char* Joystick::_buttonActionNextCamera = QT_TR_NOOP("Next Camera"); const char* Joystick::_buttonActionNextCamera = QT_TR_NOOP("Next Camera");
...@@ -71,6 +76,19 @@ const char* Joystick::_rgFunctionSettingsKey[Joystick::maxFunction] = { ...@@ -71,6 +76,19 @@ const char* Joystick::_rgFunctionSettingsKey[Joystick::maxFunction] = {
int Joystick::_transmitterMode = 2; int Joystick::_transmitterMode = 2;
AssignedButtonAction::AssignedButtonAction(QObject* parent, const QString name)
: QObject(parent)
, action(name)
{
}
AssignableButtonAction::AssignableButtonAction(QObject* parent, QString action_, bool canRepeat_)
: QObject(parent)
, _action(action_)
, _repeat(canRepeat_)
{
}
Joystick::Joystick(const QString& name, int axisCount, int buttonCount, int hatCount, MultiVehicleManager* multiVehicleManager) Joystick::Joystick(const QString& name, int axisCount, int buttonCount, int hatCount, MultiVehicleManager* multiVehicleManager)
: _name(name) : _name(name)
, _axisCount(axisCount) , _axisCount(axisCount)
...@@ -83,14 +101,47 @@ Joystick::Joystick(const QString& name, int axisCount, int buttonCount, int hatC ...@@ -83,14 +101,47 @@ Joystick::Joystick(const QString& name, int axisCount, int buttonCount, int hatC
_rgAxisValues = new int[static_cast<size_t>(_axisCount)]; _rgAxisValues = new int[static_cast<size_t>(_axisCount)];
_rgCalibration = new Calibration_t[static_cast<size_t>(_axisCount)]; _rgCalibration = new Calibration_t[static_cast<size_t>(_axisCount)];
_rgButtonValues = new uint8_t[static_cast<size_t>(_totalButtonCount)]; _rgButtonValues = new uint8_t[static_cast<size_t>(_totalButtonCount)];
for (int i = 0; i < _axisCount; i++) { for (int i = 0; i < _axisCount; i++) {
_rgAxisValues[i] = 0; _rgAxisValues[i] = 0;
} }
for (int i = 0; i < _totalButtonCount; i++) { for (int i = 0; i < _totalButtonCount; i++) {
_rgButtonValues[i] = BUTTON_UP; _rgButtonValues[i] = BUTTON_UP;
_buttonActionArray.append(nullptr);
}
//-- Available Actions
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionNone));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionArm));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionDisarm));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionToggleArm));
if (_activeVehicle) {
QStringList list = _activeVehicle->flightModes();
foreach(auto mode, list) {
_assignableButtonActions.append(new AssignableButtonAction(this, mode));
}
}
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionVTOLFixedWing));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionVTOLMultiRotor));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionContinuousZoomIn, true));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionContinuousZoomOut, true));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionStepZoomIn, true));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionStepZoomOut, true));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionNextStream));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionPreviousStream));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionNextCamera));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionPreviousCamera));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionTriggerCamera));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionStartVideoRecord));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionStopVideoRecord));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionToggleVideoRecord));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionGimbalDown, true));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionGimbalUp, true));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionGimbalLeft, true));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionGimbalRight, true));
_assignableButtonActions.append(new AssignableButtonAction(this, _buttonActionGimbalCenter));
for(int i = 0; i < _assignableButtonActions.count(); i++) {
AssignableButtonAction* p = qobject_cast<AssignableButtonAction*>(_assignableButtonActions[i]);
_availableActionTitles << p->action();
} }
_updateTXModeSettingsKey(_multiVehicleManager->activeVehicle()); _updateTXModeSettingsKey(_multiVehicleManager->activeVehicle());
_loadSettings(); _loadSettings();
connect(_multiVehicleManager, &MultiVehicleManager::activeVehicleChanged, this, &Joystick::_activeVehicleChanged); connect(_multiVehicleManager, &MultiVehicleManager::activeVehicleChanged, this, &Joystick::_activeVehicleChanged);
...@@ -101,14 +152,19 @@ Joystick::~Joystick() ...@@ -101,14 +152,19 @@ Joystick::~Joystick()
// Crash out of the thread if it is still running // Crash out of the thread if it is still running
terminate(); terminate();
wait(); wait();
delete[] _rgAxisValues; delete[] _rgAxisValues;
delete[] _rgCalibration; delete[] _rgCalibration;
delete[] _rgButtonValues; delete[] _rgButtonValues;
_assignableButtonActions.deleteListAndContents();
for (int button = 0; button < _totalButtonCount; button++) {
if(_buttonActionArray[button]) {
_buttonActionArray[button]->deleteLater();
}
}
} }
void Joystick::_setDefaultCalibration(void) { void Joystick::_setDefaultCalibration(void) {
QSettings settings; QSettings settings;
settings.beginGroup(_settingsGroup); settings.beginGroup(_settingsGroup);
settings.beginGroup(_name); settings.beginGroup(_name);
_calibrated = settings.value(_calibratedSettingsKey, false).toBool(); _calibrated = settings.value(_calibratedSettingsKey, false).toBool();
...@@ -136,7 +192,8 @@ void Joystick::_setDefaultCalibration(void) { ...@@ -136,7 +192,8 @@ void Joystick::_setDefaultCalibration(void) {
_exponential = 0; _exponential = 0;
_accumulator = false; _accumulator = false;
_deadband = false; _deadband = false;
_frequency = 25.0f; _axisFrequency = 25.0f;
_buttonFrequency= 5.0f;
_throttleMode = ThrottleModeDownZero; _throttleMode = ThrottleModeDownZero;
_calibrated = true; _calibrated = true;
_circleCorrection = false; _circleCorrection = false;
...@@ -198,7 +255,8 @@ void Joystick::_loadSettings() ...@@ -198,7 +255,8 @@ void Joystick::_loadSettings()
_exponential = settings.value(_exponentialSettingsKey, 0).toFloat(); _exponential = settings.value(_exponentialSettingsKey, 0).toFloat();
_accumulator = settings.value(_accumulatorSettingsKey, false).toBool(); _accumulator = settings.value(_accumulatorSettingsKey, false).toBool();
_deadband = settings.value(_deadbandSettingsKey, false).toBool(); _deadband = settings.value(_deadbandSettingsKey, false).toBool();
_frequency = settings.value(_frequencySettingsKey, 25.0f).toFloat(); _axisFrequency = settings.value(_axisFrequencySettingsKey, 25.0f).toFloat();
_buttonFrequency= settings.value(_buttonFrequencySettingsKey, 5.0f).toFloat();
_circleCorrection = settings.value(_circleCorrectionSettingsKey, false).toBool(); _circleCorrection = settings.value(_circleCorrectionSettingsKey, false).toBool();
_gimbalEnabled = settings.value(_gimbalSettingsKey, false).toBool(); _gimbalEnabled = settings.value(_gimbalSettingsKey, false).toBool();
...@@ -233,23 +291,37 @@ void Joystick::_loadSettings() ...@@ -233,23 +291,37 @@ void Joystick::_loadSettings()
qCDebug(JoystickLog) << "_loadSettings axis:min:max:trim:reversed:deadband:badsettings" << axis << calibration->min << calibration->max << calibration->center << calibration->reversed << calibration->deadband << badSettings; qCDebug(JoystickLog) << "_loadSettings axis:min:max:trim:reversed:deadband:badsettings" << axis << calibration->min << calibration->max << calibration->center << calibration->reversed << calibration->deadband << badSettings;
} }
int workingAxis = 0;
for (int function = 0; function < maxFunction; function++) { for (int function = 0; function < maxFunction; function++) {
int functionAxis; int functionAxis;
functionAxis = settings.value(_rgFunctionSettingsKey[function], -1).toInt(&convertOk); functionAxis = settings.value(_rgFunctionSettingsKey[function], -1).toInt(&convertOk);
badSettings |= !convertOk || (functionAxis == -1) || (functionAxis >= _axisCount); badSettings |= !convertOk || (functionAxis >= _axisCount);
if(functionAxis >= 0) {
workingAxis++;
}
if(functionAxis < _axisCount) { if(functionAxis < _axisCount) {
_rgFunctionAxis[function] = functionAxis; _rgFunctionAxis[function] = functionAxis;
} }
qCDebug(JoystickLog) << "_loadSettings function:axis:badsettings" << function << functionAxis << badSettings; qCDebug(JoystickLog) << "_loadSettings function:axis:badsettings" << function << functionAxis << badSettings;
} }
badSettings |= workingAxis < 4;
// FunctionAxis mappings are always stored in TX mode 2 // FunctionAxis mappings are always stored in TX mode 2
// Remap to stored TX mode in settings // Remap to stored TX mode in settings
_remapAxes(2, _transmitterMode, _rgFunctionAxis); _remapAxes(2, _transmitterMode, _rgFunctionAxis);
for (int button=0; button<_totalButtonCount; button++) { for (int button = 0; button < _totalButtonCount; button++) {
_rgButtonActions << settings.value(QString(_buttonActionSettingsKey).arg(button), QString()).toString(); QString a = settings.value(QString(_buttonActionNameKey).arg(button), QString()).toString();
qCDebug(JoystickLog) << "_loadSettings button:action" << button << _rgButtonActions[button]; if(!a.isEmpty() && _findAssignableButtonAction(a) >= 0 && a != _buttonActionNone) {
if(_buttonActionArray[button]) {
_buttonActionArray[button]->deleteLater();
}
AssignedButtonAction* ap = new AssignedButtonAction(this, a);
ap->repeat = settings.value(QString(_buttonActionRepeatKey).arg(button), false).toBool();
_buttonActionArray[button] = ap;
_buttonActionArray[button]->buttonTime.start();
qCDebug(JoystickLog) << "_loadSettings button:action" << button << _buttonActionArray[button]->action << _buttonActionArray[button]->repeat;
}
} }
if (badSettings) { if (badSettings) {
...@@ -258,26 +330,39 @@ void Joystick::_loadSettings() ...@@ -258,26 +330,39 @@ void Joystick::_loadSettings()
} }
} }
void Joystick::_saveSettings() void Joystick::_saveButtonSettings()
{ {
QSettings settings; QSettings settings;
settings.beginGroup(_settingsGroup);
settings.beginGroup(_name);
for (int button = 0; button < _totalButtonCount; button++) {
if(_buttonActionArray[button]) {
settings.setValue(QString(_buttonActionNameKey).arg(button), _buttonActionArray[button]->action);
settings.setValue(QString(_buttonActionRepeatKey).arg(button), _buttonActionArray[button]->repeat);
qCDebug(JoystickLog) << "_saveButtonSettings button:action" << button << _buttonActionArray[button]->action << _buttonActionArray[button]->repeat;
}
}
}
void Joystick::_saveSettings()
{
QSettings settings;
settings.beginGroup(_settingsGroup); settings.beginGroup(_settingsGroup);
// Transmitter mode is static // Transmitter mode is static
// Save the mode we are using // Save the mode we are using
if(_txModeSettingsKey) if(_txModeSettingsKey)
settings.setValue(_txModeSettingsKey, _transmitterMode); settings.setValue(_txModeSettingsKey, _transmitterMode);
settings.beginGroup(_name); settings.beginGroup(_name);
settings.setValue(_calibratedSettingsKey, _calibrated);
settings.setValue(_calibratedSettingsKey, _calibrated); settings.setValue(_exponentialSettingsKey, _exponential);
settings.setValue(_exponentialSettingsKey, _exponential); settings.setValue(_accumulatorSettingsKey, _accumulator);
settings.setValue(_accumulatorSettingsKey, _accumulator); settings.setValue(_deadbandSettingsKey, _deadband);
settings.setValue(_deadbandSettingsKey, _deadband); settings.setValue(_axisFrequencySettingsKey, _axisFrequency);
settings.setValue(_frequencySettingsKey, _frequency); settings.setValue(_buttonFrequencySettingsKey, _buttonFrequency);
settings.setValue(_throttleModeSettingsKey, _throttleMode); settings.setValue(_throttleModeSettingsKey, _throttleMode);
settings.setValue(_gimbalSettingsKey, _gimbalEnabled); settings.setValue(_gimbalSettingsKey, _gimbalEnabled);
settings.setValue(_circleCorrectionSettingsKey, _circleCorrection); settings.setValue(_circleCorrectionSettingsKey, _circleCorrection);
qCDebug(JoystickLog) << "_saveSettings calibrated:throttlemode:deadband:txmode" << _calibrated << _throttleMode << _deadband << _circleCorrection << _transmitterMode; qCDebug(JoystickLog) << "_saveSettings calibrated:throttlemode:deadband:txmode" << _calibrated << _throttleMode << _deadband << _circleCorrection << _transmitterMode;
...@@ -309,16 +394,11 @@ void Joystick::_saveSettings() ...@@ -309,16 +394,11 @@ void Joystick::_saveSettings()
// Write mode 2 mappings without changing mapping currently in use // Write mode 2 mappings without changing mapping currently in use
int temp[maxFunction]; int temp[maxFunction];
_remapAxes(_transmitterMode, 2, temp); _remapAxes(_transmitterMode, 2, temp);
for (int function = 0; function < maxFunction; function++) { for (int function = 0; function < maxFunction; function++) {
settings.setValue(_rgFunctionSettingsKey[function], temp[function]); settings.setValue(_rgFunctionSettingsKey[function], temp[function]);
qCDebug(JoystickLog) << "_saveSettings name:function:axis" << _name << function << _rgFunctionSettingsKey[function]; qCDebug(JoystickLog) << "_saveSettings name:function:axis" << _name << function << _rgFunctionSettingsKey[function];
} }
_saveButtonSettings();
for (int button = 0; button < _totalButtonCount; button++) {
settings.setValue(QString(_buttonActionSettingsKey).arg(button), _rgButtonActions[button]);
qCDebug(JoystickLog) << "_saveSettings button:action" << button << _rgButtonActions[button];
}
} }
// Relative mappings of axis functions between different TX modes // Relative mappings of axis functions between different TX modes
...@@ -334,15 +414,12 @@ int Joystick::_mapFunctionMode(int mode, int function) { ...@@ -334,15 +414,12 @@ int Joystick::_mapFunctionMode(int mode, int function) {
// Remap current axis functions from current TX mode to new TX mode // Remap current axis functions from current TX mode to new TX mode
void Joystick::_remapAxes(int currentMode, int newMode, int (&newMapping)[maxFunction]) { void Joystick::_remapAxes(int currentMode, int newMode, int (&newMapping)[maxFunction]) {
int temp[maxFunction]; int temp[maxFunction];
for(int function = 0; function < maxFunction; function++) { for(int function = 0; function < maxFunction; function++) {
temp[_mapFunctionMode(newMode, function)] = _rgFunctionAxis[_mapFunctionMode(currentMode, function)]; temp[_mapFunctionMode(newMode, function)] = _rgFunctionAxis[_mapFunctionMode(currentMode, function)];
} }
for(int function = 0; function < maxFunction; function++) { for(int function = 0; function < maxFunction; function++) {
newMapping[function] = temp[function]; newMapping[function] = temp[function];
} }
} }
void Joystick::setTXMode(int mode) { void Joystick::setTXMode(int mode) {
...@@ -413,49 +490,98 @@ float Joystick::_adjustRange(int value, Calibration_t calibration, bool withDead ...@@ -413,49 +490,98 @@ float Joystick::_adjustRange(int value, Calibration_t calibration, bool withDead
void Joystick::run() void Joystick::run()
{ {
//-- Joystick thread
_open(); _open();
//-- Reset timers
_axisTime.start();
for (int buttonIndex = 0; buttonIndex < _totalButtonCount; buttonIndex++) {
if(_buttonActionArray[buttonIndex]) {
_buttonActionArray[buttonIndex]->buttonTime.start();
}
}
while (!_exitThread) { while (!_exitThread) {
_update(); _update();
_handleButtons();
_handleAxis();
QGC::SLEEP::msleep(20);
}
_close();
}
// Update axes void Joystick::_handleButtons()
for (int axisIndex = 0; axisIndex < _axisCount; axisIndex++) { {
int newAxisValue = _getAxis(axisIndex); //-- Update button states
// Calibration code requires signal to be emitted even if value hasn't changed for (int buttonIndex = 0; buttonIndex < _buttonCount; buttonIndex++) {
_rgAxisValues[axisIndex] = newAxisValue; bool newButtonValue = _getButton(buttonIndex);
emit rawAxisValueChanged(axisIndex, newAxisValue); if (newButtonValue && _rgButtonValues[buttonIndex] == BUTTON_UP) {
_rgButtonValues[buttonIndex] = BUTTON_DOWN;
emit rawButtonPressedChanged(buttonIndex, newButtonValue);
} else if (!newButtonValue && _rgButtonValues[buttonIndex] != BUTTON_UP) {
_rgButtonValues[buttonIndex] = BUTTON_UP;
emit rawButtonPressedChanged(buttonIndex, newButtonValue);
} }
}
// Update buttons //-- Update hat - append hat buttons to the end of the normal button list
for (int buttonIndex = 0; buttonIndex < _buttonCount; buttonIndex++) { int numHatButtons = 4;
bool newButtonValue = _getButton(buttonIndex); for (int hatIndex = 0; hatIndex < _hatCount; hatIndex++) {
if (newButtonValue && _rgButtonValues[buttonIndex] == BUTTON_UP) { for (int hatButtonIndex = 0; hatButtonIndex<numHatButtons; hatButtonIndex++) {
_rgButtonValues[buttonIndex] = BUTTON_DOWN; // Create new index value that includes the normal button list
emit rawButtonPressedChanged(buttonIndex, newButtonValue); int rgButtonValueIndex = hatIndex*numHatButtons + hatButtonIndex + _buttonCount;
} else if (!newButtonValue && _rgButtonValues[buttonIndex] != BUTTON_UP) { // Get hat value from joystick
_rgButtonValues[buttonIndex] = BUTTON_UP; bool newButtonValue = _getHat(hatIndex, hatButtonIndex);
emit rawButtonPressedChanged(buttonIndex, newButtonValue); if (newButtonValue && _rgButtonValues[rgButtonValueIndex] == BUTTON_UP) {
_rgButtonValues[rgButtonValueIndex] = BUTTON_DOWN;
emit rawButtonPressedChanged(rgButtonValueIndex, newButtonValue);
} else if (!newButtonValue && _rgButtonValues[rgButtonValueIndex] != BUTTON_UP) {
_rgButtonValues[rgButtonValueIndex] = BUTTON_UP;
emit rawButtonPressedChanged(rgButtonValueIndex, newButtonValue);
} }
} }
}
// Update hat - append hat buttons to the end of the normal button list //-- Process button press
int numHatButtons = 4; for (int buttonIndex = 0; buttonIndex < _totalButtonCount; buttonIndex++) {
for (int hatIndex = 0; hatIndex < _hatCount; hatIndex++) { if(_rgButtonValues[buttonIndex] == BUTTON_DOWN || _rgButtonValues[buttonIndex] == BUTTON_REPEAT) {
for (int hatButtonIndex = 0; hatButtonIndex<numHatButtons; hatButtonIndex++) { if(_buttonActionArray[buttonIndex]) {
// Create new index value that includes the normal button list QString buttonAction = _buttonActionArray[buttonIndex]->action;
int rgButtonValueIndex = hatIndex*numHatButtons + hatButtonIndex + _buttonCount; if(buttonAction.isEmpty() || buttonAction == _buttonActionNone)
// Get hat value from joystick continue;
bool newButtonValue = _getHat(hatIndex, hatButtonIndex); //-- Process single button
if (newButtonValue && _rgButtonValues[rgButtonValueIndex] == BUTTON_UP) { if(!_buttonActionArray[buttonIndex]->repeat) {
_rgButtonValues[rgButtonValueIndex] = BUTTON_DOWN; //-- This button just went down
emit rawButtonPressedChanged(rgButtonValueIndex, newButtonValue); if(_rgButtonValues[buttonIndex] == BUTTON_DOWN) {
} else if (!newButtonValue && _rgButtonValues[rgButtonValueIndex] != BUTTON_UP) { qCDebug(JoystickLog) << "Single button triggered" << buttonIndex << buttonAction;
_rgButtonValues[rgButtonValueIndex] = BUTTON_UP; _executeButtonAction(buttonAction);
emit rawButtonPressedChanged(rgButtonValueIndex, newButtonValue); }
} else {
//-- Process repeat buttons
int buttonDelay = static_cast<int>(1000.0f / _buttonFrequency);
if(_buttonActionArray[buttonIndex]->buttonTime.elapsed() > buttonDelay) {
_buttonActionArray[buttonIndex]->buttonTime.start();
qCDebug(JoystickLog) << "Repeat button triggered" << buttonIndex << buttonAction;
_executeButtonAction(buttonAction);
}
} }
} }
//-- Flag it as processed
_rgButtonValues[buttonIndex] = BUTTON_REPEAT;
} }
}
}
void Joystick::_handleAxis()
{
//-- Get frequency
int axisDelay = static_cast<int>(1000.0f / _axisFrequency);
//-- Check elapsed time since last run
if(_axisTime.elapsed() > axisDelay) {
_axisTime.start();
//-- Update axis
for (int axisIndex = 0; axisIndex < _axisCount; axisIndex++) {
int newAxisValue = _getAxis(axisIndex);
// Calibration code requires signal to be emitted even if value hasn't changed
_rgAxisValues[axisIndex] = newAxisValue;
emit rawAxisValueChanged(axisIndex, newAxisValue);
}
if (_activeVehicle->joystickEnabled() && !_calibrationMode && _calibrated) { if (_activeVehicle->joystickEnabled() && !_calibrationMode && _calibrated) {
int axis = _rgFunctionAxis[rollFunction]; int axis = _rgFunctionAxis[rollFunction];
float roll = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis], _deadband); float roll = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis], _deadband);
...@@ -519,22 +645,8 @@ void Joystick::run() ...@@ -519,22 +645,8 @@ void Joystick::run()
} else { } else {
throttle = (throttle + 1.0f) / 2.0f; throttle = (throttle + 1.0f) / 2.0f;
} }
qCDebug(JoystickValuesLog) << "name:roll:pitch:yaw:throttle:gimbalPitch:gimbalYaw" << name() << roll << -pitch << yaw << throttle << gimbalPitch << gimbalYaw;
//-- Process button press // NOTE: The buttonPressedBits going to MANUAL_CONTROL are currently used by ArduSub (and it only handles 16 bits)
for (int buttonIndex = 0; buttonIndex < _totalButtonCount; buttonIndex++) {
//-- This button just went down
if(_rgButtonValues[buttonIndex] == BUTTON_DOWN) {
//-- Flag it as processed
_rgButtonValues[buttonIndex] = BUTTON_REPEAT;
//-- Process button
QString buttonAction =_rgButtonActions[buttonIndex];
qCDebug(JoystickLog) << "button triggered" << buttonIndex << buttonAction;
if (!buttonAction.isEmpty()) {
_buttonAction(buttonAction);
}
}
}
// Set up button bitmap // Set up button bitmap
quint64 buttonPressedBits = 0; // Buttons pressed for manualControl signal quint64 buttonPressedBits = 0; // Buttons pressed for manualControl signal
for (int buttonIndex = 0; buttonIndex < _totalButtonCount; buttonIndex++) { for (int buttonIndex = 0; buttonIndex < _totalButtonCount; buttonIndex++) {
...@@ -544,9 +656,6 @@ void Joystick::run() ...@@ -544,9 +656,6 @@ void Joystick::run()
buttonPressedBits |= buttonBit; buttonPressedBits |= buttonBit;
} }
} }
qCDebug(JoystickValuesLog) << "name:roll:pitch:yaw:throttle:gimbalPitch:gimbalYaw" << name() << roll << -pitch << yaw << throttle << gimbalPitch << gimbalYaw;
// NOTE: The buttonPressedBits going to MANUAL_CONTROL are currently used by ArduSub (and it only handles 16 bits)
uint16_t shortButtons = static_cast<uint16_t>(buttonPressedBits & 0xFFFF); uint16_t shortButtons = static_cast<uint16_t>(buttonPressedBits & 0xFFFF);
emit manualControl(roll, -pitch, yaw, throttle, shortButtons, _activeVehicle->joystickMode()); emit manualControl(roll, -pitch, yaw, throttle, shortButtons, _activeVehicle->joystickMode());
if(_activeVehicle && _axisCount > 4 && _gimbalEnabled) { if(_activeVehicle && _axisCount > 4 && _gimbalEnabled) {
...@@ -555,13 +664,7 @@ void Joystick::run() ...@@ -555,13 +664,7 @@ void Joystick::run()
emit manualControlGimbal((gimbalPitch + 1.0f) / 2.0f * 90.0f, gimbalYaw * 180.0f); emit manualControlGimbal((gimbalPitch + 1.0f) / 2.0f * 90.0f, gimbalYaw * 180.0f);
} }
} }
// Sleep. Update rate of joystick is by default 25 Hz
unsigned long mswait = static_cast<unsigned long>(1000.0f / _frequency);
QGC::SLEEP::msleep(mswait);
} }
_close();
} }
void Joystick::startPolling(Vehicle* vehicle) void Joystick::startPolling(Vehicle* vehicle)
...@@ -631,7 +734,6 @@ void Joystick::stopPolling(void) ...@@ -631,7 +734,6 @@ void Joystick::stopPolling(void)
void Joystick::setCalibration(int axis, Calibration_t& calibration) void Joystick::setCalibration(int axis, Calibration_t& calibration)
{ {
if (!_validAxis(axis)) { if (!_validAxis(axis)) {
qCWarning(JoystickLog) << "Invalid axis index" << axis;
return; return;
} }
_calibrated = true; _calibrated = true;
...@@ -643,16 +745,14 @@ void Joystick::setCalibration(int axis, Calibration_t& calibration) ...@@ -643,16 +745,14 @@ void Joystick::setCalibration(int axis, Calibration_t& calibration)
Joystick::Calibration_t Joystick::getCalibration(int axis) Joystick::Calibration_t Joystick::getCalibration(int axis)
{ {
if (!_validAxis(axis)) { if (!_validAxis(axis)) {
qCWarning(JoystickLog) << "Invalid axis index" << axis; return Calibration_t();
} }
return _rgCalibration[axis]; return _rgCalibration[axis];
} }
void Joystick::setFunctionAxis(AxisFunction_t function, int axis) void Joystick::setFunctionAxis(AxisFunction_t function, int axis)
{ {
if (!_validAxis(axis)) { if (!_validAxis(axis)) {
qCWarning(JoystickLog) << "Invalid axis index" << axis;
return; return;
} }
_calibrated = true; _calibrated = true;
...@@ -669,62 +769,86 @@ int Joystick::getFunctionAxis(AxisFunction_t function) ...@@ -669,62 +769,86 @@ int Joystick::getFunctionAxis(AxisFunction_t function)
return _rgFunctionAxis[function]; return _rgFunctionAxis[function];
} }
QStringList Joystick::actions() void Joystick::setButtonRepeat(int button, bool repeat)
{ {
QStringList list; if (!_validButton(button) || !_buttonActionArray[button]) {
list << _buttonActionArm << _buttonActionDisarm << _buttonActionToggleArm; return;
if (_activeVehicle) { }
list << _activeVehicle->flightModes(); _buttonActionArray[button]->repeat = repeat;
} _buttonActionArray[button]->buttonTime.start();
list << _buttonActionVTOLFixedWing << _buttonActionVTOLMultiRotor; //-- Save to settings
list << _buttonActionZoomIn << _buttonActionZoomOut; QSettings settings;
list << _buttonActionNextStream << _buttonActionPreviousStream; settings.beginGroup(_settingsGroup);
list << _buttonActionNextCamera << _buttonActionPreviousCamera; settings.beginGroup(_name);
list << _buttonActionTriggerCamera; settings.setValue(QString(_buttonActionRepeatKey).arg(button), _buttonActionArray[button]->repeat);
list << _buttonActionStartVideoRecord; }
list << _buttonActionStopVideoRecord;
list << _buttonActionToggleVideoRecord; bool Joystick::getButtonRepeat(int button)
list << _buttonActionGimbalDown; {
list << _buttonActionGimbalUp; if (!_validButton(button) || !_buttonActionArray[button]) {
list << _buttonActionGimbalLeft; return false;
list << _buttonActionGimbalRight; }
list << _buttonActionGimbalCenter; return _buttonActionArray[button]->repeat;
return list;
} }
void Joystick::setButtonAction(int button, const QString& action) void Joystick::setButtonAction(int button, const QString& action)
{ {
if (!_validButton(button)) { if (!_validButton(button)) {
qCWarning(JoystickLog) << "Invalid button index" << button;
return; return;
} }
qCWarning(JoystickLog) << "setButtonAction:" << button << action;
qDebug() << "setButtonAction" << action; QSettings settings;
settings.beginGroup(_settingsGroup);
_rgButtonActions[button] = action; settings.beginGroup(_name);
_saveSettings(); if(action.isEmpty() || action == _buttonActionNone) {
emit buttonActionsChanged(buttonActions()); if(_buttonActionArray[button]) {
_buttonActionArray[button]->deleteLater();
_buttonActionArray[button] = nullptr;
//-- Clear from settings
settings.remove(QString(_buttonActionNameKey).arg(button));
settings.remove(QString(_buttonActionRepeatKey).arg(button));
}
} else {
if(!_buttonActionArray[button]) {
_buttonActionArray[button] = new AssignedButtonAction(this, action);
} else {
_buttonActionArray[button]->action = action;
//-- Make sure repeat is off if this action doesn't support repeats
int idx = _findAssignableButtonAction(action);
if(idx >= 0) {
AssignableButtonAction* p = qobject_cast<AssignableButtonAction*>(_assignableButtonActions[idx]);
if(!p->canRepeat()) {
_buttonActionArray[button]->repeat = false;
}
}
}
//-- Save to settings
settings.setValue(QString(_buttonActionNameKey).arg(button), _buttonActionArray[button]->action);
settings.setValue(QString(_buttonActionRepeatKey).arg(button), _buttonActionArray[button]->repeat);
}
emit buttonActionsChanged();
} }
QString Joystick::getButtonAction(int button) QString Joystick::getButtonAction(int button)
{ {
if (!_validButton(button)) { if (_validButton(button)) {
qCWarning(JoystickLog) << "Invalid button index" << button; if(_buttonActionArray[button]) {
return _buttonActionArray[button]->action;
}
} }
return QString(_buttonActionNone);
return _rgButtonActions[button];
} }
QVariantList Joystick::buttonActions() QStringList Joystick::buttonActions()
{ {
QVariantList list; QStringList list;
for (int button=0; button<_totalButtonCount; button++) { for (int button = 0; button < _totalButtonCount; button++) {
list += QVariant::fromValue(_rgButtonActions[button]); list << getButtonAction(button);
} }
return list; return list;
} }
int Joystick::throttleMode(void) int Joystick::throttleMode()
{ {
return _throttleMode; return _throttleMode;
} }
...@@ -743,7 +867,7 @@ void Joystick::setThrottleMode(int mode) ...@@ -743,7 +867,7 @@ void Joystick::setThrottleMode(int mode)
emit throttleModeChanged(_throttleMode); emit throttleModeChanged(_throttleMode);
} }
bool Joystick::negativeThrust(void) bool Joystick::negativeThrust()
{ {
return _negativeThrust; return _negativeThrust;
} }
...@@ -758,7 +882,7 @@ void Joystick::setNegativeThrust(bool allowNegative) ...@@ -758,7 +882,7 @@ void Joystick::setNegativeThrust(bool allowNegative)
emit negativeThrustChanged(_negativeThrust); emit negativeThrustChanged(_negativeThrust);
} }
float Joystick::exponential(void) float Joystick::exponential()
{ {
return _exponential; return _exponential;
} }
...@@ -770,7 +894,7 @@ void Joystick::setExponential(float expo) ...@@ -770,7 +894,7 @@ void Joystick::setExponential(float expo)
emit exponentialChanged(_exponential); emit exponentialChanged(_exponential);
} }
bool Joystick::accumulator(void) bool Joystick::accumulator()
{ {
return _accumulator; return _accumulator;
} }
...@@ -782,7 +906,7 @@ void Joystick::setAccumulator(bool accu) ...@@ -782,7 +906,7 @@ void Joystick::setAccumulator(bool accu)
emit accumulatorChanged(_accumulator); emit accumulatorChanged(_accumulator);
} }
bool Joystick::deadband(void) bool Joystick::deadband()
{ {
return _deadband; return _deadband;
} }
...@@ -793,7 +917,7 @@ void Joystick::setDeadband(bool deadband) ...@@ -793,7 +917,7 @@ void Joystick::setDeadband(bool deadband)
_saveSettings(); _saveSettings();
} }
bool Joystick::circleCorrection(void) bool Joystick::circleCorrection()
{ {
return _circleCorrection; return _circleCorrection;
} }
...@@ -805,11 +929,6 @@ void Joystick::setCircleCorrection(bool circleCorrection) ...@@ -805,11 +929,6 @@ void Joystick::setCircleCorrection(bool circleCorrection)
emit circleCorrectionChanged(_circleCorrection); emit circleCorrectionChanged(_circleCorrection);
} }
float Joystick::frequency()
{
return _frequency;
}
void Joystick::setGimbalEnabled(bool set) void Joystick::setGimbalEnabled(bool set)
{ {
_gimbalEnabled = set; _gimbalEnabled = set;
...@@ -817,14 +936,24 @@ void Joystick::setGimbalEnabled(bool set) ...@@ -817,14 +936,24 @@ void Joystick::setGimbalEnabled(bool set)
emit gimbalEnabledChanged(); emit gimbalEnabledChanged();
} }
void Joystick::setFrequency(float val) void Joystick::setAxisFrequency(float val)
{ {
//-- Arbitrary limits //-- Arbitrary limits
if(val < 0.25f) val = 0.25f; if(val < 0.25f) val = 0.25f;
if(val > 100.0f) val = 100.0f; if(val > 50.0f) val = 50.0f;
_frequency = val; _axisFrequency = val;
_saveSettings(); _saveSettings();
emit frequencyChanged(); emit axisFrequencyChanged();
}
void Joystick::setButtonFrequency(float val)
{
//-- Arbitrary limits
if(val < 0.25f) val = 0.25f;
if(val > 50.0f) val = 50.0f;
_buttonFrequency = val;
_saveSettings();
emit buttonFrequencyChanged();
} }
void Joystick::setCalibrationMode(bool calibrating) void Joystick::setCalibrationMode(bool calibrating)
...@@ -840,9 +969,9 @@ void Joystick::setCalibrationMode(bool calibrating) ...@@ -840,9 +969,9 @@ void Joystick::setCalibrationMode(bool calibrating)
} }
void Joystick::_buttonAction(const QString& action) void Joystick::_executeButtonAction(const QString& action)
{ {
if (!_activeVehicle || !_activeVehicle->joystickEnabled()) { if (!_activeVehicle || !_activeVehicle->joystickEnabled() || action == _buttonActionNone) {
return; return;
} }
if (action == _buttonActionArm) { if (action == _buttonActionArm) {
...@@ -857,8 +986,10 @@ void Joystick::_buttonAction(const QString& action) ...@@ -857,8 +986,10 @@ void Joystick::_buttonAction(const QString& action)
emit setVtolInFwdFlight(false); emit setVtolInFwdFlight(false);
} else if (_activeVehicle->flightModes().contains(action)) { } else if (_activeVehicle->flightModes().contains(action)) {
emit setFlightMode(action); emit setFlightMode(action);
} else if(action == _buttonActionZoomIn || action == _buttonActionZoomOut) { } else if(action == _buttonActionContinuousZoomIn || action == _buttonActionContinuousZoomOut) {
emit stepZoom(action == _buttonActionZoomIn ? 1 : -1); emit startContinuousZoom(action == _buttonActionStepZoomIn ? 1 : -1);
} else if(action == _buttonActionStepZoomIn || action == _buttonActionStepZoomOut) {
emit stepZoom(action == _buttonActionStepZoomIn ? 1 : -1);
} else if(action == _buttonActionNextStream || action == _buttonActionPreviousStream) { } else if(action == _buttonActionNextStream || action == _buttonActionPreviousStream) {
emit stepStream(action == _buttonActionNextStream ? 1 : -1); emit stepStream(action == _buttonActionNextStream ? 1 : -1);
} else if(action == _buttonActionNextCamera || action == _buttonActionPreviousCamera) { } else if(action == _buttonActionNextCamera || action == _buttonActionPreviousCamera) {
...@@ -888,11 +1019,28 @@ void Joystick::_buttonAction(const QString& action) ...@@ -888,11 +1019,28 @@ void Joystick::_buttonAction(const QString& action)
bool Joystick::_validAxis(int axis) bool Joystick::_validAxis(int axis)
{ {
return axis >= 0 && axis < _axisCount; if(axis >= 0 && axis < _axisCount) {
return true;
}
qCWarning(JoystickLog) << "Invalid axis index" << axis;
return false;
} }
bool Joystick::_validButton(int button) bool Joystick::_validButton(int button)
{ {
return button >= 0 && button < _totalButtonCount; if(button >= 0 && button < _totalButtonCount)
return true;
qCWarning(JoystickLog) << "Invalid button index" << button;
return false;
}
int Joystick::_findAssignableButtonAction(const QString& action)
{
for(int i = 0; i < _assignableButtonActions.count(); i++) {
AssignableButtonAction* p = qobject_cast<AssignableButtonAction*>(_assignableButtonActions[i]);
if(p->action() == action)
return i;
}
return -1;
} }
...@@ -21,10 +21,33 @@ ...@@ -21,10 +21,33 @@
Q_DECLARE_LOGGING_CATEGORY(JoystickLog) Q_DECLARE_LOGGING_CATEGORY(JoystickLog)
Q_DECLARE_LOGGING_CATEGORY(JoystickValuesLog) Q_DECLARE_LOGGING_CATEGORY(JoystickValuesLog)
//-- Action assigned to button
class AssignedButtonAction : public QObject {
Q_OBJECT
public:
AssignedButtonAction(QObject* parent, const QString name);
QString action;
QTime buttonTime;
bool repeat = false;
};
//-- Assignable Button Action
class AssignableButtonAction : public QObject {
Q_OBJECT
public:
AssignableButtonAction(QObject* parent, QString action_, bool canRepeat_ = false);
Q_PROPERTY(QString action READ action CONSTANT)
Q_PROPERTY(bool canRepeat READ canRepeat CONSTANT)
QString action () { return _action; }
bool canRepeat () { return _repeat; }
private:
QString _action;
bool _repeat = false;
};
class Joystick : public QThread class Joystick : public QThread
{ {
Q_OBJECT Q_OBJECT
public: public:
Joystick(const QString& name, int axisCount, int buttonCount, int hatCount, MultiVehicleManager* multiVehicleManager); Joystick(const QString& name, int axisCount, int buttonCount, int hatCount, MultiVehicleManager* multiVehicleManager);
...@@ -60,24 +83,33 @@ public: ...@@ -60,24 +83,33 @@ public:
ThrottleModeMax ThrottleModeMax
} ThrottleMode_t; } ThrottleMode_t;
Q_PROPERTY(QString name READ name CONSTANT) Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(bool calibrated MEMBER _calibrated NOTIFY calibratedChanged) Q_PROPERTY(bool calibrated MEMBER _calibrated NOTIFY calibratedChanged)
Q_PROPERTY(int totalButtonCount READ totalButtonCount CONSTANT) Q_PROPERTY(int totalButtonCount READ totalButtonCount CONSTANT)
Q_PROPERTY(int axisCount READ axisCount CONSTANT) Q_PROPERTY(int axisCount READ axisCount CONSTANT)
Q_PROPERTY(bool requiresCalibration READ requiresCalibration CONSTANT) Q_PROPERTY(bool requiresCalibration READ requiresCalibration CONSTANT)
Q_PROPERTY(QStringList actions READ actions CONSTANT)
Q_PROPERTY(QVariantList buttonActions READ buttonActions NOTIFY buttonActionsChanged) //-- Actions assigned to buttons
Q_PROPERTY(QStringList buttonActions READ buttonActions NOTIFY buttonActionsChanged)
Q_PROPERTY(bool gimbalEnabled READ gimbalEnabled WRITE setGimbalEnabled NOTIFY gimbalEnabledChanged)
Q_PROPERTY(int throttleMode READ throttleMode WRITE setThrottleMode NOTIFY throttleModeChanged) //-- Actions that can be assigned to buttons
Q_PROPERTY(float frequency READ frequency WRITE setFrequency NOTIFY frequencyChanged) Q_PROPERTY(QmlObjectListModel* assignableActions READ assignableActions CONSTANT)
Q_PROPERTY(bool negativeThrust READ negativeThrust WRITE setNegativeThrust NOTIFY negativeThrustChanged) Q_PROPERTY(QStringList assignableActionTitles READ assignableActionTitles CONSTANT)
Q_PROPERTY(float exponential READ exponential WRITE setExponential NOTIFY exponentialChanged) Q_PROPERTY(QString disabledActionName READ disabledActionName CONSTANT)
Q_PROPERTY(bool accumulator READ accumulator WRITE setAccumulator NOTIFY accumulatorChanged)
Q_PROPERTY(bool circleCorrection READ circleCorrection WRITE setCircleCorrection NOTIFY circleCorrectionChanged) Q_PROPERTY(bool gimbalEnabled READ gimbalEnabled WRITE setGimbalEnabled NOTIFY gimbalEnabledChanged)
Q_PROPERTY(int throttleMode READ throttleMode WRITE setThrottleMode NOTIFY throttleModeChanged)
Q_INVOKABLE void setButtonAction (int button, const QString& action); Q_PROPERTY(float axisFrequency READ axisFrequency WRITE setAxisFrequency NOTIFY axisFrequencyChanged)
Q_INVOKABLE QString getButtonAction (int button); Q_PROPERTY(float buttonFrequency READ buttonFrequency WRITE setButtonFrequency NOTIFY buttonFrequencyChanged)
Q_PROPERTY(bool negativeThrust READ negativeThrust WRITE setNegativeThrust NOTIFY negativeThrustChanged)
Q_PROPERTY(float exponential READ exponential WRITE setExponential NOTIFY exponentialChanged)
Q_PROPERTY(bool accumulator READ accumulator WRITE setAccumulator NOTIFY accumulatorChanged)
Q_PROPERTY(bool circleCorrection READ circleCorrection WRITE setCircleCorrection NOTIFY circleCorrectionChanged)
Q_INVOKABLE void setButtonRepeat (int button, bool repeat);
Q_INVOKABLE bool getButtonRepeat (int button);
Q_INVOKABLE void setButtonAction (int button, const QString& action);
Q_INVOKABLE QString getButtonAction (int button);
// Property accessors // Property accessors
...@@ -85,8 +117,11 @@ public: ...@@ -85,8 +117,11 @@ public:
int totalButtonCount () { return _totalButtonCount; } int totalButtonCount () { return _totalButtonCount; }
int axisCount () { return _axisCount; } int axisCount () { return _axisCount; }
bool gimbalEnabled () { return _gimbalEnabled; } bool gimbalEnabled () { return _gimbalEnabled; }
QStringList actions (); QStringList buttonActions ();
QVariantList buttonActions ();
QmlObjectListModel* assignableActions () { return &_assignableButtonActions; }
QStringList assignableActionTitles () { return _availableActionTitles; }
QString disabledActionName () { return _buttonActionNone; }
void setGimbalEnabled (bool set); void setGimbalEnabled (bool set);
...@@ -109,53 +144,48 @@ public: ...@@ -109,53 +144,48 @@ public:
*/ */
virtual bool requiresCalibration(void) { return true; } virtual bool requiresCalibration(void) { return true; }
int throttleMode(void); int throttleMode ();
void setThrottleMode(int mode); void setThrottleMode (int mode);
bool negativeThrust(void); bool negativeThrust ();
void setNegativeThrust(bool allowNegative); void setNegativeThrust (bool allowNegative);
float exponential(void); float exponential ();
void setExponential(float expo); void setExponential (float expo);
bool accumulator(void); bool accumulator ();
void setAccumulator(bool accu); void setAccumulator (bool accu);
bool deadband(void); bool deadband ();
void setDeadband(bool accu); void setDeadband (bool accu);
bool circleCorrection(void); bool circleCorrection ();
void setCircleCorrection(bool circleCorrection); void setCircleCorrection(bool circleCorrection);
void setTXMode(int mode); void setTXMode (int mode);
int getTXMode(void) { return _transmitterMode; } int getTXMode () { return _transmitterMode; }
/// Set the current calibration mode /// Set the current calibration mode
void setCalibrationMode(bool calibrating); void setCalibrationMode (bool calibrating);
float frequency(); float axisFrequency () { return _axisFrequency; }
void setFrequency(float val); void setAxisFrequency (float val);
signals: float buttonFrequency () { return _buttonFrequency; }
void calibratedChanged(bool calibrated); void setButtonFrequency(float val);
signals:
// The raw signals are only meant for use by calibration // The raw signals are only meant for use by calibration
void rawAxisValueChanged(int index, int value); void rawAxisValueChanged (int index, int value);
void rawButtonPressedChanged(int index, int pressed); void rawButtonPressedChanged (int index, int pressed);
void calibratedChanged (bool calibrated);
void buttonActionsChanged(QVariantList actions); void buttonActionsChanged ();
void throttleModeChanged (int mode);
void throttleModeChanged(int mode); void negativeThrustChanged (bool allowNegative);
void exponentialChanged (float exponential);
void negativeThrustChanged(bool allowNegative); void accumulatorChanged (bool accumulator);
void enabledChanged (bool enabled);
void exponentialChanged(float exponential); void circleCorrectionChanged (bool circleCorrection);
void accumulatorChanged(bool accumulator);
void enabledChanged(bool enabled);
void circleCorrectionChanged(bool circleCorrection);
/// Signal containing new joystick information /// Signal containing new joystick information
/// @param roll Range is -1:1, negative meaning roll left, positive meaning roll right /// @param roll Range is -1:1, negative meaning roll left, positive meaning roll right
...@@ -163,35 +193,42 @@ signals: ...@@ -163,35 +193,42 @@ signals:
/// @param yaw Range is -1:1, negative meaning yaw left, positive meaning yaw right /// @param yaw Range is -1:1, negative meaning yaw left, positive meaning yaw right
/// @param throttle Range is 0:1, 0 meaning no throttle, 1 meaning full throttle /// @param throttle Range is 0:1, 0 meaning no throttle, 1 meaning full throttle
/// @param mode See Vehicle::JoystickMode_t enum /// @param mode See Vehicle::JoystickMode_t enum
void manualControl (float roll, float pitch, float yaw, float throttle, quint16 buttons, int joystickMmode); void manualControl (float roll, float pitch, float yaw, float throttle, quint16 buttons, int joystickMmode);
void manualControlGimbal (float gimbalPitch, float gimbalYaw); void manualControlGimbal (float gimbalPitch, float gimbalYaw);
void buttonActionTriggered(int action); void buttonActionTriggered (int action);
void gimbalEnabledChanged (); void gimbalEnabledChanged ();
void frequencyChanged (); void axisFrequencyChanged ();
void stepZoom (int direction); void buttonFrequencyChanged ();
void stepCamera (int direction); void startContinuousZoom (int direction);
void stepStream (int direction); void stopContinuousZoom ();
void triggerCamera (); void stepZoom (int direction);
void startVideoRecord (); void stepCamera (int direction);
void stopVideoRecord (); void stepStream (int direction);
void toggleVideoRecord (); void triggerCamera ();
void gimbalPitchStep (int direction); void startVideoRecord ();
void gimbalYawStep (int direction); void stopVideoRecord ();
void centerGimbal (); void toggleVideoRecord ();
void setArmed (bool arm); void gimbalPitchStep (int direction);
void setVtolInFwdFlight (bool set); void gimbalYawStep (int direction);
void setFlightMode (const QString& flightMode); void centerGimbal ();
void setArmed (bool arm);
void setVtolInFwdFlight (bool set);
void setFlightMode (const QString& flightMode);
protected: protected:
void _setDefaultCalibration (); void _setDefaultCalibration ();
void _saveSettings (); void _saveSettings ();
void _saveButtonSettings ();
void _loadSettings (); void _loadSettings ();
float _adjustRange (int value, Calibration_t calibration, bool withDeadbands); float _adjustRange (int value, Calibration_t calibration, bool withDeadbands);
void _buttonAction (const QString& action); void _executeButtonAction (const QString& action);
int _findAssignableButtonAction(const QString& action);
bool _validAxis (int axis); bool _validAxis (int axis);
bool _validButton (int button); bool _validButton (int button);
void _handleAxis ();
void _handleButtons ();
private: private:
virtual bool _open () = 0; virtual bool _open () = 0;
...@@ -229,7 +266,8 @@ protected: ...@@ -229,7 +266,8 @@ protected:
bool _accumulator = false; bool _accumulator = false;
bool _deadband = false; bool _deadband = false;
bool _circleCorrection = true; bool _circleCorrection = true;
float _frequency = 25.0f; float _axisFrequency = 25.0f;
float _buttonFrequency = 5.0f;
Vehicle* _activeVehicle = nullptr; Vehicle* _activeVehicle = nullptr;
bool _gimbalEnabled = false; bool _gimbalEnabled = false;
...@@ -244,25 +282,28 @@ protected: ...@@ -244,25 +282,28 @@ protected:
int _totalButtonCount; int _totalButtonCount;
static int _transmitterMode; static int _transmitterMode;
int _rgFunctionAxis[maxFunction] = {}; int _rgFunctionAxis[maxFunction] = {};
QTime _axisTime;
QStringList _rgButtonActions; QmlObjectListModel _assignableButtonActions;
QList<AssignedButtonAction*> _buttonActionArray;
MultiVehicleManager* _multiVehicleManager = nullptr; QStringList _availableActionTitles;
MultiVehicleManager* _multiVehicleManager = nullptr;
private: private:
static const char* _rgFunctionSettingsKey[maxFunction]; static const char* _rgFunctionSettingsKey[maxFunction];
static const char* _settingsGroup; static const char* _settingsGroup;
static const char* _calibratedSettingsKey; static const char* _calibratedSettingsKey;
static const char* _buttonActionSettingsKey; static const char* _buttonActionNameKey;
static const char* _buttonActionRepeatKey;
static const char* _throttleModeSettingsKey; static const char* _throttleModeSettingsKey;
static const char* _exponentialSettingsKey; static const char* _exponentialSettingsKey;
static const char* _accumulatorSettingsKey; static const char* _accumulatorSettingsKey;
static const char* _deadbandSettingsKey; static const char* _deadbandSettingsKey;
static const char* _circleCorrectionSettingsKey; static const char* _circleCorrectionSettingsKey;
static const char* _frequencySettingsKey; static const char* _axisFrequencySettingsKey;
static const char* _buttonFrequencySettingsKey;
static const char* _txModeSettingsKey; static const char* _txModeSettingsKey;
static const char* _fixedWingTXModeSettingsKey; static const char* _fixedWingTXModeSettingsKey;
static const char* _multiRotorTXModeSettingsKey; static const char* _multiRotorTXModeSettingsKey;
...@@ -271,13 +312,16 @@ private: ...@@ -271,13 +312,16 @@ private:
static const char* _submarineTXModeSettingsKey; static const char* _submarineTXModeSettingsKey;
static const char* _gimbalSettingsKey; static const char* _gimbalSettingsKey;
static const char* _buttonActionNone;
static const char* _buttonActionArm; static const char* _buttonActionArm;
static const char* _buttonActionDisarm; static const char* _buttonActionDisarm;
static const char* _buttonActionToggleArm; static const char* _buttonActionToggleArm;
static const char* _buttonActionVTOLFixedWing; static const char* _buttonActionVTOLFixedWing;
static const char* _buttonActionVTOLMultiRotor; static const char* _buttonActionVTOLMultiRotor;
static const char* _buttonActionZoomIn; static const char* _buttonActionStepZoomIn;
static const char* _buttonActionZoomOut; static const char* _buttonActionStepZoomOut;
static const char* _buttonActionContinuousZoomIn;
static const char* _buttonActionContinuousZoomOut;
static const char* _buttonActionNextStream; static const char* _buttonActionNextStream;
static const char* _buttonActionPreviousStream; static const char* _buttonActionPreviousStream;
static const char* _buttonActionNextCamera; static const char* _buttonActionNextCamera;
......
...@@ -32,6 +32,14 @@ QmlObjectListModel::~QmlObjectListModel() ...@@ -32,6 +32,14 @@ QmlObjectListModel::~QmlObjectListModel()
} }
QObject* QmlObjectListModel::get(int index)
{
if (index < 0 || index >= _objectList.count()) {
return nullptr;
}
return _objectList[index];
}
int QmlObjectListModel::rowCount(const QModelIndex& parent) const int QmlObjectListModel::rowCount(const QModelIndex& parent) const
{ {
Q_UNUSED(parent); Q_UNUSED(parent);
...@@ -160,19 +168,17 @@ void QmlObjectListModel::insert(int i, QObject* object) ...@@ -160,19 +168,17 @@ void QmlObjectListModel::insert(int i, QObject* object)
if (i < 0 || i > _objectList.count()) { if (i < 0 || i > _objectList.count()) {
qWarning() << "Invalid index index:count" << i << _objectList.count(); qWarning() << "Invalid index index:count" << i << _objectList.count();
} }
if(object) {
QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership); QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
// Look for a dirtyChanged signal on the object
// Look for a dirtyChanged signal on the object if (object->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("dirtyChanged(bool)")) != -1) {
if (object->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("dirtyChanged(bool)")) != -1) { if (!_skipDirtyFirstItem || i != 0) {
if (!_skipDirtyFirstItem || i != 0) { QObject::connect(object, SIGNAL(dirtyChanged(bool)), this, SLOT(_childDirtyChanged(bool)));
QObject::connect(object, SIGNAL(dirtyChanged(bool)), this, SLOT(_childDirtyChanged(bool))); }
} }
} }
_objectList.insert(i, object); _objectList.insert(i, object);
insertRows(i, 1); insertRows(i, 1);
setDirty(true); setDirty(true);
} }
......
...@@ -27,7 +27,7 @@ public: ...@@ -27,7 +27,7 @@ public:
/// a dirty property and dirtyChanged signal. /// a dirty property and dirtyChanged signal.
Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged) Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged)
Q_INVOKABLE QObject* get(int index) { return _objectList[index]; } Q_INVOKABLE QObject* get(int index);
// Property accessors // Property accessors
......
...@@ -61,6 +61,9 @@ SetupPage { ...@@ -61,6 +61,9 @@ SetupPage {
QGCTabBar { QGCTabBar {
id: bar id: bar
width: parent.width width: parent.width
Component.onCompleted: {
currentIndex = _activeJoystick && _activeJoystick.calibrated ? 0 : 2
}
anchors.top: parent.top anchors.top: parent.top
QGCTabButton { QGCTabButton {
text: qsTr("General") text: qsTr("General")
......
...@@ -144,20 +144,38 @@ Item { ...@@ -144,20 +144,38 @@ Item {
visible: advancedSettings.checked visible: advancedSettings.checked
} }
//----------------------------------------------------------------- //-----------------------------------------------------------------
//-- Message Frequency //-- Axis Message Frequency
QGCLabel { QGCLabel {
text: qsTr("Message frequency (Hz):") text: qsTr("Axis frequency (Hz):")
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
visible: advancedSettings.checked visible: advancedSettings.checked
} }
QGCTextField { QGCTextField {
text: _activeJoystick.frequency text: _activeJoystick.axisFrequency
enabled: advancedSettings.checked enabled: advancedSettings.checked
validator: DoubleValidator { bottom: 0.25; top: 100.0; } validator: DoubleValidator { bottom: 0.25; top: 50.0; }
inputMethodHints: Qt.ImhFormattedNumbersOnly inputMethodHints: Qt.ImhFormattedNumbersOnly
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
onEditingFinished: { onEditingFinished: {
_activeJoystick.frequency = parseFloat(text) _activeJoystick.axisFrequency = parseFloat(text)
}
visible: advancedSettings.checked
}
//-----------------------------------------------------------------
//-- Button Repeat Frequency
QGCLabel {
text: qsTr("Button repeat frequency (Hz):")
Layout.alignment: Qt.AlignVCenter
visible: advancedSettings.checked
}
QGCTextField {
text: _activeJoystick.buttonFrequency
enabled: advancedSettings.checked
validator: DoubleValidator { bottom: 0.25; top: 50.0; }
inputMethodHints: Qt.ImhFormattedNumbersOnly
Layout.alignment: Qt.AlignVCenter
onEditingFinished: {
_activeJoystick.buttonFrequency = parseFloat(text)
} }
visible: advancedSettings.checked visible: advancedSettings.checked
} }
......
...@@ -46,11 +46,7 @@ Item { ...@@ -46,11 +46,7 @@ Item {
Row { Row {
spacing: ScreenTools.defaultFontPixelWidth spacing: ScreenTools.defaultFontPixelWidth
property bool pressed property bool pressed
QGCCheckBox { property var currentAssignableAction: _activeJoystick ? _activeJoystick.assignableActions.get(buttonActionCombo.currentIndex) : null
anchors.verticalCenter: parent.verticalCenter
checked: _activeJoystick ? _activeJoystick.buttonActions[modelData] !== "" : false
onClicked: _activeJoystick.setButtonAction(modelData, checked ? buttonActionCombo.textAt(buttonActionCombo.currentIndex) : "")
}
Rectangle { Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: ScreenTools.defaultFontPixelHeight * 1.5 width: ScreenTools.defaultFontPixelHeight * 1.5
...@@ -69,9 +65,35 @@ Item { ...@@ -69,9 +65,35 @@ Item {
QGCComboBox { QGCComboBox {
id: buttonActionCombo id: buttonActionCombo
width: ScreenTools.defaultFontPixelWidth * 26 width: ScreenTools.defaultFontPixelWidth * 26
model: _activeJoystick ? _activeJoystick.actions : 0 model: _activeJoystick ? _activeJoystick.assignableActionTitles : []
onActivated: _activeJoystick.setButtonAction(modelData, textAt(index)) onActivated: {
Component.onCompleted: currentIndex = find(_activeJoystick.buttonActions[modelData]) _activeJoystick.setButtonAction(modelData, textAt(index))
}
Component.onCompleted: {
if(_activeJoystick) {
var i = find(_activeJoystick.buttonActions[modelData])
if(i < 0) i = 0
currentIndex = i
}
}
}
QGCCheckBox {
id: repeatCheck
text: qsTr("Repeat")
enabled: currentAssignableAction && _activeJoystick.calibrated && currentAssignableAction.canRepeat
onClicked: {
_activeJoystick.setButtonRepeat(modelData, checked)
}
Component.onCompleted: {
if(_activeJoystick) {
checked = _activeJoystick.getButtonRepeat(modelData)
}
}
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: ScreenTools.defaultFontPixelWidth * 2
height: 1
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment