1
0
Fork 0
mirror of https://github.com/betaflight/betaflight-configurator.git synced 2025-07-14 20:10:13 +03:00

Merge pull request #2296 from limonspb/esc_dshot_reverse

This commit is contained in:
Michael Keller 2021-01-01 15:31:06 +01:00 committed by GitHub
commit d5d0146af7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 1255 additions and 103 deletions

View file

@ -2586,6 +2586,82 @@
"message": "Start over"
},
"escDshotDirectionDialog-Title": {
"message": "Motor Direction - <strong class=\"message-negative-italic\">Warning: Ensure props are removed!</strong>"
},
"escDshotDirectionDialog-SelectMotor": {
"message": "Select one or all motors"
},
"escDshotDirectionDialog-SelectMotorSafety": {
"message": "Motors will spin when selected!"
},
"escDshotDirectionDialog-RiskNotice": {
"message": "<strong>Safety notice</strong><br /><strong class=\"message-negative-italic\">Remove all propellers to prevent injury!</strong><br />The motors will <strong>spin up</strong> immediately when selected!"
},
"escDshotDirectionDialog-UnderstandRisks": {
"message": "<strong>I understand the risks</strong>,<br />all propellers are removed."
},
"escDshotDirectionDialog-InformationNotice": {
"message": "<strong>Information notice</strong><br />To change the motor directions, the battery must be plugged in and the correct ESC protocol must be set up in the $t(tabConfiguration.message) tab. Note that not all Dshot ESCs will work with this dialog. Check your ESC firmware."
},
"escDshotDirectionDialog-NormalInformationNotice": {
"message": "Set motor spin direction by selecting and spinning each motor individually."
},
"escDshotDirectionDialog-WizardInformationNotice": {
"message": "Resets all motor spin directions, then allows the user to choose which to reverse."
},
"escDshotDirectionDialog-Open": {
"message": "Motor direction"
},
"escDshotDirectionDialog-CommandNormal": {
"message": "Normal"
},
"escDshotDirectionDialog-CommandReverse": {
"message": "Reverse"
},
"escDshotDirectionDialog-CommandSpin": {
"message": "Test motor"
},
"escDshotDirectionDialog-ReleaseButtonToStop": {
"message": "Release button to stop"
},
"escDshotDirectionDialog-ReleaseToStop": {
"message": "Release to stop"
},
"escDshotDirectionDialog-Start": {
"message": "Individually"
},
"escDshotDirectionDialog-StartWizard": {
"message": "Wizard"
},
"escDshotDirectionDialog-SetDirectionHint": {
"message": "Change direction of selected motor(s)"
},
"escDshotDirectionDialog-SetDirectionHintSafety": {
"message": "Motors will spin when setting the direction!"
},
"escDshotDirectionDialog-WrongProtocolText": {
"message": "Feature works with DSHOT ESCs only.<br />Verify that your ESC (electric speed controller) supports DSHOT protocol and change it on $t(tabConfiguration.message) tab."
},
"escDshotDirectionDialog-WrongMixerText": {
"message": "Number of motors is 0.<br />Verify the current Mixer on $t(tabConfiguration.message) tab or setup a custom one through CLI. Refer to this <a href=\"https://github.com/betaflight/betaflight/blob/master/docs/Mixer.md\" target=\"_blank\" rel=\"noopener noreferrer\">Wiki page</a>."
},
"escDshotDirectionDialog-WrongFirmwareText": {
"message": "Update the firmware.<br /> Make sure you are using the latest firmware: Betaflight 4.3 or newer."
},
"escDshotDirectionDialog-WizardActionHint": {
"message": "Click on motor numbers individually to change spin direction"
},
"escDshotDirectionDialog-WizardActionHintSecondLine": {
"message": "Verify all motors are spinning correctly"
},
"escDshotDirectionDialog-SpinWizard": {
"message": "Start / spin motors"
},
"escDshotDirectionDialog-StopWizard": {
"message": "Stop motors"
},
"sensorsInfo": {
"message": "Keep in mind that using fast update periods and rendering multiple graphs at the same time is resource heavy and will burn your battery quicker if you use a laptop.<br />We recommend to only render graphs for sensors you are interested in while using reasonable update periods."
},

View file

@ -0,0 +1,66 @@
<div class="escDshotDirection-Component">
<h3 i18n="escDshotDirectionDialog-Title" class="escDshotDirection-ComponentHeader"></h3>
<div class="componentContent" id="escDshotDirectionDialog-ConfigErrors">
<div class="escDshotDirectionErrorTextBlock" id="escDshotDirectionDialog-WrongProtocol" i18n="escDshotDirectionDialog-WrongProtocolText"></div>
<div class="escDshotDirectionErrorTextBlock" id="escDshotDirectionDialog-WrongMixer" i18n="escDshotDirectionDialog-WrongMixerText"></div>
<div class="escDshotDirectionErrorTextBlock" id="escDshotDirectionDialog-WrongFirmware" i18n="escDshotDirectionDialog-WrongFirmwareText"></div>
</div>
<div class="componentContent" id="escDshotDirectionDialog-MainContent">
<div id="escDshotDirectionDialog-MixerPreview" class="grey">
<img id="escDshotDirectionDialog-MixerPreviewImg" alt="" src="./resources/motor_order/custom.svg" />
</div>
<div id="escDshotDirectionDialog-NormalDialog" class="display-contents">
<h4 id="escDshotDirectionDialog-ActionHint" i18n="escDshotDirectionDialog-SelectMotor"></h4>
<h4 id="escDshotDirectionDialog-ActionHintSafety" i18n="escDshotDirectionDialog-SelectMotorSafety"></h4>
<div id="escDshotDirectionDialog-SelectMotorButtonsWrapper">
</div>
<div id = "escDshotDirectionDialog-SecondActionBlock" class="display-contents">
<h4 id="escDshotDirectionDialog-SecondHint" i18n="escDshotDirectionDialog-SetDirectionHint"></h4>
<h4 id="escDshotDirectionDialog-SecondHintSafety" i18n="escDshotDirectionDialog-SetDirectionHintSafety"></h4>
<div id="escDshotDirectionDialog-CommandsWrapper">
<a href="#" id="escDshotDirectionDialog-RotationNormal" class="regular-button" i18n="escDshotDirectionDialog-CommandNormal"></a>
<a href="#" id="escDshotDirectionDialog-RotationReverse" class="regular-button" i18n="escDshotDirectionDialog-CommandReverse"></a>
</div>
</div>
</div>
<div id="escDshotDirectionDialog-WizardDialog" class="display-contents">
<a href="#" id="escDshotDirectionDialog-SpinWizard" class="regular-button" i18n="escDshotDirectionDialog-SpinWizard"></a>
<div id="escDshotDirectionDialog-SpinningWizard" class="display-contents">
<h4 id="escDshotDirectionDialog-WizardActionHint" i18n="escDshotDirectionDialog-WizardActionHint"></h4>
<h4 id="escDshotDirectionDialog-WizardActionHintSecondLine" i18n="escDshotDirectionDialog-WizardActionHintSecondLine"></h4>
<div id="escDshotDirectionDialog-WizardMotorButtons">
</div>
<a href="#" id="escDshotDirectionDialog-StopWizard" class="regular-button" i18n="escDshotDirectionDialog-StopWizard"></a>
</div>
</div>
</div>
<div class="componentContent" id="escDshotDirectionDialog-Warning">
<div>
<p class="escDshotDirectionDialog-RiskNoticeText" i18n="escDshotDirectionDialog-RiskNotice"></p>
<div class="escDshotDirectionToggleParentContainer">
<div class="escDshotDirectionToggleNarrow">
<input id="escDshotDirectionDialog-safetyCheckbox" type="checkbox" class="toggle"/>
</div>
<div class="escDshotDirectionDialog-ToggleWide">
<span class="motorsEnableTestMode escDshotDirectionDialog-RiskNoticeText" i18n="escDshotDirectionDialog-UnderstandRisks"></span>
</div>
</div>
<div class="escDshotDirectionDialog-InformationNotice" i18n="escDshotDirectionDialog-InformationNotice"></div>
<div id="escDshotDirectionDialog-StartWizardBlock" class="escDshotDirectionDialog-StartBlock">
<div class="escDshotDirectionDialog-Buttons">
<a href="#" id="escDshotDirectionDialog-StartWizard" class="regular-button escDshotDirectionDialog-StartButton" i18n="escDshotDirectionDialog-StartWizard"></a>
</div>
<div class="escDshotDirectionDialog-Description" i18n="escDshotDirectionDialog-WizardInformationNotice"></div>
</div>
<div id="escDshotDirectionDialog-StartNormalBlock" class="escDshotDirectionDialog-StartBlock">
<div class="escDshotDirectionDialog-Buttons">
<a href="#" id="escDshotDirectionDialog-Start" class="regular-button escDshotDirectionDialog-StartButton" i18n="escDshotDirectionDialog-Start"></a>
</div>
<div class="escDshotDirectionDialog-Description" i18n="escDshotDirectionDialog-NormalInformationNotice"></div>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,67 @@
'use strict';
class EscDshotCommandQueue
{
constructor (intervalMs)
{
this._intervalId = null;
this._interval = intervalMs;
this._queue = [];
this._purging = false;
}
pushCommand(command, buffer)
{
this._queue.push([command, buffer]);
}
pushPause(milliseconds)
{
const counter = Math.ceil(milliseconds / this._interval);
for (let i = 0; i < counter; i++) {
this.pushCommand(null, null);
}
}
start()
{
if (null === this._intervalId) {
this._intervalId = setInterval(
() => { this._checkQueue(); },
this._interval);
}
}
stop()
{
if(null !== this._intervalId) {
clearInterval(this._intervalId);
this._intervalId = null;
}
}
stopWhenEmpty()
{
this._purging = true;
}
clear()
{
this._queue = [];
}
_checkQueue()
{
if (0 !== this._queue.length) {
const command = this._queue.shift();
if (null !== command[0]) {
MSP.send_message(command[0], command[1]);
}
} else if (this._purging) {
this._purging = false;
this.stop();
}
}
}

