Expose Cloud Build Options and hide tabs and features (#3332)

Expose Cloud Build Options

Add cloud build options to auto-detect
master
Mark Haslinghuis 2023-03-03 00:11:20 +01:00 committed by GitHub
parent 65d0ab3796
commit 584e672c4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 208 additions and 113 deletions

View File

@ -549,6 +549,9 @@
"buildServerSupportRequestSubmission": {
"message": "<br>*** Support data submitted *** <br>Id: $1<br><br><br># copy ID and provide to the betaflight team."
},
"buildKey": {
"message": "Build Key: <strong>$1</strong>"
},
"supportWarningDialogTitle": {
"message": "Confirm Data Submission"
},

View File

@ -149,6 +149,18 @@ export default class BuildApi {
});
}
requestBuildOptions(key, onSuccess, onFailure) {
const url = `${this._url}/api/builds/${key}/json`;
$.get(url, function (data) {
onSuccess(data);
}).fail(xhr => {
if (onFailure !== undefined) {
onFailure();
}
});
}
loadOptions(onSuccess, onFailure) {
const url = `${this._url}/api/options`;

View File

@ -1,5 +1,5 @@
import { bit_check, bit_set, bit_clear } from "./bit";
import { API_VERSION_1_44 } from './data_storage';
import { API_VERSION_1_44, API_VERSION_1_45 } from './data_storage';
import semver from "semver";
import { tracking } from "./Analytics";
@ -11,21 +11,22 @@ const Features = function (config) {
{bit: 2, group: 'other', name: 'INFLIGHT_ACC_CAL'},
{bit: 3, group: 'rxMode', mode: 'select', name: 'RX_SERIAL'},
{bit: 4, group: 'escMotorStop', name: 'MOTOR_STOP'},
{bit: 5, group: 'other', name: 'SERVO_TILT', haveTip: true},
{bit: 5, group: 'other', name: 'SERVO_TILT', haveTip: true, dependsOn: 'SERVOS'},
{bit: 6, group: 'other', name: 'SOFTSERIAL', haveTip: true},
{bit: 7, group: 'gps', name: 'GPS', haveTip: true},
{bit: 9, group: 'other', name: 'SONAR'},
{bit: 10, group: 'telemetry', name: 'TELEMETRY'},
{bit: 7, group: 'other', name: 'GPS', haveTip: true, dependsOn: 'GPS'},
{bit: 9, group: 'other', name: 'SONAR', dependsOn: 'RANGEFINDER'},
{bit: 10, group: 'telemetry', name: 'TELEMETRY', dependsOn: 'TELEMETRY'},
{bit: 12, group: '3D', name: '3D'},
{bit: 13, group: 'rxMode', mode: 'select', name: 'RX_PARALLEL_PWM'},
{bit: 14, group: 'rxMode', mode: 'select', name: 'RX_MSP'},
{bit: 15, group: 'rssi', name: 'RSSI_ADC'},
{bit: 16, group: 'other', name: 'LED_STRIP'},
{bit: 17, group: 'other', name: 'DISPLAY', haveTip: true},
{bit: 18, group: 'other', name: 'OSD'},
{bit: 20, group: 'other', name: 'CHANNEL_FORWARDING'},
{bit: 21, group: 'other', name: 'TRANSPONDER', haveTip: true},
{bit: 16, group: 'other', name: 'LED_STRIP', dependsOn: 'LED_STRIP'},
{bit: 17, group: 'other', name: 'DISPLAY', haveTip: true, dependsOn: 'DASHBOARD'},
{bit: 18, group: 'other', name: 'OSD', dependsOn: 'OSD'},
{bit: 20, group: 'other', name: 'CHANNEL_FORWARDING', dependsOn: 'SERVOS'},
{bit: 21, group: 'other', name: 'TRANSPONDER', haveTip: true, dependsOn: 'TRANSPONDER'},
{bit: 22, group: 'other', name: 'AIRMODE'},
{bit: 24, group: 'vtx', name: 'VTX', dependsOn: 'VTX'},
{bit: 25, group: 'rxMode', mode: 'select', name: 'RX_SPI'},
{bit: 27, group: 'escSensor', name: 'ESC_SENSOR'},
{bit: 28, group: 'antiGravity', name: 'ANTI_GRAVITY', haveTip: true, hideName: true},
@ -37,7 +38,19 @@ const Features = function (config) {
);
}
self._features = features.sort((a, b) => a.name.localeCompare(b.name, window.navigator.language, { ignorePunctuation: true }));
self._features = features;
if (semver.gte(config.apiVersion, API_VERSION_1_45) && config.buildKey.length === 32) {
self._features = [];
for (const feature of features) {
if (config.buildOptions.some(opt => opt.includes(feature.dependsOn)) || feature.dependsOn === undefined) {
self._features.push(feature);
}
}
}
self._features.sort((a, b) => a.name.localeCompare(b.name, window.navigator.language, { ignorePunctuation: true }));
self._featureMask = 0;
self._analyticsChanges = {};

View File

@ -6,12 +6,13 @@ export const API_VERSION_1_42 = '1.42.0';
export const API_VERSION_1_43 = '1.43.0';
export const API_VERSION_1_44 = '1.44.0';
export const API_VERSION_1_45 = '1.45.0';
export const API_VERSION_1_46 = '1.46.0';
const CONFIGURATOR = {
// all versions are specified and compared using semantic versioning http://semver.org/
API_VERSION_ACCEPTED: API_VERSION_1_41,
API_VERSION_MIN_SUPPORTED_BACKUP_RESTORE: API_VERSION_1_41,
API_VERSION_MAX_SUPPORTED: API_VERSION_1_45,
API_VERSION_MAX_SUPPORTED: API_VERSION_1_46,
connectionValid: false,
connectionValidCliOnly: false,

View File

@ -8,6 +8,8 @@ const INITIAL_CONFIG = {
flightControllerVersion: '',
version: 0,
buildInfo: '',
buildKey: '',
buildOptions: [],
multiType: 0,
msp_version: 0, // not specified using semantic versioning
capability: 0,

View File

@ -33,19 +33,16 @@ class GuiControl {
'options',
'help',
];
this.defaultAllowedFCTabsWhenConnected = [
this.defaultAllowedTabsCloudBuild = [
'setup',
'failsafe',
'transponder',
'osd',
'power',
'adjustments',
'auxiliary',
'presets',
'cli',
'configuration',
'gps',
'led_strip',
'logging',
'onboard_logging',
'modes',
@ -54,10 +51,19 @@ class GuiControl {
'ports',
'receiver',
'sensors',
];
this.defaultCloudBuildTabOptions = [
'gps',
'led_strip',
'osd',
'servos',
'transponder',
'vtx',
];
this.defaultAllowedFCTabsWhenConnected = [ ...this.defaultAllowedTabsCloudBuild, ...this.defaultCloudBuildTabOptions];
this.allowedTabs = this.defaultAllowedTabsWhenDisconnected;
// check which operating system is user running

View File

@ -202,6 +202,7 @@ const MSPCodes = {
CRAFT_NAME: 2,
PID_PROFILE_NAME: 3,
RATE_PROFILE_NAME: 4,
BUILD_KEY: 5,
};
export default MSPCodes;

View File

@ -851,6 +851,9 @@ MspHelper.prototype.process_data = function(dataHandler) {
case MSPCodes.RATE_PROFILE_NAME:
FC.CONFIG.rateProfileNames[FC.CONFIG.rateProfile] = self.getText(data);
break;
case MSPCodes.BUILD_KEY:
FC.CONFIG.buildKey = self.getText(data);
break;
default:
console.log('Unsupport text type');
break;

View File

@ -23,6 +23,7 @@ import { get as getConfig, set as setConfig } from "./ConfigStorage";
import { tracking } from "./Analytics";
import semver from 'semver';
import CryptoES from "crypto-es";
import BuildApi from "./BuildApi";
let mspHelper;
let connectionTimestamp;
@ -458,17 +459,39 @@ function checkReportProblems() {
});
}
function processUid() {
MSP.send_message(MSPCodes.MSP_UID, false, false, function () {
const deviceIdentifier = FC.CONFIG.deviceIdentifier;
tracking.setFlightControllerData(tracking.DATA.MCU_ID, CryptoES.SHA1(deviceIdentifier));
tracking.sendEvent(tracking.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'Connected');
connectionTimestamp = Date.now();
gui_log(i18n.getMessage('uniqueDeviceIdReceived', [deviceIdentifier]));
async function processBuildConfiguration() {
const buildApi = new BuildApi();
function onLoadCloudBuild(options) {
FC.CONFIG.buildOptions = options.Request.Options;
processCraftName();
});
}
await MSP.promise(MSPCodes.MSP2_GET_TEXT, mspHelper.crunch(MSPCodes.MSP2_GET_TEXT, MSPCodes.BUILD_KEY));
if (FC.CONFIG.buildKey.length === 32 && navigator.onLine) {
gui_log(i18n.getMessage('buildKey', FC.CONFIG.buildKey));
buildApi.requestBuildOptions(FC.CONFIG.buildKey, onLoadCloudBuild, processCraftName);
} else {
processCraftName();
}
}
async function processUid() {
await MSP.promise(MSPCodes.MSP_UID);
tracking.setFlightControllerData(tracking.DATA.MCU_ID, CryptoES.SHA1(FC.CONFIG.deviceIdentifier));
tracking.sendEvent(tracking.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'Connected');
connectionTimestamp = Date.now();
gui_log(i18n.getMessage('uniqueDeviceIdReceived', FC.CONFIG.deviceIdentifier));
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_45)) {
processBuildConfiguration();
} else {
processCraftName();
}
}
async function processCraftName() {
@ -494,7 +517,19 @@ function setRtc() {
function finishOpen() {
CONFIGURATOR.connectionValid = true;
GUI.allowedTabs = GUI.defaultAllowedFCTabsWhenConnected.slice();
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_45) && FC.CONFIG.buildKey.length === 32) {
GUI.allowedTabs = GUI.defaultAllowedTabsCloudBuild;
for (const tab of GUI.defaultCloudBuildTabOptions) {
if (FC.CONFIG.buildOptions.some(opt => opt.toLowerCase().includes(tab))) {
GUI.allowedTabs.push(tab);
}
}
} else {
GUI.allowedTabs = GUI.defaultAllowedFCTabsWhenConnected.slice();
}
if (GUI.isCordova()) {
UI_PHONES.reset();

View File

@ -11,7 +11,7 @@ import FC from '../fc';
import MSP from '../msp';
import MSPCodes from '../msp/MSPCodes';
import PortHandler, { usbDevices } from '../port_handler';
import CONFIGURATOR, { API_VERSION_1_39 } from '../data_storage';
import CONFIGURATOR, { API_VERSION_1_39, API_VERSION_1_45 } from '../data_storage';
import serial from '../serial';
import STM32DFU from '../protocols/stm32usbdfu';
import { gui_log } from '../gui_log';
@ -165,11 +165,9 @@ firmware_flasher.initialize = function (callback) {
TABS.firmware_flasher.targets = targets;
result = getStorage('selected_board');
if (result.selected_board) {
const selected = targets.find(t => t.target === result.selected_board);
$('select[name="board"]').val(selected ? result.selected_board : 0).trigger('change');
}
// For discussion. Rather remove build configuration and let user use auto-detect. Often I think already had pressed the button.
$('div.build_configuration').slideUp();
}
function buildOptionsList(select_e, options) {
@ -399,10 +397,6 @@ firmware_flasher.initialize = function (callback) {
}
if (!GUI.connect_lock) {
if (target !== '0') {
setStorage({'selected_board': target});
}
self.selectedBoard = target;
console.log('board changed to', target);
@ -535,6 +529,8 @@ firmware_flasher.initialize = function (callback) {
function verifyBoard() {
if (!$('option:selected', portPickerElement).data().isDFU) {
let mspHelper;
function onFinishClose() {
MSP.clearListeners();
}
@ -561,38 +557,91 @@ firmware_flasher.initialize = function (callback) {
if (board !== target) {
boardSelect.val(board).trigger('change');
}
gui_log(i18n.getMessage(targetAvailable ? 'firmwareFlasherBoardVerificationSuccess' : 'firmwareFlasherBoardVerficationTargetNotAvailable',
{ boardName: board }));
} else {
gui_log(i18n.getMessage('firmwareFlasherBoardVerificationFail'));
}
onClose();
}
function getBoard() {
function getBoardInfo() {
MSP.send_message(MSPCodes.MSP_BOARD_INFO, false, false, onFinish);
}
function presetBuildOptions(data) {
const newOptions = [];
newOptions.generalOptions = [];
newOptions.motorProtocols = [];
newOptions.radioProtocols = [];
newOptions.telemetryProtocols = [];
for (const option of data.generalOptions) {
option.default = FC.CONFIG.buildOptions.some(opt => opt.includes(option.value));
newOptions.generalOptions.push(option);
}
for (const option of data.motorProtocols) {
option.default = FC.CONFIG.buildOptions.some(opt => opt.includes(option.value));
newOptions.motorProtocols.push(option);
}
for (const option of data.radioProtocols) {
option.default = FC.CONFIG.buildOptions.some(opt => opt.includes(option.value));
newOptions.radioProtocols.push(option);
}
for (const option of data.telemetryProtocols) {
option.default = FC.CONFIG.buildOptions.some(opt => opt.includes(option.value));
newOptions.telemetryProtocols.push(option);
}
buildOptions(newOptions);
}
function getBuildInfo() {
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_45) && navigator.onLine) {
function onLoadCloudBuild(options) {
if (FC.CONFIG.buildKey.length === 32) {
FC.CONFIG.buildOptions = options.Request.Options;
self.releaseLoader.loadOptions(presetBuildOptions);
}
getBoardInfo();
}
MSP.send_message(MSPCodes.MSP2_GET_TEXT, mspHelper.crunch(MSPCodes.MSP2_GET_TEXT, MSPCodes.BUILD_KEY), false, () => {
self.releaseLoader.requestBuildOptions(FC.CONFIG.buildKey, onLoadCloudBuild, getBoardInfo);
});
} else {
getBoardInfo();
}
}
function detectBoard() {
console.log(`Requesting board information`);
MSP.send_message(MSPCodes.MSP_API_VERSION, false, false, () => {
if (!FC.CONFIG.apiVersion || FC.CONFIG.apiVersion === 'null.null.0') {
FC.CONFIG.apiVersion = '0.0.0';
}
console.log(FC.CONFIG.apiVersion);
MSP.send_message(MSPCodes.MSP_UID, false, false, () => {
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_39)) {
MSP.send_message(MSPCodes.MSP_BOARD_INFO, false, false, onFinish);
} else {
console.log('Firmware version not supported for reading board information');
onClose();
}
});
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_39)) {
onClose(); // not supported
} else {
MSP.send_message(MSPCodes.MSP_UID, false, false, getBuildInfo);
}
});
}
function onConnect(openInfo) {
if (openInfo) {
serial.onReceive.addListener(data => MSP.read(data));
const mspHelper = new MspHelper();
mspHelper = new MspHelper();
MSP.listen(mspHelper.process_data.bind(mspHelper));
getBoard();
detectBoard();
} else {
gui_log(i18n.getMessage('serialPortOpenFail'));
}
@ -1219,7 +1268,6 @@ firmware_flasher.showDialogVerifyBoard = function (selected, verified, onAbort,
if (!dialogVerifyBoard.hasAttribute('open')) {
dialogVerifyBoard.showModal();
$('#dialog-verify-board-abort-confirmbtn').click(function() {
setStorage({'selected_board': FC.CONFIG.boardName});
dialogVerifyBoard.close();
onAbort();
});

View File

@ -28,25 +28,16 @@ ports.initialize = function (callback) {
{ name: 'TELEMETRY_SMARTPORT', groups: ['telemetry'], maxPorts: 1 },
{ name: 'RX_SERIAL', groups: ['rx'], maxPorts: 1 },
{ name: 'BLACKBOX', groups: ['peripherals'], sharableWith: ['msp'], notSharableWith: ['telemetry'], maxPorts: 1 },
{ name: 'TELEMETRY_LTM', groups: ['telemetry'], sharableWith: ['msp'], notSharableWith: ['peripherals'], maxPorts: 1 },
{ name: 'TELEMETRY_MAVLINK', groups: ['telemetry'], sharableWith: ['msp'], notSharableWith: ['peripherals'], maxPorts: 1 },
{ name: 'IRC_TRAMP', groups: ['peripherals'], maxPorts: 1 },
{ name: 'ESC_SENSOR', groups: ['sensors'], maxPorts: 1 },
{ name: 'TBS_SMARTAUDIO', groups: ['peripherals'], maxPorts: 1 },
{ name: 'TELEMETRY_IBUS', groups: ['telemetry'], maxPorts: 1 },
{ name: 'RUNCAM_DEVICE_CONTROL', groups: ['peripherals'], maxPorts: 1 },
{ name: 'LIDAR_TF', groups: ['peripherals'], maxPorts: 1 },
];
const ltmFunctionRule = {name: 'TELEMETRY_LTM', groups: ['telemetry'], sharableWith: ['msp'], notSharableWith: ['peripherals'], maxPorts: 1};
functionRules.push(ltmFunctionRule);
const mavlinkFunctionRule = {name: 'TELEMETRY_MAVLINK', groups: ['telemetry'], sharableWith: ['msp'], notSharableWith: ['peripherals'], maxPorts: 1};
functionRules.push(mavlinkFunctionRule);
functionRules.push({ name: 'IRC_TRAMP', groups: ['peripherals'], maxPorts: 1 });
functionRules.push({ name: 'ESC_SENSOR', groups: ['sensors'], maxPorts: 1 });
functionRules.push({ name: 'TBS_SMARTAUDIO', groups: ['peripherals'], maxPorts: 1 });
functionRules.push({ name: 'TELEMETRY_IBUS', groups: ['telemetry'], maxPorts: 1 });
functionRules.push({ name: 'RUNCAM_DEVICE_CONTROL', groups: ['peripherals'], maxPorts: 1 });
functionRules.push({ name: 'LIDAR_TF', groups: ['peripherals'], maxPorts: 1 });
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_43)) {
functionRules.push({ name: 'FRSKY_OSD', groups: ['peripherals'], maxPorts: 1 });
}
@ -424,6 +415,7 @@ ports.initialize = function (callback) {
let enableBlackbox = false;
let enableEsc = false;
let enableGps = false;
let enableVtx = false;
for (const port of FC.SERIAL_CONFIG.ports) {
const func = port.functions;
@ -447,6 +439,10 @@ ports.initialize = function (callback) {
if (func.includes('GPS')) {
enableGps = true;
}
if (func.includes('IRC_TRAMP') || func.includes('TBS_SMARTAUDIO')) {
enableVtx = true;
}
}
const featureConfig = FC.FEATURE_CONFIG.features;
@ -479,6 +475,12 @@ ports.initialize = function (callback) {
featureConfig.disable('GPS');
}
if (enableVtx) {
featureConfig.enable('VTX');
} else {
featureConfig.disable('VTX');
}
mspHelper.sendSerialConfig(save_features);
function save_features() {

View File

@ -1,53 +1,22 @@
import semver from "semver";
import { API_VERSION_1_42 } from "../data_storage";
import { API_VERSION_1_42, API_VERSION_1_45 } from "../data_storage";
import FC from "../fc";
import { isExpertModeEnabled } from "./isExportModeEnabled";
export function updateTabList(features) {
const isExpertModeEnabled = $('input[name="expertModeCheckbox"]').is(':checked');
if (isExpertModeEnabled()) {
$('#tabs ul.mode-connected li.tab_failsafe').show();
$('#tabs ul.mode-connected li.tab_adjustments').show();
$('#tabs ul.mode-connected li.tab_servos').show();
$('#tabs ul.mode-connected li.tab_sensors').show();
$('#tabs ul.mode-connected li.tab_logging').show();
} else {
$('#tabs ul.mode-connected li.tab_failsafe').hide();
$('#tabs ul.mode-connected li.tab_adjustments').hide();
$('#tabs ul.mode-connected li.tab_servos').hide();
$('#tabs ul.mode-connected li.tab_sensors').hide();
$('#tabs ul.mode-connected li.tab_logging').hide();
}
$('#tabs ul.mode-connected li.tab_failsafe').toggle(isExpertModeEnabled);
$('#tabs ul.mode-connected li.tab_adjustments').toggle(isExpertModeEnabled);
$('#tabs ul.mode-connected li.tab_servos').toggle(isExpertModeEnabled);
$('#tabs ul.mode-connected li.tab_sensors').toggle(isExpertModeEnabled);
$('#tabs ul.mode-connected li.tab_logging').toggle(isExpertModeEnabled);
if (features.isEnabled('GPS') && isExpertModeEnabled()) {
$('#tabs ul.mode-connected li.tab_gps').show();
} else {
$('#tabs ul.mode-connected li.tab_gps').hide();
}
if (features.isEnabled('LED_STRIP')) {
$('#tabs ul.mode-connected li.tab_led_strip').show();
} else {
$('#tabs ul.mode-connected li.tab_led_strip').hide();
}
if (features.isEnabled('TRANSPONDER')) {
$('#tabs ul.mode-connected li.tab_transponder').show();
} else {
$('#tabs ul.mode-connected li.tab_transponder').hide();
}
if (features.isEnabled('OSD')) {
$('#tabs ul.mode-connected li.tab_osd').show();
} else {
$('#tabs ul.mode-connected li.tab_osd').hide();
}
$('#tabs ul.mode-connected li.tab_power').show();
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42)) {
$('#tabs ul.mode-connected li.tab_vtx').show();
} else {
$('#tabs ul.mode-connected li.tab_vtx').hide();
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_45 || FC.CONFIG.buildKey.length !== 32)) {
$('#tabs ul.mode-connected li.tab_gps').toggle(features.isEnabled('GPS'));
$('#tabs ul.mode-connected li.tab_led_strip').toggle(features.isEnabled('LED_STRIP'));
$('#tabs ul.mode-connected li.tab_servos').toggle(features.isEnabled('CHANNEL_FORWARDING') || features.isEnabled('SERVO_TILT'));
$('#tabs ul.mode-connected li.tab_transponder').toggle(features.isEnabled('TRANSPONDER'));
$('#tabs ul.mode-connected li.tab_osd').toggle(features.isEnabled('OSD'));
$('#tabs ul.mode-connected li.tab_vtx').toggle(features.isEnabled('VTX') && semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42));
}
}

View File

@ -135,7 +135,7 @@
<th i18n="configurationFeatureName"></th>
</tr>
</thead>
<tbody class="features gps other" id="noline">
<tbody class="features other" id="noline">
<!-- table generated here -->
</tbody>
</table>