1
0
Fork 0
mirror of https://github.com/betaflight/betaflight-configurator.git synced 2025-07-24 00:35:26 +03:00

Bringing in changes from the trunk

This commit is contained in:
Robert Cisneros 2021-01-14 19:24:34 -06:00
commit 4c22f6e8c0
20 changed files with 396 additions and 123 deletions

View file

@ -153,6 +153,7 @@ const FC = {
VTXTABLE_BAND: null,
VTXTABLE_POWERLEVEL: null,
VTX_CONFIG: null,
VTX_DEVICE_STATUS: null,
resetState () {
// Using `Object.assign` instead of reassigning to
@ -621,6 +622,7 @@ const FC = {
gyro_notch2_cutoff: 100,
gyro_notch2_hz: 200,
gyro_rpm_notch_harmonics: 3,
gyro_rpm_notch_min_hz: 100,
dterm_lowpass_hz: 100,
dterm_lowpass_dyn_min_hz: 150,
dterm_lowpass_dyn_max_hz: 250,
@ -635,6 +637,8 @@ const FC = {
dyn_notch_width_percent: 8,
dyn_notch_q_rpm: 250, // default with rpm filtering
dyn_notch_width_percent_rpm: 0,
dyn_notch_min_hz: 150,
dyn_notch_max_hz: 600,
};
this.DEFAULT_PIDS = [
@ -642,6 +646,8 @@ const FC = {
46, 90, 38, 22, 95,
30, 90, 0, 0, 90,
];
this.VTX_DEVICE_STATUS = null;
},
getSerialRxTypes: () => {

View file

@ -113,6 +113,21 @@ GuiControl.prototype.interval_add = function (name, code, interval, first) {
return data;
};
// name = string
// code = function reference (code to be executed)
// interval = time interval in miliseconds
// first = true/false if code should be ran initially before next timer interval hits
// condition = function reference with true/false result, a condition to be checked before every interval code execution
GuiControl.prototype.interval_add_condition = function (name, code, interval, first, condition) {
this.interval_add(name, () => {
if (condition()) {
code();
} else {
this.interval_remove(name);
}
}, interval, first);
}
// name = string
GuiControl.prototype.interval_remove = function (name) {
for (let i = 0; i < this.interval_array.length; i++) {

View file

@ -182,4 +182,5 @@ const MSPCodes = {
MSP2_MOTOR_OUTPUT_REORDERING: 0x3001,
MSP2_SET_MOTOR_OUTPUT_REORDERING: 0x3002,
MSP2_SEND_DSHOT_COMMAND: 0x3003,
MSP2_GET_VTX_DEVICE_STATUS: 0x3004,
};

View file

@ -5,12 +5,7 @@
const ledDirectionLetters = ['n', 'e', 's', 'w', 'u', 'd']; // in LSB bit order
const ledFunctionLetters = ['i', 'w', 'f', 'a', 't', 'r', 'c', 'g', 's', 'b', 'l']; // in LSB bit order
const ledBaseFunctionLetters = ['c', 'f', 'a', 'l', 's', 'g', 'r']; // in LSB bit
let ledOverlayLetters;
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_36)) {
ledOverlayLetters = ['t', 'o', 'b', 'n', 'i', 'w']; // in LSB bit
} else {
ledOverlayLetters = ['t', 'o', 'b', 'v', 'i', 'w']; // in LSB bit
}
let ledOverlayLetters = ['t', 'o', 'b', 'v', 'i', 'w']; // in LSB bit
function MspHelper() {
const self = this;
@ -144,6 +139,17 @@ MspHelper.prototype.process_data = function(dataHandler) {
FC.MOTOR_OUTPUT_ORDER[i] = data.readU8();
}
break;
case MSPCodes.MSP2_GET_VTX_DEVICE_STATUS:
FC.VTX_DEVICE_STATUS = null;
const dataLength = data.byteLength;
if (dataLength > 0) {
const vtxDeviceStatusData = new Uint8Array(dataLength);
for (let i = 0; i < dataLength; i++) {
vtxDeviceStatusData[i] = data.readU8();
}
FC.VTX_DEVICE_STATUS = vtxDeviceStatusFactory.createVtxDeviceStatus(vtxDeviceStatusData);
}
break;
case MSPCodes.MSP_MOTOR_TELEMETRY:
const telemMotorCount = data.readU8();
for (let i = 0; i < telemMotorCount; i++) {
@ -1191,6 +1197,9 @@ MspHelper.prototype.process_data = function(dataHandler) {
if (semver.gte(FC.CONFIG.apiVersion, "1.20.0")) {
ledCount = data.byteLength / 4;
}
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_36)) {
ledOverlayLetters = ['t', 'o', 'b', 'n', 'i', 'w']; // in LSB bit
}
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_41)) {
// According to betaflight/src/main/msp/msp.c
// API 1.41 - add indicator for advanced profile support and the current profile selection
@ -2574,9 +2583,13 @@ MspHelper.prototype.sendLedStripConfig = function(onCompleteCallback) {
buffer.push(ledIndex);
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_36)) {
ledOverlayLetters = ['t', 'o', 'b', 'n', 'i', 'w']; // in LSB bit
}
if (semver.lt(FC.CONFIG.apiVersion, "1.20.0")) {
let directionMask = 0;
for (const directionLetterIndex of led.directions) {
for (let directionLetterIndex = 0; directionLetterIndex < led.directions.length; directionLetterIndex++) {
const bitIndex = ledDirectionLetters.indexOf(led.directions[directionLetterIndex]);
if (bitIndex >= 0) {
directionMask = bit_set(directionMask, bitIndex);
@ -2585,7 +2598,7 @@ MspHelper.prototype.sendLedStripConfig = function(onCompleteCallback) {
buffer.push16(directionMask);
let functionMask = 0;
for (const functionLetterIndex of led.functions) {
for (let functionLetterIndex = 0; functionLetterIndex < led.functions.length; functionLetterIndex++) {
const bitIndex = ledFunctionLetters.indexOf(led.functions[functionLetterIndex]);
if (bitIndex >= 0) {
functionMask = bit_set(functionMask, bitIndex);
@ -2602,7 +2615,7 @@ MspHelper.prototype.sendLedStripConfig = function(onCompleteCallback) {
mask |= (led.y << 0);
mask |= (led.x << 4);
for (const functionLetterIndex of led.functions) {
for (let functionLetterIndex = 0; functionLetterIndex < led.functions.length; functionLetterIndex++) {
const fnIndex = ledBaseFunctionLetters.indexOf(led.functions[functionLetterIndex]);
if (fnIndex >= 0) {
mask |= (fnIndex << 8);
@ -2610,7 +2623,7 @@ MspHelper.prototype.sendLedStripConfig = function(onCompleteCallback) {
}
}
for (const overlayLetterIndex of led.functions) {
for (let overlayLetterIndex = 0; overlayLetterIndex < led.functions.length; overlayLetterIndex++) {
const bitIndex = ledOverlayLetters.indexOf(led.functions[overlayLetterIndex]);
if (bitIndex >= 0) {
mask |= bit_set(mask, bitIndex + 12);
@ -2619,7 +2632,7 @@ MspHelper.prototype.sendLedStripConfig = function(onCompleteCallback) {
mask |= (led.color << 18);
for (const directionLetterIndex of led.directions) {
for (let directionLetterIndex = 0; directionLetterIndex < led.directions.length; directionLetterIndex++) {
const bitIndex = ledDirectionLetters.indexOf(led.directions[directionLetterIndex]);
if (bitIndex >= 0) {
mask |= bit_set(mask, bitIndex + 22);

View file

@ -242,8 +242,10 @@ const serial = {
});
} else {
self.connectionId = false;
CONFIGURATOR.virtualMode = false;
self.connectionType = false;
if (callback) {
callback();
callback(true);
}
}
} else {

View file

@ -9,6 +9,7 @@ TABS.led_strip = {
TABS.led_strip.initialize = function (callback, scrollPosition) {
let selectedColorIndex = null;
let selectedModeColor = null;
const functionTag = '.function-';
if (semver.lt(FC.CONFIG.apiVersion, "1.20.0")) {
TABS.led_strip.functions = ['i', 'w', 'f', 'a', 't', 'r', 'c', 'g', 's', 'b'];
@ -68,8 +69,6 @@ TABS.led_strip.initialize = function (callback, scrollPosition) {
i18n.localizePage();
const functionTag = '.function-';
// Build Grid
const theHTML = [];
let theHTMLlength = 0;
@ -316,6 +315,7 @@ TABS.led_strip.initialize = function (callback, scrollPosition) {
$('.mainGrid').selectable({
filter: ' > div',
stop: function() {
const functionsInSelection = [];
const directionsInSelection = [];
clearModeColorSelection();
@ -566,7 +566,7 @@ TABS.led_strip.initialize = function (callback, scrollPosition) {
$(this).find('.wire').html(ledIndex);
for (let modeIndex = 0; modeIndex < led.functions.length; modeIndex++) {
$(this).addClass(`function-'${led.functions[modeIndex]}`);
$(this).addClass(`function-${led.functions[modeIndex]}`);
}
for (let directionIndex = 0; directionIndex < led.directions.length; directionIndex++) {
@ -1052,7 +1052,7 @@ TABS.led_strip.initialize = function (callback, scrollPosition) {
const className = 'color-' + colorIndex;
if ($(this).is('.' + className)) {
$(this).find('.overlay-color').addClass(className);
$(this).find('.overlay-color').css('background-color', HsvToColor(FC.LED_COLORS[colorIndex]))
$(this).find('.overlay-color').css('background-color', HsvToColor(FC.LED_COLORS[colorIndex]));
} else {
if ($(this).find('.overlay-color').is('.' + className))
$(this).find('.overlay-color').removeClass(className);

View file

@ -12,6 +12,39 @@ TABS.vtx = {
analyticsChanges: {},
updating: true,
env: new djv(),
get _DEVICE_STATUS_UPDATE_INTERVAL_NAME() {
return "vtx_device_status_request";
}
};
TABS.vtx.isVtxDeviceStatusNotReady = function()
{
const isReady = (null !== FC.VTX_DEVICE_STATUS) && (FC.VTX_DEVICE_STATUS.deviceIsReady);
return !isReady;
};
TABS.vtx.updateVtxDeviceStatus = function()
{
MSP.send_message(MSPCodes.MSP2_GET_VTX_DEVICE_STATUS, false, false, vtxDeviceStatusReceived);
function vtxDeviceStatusReceived()
{
$("#vtx_type_description").text(TABS.vtx.getVtxTypeString());
}
};
TABS.vtx.getVtxTypeString = function()
{
let result = i18n.getMessage(`vtxType_${FC.VTX_CONFIG.vtx_type}`);
const isSmartAudio = VtxDeviceTypes.VTXDEV_SMARTAUDIO === FC.VTX_CONFIG.vtx_type;
const isVtxDeviceStatusReceived = null !== FC.VTX_DEVICE_STATUS;
if (isSmartAudio && isVtxDeviceStatusReceived) {
result += ` ${FC.VTX_DEVICE_STATUS.smartAudioVersion}`;
}
return result;
};
TABS.vtx.initialize = function (callback) {
@ -55,7 +88,19 @@ TABS.vtx.initialize = function (callback) {
vtx_config();
function vtx_config() {
MSP.send_message(MSPCodes.MSP_VTX_CONFIG, false, false, vtxtable_bands);
MSP.send_message(MSPCodes.MSP_VTX_CONFIG, false, false, vtxConfigReceived);
}
function vtxConfigReceived() {
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
GUI.interval_add_condition(self._DEVICE_STATUS_UPDATE_INTERVAL_NAME,
TABS.vtx.updateVtxDeviceStatus,
1000, false,
TABS.vtx.isVtxDeviceStatusNotReady
);
}
vtxtable_bands();
}
function vtxtable_bands() {
@ -196,11 +241,11 @@ TABS.vtx.initialize = function (callback) {
});
// Supported?
const vtxSupported = FC.VTX_CONFIG.vtx_type !== 0 && FC.VTX_CONFIG.vtx_type !== 255;
const vtxSupported = FC.VTX_CONFIG.vtx_type !== VtxDeviceTypes.VTXDEV_UNSUPPORTED && FC.VTX_CONFIG.vtx_type !== VtxDeviceTypes.VTXDEV_UNKNOWN;
const vtxTableNotConfigured = vtxSupported && FC.VTX_CONFIG.vtx_table_available &&
(FC.VTX_CONFIG.vtx_table_bands === 0 || FC.VTX_CONFIG.vtx_table_channels === 0 || FC.VTX_CONFIG.vtx_table_powerlevels === 0);
TABS.vtx.vtxTableFactoryBandsSupported = FC.VTX_CONFIG.vtx_type === 3;
TABS.vtx.vtxTableFactoryBandsSupported = FC.VTX_CONFIG.vtx_type === VtxDeviceTypes.VTXDEV_SMARTAUDIO;
$(".vtx_supported").toggle(vtxSupported);
$(".vtx_not_supported").toggle(!vtxSupported);
@ -234,7 +279,7 @@ TABS.vtx.initialize = function (callback) {
const noMessage = i18n.getMessage("no");
$("#vtx_device_ready_description").text(FC.VTX_CONFIG.vtx_device_ready ? yesMessage : noMessage);
$("#vtx_type_description").text(i18n.getMessage(`vtxType_${FC.VTX_CONFIG.vtx_type}`));
$("#vtx_type_description").text(self.getVtxTypeString());
$("#vtx_channel_description").text(FC.VTX_CONFIG.vtx_channel);
$("#vtx_frequency_description").text(FC.VTX_CONFIG.vtx_frequency);
$("#vtx_pit_mode_description").text(FC.VTX_CONFIG.vtx_pit_mode ? yesMessage : noMessage);
@ -513,23 +558,23 @@ TABS.vtx.initialize = function (callback) {
switch (vtxType) {
case 0: // Unsupported
case VtxDeviceTypes.VTXDEV_UNSUPPORTED:
powerMinMax = {};
break;
case 1: // RTC6705
case VtxDeviceTypes.VTXDEV_RTC6705:
powerMinMax = {min: 1, max: 3};
break;
case 3: // SmartAudio
case VtxDeviceTypes.VTXDEV_SMARTAUDIO:
powerMinMax = {min: 1, max: 4};
break;
case 4: // Tramp
case VtxDeviceTypes.VTXDEV_TRAMP:
powerMinMax = {min: 1, max: 5};
break;
case 255: // Unknown
case VtxDeviceTypes.VTXDEV_UNKNOWN:
default:
powerMinMax = {min: 0, max: 7};
}
@ -969,6 +1014,8 @@ TABS.vtx.cleanup = function (callback) {
this.VTXTABLE_BAND_LIST = [];
this.VTXTABLE_POWERLEVEL_LIST = [];
GUI.interval_remove(this._DEVICE_STATUS_UPDATE_INTERVAL_NAME);
if (callback) {
callback();
}

View file

@ -0,0 +1,19 @@
'use strict';
class VtxDeviceStatusRtc6705 extends VtxDeviceStatus {
constructor(dataView)
{
super(dataView);
dataView.readU8(); // custom device status size
// Read other Tramp VTX device parameters here
}
static get staticDeviceStatusType()
{
return VtxDeviceTypes.VTXDEV_RTC6705;
}
}
vtxDeviceStatusFactory.registerVtxDeviceStatusClass(VtxDeviceStatusRtc6705);

View file

@ -0,0 +1,49 @@
'use strict';
class VtxDeviceStatusSmartAudio extends VtxDeviceStatus {
constructor(dataView)
{
super(dataView);
dataView.readU8(); // custom device status size
this._version = dataView.readU8();
this._mode = dataView.readU8();
this._orfreq = dataView.readU16();
this._willBootIntoPitMode = Boolean(dataView.readU8());
}
get smartAudioVersion()
{
const sa = this._version * 100 + this._mode;
let result = "";
switch (this._version) {
case 1:
result = "1.0";
break;
case 2:
result = "2.0";
break;
case 3:
result = "2.1";
break;
default:
// unknown SA version
result = i18n.getMessage("vtxType_255");
}
if (16 == this._mode) {
result = i18n.getMessage("vtxSmartAudioUnlocked", {"version": result});
}
return result;
}
static get staticDeviceStatusType()
{
return VtxDeviceTypes.VTXDEV_SMARTAUDIO;
}
}
vtxDeviceStatusFactory.registerVtxDeviceStatusClass(VtxDeviceStatusSmartAudio);

View file

@ -0,0 +1,19 @@
'use strict';
class VtxDeviceStatusTramp extends VtxDeviceStatus {
constructor(dataView)
{
super(dataView);
dataView.readU8(); // custom device status size
// Read other Tramp VTX device parameters here
}
static get staticDeviceStatusType()
{
return VtxDeviceTypes.VTXDEV_TRAMP;
}
}
vtxDeviceStatusFactory.registerVtxDeviceStatusClass(VtxDeviceStatusTramp);

View file

@ -0,0 +1,79 @@
'use strict';
const VtxDeviceTypes = {
VTXDEV_UNSUPPORTED: 0, // reserved for MSP
VTXDEV_RTC6705: 1,
// 2 reserved
VTXDEV_SMARTAUDIO: 3,
VTXDEV_TRAMP: 4,
VTXDEV_UNKNOWN: 0xFF,
};
class VtxDeviceStatus
{
constructor(dataView)
{
this._deviceIsReady = dataView.readU8();
const bandAndChannelAvailable = Boolean(dataView.readU8());
this._band = dataView.readU8();
this._channel = dataView.readU8();
if (!bandAndChannelAvailable) {
this._band = undefined;
this._channel = undefined;
}
const powerIndexAvailable = Boolean(dataView.readU8());
this._powerIndex = dataView.readU8();
if (!powerIndexAvailable) {
this._powerIndex = undefined;
}
const frequencyAvailable = Boolean(dataView.readU8());
this._frequency = dataView.readU16();
if (!frequencyAvailable) {
this._frequency = undefined;
}
const vtxStatusAvailable = Boolean(dataView.readU8());
this._vtxStatus = dataView.readU32(); // pitmode and/or locked
if (!vtxStatusAvailable) {
this._vtxStatus = undefined;
}
this._readPowerLevels(dataView);
}
_readPowerLevels(dataView)
{
this._levels = [];
this._powers = [];
const powerLevelCount = dataView.readU8();
for (let i = 0; i < powerLevelCount; i++)
{
this._levels.push(dataView.readU16());
this._powers.push(dataView.readU16());
}
}
get deviceIsReady()
{
return this._deviceIsReady;
}
// overload this function in subclasses
static get staticDeviceStatusType()
{
return VtxDeviceTypes.VTXDEV_UNKNOWN;
}
get deviceStatusType()
{
// returns result of overloaded static function "staticDeviceStatusType"
return this.constructor.staticDeviceStatusType;
}
}

View file

@ -0,0 +1,40 @@
'use strict';
const vtxDeviceStatusFactory = {
_vtxDeviceStatusClasses: [],
// call this to register a new vtx type like SmartAudio, Tramp or Rtc6705
registerVtxDeviceStatusClass: function(vtxDeviceStatusClass)
{
this._vtxDeviceStatusClasses.push(vtxDeviceStatusClass);
},
createVtxDeviceStatus: function(byteArray)
{
const dataView = new DataView(byteArray.buffer);
const vtxTypeIndex = dataView.readU8();
const vtxDeviceStatusClass = this._getDeviceStatusClass(vtxTypeIndex);
return new vtxDeviceStatusClass(dataView);
},
_readVtxType: function(dataView)
{
return dataView.readU8();
},
_getDeviceStatusClass: function(vtxTypeIndex)
{
let result = this._vtxDeviceStatusClasses.find(
(vtxClass) => {
return vtxClass.staticDeviceStatusType === vtxTypeIndex;
});
if (typeof result === 'undefined') {
result = VtxDeviceStatus;
}
return result;
},
};