View file

@ -0,0 +1,383 @@
'use strict';
class EscDshotDirectionComponent
{
constructor(contentDiv, onLoadedCallback, motorConfig)
{
this._buttonTimeoutMs = 400;
const motorDriverQueueIntervalMs = 100;
const motorDriverStopMotorsPauseMs = 400;
this._motorDriver = new EscDshotDirectionMotorDriver(motorConfig,
motorDriverQueueIntervalMs, motorDriverStopMotorsPauseMs);
this._escProtocolIsDshot = motorConfig.escProtocolIsDshot;
this._numberOfMotors = motorConfig.numberOfMotors;
this._contentDiv = contentDiv;
this._onLoadedCallback = onLoadedCallback;
this._currentSpinningMotor = -1;
this._selectedMotor = -1;
this._motorIsSpinning = false;
this._allMotorsAreSpinning = false;
this._spinDirectionToggleIsActive = true;
this._activationButtonTimeoutId = null;
this._contentDiv.load("./components/EscDshotDirection/Body.html", () =>
{
this._initializeDialog();
});
}
static get PUSHED_BUTTON_CLASS() { return "pushed"; }
static get HIGHLIGHTED_BUTTON_CLASS() { return "highlighted"; }
static get RED_TEXT_CLASS() { return "red-text"; }
_readDom()
{
this._domAgreeSafetyCheckBox = $("#escDshotDirectionDialog-safetyCheckbox");
this._domStartButton = $("#escDshotDirectionDialog-Start");
this._domStartWizardButton = $("#escDshotDirectionDialog-StartWizard");
this._domMainContentBlock = $("#escDshotDirectionDialog-MainContent");
this._domWarningContentBlock = $("#escDshotDirectionDialog-Warning");
this._domMixerImg = $("#escDshotDirectionDialog-MixerPreviewImg");
this._domMotorButtonsBlock = $("#escDshotDirectionDialog-SelectMotorButtonsWrapper");
this._domSpinDirectionWrapper = $("#escDshotDirectionDialog-CommandsWrapper");
this._domActionHint = $("#escDshotDirectionDialog-ActionHint");
this._domSpinNormalButton = $("#escDshotDirectionDialog-RotationNormal");
this._domSpinReverseButton = $("#escDshotDirectionDialog-RotationReverse");
this._domSecondHint = $("#escDshotDirectionDialog-SecondHint");
this._domSecondActionDiv = $("#escDshotDirectionDialog-SecondActionBlock");
this._domConfigErrors = $("#escDshotDirectionDialog-ConfigErrors");
this._domWrongProtocolMessage = $("#escDshotDirectionDialog-WrongProtocol");
this._domWrongMixerMessage = $("#escDshotDirectionDialog-WrongMixer");
this._domWrongFirmwareMessage = $("#escDshotDirectionDialog-WrongFirmware");
this._domWizardBlock = $("#escDshotDirectionDialog-WizardDialog");
this._domNormalDialogBlock = $("#escDshotDirectionDialog-NormalDialog");
this._domSpinningWizard = $("#escDshotDirectionDialog-SpinningWizard");
this._domSpinWizardButton = $("#escDshotDirectionDialog-SpinWizard");
this._domStopWizardButton = $("#escDshotDirectionDialog-StopWizard");
this._domWizardMotorButtonsBlock = $("#escDshotDirectionDialog-WizardMotorButtons");
this._domStartWizardBlock = $("#escDshotDirectionDialog-StartWizardBlock");
this._domStartNormalBlock = $("#escDshotDirectionDialog-StartNormalBlock");
this._topHintText = i18n.getMessage("escDshotDirectionDialog-SelectMotor");
this._releaseToStopText = i18n.getMessage("escDshotDirectionDialog-ReleaseToStop");
this._releaseButtonToStopText = i18n.getMessage("escDshotDirectionDialog-ReleaseButtonToStop");
this._normalText = i18n.getMessage("escDshotDirectionDialog-CommandNormal");
this._reverseText = i18n.getMessage("escDshotDirectionDialog-CommandReverse");
this._secondHintText = i18n.getMessage("escDshotDirectionDialog-SetDirectionHint");
}
_initializeDialog()
{
this._readDom();
this._createMotorButtons();
this._createWizardMotorButtons();
this._domSecondActionDiv.toggle(false);
i18n.localizePage();
this._resetGui();
this._domAgreeSafetyCheckBox.on("change", () => {
const enabled = this._domAgreeSafetyCheckBox.is(':checked');
this._domStartNormalBlock.toggle(enabled);
this._domStartWizardBlock.toggle(enabled);
});
this._domStartButton.on("click", () => {
this._onStartButtonClicked();
});
this._domStartWizardButton.on("click", () => {
this._onStartWizardButtonClicked();
});
this._domSpinWizardButton.on("click", () => {
this._onSpinWizardButtonClicked();
});
this._domStopWizardButton.on("click", () => {
this._onStopWizardButtonClicked();
});
const imgSrc = CommonUtils.GetMixerImageSrc(FC.MIXER_CONFIG.mixer, FC.MIXER_CONFIG.reverseMotorDir, FC.CONFIG.apiVersion);
this._domMixerImg.attr('src', imgSrc);
this._onLoadedCallback();
}
_activateNormalReverseButtons(timeoutMs)
{
this._activationButtonTimeoutId = setTimeout(() => {
this._subscribeDirectionSpinButton(this._domSpinNormalButton,
DshotCommand.dshotCommands_e.DSHOT_CMD_SPIN_DIRECTION_1, this._normalText);
this._subscribeDirectionSpinButton(this._domSpinReverseButton,
DshotCommand.dshotCommands_e.DSHOT_CMD_SPIN_DIRECTION_2, this._reverseText);
}, timeoutMs);
}
_deactivateNormalReverseButtons()
{
if (null !== this._activationButtonTimeoutId)
{
clearTimeout(this._activationButtonTimeoutId);
}
this._domSpinNormalButton.off();
this._domSpinReverseButton.off();
}
_subscribeDirectionSpinButton(button, direction, buttonText)
{
button.on("mousedown touchstart", () => {
this._sendCurrentEscSpinDirection(direction);
this._motorIsSpinning = true;
button.text(this._releaseToStopText);
button.addClass(EscDshotDirectionComponent.HIGHLIGHTED_BUTTON_CLASS);
this._motorDriver.spinMotor(this._selectedMotor);
this._domSecondHint.html(this._releaseButtonToStopText);
this._domSecondHint.addClass(EscDshotDirectionComponent.RED_TEXT_CLASS);
});
button.on("mouseup mouseout touchend", () => {
if (this._motorIsSpinning) {
button.text(buttonText);
this._motorIsSpinning = false;
button.removeClass(EscDshotDirectionComponent.HIGHLIGHTED_BUTTON_CLASS);
this._motorDriver.stopAllMotors();
this._domSecondHint.text(this._secondHintText);
this._domSecondHint.removeClass(EscDshotDirectionComponent.RED_TEXT_CLASS);
this._deactivateNormalReverseButtons();
this._activateNormalReverseButtons(this._buttonTimeoutMs);
}
});
}
_sendCurrentEscSpinDirection(direction)
{
this._motorDriver.setEscSpinDirection(this._selectedMotor, direction);
}
_createMotorButtons()
{
this._motorButtons = {};
for (let i = 0; i < this._numberOfMotors; i++) {
this._addMotorButton(i + 1, i);
}
this._addMotorButton("All", DshotCommand.ALL_MOTORS);
}
_addMotorButton(buttonText, motorIndex)
{
const button = $(`<a href="#" class="regular-button ${EscDshotDirectionComponent.PUSHED_BUTTON_CLASS}"></a>`).text(buttonText);
this._domMotorButtonsBlock.append(button);
this._motorButtons[motorIndex] = button;
button.on("mousedown touchstart", () => {
this._domSecondActionDiv.toggle(true);
this._motorIsSpinning = true;
this._domActionHint.html(this._releaseButtonToStopText);
this._domActionHint.addClass(EscDshotDirectionComponent.RED_TEXT_CLASS);
this._changeSelectedMotor(motorIndex);
button.addClass(EscDshotDirectionComponent.HIGHLIGHTED_BUTTON_CLASS);
this._motorDriver.spinMotor(this._selectedMotor);
});
button.on("mouseup mouseout touchend", () => {
if (this._motorIsSpinning) {
this._domActionHint.html(this._topHintText);
this._domActionHint.removeClass(EscDshotDirectionComponent.RED_TEXT_CLASS);
this._motorIsSpinning = false;
button.removeClass(EscDshotDirectionComponent.HIGHLIGHTED_BUTTON_CLASS);
this._motorDriver.stopAllMotors();
this._deactivateNormalReverseButtons();
this._activateNormalReverseButtons(this._buttonTimeoutMs);
}
});
}
_createWizardMotorButtons()
{
this._wizardMotorButtons = {};
for (let i = 0; i < this._numberOfMotors; i++) {
this._addWizardMotorButton(i + 1, i);
}
}
_activateWizardMotorButtons(timeoutMs)
{
this._activationButtonTimeoutId = setTimeout(() => {
for (let i = 0; i < this._numberOfMotors; i++) {
this._activateWizardMotorButton(i);
}
}, timeoutMs);
}
_deactivateWizardMotorButtons()
{
if (null !== this._activationButtonTimeoutId)
{
clearTimeout(this._activationButtonTimeoutId);
}
for (let i = 0; i < this._numberOfMotors; i++) {
const button = this._wizardMotorButtons[i];
button.off();
}
}
_addWizardMotorButton(buttonText, motorIndex)
{
const button = $(`<a href="#" class="regular-button"></a>`).text(buttonText);
this._domWizardMotorButtonsBlock.append(button);
this._wizardMotorButtons[motorIndex] = button;
}
_activateWizardMotorButton(motorIndex)
{
const button = this._wizardMotorButtons[motorIndex];
button.on("click", () => {
this._wizardMotorButtonClick(button, motorIndex);
});
}
_wizardMotorButtonClick(button, motorIndex)
{
this._deactivateWizardMotorButtons();
const currentlyDown = button.hasClass(EscDshotDirectionComponent.PUSHED_BUTTON_CLASS);
if (currentlyDown) {
button.removeClass(EscDshotDirectionComponent.PUSHED_BUTTON_CLASS);
this._motorDriver.setEscSpinDirection(motorIndex, DshotCommand.dshotCommands_e.DSHOT_CMD_SPIN_DIRECTION_1);
} else {
this._motorDriver.setEscSpinDirection(motorIndex, DshotCommand.dshotCommands_e.DSHOT_CMD_SPIN_DIRECTION_2);
button.addClass(EscDshotDirectionComponent.PUSHED_BUTTON_CLASS);
}
this._activateWizardMotorButtons(this._buttonTimeoutMs);
}
_changeSelectedMotor(newIndex)
{
if (this._selectedMotor >= 0) {
this._motorButtons[this._selectedMotor].addClass(EscDshotDirectionComponent.PUSHED_BUTTON_CLASS);
}
this._selectedMotor = newIndex;
if (this._selectedMotor > -1) {
this._motorButtons[this._selectedMotor].removeClass(EscDshotDirectionComponent.PUSHED_BUTTON_CLASS);
}
}
close()
{
this._motorDriver.stopAllMotorsNow();
this._motorDriver.deactivate();
this._resetGui();
}
_resetGui()
{
this._toggleMainContent(false);
this._domStartNormalBlock.hide();
this._domStartWizardBlock.hide();
this._domAgreeSafetyCheckBox.prop('checked', false);
this._domAgreeSafetyCheckBox.trigger('change');
this._domSecondActionDiv.toggle(false);
this._changeSelectedMotor(-1);
this._checkForConfigurationErrors();
}
_checkForConfigurationErrors()
{
let anyError = false;
this._domWrongProtocolMessage.hide();
this._domWrongMixerMessage.hide();
this._domWrongFirmwareMessage.hide();
if (!this._escProtocolIsDshot) {
anyError = true;
this._domWrongProtocolMessage.show();
}
if (this._numberOfMotors <= 0) {
anyError = true;
this._domWrongMixerMessage.show();
}
if (!semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
// if BF4.2 or older - show the error message
anyError = true;
this._domWrongFirmwareMessage.show();
}
if (anyError) {
this._domMainContentBlock.hide();
this._domWarningContentBlock.hide();
this._domStartNormalBlock.hide();
this._domStartWizardBlock.hide();
this._domConfigErrors.show();
} else {
this._domConfigErrors.hide();
}
}
_onStartButtonClicked()
{
this._toggleMainContent(true);
this._domWizardBlock.toggle(false);
this._domNormalDialogBlock.toggle(true);
this._motorDriver.activate();
}
_onStartWizardButtonClicked()
{
this._domSpinningWizard.toggle(false);
this._domSpinWizardButton.toggle(true);
this._toggleMainContent(true);
this._domWizardBlock.toggle(true);
this._domNormalDialogBlock.toggle(false);
this._motorDriver.activate();
}
_onSpinWizardButtonClicked()
{
for (let i = 0; i < this._numberOfMotors; i++) {
this._wizardMotorButtons[i].removeClass(EscDshotDirectionComponent.PUSHED_BUTTON_CLASS);
}
this._motorDriver.setEscSpinDirection(DshotCommand.ALL_MOTORS, DshotCommand.dshotCommands_e.DSHOT_CMD_SPIN_DIRECTION_1);
this._domSpinWizardButton.toggle(false);
this._domSpinningWizard.toggle(true);
this._motorDriver.spinAllMotors();
this._activateWizardMotorButtons(0);
}
_onStopWizardButtonClicked()
{
this._domSpinWizardButton.toggle(true);
this._domSpinningWizard.toggle(false);
this._motorDriver.stopAllMotorsNow();
this._deactivateWizardMotorButtons();
}
_toggleMainContent(value)
{
this._domWarningContentBlock.toggle(!value);
this._domMainContentBlock.toggle(value);
this._domConfigErrors.toggle(false);
}
}

View file

@ -0,0 +1,155 @@
'use strict';
class EscDshotDirectionMotorDriver
{
constructor(motorConfig, motorDriverQueueIntervalMs, motorDriverStopMotorsPauseMs)
{
this._numberOfMotors = motorConfig.numberOfMotors;
this._motorStopValue = motorConfig.motorStopValue;
this._motorSpinValue = motorConfig.motorSpinValue;
this._motorDriverStopMotorsPauseMs = motorDriverStopMotorsPauseMs;
this._state = [];
for (let i = 0; i < this._numberOfMotors; i++)
{
this._state.push(this._motorStopValue);
}
this._stateStack = [];
this._EscDshotCommandQueue = new EscDshotCommandQueue(motorDriverQueueIntervalMs);
}
activate()
{
this._EscDshotCommandQueue.start();
}
deactivate()
{
this._EscDshotCommandQueue.stopWhenEmpty();
}
stopMotor(motorIndex)
{
this._spinMotor(motorIndex, this._motorStopValue);
}
spinMotor(motorIndex)
{
this._spinMotor(motorIndex, this._motorSpinValue);
}
spinAllMotors()
{
this._spinAllMotors(this._motorSpinValue);
}
stopAllMotors()
{
this._spinAllMotors(this._motorStopValue);
}
stopAllMotorsNow()
{
this._EscDshotCommandQueue.clear();
this._spinAllMotors(this._motorStopValue);
}
setEscSpinDirection(motorIndex, direction)
{
let needStopMotor = false;
if (DshotCommand.ALL_MOTORS === motorIndex) {
needStopMotor = this._isAnythingSpinning();
} else {
needStopMotor = this._isMotorSpinning(motorIndex);
}
if (needStopMotor) {
this._pushState();
this._spinMotor(motorIndex, this._motorStopValue);
this._EscDshotCommandQueue.pushPause(this._motorDriverStopMotorsPauseMs);
this._sendEscSpinDirection(motorIndex, direction);
this._popState();
this._sendState();
} else {
this._sendEscSpinDirection(motorIndex, direction);
}
}
_pushState()
{
const state = [...this._state];
this._stateStack.push(state);
}
_popState()
{
const state = this._stateStack.pop();
this._state = [...state];
}
_isAnythingSpinning()
{
let result = false;
for (let i = 0; i < this._numberOfMotors; i++) {
if (this._motorStopValue !== this._state[i]) {
result = true;
break;
}
}
return result;
}
_isMotorSpinning(motorIndex)
{
return (this._motorStopValue !== this._state[motorIndex]);
}
_sendEscSpinDirection(motorIndex, direction)
{
const buffer = [];
buffer.push8(DshotCommand.dshotCommandType_e.DSHOT_CMD_TYPE_BLOCKING);
buffer.push8(motorIndex);
buffer.push8(2); // two commands
buffer.push8(direction);
buffer.push8(DshotCommand.dshotCommands_e.DSHOT_CMD_SAVE_SETTINGS);
this._EscDshotCommandQueue.pushCommand(MSPCodes.MSP2_SEND_DSHOT_COMMAND, buffer);
}
_spinMotor(motorIndex, value)
{
if (DshotCommand.ALL_MOTORS === motorIndex) {
this._spinAllMotors(value);
} else {
this._state[motorIndex] = value;
this._sendState();
}
}
_spinAllMotors(value)
{
for (let i = 0; i < this._numberOfMotors; i++) {
this._state[i] = value;
}
this._sendState();
}
_sendState()
{
const buffer = [];
for (let i = 0; i < this._numberOfMotors; i++) {
buffer.push16(this._state[i]);
}
this._EscDshotCommandQueue.pushCommand(MSPCodes.MSP_SET_MOTOR, buffer);
}
}

View file

@ -0,0 +1,177 @@
.escDshotDirection-Component {
display: flex;
height: 100%;
flex-flow: column;
}
.escDshotDirection-ComponentHeader {
padding-bottom: 12px;
}
#escDshotDirectionDialog-MainContent {
display: flex;
height: 100%;
flex-flow: column;
}
#escDshotDirectionDialog-Warning {
display: flex;
height: 100%;
flex-flow: column;
border-top: 1px solid var(--superSubtleAccent);
padding-top: 16px;
}
.escDshotDirectionToggleParentContainer {
display: flex;
margin-bottom: 1.5em;
margin-top: 1.5em;
}
.escDshotDirectionToggleNarrow {
margin-right: 12px;
display: flex;
align-items: center;
}
.escDshotDirectionDialog-ToggleWide {
flex: 1;
}
.escDshotDirectionDialog-RiskNoticeText {
font-size: 1.2em;
}
.escDshotDirectionDialogInformationNotice {
font-size: 1.0em;
margin-bottom: 1.5em;
margin-top: 1.5em;
}
#escDshotDirectionDialog-MixerPreview {
width: 100%;
padding-top: 8px;
padding-bottom: 9px;
margin-bottom: 8px;
}
#escDshotDirectionDialog-MixerPreviewImg {
display: block;
width: 160px;
height: 160px;
margin-left: auto;
margin-right: auto;
margin-top: auto;
margin-bottom: auto;
}
#escDshotDirectionDialog-MainContent h4 {
margin-left: auto;
margin-right: auto;
font-weight: 500;
}
#escDshotDirectionDialog-MainContent .red-text {
color: #EE0000;
}
#escDshotDirectionDialog-ActionHint, #escDshotDirectionDialog-SecondHint, #escDshotDirectionDialog-WizardActionHint {
margin-top: 10px;
}
#escDshotDirectionDialog-ActionHintSafety, #escDshotDirectionDialog-SecondHintSafety {
margin-top: 0px;
}
#escDshotDirectionDialog-SelectMotorButtonsWrapper, #escDshotDirectionDialog-WizardMotorButtons {
margin-left: auto;
margin-right: auto;
}
#escDshotDirectionDialog-SelectMotorButtonsWrapper .regular-button, #escDshotDirectionDialog-WizardMotorButtons .regular-button {
font-size: 15px;
line-height: 34px;
padding: 0px;
margin-left: 4px;
margin-right: 4px;
border-radius: 17px;
width: 34px;
height: 34px;
text-align: center;
}
#escDshotDirectionDialog-NormalDialog .regular-button.pushed:hover {
background-color: #993333;
}
#escDshotDirectionDialog-NormalDialog .regular-button:hover {
background-color: #993333;
}
#escDshotDirectionDialog-MainContent .regular-button.highlighted {
background-color: #EE2222;
}
#escDshotDirectionDialog-CommandsWrapper {
margin-left: auto;
margin-right: auto;
}
#escDshotDirectionDialog-CommandSpin {
margin-left: auto;
margin-right: auto;
width: 224px;
display: block;
text-align: center;
}
#escDshotDirectionDialog-CommandsWrapper .regular-button {
width: 130px;
text-align: center;
margin-left: 5px;
margin-right: 5px;
}
.escDshotDirectionErrorTextBlock {
margin-top: 12px;
font-weight: 500;
}
.display-contents {
display: contents;
}
#escDshotDirectionDialog-SpinWizard, #escDshotDirectionDialog-StopWizard {
margin-left: auto;
margin-right: auto;
width: 160px;
text-align: center;
}
.escDshotDirectionDialog-InformationNotice {
margin-top: 18px;
padding-top: 16px;
padding-bottom: 16px;
border-top: 1px solid var(--superSubtleAccent);
border-bottom: 1px solid var(--superSubtleAccent);
}
.escDshotDirectionDialog-StartButton {
width: 80px;
text-align: center;
margin-left: 0px;
margin-right: 16px;
margin-top: 0px;
margin-bottom: 0px;
}
.escDshotDirectionDialog-Buttons {
float: left;
margin: 0px;
}
.escDshotDirectionDialog-StartBlock {
display: flex;
margin-top: 16px;
}

View file

@ -25,7 +25,7 @@ class MotorOutputReorderComponent
_readDom()
{
this._domAgreeSafetyCheckBox = $('#motorsEnableTestMode-dialogMotorOutputReorder');
this._domAgreeButton = $('#dialogMotorOutputReorderAgreeButton');
this._domStartButton = $('#dialogMotorOutputReorderAgreeButton');
this._domStartOverButton = $('#motorsRemapDialogStartOver');
this._domSaveButton = $('#motorsRemapDialogSave');
this._domMainContentBlock = $('#dialogMotorOutputReorderMainContent');
@ -44,12 +44,12 @@ class MotorOutputReorderComponent
this._domAgreeSafetyCheckBox.change(() =>
{
const enabled = this._domAgreeSafetyCheckBox.is(':checked');
this._domAgreeButton.toggle(enabled);
this._domStartButton.toggle(enabled);
});
this._domAgreeButton.click(() =>
this._domStartButton.click(() =>
{
this._onAgreeButtonClicked();
this._onStartButtonClicked();
});
this._domStartOverButton.click(() =>
{
@ -75,7 +75,7 @@ class MotorOutputReorderComponent
{
this._domMainContentBlock.hide();
this._domWarningContentBlock.show();
this._domAgreeButton.hide();
this._domStartButton.hide();
this._domAgreeSafetyCheckBox.prop('checked', false);
this._domAgreeSafetyCheckBox.change();
@ -138,7 +138,7 @@ class MotorOutputReorderComponent
}
}
_onAgreeButtonClicked()
_onStartButtonClicked()
{
this._domActionHintBlock.text(i18n.getMessage("motorOutputReorderDialogSelectSpinningMotor"));
this._domWarningContentBlock.hide();

View file

@ -5,8 +5,6 @@
}
.motorOutputReorderComponentHeader {
border-bottom: 1px solid var(--accent);
margin-bottom: 10px;
padding-bottom: 12px;
}

View file

@ -14,6 +14,10 @@
--gimbalBackground: var(--subtleAccent);
--gimbalCrosshair: var(--mutedText);
--switcherysecond: #858585;
--pushedButton-background: #616161;
--pushedButton-fontColor: #ffffff;
--hoverButton-background: #ffcc3e;
--superSubtleAccent: #595959;
}
.background_paper {
@ -24,6 +28,11 @@ body {
color: white;
}
::backdrop {
background-image: none;
background-color: rgba(0, 0, 0, 0.5);
}
#options-window {
background-color: #393b3a;
}
@ -219,7 +228,7 @@ button {
}
.tab-auxiliary .buttons a:hover {
background-color: #393b3a;
background-color: var(--hoverButton-background);
}
@ -357,7 +366,7 @@ button {
}
.tab-gps #loadmap .controls a:hover {
background-color: #393b3a;
background-color: var(--hoverButton-background);
}
.tab-gps #loadmap .controls a:active {

View file

@ -16,6 +16,10 @@
--gimbalBackground: #eee;
--gimbalCrosshair: var(--subtleAccent);
--switcherysecond: #c4c4c4;
--pushedButton-background: #c4c4c4;
--pushedButton-fontColor: #000000;
--hoverButton-background: #ffcc3e;
--superSubtleAccent: #CCCCCC;
}
* {
@ -40,6 +44,11 @@ body {
overflow: hidden;
}
::backdrop {
background-image: none;
background-color: rgba(1, 1, 1, 0.5);
}
a {
text-decoration: none;
color: var(--linkText);
@ -140,7 +149,11 @@ input[type="number"]::-webkit-inner-spin-button {
font-weight: bold !important;
}
.message-negative-italic {
color: var(--error) !important;
font-weight: bold !important;
font-style: italic;
}
/** Main wrapper **/
#main-wrapper {
@ -1478,7 +1491,7 @@ dialog .dialog_toolbar .btn a {
}
dialog .dialog_toolbar .btn a:hover {
background-color: #ffcc3e;
background-color: var(--hoverButton-background);
transition: all ease 0.2s;
}
@ -1574,7 +1587,7 @@ dialog .dialog_toolbar .btn a.disabled {
}
.content_toolbar .btn a:hover {
background-color: #ffcc3e;
background-color: var(--hoverButton-background);
transition: all ease 0.2s;
}
@ -1862,7 +1875,7 @@ dialog .dialog_toolbar .btn a.disabled {
}
.fixed_band .save_btn a:hover {
background-color: #ffcc3f;
background-color: var(--hoverButton-background);
transition: all ease 0.2s;
}
@ -1898,7 +1911,7 @@ dialog .dialog_toolbar .btn a.disabled {
}
.default_btn a:hover {
background-color: #ffcc3f;
background-color: var(--hoverButton-background);
color: #000;
text-shadow: 0 1px rgba(255, 255, 255, 0.25);
transition: all ease 0.2s;
@ -1907,7 +1920,7 @@ dialog .dialog_toolbar .btn a.disabled {
}
.default_btn a:active {
background-color: #ffcc3f;
background-color: var(--hoverButton-background);
transition: all ease 0.0s;
box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.35);
}
@ -1917,6 +1930,7 @@ dialog .dialog_toolbar .btn a.disabled {
}
.regular-button {
-webkit-user-drag: none;
margin-top: 8px;
margin-bottom: 8px;
margin-right: 10px;
@ -1934,6 +1948,16 @@ dialog .dialog_toolbar .btn a.disabled {
line-height: 28px;
}
.regular-button:hover {
background-color: var(--hoverButton-background);
}
.regular-button.pushed {
background-color: var(--pushedButton-background);
color: var(--pushedButton-fontColor);
border-radius: 3px;
}
.small {
width: auto;
position: relative;

View file

@ -25,7 +25,7 @@
.tab-motors #dialogMotorOutputReorder {
width: 400px;
height:440px
height: 440px
;}
.tab-motors #dialogMotorOutputReorderContentWrapper {
@ -39,6 +39,31 @@
flex-grow: 1;
}
.tab-motors #escDshotDirectionDialog-closebtn {
margin-right: 0px;
margin-bottom: 0px;
position: absolute;
right: 0px;
bottom: 0px;
}
.tab-motors #escDshotDirectionDialog {
width: 400px;
height: 440px;
}
.tab-motors #escDshotDirectionDialog-ContentWrapper {
display: flex;
flex-flow: column;
width: 100%;
height: 100%;
position: relative;
}
.tab-motors #escDshotDirectionDialog-Content {
flex-grow: 1;
}
.tab-motors .mixerPreview img {
width: 120px;
height: 120px;
@ -457,4 +482,16 @@
margin: 0;
height: auto;
}
.tab-motors #escDshotDirectionDialog- {
position: fixed;
width: calc(100% - 2em);
bottom: 0;
top: 56px;
border-radius: unset;
border: none;
overflow: auto;
margin: 0;
height: auto;
}
}

View file

@ -181,4 +181,5 @@ const MSPCodes = {
MSP2_BETAFLIGHT_BIND: 0x3000,
MSP2_MOTOR_OUTPUT_REORDERING: 0x3001,
MSP2_SET_MOTOR_OUTPUT_REORDERING: 0x3002,
MSP2_SEND_DSHOT_COMMAND: 0x3003,
};

View file

@ -57,26 +57,6 @@ function MspHelper() {
self.mspMultipleCache = [];
}
MspHelper.prototype.reorderPwmProtocols = function (protocol) {
let result = protocol;
if (semver.lt(FC.CONFIG.apiVersion, "1.26.0")) {
switch (protocol) {
case 5:
result = 7;
break;
case 7:
result = 5;
break;
default:
break;
}
}
return result;
}
MspHelper.prototype.process_data = function(dataHandler) {
const self = this;
const data = dataHandler.dataView; // DataView (allowing us to view arrayBuffer as struct/union)
@ -1039,7 +1019,7 @@ MspHelper.prototype.process_data = function(dataHandler) {
FC.PID_ADVANCED_CONFIG.gyro_sync_denom = data.readU8();
FC.PID_ADVANCED_CONFIG.pid_process_denom = data.readU8();
FC.PID_ADVANCED_CONFIG.use_unsyncedPwm = data.readU8();
FC.PID_ADVANCED_CONFIG.fast_pwm_protocol = self.reorderPwmProtocols(data.readU8());
FC.PID_ADVANCED_CONFIG.fast_pwm_protocol = EscProtocols.ReorderPwmProtocols(FC.CONFIG.apiVersion, data.readU8());
FC.PID_ADVANCED_CONFIG.motor_pwm_rate = data.readU16();
if (semver.gte(FC.CONFIG.apiVersion, "1.24.0")) {
FC.PID_ADVANCED_CONFIG.digitalIdlePercent = data.readU16() / 100;
@ -1569,6 +1549,9 @@ MspHelper.prototype.process_data = function(dataHandler) {
case MSPCodes.MSP2_SET_MOTOR_OUTPUT_REORDERING:
console.log('Motor output reordering set');
break;
case MSPCodes.MSP2_SEND_DSHOT_COMMAND:
console.log('DSHOT command sent');
break;
case MSPCodes.MSP_MULTIPLE_MSP:
@ -1981,7 +1964,7 @@ MspHelper.prototype.crunch = function(code) {
buffer.push8(FC.PID_ADVANCED_CONFIG.gyro_sync_denom)
.push8(FC.PID_ADVANCED_CONFIG.pid_process_denom)
.push8(FC.PID_ADVANCED_CONFIG.use_unsyncedPwm)
.push8(self.reorderPwmProtocols(FC.PID_ADVANCED_CONFIG.fast_pwm_protocol))
.push8(EscProtocols.ReorderPwmProtocols(FC.CONFIG.apiVersion, FC.PID_ADVANCED_CONFIG.fast_pwm_protocol))
.push16(FC.PID_ADVANCED_CONFIG.motor_pwm_rate);
if (semver.gte(FC.CONFIG.apiVersion, "1.24.0")) {
buffer.push16(FC.PID_ADVANCED_CONFIG.digitalIdlePercent * 100);
@ -2278,6 +2261,10 @@ MspHelper.prototype.crunch = function(code) {
break;
case MSPCodes.MSP2_SEND_DSHOT_COMMAND:
buffer.push8(1);
break;
default:
return false;
}

View file

@ -213,14 +213,8 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
}
function refreshMixerPreview() {
const mixer = FC.MIXER_CONFIG.mixer
let reverse = "";
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_36)) {
reverse = FC.MIXER_CONFIG.reverseMotorDir ? "_reversed" : "";
}
$('.mixerPreview img').attr('src', './resources/motor_order/' + mixerList[mixer - 1].image + reverse + '.svg');
const imgSrc = CommonUtils.GetMixerImageSrc(FC.MIXER_CONFIG.mixer, FC.MIXER_CONFIG.reverseMotorDir, FC.CONFIG.apiVersion);
$('.mixerPreview img').attr('src', imgSrc);
}
const reverseMotorSwitch_e = $('#reverseMotorSwitch');
@ -462,34 +456,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
}
// ESC protocols
const escProtocols = [
'PWM',
'ONESHOT125',
'ONESHOT42',
'MULTISHOT',
];
if (semver.gte(FC.CONFIG.apiVersion, "1.20.0")) {
escProtocols.push('BRUSHED');
}
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_31)) {
escProtocols.push('DSHOT150');
escProtocols.push('DSHOT300');
escProtocols.push('DSHOT600');
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_42)) {
escProtocols.push('DSHOT1200');
}
}
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_36)) {
escProtocols.push('PROSHOT1000');
}
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_43)) {
escProtocols.push('DISABLED');
}
const escProtocols = EscProtocols.GetAvailableProtocols(FC.CONFIG.apiVersion);
const esc_protocol_e = $('select.escprotocol');

View file

@ -31,7 +31,8 @@ TABS.motors = {
// These are translated into proper Dshot values on the flight controller
DSHOT_DISARMED_VALUE: 1000,
DSHOT_MAX_VALUE: 2000,
DSHOT_3D_NEUTRAL: 1500
DSHOT_3D_NEUTRAL: 1500,
numberOfValidOutputs: -1,
};
TABS.motors.initialize = function (callback) {
@ -105,7 +106,7 @@ TABS.motors.initialize = function (callback) {
}
function initDataArray(length) {
const data = new Array(length);
const data = Array.from({length: length});
for (let i = 0; i < length; i++) {
data[i] = [];
data[i].min = -1;
@ -126,8 +127,8 @@ TABS.motors.initialize = function (callback) {
}
}
while (data[0].length > 300) {
for (let i = 0; i < data.length; i++) {
data[i].shift();
for (const item of data) {
item.shift();
}
}
return sampleNumber + 1;
@ -220,13 +221,8 @@ TABS.motors.initialize = function (callback) {
}
function update_model(mixer) {
let reverse = "";
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_36)) {
reverse = FC.MIXER_CONFIG.reverseMotorDir ? "_reversed" : "";
}
$('.mixerPreview img').attr('src', './resources/motor_order/' + mixerList[mixer - 1].image + reverse + '.svg');
const imgSrc = CommonUtils.GetMixerImageSrc(mixer, FC.MIXER_CONFIG.reverseMotorDir, FC.CONFIG.apiVersion);
$('.mixerPreview img').attr('src', imgSrc);
const motorOutputReorderConfig = new MotorOutputReorderConfig(100);
const domMotorOutputReorderDialogOpen = $('#motorOutputReorderDialogOpen');
@ -234,6 +230,8 @@ TABS.motors.initialize = function (callback) {
const isMotorReorderingAvailable = (mixerList[mixer - 1].name in motorOutputReorderConfig)
&& (FC.MOTOR_OUTPUT_ORDER) && (FC.MOTOR_OUTPUT_ORDER.length > 0);
domMotorOutputReorderDialogOpen.toggle(isMotorReorderingAvailable);
self.escProtocolIsDshot = EscProtocols.IsProtocolDshot(FC.CONFIG.apiVersion, FC.PID_ADVANCED_CONFIG.fast_pwm_protocol);
}
function process_html() {
@ -244,12 +242,6 @@ TABS.motors.initialize = function (callback) {
self.feature3DEnabled = FC.FEATURE_CONFIG.features.isEnabled('3D');
if (FC.PID_ADVANCED_CONFIG.fast_pwm_protocol >= TABS.configuration.DSHOT_PROTOCOL_MIN_VALUE) {
self.escProtocolIsDshot = true;
} else {
self.escProtocolIsDshot = false;
}
$('#motorsEnableTestMode').prop('checked', false);
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_42) || !(FC.MOTOR_CONFIG.use_dshot_telemetry || FC.MOTOR_CONFIG.use_esc_sensor)) {
@ -416,7 +408,7 @@ TABS.motors.initialize = function (callback) {
function computeAndUpdate(sensor_data, data, max_read) {
let sum = 0.0;
for (let j = 0, jlength = data.length; j < jlength; j++) {
for (let k = 0, klength = data[j].length; k < klength; k++){
for (let k = 0, klength = data[j].length; k < klength; k++) {
sum += data[j][k][1]*data[j][k][1];
}
}
@ -455,6 +447,7 @@ TABS.motors.initialize = function (callback) {
motor_mah_drawing_e.text(i18n.getMessage('motorsADrawingValue', [FC.ANALOG.amperage.toFixed(2)]));
motor_mah_drawn_e.text(i18n.getMessage('motorsmAhDrawnValue', [FC.ANALOG.mAhdrawn]));
}
GUI.interval_add('motors_power_data_pull_slow', power_data_pull, 250, true); // 4 fps
$('a.reset_max').click(function () {
@ -463,7 +456,7 @@ TABS.motors.initialize = function (callback) {
accelOffsetEstablished = false;
});
const numberOfValidOutputs = (FC.MOTOR_DATA.indexOf(0) > -1) ? FC.MOTOR_DATA.indexOf(0) : 8;
self.numberOfValidOutputs = (FC.MOTOR_DATA.indexOf(0) > -1) ? FC.MOTOR_DATA.indexOf(0) : 8;
let rangeMin;
let rangeMax;
let neutral3d;
@ -526,7 +519,7 @@ TABS.motors.initialize = function (callback) {
function setSlidersEnabled(isEnabled) {
if (isEnabled && !self.armed) {
$('div.sliders input').slice(0, numberOfValidOutputs).prop('disabled', false);
$('div.sliders input').slice(0, self.numberOfValidOutputs).prop('disabled', false);
// unlock master slider
$('div.sliders input:last').prop('disabled', false);
@ -583,14 +576,14 @@ TABS.motors.initialize = function (callback) {
const val = $(this).val();
$('div.sliders input:not(:disabled, :last)').val(val);
$('div.values li:not(:last)').slice(0, numberOfValidOutputs).text(val);
$('div.values li:not(:last)').slice(0, self.numberOfValidOutputs).text(val);
$('div.sliders input:not(:last):first').trigger('input');
});
// check if motors are already spinning
let motorsRunning = false;
for (let i = 0; i < numberOfValidOutputs; i++) {
for (let i = 0; i < self.numberOfValidOutputs; i++) {
if (!self.feature3DEnabled) {
if (FC.MOTOR_DATA[i] > rangeMin) {
motorsRunning = true;
@ -747,7 +740,11 @@ TABS.motors.initialize = function (callback) {
zeroThrottleValue = neutral3d;
}
setup_motor_output_reordering_dialog(content_ready, zeroThrottleValue);
setup_motor_output_reordering_dialog(SetupEscDshotDirectionDialogCallback, zeroThrottleValue);
function SetupEscDshotDirectionDialogCallback() {
SetupdescDshotDirectionDialog(content_ready, zeroThrottleValue);
}
function content_ready() {
GUI.content_ready(callback);
@ -764,9 +761,9 @@ TABS.motors.initialize = function (callback) {
callbackFunction, mixerList[FC.MIXER_CONFIG.mixer - 1].name,
zeroThrottleValue, zeroThrottleValue + 200);
$('#dialogMotorOutputReorder-closebtn').click(closeDialog);
$('#dialogMotorOutputReorder-closebtn').click(closeDialogMotorOutputReorder);
function closeDialog()
function closeDialogMotorOutputReorder()
{
domDialogMotorOutputReorder[0].close();
motorOutputReorderComponent.close();
@ -776,7 +773,7 @@ TABS.motors.initialize = function (callback) {
function onDocumentKeyPress(event)
{
if (27 === event.which) {
closeDialog();
closeDialogMotorOutputReorder();
}
}
@ -786,6 +783,47 @@ TABS.motors.initialize = function (callback) {
domDialogMotorOutputReorder[0].showModal();
});
}
function SetupdescDshotDirectionDialog(callbackFunction, zeroThrottleValue)
{
const domEscDshotDirectionDialog = $('#escDshotDirectionDialog');
const idleThrottleValue = zeroThrottleValue + FC.PID_ADVANCED_CONFIG.digitalIdlePercent * 1000 / 100;
const motorConfig = {
numberOfMotors: self.numberOfValidOutputs,
motorStopValue: zeroThrottleValue,
motorSpinValue: idleThrottleValue,
escProtocolIsDshot: self.escProtocolIsDshot,
};
const escDshotDirectionComponent = new EscDshotDirectionComponent(
$('#escDshotDirectionDialog-Content'), callbackFunction, motorConfig);
$('#escDshotDirectionDialog-closebtn').on("click", closeEscDshotDirectionDialog);
function closeEscDshotDirectionDialog()
{
domEscDshotDirectionDialog[0].close();
escDshotDirectionComponent.close();
$(document).off("keydown", onDocumentKeyPress);
}
function onDocumentKeyPress(event)
{
if (27 === event.which) {
closeEscDshotDirectionDialog();
}
}
$('#escDshotDirectionDialog-Open').click(function()
{
$(document).on("keydown", onDocumentKeyPress);
domEscDshotDirectionDialog[0].showModal();
});
callbackFunction();
}
};
TABS.motors.cleanup = function (callback) {

View file

@ -0,0 +1,15 @@
'use strict';
class CommonUtils
{
static GetMixerImageSrc(mixerIndex, reverseMotorDir, apiVersion)
{
let reverse = "";
if (semver.gte(apiVersion, API_VERSION_1_36)) {
reverse = reverseMotorDir ? "_reversed" : "";
}
return `./resources/motor_order/${mixerList[mixerIndex - 1].image}${reverse}.svg`;
}
}

View file

@ -0,0 +1,40 @@
'use strict';
class DshotCommand
{
static get ALL_MOTORS() { return 255; }
}
DshotCommand.dshotCommands_e = {
DSHOT_CMD_MOTOR_STOP: 0,
DSHOT_CMD_BEACON1: 1,
DSHOT_CMD_BEACON2: 2,
DSHOT_CMD_BEACON3: 3,
DSHOT_CMD_BEACON4: 4,
DSHOT_CMD_BEACON5: 5,
DSHOT_CMD_ESC_INFO: 6, // V2 includes settings
DSHOT_CMD_SPIN_DIRECTION_1: 7,
DSHOT_CMD_SPIN_DIRECTION_2: 8,
DSHOT_CMD_3D_MODE_OFF: 9,
DSHOT_CMD_3D_MODE_ON: 10,
DSHOT_CMD_SETTINGS_REQUEST: 11, // Currently not implemented
DSHOT_CMD_SAVE_SETTINGS: 12,
DSHOT_CMD_SPIN_DIRECTION_NORMAL: 20,
DSHOT_CMD_SPIN_DIRECTION_REVERSED: 21,
DSHOT_CMD_LED0_ON: 22, // BLHeli32 only
DSHOT_CMD_LED1_ON: 23, // BLHeli32 only
DSHOT_CMD_LED2_ON: 24, // BLHeli32 only
DSHOT_CMD_LED3_ON: 25, // BLHeli32 only
DSHOT_CMD_LED0_OFF: 26, // BLHeli32 only
DSHOT_CMD_LED1_OFF: 27, // BLHeli32 only
DSHOT_CMD_LED2_OFF: 28, // BLHeli32 only
DSHOT_CMD_LED3_OFF: 29, // BLHeli32 only
DSHOT_CMD_AUDIO_STREAM_MODE_ON_OFF: 30, // KISS audio Stream mode on/Off
DSHOT_CMD_SILENT_MODE_ON_OFF: 31, // KISS silent Mode on/Off
DSHOT_CMD_MAX: 47,
};
DshotCommand.dshotCommandType_e = {
DSHOT_CMD_TYPE_INLINE: 0, // dshot commands sent inline with motor signal (motors must be enabled)
DSHOT_CMD_TYPE_BLOCKING: 1, // dshot commands sent in blocking method (motors must be disabled)
};

View file

@ -0,0 +1,95 @@
'use strict';
class EscProtocols
{
static get PROTOCOL_PWM() { return "PWM"; }
static get PROTOCOL_ONESHOT125() { return "ONESHOT125"; }
static get PROTOCOL_ONESHOT42() { return "ONESHOT42"; }
static get PROTOCOL_MULTISHOT() { return "MULTISHOT"; }
static get PROTOCOL_BRUSHED() { return "BRUSHED"; }
static get PROTOCOL_DSHOT150() { return "DSHOT150"; }
static get PROTOCOL_DSHOT300() { return "DSHOT300"; }
static get PROTOCOL_DSHOT600() { return "DSHOT600"; }
static get PROTOCOL_DSHOT1200() { return "DSHOT1200"; }
static get PROTOCOL_PROSHOT1000() { return "PROSHOT1000"; }
static get PROTOCOL_DISABLED() { return "DISABLED"; }
static get DSHOT_PROTOCOLS_SET()
{
return [
EscProtocols.PROTOCOL_DSHOT150,
EscProtocols.PROTOCOL_DSHOT300,
EscProtocols.PROTOCOL_DSHOT600,
EscProtocols.PROTOCOL_DSHOT1200,
EscProtocols.PROTOCOL_PROSHOT1000,
];
}
static GetProtocolName(apiVersion, protocolIndex)
{
const escProtocols = EscProtocols.GetAvailableProtocols(apiVersion);
return escProtocols[protocolIndex];
}
static IsProtocolDshot(apiVersion, protocolIndex)
{
const protocolName = EscProtocols.GetProtocolName(apiVersion, protocolIndex);
return EscProtocols.DSHOT_PROTOCOLS_SET.includes(protocolName);
}
static GetAvailableProtocols(apiVersion)
{
const escProtocols = [
EscProtocols.PROTOCOL_PWM,
EscProtocols.PROTOCOL_ONESHOT125,
EscProtocols.PROTOCOL_ONESHOT42,
EscProtocols.PROTOCOL_MULTISHOT,
];
if (semver.gte(apiVersion, "1.20.0")) {
escProtocols.push(EscProtocols.PROTOCOL_BRUSHED);
}
if (semver.gte(apiVersion, API_VERSION_1_31)) {
escProtocols.push(EscProtocols.PROTOCOL_DSHOT150);
escProtocols.push(EscProtocols.PROTOCOL_DSHOT300);
escProtocols.push(EscProtocols.PROTOCOL_DSHOT600);
if (semver.lt(apiVersion, API_VERSION_1_42)) {
escProtocols.push(EscProtocols.PROTOCOL_DSHOT1200);
}
}
if (semver.gte(apiVersion, API_VERSION_1_36)) {
escProtocols.push(EscProtocols.PROTOCOL_PROSHOT1000);
}
if (semver.gte(apiVersion, API_VERSION_1_43)) {
escProtocols.push(EscProtocols.PROTOCOL_DISABLED);
}
return escProtocols;
}
static ReorderPwmProtocols(apiVersion, protocolIndex)
{
let result = protocolIndex;
if (semver.lt(apiVersion, "1.26.0")) {
switch (protocolIndex) {
case 5:
result = 7;
break;
case 7:
result = 5;
break;
default:
break;
}
}
return result;
}
}

View file

@ -42,6 +42,7 @@
<link type="text/css" rel="stylesheet" href="./components/MotorOutputReordering/Styles.css" media="all"/>
<link type="text/css" rel="stylesheet" href="./css/select2_custom.css" media="all"/>
<link type="text/css" rel="stylesheet" href="./node_modules/select2/dist/css/select2.min.css" media="all"/>
<link type="text/css" rel="stylesheet" href="./components/EscDshotDirection/Styles.css" media="all"/>
<link type="text/css" rel="stylesheet" href="./css/dark-theme.css" media="all" disabled/>
@ -72,6 +73,7 @@
<script type="text/javascript" src="./js/utils/common.js"></script>
<script type="text/javascript" src="./js/utils/css.js"></script>
<script type="text/javascript" src="./js/utils/window_watchers.js"></script>
<script type="text/javascript" src="./js/utils/CommonUtils.js"></script>
<script type="text/javascript" src="./js/injected_methods.js"></script>
<script type="text/javascript" src="./js/ConfigStorage.js"></script>
<script type="text/javascript" src="./js/data_storage.js"></script>
@ -142,6 +144,11 @@
<script type="text/javascript" src="./components/MotorOutputReordering/MotorOutputReorderingCanvas.js"></script>
<script type="text/javascript" src="./components/MotorOutputReordering/MotorOutputReorderingConfig.js"></script>
<script type="text/javascript" src="./node_modules/select2/dist/js/select2.min.js"></script>
<script type="text/javascript" src="./js/utils/EscProtocols.js"></script>
<script type="text/javascript" src="./js/utils/DshotCommand.js"></script>
<script type="text/javascript" src="./components/EscDshotDirection/EscDshotDirectionComponent.js"></script>
<script type="text/javascript" src="./components/EscDshotDirection/EscDshotDirectionMotorDriver.js"></script>
<script type="text/javascript" src="./components/EscDshotDirection/EscDshotCommandQueue.js"></script>
<title></title>
</head>

View file

@ -101,6 +101,7 @@
</div>
<div class="power_info">
<a href="#" id="motorOutputReorderDialogOpen" class="regular-button" i18n="motorOutputReorderDialogOpen"></a>
<a href="#" id="escDshotDirectionDialog-Open" class="regular-button" i18n="escDshotDirectionDialog-Open"></a>
<span i18n="motorsVoltage" class="power_text"></span><span class="motors-bat-voltage power_value"></span>
<span i18n="motorsADrawing" class="power_text"></span><span class="motors-bat-mah-drawing power_value"></span>
<span i18n="motorsmAhDrawn" class="power_text"></span><span class="motors-bat-mah-drawn power_value"></span>
@ -200,4 +201,13 @@
</div>
</div>
</dialog>
</div>
<dialog id="escDshotDirectionDialog">
<div id="escDshotDirectionDialog-ContentWrapper">
<div id="escDshotDirectionDialog-Content">
</div>
<a href="#" id="escDshotDirectionDialog-closebtn" class="regular-button right" i18n="close"></a>
</div>
</dialog>
</div>